From d09d6f1cc0cd2b144148a189b92383dd5e920896 Mon Sep 17 00:00:00 2001 From: feie9456 Date: Wed, 18 Mar 2026 12:54:00 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0AI=E6=9C=8D=E5=8A=A1=EF=BC=8C?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E9=BA=A6=E5=85=8B=E9=A3=8E=E3=80=81=E6=91=84?= =?UTF-8?q?=E5=83=8F=E5=A4=B4=E8=BE=93=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 31 + README.md | 405 ++ README_zh.md | 485 ++ android_glide_lint.xml | 7 + build.gradle | 39 + demo.jks | Bin 0 -> 2676 bytes duix-sdk/.gitignore | 1 + duix-sdk/build.gradle | 68 + duix-sdk/consumer-rules.pro | 0 duix-sdk/libs/resource_loader.jar | Bin 0 -> 13872 bytes duix-sdk/proguard-rules.pro | 90 + duix-sdk/src/main/AndroidManifest.xml | 4 + duix-sdk/src/main/cpp/CMakeLists.txt | 199 + duix-sdk/src/main/cpp/aes/aes.h | 41 + duix-sdk/src/main/cpp/aes/aes_cbc.c | 23 + duix-sdk/src/main/cpp/aes/aes_core.c | 1127 +++ duix-sdk/src/main/cpp/aes/aes_ecb.c | 24 + duix-sdk/src/main/cpp/aes/aes_locl.h | 42 + duix-sdk/src/main/cpp/aes/aesmain.c | 111 + duix-sdk/src/main/cpp/aes/aesmain.h | 16 + duix-sdk/src/main/cpp/aes/base64.c | 164 + duix-sdk/src/main/cpp/aes/base64.h | 29 + duix-sdk/src/main/cpp/aes/cbc128.c | 161 + duix-sdk/src/main/cpp/aes/gaes_stream.cc | 213 + duix-sdk/src/main/cpp/aes/gaes_stream.h | 22 + duix-sdk/src/main/cpp/aes/gaesmain | Bin 0 -> 64344 bytes duix-sdk/src/main/cpp/aes/gj_aes.c | 69 + duix-sdk/src/main/cpp/aes/gj_aes.h | 22 + duix-sdk/src/main/cpp/aes/gj_dll.h | 21 + duix-sdk/src/main/cpp/aes/makefile | 3 + duix-sdk/src/main/cpp/aes/modes.h | 22 + duix-sdk/src/main/cpp/android/DuixJni.cpp | 243 + duix-sdk/src/main/cpp/android/JniHelper.cpp | 384 + duix-sdk/src/main/cpp/android/JniHelper.h | 50 + duix-sdk/src/main/cpp/android/Log.cpp | 80 + duix-sdk/src/main/cpp/android/Log.h | 44 + duix-sdk/src/main/cpp/dhcore/atomicops.h | 761 ++ .../main/cpp/dhcore/blockingconcurrentqueue.h | 582 ++ .../src/main/cpp/dhcore/concurrentqueue.h | 3747 ++++++++++ duix-sdk/src/main/cpp/dhcore/dh_atomic.h | 1198 ++++ duix-sdk/src/main/cpp/dhcore/dh_data.cpp | 391 + duix-sdk/src/main/cpp/dhcore/dh_data.h | 77 + duix-sdk/src/main/cpp/dhcore/dh_mem.c | 300 + duix-sdk/src/main/cpp/dhcore/dh_mem.h | 28 + duix-sdk/src/main/cpp/dhcore/dh_que.cpp | 241 + duix-sdk/src/main/cpp/dhcore/dh_que.h | 29 + duix-sdk/src/main/cpp/dhcore/dh_types.h | 389 + .../main/cpp/dhcore/lightweightsemaphore.h | 427 ++ .../cpp/dhcore/readerwritercircularbuffer.h | 321 + .../src/main/cpp/dhcore/readerwriterqueue.h | 979 +++ duix-sdk/src/main/cpp/dhmfcc/AudioFFT.cpp | 1146 +++ duix-sdk/src/main/cpp/dhmfcc/dhpcm.cpp | 803 +++ duix-sdk/src/main/cpp/dhmfcc/dhpcm.h | 168 + duix-sdk/src/main/cpp/dhmfcc/dhwenet.cpp | 44 + duix-sdk/src/main/cpp/dhmfcc/dhwenet.h | 14 + duix-sdk/src/main/cpp/dhmfcc/iir_filter.cpp | 310 + duix-sdk/src/main/cpp/dhmfcc/mfcc.cpp | 369 + .../src/main/cpp/dhmfcc/mfcc/AudioFFT.hpp | 120 + .../src/main/cpp/dhmfcc/mfcc/iir_filter.hpp | 69 + duix-sdk/src/main/cpp/dhmfcc/mfcc/mfcc.hpp | 7 + duix-sdk/src/main/cpp/dhmfcc/mfcc/sas_util.h | 120 + duix-sdk/src/main/cpp/dhmfcc/wenetai.cpp | 119 + duix-sdk/src/main/cpp/dhmfcc/wenetai.h | 92 + duix-sdk/src/main/cpp/dhmfcc/wenetov.cpp | 134 + duix-sdk/src/main/cpp/dhunet/blendgram.cpp | 437 ++ duix-sdk/src/main/cpp/dhunet/blendgram.h | 287 + duix-sdk/src/main/cpp/dhunet/face_utils.cpp | 133 + duix-sdk/src/main/cpp/dhunet/face_utils.h | 21 + duix-sdk/src/main/cpp/dhunet/jmat.cpp | 507 ++ duix-sdk/src/main/cpp/dhunet/jmat.h | 99 + duix-sdk/src/main/cpp/dhunet/malpha.cpp | 184 + duix-sdk/src/main/cpp/dhunet/malpha.h | 56 + duix-sdk/src/main/cpp/dhunet/munet.cpp | 275 + duix-sdk/src/main/cpp/dhunet/munet.h | 31 + duix-sdk/src/main/cpp/duix/gjduix.cpp | 290 + duix-sdk/src/main/cpp/duix/gjduix.h | 38 + duix-sdk/src/main/cpp/duix/gjsimp.cpp | 453 ++ duix-sdk/src/main/cpp/include/aicommon.h | 39 + duix-sdk/src/main/cpp/include/dhextctrl.h | 55 + duix-sdk/src/main/cpp/include/dhextend.h | 62 + duix-sdk/src/main/cpp/include/dhextinc.h | 22 + duix-sdk/src/main/cpp/include/gj_dll.h | 21 + duix-sdk/src/main/cpp/include/gjduix.h | 38 + duix-sdk/src/main/cpp/include/gjsimp.h | 52 + duix-sdk/src/main/cpp/iostest/testduix.cpp | 129 + duix-sdk/src/main/cpp/iostest/testsimp.cpp | 200 + duix-sdk/src/main/cpp/mk/Android.mk64 | 37 + duix-sdk/src/main/cpp/mk/android.sh | 17 + duix-sdk/src/main/cpp/mk/bt | 58 + duix-sdk/src/main/cpp/mk/exbuildso64 | 4 + .../ffmpeg-lite/build_free_arm64_lite.sh | 119 + .../ffmpeg-lite/build_free_arm_lite.sh | 119 + .../main/cpp/third/arm/armeabi-v7a/libcurl.la | 41 + .../arm/include/ffmpeg/libavcodec/avcodec.h | 6342 +++++++++++++++++ .../arm/include/ffmpeg/libavcodec/avdct.h | 84 + .../arm/include/ffmpeg/libavcodec/avfft.h | 118 + .../arm/include/ffmpeg/libavcodec/d3d11va.h | 112 + .../arm/include/ffmpeg/libavcodec/dirac.h | 131 + .../include/ffmpeg/libavcodec/dv_profile.h | 83 + .../arm/include/ffmpeg/libavcodec/dxva2.h | 93 + .../third/arm/include/ffmpeg/libavcodec/jni.h | 46 + .../include/ffmpeg/libavcodec/mediacodec.h | 88 + .../third/arm/include/ffmpeg/libavcodec/qsv.h | 107 + .../arm/include/ffmpeg/libavcodec/vaapi.h | 195 + .../third/arm/include/ffmpeg/libavcodec/vda.h | 230 + .../arm/include/ffmpeg/libavcodec/vdpau.h | 253 + .../arm/include/ffmpeg/libavcodec/version.h | 243 + .../include/ffmpeg/libavcodec/videotoolbox.h | 127 + .../include/ffmpeg/libavcodec/vorbis_parser.h | 77 + .../arm/include/ffmpeg/libavcodec/xvmc.h | 170 + .../arm/include/ffmpeg/libavdevice/avdevice.h | 514 ++ .../arm/include/ffmpeg/libavdevice/version.h | 50 + .../arm/include/ffmpeg/libavfilter/avfilter.h | 1182 +++ .../ffmpeg/libavfilter/avfiltergraph.h | 28 + .../include/ffmpeg/libavfilter/buffersink.h | 165 + .../include/ffmpeg/libavfilter/buffersrc.h | 201 + .../arm/include/ffmpeg/libavfilter/version.h | 74 + .../arm/include/ffmpeg/libavformat/avformat.h | 3008 ++++++++ .../arm/include/ffmpeg/libavformat/avio.h | 827 +++ .../arm/include/ffmpeg/libavformat/version.h | 105 + .../arm/include/ffmpeg/libavutil/adler32.h | 60 + .../third/arm/include/ffmpeg/libavutil/aes.h | 65 + .../arm/include/ffmpeg/libavutil/aes_ctr.h | 83 + .../arm/include/ffmpeg/libavutil/attributes.h | 167 + .../arm/include/ffmpeg/libavutil/audio_fifo.h | 187 + .../arm/include/ffmpeg/libavutil/avassert.h | 75 + .../arm/include/ffmpeg/libavutil/avconfig.h | 6 + .../arm/include/ffmpeg/libavutil/avstring.h | 402 ++ .../arm/include/ffmpeg/libavutil/avutil.h | 365 + .../arm/include/ffmpeg/libavutil/base64.h | 72 + .../arm/include/ffmpeg/libavutil/blowfish.h | 82 + .../arm/include/ffmpeg/libavutil/bprint.h | 219 + .../arm/include/ffmpeg/libavutil/bswap.h | 109 + .../arm/include/ffmpeg/libavutil/buffer.h | 291 + .../arm/include/ffmpeg/libavutil/camellia.h | 70 + .../arm/include/ffmpeg/libavutil/cast5.h | 80 + .../include/ffmpeg/libavutil/channel_layout.h | 232 + .../arm/include/ffmpeg/libavutil/common.h | 530 ++ .../third/arm/include/ffmpeg/libavutil/cpu.h | 116 + .../third/arm/include/ffmpeg/libavutil/crc.h | 103 + .../third/arm/include/ffmpeg/libavutil/des.h | 77 + .../third/arm/include/ffmpeg/libavutil/dict.h | 200 + .../arm/include/ffmpeg/libavutil/display.h | 87 + .../include/ffmpeg/libavutil/downmix_info.h | 115 + .../arm/include/ffmpeg/libavutil/error.h | 126 + .../third/arm/include/ffmpeg/libavutil/eval.h | 113 + .../arm/include/ffmpeg/libavutil/ffversion.h | 5 + .../third/arm/include/ffmpeg/libavutil/fifo.h | 179 + .../third/arm/include/ffmpeg/libavutil/file.h | 69 + .../arm/include/ffmpeg/libavutil/frame.h | 746 ++ .../third/arm/include/ffmpeg/libavutil/hash.h | 263 + .../third/arm/include/ffmpeg/libavutil/hmac.h | 100 + .../arm/include/ffmpeg/libavutil/hwcontext.h | 523 ++ .../include/ffmpeg/libavutil/hwcontext_cuda.h | 51 + .../ffmpeg/libavutil/hwcontext_dxva2.h | 72 + .../include/ffmpeg/libavutil/hwcontext_qsv.h | 53 + .../ffmpeg/libavutil/hwcontext_vaapi.h | 110 + .../ffmpeg/libavutil/hwcontext_vdpau.h | 44 + .../arm/include/ffmpeg/libavutil/imgutils.h | 246 + .../arm/include/ffmpeg/libavutil/intfloat.h | 77 + .../include/ffmpeg/libavutil/intreadwrite.h | 634 ++ .../third/arm/include/ffmpeg/libavutil/lfg.h | 71 + .../third/arm/include/ffmpeg/libavutil/log.h | 376 + .../third/arm/include/ffmpeg/libavutil/lzo.h | 66 + .../arm/include/ffmpeg/libavutil/macros.h | 50 + .../libavutil/mastering_display_metadata.h | 89 + .../include/ffmpeg/libavutil/mathematics.h | 242 + .../third/arm/include/ffmpeg/libavutil/md5.h | 89 + .../third/arm/include/ffmpeg/libavutil/mem.h | 699 ++ .../include/ffmpeg/libavutil/motion_vector.h | 57 + .../arm/include/ffmpeg/libavutil/murmur3.h | 114 + .../third/arm/include/ffmpeg/libavutil/opt.h | 866 +++ .../arm/include/ffmpeg/libavutil/parseutils.h | 193 + .../arm/include/ffmpeg/libavutil/pixdesc.h | 399 ++ .../arm/include/ffmpeg/libavutil/pixelutils.h | 52 + .../arm/include/ffmpeg/libavutil/pixfmt.h | 510 ++ .../include/ffmpeg/libavutil/random_seed.h | 43 + .../arm/include/ffmpeg/libavutil/rational.h | 214 + .../third/arm/include/ffmpeg/libavutil/rc4.h | 66 + .../arm/include/ffmpeg/libavutil/replaygain.h | 50 + .../arm/include/ffmpeg/libavutil/ripemd.h | 83 + .../arm/include/ffmpeg/libavutil/samplefmt.h | 272 + .../third/arm/include/ffmpeg/libavutil/sha.h | 90 + .../arm/include/ffmpeg/libavutil/sha512.h | 92 + .../arm/include/ffmpeg/libavutil/spherical.h | 232 + .../arm/include/ffmpeg/libavutil/stereo3d.h | 170 + .../third/arm/include/ffmpeg/libavutil/tea.h | 71 + .../include/ffmpeg/libavutil/threadmessage.h | 107 + .../third/arm/include/ffmpeg/libavutil/time.h | 56 + .../arm/include/ffmpeg/libavutil/timecode.h | 140 + .../arm/include/ffmpeg/libavutil/timestamp.h | 78 + .../third/arm/include/ffmpeg/libavutil/tree.h | 138 + .../arm/include/ffmpeg/libavutil/twofish.h | 70 + .../arm/include/ffmpeg/libavutil/version.h | 145 + .../third/arm/include/ffmpeg/libavutil/xtea.h | 94 + .../include/ffmpeg/libswresample/swresample.h | 583 ++ .../include/ffmpeg/libswresample/version.h | 45 + .../arm/include/ffmpeg/libswscale/swscale.h | 336 + .../arm/include/ffmpeg/libswscale/version.h | 53 + .../cpp/third/arm/include/ncnn/allocator.h | 448 ++ .../cpp/third/arm/include/ncnn/benchmark.h | 39 + .../main/cpp/third/arm/include/ncnn/blob.h | 44 + .../main/cpp/third/arm/include/ncnn/c_api.h | 347 + .../main/cpp/third/arm/include/ncnn/command.h | 136 + .../src/main/cpp/third/arm/include/ncnn/cpu.h | 178 + .../cpp/third/arm/include/ncnn/datareader.h | 122 + .../src/main/cpp/third/arm/include/ncnn/gpu.h | 392 + .../main/cpp/third/arm/include/ncnn/layer.h | 222 + .../arm/include/ncnn/layer_shader_type.h | 29 + .../arm/include/ncnn/layer_shader_type_enum.h | 5 + .../cpp/third/arm/include/ncnn/layer_type.h | 30 + .../third/arm/include/ncnn/layer_type_enum.h | 109 + .../src/main/cpp/third/arm/include/ncnn/mat.h | 1843 +++++ .../cpp/third/arm/include/ncnn/modelbin.h | 80 + .../cpp/third/arm/include/ncnn/ncnn_export.h | 42 + .../src/main/cpp/third/arm/include/ncnn/net.h | 274 + .../main/cpp/third/arm/include/ncnn/option.h | 156 + .../cpp/third/arm/include/ncnn/paramdict.h | 73 + .../cpp/third/arm/include/ncnn/pipeline.h | 113 + .../third/arm/include/ncnn/pipelinecache.h | 85 + .../cpp/third/arm/include/ncnn/platform.h | 293 + .../cpp/third/arm/include/ncnn/simplemath.h | 102 + .../cpp/third/arm/include/ncnn/simpleocv.h | 503 ++ .../cpp/third/arm/include/ncnn/simpleomp.h | 53 + .../cpp/third/arm/include/ncnn/simplestl.h | 565 ++ .../arm/include/ncnn/vulkan_header_fix.h | 449 ++ .../arm/include/onnx/cpu_provider_factory.h | 19 + .../arm/include/onnx/nnapi_provider_factory.h | 62 + .../arm/include/onnx/onnxruntime_c_api.h | 4550 ++++++++++++ .../arm/include/onnx/onnxruntime_cxx_api.h | 2268 ++++++ .../arm/include/onnx/onnxruntime_cxx_inline.h | 1886 +++++ .../arm/include/onnx/onnxruntime_float16.h | 540 ++ .../cpp/third/arm/include/opencv2/core.hpp | 3354 +++++++++ .../third/arm/include/opencv2/core/affine.hpp | 678 ++ .../third/arm/include/opencv2/core/async.hpp | 105 + .../third/arm/include/opencv2/core/base.hpp | 664 ++ .../include/opencv2/core/bindings_utils.hpp | 287 + .../arm/include/opencv2/core/bufferpool.hpp | 40 + .../third/arm/include/opencv2/core/check.hpp | 160 + .../third/arm/include/opencv2/core/core.hpp | 48 + .../third/arm/include/opencv2/core/core_c.h | 3128 ++++++++ .../third/arm/include/opencv2/core/cuda.hpp | 1271 ++++ .../arm/include/opencv2/core/cuda.inl.hpp | 723 ++ .../arm/include/opencv2/core/cuda/block.hpp | 211 + .../opencv2/core/cuda/border_interpolate.hpp | 722 ++ .../arm/include/opencv2/core/cuda/color.hpp | 309 + .../arm/include/opencv2/core/cuda/common.hpp | 123 + .../opencv2/core/cuda/datamov_utils.hpp | 113 + .../opencv2/core/cuda/detail/color_detail.hpp | 2018 ++++++ .../opencv2/core/cuda/detail/reduce.hpp | 365 + .../core/cuda/detail/reduce_key_val.hpp | 502 ++ .../core/cuda/detail/transform_detail.hpp | 392 + .../core/cuda/detail/type_traits_detail.hpp | 191 + .../core/cuda/detail/vec_distance_detail.hpp | 121 + .../opencv2/core/cuda/dynamic_smem.hpp | 88 + .../include/opencv2/core/cuda/emulation.hpp | 269 + .../arm/include/opencv2/core/cuda/filters.hpp | 293 + .../include/opencv2/core/cuda/funcattrib.hpp | 79 + .../include/opencv2/core/cuda/functional.hpp | 805 +++ .../arm/include/opencv2/core/cuda/limits.hpp | 128 + .../arm/include/opencv2/core/cuda/reduce.hpp | 209 + .../opencv2/core/cuda/saturate_cast.hpp | 292 + .../arm/include/opencv2/core/cuda/scan.hpp | 258 + .../opencv2/core/cuda/simd_functions.hpp | 869 +++ .../include/opencv2/core/cuda/transform.hpp | 75 + .../include/opencv2/core/cuda/type_traits.hpp | 90 + .../arm/include/opencv2/core/cuda/utility.hpp | 230 + .../opencv2/core/cuda/vec_distance.hpp | 232 + .../include/opencv2/core/cuda/vec_math.hpp | 923 +++ .../include/opencv2/core/cuda/vec_traits.hpp | 288 + .../arm/include/opencv2/core/cuda/warp.hpp | 139 + .../include/opencv2/core/cuda/warp_reduce.hpp | 76 + .../opencv2/core/cuda/warp_shuffle.hpp | 162 + .../opencv2/core/cuda_stream_accessor.hpp | 86 + .../arm/include/opencv2/core/cuda_types.hpp | 144 + .../include/opencv2/core/cv_cpu_dispatch.h | 368 + .../arm/include/opencv2/core/cv_cpu_helper.h | 508 ++ .../third/arm/include/opencv2/core/cvdef.h | 967 +++ .../third/arm/include/opencv2/core/cvstd.hpp | 190 + .../arm/include/opencv2/core/cvstd.inl.hpp | 197 + .../include/opencv2/core/cvstd_wrapper.hpp | 154 + .../opencv2/core/detail/async_promise.hpp | 71 + .../core/detail/dispatch_helper.impl.hpp | 49 + .../opencv2/core/detail/exception_ptr.hpp | 27 + .../arm/include/opencv2/core/directx.hpp | 184 + .../include/opencv2/core/dualquaternion.hpp | 979 +++ .../opencv2/core/dualquaternion.inl.hpp | 487 ++ .../third/arm/include/opencv2/core/eigen.hpp | 402 ++ .../arm/include/opencv2/core/fast_math.hpp | 411 ++ .../arm/include/opencv2/core/hal/hal.hpp | 256 + .../arm/include/opencv2/core/hal/interface.h | 190 + .../arm/include/opencv2/core/hal/intrin.hpp | 706 ++ .../include/opencv2/core/hal/intrin_avx.hpp | 3177 +++++++++ .../opencv2/core/hal/intrin_avx512.hpp | 3090 ++++++++ .../include/opencv2/core/hal/intrin_cpp.hpp | 3320 +++++++++ .../opencv2/core/hal/intrin_forward.hpp | 191 + .../include/opencv2/core/hal/intrin_msa.hpp | 1887 +++++ .../include/opencv2/core/hal/intrin_neon.hpp | 2615 +++++++ .../include/opencv2/core/hal/intrin_rvv.hpp | 3320 +++++++++ .../opencv2/core/hal/intrin_rvv071.hpp | 2545 +++++++ .../include/opencv2/core/hal/intrin_sse.hpp | 3467 +++++++++ .../opencv2/core/hal/intrin_sse_em.hpp | 180 + .../include/opencv2/core/hal/intrin_vsx.hpp | 1608 +++++ .../include/opencv2/core/hal/intrin_wasm.hpp | 2782 ++++++++ .../arm/include/opencv2/core/hal/msa_macros.h | 1558 ++++ .../opencv2/core/hal/simd_utils.impl.hpp | 146 + .../third/arm/include/opencv2/core/mat.hpp | 3775 ++++++++++ .../arm/include/opencv2/core/mat.inl.hpp | 3422 +++++++++ .../third/arm/include/opencv2/core/matx.hpp | 1528 ++++ .../arm/include/opencv2/core/neon_utils.hpp | 128 + .../third/arm/include/opencv2/core/ocl.hpp | 902 +++ .../arm/include/opencv2/core/ocl_genbase.hpp | 69 + .../include/opencv2/core/opencl/ocl_defs.hpp | 82 + .../opencv2/core/opencl/opencl_info.hpp | 212 + .../opencv2/core/opencl/opencl_svm.hpp | 81 + .../runtime/autogenerated/opencl_clblas.hpp | 602 ++ .../runtime/autogenerated/opencl_clfft.hpp | 146 + .../runtime/autogenerated/opencl_core.hpp | 371 + .../autogenerated/opencl_core_wrappers.hpp | 272 + .../runtime/autogenerated/opencl_gl.hpp | 62 + .../autogenerated/opencl_gl_wrappers.hpp | 42 + .../core/opencl/runtime/opencl_clblas.hpp | 53 + .../core/opencl/runtime/opencl_clfft.hpp | 53 + .../core/opencl/runtime/opencl_core.hpp | 84 + .../opencl/runtime/opencl_core_wrappers.hpp | 47 + .../opencv2/core/opencl/runtime/opencl_gl.hpp | 53 + .../opencl/runtime/opencl_gl_wrappers.hpp | 47 + .../core/opencl/runtime/opencl_svm_20.hpp | 48 + .../opencl/runtime/opencl_svm_definitions.hpp | 42 + .../runtime/opencl_svm_hsa_extension.hpp | 166 + .../third/arm/include/opencv2/core/opengl.hpp | 725 ++ .../arm/include/opencv2/core/operations.hpp | 610 ++ .../third/arm/include/opencv2/core/optim.hpp | 302 + .../third/arm/include/opencv2/core/ovx.hpp | 28 + .../parallel/backend/parallel_for.openmp.hpp | 72 + .../parallel/backend/parallel_for.tbb.hpp | 153 + .../core/parallel/parallel_backend.hpp | 90 + .../arm/include/opencv2/core/persistence.hpp | 1350 ++++ .../arm/include/opencv2/core/quaternion.hpp | 1696 +++++ .../include/opencv2/core/quaternion.inl.hpp | 1063 +++ .../arm/include/opencv2/core/saturate.hpp | 179 + .../include/opencv2/core/simd_intrinsics.hpp | 87 + .../arm/include/opencv2/core/softfloat.hpp | 514 ++ .../arm/include/opencv2/core/sse_utils.hpp | 652 ++ .../third/arm/include/opencv2/core/traits.hpp | 417 ++ .../third/arm/include/opencv2/core/types.hpp | 2439 +++++++ .../third/arm/include/opencv2/core/types_c.h | 2126 ++++++ .../arm/include/opencv2/core/utility.hpp | 1229 ++++ .../opencv2/core/utils/allocator_stats.hpp | 29 + .../core/utils/allocator_stats.impl.hpp | 158 + .../include/opencv2/core/utils/filesystem.hpp | 82 + .../opencv2/core/utils/fp_control_utils.hpp | 69 + .../opencv2/core/utils/instrumentation.hpp | 125 + .../opencv2/core/utils/logger.defines.hpp | 42 + .../arm/include/opencv2/core/utils/logger.hpp | 218 + .../arm/include/opencv2/core/utils/logtag.hpp | 28 + .../arm/include/opencv2/core/utils/tls.hpp | 235 + .../arm/include/opencv2/core/utils/trace.hpp | 252 + .../arm/include/opencv2/core/va_intel.hpp | 75 + .../arm/include/opencv2/core/version.hpp | 26 + .../arm/include/opencv2/core/vsx_utils.hpp | 1047 +++ .../cpp/third/arm/include/opencv2/cvconfig.h | 149 + .../third/arm/include/opencv2/features2d.hpp | 1535 ++++ .../include/opencv2/features2d/features2d.hpp | 48 + .../opencv2/features2d/hal/interface.h | 33 + .../cpp/third/arm/include/opencv2/highgui.hpp | 17 + .../arm/include/opencv2/highgui/highgui.hpp | 62 + .../cpp/third/arm/include/opencv2/imgproc.hpp | 5005 +++++++++++++ .../arm/include/opencv2/imgproc/bindings.hpp | 34 + .../opencv2/imgproc/detail/gcgraph.hpp | 395 + .../arm/include/opencv2/imgproc/hal/hal.hpp | 246 + .../include/opencv2/imgproc/hal/interface.h | 46 + .../arm/include/opencv2/imgproc/imgproc.hpp | 48 + .../arm/include/opencv2/imgproc/imgproc_c.h | 1177 +++ .../include/opencv2/imgproc/segmentation.hpp | 141 + .../arm/include/opencv2/imgproc/types_c.h | 659 ++ .../cpp/third/arm/include/opencv2/opencv.hpp | 95 + .../arm/include/opencv2/opencv_modules.hpp | 20 + .../cpp/third/arm/include/opencv2/photo.hpp | 858 +++ .../third/arm/include/opencv2/photo/cuda.hpp | 132 + .../opencv2/photo/legacy/constants_c.h | 14 + .../third/arm/include/opencv2/photo/photo.hpp | 48 + .../cpp/third/arm/include/opencv2/video.hpp | 59 + .../include/opencv2/video/background_segm.hpp | 317 + .../opencv2/video/detail/tracking.detail.hpp | 406 ++ .../opencv2/video/legacy/constants_c.h | 16 + .../arm/include/opencv2/video/tracking.hpp | 857 +++ .../third/arm/include/opencv2/video/video.hpp | 48 + .../src/main/cpp/third/arm/include/rknn_api.h | 697 ++ .../main/cpp/third/arm/include/tjpeg/bmp.h | 46 + .../cpp/third/arm/include/tjpeg/cderror.h | 134 + .../main/cpp/third/arm/include/tjpeg/cdjpeg.h | 187 + .../main/cpp/third/arm/include/tjpeg/config.h | 131 + .../third/arm/include/tjpeg/cpu-features.h | 198 + .../main/cpp/third/arm/include/tjpeg/jchuff.h | 47 + .../cpp/third/arm/include/tjpeg/jconfig.h | 62 + .../main/cpp/third/arm/include/tjpeg/jdct.h | 184 + .../main/cpp/third/arm/include/tjpeg/jdhuff.h | 235 + .../main/cpp/third/arm/include/tjpeg/jerror.h | 314 + .../cpp/third/arm/include/tjpeg/jinclude.h | 91 + .../cpp/third/arm/include/tjpeg/jmemsys.h | 198 + .../cpp/third/arm/include/tjpeg/jmorecfg.h | 446 ++ .../cpp/third/arm/include/tjpeg/jpegcomp.h | 26 + .../cpp/third/arm/include/tjpeg/jpegint.h | 460 ++ .../cpp/third/arm/include/tjpeg/jpeglib.h | 1611 +++++ .../main/cpp/third/arm/include/tjpeg/jsimd.h | 666 ++ .../third/arm/include/tjpeg/jsimdcfg.inc.h | 199 + .../cpp/third/arm/include/tjpeg/jsimddct.h | 102 + .../cpp/third/arm/include/tjpeg/jversion.h | 36 + .../cpp/third/arm/include/tjpeg/platform.h | 11 + .../main/cpp/third/arm/include/tjpeg/tjutil.h | 47 + .../cpp/third/arm/include/tjpeg/transupp.h | 217 + .../cpp/third/arm/include/tjpeg/turbojpeg.h | 897 +++ .../cpp/third/arm/include/turbojpeg/jconfig.h | 60 + .../cpp/third/arm/include/turbojpeg/jerror.h | 336 + .../third/arm/include/turbojpeg/jmorecfg.h | 385 + .../cpp/third/arm/include/turbojpeg/jpeglib.h | 1209 ++++ .../third/arm/include/turbojpeg/turbojpeg.h | 2286 ++++++ .../arm64-v8a/include/ncnn/allocator.h | 448 ++ .../arm64-v8a/include/ncnn/benchmark.h | 36 + .../arm64-v8a/include/ncnn/blob.h | 44 + .../arm64-v8a/include/ncnn/c_api.h | 327 + .../arm64-v8a/include/ncnn/command.h | 136 + .../arm64-v8a/include/ncnn/cpu.h | 169 + .../arm64-v8a/include/ncnn/datareader.h | 122 + .../arm64-v8a/include/ncnn/gpu.h | 359 + .../arm64-v8a/include/ncnn/layer.h | 214 + .../include/ncnn/layer_shader_type.h | 29 + .../include/ncnn/layer_shader_type_enum.h | 370 + .../arm64-v8a/include/ncnn/layer_type.h | 30 + .../arm64-v8a/include/ncnn/layer_type_enum.h | 103 + .../arm64-v8a/include/ncnn/mat.h | 1843 +++++ .../arm64-v8a/include/ncnn/modelbin.h | 80 + .../arm64-v8a/include/ncnn/ncnn_export.h | 42 + .../arm64-v8a/include/ncnn/net.h | 272 + .../arm64-v8a/include/ncnn/option.h | 153 + .../arm64-v8a/include/ncnn/paramdict.h | 73 + .../arm64-v8a/include/ncnn/pipeline.h | 113 + .../arm64-v8a/include/ncnn/pipelinecache.h | 85 + .../arm64-v8a/include/ncnn/platform.h | 285 + .../arm64-v8a/include/ncnn/simpleocv.h | 501 ++ .../arm64-v8a/include/ncnn/simpleomp.h | 53 + .../arm64-v8a/include/ncnn/simplestl.h | 565 ++ .../include/ncnn/vulkan_header_fix.h | 251 + .../lib/cmake/ncnn/ncnn-release.cmake | 19 + .../arm64-v8a/lib/cmake/ncnn/ncnn.cmake | 109 + .../arm64-v8a/lib/cmake/ncnn/ncnnConfig.cmake | 42 + .../arm64-v8a/lib/pkgconfig/ncnn.pc | 11 + .../armeabi-v7a/include/ncnn/allocator.h | 448 ++ .../armeabi-v7a/include/ncnn/benchmark.h | 36 + .../armeabi-v7a/include/ncnn/blob.h | 44 + .../armeabi-v7a/include/ncnn/c_api.h | 327 + .../armeabi-v7a/include/ncnn/command.h | 136 + .../armeabi-v7a/include/ncnn/cpu.h | 169 + .../armeabi-v7a/include/ncnn/datareader.h | 122 + .../armeabi-v7a/include/ncnn/gpu.h | 359 + .../armeabi-v7a/include/ncnn/layer.h | 214 + .../include/ncnn/layer_shader_type.h | 29 + .../include/ncnn/layer_shader_type_enum.h | 370 + .../armeabi-v7a/include/ncnn/layer_type.h | 30 + .../include/ncnn/layer_type_enum.h | 103 + .../armeabi-v7a/include/ncnn/mat.h | 1843 +++++ .../armeabi-v7a/include/ncnn/modelbin.h | 80 + .../armeabi-v7a/include/ncnn/ncnn_export.h | 42 + .../armeabi-v7a/include/ncnn/net.h | 272 + .../armeabi-v7a/include/ncnn/option.h | 153 + .../armeabi-v7a/include/ncnn/paramdict.h | 73 + .../armeabi-v7a/include/ncnn/pipeline.h | 113 + .../armeabi-v7a/include/ncnn/pipelinecache.h | 85 + .../armeabi-v7a/include/ncnn/platform.h | 285 + .../armeabi-v7a/include/ncnn/simpleocv.h | 501 ++ .../armeabi-v7a/include/ncnn/simpleomp.h | 53 + .../armeabi-v7a/include/ncnn/simplestl.h | 565 ++ .../include/ncnn/vulkan_header_fix.h | 251 + .../lib/cmake/ncnn/ncnn-release.cmake | 19 + .../armeabi-v7a/lib/cmake/ncnn/ncnn.cmake | 109 + .../lib/cmake/ncnn/ncnnConfig.cmake | 42 + .../armeabi-v7a/lib/pkgconfig/ncnn.pc | 11 + .../x86/include/ncnn/allocator.h | 448 ++ .../x86/include/ncnn/benchmark.h | 36 + .../x86/include/ncnn/blob.h | 44 + .../x86/include/ncnn/c_api.h | 327 + .../x86/include/ncnn/command.h | 136 + .../x86/include/ncnn/cpu.h | 169 + .../x86/include/ncnn/datareader.h | 122 + .../x86/include/ncnn/gpu.h | 359 + .../x86/include/ncnn/layer.h | 214 + .../x86/include/ncnn/layer_shader_type.h | 29 + .../x86/include/ncnn/layer_shader_type_enum.h | 370 + .../x86/include/ncnn/layer_type.h | 30 + .../x86/include/ncnn/layer_type_enum.h | 103 + .../x86/include/ncnn/mat.h | 1843 +++++ .../x86/include/ncnn/modelbin.h | 80 + .../x86/include/ncnn/ncnn_export.h | 42 + .../x86/include/ncnn/net.h | 272 + .../x86/include/ncnn/option.h | 153 + .../x86/include/ncnn/paramdict.h | 73 + .../x86/include/ncnn/pipeline.h | 113 + .../x86/include/ncnn/pipelinecache.h | 85 + .../x86/include/ncnn/platform.h | 285 + .../x86/include/ncnn/simpleocv.h | 501 ++ .../x86/include/ncnn/simpleomp.h | 53 + .../x86/include/ncnn/simplestl.h | 565 ++ .../x86/include/ncnn/vulkan_header_fix.h | 251 + .../x86/lib/cmake/ncnn/ncnn-release.cmake | 19 + .../x86/lib/cmake/ncnn/ncnn.cmake | 109 + .../x86/lib/cmake/ncnn/ncnnConfig.cmake | 42 + .../x86/lib/pkgconfig/ncnn.pc | 11 + .../x86_64/include/ncnn/allocator.h | 448 ++ .../x86_64/include/ncnn/benchmark.h | 36 + .../x86_64/include/ncnn/blob.h | 44 + .../x86_64/include/ncnn/c_api.h | 327 + .../x86_64/include/ncnn/command.h | 136 + .../x86_64/include/ncnn/cpu.h | 169 + .../x86_64/include/ncnn/datareader.h | 122 + .../x86_64/include/ncnn/gpu.h | 359 + .../x86_64/include/ncnn/layer.h | 214 + .../x86_64/include/ncnn/layer_shader_type.h | 29 + .../include/ncnn/layer_shader_type_enum.h | 370 + .../x86_64/include/ncnn/layer_type.h | 30 + .../x86_64/include/ncnn/layer_type_enum.h | 103 + .../x86_64/include/ncnn/mat.h | 1843 +++++ .../x86_64/include/ncnn/modelbin.h | 80 + .../x86_64/include/ncnn/ncnn_export.h | 42 + .../x86_64/include/ncnn/net.h | 272 + .../x86_64/include/ncnn/option.h | 153 + .../x86_64/include/ncnn/paramdict.h | 73 + .../x86_64/include/ncnn/pipeline.h | 113 + .../x86_64/include/ncnn/pipelinecache.h | 85 + .../x86_64/include/ncnn/platform.h | 285 + .../x86_64/include/ncnn/simpleocv.h | 501 ++ .../x86_64/include/ncnn/simpleomp.h | 53 + .../x86_64/include/ncnn/simplestl.h | 565 ++ .../x86_64/include/ncnn/vulkan_header_fix.h | 251 + .../x86_64/lib/cmake/ncnn/ncnn-release.cmake | 19 + .../x86_64/lib/cmake/ncnn/ncnn.cmake | 109 + .../x86_64/lib/cmake/ncnn/ncnnConfig.cmake | 42 + .../x86_64/lib/pkgconfig/ncnn.pc | 11 + .../arm64-v8a/include/ncnn/allocator.h | 448 ++ .../arm64-v8a/include/ncnn/benchmark.h | 39 + .../arm64-v8a/include/ncnn/blob.h | 44 + .../arm64-v8a/include/ncnn/c_api.h | 347 + .../arm64-v8a/include/ncnn/command.h | 136 + .../arm64-v8a/include/ncnn/cpu.h | 178 + .../arm64-v8a/include/ncnn/datareader.h | 122 + .../arm64-v8a/include/ncnn/gpu.h | 392 + .../arm64-v8a/include/ncnn/layer.h | 222 + .../include/ncnn/layer_shader_type.h | 29 + .../include/ncnn/layer_shader_type_enum.h | 5 + .../arm64-v8a/include/ncnn/layer_type.h | 30 + .../arm64-v8a/include/ncnn/layer_type_enum.h | 109 + .../arm64-v8a/include/ncnn/mat.h | 1843 +++++ .../arm64-v8a/include/ncnn/modelbin.h | 80 + .../arm64-v8a/include/ncnn/ncnn_export.h | 42 + .../arm64-v8a/include/ncnn/net.h | 274 + .../arm64-v8a/include/ncnn/option.h | 156 + .../arm64-v8a/include/ncnn/paramdict.h | 73 + .../arm64-v8a/include/ncnn/pipeline.h | 113 + .../arm64-v8a/include/ncnn/pipelinecache.h | 85 + .../arm64-v8a/include/ncnn/platform.h | 293 + .../arm64-v8a/include/ncnn/simplemath.h | 102 + .../arm64-v8a/include/ncnn/simpleocv.h | 503 ++ .../arm64-v8a/include/ncnn/simpleomp.h | 53 + .../arm64-v8a/include/ncnn/simplestl.h | 565 ++ .../include/ncnn/vulkan_header_fix.h | 449 ++ .../lib/cmake/ncnn/ncnn-release.cmake | 19 + .../arm64-v8a/lib/cmake/ncnn/ncnn.cmake | 109 + .../arm64-v8a/lib/cmake/ncnn/ncnnConfig.cmake | 42 + .../arm64-v8a/lib/pkgconfig/ncnn.pc | 11 + .../armeabi-v7a/include/ncnn/allocator.h | 448 ++ .../armeabi-v7a/include/ncnn/benchmark.h | 39 + .../armeabi-v7a/include/ncnn/blob.h | 44 + .../armeabi-v7a/include/ncnn/c_api.h | 347 + .../armeabi-v7a/include/ncnn/command.h | 136 + .../armeabi-v7a/include/ncnn/cpu.h | 178 + .../armeabi-v7a/include/ncnn/datareader.h | 122 + .../armeabi-v7a/include/ncnn/gpu.h | 392 + .../armeabi-v7a/include/ncnn/layer.h | 222 + .../include/ncnn/layer_shader_type.h | 29 + .../include/ncnn/layer_shader_type_enum.h | 5 + .../armeabi-v7a/include/ncnn/layer_type.h | 30 + .../include/ncnn/layer_type_enum.h | 109 + .../armeabi-v7a/include/ncnn/mat.h | 1843 +++++ .../armeabi-v7a/include/ncnn/modelbin.h | 80 + .../armeabi-v7a/include/ncnn/ncnn_export.h | 42 + .../armeabi-v7a/include/ncnn/net.h | 274 + .../armeabi-v7a/include/ncnn/option.h | 156 + .../armeabi-v7a/include/ncnn/paramdict.h | 73 + .../armeabi-v7a/include/ncnn/pipeline.h | 113 + .../armeabi-v7a/include/ncnn/pipelinecache.h | 85 + .../armeabi-v7a/include/ncnn/platform.h | 293 + .../armeabi-v7a/include/ncnn/simplemath.h | 102 + .../armeabi-v7a/include/ncnn/simpleocv.h | 503 ++ .../armeabi-v7a/include/ncnn/simpleomp.h | 53 + .../armeabi-v7a/include/ncnn/simplestl.h | 565 ++ .../include/ncnn/vulkan_header_fix.h | 449 ++ .../lib/cmake/ncnn/ncnn-release.cmake | 19 + .../armeabi-v7a/lib/cmake/ncnn/ncnn.cmake | 109 + .../lib/cmake/ncnn/ncnnConfig.cmake | 42 + .../armeabi-v7a/lib/pkgconfig/ncnn.pc | 11 + .../x86/include/ncnn/allocator.h | 448 ++ .../x86/include/ncnn/benchmark.h | 39 + .../x86/include/ncnn/blob.h | 44 + .../x86/include/ncnn/c_api.h | 347 + .../x86/include/ncnn/command.h | 136 + .../x86/include/ncnn/cpu.h | 178 + .../x86/include/ncnn/datareader.h | 122 + .../x86/include/ncnn/gpu.h | 392 + .../x86/include/ncnn/layer.h | 222 + .../x86/include/ncnn/layer_shader_type.h | 29 + .../x86/include/ncnn/layer_shader_type_enum.h | 5 + .../x86/include/ncnn/layer_type.h | 30 + .../x86/include/ncnn/layer_type_enum.h | 109 + .../x86/include/ncnn/mat.h | 1843 +++++ .../x86/include/ncnn/modelbin.h | 80 + .../x86/include/ncnn/ncnn_export.h | 42 + .../x86/include/ncnn/net.h | 274 + .../x86/include/ncnn/option.h | 156 + .../x86/include/ncnn/paramdict.h | 73 + .../x86/include/ncnn/pipeline.h | 113 + .../x86/include/ncnn/pipelinecache.h | 85 + .../x86/include/ncnn/platform.h | 293 + .../x86/include/ncnn/simplemath.h | 102 + .../x86/include/ncnn/simpleocv.h | 503 ++ .../x86/include/ncnn/simpleomp.h | 53 + .../x86/include/ncnn/simplestl.h | 565 ++ .../x86/include/ncnn/vulkan_header_fix.h | 449 ++ .../x86/lib/cmake/ncnn/ncnn-release.cmake | 19 + .../x86/lib/cmake/ncnn/ncnn.cmake | 109 + .../x86/lib/cmake/ncnn/ncnnConfig.cmake | 42 + .../x86/lib/pkgconfig/ncnn.pc | 11 + .../x86_64/include/ncnn/allocator.h | 448 ++ .../x86_64/include/ncnn/benchmark.h | 39 + .../x86_64/include/ncnn/blob.h | 44 + .../x86_64/include/ncnn/c_api.h | 347 + .../x86_64/include/ncnn/command.h | 136 + .../x86_64/include/ncnn/cpu.h | 178 + .../x86_64/include/ncnn/datareader.h | 122 + .../x86_64/include/ncnn/gpu.h | 392 + .../x86_64/include/ncnn/layer.h | 222 + .../x86_64/include/ncnn/layer_shader_type.h | 29 + .../include/ncnn/layer_shader_type_enum.h | 5 + .../x86_64/include/ncnn/layer_type.h | 30 + .../x86_64/include/ncnn/layer_type_enum.h | 109 + .../x86_64/include/ncnn/mat.h | 1843 +++++ .../x86_64/include/ncnn/modelbin.h | 80 + .../x86_64/include/ncnn/ncnn_export.h | 42 + .../x86_64/include/ncnn/net.h | 274 + .../x86_64/include/ncnn/option.h | 156 + .../x86_64/include/ncnn/paramdict.h | 73 + .../x86_64/include/ncnn/pipeline.h | 113 + .../x86_64/include/ncnn/pipelinecache.h | 85 + .../x86_64/include/ncnn/platform.h | 293 + .../x86_64/include/ncnn/simplemath.h | 102 + .../x86_64/include/ncnn/simpleocv.h | 503 ++ .../x86_64/include/ncnn/simpleomp.h | 53 + .../x86_64/include/ncnn/simplestl.h | 565 ++ .../x86_64/include/ncnn/vulkan_header_fix.h | 449 ++ .../x86_64/lib/cmake/ncnn/ncnn-release.cmake | 19 + .../x86_64/lib/cmake/ncnn/ncnn.cmake | 109 + .../x86_64/lib/cmake/ncnn/ncnnConfig.cmake | 42 + .../x86_64/lib/pkgconfig/ncnn.pc | 11 + .../src/main/java/ai/guiji/duix/DuixNcnn.java | 34 + .../ai/guiji/duix/sdk/client/Callback.java | 7 + .../ai/guiji/duix/sdk/client/Constant.java | 21 + .../java/ai/guiji/duix/sdk/client/DUIX.java | 231 + .../duix/sdk/client/VirtualModelUtil.java | 162 + .../duix/sdk/client/audio/AudioPlayer.java | 172 + .../duix/sdk/client/bean/AudioFrame.java | 25 + .../duix/sdk/client/bean/ImageFrame.java | 21 + .../sdk/client/net/DownloadZipService.java | 99 + .../duix/sdk/client/net/FileDownloader.java | 75 + .../duix/sdk/client/render/DUIXRenderer.java | 110 + .../sdk/client/render/DUIXTextureView.java | 1832 +++++ .../duix/sdk/client/render/ImageDrawer.java | 176 + .../duix/sdk/client/render/RenderSink.java | 12 + .../duix/sdk/client/render/TextureMatrix.java | 161 + .../duix/sdk/client/thread/RenderThread.java | 460 ++ .../duix/sdk/client/util/DeviceUtils.java | 149 + .../guiji/duix/sdk/client/util/FileUtil.java | 23 + .../ai/guiji/duix/sdk/client/util/Logger.java | 56 + .../guiji/duix/sdk/client/util/MD5Util.java | 172 + .../duix/sdk/client/util/OpenGLUtil.java | 537 ++ .../duix/sdk/client/util/SystemUtils.java | 71 + .../guiji/duix/sdk/client/util/ZipUtil.java | 98 + gradle.properties | 17 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54329 bytes gradle/wrapper/gradle-wrapper.properties | 6 + settings.gradle | 2 + test/.gitignore | 1 + test/build.gradle | 90 + test/lint-baseline.xml | 561 ++ test/proguard-rules.pro | 26 + test/src/main/AndroidManifest.xml | 35 + test/src/main/assets/bg/bg1.png | Bin 0 -> 1022393 bytes test/src/main/assets/bg/bg2.jpg | Bin 0 -> 290851 bytes test/src/main/assets/pcm/2.pcm | Bin 0 -> 179812 bytes test/src/main/assets/pcm/222.pcm | Bin 0 -> 192640 bytes test/src/main/assets/wav/1.wav | Bin 0 -> 55274 bytes test/src/main/assets/wav/2.wav | Bin 0 -> 179856 bytes .../src/main/java/ai/guiji/duix/test/App.java | 31 + .../guiji/duix/test/audio/AudioRecorder.java | 110 + .../guiji/duix/test/audio/AudioResampler.java | 52 + .../test/audio/StreamingAudioRecorder.java | 106 + .../duix/test/camera/CameraFrameCapture.java | 299 + .../guiji/duix/test/net/SyncDownloadFile.java | 83 + .../test/realtime/OmniRealtimeClient.java | 311 + .../ai/guiji/duix/test/render/DebugSink.java | 24 + .../duix/test/service/StorageService.java | 216 + .../duix/test/ui/activity/BaseActivity.java | 119 + .../duix/test/ui/activity/CallActivity.kt | 490 ++ .../duix/test/ui/activity/MainActivity.kt | 203 + .../test/ui/adapter/ModelSelectorAdapter.kt | 39 + .../duix/test/ui/adapter/MotionAdapter.kt | 39 + .../duix/test/ui/dialog/AudioRecordDialog.kt | 96 + .../duix/test/ui/dialog/LoadingDialog.kt | 50 + .../test/ui/dialog/ModelSelectorDialog.kt | 39 + .../ai/guiji/duix/test/util/StringUtils.java | 396 + .../ai/guiji/duix/test/util/SystemUtils.java | 71 + .../java/ai/guiji/duix/test/util/ZipUtil.java | 101 + test/src/main/res/anim/rotate.xml | 13 + .../res/drawable/ic_launcher_background.xml | 170 + .../res/drawable/ic_launcher_foreground.xml | 30 + .../main/res/drawable/selector_60_primary.xml | 5 + .../res/drawable/shape_circle_camera_off.xml | 5 + .../res/drawable/shape_circle_camera_on.xml | 5 + .../main/res/drawable/shape_circle_fab.xml | 5 + .../main/res/drawable/shape_common_btn.xml | 4 + .../drawable/shape_corners_60_99_primary.xml | 5 + .../res/drawable/shape_corners_60_primary.xml | 5 + .../shape_solid_b3000000_radius_7.xml | 4 + .../res/drawable/shape_tl_tr_32_ffffffff.xml | 9 + .../drawable/shape_tl_tr_bl_20_ff147bf7.xml | 8 + .../drawable/shape_tl_tr_br_20_ffd9eaff.xml | 10 + test/src/main/res/layout/activity_call.xml | 180 + test/src/main/res/layout/activity_main.xml | 121 + .../main/res/layout/dialog_audio_record.xml | 36 + test/src/main/res/layout/dialog_loading.xml | 35 + .../main/res/layout/dialog_model_selector.xml | 16 + .../main/res/layout/item_model_selector.xml | 18 + .../main/res/layout/item_motion_button.xml | 17 + .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1404 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2898 bytes .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 982 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1772 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1900 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3918 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2884 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 5914 bytes .../main/res/mipmap-xxhdpi/iv_progress.png | Bin 0 -> 3869 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3844 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 7778 bytes test/src/main/res/values-zh-rCN/strings.xml | 29 + test/src/main/res/values/attrs.xml | 19 + test/src/main/res/values/colors.xml | 12 + test/src/main/res/values/strings.xml | 28 + test/src/main/res/values/style.xml | 15 + test/src/main/res/values/themes.xml | 15 + .../main/res/xml/network_security_config.xml | 4 + 759 files changed, 240072 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 README_zh.md create mode 100644 android_glide_lint.xml create mode 100644 build.gradle create mode 100644 demo.jks create mode 100644 duix-sdk/.gitignore create mode 100644 duix-sdk/build.gradle create mode 100644 duix-sdk/consumer-rules.pro create mode 100644 duix-sdk/libs/resource_loader.jar create mode 100644 duix-sdk/proguard-rules.pro create mode 100644 duix-sdk/src/main/AndroidManifest.xml create mode 100644 duix-sdk/src/main/cpp/CMakeLists.txt create mode 100644 duix-sdk/src/main/cpp/aes/aes.h create mode 100644 duix-sdk/src/main/cpp/aes/aes_cbc.c create mode 100644 duix-sdk/src/main/cpp/aes/aes_core.c create mode 100644 duix-sdk/src/main/cpp/aes/aes_ecb.c create mode 100644 duix-sdk/src/main/cpp/aes/aes_locl.h create mode 100644 duix-sdk/src/main/cpp/aes/aesmain.c create mode 100644 duix-sdk/src/main/cpp/aes/aesmain.h create mode 100644 duix-sdk/src/main/cpp/aes/base64.c create mode 100644 duix-sdk/src/main/cpp/aes/base64.h create mode 100644 duix-sdk/src/main/cpp/aes/cbc128.c create mode 100644 duix-sdk/src/main/cpp/aes/gaes_stream.cc create mode 100644 duix-sdk/src/main/cpp/aes/gaes_stream.h create mode 100644 duix-sdk/src/main/cpp/aes/gaesmain create mode 100644 duix-sdk/src/main/cpp/aes/gj_aes.c create mode 100644 duix-sdk/src/main/cpp/aes/gj_aes.h create mode 100644 duix-sdk/src/main/cpp/aes/gj_dll.h create mode 100644 duix-sdk/src/main/cpp/aes/makefile create mode 100644 duix-sdk/src/main/cpp/aes/modes.h create mode 100644 duix-sdk/src/main/cpp/android/DuixJni.cpp create mode 100644 duix-sdk/src/main/cpp/android/JniHelper.cpp create mode 100644 duix-sdk/src/main/cpp/android/JniHelper.h create mode 100644 duix-sdk/src/main/cpp/android/Log.cpp create mode 100644 duix-sdk/src/main/cpp/android/Log.h create mode 100644 duix-sdk/src/main/cpp/dhcore/atomicops.h create mode 100644 duix-sdk/src/main/cpp/dhcore/blockingconcurrentqueue.h create mode 100644 duix-sdk/src/main/cpp/dhcore/concurrentqueue.h create mode 100644 duix-sdk/src/main/cpp/dhcore/dh_atomic.h create mode 100644 duix-sdk/src/main/cpp/dhcore/dh_data.cpp create mode 100644 duix-sdk/src/main/cpp/dhcore/dh_data.h create mode 100644 duix-sdk/src/main/cpp/dhcore/dh_mem.c create mode 100644 duix-sdk/src/main/cpp/dhcore/dh_mem.h create mode 100644 duix-sdk/src/main/cpp/dhcore/dh_que.cpp create mode 100644 duix-sdk/src/main/cpp/dhcore/dh_que.h create mode 100644 duix-sdk/src/main/cpp/dhcore/dh_types.h create mode 100644 duix-sdk/src/main/cpp/dhcore/lightweightsemaphore.h create mode 100644 duix-sdk/src/main/cpp/dhcore/readerwritercircularbuffer.h create mode 100644 duix-sdk/src/main/cpp/dhcore/readerwriterqueue.h create mode 100644 duix-sdk/src/main/cpp/dhmfcc/AudioFFT.cpp create mode 100644 duix-sdk/src/main/cpp/dhmfcc/dhpcm.cpp create mode 100644 duix-sdk/src/main/cpp/dhmfcc/dhpcm.h create mode 100644 duix-sdk/src/main/cpp/dhmfcc/dhwenet.cpp create mode 100644 duix-sdk/src/main/cpp/dhmfcc/dhwenet.h create mode 100644 duix-sdk/src/main/cpp/dhmfcc/iir_filter.cpp create mode 100644 duix-sdk/src/main/cpp/dhmfcc/mfcc.cpp create mode 100644 duix-sdk/src/main/cpp/dhmfcc/mfcc/AudioFFT.hpp create mode 100644 duix-sdk/src/main/cpp/dhmfcc/mfcc/iir_filter.hpp create mode 100644 duix-sdk/src/main/cpp/dhmfcc/mfcc/mfcc.hpp create mode 100644 duix-sdk/src/main/cpp/dhmfcc/mfcc/sas_util.h create mode 100644 duix-sdk/src/main/cpp/dhmfcc/wenetai.cpp create mode 100644 duix-sdk/src/main/cpp/dhmfcc/wenetai.h create mode 100644 duix-sdk/src/main/cpp/dhmfcc/wenetov.cpp create mode 100644 duix-sdk/src/main/cpp/dhunet/blendgram.cpp create mode 100644 duix-sdk/src/main/cpp/dhunet/blendgram.h create mode 100644 duix-sdk/src/main/cpp/dhunet/face_utils.cpp create mode 100644 duix-sdk/src/main/cpp/dhunet/face_utils.h create mode 100644 duix-sdk/src/main/cpp/dhunet/jmat.cpp create mode 100644 duix-sdk/src/main/cpp/dhunet/jmat.h create mode 100644 duix-sdk/src/main/cpp/dhunet/malpha.cpp create mode 100644 duix-sdk/src/main/cpp/dhunet/malpha.h create mode 100644 duix-sdk/src/main/cpp/dhunet/munet.cpp create mode 100644 duix-sdk/src/main/cpp/dhunet/munet.h create mode 100644 duix-sdk/src/main/cpp/duix/gjduix.cpp create mode 100644 duix-sdk/src/main/cpp/duix/gjduix.h create mode 100644 duix-sdk/src/main/cpp/duix/gjsimp.cpp create mode 100644 duix-sdk/src/main/cpp/include/aicommon.h create mode 100644 duix-sdk/src/main/cpp/include/dhextctrl.h create mode 100644 duix-sdk/src/main/cpp/include/dhextend.h create mode 100644 duix-sdk/src/main/cpp/include/dhextinc.h create mode 100644 duix-sdk/src/main/cpp/include/gj_dll.h create mode 100644 duix-sdk/src/main/cpp/include/gjduix.h create mode 100644 duix-sdk/src/main/cpp/include/gjsimp.h create mode 100644 duix-sdk/src/main/cpp/iostest/testduix.cpp create mode 100644 duix-sdk/src/main/cpp/iostest/testsimp.cpp create mode 100644 duix-sdk/src/main/cpp/mk/Android.mk64 create mode 100644 duix-sdk/src/main/cpp/mk/android.sh create mode 100644 duix-sdk/src/main/cpp/mk/bt create mode 100644 duix-sdk/src/main/cpp/mk/exbuildso64 create mode 100644 duix-sdk/src/main/cpp/third/arm/arm64-v8a/ffmpeg-lite/build_free_arm64_lite.sh create mode 100644 duix-sdk/src/main/cpp/third/arm/armeabi-v7a/ffmpeg-lite/build_free_arm_lite.sh create mode 100644 duix-sdk/src/main/cpp/third/arm/armeabi-v7a/libcurl.la create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/avcodec.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/avdct.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/avfft.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/d3d11va.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/dirac.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/dv_profile.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/dxva2.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/jni.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/mediacodec.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/qsv.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/vaapi.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/vda.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/vdpau.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/version.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/videotoolbox.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/vorbis_parser.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/xvmc.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavdevice/avdevice.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavdevice/version.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavfilter/avfilter.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavfilter/avfiltergraph.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavfilter/buffersink.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavfilter/buffersrc.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavfilter/version.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavformat/avformat.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavformat/avio.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavformat/version.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/adler32.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/aes.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/aes_ctr.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/attributes.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/audio_fifo.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/avassert.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/avconfig.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/avstring.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/avutil.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/base64.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/blowfish.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/bprint.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/bswap.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/buffer.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/camellia.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/cast5.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/channel_layout.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/common.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/cpu.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/crc.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/des.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/dict.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/display.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/downmix_info.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/error.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/eval.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/ffversion.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/fifo.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/file.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/frame.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hash.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hmac.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext_cuda.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext_dxva2.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext_qsv.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext_vaapi.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext_vdpau.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/imgutils.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/intfloat.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/intreadwrite.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/lfg.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/log.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/lzo.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/macros.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/mastering_display_metadata.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/mathematics.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/md5.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/mem.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/motion_vector.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/murmur3.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/opt.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/parseutils.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/pixdesc.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/pixelutils.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/pixfmt.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/random_seed.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/rational.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/rc4.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/replaygain.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/ripemd.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/samplefmt.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/sha.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/sha512.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/spherical.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/stereo3d.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/tea.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/threadmessage.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/time.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/timecode.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/timestamp.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/tree.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/twofish.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/version.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/xtea.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libswresample/swresample.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libswresample/version.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libswscale/swscale.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libswscale/version.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/allocator.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/benchmark.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/blob.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/c_api.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/command.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/cpu.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/datareader.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/gpu.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/layer.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/layer_shader_type.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/layer_shader_type_enum.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/layer_type.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/layer_type_enum.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/mat.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/modelbin.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/ncnn_export.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/net.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/option.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/paramdict.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/pipeline.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/pipelinecache.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/platform.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/simplemath.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/simpleocv.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/simpleomp.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/simplestl.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/ncnn/vulkan_header_fix.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/onnx/cpu_provider_factory.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/onnx/nnapi_provider_factory.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/onnx/onnxruntime_c_api.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/onnx/onnxruntime_cxx_api.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/onnx/onnxruntime_cxx_inline.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/onnx/onnxruntime_float16.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/affine.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/async.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/base.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/bindings_utils.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/bufferpool.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/check.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/core.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/core_c.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda.inl.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/block.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/border_interpolate.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/color.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/common.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/datamov_utils.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/color_detail.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/reduce.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/reduce_key_val.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/transform_detail.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/type_traits_detail.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/vec_distance_detail.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/dynamic_smem.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/emulation.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/filters.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/funcattrib.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/functional.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/limits.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/reduce.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/saturate_cast.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/scan.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/simd_functions.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/transform.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/type_traits.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/utility.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/vec_distance.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/vec_math.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/vec_traits.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/warp.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/warp_reduce.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/warp_shuffle.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda_stream_accessor.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda_types.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cv_cpu_dispatch.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cv_cpu_helper.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cvdef.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cvstd.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cvstd.inl.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cvstd_wrapper.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/detail/async_promise.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/detail/dispatch_helper.impl.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/detail/exception_ptr.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/directx.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/dualquaternion.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/dualquaternion.inl.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/eigen.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/fast_math.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/hal.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/interface.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_avx.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_avx512.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_cpp.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_forward.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_msa.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_neon.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_rvv.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_rvv071.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_sse.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_sse_em.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_vsx.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_wasm.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/msa_macros.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/simd_utils.impl.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/mat.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/mat.inl.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/matx.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/neon_utils.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/ocl.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/ocl_genbase.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/ocl_defs.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/opencl_info.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/opencl_svm.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_clblas.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_clfft.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_core.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_core_wrappers.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl_wrappers.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_clblas.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_clfft.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_core.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_core_wrappers.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_gl.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_gl_wrappers.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_svm_20.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_svm_definitions.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_svm_hsa_extension.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opengl.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/operations.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/optim.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/ovx.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/parallel/backend/parallel_for.openmp.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/parallel/backend/parallel_for.tbb.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/parallel/parallel_backend.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/persistence.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/quaternion.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/quaternion.inl.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/saturate.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/simd_intrinsics.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/softfloat.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/sse_utils.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/traits.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/types.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/types_c.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utility.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/allocator_stats.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/allocator_stats.impl.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/filesystem.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/fp_control_utils.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/instrumentation.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/logger.defines.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/logger.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/logtag.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/tls.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/trace.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/va_intel.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/version.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/core/vsx_utils.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/cvconfig.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/features2d.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/features2d/features2d.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/features2d/hal/interface.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/highgui.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/highgui/highgui.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/bindings.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/detail/gcgraph.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/hal/hal.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/hal/interface.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/imgproc.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/imgproc_c.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/segmentation.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/types_c.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/opencv.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/opencv_modules.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/photo.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/photo/cuda.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/photo/legacy/constants_c.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/photo/photo.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/video.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/video/background_segm.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/video/detail/tracking.detail.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/video/legacy/constants_c.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/video/tracking.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/opencv2/video/video.hpp create mode 100644 duix-sdk/src/main/cpp/third/arm/include/rknn_api.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/bmp.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/cderror.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/cdjpeg.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/config.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/cpu-features.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/jchuff.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/jconfig.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/jdct.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/jdhuff.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/jerror.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/jinclude.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/jmemsys.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/jmorecfg.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/jpegcomp.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/jpegint.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/jpeglib.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/jsimd.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/jsimdcfg.inc.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/jsimddct.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/jversion.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/platform.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/tjutil.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/transupp.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/tjpeg/turbojpeg.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/turbojpeg/jconfig.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/turbojpeg/jerror.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/turbojpeg/jmorecfg.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/turbojpeg/jpeglib.h create mode 100644 duix-sdk/src/main/cpp/third/arm/include/turbojpeg/turbojpeg.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/allocator.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/benchmark.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/blob.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/c_api.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/command.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/cpu.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/datareader.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/gpu.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/layer.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/layer_shader_type.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/layer_shader_type_enum.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/layer_type.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/layer_type_enum.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/mat.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/modelbin.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/ncnn_export.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/net.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/option.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/paramdict.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/pipeline.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/pipelinecache.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/platform.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/simpleocv.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/simpleomp.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/simplestl.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/vulkan_header_fix.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/lib/cmake/ncnn/ncnn-release.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/lib/cmake/ncnn/ncnn.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/lib/cmake/ncnn/ncnnConfig.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/lib/pkgconfig/ncnn.pc create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/allocator.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/benchmark.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/blob.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/c_api.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/command.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/cpu.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/datareader.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/gpu.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/layer.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/layer_shader_type.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/layer_shader_type_enum.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/layer_type.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/layer_type_enum.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/mat.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/modelbin.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/ncnn_export.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/net.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/option.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/paramdict.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/pipeline.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/pipelinecache.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/platform.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/simpleocv.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/simpleomp.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/simplestl.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/vulkan_header_fix.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/lib/cmake/ncnn/ncnn-release.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/lib/cmake/ncnn/ncnn.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/lib/cmake/ncnn/ncnnConfig.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/lib/pkgconfig/ncnn.pc create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/allocator.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/benchmark.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/blob.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/c_api.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/command.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/cpu.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/datareader.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/gpu.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/layer.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/layer_shader_type.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/layer_shader_type_enum.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/layer_type.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/layer_type_enum.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/mat.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/modelbin.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/ncnn_export.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/net.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/option.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/paramdict.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/pipeline.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/pipelinecache.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/platform.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/simpleocv.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/simpleomp.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/simplestl.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/vulkan_header_fix.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/lib/cmake/ncnn/ncnn-release.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/lib/cmake/ncnn/ncnn.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/lib/cmake/ncnn/ncnnConfig.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/lib/pkgconfig/ncnn.pc create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/allocator.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/benchmark.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/blob.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/c_api.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/command.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/cpu.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/datareader.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/gpu.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/layer.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/layer_shader_type.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/layer_shader_type_enum.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/layer_type.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/layer_type_enum.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/mat.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/modelbin.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/ncnn_export.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/net.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/option.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/paramdict.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/pipeline.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/pipelinecache.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/platform.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/simpleocv.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/simpleomp.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/simplestl.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/vulkan_header_fix.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/lib/cmake/ncnn/ncnn-release.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/lib/cmake/ncnn/ncnn.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/lib/cmake/ncnn/ncnnConfig.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/lib/pkgconfig/ncnn.pc create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/allocator.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/benchmark.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/blob.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/c_api.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/command.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/cpu.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/datareader.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/gpu.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/layer.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/layer_shader_type.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/layer_shader_type_enum.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/layer_type.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/layer_type_enum.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/mat.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/modelbin.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/ncnn_export.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/net.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/option.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/paramdict.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/pipeline.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/pipelinecache.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/platform.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/simplemath.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/simpleocv.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/simpleomp.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/simplestl.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/vulkan_header_fix.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/lib/cmake/ncnn/ncnn-release.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/lib/cmake/ncnn/ncnn.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/lib/cmake/ncnn/ncnnConfig.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/lib/pkgconfig/ncnn.pc create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/allocator.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/benchmark.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/blob.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/c_api.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/command.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/cpu.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/datareader.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/gpu.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/layer.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/layer_shader_type.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/layer_shader_type_enum.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/layer_type.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/layer_type_enum.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/mat.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/modelbin.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/ncnn_export.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/net.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/option.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/paramdict.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/pipeline.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/pipelinecache.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/platform.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/simplemath.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/simpleocv.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/simpleomp.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/simplestl.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/vulkan_header_fix.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/lib/cmake/ncnn/ncnn-release.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/lib/cmake/ncnn/ncnn.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/lib/cmake/ncnn/ncnnConfig.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/lib/pkgconfig/ncnn.pc create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/allocator.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/benchmark.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/blob.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/c_api.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/command.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/cpu.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/datareader.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/gpu.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/layer.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/layer_shader_type.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/layer_shader_type_enum.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/layer_type.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/layer_type_enum.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/mat.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/modelbin.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/ncnn_export.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/net.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/option.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/paramdict.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/pipeline.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/pipelinecache.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/platform.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/simplemath.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/simpleocv.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/simpleomp.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/simplestl.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/vulkan_header_fix.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/lib/cmake/ncnn/ncnn-release.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/lib/cmake/ncnn/ncnn.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/lib/cmake/ncnn/ncnnConfig.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/lib/pkgconfig/ncnn.pc create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/allocator.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/benchmark.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/blob.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/c_api.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/command.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/cpu.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/datareader.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/gpu.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/layer.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/layer_shader_type.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/layer_shader_type_enum.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/layer_type.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/layer_type_enum.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/mat.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/modelbin.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/ncnn_export.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/net.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/option.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/paramdict.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/pipeline.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/pipelinecache.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/platform.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/simplemath.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/simpleocv.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/simpleomp.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/simplestl.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/vulkan_header_fix.h create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/lib/cmake/ncnn/ncnn-release.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/lib/cmake/ncnn/ncnn.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/lib/cmake/ncnn/ncnnConfig.cmake create mode 100644 duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/lib/pkgconfig/ncnn.pc create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/DuixNcnn.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/Callback.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/Constant.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/DUIX.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/VirtualModelUtil.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/audio/AudioPlayer.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/bean/AudioFrame.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/bean/ImageFrame.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/net/DownloadZipService.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/net/FileDownloader.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/render/DUIXRenderer.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/render/DUIXTextureView.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/render/ImageDrawer.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/render/RenderSink.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/render/TextureMatrix.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/thread/RenderThread.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/DeviceUtils.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/FileUtil.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/Logger.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/MD5Util.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/OpenGLUtil.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/SystemUtils.java create mode 100644 duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/ZipUtil.java create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 settings.gradle create mode 100644 test/.gitignore create mode 100644 test/build.gradle create mode 100644 test/lint-baseline.xml create mode 100644 test/proguard-rules.pro create mode 100644 test/src/main/AndroidManifest.xml create mode 100644 test/src/main/assets/bg/bg1.png create mode 100644 test/src/main/assets/bg/bg2.jpg create mode 100644 test/src/main/assets/pcm/2.pcm create mode 100644 test/src/main/assets/pcm/222.pcm create mode 100644 test/src/main/assets/wav/1.wav create mode 100644 test/src/main/assets/wav/2.wav create mode 100644 test/src/main/java/ai/guiji/duix/test/App.java create mode 100644 test/src/main/java/ai/guiji/duix/test/audio/AudioRecorder.java create mode 100644 test/src/main/java/ai/guiji/duix/test/audio/AudioResampler.java create mode 100644 test/src/main/java/ai/guiji/duix/test/audio/StreamingAudioRecorder.java create mode 100644 test/src/main/java/ai/guiji/duix/test/camera/CameraFrameCapture.java create mode 100644 test/src/main/java/ai/guiji/duix/test/net/SyncDownloadFile.java create mode 100644 test/src/main/java/ai/guiji/duix/test/realtime/OmniRealtimeClient.java create mode 100644 test/src/main/java/ai/guiji/duix/test/render/DebugSink.java create mode 100644 test/src/main/java/ai/guiji/duix/test/service/StorageService.java create mode 100644 test/src/main/java/ai/guiji/duix/test/ui/activity/BaseActivity.java create mode 100644 test/src/main/java/ai/guiji/duix/test/ui/activity/CallActivity.kt create mode 100644 test/src/main/java/ai/guiji/duix/test/ui/activity/MainActivity.kt create mode 100644 test/src/main/java/ai/guiji/duix/test/ui/adapter/ModelSelectorAdapter.kt create mode 100644 test/src/main/java/ai/guiji/duix/test/ui/adapter/MotionAdapter.kt create mode 100644 test/src/main/java/ai/guiji/duix/test/ui/dialog/AudioRecordDialog.kt create mode 100644 test/src/main/java/ai/guiji/duix/test/ui/dialog/LoadingDialog.kt create mode 100644 test/src/main/java/ai/guiji/duix/test/ui/dialog/ModelSelectorDialog.kt create mode 100644 test/src/main/java/ai/guiji/duix/test/util/StringUtils.java create mode 100644 test/src/main/java/ai/guiji/duix/test/util/SystemUtils.java create mode 100644 test/src/main/java/ai/guiji/duix/test/util/ZipUtil.java create mode 100644 test/src/main/res/anim/rotate.xml create mode 100644 test/src/main/res/drawable/ic_launcher_background.xml create mode 100644 test/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 test/src/main/res/drawable/selector_60_primary.xml create mode 100644 test/src/main/res/drawable/shape_circle_camera_off.xml create mode 100644 test/src/main/res/drawable/shape_circle_camera_on.xml create mode 100644 test/src/main/res/drawable/shape_circle_fab.xml create mode 100644 test/src/main/res/drawable/shape_common_btn.xml create mode 100644 test/src/main/res/drawable/shape_corners_60_99_primary.xml create mode 100644 test/src/main/res/drawable/shape_corners_60_primary.xml create mode 100644 test/src/main/res/drawable/shape_solid_b3000000_radius_7.xml create mode 100644 test/src/main/res/drawable/shape_tl_tr_32_ffffffff.xml create mode 100644 test/src/main/res/drawable/shape_tl_tr_bl_20_ff147bf7.xml create mode 100644 test/src/main/res/drawable/shape_tl_tr_br_20_ffd9eaff.xml create mode 100644 test/src/main/res/layout/activity_call.xml create mode 100644 test/src/main/res/layout/activity_main.xml create mode 100644 test/src/main/res/layout/dialog_audio_record.xml create mode 100644 test/src/main/res/layout/dialog_loading.xml create mode 100644 test/src/main/res/layout/dialog_model_selector.xml create mode 100644 test/src/main/res/layout/item_model_selector.xml create mode 100644 test/src/main/res/layout/item_motion_button.xml create mode 100644 test/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 test/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 test/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 test/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 test/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 test/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 test/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 test/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 test/src/main/res/mipmap-xxhdpi/iv_progress.png create mode 100644 test/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 test/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 test/src/main/res/values-zh-rCN/strings.xml create mode 100644 test/src/main/res/values/attrs.xml create mode 100644 test/src/main/res/values/colors.xml create mode 100644 test/src/main/res/values/strings.xml create mode 100644 test/src/main/res/values/style.xml create mode 100644 test/src/main/res/values/themes.xml create mode 100644 test/src/main/res/xml/network_security_config.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a27acfc --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +*.iml +.gradle +/local.properties +/.idea/ +.DS_Store +/build/ +*/build/ +*/*/build/ +*/debug/ +*/release/ +/captures +.externalNativeBuild +.cxx +*.bat +*.apk +output-metadata.json +# app用到zip的请忽略 +# 自定义了local.properties的请删除这条 +local.properties +~$* +gradlew +.idea +# 自定义了根目录gradle/gradle-wrapper.properties的请删除这条(不推荐自定义) +#gradle +build + +# 预编译的静态库和第三方二进制文件(opencv-mobile 等) +# 这些文件体积大、为二进制,应从发布源获取而非纳入版本控制 +*.a +*.so +duix-sdk/src/main/cpp/third/opencv-mobile-*/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..d65d7d3 --- /dev/null +++ b/README.md @@ -0,0 +1,405 @@ +# Duix Mobile for Android SDK Documentation + +English | [中文](./README_zh.md) + +## 1. Product Overview + +`Duix Mobile for Android` is a lightweight, fully offline 2D digital human solution for Android, supporting real-time rendering of digital avatars driven by voice audio. + +### 1.1 Application Scenarios + +- **Low deployment cost**: Suitable for unattended scenarios such as large-screen terminals, government halls, and banks. +- **Minimal network dependency**: Runs entirely locally, no internet required, stable operation in subways and remote areas. +- **Diverse functionality**: Can serve as a guide, Q&A customer service, intelligent companion, and more. + +### 1.2 Core Features + +- Customizable digital avatar and local rendering +- Real-time voice-driven playback (supports WAV playback and PCM streaming) +- Motion playback control (specific or random actions) +- Automatic resource download management + +--- + +## 2. Terminology + +| Term | Meaning | +|--------------------|----------------------------------------------------------------------------| +| PCM | Pulse-Code Modulation, raw audio stream with 16kHz sample rate, 16-bit depth, Mono channel | +| WAV | An audio file format that supports PCM encoding, suitable for short voice playback | +| RenderSink | Rendering data reception interface, implemented by the SDK, can be used for custom rendering or default display | +| DUIX | Main control object of the digital human, integrates model loading, rendering, broadcasting, and motion control | +| GLES | OpenGL ES, a graphics interface for rendering images on Android | +| SpecialAction | A JSON file attached to the model that marks action intervals (e.g., greetings, waving) | + +--- + +## 3. SDK Access + +### 3.1 Module Reference (Recommended) + +1. Obtain the complete source package, unzip it, and copy the `duix-sdk` directory to the project root directory. +2. In the project `settings.gradle`, add: + +```gradle +include ':duix-sdk' +``` + +3. In the module's `build.gradle`, add the dependency: + +```gradle +dependencies { + api project(":duix-sdk") +} +``` + +### 3.2 AAR Reference (Optional) + +1. Place the compiled `duix-sdk-release.aar` module into the `libs/` directory. +2. Add the dependency: + +```gradle +dependencies { + api fileTree(include: ['*.jar', '*.aar'], dir: 'libs') +} +``` + +--- + +## 4. Integration Requirements + +| Item | Description | +|----------------|-----------------------------------------------------------------| +| System | Supports Android 10+ systems. | +| CPU Architecture | armeabi-v7a, arm64-v8a | +| Hardware Requirements | Device CPU with 8 or more cores (Snapdragon 8 Gen 2), 8GB or more memory, available storage space of 1GB or more | +| Network | None (Fully local operation) | +| Development IDE | Android Studio Giraffe 2022.3.1 Patch 2 | +| Memory Requirements | Minimum 800MB memory available for the digital human | + +--- + +## 5. Usage Flow Overview + +```mermaid +graph TD +A[Check Configuration and Models] --> B[Build DUIX Instance] +B --> C[Call init to Initialize] +C --> D[Display Avatar / Render] +D --> E[PCM or WAV Audio Driving] +E --> F[Playback Control & Motion Triggering] +F --> G[Resource Release] +``` + +--- + +## 6. Key Interfaces and Example Calls + +### 6.1 Model Check and Download + +Before using the rendering service, ensure that the basic configuration and model files are synchronized to local storage. The SDK provides a simple demonstration of the model download and decompression process using `VirtualModelUtil`. If model download is slow or fails, developers can choose to cache the model package to their own storage service. + +> Function Definition: `ai.guiji.duix.sdk.client.VirtualModelUtil` + +``` +// Check if base configuration is downloaded +boolean checkBaseConfig(Context context) + +// Check if the model is downloaded +boolean checkModel(Context context, String name) + +// Base configuration download +void baseConfigDownload(Context context, String url, ModelDownloadCallback callback) + +// Model download +void modelDownload(Context context, String modelUrl, ModelDownloadCallback callback) +``` + +`ModelDownloadCallback` includes progress, completion, failure callbacks, etc., as defined in the SDK. + +``` +interface ModelDownloadCallback { + // Download progress + void onDownloadProgress(String url, long current, long total); + // Unzip progress + void onUnzipProgress(String url, long current, long total); + // Download and unzip complete + void onDownloadComplete(String url, File dir); + // Download and unzip failed + void onDownloadFail(String url, int code, String msg); +} +``` + +**Call Example**: + +```kotlin +if (!VirtualModelUtil.checkBaseConfig(mContext)){ + VirtualModelUtil.baseConfigDownload(mContext, baseConfigUrl, callback) +} +``` + +```kotlin +if (!VirtualModelUtil.checkModel(mContext, modelUrl)){ + VirtualModelUtil.modelDownload(mContext, modelUrl, callback) +} +``` + +--- + +### 6.2 Initialization and Rendering Start + +In the `onCreate()` stage of the rendering page, build the DUIX object and call the init interface. + +> Function Definition: `ai.guiji.duix.sdk.client.DUIX` + +``` +// Build DUIX object +public DUIX(Context context, String modelName, RenderSink sink, Callback callback) + +// Initialize DUIX service +void init() +``` + +**DUIX Object Construction Explanation**: + +| Parameter | Type | Description | +|---------------|-----------|----------------------------------------------------------------| +| context | Context | System context | +| modelName | String | Can pass the model download URL (if downloaded) or cached filename | +| render | RenderSink| Rendering data interface, SDK provides a default rendering component inheriting from this interface, or you can implement it yourself | +| callback | Callback | Various callback events handled by the SDK | + +Where **Callback** is defined as: `ai.guiji.duix.sdk.client.Callback` + +``` +interface Callback { + void onEvent(String event, String msg, Object info); +} +``` + +**Call Example**: + +```kotlin +duix = DUIX(mContext, modelUrl, mDUIXRender) { event, msg, info -> + when (event) { + ai.guiji.duix.sdk.client.Constant.CALLBACK_EVENT_INIT_READY -> { + initOK() + } + + ai.guiji.duix.sdk.client.Constant.CALLBACK_EVENT_INIT_ERROR -> { + initError() + } + // ... + } +} +// Asynchronous callback result +duix?.init() +``` + +In the `init` callback, confirm the initialization result. + +--- + +### 6.3 Digital Human Avatar Display + +Use the SDK-provided `DUIXRenderer` and `DUIXTextureView` to quickly implement rendering with transparency support. Alternatively, you can implement the `RenderSink` interface to customize the rendering logic. + +The **RenderSink** definition is as follows: `ai.guiji.duix.sdk.client.render.RenderSink` + +```java +/** + * Rendering pipeline, returns rendering data through this interface + */ +public interface RenderSink { + + // The frame's buffer data is arranged in BGR order + void onVideoFrame(ImageFrame imageFrame); + +} +``` + +**Call Example**: + +Use `DUIXRenderer` and `DUIXTextureView` to quickly implement rendering. These controls support transparency and can freely set the background and foreground. + +```kotlin +override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // ... + mDUIXRender = + DUIXRenderer( + mContext, + binding.glTextureView + ) + + binding.glTextureView.setEGLContextClientVersion(GL_CONTEXT_VERSION) + binding.glTextureView.setEGLConfigChooser(8, 8, 8, 8, 16, 0) // Transparency + binding.glTextureView.isOpaque = false // Transparency + binding.glTextureView.setRenderer(mDUIXRender) + binding.glTextureView.renderMode = + GLSurfaceView.RENDERMODE_WHEN_DIRTY // Must be called after setting the renderer + + duix = DUIX(mContext, modelUrl, mDUIXRender) { event, msg, _ -> + } + // ... +} +``` + +--- + +### 6.4 Broadcasting Control + +#### Use Streaming PCM to Drive Digital Human Broadcasting + +**PCM Format: 16kHz sample rate, single channel, 16-bit depth** + +> Function Definition: `ai.guiji.duix.sdk.client.DUIX` + +``` +// Notify service to start pushing audio +void startPush() + +// Push PCM data +void pushPcm(byte[] buffer) + +// Finish a segment of audio push (Call this after the audio push is complete, not after playback finishes) +void stopPush() +``` + +`startPush`, `pushPcm`, and `stopPush` need to be called in pairs. `pushPcm` should not be too long. After pushing the entire audio, call `stopPush` to end the session. Use `startPush` again for the next audio. + +**The audio data between each startPush and stopPush segment should be at least 1 second (32000 bytes), otherwise the mouth shape driver cannot be triggered, and blank frames can be used to fill in.** + +**Call Example**: + +```kotlin +val thread = Thread { + duix?.startPush() + val inputStream = assets.open("pcm/2.pcm") + val buffer = ByteArray(320) + var length = 0 + while (inputStream.read(buffer).also { length = it } > 0){ + val data = buffer.copyOfRange(0, length) + duix?.pushPcm(data) + } + duix?.stopPush() + inputStream.close() +} +thread.start() +``` + +--- + +### 6.5 Motion Control + +#### Play Specific Motion Interval + +The model supports new motion intervals marked in `SpecialAction.json` + +> Function Definition: `ai.guiji.duix.sdk.client.DUIX` + +``` +/** + * Play specific motion interval + * @param name The motion interval name, which can be obtained from @{ModelInfo.getSilenceRegion()} after init callback + * @param now Whether to play immediately: true: play now; false: wait for current silent or motion interval to finish + */ +void startMotion(String name, boolean now) +``` + +**Call Example**: + +```kotlin +duix?.startMotion("Greeting", true) +``` + +#### Randomly Play Motion Interval + +> Function Definition: `ai.guiji.duix.sdk.client.DUIX` + +``` +/** + * Randomly play a motion interval + * @param now Whether to play immediately: true: play now; false: wait for current silent or motion interval to finish + */ +void startRandomMotion(boolean now); +``` + +**Call Example**: + +```kotlin +duix?.startRandomMotion(true) +``` + +--- + +## 7. Proguard Configuration + +If using obfuscation, add the following in `proguard-rules.pro`: + +```proguard +-keep class ai.guiji.duix.DuixNcnn{*; } +``` + +--- + +## 8. Precautions + +1. Ensure that the base configuration file and model are downloaded to the specified location before driving rendering initialization. +2. PCM audio should not be too long, as PCM buffers are cached in memory; long audio streams may cause memory overflow. +3. To replace the preview model, modify the `modelUrl` value in `MainActivity.kt` and use the SDK's built-in file download and decompression management to obtain the complete model files. +4. Audio driving format: 16kHz sample rate, single channel, 16-bit depth. +5. Insufficient device performance may result in the audio feature extraction speed not matching the playback speed. You can use `duix?.setReporter()` to monitor frame rendering information. + +--- + +## 9. FAQ and Troubleshooting Guide + +| Issue | Possible Cause | Solution | +|---------------------------------|------------------------------|------------------------------| +| init callback failed | Model path error or model not downloaded | Use `checkModel` to check model status | +| Rendering black screen | EGL configuration or texture view error | Use SDK-provided example settings | +| No PCM playback effect | Incorrect format or `startPush` not called | Ensure audio format is correct and call push method | +| Model download slow | Unstable network or restricted CDN | Support self-hosted model file storage service | + +--- + +## 10. Version History + +**4.0.1** + +1. Supports PCM audio stream driving the digital human, improving audio playback response speed. +2. Optimized motion interval playback, allowing specific motion intervals based on model configuration. +3. Custom audio player, removed Exoplayer playback dependency. +4. Provided simplified model download synchronization management tools. +5. The audio data between each startPush and stopPush segment should be at least 1 second (32000 bytes), otherwise the mouth shape driver cannot be triggered, and blank frames can be used to fill in. + +**3.0.5** + +```text +1. Updated arm32 CPU libonnxruntime.so version to fix compatibility issues. +2. Modified motion interval playback function, supports random and sequential playback, requires manual call to stop playback to return to silent interval. +``` + +**3.0.4** + +```text +1. Fixed model display issue due to low float precision on some devices. +``` + +**3.0.3** + +```text +1. Optimized local rendering. +``` + +## 11. 🔗 Open-source Dependencies + +| Module | Description | +|------------------------------------------|--------------------------------| +| [onnx](https://github.com/onnx/onnx) | General AI model standard format | +| [ncnn](https://github.com/Tencent/ncnn) | High-performance neural network computing framework (Tencent) | + +--- + +For more help, please contact the technical support team. \ No newline at end of file diff --git a/README_zh.md b/README_zh.md new file mode 100644 index 0000000..d16e9b6 --- /dev/null +++ b/README_zh.md @@ -0,0 +1,485 @@ +# Duix Mobile for Android SDK 文档 + +中文 | [English](./README.md) + +## 一、产品介绍 + +`Duix Mobile for Android` 是一套轻量级、纯离线的 Android 平台 2D 虚拟人解决方案,支持通过语音音频驱动数字人形象并进行实时渲染。 + +### 1.1 应用场景 + +- **部署成本低**:适用于大屏终端、政务展厅、银行等无人值守场景。 +- **网络依赖小**:完全本地运行,无需联网,可在地铁、偏远地区稳定运行。 +- **功能多样化**:可服务于导览讲解、问答客服、智能陪伴等多种业务形态。 + +### 1.2 核心功能 + +- 数字人形象定制与本地渲染 +- 实时语音驱动播报(支持 WAV 播放和 PCM 推送) +- 动作播放控制(指定动作、随机动作) +- 资源自动下载管理 + +--- + +## 二、术语说明 + +| 术语 | 含义 | +|-------------------|------------------------------------------------------------------------| +| PCM | Pulse-Code Modulation,16kHz 采样率、16bit 位深、Mono 单通道的原始音频流 | +| WAV | 一种音频文件格式,支持 PCM 编码,适合短语音播放 | +| RenderSink | 渲染数据接收接口,由 SDK 提供实现,可用于自定义渲染或默认展示 | +| DUIX | 数字人主控对象,集成了模型加载、渲染、播报、动作等能力 | +| GLES | OpenGL ES,Android 渲染图像用到的图形接口 | +| SpecialAction | 模型附带的 JSON 文件,标注动作区间(例如打招呼、挥手等) | + +--- + +## 三、SDK 获取方式 + +### 3.1 Module 引用(推荐) + +1. 获取完整源码包,解压后将 `duix-sdk` 目录复制到项目根目录下。 +2. 在项目 `settings.gradle` 中添加: + +```gradle +include ':duix-sdk' +``` + +3. 在模块 `build.gradle` 中添加依赖: + +```gradle +dependencies { + api project(":duix-sdk") +} +``` + +### 3.2 AAR 引用(可选) + +1. 将duix-sdk模块编译的 `duix-sdk-release.aar` 放入 `libs/` 目录。 +2. 添加依赖: + +```gradle +dependencies { + api fileTree(include: ['*.jar', '*.aar'], dir: 'libs') +} +``` + +--- + +## 四、集成要求 + +| 项目 | 描述 | +|--------|----------------------------------------------------| +| 系统 | 支持 Android 10+ 系统。 | +| CPU架构 | armeabi-v7a, arm64-v8a | +| 硬件要求 | 要求设备 CPU8 核及以上(骁龙8 Gen2),内存 8G 及以上。可用存储空间 1GB 及以上。 | +| 网络 | 无(完全本地运行) | +| 开发 IDE | Android Studio Giraffe 2022.3.1 Patch 2 | +| 内存要求 | 可用于数字人的内存 >= 800MB | + + +**编译项目的Gradle使用的JDK版本为17,需要在File->Setting->Build,Execution,Deployment->Grade Projects->Gradle JDK: ${选择一个17版本的JDK}** + +--- + +## 五、使用流程概览 + +```mermaid +graph TD +A[检查配置与模型] --> B[构建 DUIX 实例] +B --> C[调用 init 初始化] +C --> D[展示形象 / 渲染] +D --> E[PCM 或 WAV 音频驱动] +E --> F[播放控制与动作触发] +F --> G[资源释放] +``` + +--- + +## 六、关键接口与调用示例 + +### 6.1. 模型检查及下载 + +使用渲染服务前需要将基础配置及模型文件同步到本地存储中,SDK中提供了VirtualModelUtil简单演示了模型下载解压流程。 +若模型下载过慢或无法下载,开发者可以选择将模型包缓存到自己的存储服务。 + +> 函数定义: `ai.guiji.duix.sdk.client.VirtualModelUtil` + +``` +// 检查基础配置是否已下载 +boolean checkBaseConfig(Context context) + +// 检查模型是否已下载 +boolean checkModel(Context context, String name) + +// 基础配置下载 +void baseConfigDownload(Context context, String url, ModelDownloadCallback callback) + +// 模型下载 +void modelDownload(Context context, String modelUrl, ModelDownloadCallback callback) +``` + +`ModelDownloadCallback` 包含进度、完成、失败等回调,详见 SDK 定义。 + +``` +interface ModelDownloadCallback { + // 下载进度 + void onDownloadProgress(String url, long current, long total); + // 解压进度 + void onUnzipProgress(String url, long current, long total); + // 下载解压完成 + void onDownloadComplete(String url, File dir); + // 下载解压失败 + void onDownloadFail(String url, int code, String msg); +} +``` + +**调用示例**: + +```kotlin +if (!VirtualModelUtil.checkBaseConfig(mContext)){ + VirtualModelUtil.baseConfigDownload(mContext, baseConfigUrl, callback) +} +``` + +```kotlin +if (!VirtualModelUtil.checkModel(mContext, modelUrl)){ + VirtualModelUtil.modelDownload(mContext, modelUrl, callback) +} + +``` + +--- + +### 6.2. 初始化与渲染启动 + +在渲染页onCreate()阶段构建DUIX对象并调用init接口 + +> 函数定义: `ai.guiji.duix.sdk.client.DUIX` + +``` +// 构建DUIX对象 +public DUIX(Context context, String modelName, RenderSink sink, Callback callback) + +// 初始化DUIX服务 +void init() +``` + +**DUIX对象构建说明**: + +| 参数 | 类型 | 描述 | +|------------|------------|-------------------------------------| +| context | Context | 系统上下文 | +| modelName | String | 可以传递模型下载的URL(已下载完成)或缓存的文件名 | +| render | RenderSink | 渲染数据接口,sdk提供了默认的渲染组件继承自该接口,也可以自己实现 | +| callback | Callback | SDK处理的各种回调事件 | + + +其中**Callback**的定义: `ai.guiji.duix.sdk.client.Callback` + +``` +interface Callback { + void onEvent(String event, String msg, Object info); +} +``` + +**调用示例**: + +```kotlin +duix = DUIX(mContext, modelUrl, mDUIXRender) { event, msg, info -> + when (event) { + ai.guiji.duix.sdk.client.Constant.CALLBACK_EVENT_INIT_READY -> { + initOK() + } + + ai.guiji.duix.sdk.client.Constant.CALLBACK_EVENT_INIT_ERROR -> { + initError() + } + // ... + + } +} +// 异步回调结果 +duix?.init() +``` + +在init回调中确认初始化结果 + +--- + +### 6.3. 数字人形象展示 + +使用 SDK 提供的 `DUIXRenderer` 和 `DUIXTextureView` 可快速实现支持透明通道的渲染。也可以自己实现RenderSink接口自定义渲染逻辑。 + +其中**RenderSink**的定义如下: `ai.guiji.duix.sdk.client.render.RenderSink` + +```java +/** + * 渲染管道,通过该接口返回渲染数据 + */ +public interface RenderSink { + + // frame中的buffer数据以bgr顺序排列 + void onVideoFrame(ImageFrame imageFrame); + +} +``` + +**调用示例**: + +使用DUIXRenderer及DUIXTextureView控件简单实现渲染展示,该控件支持透明通道可以自由设置背景及前景 + +```kotlin +override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // ... + mDUIXRender = + DUIXRenderer( + mContext, + binding.glTextureView + ) + + binding.glTextureView.setEGLContextClientVersion(GL_CONTEXT_VERSION) + binding.glTextureView.setEGLConfigChooser(8, 8, 8, 8, 16, 0) // 透明 + binding.glTextureView.isOpaque = false // 透明 + binding.glTextureView.setRenderer(mDUIXRender) + binding.glTextureView.renderMode = + GLSurfaceView.RENDERMODE_WHEN_DIRTY // 一定要在设置完Render之后再调用 + + duix = DUIX(mContext, modelUrl, mDUIXRender) { event, msg, _ -> + } + // ... +} +``` + +--- + +### 6.4 播报控制 + +#### 使用流式推送PCM驱动数字人播报 + +**PCM格式:16k采样率单通道16位深** + +> 函数定义: `ai.guiji.duix.sdk.client.DUIX` + +``` +// 通知服务开始推送音频 +void startPush() + +// 推送PCM数据 +void pushPcm(byte[] buffer) + +// 完成一段音频推送(音频推送完就调要该函数,而不是等播放完成再调用。) +void stopPush() + +``` + +startPush、pushPcm、stopPush需要成对调用,pushPcm不宜过长。可以在一整段音频推送完后调用stopPush结束当前会话,下一段音频再使用startPush重新开启推送。 + +**每段startPush到stopPush中间的音频数据最少要1秒(32000字节)否则无法触发口型驱动,可以自行使用空白帧填充。** + +**调用示例**: + +```kotlin +val thread = Thread { + duix?.startPush() + val inputStream = assets.open("pcm/2.pcm") + val buffer = ByteArray(320) + var length = 0 + while (inputStream.read(buffer).also { length = it } > 0){ + val data = buffer.copyOfRange(0, length) + duix?.pushPcm(data) + } + duix?.stopPush() + inputStream.close() +} +thread.start() +``` + +--- + +#### WAV 播放驱动 + +> 函数定义: `ai.guiji.duix.sdk.client.DUIX` + +``` +void playAudio(String wavPath) +``` + +**该函数兼容旧的wav驱动数字人接口,在内部实际是调用了PCM推流方式实现驱动。** + + +**参数说明**: + +| 参数 | 类型 | 描述 | +|---------|--------|-----------------------| +| wavPath | String | 16k采样率单通道16位深的wav本地文件 | + + +**调用示例**: + +```kotlin +duix?.playAudio(wavPath) +``` + +音频播放状态及进度回调: + +```kotlin +object : Callback { + fun onEvent(event: String, msg: String, info: Object) { + when (event) { + // ... + + "play.start" -> { + // 开始播放音频 + } + + "play.end" -> { + // 完成播放音频 + } + "play.error" -> { + // 音频播放异常 + } + } + } +} +``` + +--- + +#### 终止当前播报 + +当数字人正在播报时调用该接口终止播报。 + +> 函数定义: `ai.guiji.duix.sdk.client.DUIX` + +``` +boolean stopAudio(); +``` + +**调用示例如下**: + +```kotlin +duix?.stopAudio() +``` + +--- + +### 6.5. 动作控制 + + +#### 播放指定动作区间 + +模型中支持新的动作区间标注(SpecialAction.json) + +> 函数定义: `ai.guiji.duix.sdk.client.DUIX` + +``` +/** + * 播放指定动作区间 + * @param name 动作区间名称,在init成功回调时,可以在@{ModelInfo.getSilenceRegion()}中获取到可用的动作区间 + * @param now 是否立即播放 true: 立即播放; false: 等待当前静默区间或动作区间播放完毕后播放 + */ +void startMotion(String name, boolean now) +``` + +**调用示例如下**: + +```kotlin +duix?.startMotion("打招呼", true) +``` + +#### 随机播放动作区间 + +随机播放场景及旧的标注协议(config.json) + +> 函数定义: `ai.guiji.duix.sdk.client.DUIX` + +``` +/** + * 随机播放一个动作区间 + * @param now 是否立即播放 true: 立即播放; false: 等待当前静默区间或动作区间播放完毕后播放 + */ +void startRandomMotion(boolean now); +``` + +**调用示例如下**: + +```kotlin +duix?.startRandomMotion(true) +``` + +--- + +## 七. Proguard配置 + +如果代码使用了混淆,请在proguard-rules.pro中配置: + +```proguard +-keep class ai.guiji.duix.DuixNcnn{*; } +``` + +--- + +## 八、注意事项 + +1. 驱动渲染初始化前需要确保基础配置文件及模型下载到指定位置。 +2. 播放的PCM音频不宜过长,播放的PCM缓存在内存中,过长的音频流可能导致内存溢出。 +3. 替换预览模型可以在MainActivity.kt文件中修改modelUrl的值,使用SDK中自带的文件下载解压管理以获得完整的模型文件。 +4. 音频驱动的格式: 16k采样率单通道16位深度 +5. 设备性能不足时可能导致音频特征提取的速度跟不上音频播放的速度,可以使用duix?.setReporter()函数添加一个监控观察帧渲染返回的信息。 +6. 每段startPush到stopPush中间的音频数据最少要1秒(32000字节)否则无法触发口型驱动,可以自行使用空白帧填充。 + +--- + +## 九、常见问题与排查指南 + +| 问题现象 | 可能原因 | 解决方案 | +|---------------------|--------------------------|------------------------| +| init 回调失败 | 模型路径错误或未下载完成 | 使用 `checkModel` 检查模型状态 | +| 渲染黑屏 | EGL 配置或纹理视图设置错误 | 使用 SDK 提供示例中的设置方法 | +| PCM 无播报效果 | 格式不符或未调用 startPush | 确保音频格式正确并调用推送方法 | +| 模型下载过慢 | 网络不稳定或 CDN 受限 | 支持自建模型文件托管服务 | + +--- + +## 十、版本记录 + +**4.0.1** + +```text +1. 支持PCM音频流驱动数字人,提升音频播放响应速度。 +2. 优化动作区间播放,可根据模型配置指定播放动作区间。 +3. 自定义音频播放器,去除Exoplayer播放依赖 +4. 提供简洁的模型下载同步管理工具 +``` + +**3.0.5** + +```text +1. 更新arm32位cpu的libonnxruntime.so版本以修复兼容问题。 +2. 修改动作区间播放函数,可以使用随机播放和顺序播放,需要主动调用停止播放动作区间以回到静默区间。 +``` + +**3.0.4** + +```text +1. 修复部分设备gl默认float低精度导致无法正常显示形象问题。 +``` + +**3.0.3** + +```text +1. 优化本地渲染。 +``` + +## 十一、🔗 开源依赖 + +| 模块 | 描述 | +|-------------------------------------------|-------------------| +| [onnx](https://github.com/onnx/onnx) | 通用AI模型标准格式 | +| [ncnn](https://github.com/Tencent/ncnn) | 高性能神经网络计算框架(腾讯) | + +--- + +如需更多帮助,请联系技术支持团队。 \ No newline at end of file diff --git a/android_glide_lint.xml b/android_glide_lint.xml new file mode 100644 index 0000000..90c96a4 --- /dev/null +++ b/android_glide_lint.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..d22ff0c --- /dev/null +++ b/build.gradle @@ -0,0 +1,39 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + repositories { + + maven { url 'https://maven.aliyun.com/repository/public/' } + maven { url 'https://maven.aliyun.com/repository/central' } + maven { url 'https://maven.aliyun.com/repository/google' } + maven { url 'https://maven.aliyun.com/repository/gradle-plugin' } + maven { url 'https://jitpack.io' } + maven { url 'https://repo1.maven.org/maven2/' } + google() + } + dependencies { + classpath 'com.android.tools.build:gradle:8.1.2' + classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.10' + } +} + +allprojects { + repositories { + + maven { url 'https://maven.aliyun.com/repository/public/' } + maven { url 'https://maven.aliyun.com/repository/central' } + maven { url 'https://maven.aliyun.com/repository/google' } + maven { url 'https://maven.aliyun.com/repository/gradle-plugin' } + maven { url 'https://jitpack.io' } + maven { url 'https://repo1.maven.org/maven2/' } + google() + } +} + +ext { + compileSdkVersion = 33 + buildToolsVersion = '30.0.2' + minSdkVersion = 24 + targetSdkVersion = 33 + versionCode = 2 + versionName = "0.0.2" +} diff --git a/demo.jks b/demo.jks new file mode 100644 index 0000000000000000000000000000000000000000..3cfe0f594f0f2bcf1d273354d7c8d0066868a86c GIT binary patch literal 2676 zcma);X*d*&7RP7C%ozJNaT$ALo0zdQlzkmbmSKoqYb26guCfjhk?m%AX~IQLg&LOK59;$#PcN(m7CUr-x$^|u4Ug>pt| z{xx!?hz$Zji9y*slCeM^ z7BEl|%zJE|ED>P6qBXHLBJB@6Jq9L#-xwA+R8*w-H(m67Z}y?&0+-$i#5RB^k?_=X zQ!m&N!s;i=JtPY$^`6&OG<6WzEVjhVBn~|%aeSk2y;(Id4NU*QidWBwN);U=jW0*s z74?2$Koy36Z1RoxE8)ChR-yo8=9f#d5Qru1gEVLzF%N&J9fvOlt&uCp@ zPL8)l#&poPAEq42 z`y*JE$D}0K7*x)pg?Q@mGXZYd0jHSO00!g6Rnne}a^G!&O!&usjhb?&9mrML@mIT~ zG6RjYW`|v!qw|t@e-{?oJ8+R&P$7xhi{k!nDegCJJnovkv!qt{W1iULi0(=ZP10OM z=E9WzzJHHaJH3UY^|-g|Y++?|!ii#)o@9$yhvD{>bQNbK^PJhO_)XiPEcnvqhVqV- zVHh%9n)AJJmC(wzqyOW9l0w(v@tsia?xRna@qhD#D!Z+ldb9nxS+B$)73p2VYJ3lU z&Se-1@NBl-J3v>(-Kw3M9|MiGy{!EqPo;jZa9uZS!OtGgXQVWGgm&GI?sF41aWZY< zrQ+;$Z1oWpOOkI2xhBIWY+?t0F74(X00y$M?9czaJ<8HsD}z|i1r*%^+4f(AZ6 zfr5%TF<~C%&o%Y)HiS6`a+ocz^am%%0WaK@Wbr0b`n?Ao8qj2gTHzL)>6llB&(;!? zE>fW1UCDk|c=5s}C){75bPM;SEdSFQO-}vpYyA>HMv!Tn!A4uX0xRzqye6uzRn{_b zAT+VkfGVWxZ8%{}8D&YW?MrXDt|Gc{OdxA|d;r1ri|KT;gy||C8i)la|HZY!mST<& zFRiLhbdkR)@ky~HT4CYS@WiZ(flB4tM~6V-4Cp%K=gHT|&w)uBZw}lOzQoZk4`Zzb zlo#ghnsfzpDC91i9}2*<9^HqG#MPE%jkATCwOm5LF_xz4>Vh7R064bat4nI$k(vm>JNXg&< zu~6Cy`&>x!X(MVVt)o>$F|92Oqi1w*Ws6Tbf5p_Z^1Ie_nBV4g9bE~}V~vEZJ^OO~ zzA1ck>z!2%>rCF>jFIrznJahmM4uz3aI@=Y`_}`@Le`=3VXAz|#?DsPWXCSB#+A_g z?u3(8(b_1X-*L$XN3)B=0Nwx}zzskUO6o7+6dDfZcksL6BZ8d@j< z*zWfdE3}jVHvENjK|sK-hWSeY{;!DM=Tp6@+Mb&zSOlcUV11aJ`L~7tpNM{_Cp&&% zI2y-lwqOAtOVElZuyo3gNyv8cYU%=%s&X>FwaOjw9HS43lYWKWh-oR6>n4jcbrp%i zcdbLJsm0-rZ9;oHnEnP4pz6+uK*p)V9OW)q3e$p z3hF-3ai{~t?~`K$)4P+fCgC`}Vvm*GYDShjJ^0f|fA;R{Tyc`n$)<0NRG||amCTr* ztQkan&q;ZRlIE45p&<{HKj7z@yYg~6DMA4 zjC`jZRZlPj9_!0l>yu*&RFU0%!1^d<4RMOxO^0JPR=K&gC;xzDavO7Ggos}eAuYN0fAS~F>5Wolu3w!Z6CJ#+aAe+}>P z&5U*KDf)ov{zGyq%5wuL(m>BMRT-@x$`ehW-j4EJ>p68!kik-JeyfQl(HNG%6Jh%9 zr|{=@$Yi7^ + variant.outputs.all { + outputFileName = "duix_client_sdk_${buildType.name}_${defaultConfig.versionName}.aar" + } + } + } + } + + externalNativeBuild { + cmake { + path "src/main/cpp/CMakeLists.txt" + version "3.18.1" + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +// kotlinOptions { +// jvmTarget = '1.8' +// } +// packagingOptions { +// exclude 'lib/**/libonnxruntime.so' +// } +} + +dependencies { + api fileTree(include: ['*.jar', '*.aar'], dir: 'libs') +} \ No newline at end of file diff --git a/duix-sdk/consumer-rules.pro b/duix-sdk/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/duix-sdk/libs/resource_loader.jar b/duix-sdk/libs/resource_loader.jar new file mode 100644 index 0000000000000000000000000000000000000000..c372c59ba3b2e91d710c252d6862b84e013cbeda GIT binary patch literal 13872 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 Cp(%v` literal 0 HcmV?d00001 diff --git a/duix-sdk/proguard-rules.pro b/duix-sdk/proguard-rules.pro new file mode 100644 index 0000000..15502f3 --- /dev/null +++ b/duix-sdk/proguard-rules.pro @@ -0,0 +1,90 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +-optimizationpasses 5 #指定代码的压缩级别 0 - 7,一般都是5,无需改变 +-dontusemixedcaseclassnames #不使用大小写混合 +#告诉Proguard 不要跳过对非公开类的处理,默认是跳过 +-dontskipnonpubliclibraryclasses #如果应用程序引入的有jar包,并且混淆jar包里面的class +-verbose #混淆时记录日志(混淆后生产映射文件 map 类名 -> 转化后类名的映射 +#指定混淆时的算法,后面的参数是一个过滤器 +#这个过滤器是谷歌推荐的算法,一般也不会改变 +-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* +#类型转换错误 添加如下代码以便过滤泛型(不写可能会出现类型转换错误,一般情况把这个加上就是了),即避免泛型被混淆 +-keepattributes Signature +#假如项目中有用到注解,应加入这行配置,对JSON实体映射也很重要,eg:fastjson +-keepattributes *Annotation* +#抛出异常时保留代码行数 +-keepattributes SourceFile,LineNumberTable +#保持 native 的方法不去混淆 +-keepclasseswithmembernames class * { + native ; +} + +#保持指定规则的方法不被混淆(Android layout 布局文件中为控件配置的onClick方法不能混淆) +-keepclassmembers class * extends android.app.Activity { + public void *(android.view.View); +} +#保持自定义控件指定规则的方法不被混淆 +-keep public class * extends android.view.View { + public (android.content.Context); + public (android.content.Context, android.util.AttributeSet); + public (android.content.Context, android.util.AttributeSet, int); + public void set*(...); +} +#保持枚举 enum 不被混淆 +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} +#保持 Parcelable 不被混淆(aidl文件不能去混淆) +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} +#需要序列化和反序列化的类不能被混淆(注:Java反射用到的类也不能被混淆) +-keepnames class * implements java.io.Serializable +#保护实现接口Serializable的类中,指定规则的类成员不被混淆 +-keepclassmembers class * implements java.io.Serializable { + static final long serialVersionUID; + private static final java.io.ObjectStreamField[] serialPersistentFields; + !static !transient ; + private void writeObject(java.io.ObjectOutputStream); + private void readObject(java.io.ObjectInputStream); + java.lang.Object writeReplace(); + java.lang.Object readResolve(); +} +#保持R文件不被混淆,否则,你的反射是获取不到资源id的 +-keep class **.R$* { *; } + +-keepclassmembers class * { + public (org.json.JSONObject); +} + +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + + +#以下针对App本身设置 + + +-keep class ai.guiji.duix.DuixNcnn{*; } \ No newline at end of file diff --git a/duix-sdk/src/main/AndroidManifest.xml b/duix-sdk/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a5918e6 --- /dev/null +++ b/duix-sdk/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/duix-sdk/src/main/cpp/CMakeLists.txt b/duix-sdk/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000..9d2577e --- /dev/null +++ b/duix-sdk/src/main/cpp/CMakeLists.txt @@ -0,0 +1,199 @@ +cmake_minimum_required(VERSION 3.13.2) +project(gjmywrt) + +#set(CMAKE_CXX_COMPILER g++) +#set(CMAKE_C_COMPILER gcc) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -fPIC -funwind-tables -fno-omit-frame-pointer") +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC ") +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_BUILD_TYPE "Debug") +set(ORT_NO_EXCEPTIONS FALSE) + +#set(DEVAUD false) +option(DEVARM "shared library support" TRUE) + +if(DEVARM) + set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/third/opencv-mobile-4.6.0-android/sdk/native/jni) + find_package(OpenCV REQUIRED core imgproc highgui) + + set(ncnn_DIR ${CMAKE_SOURCE_DIR}/third/ncnn-20231027-android-shared/${ANDROID_ABI}/lib/cmake/ncnn) + find_package(ncnn REQUIRED) + + add_library(turbojpeg STATIC IMPORTED) + set_target_properties(turbojpeg + PROPERTIES IMPORTED_LOCATION + ${CMAKE_SOURCE_DIR}/third/arm/${ANDROID_ABI}/libturbojpeg.a) + + add_library(libjpeg STATIC IMPORTED) + set_target_properties(libjpeg + PROPERTIES IMPORTED_LOCATION + ${CMAKE_SOURCE_DIR}/third/arm/${ANDROID_ABI}/libjpeg.a) + + add_library(onnx-lib SHARED IMPORTED) + set_target_properties( + onnx-lib + PROPERTIES IMPORTED_LOCATION + ${CMAKE_SOURCE_DIR}/third/arm/${ANDROID_ABI}/libonnxruntime.so) +endif() + +option(USE_OPENCV "shared library support" TRUE) +option(USE_NCNN "shared library support" TRUE) +option(USE_OPENVINO "shared library support" FALSE) +set(THIRD_INC "third/include") + +if(DEVARM) + set(THIRD_LIB "third/libarm") +else() + set(THIRD_LIB "third/lib64") +endif() + + + +if(DEVARM) + + include_directories( + include + dhcore + dhmfcc + aes + android + third/arm/include + third/arm/include/onnx + third/arm/include/ncnn + third/arm/include/turbojpeg + ) +else() + + include_directories( + include + dhcore + dhmfcc + aes + third2/include + third2/inc2404 + third2/include/onnx + third2/include/turbojpeg + third2/include/ncnn + /usr/local/include/opencv4 + ) + + link_directories( + ${CMAKE_SOURCE_DIR}/lib64 + ${CMAKE_SOURCE_DIR}/third2/lib64 + ${CMAKE_SOURCE_DIR}/third2/lib2404 + /usr/local/lib + ) +endif() + +add_library(dhcore STATIC + dhcore/dh_mem.c + dhcore/dh_data.cpp + dhcore/dh_que.cpp +) + +target_link_libraries(dhcore + -lm -lz -pthread +) + + + + + +add_library(dhmfcc STATIC + dhmfcc/dhpcm.cpp + dhmfcc/dhwenet.cpp + dhmfcc/wenetai.cpp + dhmfcc/AudioFFT.cpp + dhmfcc/iir_filter.cpp + dhmfcc/mfcc.cpp +) + +target_link_libraries(dhmfcc + dhcore + -lz -lm +) + +target_compile_options(dhmfcc PRIVATE + -std=c++17 +) + +include_directories( + include + dhunet +) + +add_library(dhunet STATIC + dhunet/jmat.cpp + dhunet/blendgram.cpp + dhunet/face_utils.cpp + dhunet/malpha.cpp + dhunet/munet.cpp +) + +target_link_libraries(dhunet + dhcore + dhmfcc + -lz -lm +) + +if(DEVARM) + + add_library(gjduix SHARED + duix/gjduix.cpp + duix/gjsimp.cpp + android/Log.cpp + android/DuixJni.cpp + android/JniHelper.cpp + aes/aes_cbc.c aes/aes_core.c aes/aes_ecb.c aes/base64.c aes/cbc128.c aes/gj_aes.c + aes/aesmain.c + ) + + target_link_libraries(gjduix + dhcore + dhmfcc + dhunet + ${OpenCV_LIBS} + ${log-lib} + ncnn + onnx-lib + libjpeg + turbojpeg + -lz -lm + -landroid + ) + +else() + add_library(gjduix SHARED + duix/gjduix.cpp + duix/gjsimp.cpp + ) + + target_link_libraries(gjduix + dhcore + dhmfcc + dhunet + -ljpeg + -lopencv_core + -lopencv_imgproc + -lopencv_highgui + -lturbojpeg + -lonnxruntime + -lncnn + -lz -lm + ) + + +endif() + + +add_executable(duixtest + #iostest/testduix.cpp + iostest/testsimp.cpp +) + +target_link_libraries(duixtest + dhcore + gjduix +) + diff --git a/duix-sdk/src/main/cpp/aes/aes.h b/duix-sdk/src/main/cpp/aes/aes.h new file mode 100644 index 0000000..854538e --- /dev/null +++ b/duix-sdk/src/main/cpp/aes/aes.h @@ -0,0 +1,41 @@ + + +#ifndef HEADER_AES_H +# define HEADER_AES_H + +# include + +# define AES_ENCRYPT 1 +# define AES_DECRYPT 0 + +# define AES_MAXNR 14 +# define AES_BLOCK_SIZE 16 + +struct aes_key_st { +# ifdef AES_LONG + unsigned long rd_key[4 * (AES_MAXNR + 1)]; +# else + unsigned int rd_key[4 * (AES_MAXNR + 1)]; +# endif + int rounds; +}; + +typedef struct aes_key_st AES_KEY; + + +int AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key); +int AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key); + +void AES_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key); +void AES_decrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key); + +void AES_ecb_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key, + const int enc); + +void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const AES_KEY *key, + unsigned char *ivec, const int enc); + +#endif + + diff --git a/duix-sdk/src/main/cpp/aes/aes_cbc.c b/duix-sdk/src/main/cpp/aes/aes_cbc.c new file mode 100644 index 0000000..3925bb1 --- /dev/null +++ b/duix-sdk/src/main/cpp/aes/aes_cbc.c @@ -0,0 +1,23 @@ +/* + * Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "aes.h" +#include "modes.h" + +void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + size_t len, const AES_KEY *key, + unsigned char *ivec, const int enc) +{ + + if (enc) + CRYPTO_cbc128_encrypt(in, out, len, key, ivec, + (block128_f) AES_encrypt); + else + CRYPTO_cbc128_decrypt(in, out, len, key, ivec, (block128_f) AES_decrypt); +} diff --git a/duix-sdk/src/main/cpp/aes/aes_core.c b/duix-sdk/src/main/cpp/aes/aes_core.c new file mode 100644 index 0000000..5801309 --- /dev/null +++ b/duix-sdk/src/main/cpp/aes/aes_core.c @@ -0,0 +1,1127 @@ +#include + +#include "aes.h" +#include "aes_locl.h" + + + +/*- +Te0[x] = S [x].[02, 01, 01, 03]; +Te1[x] = S [x].[03, 02, 01, 01]; +Te2[x] = S [x].[01, 03, 02, 01]; +Te3[x] = S [x].[01, 01, 03, 02]; + +Td0[x] = Si[x].[0e, 09, 0d, 0b]; +Td1[x] = Si[x].[0b, 0e, 09, 0d]; +Td2[x] = Si[x].[0d, 0b, 0e, 09]; +Td3[x] = Si[x].[09, 0d, 0b, 0e]; +Td4[x] = Si[x].[01]; +*/ + +static const u32 Te0[256] = { + 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, + 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, + 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, + 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, + 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, + 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, + 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, + 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, + 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, + 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, + 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, + 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, + 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, + 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, + 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, + 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, + 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, + 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, + 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, + 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, + 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, + 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, + 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, + 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, + 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, + 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, + 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, + 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, + 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, + 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, + 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, + 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, + 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, + 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, + 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, + 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, + 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, + 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, + 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, + 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, + 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, + 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, + 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, + 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, + 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, + 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, + 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, + 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, + 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, + 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, + 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, + 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, + 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, + 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, + 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, + 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, + 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, + 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, + 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, + 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, + 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, + 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, + 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, + 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, +}; +static const u32 Te1[256] = { + 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, + 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, + 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, + 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, + 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, + 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, + 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, + 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, + 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, + 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, + 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, + 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, + 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, + 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, + 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, + 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, + 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, + 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, + 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, + 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, + 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, + 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, + 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, + 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, + 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, + 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, + 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, + 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, + 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, + 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, + 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, + 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, + 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, + 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, + 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, + 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, + 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, + 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, + 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, + 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, + 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, + 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, + 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, + 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, + 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, + 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, + 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, + 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, + 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, + 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, + 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, + 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, + 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, + 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, + 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, + 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, + 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, + 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, + 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, + 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, + 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, + 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, + 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, + 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, +}; +static const u32 Te2[256] = { + 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, + 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, + 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, + 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, + 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, + 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, + 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, + 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, + 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, + 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, + 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, + 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, + 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, + 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, + 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, + 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, + 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, + 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, + 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, + 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, + 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, + 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, + 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, + 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, + 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, + 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, + 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, + 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, + 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, + 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, + 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, + 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, + 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, + 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, + 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, + 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, + 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, + 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, + 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, + 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, + 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, + 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, + 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, + 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, + 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, + 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, + 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, + 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, + 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, + 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, + 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, + 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, + 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, + 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, + 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, + 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, + 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, + 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, + 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, + 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, + 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, + 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, + 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, + 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, +}; +static const u32 Te3[256] = { + 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, + 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, + 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, + 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, + 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, + 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, + 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, + 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, + 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, + 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, + 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, + 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, + 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, + 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, + 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, + 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, + 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, + 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, + 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, + 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, + 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, + 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, + 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, + 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, + 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, + 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, + 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, + 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, + 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, + 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, + 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, + 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, + 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, + 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, + 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, + 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, + 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, + 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, + 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, + 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, + 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, + 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, + 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, + 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, + 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, + 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, + 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, + 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, + 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, + 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, + 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, + 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, + 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, + 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, + 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, + 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, + 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, + 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, + 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, + 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, + 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, + 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, + 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, + 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, +}; + +static const u32 Td0[256] = { + 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, + 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, + 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, + 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, + 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, + 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, + 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, + 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, + 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, + 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, + 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, + 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, + 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, + 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, + 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, + 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, + 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, + 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, + 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, + 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, + 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, + 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, + 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, + 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, + 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, + 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, + 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, + 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, + 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, + 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, + 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, + 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, + 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, + 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, + 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, + 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, + 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, + 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, + 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, + 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, + 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, + 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, + 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, + 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, + 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, + 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, + 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, + 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, + 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, + 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, + 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, + 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, + 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, + 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, + 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, + 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, + 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, + 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, + 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, + 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, + 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, + 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, + 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, + 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, +}; +static const u32 Td1[256] = { + 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, + 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, + 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, + 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, + 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, + 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, + 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, + 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, + 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, + 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, + 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, + 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, + 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, + 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, + 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, + 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, + 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, + 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, + 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, + 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, + 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, + 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, + 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, + 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, + 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, + 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, + 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, + 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, + 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, + 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, + 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, + 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, + 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, + 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, + 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, + 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, + 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, + 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, + 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, + 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, + 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, + 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, + 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, + 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, + 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, + 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, + 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, + 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, + 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, + 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, + 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, + 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, + 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, + 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, + 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, + 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, + 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, + 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, + 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, + 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, + 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, + 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, + 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, + 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, +}; +static const u32 Td2[256] = { + 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, + 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, + 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, + 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, + 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, + 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, + 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, + 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, + 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, + 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, + 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, + 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, + 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, + 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, + 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, + 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, + 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, + 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, + 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, + 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, + 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, + 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, + 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, + 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, + 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, + 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, + 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, + 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, + 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, + 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, + 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, + 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, + 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, + 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, + 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, + 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, + 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, + 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, + 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, + 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, + 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, + 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, + 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, + 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, + 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, + 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, + 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, + 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, + 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, + 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, + 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, + 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, + 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, + 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, + 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, + 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, + 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, + 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, + 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, + 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, + 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, + 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, + 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, + 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, +}; +static const u32 Td3[256] = { + 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, + 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, + 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, + 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, + 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, + 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, + 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, + 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, + 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, + 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, + 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, + 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, + 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, + 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, + 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, + 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, + 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, + 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, + 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, + 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, + 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, + 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, + 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, + 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, + 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, + 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, + 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, + 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, + 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, + 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, + 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, + 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, + 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, + 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, + 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, + 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, + 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, + 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, + 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, + 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, + 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, + 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, + 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, + 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, + 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, + 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, + 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, + 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, + 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, + 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, + 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, + 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, + 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, + 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, + 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, + 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, + 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, + 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, + 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, + 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, + 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, + 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, + 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, + 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, +}; +static const u8 Td4[256] = { + 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, + 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, + 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, + 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, + 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, + 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU, + 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U, + 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, + 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, + 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U, + 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, + 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, + 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, + 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U, + 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, + 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, + 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, + 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U, + 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, + 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, + 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, + 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, + 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, + 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, + 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, + 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, + 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, + 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU, + 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, + 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, + 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, + 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU, +}; +static const u32 rcon[] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; + +/** + * Expand the cipher key into the encryption key schedule. + */ +int AES_set_encrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key) +{ + + u32 *rk; + int i = 0; + u32 temp; + + if (!userKey || !key) + return -1; + if (bits != 128 && bits != 192 && bits != 256) + return -2; + + rk = key->rd_key; + + if (bits == 128) + key->rounds = 10; + else if (bits == 192) + key->rounds = 12; + else + key->rounds = 14; + + rk[0] = GETU32(userKey ); + rk[1] = GETU32(userKey + 4); + rk[2] = GETU32(userKey + 8); + rk[3] = GETU32(userKey + 12); + if (bits == 128) { + while (1) { + temp = rk[3]; + rk[4] = rk[0] ^ + (Te2[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te0[(temp ) & 0xff] & 0x0000ff00) ^ + (Te1[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + if (++i == 10) { + return 0; + } + rk += 4; + } + } + rk[4] = GETU32(userKey + 16); + rk[5] = GETU32(userKey + 20); + if (bits == 192) { + while (1) { + temp = rk[ 5]; + rk[ 6] = rk[ 0] ^ + (Te2[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te0[(temp ) & 0xff] & 0x0000ff00) ^ + (Te1[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 7] = rk[ 1] ^ rk[ 6]; + rk[ 8] = rk[ 2] ^ rk[ 7]; + rk[ 9] = rk[ 3] ^ rk[ 8]; + if (++i == 8) { + return 0; + } + rk[10] = rk[ 4] ^ rk[ 9]; + rk[11] = rk[ 5] ^ rk[10]; + rk += 6; + } + } + rk[6] = GETU32(userKey + 24); + rk[7] = GETU32(userKey + 28); + if (bits == 256) { + while (1) { + temp = rk[ 7]; + rk[ 8] = rk[ 0] ^ + (Te2[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te0[(temp ) & 0xff] & 0x0000ff00) ^ + (Te1[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 9] = rk[ 1] ^ rk[ 8]; + rk[10] = rk[ 2] ^ rk[ 9]; + rk[11] = rk[ 3] ^ rk[10]; + if (++i == 7) { + return 0; + } + temp = rk[11]; + rk[12] = rk[ 4] ^ + (Te2[(temp >> 24) ] & 0xff000000) ^ + (Te3[(temp >> 16) & 0xff] & 0x00ff0000) ^ + (Te0[(temp >> 8) & 0xff] & 0x0000ff00) ^ + (Te1[(temp ) & 0xff] & 0x000000ff); + rk[13] = rk[ 5] ^ rk[12]; + rk[14] = rk[ 6] ^ rk[13]; + rk[15] = rk[ 7] ^ rk[14]; + + rk += 8; + } + } + return 0; +} + +/** + * Expand the cipher key into the decryption key schedule. + */ +int AES_set_decrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key) +{ + + u32 *rk; + int i, j, status; + u32 temp; + + /* first, start with an encryption schedule */ + status = AES_set_encrypt_key(userKey, bits, key); + if (status < 0) + return status; + + rk = key->rd_key; + + /* invert the order of the round keys: */ + for (i = 0, j = 4*(key->rounds); i < j; i += 4, j -= 4) { + temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; + temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; + temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; + temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; + } + /* apply the inverse MixColumn transform to all round keys but the first and the last: */ + for (i = 1; i < (key->rounds); i++) { + rk += 4; + rk[0] = + Td0[Te1[(rk[0] >> 24) ] & 0xff] ^ + Td1[Te1[(rk[0] >> 16) & 0xff] & 0xff] ^ + Td2[Te1[(rk[0] >> 8) & 0xff] & 0xff] ^ + Td3[Te1[(rk[0] ) & 0xff] & 0xff]; + rk[1] = + Td0[Te1[(rk[1] >> 24) ] & 0xff] ^ + Td1[Te1[(rk[1] >> 16) & 0xff] & 0xff] ^ + Td2[Te1[(rk[1] >> 8) & 0xff] & 0xff] ^ + Td3[Te1[(rk[1] ) & 0xff] & 0xff]; + rk[2] = + Td0[Te1[(rk[2] >> 24) ] & 0xff] ^ + Td1[Te1[(rk[2] >> 16) & 0xff] & 0xff] ^ + Td2[Te1[(rk[2] >> 8) & 0xff] & 0xff] ^ + Td3[Te1[(rk[2] ) & 0xff] & 0xff]; + rk[3] = + Td0[Te1[(rk[3] >> 24) ] & 0xff] ^ + Td1[Te1[(rk[3] >> 16) & 0xff] & 0xff] ^ + Td2[Te1[(rk[3] >> 8) & 0xff] & 0xff] ^ + Td3[Te1[(rk[3] ) & 0xff] & 0xff]; + } + return 0; +} + +/* + * Encrypt a single block + * in and out can overlap + */ +void AES_encrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key) { + + const u32 *rk; + u32 s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + assert(in && out && key); + rk = key->rd_key; + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(in ) ^ rk[0]; + s1 = GETU32(in + 4) ^ rk[1]; + s2 = GETU32(in + 8) ^ rk[2]; + s3 = GETU32(in + 12) ^ rk[3]; +#ifdef FULL_UNROLL + /* round 1: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7]; + /* round 2: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39]; + if (key->rounds > 10) { + /* round 10: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47]; + if (key->rounds > 12) { + /* round 12: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55]; + } + } + rk += key->rounds << 2; +#else /* !FULL_UNROLL */ + /* + * Nr - 1 full rounds: + */ + r = key->rounds >> 1; + for (;;) { + t0 = + Te0[(s0 >> 24) ] ^ + Te1[(s1 >> 16) & 0xff] ^ + Te2[(s2 >> 8) & 0xff] ^ + Te3[(s3 ) & 0xff] ^ + rk[4]; + t1 = + Te0[(s1 >> 24) ] ^ + Te1[(s2 >> 16) & 0xff] ^ + Te2[(s3 >> 8) & 0xff] ^ + Te3[(s0 ) & 0xff] ^ + rk[5]; + t2 = + Te0[(s2 >> 24) ] ^ + Te1[(s3 >> 16) & 0xff] ^ + Te2[(s0 >> 8) & 0xff] ^ + Te3[(s1 ) & 0xff] ^ + rk[6]; + t3 = + Te0[(s3 >> 24) ] ^ + Te1[(s0 >> 16) & 0xff] ^ + Te2[(s1 >> 8) & 0xff] ^ + Te3[(s2 ) & 0xff] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Te0[(t0 >> 24) ] ^ + Te1[(t1 >> 16) & 0xff] ^ + Te2[(t2 >> 8) & 0xff] ^ + Te3[(t3 ) & 0xff] ^ + rk[0]; + s1 = + Te0[(t1 >> 24) ] ^ + Te1[(t2 >> 16) & 0xff] ^ + Te2[(t3 >> 8) & 0xff] ^ + Te3[(t0 ) & 0xff] ^ + rk[1]; + s2 = + Te0[(t2 >> 24) ] ^ + Te1[(t3 >> 16) & 0xff] ^ + Te2[(t0 >> 8) & 0xff] ^ + Te3[(t1 ) & 0xff] ^ + rk[2]; + s3 = + Te0[(t3 >> 24) ] ^ + Te1[(t0 >> 16) & 0xff] ^ + Te2[(t1 >> 8) & 0xff] ^ + Te3[(t2 ) & 0xff] ^ + rk[3]; + } +#endif /* ?FULL_UNROLL */ + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Te2[(t0 >> 24) ] & 0xff000000) ^ + (Te3[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Te0[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Te1[(t3 ) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(out , s0); + s1 = + (Te2[(t1 >> 24) ] & 0xff000000) ^ + (Te3[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Te0[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Te1[(t0 ) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(out + 4, s1); + s2 = + (Te2[(t2 >> 24) ] & 0xff000000) ^ + (Te3[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Te0[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Te1[(t1 ) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(out + 8, s2); + s3 = + (Te2[(t3 >> 24) ] & 0xff000000) ^ + (Te3[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Te0[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Te1[(t2 ) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(out + 12, s3); +} + +/* + * Decrypt a single block + * in and out can overlap + */ +void AES_decrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key) +{ + + const u32 *rk; + u32 s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + assert(in && out && key); + rk = key->rd_key; + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(in ) ^ rk[0]; + s1 = GETU32(in + 4) ^ rk[1]; + s2 = GETU32(in + 8) ^ rk[2]; + s3 = GETU32(in + 12) ^ rk[3]; +#ifdef FULL_UNROLL + /* round 1: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7]; + /* round 2: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39]; + if (key->rounds > 10) { + /* round 10: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47]; + if (key->rounds > 12) { + /* round 12: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55]; + } + } + rk += key->rounds << 2; +#else /* !FULL_UNROLL */ + /* + * Nr - 1 full rounds: + */ + r = key->rounds >> 1; + for (;;) { + t0 = + Td0[(s0 >> 24) ] ^ + Td1[(s3 >> 16) & 0xff] ^ + Td2[(s2 >> 8) & 0xff] ^ + Td3[(s1 ) & 0xff] ^ + rk[4]; + t1 = + Td0[(s1 >> 24) ] ^ + Td1[(s0 >> 16) & 0xff] ^ + Td2[(s3 >> 8) & 0xff] ^ + Td3[(s2 ) & 0xff] ^ + rk[5]; + t2 = + Td0[(s2 >> 24) ] ^ + Td1[(s1 >> 16) & 0xff] ^ + Td2[(s0 >> 8) & 0xff] ^ + Td3[(s3 ) & 0xff] ^ + rk[6]; + t3 = + Td0[(s3 >> 24) ] ^ + Td1[(s2 >> 16) & 0xff] ^ + Td2[(s1 >> 8) & 0xff] ^ + Td3[(s0 ) & 0xff] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Td0[(t0 >> 24) ] ^ + Td1[(t3 >> 16) & 0xff] ^ + Td2[(t2 >> 8) & 0xff] ^ + Td3[(t1 ) & 0xff] ^ + rk[0]; + s1 = + Td0[(t1 >> 24) ] ^ + Td1[(t0 >> 16) & 0xff] ^ + Td2[(t3 >> 8) & 0xff] ^ + Td3[(t2 ) & 0xff] ^ + rk[1]; + s2 = + Td0[(t2 >> 24) ] ^ + Td1[(t1 >> 16) & 0xff] ^ + Td2[(t0 >> 8) & 0xff] ^ + Td3[(t3 ) & 0xff] ^ + rk[2]; + s3 = + Td0[(t3 >> 24) ] ^ + Td1[(t2 >> 16) & 0xff] ^ + Td2[(t1 >> 8) & 0xff] ^ + Td3[(t0 ) & 0xff] ^ + rk[3]; + } +#endif /* ?FULL_UNROLL */ + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + ((u32)Td4[(t0 >> 24) ] << 24) ^ + ((u32)Td4[(t3 >> 16) & 0xff] << 16) ^ + ((u32)Td4[(t2 >> 8) & 0xff] << 8) ^ + ((u32)Td4[(t1 ) & 0xff]) ^ + rk[0]; + PUTU32(out , s0); + s1 = + ((u32)Td4[(t1 >> 24) ] << 24) ^ + ((u32)Td4[(t0 >> 16) & 0xff] << 16) ^ + ((u32)Td4[(t3 >> 8) & 0xff] << 8) ^ + ((u32)Td4[(t2 ) & 0xff]) ^ + rk[1]; + PUTU32(out + 4, s1); + s2 = + ((u32)Td4[(t2 >> 24) ] << 24) ^ + ((u32)Td4[(t1 >> 16) & 0xff] << 16) ^ + ((u32)Td4[(t0 >> 8) & 0xff] << 8) ^ + ((u32)Td4[(t3 ) & 0xff]) ^ + rk[2]; + PUTU32(out + 8, s2); + s3 = + ((u32)Td4[(t3 >> 24) ] << 24) ^ + ((u32)Td4[(t2 >> 16) & 0xff] << 16) ^ + ((u32)Td4[(t1 >> 8) & 0xff] << 8) ^ + ((u32)Td4[(t0 ) & 0xff]) ^ + rk[3]; + PUTU32(out + 12, s3); +} + + diff --git a/duix-sdk/src/main/cpp/aes/aes_ecb.c b/duix-sdk/src/main/cpp/aes/aes_ecb.c new file mode 100644 index 0000000..6476803 --- /dev/null +++ b/duix-sdk/src/main/cpp/aes/aes_ecb.c @@ -0,0 +1,24 @@ +/* + * Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include + +#include "aes.h" +#include "aes_locl.h" + +void AES_ecb_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key, const int enc) +{ + assert(in && out && key); + assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc)); + + if (AES_ENCRYPT == enc) + AES_encrypt(in, out, key); + else + AES_decrypt(in, out, key); +} diff --git a/duix-sdk/src/main/cpp/aes/aes_locl.h b/duix-sdk/src/main/cpp/aes/aes_locl.h new file mode 100644 index 0000000..47d1dfa --- /dev/null +++ b/duix-sdk/src/main/cpp/aes/aes_locl.h @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_AES_LOCL_H +# define HEADER_AES_LOCL_H + +//# include +# include +# include +# include + +# if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64)) +# define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00) +# define GETU32(p) SWAP(*((u32 *)(p))) +# define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); } +# else +# define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) +# define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } +# endif + +# ifdef AES_LONG +typedef unsigned long u32; +# else +typedef unsigned int u32; +# endif +typedef unsigned short u16; +typedef unsigned char u8; + +# define MAXKC (256/32) +# define MAXKB (256/8) +# define MAXNR 14 + +/* This controls loop-unrolling in aes_core.c */ +# undef FULL_UNROLL + +#endif /* !HEADER_AES_LOCL_H */ diff --git a/duix-sdk/src/main/cpp/aes/aesmain.c b/duix-sdk/src/main/cpp/aes/aesmain.c new file mode 100644 index 0000000..547eaf5 --- /dev/null +++ b/duix-sdk/src/main/cpp/aes/aesmain.c @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include "gj_aes.h" +#include "aesmain.h" + +int mainenc(int enc,char* infn,char* outfn){ + char result[255] ; + memset(result,0,255); + char* key = "yymrjzbwyrbjszrk"; + char* aiv = "yymrjzbwyrbjszrk"; + int base64 = 1; + int outlen = 0; + int encrst = 0; + char* fn1 = infn; + char* fn2 = outfn; + FILE* fr = fopen(fn1,"rb"); + FILE* fw = fopen(fn2,"wb"); + while(1){ + if(!fr){ + encrst = -1001; + break; + } + if(!fw){ + encrst = -1002; + break; + } + gj_aesc_t* aesc = NULL; + init_aesc(key,aiv,enc,&aesc); + uint64_t size = 0; + uint64_t realsize = 0; + if(enc){ + fwrite("gjdigits",1,8,fw); + fwrite(&size,1,8,fw); + fwrite(&size,1,8,fw); + fwrite(&size,1,8,fw); + + while(!feof(fr)){ + char data[16]; + memset(data,0,16); + uint64_t rst = fread(data,1,16,fr); + if(rst){ + size +=rst; + do_aesc(aesc,data,16,result,&outlen); + fwrite(result,1,outlen,fw); + } + } + fseek(fw,8,0); + fwrite(&size,1,8,fw); + + }else{ + uint64_t rst = fread(result,1,32,fr); + if(!rst){ + encrst = -1003; + break; + } + if((result[0]!='g')||(result[1]!='j')){ + encrst = -1004; + break; + } + uint64_t *psize = (uint64_t*)(result+8); + realsize = *psize; + if(realsize>1034*1024*1024){ + encrst = -1005; + break; + } + while(!feof(fr)){ + char data[16]; + memset(data,0,16); + uint64_t rst = fread(data,1,16,fr); + if(rst){ + size +=rst; + do_aesc(aesc,data,16,result,&outlen); + if(size>realsize){ + outlen -= (size-realsize); + //printf("===%lu > %lu rst %lu %d outlen \n",size,realsize,rst,outlen); + } + fwrite(result,1,outlen,fw); + } + } + } + break; + } + if(fr) fclose(fr); + if(fw) fclose(fw); + return encrst; +} + + +#ifdef TEST +int main(int argc,char** argv){ + if(argc<4){ + printf("gaes enc|dec filein fileout\n"); + return 0; + } + char k = argv[1][0]; + if(k=='e'){ + int rst = mainenc(1,argv[2],argv[3]); + printf("====enc %s to %s rst %d\n",argv[2],argv[3],rst); + return rst; + }else if(k=='d'){ + int rst = mainenc(0,argv[2],argv[3]); + printf("====dec %s to %s rst %d\n",argv[2],argv[3],rst); + return rst; + }else{ + printf("gaes enc|dec filein fileout\n"); + return 0; + } +} +#endif diff --git a/duix-sdk/src/main/cpp/aes/aesmain.h b/duix-sdk/src/main/cpp/aes/aesmain.h new file mode 100644 index 0000000..48e53df --- /dev/null +++ b/duix-sdk/src/main/cpp/aes/aesmain.h @@ -0,0 +1,16 @@ + +#ifndef __AESMAIN_H +#define __AESMAIN_H + +#include "gj_dll.h" +#ifdef __cplusplus +extern "C" { +#endif + +int mainenc(int enc,char* infn,char* outfn); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/duix-sdk/src/main/cpp/aes/base64.c b/duix-sdk/src/main/cpp/aes/base64.c new file mode 100644 index 0000000..a35725d --- /dev/null +++ b/duix-sdk/src/main/cpp/aes/base64.c @@ -0,0 +1,164 @@ +/* This is a public domain base64 implementation written by WEI Zhicheng. */ + +#include "base64.h" + +#define BASE64_PAD '=' +#define BASE64DE_FIRST '+' +#define BASE64DE_LAST 'z' + +/* BASE 64 encode table */ +static const char base64en[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/', +}; + +/* ASCII order for BASE 64 decode, 255 in unused character */ +static const unsigned char base64de[] = { + /* nul, soh, stx, etx, eot, enq, ack, bel, */ + 255, 255, 255, 255, 255, 255, 255, 255, + + /* bs, ht, nl, vt, np, cr, so, si, */ + 255, 255, 255, 255, 255, 255, 255, 255, + + /* dle, dc1, dc2, dc3, dc4, nak, syn, etb, */ + 255, 255, 255, 255, 255, 255, 255, 255, + + /* can, em, sub, esc, fs, gs, rs, us, */ + 255, 255, 255, 255, 255, 255, 255, 255, + + /* sp, '!', '"', '#', '$', '%', '&', ''', */ + 255, 255, 255, 255, 255, 255, 255, 255, + + /* '(', ')', '*', '+', ',', '-', '.', '/', */ + 255, 255, 255, 62, 255, 255, 255, 63, + + /* '0', '1', '2', '3', '4', '5', '6', '7', */ + 52, 53, 54, 55, 56, 57, 58, 59, + + /* '8', '9', ':', ';', '<', '=', '>', '?', */ + 60, 61, 255, 255, 255, 255, 255, 255, + + /* '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', */ + 255, 0, 1, 2, 3, 4, 5, 6, + + /* 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', */ + 7, 8, 9, 10, 11, 12, 13, 14, + + /* 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', */ + 15, 16, 17, 18, 19, 20, 21, 22, + + /* 'X', 'Y', 'Z', '[', '\', ']', '^', '_', */ + 23, 24, 25, 255, 255, 255, 255, 255, + + /* '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', */ + 255, 26, 27, 28, 29, 30, 31, 32, + + /* 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', */ + 33, 34, 35, 36, 37, 38, 39, 40, + + /* 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', */ + 41, 42, 43, 44, 45, 46, 47, 48, + + /* 'x', 'y', 'z', '{', '|', '}', '~', del, */ + 49, 50, 51, 255, 255, 255, 255, 255 +}; + +unsigned int +gjbase64_encode(const unsigned char *in, unsigned int inlen, char *out) +{ + int s; + unsigned int i; + unsigned int j; + unsigned char c; + unsigned char l; + + s = 0; + l = 0; + for (i = j = 0; i < inlen; i++) { + c = in[i]; + + switch (s) { + case 0: + s = 1; + out[j++] = base64en[(c >> 2) & 0x3F]; + break; + case 1: + s = 2; + out[j++] = base64en[((l & 0x3) << 4) | ((c >> 4) & 0xF)]; + break; + case 2: + s = 0; + out[j++] = base64en[((l & 0xF) << 2) | ((c >> 6) & 0x3)]; + out[j++] = base64en[c & 0x3F]; + break; + } + l = c; + } + + switch (s) { + case 1: + out[j++] = base64en[(l & 0x3) << 4]; + out[j++] = BASE64_PAD; + out[j++] = BASE64_PAD; + break; + case 2: + out[j++] = base64en[(l & 0xF) << 2]; + out[j++] = BASE64_PAD; + break; + } + + out[j] = 0; + + return j; +} + +unsigned int +gjbase64_decode(const char *in, unsigned int inlen, unsigned char *out) +{ + unsigned int i; + unsigned int j; + unsigned char c; + + if (inlen & 0x3) { + return 0; + } + + for (i = j = 0; i < inlen; i++) { + if (in[i] == BASE64_PAD) { + break; + } + if (in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST) { + return 0; + } + + c = base64de[(unsigned char)in[i]]; + if (c == 255) { + return 0; + } + + switch (i & 0x3) { + case 0: + out[j] = (c << 2) & 0xFF; + break; + case 1: + out[j++] |= (c >> 4) & 0x3; + out[j] = (c & 0xF) << 4; + break; + case 2: + out[j++] |= (c >> 2) & 0xF; + out[j] = (c & 0x3) << 6; + break; + case 3: + out[j++] |= c; + break; + } + } + + return j; +} diff --git a/duix-sdk/src/main/cpp/aes/base64.h b/duix-sdk/src/main/cpp/aes/base64.h new file mode 100644 index 0000000..34ad948 --- /dev/null +++ b/duix-sdk/src/main/cpp/aes/base64.h @@ -0,0 +1,29 @@ +#ifndef BASE64_H +#define BASE64_H + +#define BASE64_ENCODE_OUT_SIZE(s) ((unsigned int)((((s) + 2) / 3) * 4 + 1)) +#define BASE64_DECODE_OUT_SIZE(s) ((unsigned int)(((s) / 4) * 3)) + +#ifdef __cplusplus +extern "C"{ +#endif + +/* + * out is null-terminated encode string. + * return values is out length, exclusive terminating `\0' + */ +unsigned int +gjbase64_encode(const unsigned char *in, unsigned int inlen, char *out); + +/* + * return values is out length + */ +unsigned int +gjbase64_decode(const char *in, unsigned int inlen, unsigned char *out); + +#ifdef __cplusplus +} +#endif + + +#endif /* BASE64_H */ diff --git a/duix-sdk/src/main/cpp/aes/cbc128.c b/duix-sdk/src/main/cpp/aes/cbc128.c new file mode 100644 index 0000000..f10d9ca --- /dev/null +++ b/duix-sdk/src/main/cpp/aes/cbc128.c @@ -0,0 +1,161 @@ +/* + * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +// #include +#include "modes.h" +#include + +#if !defined(STRICT_ALIGNMENT) && !defined(PEDANTIC) +# define STRICT_ALIGNMENT 0 +#endif + +void CRYPTO_cbc128_encrypt(const unsigned char *in, unsigned char *out, + size_t len, const void *key, + unsigned char ivec[16], block128_f block) +{ + size_t n; + const unsigned char *iv = ivec; + + if (len == 0) + return; + +#if !defined(OPENSSL_SMALL_FOOTPRINT) + if (STRICT_ALIGNMENT && + ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { + while (len >= 16) { + for (n = 0; n < 16; ++n) + out[n] = in[n] ^ iv[n]; + (*block) (out, out, key); + iv = out; + len -= 16; + in += 16; + out += 16; + } + } else { + while (len >= 16) { + for (n = 0; n < 16; n += sizeof(size_t)) + *(size_t *)(out + n) = + *(size_t *)(in + n) ^ *(size_t *)(iv + n); + (*block) (out, out, key); + iv = out; + len -= 16; + in += 16; + out += 16; + } + } +#endif + while (len) { + for (n = 0; n < 16 && n < len; ++n) + out[n] = in[n] ^ iv[n]; + for (; n < 16; ++n) + out[n] = iv[n]; + (*block) (out, out, key); + iv = out; + if (len <= 16) + break; + len -= 16; + in += 16; + out += 16; + } + memcpy(ivec, iv, 16); +} + +void CRYPTO_cbc128_decrypt(const unsigned char *in, unsigned char *out, + size_t len, const void *key, + unsigned char ivec[16], block128_f block) +{ + size_t n; + union { + size_t t[16 / sizeof(size_t)]; + unsigned char c[16]; + } tmp; + + if (len == 0) + return; + +#if !defined(OPENSSL_SMALL_FOOTPRINT) + if (in != out) { + const unsigned char *iv = ivec; + + if (STRICT_ALIGNMENT && + ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { + while (len >= 16) { + (*block) (in, out, key); + for (n = 0; n < 16; ++n) + out[n] ^= iv[n]; + iv = in; + len -= 16; + in += 16; + out += 16; + } + } else if (16 % sizeof(size_t) == 0) { /* always true */ + while (len >= 16) { + size_t *out_t = (size_t *)out, *iv_t = (size_t *)iv; + + (*block) (in, out, key); + for (n = 0; n < 16 / sizeof(size_t); n++) + out_t[n] ^= iv_t[n]; + iv = in; + len -= 16; + in += 16; + out += 16; + } + } + memcpy(ivec, iv, 16); + } else { + if (STRICT_ALIGNMENT && + ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { + unsigned char c; + while (len >= 16) { + (*block) (in, tmp.c, key); + for (n = 0; n < 16; ++n) { + c = in[n]; + out[n] = tmp.c[n] ^ ivec[n]; + ivec[n] = c; + } + len -= 16; + in += 16; + out += 16; + } + } else if (16 % sizeof(size_t) == 0) { /* always true */ + while (len >= 16) { + size_t c, *out_t = (size_t *)out, *ivec_t = (size_t *)ivec; + const size_t *in_t = (const size_t *)in; + + (*block) (in, tmp.c, key); + for (n = 0; n < 16 / sizeof(size_t); n++) { + c = in_t[n]; + out_t[n] = tmp.t[n] ^ ivec_t[n]; + ivec_t[n] = c; + } + len -= 16; + in += 16; + out += 16; + } + } + } +#endif + while (len) { + unsigned char c; + (*block) (in, tmp.c, key); + for (n = 0; n < 16 && n < len; ++n) { + c = in[n]; + out[n] = tmp.c[n] ^ ivec[n]; + ivec[n] = c; + } + if (len <= 16) { + for (; n < 16; ++n) + ivec[n] = in[n]; + break; + } + len -= 16; + in += 16; + out += 16; + } +} diff --git a/duix-sdk/src/main/cpp/aes/gaes_stream.cc b/duix-sdk/src/main/cpp/aes/gaes_stream.cc new file mode 100644 index 0000000..b8812cd --- /dev/null +++ b/duix-sdk/src/main/cpp/aes/gaes_stream.cc @@ -0,0 +1,213 @@ + +#include "gaes_stream.h" + +#include +#include +#include +#include +#include +#include +#include "gj_aes.h" + + +class GaesIStreamBuf final: public std::streambuf +{ +private: + char *m_inbuf; + size_t m_inbufsize; + bool m_owns_inbuf; + char *m_leftbuf; + + FILE *file; + uint64_t cur_size; + uint64_t file_size; + gj_aesc_t* aesc ; +protected: + virtual std::streambuf* setbuf(char *s, std::streamsize n){ + setg(0, 0, 0); + if (m_owns_inbuf) { + delete [] m_inbuf; + } + m_inbufsize = n; + if (s) { + m_inbuf = s; + m_owns_inbuf = false; + } else { + m_inbuf = new char[m_inbufsize]; + m_leftbuf = new char[m_inbufsize]; + m_owns_inbuf = true; + } + return this; + } + + virtual int sync(){ + int result = 0; + return result; + } + + virtual int underflow() override{ + int __c = traits_type::eof(); + if (!file) return __c; + if(cur_size>=file_size){ + printf("===eof %ld ===%ld\n",cur_size,file_size); + return __c; + } + bool initial = false; + if (eback() == 0) { + setg(m_inbuf, m_inbuf + m_inbufsize, m_inbuf + m_inbufsize); + initial = true; + } + const size_t unget_sz = initial ? 0 : std::min((egptr() - eback()) / 2, 4); + if (gptr() == egptr()) { + memmove(eback(), egptr() - unget_sz, unget_sz); + size_t nmemb = static_cast(egptr() - eback() - unget_sz); + char* pdst = eback() + unget_sz; + int modb = nmemb % 16; + size_t leftb = nmemb - modb; + char* pbuf = m_leftbuf; + size_t leftf = file_size - cur_size; + if(leftb>leftf)leftb=leftf; + memset(pbuf,0,m_inbufsize); + size_t rd = fread(pbuf, 1, leftb, file); + //printf("%d-%ld-%ld----------------%ld--%ld#\n",cur_size,file_size,modb,nmemb,rd); + //ssize_t readed = read(m_fd, eback() + unget_sz, nmemb); + if(rd>0){ + cur_size += rd; + int cnt = leftb /16; + int k; + for(k=0;kaesc); + char head[50]; + memset(head,0,50); + uint64_t rst = fread(head,1,8,file); + rst = fread(&cur_size,1,8,file); + printf("===head %s size %ld\n",head,cur_size); + rst = fread(head,1,16,file); + cur_size = 32; + } + + ~GaesIStreamBuf(){ + close(); + if (m_owns_inbuf) { + delete[] m_inbuf; + } + } + + void close(){ + if(aesc){ + free_aesc(&this->aesc); + } + if (file){ + fclose(file); + file = NULL; + } + } +}; + + + +GaesIStream::GaesIStream(std::string filename): + std::istream(new GaesIStreamBuf(filename)){ +} + +GaesIStream::~GaesIStream() +{ + delete rdbuf(); +} + +#ifdef TEST +int maindec(int argc,char** argv){ + std::string filename(argv[1]);// = "test.enc"; + //std::string filename = "final.mdlenc"; + GaesIStream fin(filename); + //std::string fn2 = "final.mdldec"; + std::string fn2(argv[2]);// = "test.dec"; + std::ofstream fout(fn2,std::ios::binary); + + char buf[1024]; + int rd = 0; + while(!fin.eof()){ + //while((rd = fin.read(buf,16))>0){ + //printf("===rd %ld\n",rd); + fin.read(buf,16); + fout.write(buf,16); + + } + //char ch; + //while (fin.get(ch)) { + //printf("+"); + //fout << ch; + //} + return 0; +} + + + +int mainenc(int argc,char** argv){ + char result[255] ; + memset(result,0,255); + char* key = "yymrjzbwyrbjszrk"; + char* aiv = "yymrjzbwyrbjszrk"; + int base64 = 1; + int outlen = 0; + gj_aesc_t* aesc = NULL; + init_aesc(key,aiv,1,&aesc); + char* fn1 = argv[1]; + char* fn2 = argv[2]; + FILE* fr = fopen(fn1,"rb"); + FILE* fw = fopen(fn2,"wb"); + fwrite("abcdefgh",1,8,fw); + uint64_t size = 0; + fwrite(&size,1,8,fw); + fwrite(&size,1,8,fw); + fwrite(&size,1,8,fw); + while(!feof(fr)){ + char data[16]; + memset(data,0,16); + uint64_t rst = fread(data,1,16,fr); + printf("===rst %d\n",rst); + if(rst){ + size +=rst; + do_aesc(aesc,data,16,result,&outlen); + printf("===out %d\n",outlen); + fwrite(result,1,16,fw); + } + } + fseek(fw,8,0); + fwrite(&size,1,8,fw); + fclose(fr); + fclose(fw); + return 0; +} + +int main(int argc,char** argv){ + if(argc<4){ + return mainenc(argc,argv); + }else{ + return maindec(argc,argv); + } +} +#endif diff --git a/duix-sdk/src/main/cpp/aes/gaes_stream.h b/duix-sdk/src/main/cpp/aes/gaes_stream.h new file mode 100644 index 0000000..d3e2d1d --- /dev/null +++ b/duix-sdk/src/main/cpp/aes/gaes_stream.h @@ -0,0 +1,22 @@ +#ifndef COMPRESSED_STREAMS_ZSTD_STREAM_H +#define COMPRESSED_STREAMS_ZSTD_STREAM_H + +#include + + + + + +class GaesIStream: public std::istream +{ +public: + GaesIStream(std::string filename); + + virtual ~GaesIStream(); +}; + + + + + +#endif // COMPRESSED_STREAMS_ZSTD_STREAM_H diff --git a/duix-sdk/src/main/cpp/aes/gaesmain b/duix-sdk/src/main/cpp/aes/gaesmain new file mode 100644 index 0000000000000000000000000000000000000000..c3cae0fd38f67f6bc71d88d564d9d3af7747fd46 GIT binary patch literal 64344 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

k8NG(gZFw{|*&DH8_-iALppHo={QrB{|fe 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 +#include +#include "gj_aes.h" +#include "base64.h" + +#include "aes.h" + + +struct gj_aesc_s{ + char key[16]; + char iv[16]; + int enc; + AES_KEY *aeskey; +}; + +int free_aesc(gj_aesc_t** paesc){ + if(!paesc||!*paesc)return -1; + if((*paesc)->aeskey)free((*paesc)->aeskey); + free(*paesc); + *paesc = NULL; + return 0; +} + + +int init_aesc(char* key,char* iv,int enc,gj_aesc_t** paesc){ + if(strlen(key)!=16) return -1; + if(strlen(iv)!=16) return -2; + gj_aesc_t* aesc = (gj_aesc_t*)malloc(sizeof(gj_aesc_t)); + int k; + for(k=0;k<16;k++){ + aesc->key[k]=key[k]; + aesc->iv[k]=iv[k]; + } + aesc->aeskey = (AES_KEY*)malloc(sizeof(AES_KEY)); + aesc->enc = enc; + if(enc){ + AES_set_encrypt_key((const unsigned char*)aesc->key, 128, aesc->aeskey); + }else{ + AES_set_decrypt_key((const unsigned char*)aesc->key, 128, aesc->aeskey); + } + *paesc = aesc; + return 0; +} + +int do_aesc(gj_aesc_t* aesc,char* in,int inlen,char* out,int* outlen){ + char* psrc = in; + char* pdest = out; + int cnt = 0; + int left=inlen; + while(left>0){ + AES_cbc_encrypt((const unsigned char*)psrc,(unsigned char*)pdest,16,aesc->aeskey,(unsigned char*)aesc->iv,aesc->enc); + psrc += 16; + pdest += 16; + left -= 16; + cnt += 16; + } + *outlen = cnt; + return 0; +} + +int do_base64(int enc,char* in,int inlen,char* out,int* outlen){ + if(enc){ + gjbase64_encode((unsigned char*)in,inlen,out); + *outlen = strlen(out); + }else{ + *outlen = gjbase64_decode(in,inlen,(unsigned char*)out); + } + return 0; +} diff --git a/duix-sdk/src/main/cpp/aes/gj_aes.h b/duix-sdk/src/main/cpp/aes/gj_aes.h new file mode 100644 index 0000000..a09338f --- /dev/null +++ b/duix-sdk/src/main/cpp/aes/gj_aes.h @@ -0,0 +1,22 @@ +#ifndef __GJ_AES_H__ +#define __GJ_AES_H__ + +#include "gj_dll.h" +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct gj_aesc_s gj_aesc_t; + +GJLIBAPI int free_aesc(gj_aesc_t** paesc); +GJLIBAPI int init_aesc(char* key,char* iv,int enc,gj_aesc_t** paesc); + +GJLIBAPI int do_aesc(gj_aesc_t* aesc,char* in,int inlen,char* out,int* outlen); + +GJLIBAPI int do_base64(int enc,char* in,int inlen,char* out,int* outlen); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/duix-sdk/src/main/cpp/aes/gj_dll.h b/duix-sdk/src/main/cpp/aes/gj_dll.h new file mode 100644 index 0000000..9d1c953 --- /dev/null +++ b/duix-sdk/src/main/cpp/aes/gj_dll.h @@ -0,0 +1,21 @@ +#ifndef __GJ_DLL_H__ +#define __GJ_DLL_H__ + +#ifdef __cplusplus +extern "C" { +#endif +#define GJLIB_EXPORT 1 +#if defined(GJLIB_EXPORT) + #if defined _WIN32 || defined __CYGWIN__ + #define GJLIBAPI __declspec(dllexport) + #else + #define GJLIBAPI __attribute__((visibility("default"))) + #endif +#else + #define GJLIBAPI +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/duix-sdk/src/main/cpp/aes/makefile b/duix-sdk/src/main/cpp/aes/makefile new file mode 100644 index 0000000..dbe0cac --- /dev/null +++ b/duix-sdk/src/main/cpp/aes/makefile @@ -0,0 +1,3 @@ +all: + g++ -fPIC -o gjaesmain -g aesmain.c \ + aes_cbc.c aes_core.c aes_ecb.c cbc128.c base64.c gj_aes.c -lm --std=c++11 -I. -DTEST diff --git a/duix-sdk/src/main/cpp/aes/modes.h b/duix-sdk/src/main/cpp/aes/modes.h new file mode 100644 index 0000000..8d2c17e --- /dev/null +++ b/duix-sdk/src/main/cpp/aes/modes.h @@ -0,0 +1,22 @@ +#ifndef HEADER_MODES_H +# define HEADER_MODES_H + +# include + +typedef void (*block128_f) (const unsigned char in[16], + unsigned char out[16], const void *key); + +typedef void (*cbc128_f) (const unsigned char *in, unsigned char *out, + size_t len, const void *key, + unsigned char ivec[16], int enc); + +void CRYPTO_cbc128_encrypt(const unsigned char *in, unsigned char *out, + size_t len, const void *key, + unsigned char ivec[16], block128_f block); +void CRYPTO_cbc128_decrypt(const unsigned char *in, unsigned char *out, + size_t len, const void *key, + unsigned char ivec[16], block128_f block); + + + +#endif \ No newline at end of file diff --git a/duix-sdk/src/main/cpp/android/DuixJni.cpp b/duix-sdk/src/main/cpp/android/DuixJni.cpp new file mode 100644 index 0000000..42f5a01 --- /dev/null +++ b/duix-sdk/src/main/cpp/android/DuixJni.cpp @@ -0,0 +1,243 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "gjsimp.h" +#include "JniHelper.h" +#include "aesmain.h" +#include "jmat.h" +#include "Log.h" + +#if __ARM_NEON +#include +#endif // __ARM_NEON + // + // +#define TAG "tooken" +#ifdef DEBUGME +#define JNIEXPORT +#define JNI_OnLoad +#define jint int +#define jlong long +#define jstring string +#define JNICALL +#define JavaVM void +#define LOGI(...) +#define JNIEnv void +#define jobject void* +#endif +extern "C" { + + static dhduix_t* g_digit = 0; + static JMat* g_gpgmat = NULL; + static int g_width = 540; + static int g_height = 960; + static int g_taskid = -1; + + JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { + LOGD(TAG, "JNI_OnLoad"); + //g_digit = new GDigit(g_width,g_height,g_msgcb); + JniHelper::sJavaVM = vm; + return JNI_VERSION_1_4; + } + + JNIEXPORT void JNI_OnUnload(JavaVM *vm, void *reserved) { + LOGI(TAG, "unload"); + if(g_digit){ + dhduix_free(g_digit); + g_digit = nullptr; + } + } + + static std::string getStringUTF(JNIEnv *env, jstring obj) { + char *c_str = (char *) env->GetStringUTFChars(obj, nullptr); + std::string tmpString = std::string(c_str); + env->ReleaseStringUTFChars(obj, c_str); + return tmpString; + } + + + JNIEXPORT jint JNICALL Java_ai_guiji_duix_DuixNcnn_alloc(JNIEnv *env, jobject thiz, + jint taskid,jint mincalc,jint width,jint height){ + LOGI(TAG, "create"); + g_taskid = taskid; + dhduix_alloc(&g_digit,mincalc,width,height); + return 0; + } + + JNIEXPORT jint JNICALL Java_ai_guiji_duix_DuixNcnn_free(JNIEnv *env, jobject thiz,jint taskid){ + if(g_taskid==taskid){ + dhduix_free(g_digit); + g_digit = nullptr; + } + return 0; + } + + JNIEXPORT jint JNICALL Java_ai_guiji_duix_DuixNcnn_initPcmex(JNIEnv *env, jobject thiz, + jint maxsize,jint minoff,jint minblock,jint maxblock,jint rgb){ + if(!g_digit)return -1; + int rst = dhduix_initPcmex(g_digit,maxsize,minoff,minblock,maxblock,rgb); + return rst; + } + + JNIEXPORT jint JNICALL Java_ai_guiji_duix_DuixNcnn_initWenet(JNIEnv *env, jobject thiz, + jstring fnwenet){ + if(!g_digit)return -1; + std::string str = getStringUTF(env,fnwenet); + char* ps = (char*)(str.c_str()); + int rst = dhduix_initWenet(g_digit,ps); + return rst; + } + + JNIEXPORT jint JNICALL Java_ai_guiji_duix_DuixNcnn_initMunet(JNIEnv *env, jobject thiz, + jstring fnparam,jstring fnbin,jstring fnmask){ + if(!g_digit)return -1; + std::string sparam = getStringUTF(env,fnparam); + std::string sbin = getStringUTF(env,fnbin); + std::string smask = getStringUTF(env,fnmask); + int rst = dhduix_initMunet(g_digit,(char*)sparam.c_str(),(char*)sbin.c_str(),(char*)smask.c_str()); + return rst; + } + + JNIEXPORT jint JNICALL Java_ai_guiji_duix_DuixNcnn_initMunetex(JNIEnv *env, jobject thiz, + jstring fnparam,jstring fnbin,jstring fnmask,jint kind){ + if(!g_digit)return -1; + std::string sparam = getStringUTF(env,fnparam); + std::string sbin = getStringUTF(env,fnbin); + std::string smask = getStringUTF(env,fnmask); + int rst = dhduix_initMunetex(g_digit,(char*)sparam.c_str(),(char*)sbin.c_str(),(char*)smask.c_str(),kind?kind:168); + return rst; + } + + JNIEXPORT jlong JNICALL Java_ai_guiji_duix_DuixNcnn_newsession(JNIEnv *env, jobject thiz){ + if(!g_digit)return -1; + uint64_t sessid = dhduix_newsession(g_digit); + return (jlong)sessid; + } + + JNIEXPORT jint JNICALL Java_ai_guiji_duix_DuixNcnn_pushpcm(JNIEnv *env, jobject thiz, + jlong sessid,jbyteArray arrbuf,jint size,jint kind){ + if(!g_digit)return -1; + jbyte *pcmbuf = (jbyte *) env->GetPrimitiveArrayCritical(arrbuf, 0); + uint64_t sid = sessid; + int rst = dhduix_pushpcm(g_digit,sid,(char*)pcmbuf,size,kind); + env->ReleasePrimitiveArrayCritical(arrbuf,pcmbuf, 0); + return rst; + } + + JNIEXPORT jint JNICALL Java_ai_guiji_duix_DuixNcnn_finsession(JNIEnv *env, jobject thiz,jlong sessid){ + if(!g_digit)return -1; + uint64_t sid = sessid; + return dhduix_finsession(g_digit,sid); + } + + JNIEXPORT jint JNICALL Java_ai_guiji_duix_DuixNcnn_consession(JNIEnv *env, jobject thiz,jlong sessid){ + if(!g_digit)return -1; + uint64_t sid = sessid; + return dhduix_consession(g_digit,sid); + } + + JNIEXPORT jint JNICALL Java_ai_guiji_duix_DuixNcnn_allcnt(JNIEnv *env, jobject thiz,jlong sessid){ + if(!g_digit)return -1; + uint64_t sid = sessid; + return dhduix_allcnt(g_digit,sid); + } + + JNIEXPORT jint JNICALL Java_ai_guiji_duix_DuixNcnn_readycnt(JNIEnv *env, jobject thiz,jlong sessid){ + if(!g_digit)return -1; + uint64_t sid = sessid; + return dhduix_readycnt(g_digit,sid); + } + + JNIEXPORT jint JNICALL Java_ai_guiji_duix_DuixNcnn_fileload(JNIEnv* env, jobject thiz, + jstring picfile, jstring mskfile,jint width,jint height, + jbyteArray arrpic,jbyteArray arrmsk,jint bursize){ + // + std::string s_pic = getStringUTF(env,picfile); + std::string s_msk = getStringUTF(env,mskfile); + jbyte *picbuf = (jbyte *) env->GetPrimitiveArrayCritical(arrpic, 0); + JMat* mat_pic = new JMat(width,height,(uint8_t*)picbuf); + mat_pic->loadjpg(s_pic,1); + env->ReleasePrimitiveArrayCritical( arrpic,picbuf, 0); + delete mat_pic; + + if(s_msk.length()){ + jbyte *mskbuf = (jbyte *) env->GetPrimitiveArrayCritical(arrmsk, 0); + JMat* mat_msk = new JMat(width,height,(uint8_t*)mskbuf); + mat_msk->loadjpg(s_msk,1); + env->ReleasePrimitiveArrayCritical( arrmsk,mskbuf, 0); + delete mat_msk; + } + return 0; + } + + JNIEXPORT jint JNICALL Java_ai_guiji_duix_DuixNcnn_bufrst(JNIEnv* env, jobject thiz, + jlong sessid, jintArray arrbox, jint inx, + jbyteArray arrimg,jint imgsize){ + if(!g_digit)return -1; + uint64_t sid = sessid; + jint *boxData = (jint*) env->GetPrimitiveArrayCritical( arrbox, 0); + jbyte *imgbuf = (jbyte*) env->GetPrimitiveArrayCritical(arrimg, 0); + int bnfinx = inx; + int rst = dhduix_simpinx(g_digit,sid,(uint8_t*)imgbuf, 0,0, + (int*)boxData,NULL,NULL,bnfinx); + env->ReleasePrimitiveArrayCritical( arrimg,imgbuf, 0); + env->ReleasePrimitiveArrayCritical( arrbox, boxData, 0); + return rst; + } + + JNIEXPORT jint JNICALL Java_ai_guiji_duix_DuixNcnn_filerst(JNIEnv* env, jobject thiz, + jlong sessid,jstring picfile, jstring mskfile, + jintArray arrbox, jstring fgfile,jint inx, + jbyteArray arrimg,jbyteArray arrmsk,jint imgsize){ + if(!g_digit)return -1; + uint64_t sid = sessid; + std::string s_pic = getStringUTF(env,picfile); + std::string s_msk = getStringUTF(env,mskfile); + std::string s_fg = getStringUTF(env,fgfile); + jint *boxData = (jint*) env->GetPrimitiveArrayCritical( arrbox, 0); + jbyte *imgbuf = (jbyte*) env->GetPrimitiveArrayCritical(arrimg, 0); + jbyte *mskbuf = (jbyte*) env->GetPrimitiveArrayCritical(arrmsk, 0); + int rst = dhduix_fileinx(g_digit,sid, + (char*)s_pic.c_str(),(int*)boxData, + (char*)s_msk.c_str(),(char*)s_fg.c_str(), + inx,(char*)imgbuf,(char*)mskbuf,imgsize); + env->ReleasePrimitiveArrayCritical( arrimg,imgbuf, 0); + env->ReleasePrimitiveArrayCritical( arrmsk,mskbuf, 0); + env->ReleasePrimitiveArrayCritical( arrbox, boxData, 0); + return rst; + } + + JNIEXPORT jint JNICALL + Java_ai_guiji_duix_DuixNcnn_startgpg(JNIEnv *env, jobject thiz, jstring picfn,jstring gpgfn){ + std::string s_pic = getStringUTF(env,picfn); + std::string s_gpg = getStringUTF(env,gpgfn); + if(!g_gpgmat)g_gpgmat = new JMat(); + int rst = g_gpgmat->loadjpg(s_pic); + if(rst)return rst; + rst = g_gpgmat->savegpg(s_gpg); + return rst; + } + + JNIEXPORT jint JNICALL + Java_ai_guiji_duix_DuixNcnn_processmd5(JNIEnv *env, jobject thiz, jint kind,jstring infn,jstring outfn){ + std::string s_in = getStringUTF(env,infn); + std::string s_out = getStringUTF(env,outfn); + int rst = mainenc(kind,(char*)s_in.c_str(),(char*)s_out.c_str()); + return rst; + } + + JNIEXPORT jint JNICALL + Java_ai_guiji_duix_DuixNcnn_stopgpg(JNIEnv *env, jobject thiz){ + if(g_gpgmat){ + delete g_gpgmat; + g_gpgmat = NULL; + } + return 0; + } +} + diff --git a/duix-sdk/src/main/cpp/android/JniHelper.cpp b/duix-sdk/src/main/cpp/android/JniHelper.cpp new file mode 100644 index 0000000..aa6f3fc --- /dev/null +++ b/duix-sdk/src/main/cpp/android/JniHelper.cpp @@ -0,0 +1,384 @@ +#include +#include "JniHelper.h" +#include "Log.h" + +#define TAG "JniHelper" + +using namespace std; + +JavaVM *JniHelper::sJavaVM = nullptr; + +JNIEnv *JniHelper::getJNIEnv() { + if (sJavaVM == nullptr) { + LOGE(TAG, "sJavaVM is nullptr"); + return nullptr; + } + + JNIEnv *env = nullptr; + bool attached = false; + switch (sJavaVM->GetEnv((void **) &env, JNI_VERSION_1_4)) { + case JNI_OK: + break; + case JNI_EDETACHED: + if (sJavaVM->AttachCurrentThread(&env, nullptr) != 0) { + LOGE(TAG, "Could not attach current thread"); + } + attached = true; + break; + case JNI_EVERSION: + LOGE(TAG, "Invalid java version"); + break; + default: + break; + } + + if (attached) { + sJavaVM->DetachCurrentThread(); + } + + return env; +} + +bool JniHelper::attachCurrentThread() { + if (sJavaVM == nullptr) { + LOGE(TAG, "sJavaVM is nullptr"); + return false; + } + + JNIEnv *env = nullptr; + bool attached = false; + switch (sJavaVM->GetEnv((void **) &env, JNI_VERSION_1_4)) { + case JNI_OK: + break; + case JNI_EDETACHED: + if (sJavaVM->AttachCurrentThread(&env, nullptr) != 0) { + LOGE(TAG, "Could not attach current thread"); + } else { + attached = true; + } + break; + case JNI_EVERSION: + LOGE(TAG, "Invalid java version"); + break; + default: + break; + } + + return attached; +} + +void JniHelper::detachCurrentThread() { + sJavaVM->DetachCurrentThread(); +} + +void JniHelper::throwException(JNIEnv *env, const char *className, const char *msg) { + jclass exception = env->FindClass(className); + env->ThrowNew(exception, msg); +} + +jstring JniHelper::newStringUTF(JNIEnv *env, const char *data) { + if (!data) return nullptr; + jstring str = nullptr; + int size = strlen(data); + jbyteArray array = env->NewByteArray(size); + if (!array) { // OutOfMemoryError exception has already been thrown. + LOGE(TAG, "convertString: OutOfMemoryError is thrown."); + } else { + env->SetByteArrayRegion(array, 0, size, (jbyte *) data); + jclass string_Clazz = env->FindClass("java/lang/String"); + jmethodID string_initMethodID = env->GetMethodID(string_Clazz, "", + "([BLjava/lang/String;)V"); + jstring utf = env->NewStringUTF("UTF-8"); + str = (jstring) env->NewObject(string_Clazz, string_initMethodID, array, utf); + env->DeleteLocalRef(utf); + env->DeleteLocalRef(array); + } + return str; +}; + +jobject JniHelper::createByteBuffer(JNIEnv *env, unsigned char *buffer, int size) { + if (env == nullptr || buffer == nullptr) { + return nullptr; + } + + jobject byteBuffer = env->NewDirectByteBuffer(buffer, size); + //byteBuffer = env->NewGlobalRef(byteBuffer); + + return byteBuffer; +} + +jobject JniHelper::createByteBuffer(JNIEnv *env, int size) { + if (env == nullptr) { + return nullptr; + } + + auto buffer = static_cast(malloc(static_cast(size))); + jobject byteBuffer = env->NewDirectByteBuffer(buffer, size); + free(buffer); + return byteBuffer; +} + +void JniHelper::deleteLocalRef(jobject jobj) { + JNIEnv *env = JniHelper::getJNIEnv(); + if (env == nullptr || jobj == nullptr) { + return; + } + + env->DeleteLocalRef(jobj); +} + +string JniHelper::getStringUTF(JNIEnv *env, jstring obj) { + char *c_str = (char *) env->GetStringUTFChars(obj, nullptr); + string tmpString = std::string(c_str); + env->ReleaseStringUTFChars(obj, c_str); + return tmpString; +} + +char *JniHelper::getCharArrayUTF(JNIEnv *env, jstring obj) { + char *c_str = (char *) env->GetStringUTFChars(obj, nullptr); + env->ReleaseStringUTFChars(obj, c_str); + return c_str; +} + +void JniHelper::callVoidMethod(jobject obj, jmethodID methodId) { + if (sJavaVM == nullptr) { + LOGE(TAG, "sJavaVM is nullptr"); + return; + } + + JNIEnv *env = nullptr; + bool attached = false; + switch (sJavaVM->GetEnv((void **) &env, JNI_VERSION_1_4)) { + case JNI_OK: + break; + case JNI_EDETACHED: + if (sJavaVM->AttachCurrentThread(&env, nullptr) != 0) { + LOGE(TAG, "Could not attach current thread"); + } + attached = true; + break; + case JNI_EVERSION: + LOGE(TAG, "Invalid java version"); + break; + default: + break; + } + + if (env != nullptr) { + env->CallVoidMethod(obj, methodId); + } + + if (attached) { + sJavaVM->DetachCurrentThread(); + } +} + +void JniHelper::callVoidMethod(jobject obj, jmethodID methodId, jint arg1, jint arg2, jint arg3, jint arg4) { + if (sJavaVM == nullptr) { + LOGE(TAG, "sJavaVM is nullptr"); + return; + } + + JNIEnv *env = nullptr; + bool attached = false; + switch (sJavaVM->GetEnv((void **) &env, JNI_VERSION_1_4)) { + case JNI_OK: + break; + case JNI_EDETACHED: + if (sJavaVM->AttachCurrentThread(&env, nullptr) != 0) { + LOGE(TAG, "Could not attach current thread"); + } + attached = true; + break; + case JNI_EVERSION: + LOGE(TAG, "Invalid java version"); + break; + default: + break; + } + + if (env != nullptr) { + env->CallVoidMethod(obj, methodId, arg1, arg2, arg3, arg4); + } + + if (attached) { + sJavaVM->DetachCurrentThread(); + } +} + +void +JniHelper::callVoidMethod(jobject obj, jmethodID methodId, jint arg1, jint arg2, jint arg3, + jstring arg4, jstring arg5, jobject arg6) { + if (sJavaVM == nullptr) { + LOGE(TAG, "sJavaVM is nullptr"); + return; + } + + JNIEnv *env = nullptr; + bool attached = false; + switch (sJavaVM->GetEnv((void **) &env, JNI_VERSION_1_4)) { + case JNI_OK: + break; + case JNI_EDETACHED: + if (sJavaVM->AttachCurrentThread(&env, nullptr) != 0) { + LOGE(TAG, "Could not attach current thread"); + } + attached = true; + break; + case JNI_EVERSION: + LOGE(TAG, "Invalid java version"); + break; + default: + break; + } + + if (env != nullptr) { + env->CallVoidMethod(obj, methodId, arg1, arg2, arg3, arg4, arg5, arg6); + } + + if (attached) { + sJavaVM->DetachCurrentThread(); + } +} + +int JniHelper::callIntMethod(jobject obj, jmethodID methodId, jobject arg1, jint arg2) { + if (sJavaVM == nullptr) { + LOGE(TAG, "sJavaVM is nullptr"); + return -1; + } + + JNIEnv *env = nullptr; + bool attached = false; + switch (sJavaVM->GetEnv((void **) &env, JNI_VERSION_1_4)) { + case JNI_OK: + break; + case JNI_EDETACHED: + if (sJavaVM->AttachCurrentThread(&env, nullptr) != 0) { + LOGE(TAG, "Could not attach current thread"); + } + attached = true; + break; + case JNI_EVERSION: + LOGE(TAG, "Invalid java version"); + break; + default: + break; + } + + int ret = -1; + if (env != nullptr) { + ret = env->CallIntMethod(obj, methodId, arg1, arg2); + } + + if (attached) { + sJavaVM->DetachCurrentThread(); + } + + return ret; +} + + +void JniHelper::callStaticVoidMethod(jclass cls, jmethodID methodId, jint arg1) { + if (sJavaVM == nullptr) { + LOGE(TAG, "sJavaVM is nullptr"); + return; + } + + JNIEnv *env = nullptr; + bool attached = false; + switch (sJavaVM->GetEnv((void **) &env, JNI_VERSION_1_4)) { + case JNI_OK: + break; + case JNI_EDETACHED: + if (sJavaVM->AttachCurrentThread(&env, nullptr) != 0) { + LOGE(TAG, "Could not attach current thread"); + } + attached = true; + break; + case JNI_EVERSION: + LOGE(TAG, "Invalid java version"); + break; + default: + break; + } + + if (env != nullptr) { + env->CallStaticVoidMethod(cls, methodId, arg1); + } + + if (attached) { + sJavaVM->DetachCurrentThread(); + } +} + +jobject JniHelper::callObjectMethod(jobject obj, jmethodID methodId) { + if (sJavaVM == nullptr) { + LOGE(TAG, "sJavaVM is nullptr"); + return nullptr; + } + + JNIEnv *env = nullptr; + bool attached = false; + switch (sJavaVM->GetEnv((void **) &env, JNI_VERSION_1_4)) { + case JNI_OK: + break; + case JNI_EDETACHED: + if (sJavaVM->AttachCurrentThread(&env, nullptr) != 0) { + LOGE(TAG, "Could not attach current thread"); + } + attached = true; + break; + case JNI_EVERSION: + LOGE(TAG, "Invalid java version"); + break; + default: + break; + } + + jobject ret = nullptr; + if (env != nullptr) { + ret = env->CallObjectMethod(obj, methodId); + } + + if (attached) { + sJavaVM->DetachCurrentThread(); + } + + return ret; +} + +jboolean JniHelper::callBooleanMethod(jobject obj, jmethodID methodId) { + if (sJavaVM == nullptr) { + LOGE(TAG, "sJavaVM is nullptr"); + return false; + } + + JNIEnv *env = nullptr; + bool attached = false; + switch (sJavaVM->GetEnv((void **) &env, JNI_VERSION_1_4)) { + case JNI_OK: + break; + case JNI_EDETACHED: + if (sJavaVM->AttachCurrentThread(&env, nullptr) != 0) { + LOGE(TAG, "Could not attach current thread"); + } + attached = true; + break; + case JNI_EVERSION: + LOGE(TAG, "Invalid java version"); + break; + default: + break; + } + + jboolean ret; + if (env != nullptr) { + ret = env->CallBooleanMethod(obj, methodId); + } + + if (attached) { + sJavaVM->DetachCurrentThread(); + } + + return ret; +} diff --git a/duix-sdk/src/main/cpp/android/JniHelper.h b/duix-sdk/src/main/cpp/android/JniHelper.h new file mode 100644 index 0000000..aae30f4 --- /dev/null +++ b/duix-sdk/src/main/cpp/android/JniHelper.h @@ -0,0 +1,50 @@ +#ifndef GPLAYER_JNIHELPER_H +#define GPLAYER_JNIHELPER_H + +#include +#include + +using namespace std; + +class JniHelper { +public: + static JNIEnv *getJNIEnv(); + + static bool attachCurrentThread(); + + static void detachCurrentThread(); + + static void throwException(JNIEnv *env, const char *className, const char *msg); + + static jstring newStringUTF(JNIEnv *env, const char *data); + + static string getStringUTF(JNIEnv *env, jstring obj); + + static char *getCharArrayUTF(JNIEnv *env, jstring obj); + + static jobject createByteBuffer(JNIEnv *env, unsigned char *buffer, int size); + + static jobject createByteBuffer(JNIEnv *env, int size); + + static void deleteLocalRef(jobject jobj); + + static void callVoidMethod(jobject obj, jmethodID methodId); + + static void callVoidMethod(jobject obj, jmethodID methodId, jint arg1, jint arg2, jint arg3, jint arg4); + + static void callVoidMethod(jobject obj, jmethodID methodId, jint arg1, jint arg2, + jint arg3, jstring arg4, jstring arg5, jobject arg6); + + static int callIntMethod(jobject obj, jmethodID methodId, jobject arg1, jint arg2); + + static void callStaticVoidMethod(jclass cls, jmethodID methodId, jint arg1); + + static jobject callObjectMethod(jobject obj, jmethodID methodId); + + static jboolean callBooleanMethod(jobject obj, jmethodID methodId); + +public: + static JavaVM *sJavaVM; +}; + +#endif //GPLAYER_JNIHELPER_H diff --git a/duix-sdk/src/main/cpp/android/Log.cpp b/duix-sdk/src/main/cpp/android/Log.cpp new file mode 100644 index 0000000..2c01e67 --- /dev/null +++ b/duix-sdk/src/main/cpp/android/Log.cpp @@ -0,0 +1,80 @@ +#if defined(_WIN32) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "Log.h" + +#include +#include +#include + +#ifdef __ANDROID__ +#include +android_LogPriority s_android_logprio[LOG_TRACE + 1] = { + ANDROID_LOG_UNKNOWN, + ANDROID_LOG_FATAL, + ANDROID_LOG_ERROR, + ANDROID_LOG_WARN, + ANDROID_LOG_INFO, + ANDROID_LOG_DEBUG, + ANDROID_LOG_VERBOSE +}; + +#endif + +#if defined(_WIN32) +#include +#endif + +void __log_print(int lv, const char *tag, const char *funame, int line, const char *fmt, ...) { + char log_info[2040]; + char *buf = log_info; + int ret, len = sizeof(log_info); + +//Android 不需要时间 +#ifndef __ANDROID__ + /* + if (lv <= LogLevel::LOG_INFO) { // 日志级别不小于INFO则打印时带时间标记 + *buf++ = '['; + _get_curtime_str(buf); + //buf = buf + strlen(buf); + buf += 23; // 时间格式为:XXXX - XX - XX XX : XX : XX.XXX 共占23个字节 + *buf++ = ']'; + *buf++ = ' '; + + len -= buf - log_info; + } + */ + + if (lv <= LogLevel::LOG_WARN) { // 日志级别不小于WARN则打印时带代码行信息 + ret = sprintf(buf, "%s line:%-4d ", funame, line); + buf += ret; + len -= ret; + } +#endif + + va_list arglist; + va_start(arglist, fmt); + + int itemLen = buf - log_info; +#if defined( WIN32 ) + ret = _vsnprintf(buf, len - 1, fmt, arglist); +#else + ret = vsnprintf(buf, len - 1, fmt, arglist); +#endif + if (ret < 0) { + buf[len - 1] = 0; + buf[len - 2] = '\n'; + itemLen += len - 1; + } else + itemLen += ret; + + va_end(arglist); + +#if defined(__ANDROID__) + __android_log_print(s_android_logprio[lv], tag, log_info, ""); +#else + //本地输出 + //printf("Tag=%s %s\n", tag, log_info); +#endif +} diff --git a/duix-sdk/src/main/cpp/android/Log.h b/duix-sdk/src/main/cpp/android/Log.h new file mode 100644 index 0000000..c506c6f --- /dev/null +++ b/duix-sdk/src/main/cpp/android/Log.h @@ -0,0 +1,44 @@ +#ifndef __GPLAYER_LOG_H__ +#define __GPLAYER_LOG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +//调试日志开关,1为开,其它为关 +#define LOG_OPEN 0 + +#define __ANDROID__ 1 +enum LogLevel +{ + LOG_OFF = 0, //!< 不打印日志 + LOG_FATAL = 1, //!< 严重 + LOG_ERROR = 2, //!< 错误 + LOG_WARN = 3, //!< 警告 + LOG_INFO = 4, //!< 信息 + LOG_DEBUG = 5, //!< 调试 + LOG_TRACE = 6, //!< 跟踪 +}; + +void __log_print(int lv, const char* tag, const char* funame, int line, const char *fmt, ...); + +#define LOGI(TAG, ...) __log_print(LogLevel::LOG_INFO, TAG, __FUNCTION__, __LINE__, __VA_ARGS__) +#define LOGW(TAG, ...) __log_print(LogLevel::LOG_WARN, TAG, __FUNCTION__, __LINE__, __VA_ARGS__) +#define LOGE(TAG, ...) __log_print(LogLevel::LOG_ERROR, TAG, __FUNCTION__, __LINE__, __VA_ARGS__) +#define LOGF(TAG, ...) __log_print(LogLevel::LOG_FATAL, TAG, __FUNCTION__, __LINE__, __VA_ARGS__) + +#if defined(__ANDROID__) +#if(LOG_OPEN == 1) +#define LOGD(TAG,...) __log_print(LogLevel::LOG_DEBUG, TAG, __FUNCTION__, __LINE__, __VA_ARGS__) +#else +#define LOGD(TAG, ...) NULL +#endif +#else +#define LOGD(TAG, ...) __log_print(LogLevel::LOG_DEBUG, TAG, __FUNCTION__, __LINE__, __VA_ARGS__) +#endif + +#ifdef __cplusplus +}; +#endif + +#endif // !__GPLAYER_LOG_H__ diff --git a/duix-sdk/src/main/cpp/dhcore/atomicops.h b/duix-sdk/src/main/cpp/dhcore/atomicops.h new file mode 100644 index 0000000..b103bc6 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhcore/atomicops.h @@ -0,0 +1,761 @@ +// ©2013-2016 Cameron Desrochers. +// Distributed under the simplified BSD license (see the license file that +// should have come with this header). +// Uses Jeff Preshing's semaphore implementation (under the terms of its +// separate zlib license, embedded below). + +#pragma once + +// Provides portable (VC++2010+, Intel ICC 13, GCC 4.7+, and anything C++11 compliant) implementation +// of low-level memory barriers, plus a few semi-portable utility macros (for inlining and alignment). +// Also has a basic atomic type (limited to hardware-supported atomics with no memory ordering guarantees). +// Uses the AE_* prefix for macros (historical reasons), and the "moodycamel" namespace for symbols. + +#include +#include +#include +#include +#include +#include + +// Platform detection +#if defined(__INTEL_COMPILER) +#define AE_ICC +#elif defined(_MSC_VER) +#define AE_VCPP +#elif defined(__GNUC__) +#define AE_GCC +#endif + +#if defined(_M_IA64) || defined(__ia64__) +#define AE_ARCH_IA64 +#elif defined(_WIN64) || defined(__amd64__) || defined(_M_X64) || defined(__x86_64__) +#define AE_ARCH_X64 +#elif defined(_M_IX86) || defined(__i386__) +#define AE_ARCH_X86 +#elif defined(_M_PPC) || defined(__powerpc__) +#define AE_ARCH_PPC +#else +#define AE_ARCH_UNKNOWN +#endif + + +// AE_UNUSED +#define AE_UNUSED(x) ((void)x) + +// AE_NO_TSAN/AE_TSAN_ANNOTATE_* +#if defined(__has_feature) +#if __has_feature(thread_sanitizer) +#if __cplusplus >= 201703L // inline variables require C++17 +namespace moodycamel { inline int ae_tsan_global; } +#define AE_TSAN_ANNOTATE_RELEASE() AnnotateHappensBefore(__FILE__, __LINE__, (void *)(&::moodycamel::ae_tsan_global)) +#define AE_TSAN_ANNOTATE_ACQUIRE() AnnotateHappensAfter(__FILE__, __LINE__, (void *)(&::moodycamel::ae_tsan_global)) +extern "C" void AnnotateHappensBefore(const char*, int, void*); +extern "C" void AnnotateHappensAfter(const char*, int, void*); +#else // when we can't work with tsan, attempt to disable its warnings +#define AE_NO_TSAN __attribute__((no_sanitize("thread"))) +#endif +#endif +#endif +#ifndef AE_NO_TSAN +#define AE_NO_TSAN +#endif +#ifndef AE_TSAN_ANNOTATE_RELEASE +#define AE_TSAN_ANNOTATE_RELEASE() +#define AE_TSAN_ANNOTATE_ACQUIRE() +#endif + + +// AE_FORCEINLINE +#if defined(AE_VCPP) || defined(AE_ICC) +#define AE_FORCEINLINE __forceinline +#elif defined(AE_GCC) +//#define AE_FORCEINLINE __attribute__((always_inline)) +#define AE_FORCEINLINE inline +#else +#define AE_FORCEINLINE inline +#endif + + +// AE_ALIGN +#if defined(AE_VCPP) || defined(AE_ICC) +#define AE_ALIGN(x) __declspec(align(x)) +#elif defined(AE_GCC) +#define AE_ALIGN(x) __attribute__((aligned(x))) +#else +// Assume GCC compliant syntax... +#define AE_ALIGN(x) __attribute__((aligned(x))) +#endif + + +// Portable atomic fences implemented below: + +namespace moodycamel { + +enum memory_order { + memory_order_relaxed, + memory_order_acquire, + memory_order_release, + memory_order_acq_rel, + memory_order_seq_cst, + + // memory_order_sync: Forces a full sync: + // #LoadLoad, #LoadStore, #StoreStore, and most significantly, #StoreLoad + memory_order_sync = memory_order_seq_cst +}; + +} // end namespace moodycamel + +#if (defined(AE_VCPP) && (_MSC_VER < 1700 || defined(__cplusplus_cli))) || (defined(AE_ICC) && __INTEL_COMPILER < 1600) +// VS2010 and ICC13 don't support std::atomic_*_fence, implement our own fences + +#include + +#if defined(AE_ARCH_X64) || defined(AE_ARCH_X86) +#define AeFullSync _mm_mfence +#define AeLiteSync _mm_mfence +#elif defined(AE_ARCH_IA64) +#define AeFullSync __mf +#define AeLiteSync __mf +#elif defined(AE_ARCH_PPC) +#include +#define AeFullSync __sync +#define AeLiteSync __lwsync +#endif + + +#ifdef AE_VCPP +#pragma warning(push) +#pragma warning(disable: 4365) // Disable erroneous 'conversion from long to unsigned int, signed/unsigned mismatch' error when using `assert` +#ifdef __cplusplus_cli +#pragma managed(push, off) +#endif +#endif + +namespace moodycamel { + +AE_FORCEINLINE void compiler_fence(memory_order order) AE_NO_TSAN +{ + switch (order) { + case memory_order_relaxed: break; + case memory_order_acquire: _ReadBarrier(); break; + case memory_order_release: _WriteBarrier(); break; + case memory_order_acq_rel: _ReadWriteBarrier(); break; + case memory_order_seq_cst: _ReadWriteBarrier(); break; + default: assert(false); + } +} + +// x86/x64 have a strong memory model -- all loads and stores have +// acquire and release semantics automatically (so only need compiler +// barriers for those). +#if defined(AE_ARCH_X86) || defined(AE_ARCH_X64) +AE_FORCEINLINE void fence(memory_order order) AE_NO_TSAN +{ + switch (order) { + case memory_order_relaxed: break; + case memory_order_acquire: _ReadBarrier(); break; + case memory_order_release: _WriteBarrier(); break; + case memory_order_acq_rel: _ReadWriteBarrier(); break; + case memory_order_seq_cst: + _ReadWriteBarrier(); + AeFullSync(); + _ReadWriteBarrier(); + break; + default: assert(false); + } +} +#else +AE_FORCEINLINE void fence(memory_order order) AE_NO_TSAN +{ + // Non-specialized arch, use heavier memory barriers everywhere just in case :-( + switch (order) { + case memory_order_relaxed: + break; + case memory_order_acquire: + _ReadBarrier(); + AeLiteSync(); + _ReadBarrier(); + break; + case memory_order_release: + _WriteBarrier(); + AeLiteSync(); + _WriteBarrier(); + break; + case memory_order_acq_rel: + _ReadWriteBarrier(); + AeLiteSync(); + _ReadWriteBarrier(); + break; + case memory_order_seq_cst: + _ReadWriteBarrier(); + AeFullSync(); + _ReadWriteBarrier(); + break; + default: assert(false); + } +} +#endif +} // end namespace moodycamel +#else +// Use standard library of atomics +#include + +namespace moodycamel { + +AE_FORCEINLINE void compiler_fence(memory_order order) AE_NO_TSAN +{ + switch (order) { + case memory_order_relaxed: break; + case memory_order_acquire: std::atomic_signal_fence(std::memory_order_acquire); break; + case memory_order_release: std::atomic_signal_fence(std::memory_order_release); break; + case memory_order_acq_rel: std::atomic_signal_fence(std::memory_order_acq_rel); break; + case memory_order_seq_cst: std::atomic_signal_fence(std::memory_order_seq_cst); break; + default: assert(false); + } +} + +AE_FORCEINLINE void fence(memory_order order) AE_NO_TSAN +{ + switch (order) { + case memory_order_relaxed: break; + case memory_order_acquire: AE_TSAN_ANNOTATE_ACQUIRE(); std::atomic_thread_fence(std::memory_order_acquire); break; + case memory_order_release: AE_TSAN_ANNOTATE_RELEASE(); std::atomic_thread_fence(std::memory_order_release); break; + case memory_order_acq_rel: AE_TSAN_ANNOTATE_ACQUIRE(); AE_TSAN_ANNOTATE_RELEASE(); std::atomic_thread_fence(std::memory_order_acq_rel); break; + case memory_order_seq_cst: AE_TSAN_ANNOTATE_ACQUIRE(); AE_TSAN_ANNOTATE_RELEASE(); std::atomic_thread_fence(std::memory_order_seq_cst); break; + default: assert(false); + } +} + +} // end namespace moodycamel + +#endif + + +#if !defined(AE_VCPP) || (_MSC_VER >= 1700 && !defined(__cplusplus_cli)) +#define AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC +#endif + +#ifdef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC +#include +#endif +#include + +// WARNING: *NOT* A REPLACEMENT FOR std::atomic. READ CAREFULLY: +// Provides basic support for atomic variables -- no memory ordering guarantees are provided. +// The guarantee of atomicity is only made for types that already have atomic load and store guarantees +// at the hardware level -- on most platforms this generally means aligned pointers and integers (only). +namespace moodycamel { +template +class weak_atomic +{ +public: + AE_NO_TSAN weak_atomic() : value() { } +#ifdef AE_VCPP +#pragma warning(push) +#pragma warning(disable: 4100) // Get rid of (erroneous) 'unreferenced formal parameter' warning +#endif + template AE_NO_TSAN weak_atomic(U&& x) : value(std::forward(x)) { } +#ifdef __cplusplus_cli + // Work around bug with universal reference/nullptr combination that only appears when /clr is on + AE_NO_TSAN weak_atomic(nullptr_t) : value(nullptr) { } +#endif + AE_NO_TSAN weak_atomic(weak_atomic const& other) : value(other.load()) { } + AE_NO_TSAN weak_atomic(weak_atomic&& other) : value(std::move(other.load())) { } +#ifdef AE_VCPP +#pragma warning(pop) +#endif + + AE_FORCEINLINE operator T() const AE_NO_TSAN { return load(); } + + +#ifndef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC + template AE_FORCEINLINE weak_atomic const& operator=(U&& x) AE_NO_TSAN { value = std::forward(x); return *this; } + AE_FORCEINLINE weak_atomic const& operator=(weak_atomic const& other) AE_NO_TSAN { value = other.value; return *this; } + + AE_FORCEINLINE T load() const AE_NO_TSAN { return value; } + + AE_FORCEINLINE T fetch_add_acquire(T increment) AE_NO_TSAN + { +#if defined(AE_ARCH_X64) || defined(AE_ARCH_X86) + if (sizeof(T) == 4) return _InterlockedExchangeAdd((long volatile*)&value, (long)increment); +#if defined(_M_AMD64) + else if (sizeof(T) == 8) return _InterlockedExchangeAdd64((long long volatile*)&value, (long long)increment); +#endif +#else +#error Unsupported platform +#endif + assert(false && "T must be either a 32 or 64 bit type"); + return value; + } + + AE_FORCEINLINE T fetch_add_release(T increment) AE_NO_TSAN + { +#if defined(AE_ARCH_X64) || defined(AE_ARCH_X86) + if (sizeof(T) == 4) return _InterlockedExchangeAdd((long volatile*)&value, (long)increment); +#if defined(_M_AMD64) + else if (sizeof(T) == 8) return _InterlockedExchangeAdd64((long long volatile*)&value, (long long)increment); +#endif +#else +#error Unsupported platform +#endif + assert(false && "T must be either a 32 or 64 bit type"); + return value; + } +#else + template + AE_FORCEINLINE weak_atomic const& operator=(U&& x) AE_NO_TSAN + { + value.store(std::forward(x), std::memory_order_relaxed); + return *this; + } + + AE_FORCEINLINE weak_atomic const& operator=(weak_atomic const& other) AE_NO_TSAN + { + value.store(other.value.load(std::memory_order_relaxed), std::memory_order_relaxed); + return *this; + } + + AE_FORCEINLINE T load() const AE_NO_TSAN { return value.load(std::memory_order_relaxed); } + + AE_FORCEINLINE T fetch_add_acquire(T increment) AE_NO_TSAN + { + return value.fetch_add(increment, std::memory_order_acquire); + } + + AE_FORCEINLINE T fetch_add_release(T increment) AE_NO_TSAN + { + return value.fetch_add(increment, std::memory_order_release); + } +#endif + + +private: +#ifndef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC + // No std::atomic support, but still need to circumvent compiler optimizations. + // `volatile` will make memory access slow, but is guaranteed to be reliable. + volatile T value; +#else + std::atomic value; +#endif +}; + +} // end namespace moodycamel + + + +// Portable single-producer, single-consumer semaphore below: + +#if defined(_WIN32) +// Avoid including windows.h in a header; we only need a handful of +// items, so we'll redeclare them here (this is relatively safe since +// the API generally has to remain stable between Windows versions). +// I know this is an ugly hack but it still beats polluting the global +// namespace with thousands of generic names or adding a .cpp for nothing. +extern "C" { + struct _SECURITY_ATTRIBUTES; + __declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES* lpSemaphoreAttributes, long lInitialCount, long lMaximumCount, const wchar_t* lpName); + __declspec(dllimport) int __stdcall CloseHandle(void* hObject); + __declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void* hHandle, unsigned long dwMilliseconds); + __declspec(dllimport) int __stdcall ReleaseSemaphore(void* hSemaphore, long lReleaseCount, long* lpPreviousCount); +} +#elif defined(__MACH__) +#include +#elif defined(__unix__) +#include +#elif defined(FREERTOS) +#include +#include +#include +#endif + +namespace moodycamel +{ + // Code in the spsc_sema namespace below is an adaptation of Jeff Preshing's + // portable + lightweight semaphore implementations, originally from + // https://github.com/preshing/cpp11-on-multicore/blob/master/common/sema.h + // LICENSE: + // Copyright (c) 2015 Jeff Preshing + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgement in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + namespace spsc_sema + { +#if defined(_WIN32) + class Semaphore + { + private: + void* m_hSema; + + Semaphore(const Semaphore& other); + Semaphore& operator=(const Semaphore& other); + + public: + AE_NO_TSAN Semaphore(int initialCount = 0) : m_hSema() + { + assert(initialCount >= 0); + const long maxLong = 0x7fffffff; + m_hSema = CreateSemaphoreW(nullptr, initialCount, maxLong, nullptr); + assert(m_hSema); + } + + AE_NO_TSAN ~Semaphore() + { + CloseHandle(m_hSema); + } + + bool wait() AE_NO_TSAN + { + const unsigned long infinite = 0xffffffff; + return WaitForSingleObject(m_hSema, infinite) == 0; + } + + bool try_wait() AE_NO_TSAN + { + return WaitForSingleObject(m_hSema, 0) == 0; + } + + bool timed_wait(std::uint64_t usecs) AE_NO_TSAN + { + return WaitForSingleObject(m_hSema, (unsigned long)(usecs / 1000)) == 0; + } + + void signal(int count = 1) AE_NO_TSAN + { + while (!ReleaseSemaphore(m_hSema, count, nullptr)); + } + }; +#elif defined(__MACH__) + //--------------------------------------------------------- + // Semaphore (Apple iOS and OSX) + // Can't use POSIX semaphores due to http://lists.apple.com/archives/darwin-kernel/2009/Apr/msg00010.html + //--------------------------------------------------------- + class Semaphore + { + private: + semaphore_t m_sema; + + Semaphore(const Semaphore& other); + Semaphore& operator=(const Semaphore& other); + + public: + AE_NO_TSAN Semaphore(int initialCount = 0) : m_sema() + { + assert(initialCount >= 0); + kern_return_t rc = semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, initialCount); + assert(rc == KERN_SUCCESS); + AE_UNUSED(rc); + } + + AE_NO_TSAN ~Semaphore() + { + semaphore_destroy(mach_task_self(), m_sema); + } + + bool wait() AE_NO_TSAN + { + return semaphore_wait(m_sema) == KERN_SUCCESS; + } + + bool try_wait() AE_NO_TSAN + { + return timed_wait(0); + } + + bool timed_wait(std::uint64_t timeout_usecs) AE_NO_TSAN + { + mach_timespec_t ts; + ts.tv_sec = static_cast(timeout_usecs / 1000000); + ts.tv_nsec = static_cast((timeout_usecs % 1000000) * 1000); + + // added in OSX 10.10: https://developer.apple.com/library/prerelease/mac/documentation/General/Reference/APIDiffsMacOSX10_10SeedDiff/modules/Darwin.html + kern_return_t rc = semaphore_timedwait(m_sema, ts); + return rc == KERN_SUCCESS; + } + + void signal() AE_NO_TSAN + { + while (semaphore_signal(m_sema) != KERN_SUCCESS); + } + + void signal(int count) AE_NO_TSAN + { + while (count-- > 0) + { + while (semaphore_signal(m_sema) != KERN_SUCCESS); + } + } + }; +#elif defined(__unix__) + //--------------------------------------------------------- + // Semaphore (POSIX, Linux) + //--------------------------------------------------------- + class Semaphore + { + private: + sem_t m_sema; + + Semaphore(const Semaphore& other); + Semaphore& operator=(const Semaphore& other); + + public: + AE_NO_TSAN Semaphore(int initialCount = 0) : m_sema() + { + assert(initialCount >= 0); + int rc = sem_init(&m_sema, 0, static_cast(initialCount)); + assert(rc == 0); + AE_UNUSED(rc); + } + + AE_NO_TSAN ~Semaphore() + { + sem_destroy(&m_sema); + } + + bool wait() AE_NO_TSAN + { + // http://stackoverflow.com/questions/2013181/gdb-causes-sem-wait-to-fail-with-eintr-error + int rc; + do + { + rc = sem_wait(&m_sema); + } + while (rc == -1 && errno == EINTR); + return rc == 0; + } + + bool try_wait() AE_NO_TSAN + { + int rc; + do { + rc = sem_trywait(&m_sema); + } while (rc == -1 && errno == EINTR); + return rc == 0; + } + + bool timed_wait(std::uint64_t usecs) AE_NO_TSAN + { + struct timespec ts; + const int usecs_in_1_sec = 1000000; + const int nsecs_in_1_sec = 1000000000; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += static_cast(usecs / usecs_in_1_sec); + ts.tv_nsec += static_cast(usecs % usecs_in_1_sec) * 1000; + // sem_timedwait bombs if you have more than 1e9 in tv_nsec + // so we have to clean things up before passing it in + if (ts.tv_nsec >= nsecs_in_1_sec) { + ts.tv_nsec -= nsecs_in_1_sec; + ++ts.tv_sec; + } + + int rc; + do { + rc = sem_timedwait(&m_sema, &ts); + } while (rc == -1 && errno == EINTR); + return rc == 0; + } + + void signal() AE_NO_TSAN + { + while (sem_post(&m_sema) == -1); + } + + void signal(int count) AE_NO_TSAN + { + while (count-- > 0) + { + while (sem_post(&m_sema) == -1); + } + } + }; +#elif defined(FREERTOS) + //--------------------------------------------------------- + // Semaphore (FreeRTOS) + //--------------------------------------------------------- + class Semaphore + { + private: + SemaphoreHandle_t m_sema; + + Semaphore(const Semaphore& other); + Semaphore& operator=(const Semaphore& other); + + public: + AE_NO_TSAN Semaphore(int initialCount = 0) : m_sema() + { + assert(initialCount >= 0); + m_sema = xSemaphoreCreateCounting(static_cast(~0ull), static_cast(initialCount)); + assert(m_sema); + } + + AE_NO_TSAN ~Semaphore() + { + vSemaphoreDelete(m_sema); + } + + bool wait() AE_NO_TSAN + { + return xSemaphoreTake(m_sema, portMAX_DELAY) == pdTRUE; + } + + bool try_wait() AE_NO_TSAN + { + // Note: In an ISR context, if this causes a task to unblock, + // the caller won't know about it + if (xPortIsInsideInterrupt()) + return xSemaphoreTakeFromISR(m_sema, NULL) == pdTRUE; + return xSemaphoreTake(m_sema, 0) == pdTRUE; + } + + bool timed_wait(std::uint64_t usecs) AE_NO_TSAN + { + std::uint64_t msecs = usecs / 1000; + TickType_t ticks = static_cast(msecs / portTICK_PERIOD_MS); + if (ticks == 0) + return try_wait(); + return xSemaphoreTake(m_sema, ticks) == pdTRUE; + } + + void signal() AE_NO_TSAN + { + // Note: In an ISR context, if this causes a task to unblock, + // the caller won't know about it + BaseType_t rc; + if (xPortIsInsideInterrupt()) + rc = xSemaphoreGiveFromISR(m_sema, NULL); + else + rc = xSemaphoreGive(m_sema); + assert(rc == pdTRUE); + AE_UNUSED(rc); + } + + void signal(int count) AE_NO_TSAN + { + while (count-- > 0) + signal(); + } + }; +#else +#error Unsupported platform! (No semaphore wrapper available) +#endif + + //--------------------------------------------------------- + // LightweightSemaphore + //--------------------------------------------------------- + class LightweightSemaphore + { + public: + typedef std::make_signed::type ssize_t; + + private: + weak_atomic m_count; + Semaphore m_sema; + + bool waitWithPartialSpinning(std::int64_t timeout_usecs = -1) AE_NO_TSAN + { + ssize_t oldCount; + // Is there a better way to set the initial spin count? + // If we lower it to 1000, testBenaphore becomes 15x slower on my Core i7-5930K Windows PC, + // as threads start hitting the kernel semaphore. + int spin = 1024; + while (--spin >= 0) + { + if (m_count.load() > 0) + { + m_count.fetch_add_acquire(-1); + return true; + } + compiler_fence(memory_order_acquire); // Prevent the compiler from collapsing the loop. + } + oldCount = m_count.fetch_add_acquire(-1); + if (oldCount > 0) + return true; + if (timeout_usecs < 0) + { + if (m_sema.wait()) + return true; + } + if (timeout_usecs > 0 && m_sema.timed_wait(static_cast(timeout_usecs))) + return true; + // At this point, we've timed out waiting for the semaphore, but the + // count is still decremented indicating we may still be waiting on + // it. So we have to re-adjust the count, but only if the semaphore + // wasn't signaled enough times for us too since then. If it was, we + // need to release the semaphore too. + while (true) + { + oldCount = m_count.fetch_add_release(1); + if (oldCount < 0) + return false; // successfully restored things to the way they were + // Oh, the producer thread just signaled the semaphore after all. Try again: + oldCount = m_count.fetch_add_acquire(-1); + if (oldCount > 0 && m_sema.try_wait()) + return true; + } + } + + public: + AE_NO_TSAN LightweightSemaphore(ssize_t initialCount = 0) : m_count(initialCount), m_sema() + { + assert(initialCount >= 0); + } + + bool tryWait() AE_NO_TSAN + { + if (m_count.load() > 0) + { + m_count.fetch_add_acquire(-1); + return true; + } + return false; + } + + bool wait() AE_NO_TSAN + { + return tryWait() || waitWithPartialSpinning(); + } + + bool wait(std::int64_t timeout_usecs) AE_NO_TSAN + { + return tryWait() || waitWithPartialSpinning(timeout_usecs); + } + + void signal(ssize_t count = 1) AE_NO_TSAN + { + assert(count >= 0); + ssize_t oldCount = m_count.fetch_add_release(count); + assert(oldCount >= -1); + if (oldCount < 0) + { + m_sema.signal(1); + } + } + + std::size_t availableApprox() const AE_NO_TSAN + { + ssize_t count = m_count.load(); + return count > 0 ? static_cast(count) : 0; + } + }; + } // end namespace spsc_sema +} // end namespace moodycamel + +#if defined(AE_VCPP) && (_MSC_VER < 1700 || defined(__cplusplus_cli)) +#pragma warning(pop) +#ifdef __cplusplus_cli +#pragma managed(pop) +#endif +#endif diff --git a/duix-sdk/src/main/cpp/dhcore/blockingconcurrentqueue.h b/duix-sdk/src/main/cpp/dhcore/blockingconcurrentqueue.h new file mode 100644 index 0000000..205a4db --- /dev/null +++ b/duix-sdk/src/main/cpp/dhcore/blockingconcurrentqueue.h @@ -0,0 +1,582 @@ +// Provides an efficient blocking version of moodycamel::ConcurrentQueue. +// ©2015-2020 Cameron Desrochers. Distributed under the terms of the simplified +// BSD license, available at the top of concurrentqueue.h. +// Also dual-licensed under the Boost Software License (see LICENSE.md) +// Uses Jeff Preshing's semaphore implementation (under the terms of its +// separate zlib license, see lightweightsemaphore.h). + +#pragma once + +#include "concurrentqueue.h" +#include "lightweightsemaphore.h" + +#include +#include +#include +#include +#include + +namespace moodycamel +{ +// This is a blocking version of the queue. It has an almost identical interface to +// the normal non-blocking version, with the addition of various wait_dequeue() methods +// and the removal of producer-specific dequeue methods. +template +class BlockingConcurrentQueue +{ +private: + typedef ::moodycamel::ConcurrentQueue ConcurrentQueue; + typedef ::moodycamel::LightweightSemaphore LightweightSemaphore; + +public: + typedef typename ConcurrentQueue::producer_token_t producer_token_t; + typedef typename ConcurrentQueue::consumer_token_t consumer_token_t; + + typedef typename ConcurrentQueue::index_t index_t; + typedef typename ConcurrentQueue::size_t size_t; + typedef typename std::make_signed::type ssize_t; + + static const size_t BLOCK_SIZE = ConcurrentQueue::BLOCK_SIZE; + static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = ConcurrentQueue::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD; + static const size_t EXPLICIT_INITIAL_INDEX_SIZE = ConcurrentQueue::EXPLICIT_INITIAL_INDEX_SIZE; + static const size_t IMPLICIT_INITIAL_INDEX_SIZE = ConcurrentQueue::IMPLICIT_INITIAL_INDEX_SIZE; + static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = ConcurrentQueue::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE; + static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = ConcurrentQueue::EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE; + static const size_t MAX_SUBQUEUE_SIZE = ConcurrentQueue::MAX_SUBQUEUE_SIZE; + +public: + // Creates a queue with at least `capacity` element slots; note that the + // actual number of elements that can be inserted without additional memory + // allocation depends on the number of producers and the block size (e.g. if + // the block size is equal to `capacity`, only a single block will be allocated + // up-front, which means only a single producer will be able to enqueue elements + // without an extra allocation -- blocks aren't shared between producers). + // This method is not thread safe -- it is up to the user to ensure that the + // queue is fully constructed before it starts being used by other threads (this + // includes making the memory effects of construction visible, possibly with a + // memory barrier). + explicit BlockingConcurrentQueue(size_t capacity = 6 * BLOCK_SIZE) + : inner(capacity), sema(create(0, (int)Traits::MAX_SEMA_SPINS), &BlockingConcurrentQueue::template destroy) + { + assert(reinterpret_cast((BlockingConcurrentQueue*)1) == &((BlockingConcurrentQueue*)1)->inner && "BlockingConcurrentQueue must have ConcurrentQueue as its first member"); + if (!sema) { + MOODYCAMEL_THROW(std::bad_alloc()); + } + } + + BlockingConcurrentQueue(size_t minCapacity, size_t maxExplicitProducers, size_t maxImplicitProducers) + : inner(minCapacity, maxExplicitProducers, maxImplicitProducers), sema(create(0, (int)Traits::MAX_SEMA_SPINS), &BlockingConcurrentQueue::template destroy) + { + assert(reinterpret_cast((BlockingConcurrentQueue*)1) == &((BlockingConcurrentQueue*)1)->inner && "BlockingConcurrentQueue must have ConcurrentQueue as its first member"); + if (!sema) { + MOODYCAMEL_THROW(std::bad_alloc()); + } + } + + // Disable copying and copy assignment + BlockingConcurrentQueue(BlockingConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION; + BlockingConcurrentQueue& operator=(BlockingConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION; + + // Moving is supported, but note that it is *not* a thread-safe operation. + // Nobody can use the queue while it's being moved, and the memory effects + // of that move must be propagated to other threads before they can use it. + // Note: When a queue is moved, its tokens are still valid but can only be + // used with the destination queue (i.e. semantically they are moved along + // with the queue itself). + BlockingConcurrentQueue(BlockingConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT + : inner(std::move(other.inner)), sema(std::move(other.sema)) + { } + + inline BlockingConcurrentQueue& operator=(BlockingConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT + { + return swap_internal(other); + } + + // Swaps this queue's state with the other's. Not thread-safe. + // Swapping two queues does not invalidate their tokens, however + // the tokens that were created for one queue must be used with + // only the swapped queue (i.e. the tokens are tied to the + // queue's movable state, not the object itself). + inline void swap(BlockingConcurrentQueue& other) MOODYCAMEL_NOEXCEPT + { + swap_internal(other); + } + +private: + BlockingConcurrentQueue& swap_internal(BlockingConcurrentQueue& other) + { + if (this == &other) { + return *this; + } + + inner.swap(other.inner); + sema.swap(other.sema); + return *this; + } + +public: + // Enqueues a single item (by copying it). + // Allocates memory if required. Only fails if memory allocation fails (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0, + // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(T const& item) + { + if ((details::likely)(inner.enqueue(item))) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues a single item (by moving it, if possible). + // Allocates memory if required. Only fails if memory allocation fails (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0, + // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(T&& item) + { + if ((details::likely)(inner.enqueue(std::move(item)))) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues a single item (by copying it) using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails (or + // Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(producer_token_t const& token, T const& item) + { + if ((details::likely)(inner.enqueue(token, item))) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues a single item (by moving it, if possible) using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails (or + // Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(producer_token_t const& token, T&& item) + { + if ((details::likely)(inner.enqueue(token, std::move(item)))) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues several items. + // Allocates memory if required. Only fails if memory allocation fails (or + // implicit production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE + // is 0, or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Note: Use std::make_move_iterator if the elements should be moved instead of copied. + // Thread-safe. + template + inline bool enqueue_bulk(It itemFirst, size_t count) + { + if ((details::likely)(inner.enqueue_bulk(std::forward(itemFirst), count))) { + sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count); + return true; + } + return false; + } + + // Enqueues several items using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails + // (or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + inline bool enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) + { + if ((details::likely)(inner.enqueue_bulk(token, std::forward(itemFirst), count))) { + sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count); + return true; + } + return false; + } + + // Enqueues a single item (by copying it). + // Does not allocate memory. Fails if not enough room to enqueue (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE + // is 0). + // Thread-safe. + inline bool try_enqueue(T const& item) + { + if (inner.try_enqueue(item)) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues a single item (by moving it, if possible). + // Does not allocate memory (except for one-time implicit producer). + // Fails if not enough room to enqueue (or implicit production is + // disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0). + // Thread-safe. + inline bool try_enqueue(T&& item) + { + if (inner.try_enqueue(std::move(item))) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues a single item (by copying it) using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Thread-safe. + inline bool try_enqueue(producer_token_t const& token, T const& item) + { + if (inner.try_enqueue(token, item)) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues a single item (by moving it, if possible) using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Thread-safe. + inline bool try_enqueue(producer_token_t const& token, T&& item) + { + if (inner.try_enqueue(token, std::move(item))) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues several items. + // Does not allocate memory (except for one-time implicit producer). + // Fails if not enough room to enqueue (or implicit production is + // disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0). + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + inline bool try_enqueue_bulk(It itemFirst, size_t count) + { + if (inner.try_enqueue_bulk(std::forward(itemFirst), count)) { + sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count); + return true; + } + return false; + } + + // Enqueues several items using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + inline bool try_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) + { + if (inner.try_enqueue_bulk(token, std::forward(itemFirst), count)) { + sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count); + return true; + } + return false; + } + + + // Attempts to dequeue from the queue. + // Returns false if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + inline bool try_dequeue(U& item) + { + if (sema->tryWait()) { + while (!inner.try_dequeue(item)) { + continue; + } + return true; + } + return false; + } + + // Attempts to dequeue from the queue using an explicit consumer token. + // Returns false if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + inline bool try_dequeue(consumer_token_t& token, U& item) + { + if (sema->tryWait()) { + while (!inner.try_dequeue(token, item)) { + continue; + } + return true; + } + return false; + } + + // Attempts to dequeue several elements from the queue. + // Returns the number of items actually dequeued. + // Returns 0 if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + inline size_t try_dequeue_bulk(It itemFirst, size_t max) + { + size_t count = 0; + max = (size_t)sema->tryWaitMany((LightweightSemaphore::ssize_t)(ssize_t)max); + while (count != max) { + count += inner.template try_dequeue_bulk(itemFirst, max - count); + } + return count; + } + + // Attempts to dequeue several elements from the queue using an explicit consumer token. + // Returns the number of items actually dequeued. + // Returns 0 if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + inline size_t try_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max) + { + size_t count = 0; + max = (size_t)sema->tryWaitMany((LightweightSemaphore::ssize_t)(ssize_t)max); + while (count != max) { + count += inner.template try_dequeue_bulk(token, itemFirst, max - count); + } + return count; + } + + + + // Blocks the current thread until there's something to dequeue, then + // dequeues it. + // Never allocates. Thread-safe. + template + inline void wait_dequeue(U& item) + { + while (!sema->wait()) { + continue; + } + while (!inner.try_dequeue(item)) { + continue; + } + } + + // Blocks the current thread until either there's something to dequeue + // or the timeout (specified in microseconds) expires. Returns false + // without setting `item` if the timeout expires, otherwise assigns + // to `item` and returns true. + // Using a negative timeout indicates an indefinite timeout, + // and is thus functionally equivalent to calling wait_dequeue. + // Never allocates. Thread-safe. + template + inline bool wait_dequeue_timed(U& item, std::int64_t timeout_usecs) + { + if (!sema->wait(timeout_usecs)) { + return false; + } + while (!inner.try_dequeue(item)) { + continue; + } + return true; + } + + // Blocks the current thread until either there's something to dequeue + // or the timeout expires. Returns false without setting `item` if the + // timeout expires, otherwise assigns to `item` and returns true. + // Never allocates. Thread-safe. + template + inline bool wait_dequeue_timed(U& item, std::chrono::duration const& timeout) + { + return wait_dequeue_timed(item, std::chrono::duration_cast(timeout).count()); + } + + // Blocks the current thread until there's something to dequeue, then + // dequeues it using an explicit consumer token. + // Never allocates. Thread-safe. + template + inline void wait_dequeue(consumer_token_t& token, U& item) + { + while (!sema->wait()) { + continue; + } + while (!inner.try_dequeue(token, item)) { + continue; + } + } + + // Blocks the current thread until either there's something to dequeue + // or the timeout (specified in microseconds) expires. Returns false + // without setting `item` if the timeout expires, otherwise assigns + // to `item` and returns true. + // Using a negative timeout indicates an indefinite timeout, + // and is thus functionally equivalent to calling wait_dequeue. + // Never allocates. Thread-safe. + template + inline bool wait_dequeue_timed(consumer_token_t& token, U& item, std::int64_t timeout_usecs) + { + if (!sema->wait(timeout_usecs)) { + return false; + } + while (!inner.try_dequeue(token, item)) { + continue; + } + return true; + } + + // Blocks the current thread until either there's something to dequeue + // or the timeout expires. Returns false without setting `item` if the + // timeout expires, otherwise assigns to `item` and returns true. + // Never allocates. Thread-safe. + template + inline bool wait_dequeue_timed(consumer_token_t& token, U& item, std::chrono::duration const& timeout) + { + return wait_dequeue_timed(token, item, std::chrono::duration_cast(timeout).count()); + } + + // Attempts to dequeue several elements from the queue. + // Returns the number of items actually dequeued, which will + // always be at least one (this method blocks until the queue + // is non-empty) and at most max. + // Never allocates. Thread-safe. + template + inline size_t wait_dequeue_bulk(It itemFirst, size_t max) + { + size_t count = 0; + max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max); + while (count != max) { + count += inner.template try_dequeue_bulk(itemFirst, max - count); + } + return count; + } + + // Attempts to dequeue several elements from the queue. + // Returns the number of items actually dequeued, which can + // be 0 if the timeout expires while waiting for elements, + // and at most max. + // Using a negative timeout indicates an indefinite timeout, + // and is thus functionally equivalent to calling wait_dequeue_bulk. + // Never allocates. Thread-safe. + template + inline size_t wait_dequeue_bulk_timed(It itemFirst, size_t max, std::int64_t timeout_usecs) + { + size_t count = 0; + max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max, timeout_usecs); + while (count != max) { + count += inner.template try_dequeue_bulk(itemFirst, max - count); + } + return count; + } + + // Attempts to dequeue several elements from the queue. + // Returns the number of items actually dequeued, which can + // be 0 if the timeout expires while waiting for elements, + // and at most max. + // Never allocates. Thread-safe. + template + inline size_t wait_dequeue_bulk_timed(It itemFirst, size_t max, std::chrono::duration const& timeout) + { + return wait_dequeue_bulk_timed(itemFirst, max, std::chrono::duration_cast(timeout).count()); + } + + // Attempts to dequeue several elements from the queue using an explicit consumer token. + // Returns the number of items actually dequeued, which will + // always be at least one (this method blocks until the queue + // is non-empty) and at most max. + // Never allocates. Thread-safe. + template + inline size_t wait_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max) + { + size_t count = 0; + max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max); + while (count != max) { + count += inner.template try_dequeue_bulk(token, itemFirst, max - count); + } + return count; + } + + // Attempts to dequeue several elements from the queue using an explicit consumer token. + // Returns the number of items actually dequeued, which can + // be 0 if the timeout expires while waiting for elements, + // and at most max. + // Using a negative timeout indicates an indefinite timeout, + // and is thus functionally equivalent to calling wait_dequeue_bulk. + // Never allocates. Thread-safe. + template + inline size_t wait_dequeue_bulk_timed(consumer_token_t& token, It itemFirst, size_t max, std::int64_t timeout_usecs) + { + size_t count = 0; + max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max, timeout_usecs); + while (count != max) { + count += inner.template try_dequeue_bulk(token, itemFirst, max - count); + } + return count; + } + + // Attempts to dequeue several elements from the queue using an explicit consumer token. + // Returns the number of items actually dequeued, which can + // be 0 if the timeout expires while waiting for elements, + // and at most max. + // Never allocates. Thread-safe. + template + inline size_t wait_dequeue_bulk_timed(consumer_token_t& token, It itemFirst, size_t max, std::chrono::duration const& timeout) + { + return wait_dequeue_bulk_timed(token, itemFirst, max, std::chrono::duration_cast(timeout).count()); + } + + + // Returns an estimate of the total number of elements currently in the queue. This + // estimate is only accurate if the queue has completely stabilized before it is called + // (i.e. all enqueue and dequeue operations have completed and their memory effects are + // visible on the calling thread, and no further operations start while this method is + // being called). + // Thread-safe. + inline size_t size_approx() const + { + return (size_t)sema->availableApprox(); + } + + + // Returns true if the underlying atomic variables used by + // the queue are lock-free (they should be on most platforms). + // Thread-safe. + static constexpr bool is_lock_free() + { + return ConcurrentQueue::is_lock_free(); + } + + +private: + template + static inline U* create(A1&& a1, A2&& a2) + { + void* p = (Traits::malloc)(sizeof(U)); + return p != nullptr ? new (p) U(std::forward(a1), std::forward(a2)) : nullptr; + } + + template + static inline void destroy(U* p) + { + if (p != nullptr) { + p->~U(); + } + (Traits::free)(p); + } + +private: + ConcurrentQueue inner; + std::unique_ptr sema; +}; + + +template +inline void swap(BlockingConcurrentQueue& a, BlockingConcurrentQueue& b) MOODYCAMEL_NOEXCEPT +{ + a.swap(b); +} + +} // end namespace moodycamel diff --git a/duix-sdk/src/main/cpp/dhcore/concurrentqueue.h b/duix-sdk/src/main/cpp/dhcore/concurrentqueue.h new file mode 100644 index 0000000..99caefc --- /dev/null +++ b/duix-sdk/src/main/cpp/dhcore/concurrentqueue.h @@ -0,0 +1,3747 @@ +// Provides a C++11 implementation of a multi-producer, multi-consumer lock-free queue. +// An overview, including benchmark results, is provided here: +// http://moodycamel.com/blog/2014/a-fast-general-purpose-lock-free-queue-for-c++ +// The full design is also described in excruciating detail at: +// http://moodycamel.com/blog/2014/detailed-design-of-a-lock-free-queue + +// Simplified BSD license: +// Copyright (c) 2013-2020, Cameron Desrochers. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted 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. +// +// 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. + +// Also dual-licensed under the Boost Software License (see LICENSE.md) + +#pragma once + +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) +// Disable -Wconversion warnings (spuriously triggered when Traits::size_t and +// Traits::index_t are set to < 32 bits, causing integer promotion, causing warnings +// upon assigning any computed values) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" + +#ifdef MCDBGQ_USE_RELACY +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" +#endif +#endif + +#if defined(_MSC_VER) && (!defined(_HAS_CXX17) || !_HAS_CXX17) +// VS2019 with /W4 warns about constant conditional expressions but unless /std=c++17 or higher +// does not support `if constexpr`, so we have no choice but to simply disable the warning +#pragma warning(push) +#pragma warning(disable: 4127) // conditional expression is constant +#endif + +#if defined(__APPLE__) +#include "TargetConditionals.h" +#endif + +#ifdef MCDBGQ_USE_RELACY +#include "relacy/relacy_std.hpp" +#include "relacy_shims.h" +// We only use malloc/free anyway, and the delete macro messes up `= delete` method declarations. +// We'll override the default trait malloc ourselves without a macro. +#undef new +#undef delete +#undef malloc +#undef free +#else +#include // Requires C++11. Sorry VS2010. +#include +#endif +#include // for max_align_t +#include +#include +#include +#include +#include +#include +#include // for CHAR_BIT +#include +#include // partly for __WINPTHREADS_VERSION if on MinGW-w64 w/ POSIX threading +#include // used for thread exit synchronization + +// Platform-specific definitions of a numeric thread ID type and an invalid value +namespace moodycamel { namespace details { + template struct thread_id_converter { + typedef thread_id_t thread_id_numeric_size_t; + typedef thread_id_t thread_id_hash_t; + static thread_id_hash_t prehash(thread_id_t const& x) { return x; } + }; +} } +#if defined(MCDBGQ_USE_RELACY) +namespace moodycamel { namespace details { + typedef std::uint32_t thread_id_t; + static const thread_id_t invalid_thread_id = 0xFFFFFFFFU; + static const thread_id_t invalid_thread_id2 = 0xFFFFFFFEU; + static inline thread_id_t thread_id() { return rl::thread_index(); } +} } +#elif defined(_WIN32) || defined(__WINDOWS__) || defined(__WIN32__) +// No sense pulling in windows.h in a header, we'll manually declare the function +// we use and rely on backwards-compatibility for this not to break +extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId(void); +namespace moodycamel { namespace details { + static_assert(sizeof(unsigned long) == sizeof(std::uint32_t), "Expected size of unsigned long to be 32 bits on Windows"); + typedef std::uint32_t thread_id_t; + static const thread_id_t invalid_thread_id = 0; // See http://blogs.msdn.com/b/oldnewthing/archive/2004/02/23/78395.aspx + static const thread_id_t invalid_thread_id2 = 0xFFFFFFFFU; // Not technically guaranteed to be invalid, but is never used in practice. Note that all Win32 thread IDs are presently multiples of 4. + static inline thread_id_t thread_id() { return static_cast(::GetCurrentThreadId()); } +} } +#elif defined(__arm__) || defined(_M_ARM) || defined(__aarch64__) || (defined(__APPLE__) && TARGET_OS_IPHONE) || defined(__MVS__) || defined(MOODYCAMEL_NO_THREAD_LOCAL) +namespace moodycamel { namespace details { + static_assert(sizeof(std::thread::id) == 4 || sizeof(std::thread::id) == 8, "std::thread::id is expected to be either 4 or 8 bytes"); + + typedef std::thread::id thread_id_t; + static const thread_id_t invalid_thread_id; // Default ctor creates invalid ID + + // Note we don't define a invalid_thread_id2 since std::thread::id doesn't have one; it's + // only used if MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED is defined anyway, which it won't + // be. + static inline thread_id_t thread_id() { return std::this_thread::get_id(); } + + template struct thread_id_size { }; + template<> struct thread_id_size<4> { typedef std::uint32_t numeric_t; }; + template<> struct thread_id_size<8> { typedef std::uint64_t numeric_t; }; + + template<> struct thread_id_converter { + typedef thread_id_size::numeric_t thread_id_numeric_size_t; +#ifndef __APPLE__ + typedef std::size_t thread_id_hash_t; +#else + typedef thread_id_numeric_size_t thread_id_hash_t; +#endif + + static thread_id_hash_t prehash(thread_id_t const& x) + { +#ifndef __APPLE__ + return std::hash()(x); +#else + return *reinterpret_cast(&x); +#endif + } + }; +} } +#else +// Use a nice trick from this answer: http://stackoverflow.com/a/8438730/21475 +// In order to get a numeric thread ID in a platform-independent way, we use a thread-local +// static variable's address as a thread identifier :-) +#if defined(__GNUC__) || defined(__INTEL_COMPILER) +#define MOODYCAMEL_THREADLOCAL __thread +#elif defined(_MSC_VER) +#define MOODYCAMEL_THREADLOCAL __declspec(thread) +#else +// Assume C++11 compliant compiler +#define MOODYCAMEL_THREADLOCAL thread_local +#endif +namespace moodycamel { namespace details { + typedef std::uintptr_t thread_id_t; + static const thread_id_t invalid_thread_id = 0; // Address can't be nullptr + static const thread_id_t invalid_thread_id2 = 1; // Member accesses off a null pointer are also generally invalid. Plus it's not aligned. + inline thread_id_t thread_id() { static MOODYCAMEL_THREADLOCAL int x; return reinterpret_cast(&x); } +} } +#endif + +// Constexpr if +#ifndef MOODYCAMEL_CONSTEXPR_IF +#if (defined(_MSC_VER) && defined(_HAS_CXX17) && _HAS_CXX17) || __cplusplus > 201402L +#define MOODYCAMEL_CONSTEXPR_IF if constexpr +#define MOODYCAMEL_MAYBE_UNUSED [[maybe_unused]] +#else +#define MOODYCAMEL_CONSTEXPR_IF if +#define MOODYCAMEL_MAYBE_UNUSED +#endif +#endif + +// Exceptions +#ifndef MOODYCAMEL_EXCEPTIONS_ENABLED +#if (defined(_MSC_VER) && defined(_CPPUNWIND)) || (defined(__GNUC__) && defined(__EXCEPTIONS)) || (!defined(_MSC_VER) && !defined(__GNUC__)) +#define MOODYCAMEL_EXCEPTIONS_ENABLED +#endif +#endif +#ifdef MOODYCAMEL_EXCEPTIONS_ENABLED +#define MOODYCAMEL_TRY try +#define MOODYCAMEL_CATCH(...) catch(__VA_ARGS__) +#define MOODYCAMEL_RETHROW throw +#define MOODYCAMEL_THROW(expr) throw (expr) +#else +#define MOODYCAMEL_TRY MOODYCAMEL_CONSTEXPR_IF (true) +#define MOODYCAMEL_CATCH(...) else MOODYCAMEL_CONSTEXPR_IF (false) +#define MOODYCAMEL_RETHROW +#define MOODYCAMEL_THROW(expr) +#endif + +#ifndef MOODYCAMEL_NOEXCEPT +#if !defined(MOODYCAMEL_EXCEPTIONS_ENABLED) +#define MOODYCAMEL_NOEXCEPT +#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) true +#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) true +#elif defined(_MSC_VER) && defined(_NOEXCEPT) && _MSC_VER < 1800 +// VS2012's std::is_nothrow_[move_]constructible is broken and returns true when it shouldn't :-( +// We have to assume *all* non-trivial constructors may throw on VS2012! +#define MOODYCAMEL_NOEXCEPT _NOEXCEPT +#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) (std::is_rvalue_reference::value && std::is_move_constructible::value ? std::is_trivially_move_constructible::value : std::is_trivially_copy_constructible::value) +#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) ((std::is_rvalue_reference::value && std::is_move_assignable::value ? std::is_trivially_move_assignable::value || std::is_nothrow_move_assignable::value : std::is_trivially_copy_assignable::value || std::is_nothrow_copy_assignable::value) && MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr)) +#elif defined(_MSC_VER) && defined(_NOEXCEPT) && _MSC_VER < 1900 +#define MOODYCAMEL_NOEXCEPT _NOEXCEPT +#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) (std::is_rvalue_reference::value && std::is_move_constructible::value ? std::is_trivially_move_constructible::value || std::is_nothrow_move_constructible::value : std::is_trivially_copy_constructible::value || std::is_nothrow_copy_constructible::value) +#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) ((std::is_rvalue_reference::value && std::is_move_assignable::value ? std::is_trivially_move_assignable::value || std::is_nothrow_move_assignable::value : std::is_trivially_copy_assignable::value || std::is_nothrow_copy_assignable::value) && MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr)) +#else +#define MOODYCAMEL_NOEXCEPT noexcept +#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) noexcept(expr) +#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) noexcept(expr) +#endif +#endif + +#ifndef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED +#ifdef MCDBGQ_USE_RELACY +#define MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED +#else +// VS2013 doesn't support `thread_local`, and MinGW-w64 w/ POSIX threading has a crippling bug: http://sourceforge.net/p/mingw-w64/bugs/445 +// g++ <=4.7 doesn't support thread_local either. +// Finally, iOS/ARM doesn't have support for it either, and g++/ARM allows it to compile but it's unconfirmed to actually work +#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && (!defined(__MINGW32__) && !defined(__MINGW64__) || !defined(__WINPTHREADS_VERSION)) && (!defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) && (!defined(__APPLE__) || !TARGET_OS_IPHONE) && !defined(__arm__) && !defined(_M_ARM) && !defined(__aarch64__) && !defined(__MVS__) +// Assume `thread_local` is fully supported in all other C++11 compilers/platforms +#define MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED // tentatively enabled for now; years ago several users report having problems with it on +#endif +#endif +#endif + +// VS2012 doesn't support deleted functions. +// In this case, we declare the function normally but don't define it. A link error will be generated if the function is called. +#ifndef MOODYCAMEL_DELETE_FUNCTION +#if defined(_MSC_VER) && _MSC_VER < 1800 +#define MOODYCAMEL_DELETE_FUNCTION +#else +#define MOODYCAMEL_DELETE_FUNCTION = delete +#endif +#endif + +namespace moodycamel { namespace details { +#ifndef MOODYCAMEL_ALIGNAS +// VS2013 doesn't support alignas or alignof, and align() requires a constant literal +#if defined(_MSC_VER) && _MSC_VER <= 1800 +#define MOODYCAMEL_ALIGNAS(alignment) __declspec(align(alignment)) +#define MOODYCAMEL_ALIGNOF(obj) __alignof(obj) +#define MOODYCAMEL_ALIGNED_TYPE_LIKE(T, obj) typename details::Vs2013Aligned::value, T>::type + template struct Vs2013Aligned { }; // default, unsupported alignment + template struct Vs2013Aligned<1, T> { typedef __declspec(align(1)) T type; }; + template struct Vs2013Aligned<2, T> { typedef __declspec(align(2)) T type; }; + template struct Vs2013Aligned<4, T> { typedef __declspec(align(4)) T type; }; + template struct Vs2013Aligned<8, T> { typedef __declspec(align(8)) T type; }; + template struct Vs2013Aligned<16, T> { typedef __declspec(align(16)) T type; }; + template struct Vs2013Aligned<32, T> { typedef __declspec(align(32)) T type; }; + template struct Vs2013Aligned<64, T> { typedef __declspec(align(64)) T type; }; + template struct Vs2013Aligned<128, T> { typedef __declspec(align(128)) T type; }; + template struct Vs2013Aligned<256, T> { typedef __declspec(align(256)) T type; }; +#else + template struct identity { typedef T type; }; +#define MOODYCAMEL_ALIGNAS(alignment) alignas(alignment) +#define MOODYCAMEL_ALIGNOF(obj) alignof(obj) +#define MOODYCAMEL_ALIGNED_TYPE_LIKE(T, obj) alignas(alignof(obj)) typename details::identity::type +#endif +#endif +} } + + +// TSAN can false report races in lock-free code. To enable TSAN to be used from projects that use this one, +// we can apply per-function compile-time suppression. +// See https://clang.llvm.org/docs/ThreadSanitizer.html#has-feature-thread-sanitizer +#define MOODYCAMEL_NO_TSAN +#if defined(__has_feature) + #if __has_feature(thread_sanitizer) + #undef MOODYCAMEL_NO_TSAN + #define MOODYCAMEL_NO_TSAN __attribute__((no_sanitize("thread"))) + #endif // TSAN +#endif // TSAN + +// Compiler-specific likely/unlikely hints +namespace moodycamel { namespace details { +#if defined(__GNUC__) + static inline bool (likely)(bool x) { return __builtin_expect((x), true); } + static inline bool (unlikely)(bool x) { return __builtin_expect((x), false); } +#else + static inline bool (likely)(bool x) { return x; } + static inline bool (unlikely)(bool x) { return x; } +#endif +} } + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG +#include "internal/concurrentqueue_internal_debug.h" +#endif + +namespace moodycamel { +namespace details { + template + struct const_numeric_max { + static_assert(std::is_integral::value, "const_numeric_max can only be used with integers"); + static const T value = std::numeric_limits::is_signed + ? (static_cast(1) << (sizeof(T) * CHAR_BIT - 1)) - static_cast(1) + : static_cast(-1); + }; + +#if defined(__GLIBCXX__) + typedef ::max_align_t std_max_align_t; // libstdc++ forgot to add it to std:: for a while +#else + typedef std::max_align_t std_max_align_t; // Others (e.g. MSVC) insist it can *only* be accessed via std:: +#endif + + // Some platforms have incorrectly set max_align_t to a type with <8 bytes alignment even while supporting + // 8-byte aligned scalar values (*cough* 32-bit iOS). Work around this with our own union. See issue #64. + typedef union { + std_max_align_t x; + long long y; + void* z; + } max_align_t; +} + +// Default traits for the ConcurrentQueue. To change some of the +// traits without re-implementing all of them, inherit from this +// struct and shadow the declarations you wish to be different; +// since the traits are used as a template type parameter, the +// shadowed declarations will be used where defined, and the defaults +// otherwise. +struct ConcurrentQueueDefaultTraits +{ + // General-purpose size type. std::size_t is strongly recommended. + typedef std::size_t size_t; + + // The type used for the enqueue and dequeue indices. Must be at least as + // large as size_t. Should be significantly larger than the number of elements + // you expect to hold at once, especially if you have a high turnover rate; + // for example, on 32-bit x86, if you expect to have over a hundred million + // elements or pump several million elements through your queue in a very + // short space of time, using a 32-bit type *may* trigger a race condition. + // A 64-bit int type is recommended in that case, and in practice will + // prevent a race condition no matter the usage of the queue. Note that + // whether the queue is lock-free with a 64-int type depends on the whether + // std::atomic is lock-free, which is platform-specific. + typedef std::size_t index_t; + + // Internally, all elements are enqueued and dequeued from multi-element + // blocks; this is the smallest controllable unit. If you expect few elements + // but many producers, a smaller block size should be favoured. For few producers + // and/or many elements, a larger block size is preferred. A sane default + // is provided. Must be a power of 2. + static const size_t BLOCK_SIZE = 32; + + // For explicit producers (i.e. when using a producer token), the block is + // checked for being empty by iterating through a list of flags, one per element. + // For large block sizes, this is too inefficient, and switching to an atomic + // counter-based approach is faster. The switch is made for block sizes strictly + // larger than this threshold. + static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = 32; + + // How many full blocks can be expected for a single explicit producer? This should + // reflect that number's maximum for optimal performance. Must be a power of 2. + static const size_t EXPLICIT_INITIAL_INDEX_SIZE = 32; + + // How many full blocks can be expected for a single implicit producer? This should + // reflect that number's maximum for optimal performance. Must be a power of 2. + static const size_t IMPLICIT_INITIAL_INDEX_SIZE = 32; + + // The initial size of the hash table mapping thread IDs to implicit producers. + // Note that the hash is resized every time it becomes half full. + // Must be a power of two, and either 0 or at least 1. If 0, implicit production + // (using the enqueue methods without an explicit producer token) is disabled. + static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = 32; + + // Controls the number of items that an explicit consumer (i.e. one with a token) + // must consume before it causes all consumers to rotate and move on to the next + // internal queue. + static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = 256; + + // The maximum number of elements (inclusive) that can be enqueued to a sub-queue. + // Enqueue operations that would cause this limit to be surpassed will fail. Note + // that this limit is enforced at the block level (for performance reasons), i.e. + // it's rounded up to the nearest block size. + static const size_t MAX_SUBQUEUE_SIZE = details::const_numeric_max::value; + + // The number of times to spin before sleeping when waiting on a semaphore. + // Recommended values are on the order of 1000-10000 unless the number of + // consumer threads exceeds the number of idle cores (in which case try 0-100). + // Only affects instances of the BlockingConcurrentQueue. + static const int MAX_SEMA_SPINS = 10000; + + // Whether to recycle dynamically-allocated blocks into an internal free list or + // not. If false, only pre-allocated blocks (controlled by the constructor + // arguments) will be recycled, and all others will be `free`d back to the heap. + // Note that blocks consumed by explicit producers are only freed on destruction + // of the queue (not following destruction of the token) regardless of this trait. + static const bool RECYCLE_ALLOCATED_BLOCKS = false; + + +#ifndef MCDBGQ_USE_RELACY + // Memory allocation can be customized if needed. + // malloc should return nullptr on failure, and handle alignment like std::malloc. +#if defined(malloc) || defined(free) + // Gah, this is 2015, stop defining macros that break standard code already! + // Work around malloc/free being special macros: + static inline void* WORKAROUND_malloc(size_t size) { return malloc(size); } + static inline void WORKAROUND_free(void* ptr) { return free(ptr); } + static inline void* (malloc)(size_t size) { return WORKAROUND_malloc(size); } + static inline void (free)(void* ptr) { return WORKAROUND_free(ptr); } +#else + static inline void* malloc(size_t size) { return std::malloc(size); } + static inline void free(void* ptr) { return std::free(ptr); } +#endif +#else + // Debug versions when running under the Relacy race detector (ignore + // these in user code) + static inline void* malloc(size_t size) { return rl::rl_malloc(size, $); } + static inline void free(void* ptr) { return rl::rl_free(ptr, $); } +#endif +}; + + +// When producing or consuming many elements, the most efficient way is to: +// 1) Use one of the bulk-operation methods of the queue with a token +// 2) Failing that, use the bulk-operation methods without a token +// 3) Failing that, create a token and use that with the single-item methods +// 4) Failing that, use the single-parameter methods of the queue +// Having said that, don't create tokens willy-nilly -- ideally there should be +// a maximum of one token per thread (of each kind). +struct ProducerToken; +struct ConsumerToken; + +template class ConcurrentQueue; +template class BlockingConcurrentQueue; +class ConcurrentQueueTests; + + +namespace details +{ + struct ConcurrentQueueProducerTypelessBase + { + ConcurrentQueueProducerTypelessBase* next; + std::atomic inactive; + ProducerToken* token; + + ConcurrentQueueProducerTypelessBase() + : next(nullptr), inactive(false), token(nullptr) + { + } + }; + + template struct _hash_32_or_64 { + static inline std::uint32_t hash(std::uint32_t h) + { + // MurmurHash3 finalizer -- see https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp + // Since the thread ID is already unique, all we really want to do is propagate that + // uniqueness evenly across all the bits, so that we can use a subset of the bits while + // reducing collisions significantly + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + return h ^ (h >> 16); + } + }; + template<> struct _hash_32_or_64<1> { + static inline std::uint64_t hash(std::uint64_t h) + { + h ^= h >> 33; + h *= 0xff51afd7ed558ccd; + h ^= h >> 33; + h *= 0xc4ceb9fe1a85ec53; + return h ^ (h >> 33); + } + }; + template struct hash_32_or_64 : public _hash_32_or_64<(size > 4)> { }; + + static inline size_t hash_thread_id(thread_id_t id) + { + static_assert(sizeof(thread_id_t) <= 8, "Expected a platform where thread IDs are at most 64-bit values"); + return static_cast(hash_32_or_64::thread_id_hash_t)>::hash( + thread_id_converter::prehash(id))); + } + + template + static inline bool circular_less_than(T a, T b) + { + static_assert(std::is_integral::value && !std::numeric_limits::is_signed, "circular_less_than is intended to be used only with unsigned integer types"); + return static_cast(a - b) > static_cast(static_cast(1) << (static_cast(sizeof(T) * CHAR_BIT - 1))); + // Note: extra parens around rhs of operator<< is MSVC bug: https://developercommunity2.visualstudio.com/t/C4554-triggers-when-both-lhs-and-rhs-is/10034931 + // silencing the bug requires #pragma warning(disable: 4554) around the calling code and has no effect when done here. + } + + template + static inline char* align_for(char* ptr) + { + const std::size_t alignment = std::alignment_of::value; + return ptr + (alignment - (reinterpret_cast(ptr) % alignment)) % alignment; + } + + template + static inline T ceil_to_pow_2(T x) + { + static_assert(std::is_integral::value && !std::numeric_limits::is_signed, "ceil_to_pow_2 is intended to be used only with unsigned integer types"); + + // Adapted from http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + for (std::size_t i = 1; i < sizeof(T); i <<= 1) { + x |= x >> (i << 3); + } + ++x; + return x; + } + + template + static inline void swap_relaxed(std::atomic& left, std::atomic& right) + { + T temp = std::move(left.load(std::memory_order_relaxed)); + left.store(std::move(right.load(std::memory_order_relaxed)), std::memory_order_relaxed); + right.store(std::move(temp), std::memory_order_relaxed); + } + + template + static inline T const& nomove(T const& x) + { + return x; + } + + template + struct nomove_if + { + template + static inline T const& eval(T const& x) + { + return x; + } + }; + + template<> + struct nomove_if + { + template + static inline auto eval(U&& x) + -> decltype(std::forward(x)) + { + return std::forward(x); + } + }; + + template + static inline auto deref_noexcept(It& it) MOODYCAMEL_NOEXCEPT -> decltype(*it) + { + return *it; + } + +#if defined(__clang__) || !defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + template struct is_trivially_destructible : std::is_trivially_destructible { }; +#else + template struct is_trivially_destructible : std::has_trivial_destructor { }; +#endif + +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED +#ifdef MCDBGQ_USE_RELACY + typedef RelacyThreadExitListener ThreadExitListener; + typedef RelacyThreadExitNotifier ThreadExitNotifier; +#else + class ThreadExitNotifier; + + struct ThreadExitListener + { + typedef void (*callback_t)(void*); + callback_t callback; + void* userData; + + ThreadExitListener* next; // reserved for use by the ThreadExitNotifier + ThreadExitNotifier* chain; // reserved for use by the ThreadExitNotifier + }; + + class ThreadExitNotifier + { + public: + static void subscribe(ThreadExitListener* listener) + { + auto& tlsInst = instance(); + std::lock_guard guard(mutex()); + listener->next = tlsInst.tail; + listener->chain = &tlsInst; + tlsInst.tail = listener; + } + + static void unsubscribe(ThreadExitListener* listener) + { + std::lock_guard guard(mutex()); + if (!listener->chain) { + return; // race with ~ThreadExitNotifier + } + auto& tlsInst = *listener->chain; + listener->chain = nullptr; + ThreadExitListener** prev = &tlsInst.tail; + for (auto ptr = tlsInst.tail; ptr != nullptr; ptr = ptr->next) { + if (ptr == listener) { + *prev = ptr->next; + break; + } + prev = &ptr->next; + } + } + + private: + ThreadExitNotifier() : tail(nullptr) { } + ThreadExitNotifier(ThreadExitNotifier const&) MOODYCAMEL_DELETE_FUNCTION; + ThreadExitNotifier& operator=(ThreadExitNotifier const&) MOODYCAMEL_DELETE_FUNCTION; + + ~ThreadExitNotifier() + { + // This thread is about to exit, let everyone know! + assert(this == &instance() && "If this assert fails, you likely have a buggy compiler! Change the preprocessor conditions such that MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED is no longer defined."); + std::lock_guard guard(mutex()); + for (auto ptr = tail; ptr != nullptr; ptr = ptr->next) { + ptr->chain = nullptr; + ptr->callback(ptr->userData); + } + } + + // Thread-local + static inline ThreadExitNotifier& instance() + { + static thread_local ThreadExitNotifier notifier; + return notifier; + } + + static inline std::mutex& mutex() + { + // Must be static because the ThreadExitNotifier could be destroyed while unsubscribe is called + static std::mutex mutex; + return mutex; + } + + private: + ThreadExitListener* tail; + }; +#endif +#endif + + template struct static_is_lock_free_num { enum { value = 0 }; }; + template<> struct static_is_lock_free_num { enum { value = ATOMIC_CHAR_LOCK_FREE }; }; + template<> struct static_is_lock_free_num { enum { value = ATOMIC_SHORT_LOCK_FREE }; }; + template<> struct static_is_lock_free_num { enum { value = ATOMIC_INT_LOCK_FREE }; }; + template<> struct static_is_lock_free_num { enum { value = ATOMIC_LONG_LOCK_FREE }; }; + template<> struct static_is_lock_free_num { enum { value = ATOMIC_LLONG_LOCK_FREE }; }; + template struct static_is_lock_free : static_is_lock_free_num::type> { }; + template<> struct static_is_lock_free { enum { value = ATOMIC_BOOL_LOCK_FREE }; }; + template struct static_is_lock_free { enum { value = ATOMIC_POINTER_LOCK_FREE }; }; +} + + +struct ProducerToken +{ + template + explicit ProducerToken(ConcurrentQueue& queue); + + template + explicit ProducerToken(BlockingConcurrentQueue& queue); + + ProducerToken(ProducerToken&& other) MOODYCAMEL_NOEXCEPT + : producer(other.producer) + { + other.producer = nullptr; + if (producer != nullptr) { + producer->token = this; + } + } + + inline ProducerToken& operator=(ProducerToken&& other) MOODYCAMEL_NOEXCEPT + { + swap(other); + return *this; + } + + void swap(ProducerToken& other) MOODYCAMEL_NOEXCEPT + { + std::swap(producer, other.producer); + if (producer != nullptr) { + producer->token = this; + } + if (other.producer != nullptr) { + other.producer->token = &other; + } + } + + // A token is always valid unless: + // 1) Memory allocation failed during construction + // 2) It was moved via the move constructor + // (Note: assignment does a swap, leaving both potentially valid) + // 3) The associated queue was destroyed + // Note that if valid() returns true, that only indicates + // that the token is valid for use with a specific queue, + // but not which one; that's up to the user to track. + inline bool valid() const { return producer != nullptr; } + + ~ProducerToken() + { + if (producer != nullptr) { + producer->token = nullptr; + producer->inactive.store(true, std::memory_order_release); + } + } + + // Disable copying and assignment + ProducerToken(ProducerToken const&) MOODYCAMEL_DELETE_FUNCTION; + ProducerToken& operator=(ProducerToken const&) MOODYCAMEL_DELETE_FUNCTION; + +private: + template friend class ConcurrentQueue; + friend class ConcurrentQueueTests; + +protected: + details::ConcurrentQueueProducerTypelessBase* producer; +}; + + +struct ConsumerToken +{ + template + explicit ConsumerToken(ConcurrentQueue& q); + + template + explicit ConsumerToken(BlockingConcurrentQueue& q); + + ConsumerToken(ConsumerToken&& other) MOODYCAMEL_NOEXCEPT + : initialOffset(other.initialOffset), lastKnownGlobalOffset(other.lastKnownGlobalOffset), itemsConsumedFromCurrent(other.itemsConsumedFromCurrent), currentProducer(other.currentProducer), desiredProducer(other.desiredProducer) + { + } + + inline ConsumerToken& operator=(ConsumerToken&& other) MOODYCAMEL_NOEXCEPT + { + swap(other); + return *this; + } + + void swap(ConsumerToken& other) MOODYCAMEL_NOEXCEPT + { + std::swap(initialOffset, other.initialOffset); + std::swap(lastKnownGlobalOffset, other.lastKnownGlobalOffset); + std::swap(itemsConsumedFromCurrent, other.itemsConsumedFromCurrent); + std::swap(currentProducer, other.currentProducer); + std::swap(desiredProducer, other.desiredProducer); + } + + // Disable copying and assignment + ConsumerToken(ConsumerToken const&) MOODYCAMEL_DELETE_FUNCTION; + ConsumerToken& operator=(ConsumerToken const&) MOODYCAMEL_DELETE_FUNCTION; + +private: + template friend class ConcurrentQueue; + friend class ConcurrentQueueTests; + +private: // but shared with ConcurrentQueue + std::uint32_t initialOffset; + std::uint32_t lastKnownGlobalOffset; + std::uint32_t itemsConsumedFromCurrent; + details::ConcurrentQueueProducerTypelessBase* currentProducer; + details::ConcurrentQueueProducerTypelessBase* desiredProducer; +}; + +// Need to forward-declare this swap because it's in a namespace. +// See http://stackoverflow.com/questions/4492062/why-does-a-c-friend-class-need-a-forward-declaration-only-in-other-namespaces +template +inline void swap(typename ConcurrentQueue::ImplicitProducerKVP& a, typename ConcurrentQueue::ImplicitProducerKVP& b) MOODYCAMEL_NOEXCEPT; + + +template +class ConcurrentQueue +{ +public: + typedef ::moodycamel::ProducerToken producer_token_t; + typedef ::moodycamel::ConsumerToken consumer_token_t; + + typedef typename Traits::index_t index_t; + typedef typename Traits::size_t size_t; + + static const size_t BLOCK_SIZE = static_cast(Traits::BLOCK_SIZE); + static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = static_cast(Traits::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD); + static const size_t EXPLICIT_INITIAL_INDEX_SIZE = static_cast(Traits::EXPLICIT_INITIAL_INDEX_SIZE); + static const size_t IMPLICIT_INITIAL_INDEX_SIZE = static_cast(Traits::IMPLICIT_INITIAL_INDEX_SIZE); + static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = static_cast(Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE); + static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = static_cast(Traits::EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE); +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4307) // + integral constant overflow (that's what the ternary expression is for!) +#pragma warning(disable: 4309) // static_cast: Truncation of constant value +#endif + static const size_t MAX_SUBQUEUE_SIZE = (details::const_numeric_max::value - static_cast(Traits::MAX_SUBQUEUE_SIZE) < BLOCK_SIZE) ? details::const_numeric_max::value : ((static_cast(Traits::MAX_SUBQUEUE_SIZE) + (BLOCK_SIZE - 1)) / BLOCK_SIZE * BLOCK_SIZE); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + static_assert(!std::numeric_limits::is_signed && std::is_integral::value, "Traits::size_t must be an unsigned integral type"); + static_assert(!std::numeric_limits::is_signed && std::is_integral::value, "Traits::index_t must be an unsigned integral type"); + static_assert(sizeof(index_t) >= sizeof(size_t), "Traits::index_t must be at least as wide as Traits::size_t"); + static_assert((BLOCK_SIZE > 1) && !(BLOCK_SIZE & (BLOCK_SIZE - 1)), "Traits::BLOCK_SIZE must be a power of 2 (and at least 2)"); + static_assert((EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD > 1) && !(EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD & (EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD - 1)), "Traits::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD must be a power of 2 (and greater than 1)"); + static_assert((EXPLICIT_INITIAL_INDEX_SIZE > 1) && !(EXPLICIT_INITIAL_INDEX_SIZE & (EXPLICIT_INITIAL_INDEX_SIZE - 1)), "Traits::EXPLICIT_INITIAL_INDEX_SIZE must be a power of 2 (and greater than 1)"); + static_assert((IMPLICIT_INITIAL_INDEX_SIZE > 1) && !(IMPLICIT_INITIAL_INDEX_SIZE & (IMPLICIT_INITIAL_INDEX_SIZE - 1)), "Traits::IMPLICIT_INITIAL_INDEX_SIZE must be a power of 2 (and greater than 1)"); + static_assert((INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) || !(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE & (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE - 1)), "Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE must be a power of 2"); + static_assert(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0 || INITIAL_IMPLICIT_PRODUCER_HASH_SIZE >= 1, "Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE must be at least 1 (or 0 to disable implicit enqueueing)"); + +public: + // Creates a queue with at least `capacity` element slots; note that the + // actual number of elements that can be inserted without additional memory + // allocation depends on the number of producers and the block size (e.g. if + // the block size is equal to `capacity`, only a single block will be allocated + // up-front, which means only a single producer will be able to enqueue elements + // without an extra allocation -- blocks aren't shared between producers). + // This method is not thread safe -- it is up to the user to ensure that the + // queue is fully constructed before it starts being used by other threads (this + // includes making the memory effects of construction visible, possibly with a + // memory barrier). + explicit ConcurrentQueue(size_t capacity = 32 * BLOCK_SIZE) + : producerListTail(nullptr), + producerCount(0), + initialBlockPoolIndex(0), + nextExplicitConsumerId(0), + globalExplicitConsumerOffset(0) + { + implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); + populate_initial_implicit_producer_hash(); + populate_initial_block_list(capacity / BLOCK_SIZE + ((capacity & (BLOCK_SIZE - 1)) == 0 ? 0 : 1)); + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + // Track all the producers using a fully-resolved typed list for + // each kind; this makes it possible to debug them starting from + // the root queue object (otherwise wacky casts are needed that + // don't compile in the debugger's expression evaluator). + explicitProducers.store(nullptr, std::memory_order_relaxed); + implicitProducers.store(nullptr, std::memory_order_relaxed); +#endif + } + + // Computes the correct amount of pre-allocated blocks for you based + // on the minimum number of elements you want available at any given + // time, and the maximum concurrent number of each type of producer. + ConcurrentQueue(size_t minCapacity, size_t maxExplicitProducers, size_t maxImplicitProducers) + : producerListTail(nullptr), + producerCount(0), + initialBlockPoolIndex(0), + nextExplicitConsumerId(0), + globalExplicitConsumerOffset(0) + { + implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); + populate_initial_implicit_producer_hash(); + size_t blocks = (((minCapacity + BLOCK_SIZE - 1) / BLOCK_SIZE) - 1) * (maxExplicitProducers + 1) + 2 * (maxExplicitProducers + maxImplicitProducers); + populate_initial_block_list(blocks); + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + explicitProducers.store(nullptr, std::memory_order_relaxed); + implicitProducers.store(nullptr, std::memory_order_relaxed); +#endif + } + + // Note: The queue should not be accessed concurrently while it's + // being deleted. It's up to the user to synchronize this. + // This method is not thread safe. + ~ConcurrentQueue() + { + // Destroy producers + auto ptr = producerListTail.load(std::memory_order_relaxed); + while (ptr != nullptr) { + auto next = ptr->next_prod(); + if (ptr->token != nullptr) { + ptr->token->producer = nullptr; + } + destroy(ptr); + ptr = next; + } + + // Destroy implicit producer hash tables + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE != 0) { + auto hash = implicitProducerHash.load(std::memory_order_relaxed); + while (hash != nullptr) { + auto prev = hash->prev; + if (prev != nullptr) { // The last hash is part of this object and was not allocated dynamically + for (size_t i = 0; i != hash->capacity; ++i) { + hash->entries[i].~ImplicitProducerKVP(); + } + hash->~ImplicitProducerHash(); + (Traits::free)(hash); + } + hash = prev; + } + } + + // Destroy global free list + auto block = freeList.head_unsafe(); + while (block != nullptr) { + auto next = block->freeListNext.load(std::memory_order_relaxed); + if (block->dynamicallyAllocated) { + destroy(block); + } + block = next; + } + + // Destroy initial free list + destroy_array(initialBlockPool, initialBlockPoolSize); + } + + // Disable copying and copy assignment + ConcurrentQueue(ConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION; + ConcurrentQueue& operator=(ConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION; + + // Moving is supported, but note that it is *not* a thread-safe operation. + // Nobody can use the queue while it's being moved, and the memory effects + // of that move must be propagated to other threads before they can use it. + // Note: When a queue is moved, its tokens are still valid but can only be + // used with the destination queue (i.e. semantically they are moved along + // with the queue itself). + ConcurrentQueue(ConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT + : producerListTail(other.producerListTail.load(std::memory_order_relaxed)), + producerCount(other.producerCount.load(std::memory_order_relaxed)), + initialBlockPoolIndex(other.initialBlockPoolIndex.load(std::memory_order_relaxed)), + initialBlockPool(other.initialBlockPool), + initialBlockPoolSize(other.initialBlockPoolSize), + freeList(std::move(other.freeList)), + nextExplicitConsumerId(other.nextExplicitConsumerId.load(std::memory_order_relaxed)), + globalExplicitConsumerOffset(other.globalExplicitConsumerOffset.load(std::memory_order_relaxed)) + { + // Move the other one into this, and leave the other one as an empty queue + implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); + populate_initial_implicit_producer_hash(); + swap_implicit_producer_hashes(other); + + other.producerListTail.store(nullptr, std::memory_order_relaxed); + other.producerCount.store(0, std::memory_order_relaxed); + other.nextExplicitConsumerId.store(0, std::memory_order_relaxed); + other.globalExplicitConsumerOffset.store(0, std::memory_order_relaxed); + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + explicitProducers.store(other.explicitProducers.load(std::memory_order_relaxed), std::memory_order_relaxed); + other.explicitProducers.store(nullptr, std::memory_order_relaxed); + implicitProducers.store(other.implicitProducers.load(std::memory_order_relaxed), std::memory_order_relaxed); + other.implicitProducers.store(nullptr, std::memory_order_relaxed); +#endif + + other.initialBlockPoolIndex.store(0, std::memory_order_relaxed); + other.initialBlockPoolSize = 0; + other.initialBlockPool = nullptr; + + reown_producers(); + } + + inline ConcurrentQueue& operator=(ConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT + { + return swap_internal(other); + } + + // Swaps this queue's state with the other's. Not thread-safe. + // Swapping two queues does not invalidate their tokens, however + // the tokens that were created for one queue must be used with + // only the swapped queue (i.e. the tokens are tied to the + // queue's movable state, not the object itself). + inline void swap(ConcurrentQueue& other) MOODYCAMEL_NOEXCEPT + { + swap_internal(other); + } + +private: + ConcurrentQueue& swap_internal(ConcurrentQueue& other) + { + if (this == &other) { + return *this; + } + + details::swap_relaxed(producerListTail, other.producerListTail); + details::swap_relaxed(producerCount, other.producerCount); + details::swap_relaxed(initialBlockPoolIndex, other.initialBlockPoolIndex); + std::swap(initialBlockPool, other.initialBlockPool); + std::swap(initialBlockPoolSize, other.initialBlockPoolSize); + freeList.swap(other.freeList); + details::swap_relaxed(nextExplicitConsumerId, other.nextExplicitConsumerId); + details::swap_relaxed(globalExplicitConsumerOffset, other.globalExplicitConsumerOffset); + + swap_implicit_producer_hashes(other); + + reown_producers(); + other.reown_producers(); + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + details::swap_relaxed(explicitProducers, other.explicitProducers); + details::swap_relaxed(implicitProducers, other.implicitProducers); +#endif + + return *this; + } + +public: + // Enqueues a single item (by copying it). + // Allocates memory if required. Only fails if memory allocation fails (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0, + // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(T const& item) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue(item); + } + + // Enqueues a single item (by moving it, if possible). + // Allocates memory if required. Only fails if memory allocation fails (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0, + // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(T&& item) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue(std::move(item)); + } + + // Enqueues a single item (by copying it) using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails (or + // Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(producer_token_t const& token, T const& item) + { + return inner_enqueue(token, item); + } + + // Enqueues a single item (by moving it, if possible) using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails (or + // Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(producer_token_t const& token, T&& item) + { + return inner_enqueue(token, std::move(item)); + } + + // Enqueues several items. + // Allocates memory if required. Only fails if memory allocation fails (or + // implicit production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE + // is 0, or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Note: Use std::make_move_iterator if the elements should be moved instead of copied. + // Thread-safe. + template + bool enqueue_bulk(It itemFirst, size_t count) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue_bulk(itemFirst, count); + } + + // Enqueues several items using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails + // (or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + bool enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) + { + return inner_enqueue_bulk(token, itemFirst, count); + } + + // Enqueues a single item (by copying it). + // Does not allocate memory. Fails if not enough room to enqueue (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE + // is 0). + // Thread-safe. + inline bool try_enqueue(T const& item) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue(item); + } + + // Enqueues a single item (by moving it, if possible). + // Does not allocate memory (except for one-time implicit producer). + // Fails if not enough room to enqueue (or implicit production is + // disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0). + // Thread-safe. + inline bool try_enqueue(T&& item) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue(std::move(item)); + } + + // Enqueues a single item (by copying it) using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Thread-safe. + inline bool try_enqueue(producer_token_t const& token, T const& item) + { + return inner_enqueue(token, item); + } + + // Enqueues a single item (by moving it, if possible) using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Thread-safe. + inline bool try_enqueue(producer_token_t const& token, T&& item) + { + return inner_enqueue(token, std::move(item)); + } + + // Enqueues several items. + // Does not allocate memory (except for one-time implicit producer). + // Fails if not enough room to enqueue (or implicit production is + // disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0). + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + bool try_enqueue_bulk(It itemFirst, size_t count) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue_bulk(itemFirst, count); + } + + // Enqueues several items using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + bool try_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) + { + return inner_enqueue_bulk(token, itemFirst, count); + } + + + + // Attempts to dequeue from the queue. + // Returns false if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + bool try_dequeue(U& item) + { + // Instead of simply trying each producer in turn (which could cause needless contention on the first + // producer), we score them heuristically. + size_t nonEmptyCount = 0; + ProducerBase* best = nullptr; + size_t bestSize = 0; + for (auto ptr = producerListTail.load(std::memory_order_acquire); nonEmptyCount < 3 && ptr != nullptr; ptr = ptr->next_prod()) { + auto size = ptr->size_approx(); + if (size > 0) { + if (size > bestSize) { + bestSize = size; + best = ptr; + } + ++nonEmptyCount; + } + } + + // If there was at least one non-empty queue but it appears empty at the time + // we try to dequeue from it, we need to make sure every queue's been tried + if (nonEmptyCount > 0) { + if ((details::likely)(best->dequeue(item))) { + return true; + } + for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + if (ptr != best && ptr->dequeue(item)) { + return true; + } + } + } + return false; + } + + // Attempts to dequeue from the queue. + // Returns false if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // This differs from the try_dequeue(item) method in that this one does + // not attempt to reduce contention by interleaving the order that producer + // streams are dequeued from. So, using this method can reduce overall throughput + // under contention, but will give more predictable results in single-threaded + // consumer scenarios. This is mostly only useful for internal unit tests. + // Never allocates. Thread-safe. + template + bool try_dequeue_non_interleaved(U& item) + { + for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + if (ptr->dequeue(item)) { + return true; + } + } + return false; + } + + // Attempts to dequeue from the queue using an explicit consumer token. + // Returns false if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + bool try_dequeue(consumer_token_t& token, U& item) + { + // The idea is roughly as follows: + // Every 256 items from one producer, make everyone rotate (increase the global offset) -> this means the highest efficiency consumer dictates the rotation speed of everyone else, more or less + // If you see that the global offset has changed, you must reset your consumption counter and move to your designated place + // If there's no items where you're supposed to be, keep moving until you find a producer with some items + // If the global offset has not changed but you've run out of items to consume, move over from your current position until you find an producer with something in it + + if (token.desiredProducer == nullptr || token.lastKnownGlobalOffset != globalExplicitConsumerOffset.load(std::memory_order_relaxed)) { + if (!update_current_producer_after_rotation(token)) { + return false; + } + } + + // If there was at least one non-empty queue but it appears empty at the time + // we try to dequeue from it, we need to make sure every queue's been tried + if (static_cast(token.currentProducer)->dequeue(item)) { + if (++token.itemsConsumedFromCurrent == EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE) { + globalExplicitConsumerOffset.fetch_add(1, std::memory_order_relaxed); + } + return true; + } + + auto tail = producerListTail.load(std::memory_order_acquire); + auto ptr = static_cast(token.currentProducer)->next_prod(); + if (ptr == nullptr) { + ptr = tail; + } + while (ptr != static_cast(token.currentProducer)) { + if (ptr->dequeue(item)) { + token.currentProducer = ptr; + token.itemsConsumedFromCurrent = 1; + return true; + } + ptr = ptr->next_prod(); + if (ptr == nullptr) { + ptr = tail; + } + } + return false; + } + + // Attempts to dequeue several elements from the queue. + // Returns the number of items actually dequeued. + // Returns 0 if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + size_t try_dequeue_bulk(It itemFirst, size_t max) + { + size_t count = 0; + for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + count += ptr->dequeue_bulk(itemFirst, max - count); + if (count == max) { + break; + } + } + return count; + } + + // Attempts to dequeue several elements from the queue using an explicit consumer token. + // Returns the number of items actually dequeued. + // Returns 0 if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + size_t try_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max) + { + if (token.desiredProducer == nullptr || token.lastKnownGlobalOffset != globalExplicitConsumerOffset.load(std::memory_order_relaxed)) { + if (!update_current_producer_after_rotation(token)) { + return 0; + } + } + + size_t count = static_cast(token.currentProducer)->dequeue_bulk(itemFirst, max); + if (count == max) { + if ((token.itemsConsumedFromCurrent += static_cast(max)) >= EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE) { + globalExplicitConsumerOffset.fetch_add(1, std::memory_order_relaxed); + } + return max; + } + token.itemsConsumedFromCurrent += static_cast(count); + max -= count; + + auto tail = producerListTail.load(std::memory_order_acquire); + auto ptr = static_cast(token.currentProducer)->next_prod(); + if (ptr == nullptr) { + ptr = tail; + } + while (ptr != static_cast(token.currentProducer)) { + auto dequeued = ptr->dequeue_bulk(itemFirst, max); + count += dequeued; + if (dequeued != 0) { + token.currentProducer = ptr; + token.itemsConsumedFromCurrent = static_cast(dequeued); + } + if (dequeued == max) { + break; + } + max -= dequeued; + ptr = ptr->next_prod(); + if (ptr == nullptr) { + ptr = tail; + } + } + return count; + } + + + + // Attempts to dequeue from a specific producer's inner queue. + // If you happen to know which producer you want to dequeue from, this + // is significantly faster than using the general-case try_dequeue methods. + // Returns false if the producer's queue appeared empty at the time it + // was checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + inline bool try_dequeue_from_producer(producer_token_t const& producer, U& item) + { + return static_cast(producer.producer)->dequeue(item); + } + + // Attempts to dequeue several elements from a specific producer's inner queue. + // Returns the number of items actually dequeued. + // If you happen to know which producer you want to dequeue from, this + // is significantly faster than using the general-case try_dequeue methods. + // Returns 0 if the producer's queue appeared empty at the time it + // was checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + inline size_t try_dequeue_bulk_from_producer(producer_token_t const& producer, It itemFirst, size_t max) + { + return static_cast(producer.producer)->dequeue_bulk(itemFirst, max); + } + + + // Returns an estimate of the total number of elements currently in the queue. This + // estimate is only accurate if the queue has completely stabilized before it is called + // (i.e. all enqueue and dequeue operations have completed and their memory effects are + // visible on the calling thread, and no further operations start while this method is + // being called). + // Thread-safe. + size_t size_approx() const + { + size_t size = 0; + for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + size += ptr->size_approx(); + } + return size; + } + + + // Returns true if the underlying atomic variables used by + // the queue are lock-free (they should be on most platforms). + // Thread-safe. + static constexpr bool is_lock_free() + { + return + details::static_is_lock_free::value == 2 && + details::static_is_lock_free::value == 2 && + details::static_is_lock_free::value == 2 && + details::static_is_lock_free::value == 2 && + details::static_is_lock_free::value == 2 && + details::static_is_lock_free::thread_id_numeric_size_t>::value == 2; + } + + +private: + friend struct ProducerToken; + friend struct ConsumerToken; + struct ExplicitProducer; + friend struct ExplicitProducer; + struct ImplicitProducer; + friend struct ImplicitProducer; + friend class ConcurrentQueueTests; + + enum AllocationMode { CanAlloc, CannotAlloc }; + + + /////////////////////////////// + // Queue methods + /////////////////////////////// + + template + inline bool inner_enqueue(producer_token_t const& token, U&& element) + { + return static_cast(token.producer)->ConcurrentQueue::ExplicitProducer::template enqueue(std::forward(element)); + } + + template + inline bool inner_enqueue(U&& element) + { + auto producer = get_or_add_implicit_producer(); + return producer == nullptr ? false : producer->ConcurrentQueue::ImplicitProducer::template enqueue(std::forward(element)); + } + + template + inline bool inner_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) + { + return static_cast(token.producer)->ConcurrentQueue::ExplicitProducer::template enqueue_bulk(itemFirst, count); + } + + template + inline bool inner_enqueue_bulk(It itemFirst, size_t count) + { + auto producer = get_or_add_implicit_producer(); + return producer == nullptr ? false : producer->ConcurrentQueue::ImplicitProducer::template enqueue_bulk(itemFirst, count); + } + + inline bool update_current_producer_after_rotation(consumer_token_t& token) + { + // Ah, there's been a rotation, figure out where we should be! + auto tail = producerListTail.load(std::memory_order_acquire); + if (token.desiredProducer == nullptr && tail == nullptr) { + return false; + } + auto prodCount = producerCount.load(std::memory_order_relaxed); + auto globalOffset = globalExplicitConsumerOffset.load(std::memory_order_relaxed); + if ((details::unlikely)(token.desiredProducer == nullptr)) { + // Aha, first time we're dequeueing anything. + // Figure out our local position + // Note: offset is from start, not end, but we're traversing from end -- subtract from count first + std::uint32_t offset = prodCount - 1 - (token.initialOffset % prodCount); + token.desiredProducer = tail; + for (std::uint32_t i = 0; i != offset; ++i) { + token.desiredProducer = static_cast(token.desiredProducer)->next_prod(); + if (token.desiredProducer == nullptr) { + token.desiredProducer = tail; + } + } + } + + std::uint32_t delta = globalOffset - token.lastKnownGlobalOffset; + if (delta >= prodCount) { + delta = delta % prodCount; + } + for (std::uint32_t i = 0; i != delta; ++i) { + token.desiredProducer = static_cast(token.desiredProducer)->next_prod(); + if (token.desiredProducer == nullptr) { + token.desiredProducer = tail; + } + } + + token.lastKnownGlobalOffset = globalOffset; + token.currentProducer = token.desiredProducer; + token.itemsConsumedFromCurrent = 0; + return true; + } + + + /////////////////////////// + // Free list + /////////////////////////// + + template + struct FreeListNode + { + FreeListNode() : freeListRefs(0), freeListNext(nullptr) { } + + std::atomic freeListRefs; + std::atomic freeListNext; + }; + + // A simple CAS-based lock-free free list. Not the fastest thing in the world under heavy contention, but + // simple and correct (assuming nodes are never freed until after the free list is destroyed), and fairly + // speedy under low contention. + template // N must inherit FreeListNode or have the same fields (and initialization of them) + struct FreeList + { + FreeList() : freeListHead(nullptr) { } + FreeList(FreeList&& other) : freeListHead(other.freeListHead.load(std::memory_order_relaxed)) { other.freeListHead.store(nullptr, std::memory_order_relaxed); } + void swap(FreeList& other) { details::swap_relaxed(freeListHead, other.freeListHead); } + + FreeList(FreeList const&) MOODYCAMEL_DELETE_FUNCTION; + FreeList& operator=(FreeList const&) MOODYCAMEL_DELETE_FUNCTION; + + inline void add(N* node) + { +#ifdef MCDBGQ_NOLOCKFREE_FREELIST + debug::DebugLock lock(mutex); +#endif + // We know that the should-be-on-freelist bit is 0 at this point, so it's safe to + // set it using a fetch_add + if (node->freeListRefs.fetch_add(SHOULD_BE_ON_FREELIST, std::memory_order_acq_rel) == 0) { + // Oh look! We were the last ones referencing this node, and we know + // we want to add it to the free list, so let's do it! + add_knowing_refcount_is_zero(node); + } + } + + inline N* try_get() + { +#ifdef MCDBGQ_NOLOCKFREE_FREELIST + debug::DebugLock lock(mutex); +#endif + auto head = freeListHead.load(std::memory_order_acquire); + while (head != nullptr) { + auto prevHead = head; + auto refs = head->freeListRefs.load(std::memory_order_relaxed); + if ((refs & REFS_MASK) == 0 || !head->freeListRefs.compare_exchange_strong(refs, refs + 1, std::memory_order_acquire, std::memory_order_relaxed)) { + head = freeListHead.load(std::memory_order_acquire); + continue; + } + + // Good, reference count has been incremented (it wasn't at zero), which means we can read the + // next and not worry about it changing between now and the time we do the CAS + auto next = head->freeListNext.load(std::memory_order_relaxed); + if (freeListHead.compare_exchange_strong(head, next, std::memory_order_acquire, std::memory_order_relaxed)) { + // Yay, got the node. This means it was on the list, which means shouldBeOnFreeList must be false no + // matter the refcount (because nobody else knows it's been taken off yet, it can't have been put back on). + assert((head->freeListRefs.load(std::memory_order_relaxed) & SHOULD_BE_ON_FREELIST) == 0); + + // Decrease refcount twice, once for our ref, and once for the list's ref + head->freeListRefs.fetch_sub(2, std::memory_order_release); + return head; + } + + // OK, the head must have changed on us, but we still need to decrease the refcount we increased. + // Note that we don't need to release any memory effects, but we do need to ensure that the reference + // count decrement happens-after the CAS on the head. + refs = prevHead->freeListRefs.fetch_sub(1, std::memory_order_acq_rel); + if (refs == SHOULD_BE_ON_FREELIST + 1) { + add_knowing_refcount_is_zero(prevHead); + } + } + + return nullptr; + } + + // Useful for traversing the list when there's no contention (e.g. to destroy remaining nodes) + N* head_unsafe() const { return freeListHead.load(std::memory_order_relaxed); } + + private: + inline void add_knowing_refcount_is_zero(N* node) + { + // Since the refcount is zero, and nobody can increase it once it's zero (except us, and we run + // only one copy of this method per node at a time, i.e. the single thread case), then we know + // we can safely change the next pointer of the node; however, once the refcount is back above + // zero, then other threads could increase it (happens under heavy contention, when the refcount + // goes to zero in between a load and a refcount increment of a node in try_get, then back up to + // something non-zero, then the refcount increment is done by the other thread) -- so, if the CAS + // to add the node to the actual list fails, decrease the refcount and leave the add operation to + // the next thread who puts the refcount back at zero (which could be us, hence the loop). + auto head = freeListHead.load(std::memory_order_relaxed); + while (true) { + node->freeListNext.store(head, std::memory_order_relaxed); + node->freeListRefs.store(1, std::memory_order_release); + if (!freeListHead.compare_exchange_strong(head, node, std::memory_order_release, std::memory_order_relaxed)) { + // Hmm, the add failed, but we can only try again when the refcount goes back to zero + if (node->freeListRefs.fetch_add(SHOULD_BE_ON_FREELIST - 1, std::memory_order_release) == 1) { + continue; + } + } + return; + } + } + + private: + // Implemented like a stack, but where node order doesn't matter (nodes are inserted out of order under contention) + std::atomic freeListHead; + + static const std::uint32_t REFS_MASK = 0x7FFFFFFF; + static const std::uint32_t SHOULD_BE_ON_FREELIST = 0x80000000; + +#ifdef MCDBGQ_NOLOCKFREE_FREELIST + debug::DebugMutex mutex; +#endif + }; + + + /////////////////////////// + // Block + /////////////////////////// + + enum InnerQueueContext { implicit_context = 0, explicit_context = 1 }; + + struct Block + { + Block() + : next(nullptr), elementsCompletelyDequeued(0), freeListRefs(0), freeListNext(nullptr), dynamicallyAllocated(true) + { +#ifdef MCDBGQ_TRACKMEM + owner = nullptr; +#endif + } + + template + inline bool is_empty() const + { + MOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { + // Check flags + for (size_t i = 0; i < BLOCK_SIZE; ++i) { + if (!emptyFlags[i].load(std::memory_order_relaxed)) { + return false; + } + } + + // Aha, empty; make sure we have all other memory effects that happened before the empty flags were set + std::atomic_thread_fence(std::memory_order_acquire); + return true; + } + else { + // Check counter + if (elementsCompletelyDequeued.load(std::memory_order_relaxed) == BLOCK_SIZE) { + std::atomic_thread_fence(std::memory_order_acquire); + return true; + } + assert(elementsCompletelyDequeued.load(std::memory_order_relaxed) <= BLOCK_SIZE); + return false; + } + } + + // Returns true if the block is now empty (does not apply in explicit context) + template + inline bool set_empty(MOODYCAMEL_MAYBE_UNUSED index_t i) + { + MOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { + // Set flag + assert(!emptyFlags[BLOCK_SIZE - 1 - static_cast(i & static_cast(BLOCK_SIZE - 1))].load(std::memory_order_relaxed)); + emptyFlags[BLOCK_SIZE - 1 - static_cast(i & static_cast(BLOCK_SIZE - 1))].store(true, std::memory_order_release); + return false; + } + else { + // Increment counter + auto prevVal = elementsCompletelyDequeued.fetch_add(1, std::memory_order_release); + assert(prevVal < BLOCK_SIZE); + return prevVal == BLOCK_SIZE - 1; + } + } + + // Sets multiple contiguous item statuses to 'empty' (assumes no wrapping and count > 0). + // Returns true if the block is now empty (does not apply in explicit context). + template + inline bool set_many_empty(MOODYCAMEL_MAYBE_UNUSED index_t i, size_t count) + { + MOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { + // Set flags + std::atomic_thread_fence(std::memory_order_release); + i = BLOCK_SIZE - 1 - static_cast(i & static_cast(BLOCK_SIZE - 1)) - count + 1; + for (size_t j = 0; j != count; ++j) { + assert(!emptyFlags[i + j].load(std::memory_order_relaxed)); + emptyFlags[i + j].store(true, std::memory_order_relaxed); + } + return false; + } + else { + // Increment counter + auto prevVal = elementsCompletelyDequeued.fetch_add(count, std::memory_order_release); + assert(prevVal + count <= BLOCK_SIZE); + return prevVal + count == BLOCK_SIZE; + } + } + + template + inline void set_all_empty() + { + MOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { + // Set all flags + for (size_t i = 0; i != BLOCK_SIZE; ++i) { + emptyFlags[i].store(true, std::memory_order_relaxed); + } + } + else { + // Reset counter + elementsCompletelyDequeued.store(BLOCK_SIZE, std::memory_order_relaxed); + } + } + + template + inline void reset_empty() + { + MOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { + // Reset flags + for (size_t i = 0; i != BLOCK_SIZE; ++i) { + emptyFlags[i].store(false, std::memory_order_relaxed); + } + } + else { + // Reset counter + elementsCompletelyDequeued.store(0, std::memory_order_relaxed); + } + } + + inline T* operator[](index_t idx) MOODYCAMEL_NOEXCEPT { return static_cast(static_cast(elements)) + static_cast(idx & static_cast(BLOCK_SIZE - 1)); } + inline T const* operator[](index_t idx) const MOODYCAMEL_NOEXCEPT { return static_cast(static_cast(elements)) + static_cast(idx & static_cast(BLOCK_SIZE - 1)); } + + private: + static_assert(std::alignment_of::value <= sizeof(T), "The queue does not support types with an alignment greater than their size at this time"); + MOODYCAMEL_ALIGNED_TYPE_LIKE(char[sizeof(T) * BLOCK_SIZE], T) elements; + public: + Block* next; + std::atomic elementsCompletelyDequeued; + std::atomic emptyFlags[BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD ? BLOCK_SIZE : 1]; + public: + std::atomic freeListRefs; + std::atomic freeListNext; + bool dynamicallyAllocated; // Perhaps a better name for this would be 'isNotPartOfInitialBlockPool' + +#ifdef MCDBGQ_TRACKMEM + void* owner; +#endif + }; + static_assert(std::alignment_of::value >= std::alignment_of::value, "Internal error: Blocks must be at least as aligned as the type they are wrapping"); + + +#ifdef MCDBGQ_TRACKMEM +public: + struct MemStats; +private: +#endif + + /////////////////////////// + // Producer base + /////////////////////////// + + struct ProducerBase : public details::ConcurrentQueueProducerTypelessBase + { + ProducerBase(ConcurrentQueue* parent_, bool isExplicit_) : + tailIndex(0), + headIndex(0), + dequeueOptimisticCount(0), + dequeueOvercommit(0), + tailBlock(nullptr), + isExplicit(isExplicit_), + parent(parent_) + { + } + + virtual ~ProducerBase() { } + + template + inline bool dequeue(U& element) + { + if (isExplicit) { + return static_cast(this)->dequeue(element); + } + else { + return static_cast(this)->dequeue(element); + } + } + + template + inline size_t dequeue_bulk(It& itemFirst, size_t max) + { + if (isExplicit) { + return static_cast(this)->dequeue_bulk(itemFirst, max); + } + else { + return static_cast(this)->dequeue_bulk(itemFirst, max); + } + } + + inline ProducerBase* next_prod() const { return static_cast(next); } + + inline size_t size_approx() const + { + auto tail = tailIndex.load(std::memory_order_relaxed); + auto head = headIndex.load(std::memory_order_relaxed); + return details::circular_less_than(head, tail) ? static_cast(tail - head) : 0; + } + + inline index_t getTail() const { return tailIndex.load(std::memory_order_relaxed); } + protected: + std::atomic tailIndex; // Where to enqueue to next + std::atomic headIndex; // Where to dequeue from next + + std::atomic dequeueOptimisticCount; + std::atomic dequeueOvercommit; + + Block* tailBlock; + + public: + bool isExplicit; + ConcurrentQueue* parent; + + protected: +#ifdef MCDBGQ_TRACKMEM + friend struct MemStats; +#endif + }; + + + /////////////////////////// + // Explicit queue + /////////////////////////// + + struct ExplicitProducer : public ProducerBase + { + explicit ExplicitProducer(ConcurrentQueue* parent_) : + ProducerBase(parent_, true), + blockIndex(nullptr), + pr_blockIndexSlotsUsed(0), + pr_blockIndexSize(EXPLICIT_INITIAL_INDEX_SIZE >> 1), + pr_blockIndexFront(0), + pr_blockIndexEntries(nullptr), + pr_blockIndexRaw(nullptr) + { + size_t poolBasedIndexSize = details::ceil_to_pow_2(parent_->initialBlockPoolSize) >> 1; + if (poolBasedIndexSize > pr_blockIndexSize) { + pr_blockIndexSize = poolBasedIndexSize; + } + + new_block_index(0); // This creates an index with double the number of current entries, i.e. EXPLICIT_INITIAL_INDEX_SIZE + } + + ~ExplicitProducer() + { + // Destruct any elements not yet dequeued. + // Since we're in the destructor, we can assume all elements + // are either completely dequeued or completely not (no halfways). + if (this->tailBlock != nullptr) { // Note this means there must be a block index too + // First find the block that's partially dequeued, if any + Block* halfDequeuedBlock = nullptr; + if ((this->headIndex.load(std::memory_order_relaxed) & static_cast(BLOCK_SIZE - 1)) != 0) { + // The head's not on a block boundary, meaning a block somewhere is partially dequeued + // (or the head block is the tail block and was fully dequeued, but the head/tail are still not on a boundary) + size_t i = (pr_blockIndexFront - pr_blockIndexSlotsUsed) & (pr_blockIndexSize - 1); + while (details::circular_less_than(pr_blockIndexEntries[i].base + BLOCK_SIZE, this->headIndex.load(std::memory_order_relaxed))) { + i = (i + 1) & (pr_blockIndexSize - 1); + } + assert(details::circular_less_than(pr_blockIndexEntries[i].base, this->headIndex.load(std::memory_order_relaxed))); + halfDequeuedBlock = pr_blockIndexEntries[i].block; + } + + // Start at the head block (note the first line in the loop gives us the head from the tail on the first iteration) + auto block = this->tailBlock; + do { + block = block->next; + if (block->ConcurrentQueue::Block::template is_empty()) { + continue; + } + + size_t i = 0; // Offset into block + if (block == halfDequeuedBlock) { + i = static_cast(this->headIndex.load(std::memory_order_relaxed) & static_cast(BLOCK_SIZE - 1)); + } + + // Walk through all the items in the block; if this is the tail block, we need to stop when we reach the tail index + auto lastValidIndex = (this->tailIndex.load(std::memory_order_relaxed) & static_cast(BLOCK_SIZE - 1)) == 0 ? BLOCK_SIZE : static_cast(this->tailIndex.load(std::memory_order_relaxed) & static_cast(BLOCK_SIZE - 1)); + while (i != BLOCK_SIZE && (block != this->tailBlock || i != lastValidIndex)) { + (*block)[i++]->~T(); + } + } while (block != this->tailBlock); + } + + // Destroy all blocks that we own + if (this->tailBlock != nullptr) { + auto block = this->tailBlock; + do { + auto nextBlock = block->next; + this->parent->add_block_to_free_list(block); + block = nextBlock; + } while (block != this->tailBlock); + } + + // Destroy the block indices + auto header = static_cast(pr_blockIndexRaw); + while (header != nullptr) { + auto prev = static_cast(header->prev); + header->~BlockIndexHeader(); + (Traits::free)(header); + header = prev; + } + } + + template + inline bool enqueue(U&& element) + { + index_t currentTailIndex = this->tailIndex.load(std::memory_order_relaxed); + index_t newTailIndex = 1 + currentTailIndex; + if ((currentTailIndex & static_cast(BLOCK_SIZE - 1)) == 0) { + // We reached the end of a block, start a new one + auto startBlock = this->tailBlock; + auto originalBlockIndexSlotsUsed = pr_blockIndexSlotsUsed; + if (this->tailBlock != nullptr && this->tailBlock->next->ConcurrentQueue::Block::template is_empty()) { + // We can re-use the block ahead of us, it's empty! + this->tailBlock = this->tailBlock->next; + this->tailBlock->ConcurrentQueue::Block::template reset_empty(); + + // We'll put the block on the block index (guaranteed to be room since we're conceptually removing the + // last block from it first -- except instead of removing then adding, we can just overwrite). + // Note that there must be a valid block index here, since even if allocation failed in the ctor, + // it would have been re-attempted when adding the first block to the queue; since there is such + // a block, a block index must have been successfully allocated. + } + else { + // Whatever head value we see here is >= the last value we saw here (relatively), + // and <= its current value. Since we have the most recent tail, the head must be + // <= to it. + auto head = this->headIndex.load(std::memory_order_relaxed); + assert(!details::circular_less_than(currentTailIndex, head)); + if (!details::circular_less_than(head, currentTailIndex + BLOCK_SIZE) + || (MAX_SUBQUEUE_SIZE != details::const_numeric_max::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head))) { + // We can't enqueue in another block because there's not enough leeway -- the + // tail could surpass the head by the time the block fills up! (Or we'll exceed + // the size limit, if the second part of the condition was true.) + return false; + } + // We're going to need a new block; check that the block index has room + if (pr_blockIndexRaw == nullptr || pr_blockIndexSlotsUsed == pr_blockIndexSize) { + // Hmm, the circular block index is already full -- we'll need + // to allocate a new index. Note pr_blockIndexRaw can only be nullptr if + // the initial allocation failed in the constructor. + + MOODYCAMEL_CONSTEXPR_IF (allocMode == CannotAlloc) { + return false; + } + else if (!new_block_index(pr_blockIndexSlotsUsed)) { + return false; + } + } + + // Insert a new block in the circular linked list + auto newBlock = this->parent->ConcurrentQueue::template requisition_block(); + if (newBlock == nullptr) { + return false; + } +#ifdef MCDBGQ_TRACKMEM + newBlock->owner = this; +#endif + newBlock->ConcurrentQueue::Block::template reset_empty(); + if (this->tailBlock == nullptr) { + newBlock->next = newBlock; + } + else { + newBlock->next = this->tailBlock->next; + this->tailBlock->next = newBlock; + } + this->tailBlock = newBlock; + ++pr_blockIndexSlotsUsed; + } + + MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (static_cast(nullptr)) T(std::forward(element)))) { + // The constructor may throw. We want the element not to appear in the queue in + // that case (without corrupting the queue): + MOODYCAMEL_TRY { + new ((*this->tailBlock)[currentTailIndex]) T(std::forward(element)); + } + MOODYCAMEL_CATCH (...) { + // Revert change to the current block, but leave the new block available + // for next time + pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; + this->tailBlock = startBlock == nullptr ? this->tailBlock : startBlock; + MOODYCAMEL_RETHROW; + } + } + else { + (void)startBlock; + (void)originalBlockIndexSlotsUsed; + } + + // Add block to block index + auto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront]; + entry.base = currentTailIndex; + entry.block = this->tailBlock; + blockIndex.load(std::memory_order_relaxed)->front.store(pr_blockIndexFront, std::memory_order_release); + pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1); + + MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (static_cast(nullptr)) T(std::forward(element)))) { + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } + } + + // Enqueue + new ((*this->tailBlock)[currentTailIndex]) T(std::forward(element)); + + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } + + template + bool dequeue(U& element) + { + auto tail = this->tailIndex.load(std::memory_order_relaxed); + auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); + if (details::circular_less_than(this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit, tail)) { + // Might be something to dequeue, let's give it a try + + // Note that this if is purely for performance purposes in the common case when the queue is + // empty and the values are eventually consistent -- we may enter here spuriously. + + // Note that whatever the values of overcommit and tail are, they are not going to change (unless we + // change them) and must be the same value at this point (inside the if) as when the if condition was + // evaluated. + + // We insert an acquire fence here to synchronize-with the release upon incrementing dequeueOvercommit below. + // This ensures that whatever the value we got loaded into overcommit, the load of dequeueOptisticCount in + // the fetch_add below will result in a value at least as recent as that (and therefore at least as large). + // Note that I believe a compiler (signal) fence here would be sufficient due to the nature of fetch_add (all + // read-modify-write operations are guaranteed to work on the latest value in the modification order), but + // unfortunately that can't be shown to be correct using only the C++11 standard. + // See http://stackoverflow.com/questions/18223161/what-are-the-c11-memory-ordering-guarantees-in-this-corner-case + std::atomic_thread_fence(std::memory_order_acquire); + + // Increment optimistic counter, then check if it went over the boundary + auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(1, std::memory_order_relaxed); + + // Note that since dequeueOvercommit must be <= dequeueOptimisticCount (because dequeueOvercommit is only ever + // incremented after dequeueOptimisticCount -- this is enforced in the `else` block below), and since we now + // have a version of dequeueOptimisticCount that is at least as recent as overcommit (due to the release upon + // incrementing dequeueOvercommit and the acquire above that synchronizes with it), overcommit <= myDequeueCount. + // However, we can't assert this since both dequeueOptimisticCount and dequeueOvercommit may (independently) + // overflow; in such a case, though, the logic still holds since the difference between the two is maintained. + + // Note that we reload tail here in case it changed; it will be the same value as before or greater, since + // this load is sequenced after (happens after) the earlier load above. This is supported by read-read + // coherency (as defined in the standard), explained here: http://en.cppreference.com/w/cpp/atomic/memory_order + tail = this->tailIndex.load(std::memory_order_acquire); + if ((details::likely)(details::circular_less_than(myDequeueCount - overcommit, tail))) { + // Guaranteed to be at least one element to dequeue! + + // Get the index. Note that since there's guaranteed to be at least one element, this + // will never exceed tail. We need to do an acquire-release fence here since it's possible + // that whatever condition got us to this point was for an earlier enqueued element (that + // we already see the memory effects for), but that by the time we increment somebody else + // has incremented it, and we need to see the memory effects for *that* element, which is + // in such a case is necessarily visible on the thread that incremented it in the first + // place with the more current condition (they must have acquired a tail that is at least + // as recent). + auto index = this->headIndex.fetch_add(1, std::memory_order_acq_rel); + + + // Determine which block the element is in + + auto localBlockIndex = blockIndex.load(std::memory_order_acquire); + auto localBlockIndexHead = localBlockIndex->front.load(std::memory_order_acquire); + + // We need to be careful here about subtracting and dividing because of index wrap-around. + // When an index wraps, we need to preserve the sign of the offset when dividing it by the + // block size (in order to get a correct signed block count offset in all cases): + auto headBase = localBlockIndex->entries[localBlockIndexHead].base; + auto blockBaseIndex = index & ~static_cast(BLOCK_SIZE - 1); + auto offset = static_cast(static_cast::type>(blockBaseIndex - headBase) / static_cast::type>(BLOCK_SIZE)); + auto block = localBlockIndex->entries[(localBlockIndexHead + offset) & (localBlockIndex->size - 1)].block; + + // Dequeue + auto& el = *((*block)[index]); + if (!MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, element = std::move(el))) { + // Make sure the element is still fully dequeued and destroyed even if the assignment + // throws + struct Guard { + Block* block; + index_t index; + + ~Guard() + { + (*block)[index]->~T(); + block->ConcurrentQueue::Block::template set_empty(index); + } + } guard = { block, index }; + + element = std::move(el); // NOLINT + } + else { + element = std::move(el); // NOLINT + el.~T(); // NOLINT + block->ConcurrentQueue::Block::template set_empty(index); + } + + return true; + } + else { + // Wasn't anything to dequeue after all; make the effective dequeue count eventually consistent + this->dequeueOvercommit.fetch_add(1, std::memory_order_release); // Release so that the fetch_add on dequeueOptimisticCount is guaranteed to happen before this write + } + } + + return false; + } + + template + bool MOODYCAMEL_NO_TSAN enqueue_bulk(It itemFirst, size_t count) + { + // First, we need to make sure we have enough room to enqueue all of the elements; + // this means pre-allocating blocks and putting them in the block index (but only if + // all the allocations succeeded). + index_t startTailIndex = this->tailIndex.load(std::memory_order_relaxed); + auto startBlock = this->tailBlock; + auto originalBlockIndexFront = pr_blockIndexFront; + auto originalBlockIndexSlotsUsed = pr_blockIndexSlotsUsed; + + Block* firstAllocatedBlock = nullptr; + + // Figure out how many blocks we'll need to allocate, and do so + size_t blockBaseDiff = ((startTailIndex + count - 1) & ~static_cast(BLOCK_SIZE - 1)) - ((startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1)); + index_t currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); + if (blockBaseDiff > 0) { + // Allocate as many blocks as possible from ahead + while (blockBaseDiff > 0 && this->tailBlock != nullptr && this->tailBlock->next != firstAllocatedBlock && this->tailBlock->next->ConcurrentQueue::Block::template is_empty()) { + blockBaseDiff -= static_cast(BLOCK_SIZE); + currentTailIndex += static_cast(BLOCK_SIZE); + + this->tailBlock = this->tailBlock->next; + firstAllocatedBlock = firstAllocatedBlock == nullptr ? this->tailBlock : firstAllocatedBlock; + + auto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront]; + entry.base = currentTailIndex; + entry.block = this->tailBlock; + pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1); + } + + // Now allocate as many blocks as necessary from the block pool + while (blockBaseDiff > 0) { + blockBaseDiff -= static_cast(BLOCK_SIZE); + currentTailIndex += static_cast(BLOCK_SIZE); + + auto head = this->headIndex.load(std::memory_order_relaxed); + assert(!details::circular_less_than(currentTailIndex, head)); + bool full = !details::circular_less_than(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head)); + if (pr_blockIndexRaw == nullptr || pr_blockIndexSlotsUsed == pr_blockIndexSize || full) { + MOODYCAMEL_CONSTEXPR_IF (allocMode == CannotAlloc) { + // Failed to allocate, undo changes (but keep injected blocks) + pr_blockIndexFront = originalBlockIndexFront; + pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; + this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock; + return false; + } + else if (full || !new_block_index(originalBlockIndexSlotsUsed)) { + // Failed to allocate, undo changes (but keep injected blocks) + pr_blockIndexFront = originalBlockIndexFront; + pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; + this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock; + return false; + } + + // pr_blockIndexFront is updated inside new_block_index, so we need to + // update our fallback value too (since we keep the new index even if we + // later fail) + originalBlockIndexFront = originalBlockIndexSlotsUsed; + } + + // Insert a new block in the circular linked list + auto newBlock = this->parent->ConcurrentQueue::template requisition_block(); + if (newBlock == nullptr) { + pr_blockIndexFront = originalBlockIndexFront; + pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; + this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock; + return false; + } + +#ifdef MCDBGQ_TRACKMEM + newBlock->owner = this; +#endif + newBlock->ConcurrentQueue::Block::template set_all_empty(); + if (this->tailBlock == nullptr) { + newBlock->next = newBlock; + } + else { + newBlock->next = this->tailBlock->next; + this->tailBlock->next = newBlock; + } + this->tailBlock = newBlock; + firstAllocatedBlock = firstAllocatedBlock == nullptr ? this->tailBlock : firstAllocatedBlock; + + ++pr_blockIndexSlotsUsed; + + auto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront]; + entry.base = currentTailIndex; + entry.block = this->tailBlock; + pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1); + } + + // Excellent, all allocations succeeded. Reset each block's emptiness before we fill them up, and + // publish the new block index front + auto block = firstAllocatedBlock; + while (true) { + block->ConcurrentQueue::Block::template reset_empty(); + if (block == this->tailBlock) { + break; + } + block = block->next; + } + + MOODYCAMEL_CONSTEXPR_IF (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast(nullptr)) T(details::deref_noexcept(itemFirst)))) { + blockIndex.load(std::memory_order_relaxed)->front.store((pr_blockIndexFront - 1) & (pr_blockIndexSize - 1), std::memory_order_release); + } + } + + // Enqueue, one block at a time + index_t newTailIndex = startTailIndex + static_cast(count); + currentTailIndex = startTailIndex; + auto endBlock = this->tailBlock; + this->tailBlock = startBlock; + assert((startTailIndex & static_cast(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr || count == 0); + if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) == 0 && firstAllocatedBlock != nullptr) { + this->tailBlock = firstAllocatedBlock; + } + while (true) { + index_t stopIndex = (currentTailIndex & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + if (details::circular_less_than(newTailIndex, stopIndex)) { + stopIndex = newTailIndex; + } + MOODYCAMEL_CONSTEXPR_IF (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast(nullptr)) T(details::deref_noexcept(itemFirst)))) { + while (currentTailIndex != stopIndex) { + new ((*this->tailBlock)[currentTailIndex++]) T(*itemFirst++); + } + } + else { + MOODYCAMEL_TRY { + while (currentTailIndex != stopIndex) { + // Must use copy constructor even if move constructor is available + // because we may have to revert if there's an exception. + // Sorry about the horrible templated next line, but it was the only way + // to disable moving *at compile time*, which is important because a type + // may only define a (noexcept) move constructor, and so calls to the + // cctor will not compile, even if they are in an if branch that will never + // be executed + new ((*this->tailBlock)[currentTailIndex]) T(details::nomove_if(nullptr)) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst)); + ++currentTailIndex; + ++itemFirst; + } + } + MOODYCAMEL_CATCH (...) { + // Oh dear, an exception's been thrown -- destroy the elements that + // were enqueued so far and revert the entire bulk operation (we'll keep + // any allocated blocks in our linked list for later, though). + auto constructedStopIndex = currentTailIndex; + auto lastBlockEnqueued = this->tailBlock; + + pr_blockIndexFront = originalBlockIndexFront; + pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; + this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock; + + if (!details::is_trivially_destructible::value) { + auto block = startBlock; + if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) == 0) { + block = firstAllocatedBlock; + } + currentTailIndex = startTailIndex; + while (true) { + stopIndex = (currentTailIndex & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + if (details::circular_less_than(constructedStopIndex, stopIndex)) { + stopIndex = constructedStopIndex; + } + while (currentTailIndex != stopIndex) { + (*block)[currentTailIndex++]->~T(); + } + if (block == lastBlockEnqueued) { + break; + } + block = block->next; + } + } + MOODYCAMEL_RETHROW; + } + } + + if (this->tailBlock == endBlock) { + assert(currentTailIndex == newTailIndex); + break; + } + this->tailBlock = this->tailBlock->next; + } + + MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast(nullptr)) T(details::deref_noexcept(itemFirst)))) { + if (firstAllocatedBlock != nullptr) + blockIndex.load(std::memory_order_relaxed)->front.store((pr_blockIndexFront - 1) & (pr_blockIndexSize - 1), std::memory_order_release); + } + + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } + + template + size_t dequeue_bulk(It& itemFirst, size_t max) + { + auto tail = this->tailIndex.load(std::memory_order_relaxed); + auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); + auto desiredCount = static_cast(tail - (this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit)); + if (details::circular_less_than(0, desiredCount)) { + desiredCount = desiredCount < max ? desiredCount : max; + std::atomic_thread_fence(std::memory_order_acquire); + + auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, std::memory_order_relaxed); + + tail = this->tailIndex.load(std::memory_order_acquire); + auto actualCount = static_cast(tail - (myDequeueCount - overcommit)); + if (details::circular_less_than(0, actualCount)) { + actualCount = desiredCount < actualCount ? desiredCount : actualCount; + if (actualCount < desiredCount) { + this->dequeueOvercommit.fetch_add(desiredCount - actualCount, std::memory_order_release); + } + + // Get the first index. Note that since there's guaranteed to be at least actualCount elements, this + // will never exceed tail. + auto firstIndex = this->headIndex.fetch_add(actualCount, std::memory_order_acq_rel); + + // Determine which block the first element is in + auto localBlockIndex = blockIndex.load(std::memory_order_acquire); + auto localBlockIndexHead = localBlockIndex->front.load(std::memory_order_acquire); + + auto headBase = localBlockIndex->entries[localBlockIndexHead].base; + auto firstBlockBaseIndex = firstIndex & ~static_cast(BLOCK_SIZE - 1); + auto offset = static_cast(static_cast::type>(firstBlockBaseIndex - headBase) / static_cast::type>(BLOCK_SIZE)); + auto indexIndex = (localBlockIndexHead + offset) & (localBlockIndex->size - 1); + + // Iterate the blocks and dequeue + auto index = firstIndex; + do { + auto firstIndexInBlock = index; + index_t endIndex = (index & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + endIndex = details::circular_less_than(firstIndex + static_cast(actualCount), endIndex) ? firstIndex + static_cast(actualCount) : endIndex; + auto block = localBlockIndex->entries[indexIndex].block; + if (MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, details::deref_noexcept(itemFirst) = std::move((*(*block)[index])))) { + while (index != endIndex) { + auto& el = *((*block)[index]); + *itemFirst++ = std::move(el); + el.~T(); + ++index; + } + } + else { + MOODYCAMEL_TRY { + while (index != endIndex) { + auto& el = *((*block)[index]); + *itemFirst = std::move(el); + ++itemFirst; + el.~T(); + ++index; + } + } + MOODYCAMEL_CATCH (...) { + // It's too late to revert the dequeue, but we can make sure that all + // the dequeued objects are properly destroyed and the block index + // (and empty count) are properly updated before we propagate the exception + do { + block = localBlockIndex->entries[indexIndex].block; + while (index != endIndex) { + (*block)[index++]->~T(); + } + block->ConcurrentQueue::Block::template set_many_empty(firstIndexInBlock, static_cast(endIndex - firstIndexInBlock)); + indexIndex = (indexIndex + 1) & (localBlockIndex->size - 1); + + firstIndexInBlock = index; + endIndex = (index & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + endIndex = details::circular_less_than(firstIndex + static_cast(actualCount), endIndex) ? firstIndex + static_cast(actualCount) : endIndex; + } while (index != firstIndex + actualCount); + + MOODYCAMEL_RETHROW; + } + } + block->ConcurrentQueue::Block::template set_many_empty(firstIndexInBlock, static_cast(endIndex - firstIndexInBlock)); + indexIndex = (indexIndex + 1) & (localBlockIndex->size - 1); + } while (index != firstIndex + actualCount); + + return actualCount; + } + else { + // Wasn't anything to dequeue after all; make the effective dequeue count eventually consistent + this->dequeueOvercommit.fetch_add(desiredCount, std::memory_order_release); + } + } + + return 0; + } + + private: + struct BlockIndexEntry + { + index_t base; + Block* block; + }; + + struct BlockIndexHeader + { + size_t size; + std::atomic front; // Current slot (not next, like pr_blockIndexFront) + BlockIndexEntry* entries; + void* prev; + }; + + + bool new_block_index(size_t numberOfFilledSlotsToExpose) + { + auto prevBlockSizeMask = pr_blockIndexSize - 1; + + // Create the new block + pr_blockIndexSize <<= 1; + auto newRawPtr = static_cast((Traits::malloc)(sizeof(BlockIndexHeader) + std::alignment_of::value - 1 + sizeof(BlockIndexEntry) * pr_blockIndexSize)); + if (newRawPtr == nullptr) { + pr_blockIndexSize >>= 1; // Reset to allow graceful retry + return false; + } + + auto newBlockIndexEntries = reinterpret_cast(details::align_for(newRawPtr + sizeof(BlockIndexHeader))); + + // Copy in all the old indices, if any + size_t j = 0; + if (pr_blockIndexSlotsUsed != 0) { + auto i = (pr_blockIndexFront - pr_blockIndexSlotsUsed) & prevBlockSizeMask; + do { + newBlockIndexEntries[j++] = pr_blockIndexEntries[i]; + i = (i + 1) & prevBlockSizeMask; + } while (i != pr_blockIndexFront); + } + + // Update everything + auto header = new (newRawPtr) BlockIndexHeader; + header->size = pr_blockIndexSize; + header->front.store(numberOfFilledSlotsToExpose - 1, std::memory_order_relaxed); + header->entries = newBlockIndexEntries; + header->prev = pr_blockIndexRaw; // we link the new block to the old one so we can free it later + + pr_blockIndexFront = j; + pr_blockIndexEntries = newBlockIndexEntries; + pr_blockIndexRaw = newRawPtr; + blockIndex.store(header, std::memory_order_release); + + return true; + } + + private: + std::atomic blockIndex; + + // To be used by producer only -- consumer must use the ones in referenced by blockIndex + size_t pr_blockIndexSlotsUsed; + size_t pr_blockIndexSize; + size_t pr_blockIndexFront; // Next slot (not current) + BlockIndexEntry* pr_blockIndexEntries; + void* pr_blockIndexRaw; + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + public: + ExplicitProducer* nextExplicitProducer; + private: +#endif + +#ifdef MCDBGQ_TRACKMEM + friend struct MemStats; +#endif + }; + + + ////////////////////////////////// + // Implicit queue + ////////////////////////////////// + + struct ImplicitProducer : public ProducerBase + { + ImplicitProducer(ConcurrentQueue* parent_) : + ProducerBase(parent_, false), + nextBlockIndexCapacity(IMPLICIT_INITIAL_INDEX_SIZE), + blockIndex(nullptr) + { + new_block_index(); + } + + ~ImplicitProducer() + { + // Note that since we're in the destructor we can assume that all enqueue/dequeue operations + // completed already; this means that all undequeued elements are placed contiguously across + // contiguous blocks, and that only the first and last remaining blocks can be only partially + // empty (all other remaining blocks must be completely full). + +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED + // Unregister ourselves for thread termination notification + if (!this->inactive.load(std::memory_order_relaxed)) { + details::ThreadExitNotifier::unsubscribe(&threadExitListener); + } +#endif + + // Destroy all remaining elements! + auto tail = this->tailIndex.load(std::memory_order_relaxed); + auto index = this->headIndex.load(std::memory_order_relaxed); + Block* block = nullptr; + assert(index == tail || details::circular_less_than(index, tail)); + bool forceFreeLastBlock = index != tail; // If we enter the loop, then the last (tail) block will not be freed + while (index != tail) { + if ((index & static_cast(BLOCK_SIZE - 1)) == 0 || block == nullptr) { + if (block != nullptr) { + // Free the old block + this->parent->add_block_to_free_list(block); + } + + block = get_block_index_entry_for_index(index)->value.load(std::memory_order_relaxed); + } + + ((*block)[index])->~T(); + ++index; + } + // Even if the queue is empty, there's still one block that's not on the free list + // (unless the head index reached the end of it, in which case the tail will be poised + // to create a new block). + if (this->tailBlock != nullptr && (forceFreeLastBlock || (tail & static_cast(BLOCK_SIZE - 1)) != 0)) { + this->parent->add_block_to_free_list(this->tailBlock); + } + + // Destroy block index + auto localBlockIndex = blockIndex.load(std::memory_order_relaxed); + if (localBlockIndex != nullptr) { + for (size_t i = 0; i != localBlockIndex->capacity; ++i) { + localBlockIndex->index[i]->~BlockIndexEntry(); + } + do { + auto prev = localBlockIndex->prev; + localBlockIndex->~BlockIndexHeader(); + (Traits::free)(localBlockIndex); + localBlockIndex = prev; + } while (localBlockIndex != nullptr); + } + } + + template + inline bool enqueue(U&& element) + { + index_t currentTailIndex = this->tailIndex.load(std::memory_order_relaxed); + index_t newTailIndex = 1 + currentTailIndex; + if ((currentTailIndex & static_cast(BLOCK_SIZE - 1)) == 0) { + // We reached the end of a block, start a new one + auto head = this->headIndex.load(std::memory_order_relaxed); + assert(!details::circular_less_than(currentTailIndex, head)); + if (!details::circular_less_than(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head))) { + return false; + } +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + // Find out where we'll be inserting this block in the block index + BlockIndexEntry* idxEntry; + if (!insert_block_index_entry(idxEntry, currentTailIndex)) { + return false; + } + + // Get ahold of a new block + auto newBlock = this->parent->ConcurrentQueue::template requisition_block(); + if (newBlock == nullptr) { + rewind_block_index_tail(); + idxEntry->value.store(nullptr, std::memory_order_relaxed); + return false; + } +#ifdef MCDBGQ_TRACKMEM + newBlock->owner = this; +#endif + newBlock->ConcurrentQueue::Block::template reset_empty(); + + MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (static_cast(nullptr)) T(std::forward(element)))) { + // May throw, try to insert now before we publish the fact that we have this new block + MOODYCAMEL_TRY { + new ((*newBlock)[currentTailIndex]) T(std::forward(element)); + } + MOODYCAMEL_CATCH (...) { + rewind_block_index_tail(); + idxEntry->value.store(nullptr, std::memory_order_relaxed); + this->parent->add_block_to_free_list(newBlock); + MOODYCAMEL_RETHROW; + } + } + + // Insert the new block into the index + idxEntry->value.store(newBlock, std::memory_order_relaxed); + + this->tailBlock = newBlock; + + MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (static_cast(nullptr)) T(std::forward(element)))) { + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } + } + + // Enqueue + new ((*this->tailBlock)[currentTailIndex]) T(std::forward(element)); + + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } + + template + bool dequeue(U& element) + { + // See ExplicitProducer::dequeue for rationale and explanation + index_t tail = this->tailIndex.load(std::memory_order_relaxed); + index_t overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); + if (details::circular_less_than(this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit, tail)) { + std::atomic_thread_fence(std::memory_order_acquire); + + index_t myDequeueCount = this->dequeueOptimisticCount.fetch_add(1, std::memory_order_relaxed); + tail = this->tailIndex.load(std::memory_order_acquire); + if ((details::likely)(details::circular_less_than(myDequeueCount - overcommit, tail))) { + index_t index = this->headIndex.fetch_add(1, std::memory_order_acq_rel); + + // Determine which block the element is in + auto entry = get_block_index_entry_for_index(index); + + // Dequeue + auto block = entry->value.load(std::memory_order_relaxed); + auto& el = *((*block)[index]); + + if (!MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, element = std::move(el))) { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + // Note: Acquiring the mutex with every dequeue instead of only when a block + // is released is very sub-optimal, but it is, after all, purely debug code. + debug::DebugLock lock(producer->mutex); +#endif + struct Guard { + Block* block; + index_t index; + BlockIndexEntry* entry; + ConcurrentQueue* parent; + + ~Guard() + { + (*block)[index]->~T(); + if (block->ConcurrentQueue::Block::template set_empty(index)) { + entry->value.store(nullptr, std::memory_order_relaxed); + parent->add_block_to_free_list(block); + } + } + } guard = { block, index, entry, this->parent }; + + element = std::move(el); // NOLINT + } + else { + element = std::move(el); // NOLINT + el.~T(); // NOLINT + + if (block->ConcurrentQueue::Block::template set_empty(index)) { + { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + // Add the block back into the global free pool (and remove from block index) + entry->value.store(nullptr, std::memory_order_relaxed); + } + this->parent->add_block_to_free_list(block); // releases the above store + } + } + + return true; + } + else { + this->dequeueOvercommit.fetch_add(1, std::memory_order_release); + } + } + + return false; + } + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4706) // assignment within conditional expression +#endif + template + bool enqueue_bulk(It itemFirst, size_t count) + { + // First, we need to make sure we have enough room to enqueue all of the elements; + // this means pre-allocating blocks and putting them in the block index (but only if + // all the allocations succeeded). + + // Note that the tailBlock we start off with may not be owned by us any more; + // this happens if it was filled up exactly to the top (setting tailIndex to + // the first index of the next block which is not yet allocated), then dequeued + // completely (putting it on the free list) before we enqueue again. + + index_t startTailIndex = this->tailIndex.load(std::memory_order_relaxed); + auto startBlock = this->tailBlock; + Block* firstAllocatedBlock = nullptr; + auto endBlock = this->tailBlock; + + // Figure out how many blocks we'll need to allocate, and do so + size_t blockBaseDiff = ((startTailIndex + count - 1) & ~static_cast(BLOCK_SIZE - 1)) - ((startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1)); + index_t currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); + if (blockBaseDiff > 0) { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + do { + blockBaseDiff -= static_cast(BLOCK_SIZE); + currentTailIndex += static_cast(BLOCK_SIZE); + + // Find out where we'll be inserting this block in the block index + BlockIndexEntry* idxEntry = nullptr; // initialization here unnecessary but compiler can't always tell + Block* newBlock; + bool indexInserted = false; + auto head = this->headIndex.load(std::memory_order_relaxed); + assert(!details::circular_less_than(currentTailIndex, head)); + bool full = !details::circular_less_than(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head)); + + if (full || !(indexInserted = insert_block_index_entry(idxEntry, currentTailIndex)) || (newBlock = this->parent->ConcurrentQueue::template requisition_block()) == nullptr) { + // Index allocation or block allocation failed; revert any other allocations + // and index insertions done so far for this operation + if (indexInserted) { + rewind_block_index_tail(); + idxEntry->value.store(nullptr, std::memory_order_relaxed); + } + currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); + for (auto block = firstAllocatedBlock; block != nullptr; block = block->next) { + currentTailIndex += static_cast(BLOCK_SIZE); + idxEntry = get_block_index_entry_for_index(currentTailIndex); + idxEntry->value.store(nullptr, std::memory_order_relaxed); + rewind_block_index_tail(); + } + this->parent->add_blocks_to_free_list(firstAllocatedBlock); + this->tailBlock = startBlock; + + return false; + } + +#ifdef MCDBGQ_TRACKMEM + newBlock->owner = this; +#endif + newBlock->ConcurrentQueue::Block::template reset_empty(); + newBlock->next = nullptr; + + // Insert the new block into the index + idxEntry->value.store(newBlock, std::memory_order_relaxed); + + // Store the chain of blocks so that we can undo if later allocations fail, + // and so that we can find the blocks when we do the actual enqueueing + if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr) { + assert(this->tailBlock != nullptr); + this->tailBlock->next = newBlock; + } + this->tailBlock = newBlock; + endBlock = newBlock; + firstAllocatedBlock = firstAllocatedBlock == nullptr ? newBlock : firstAllocatedBlock; + } while (blockBaseDiff > 0); + } + + // Enqueue, one block at a time + index_t newTailIndex = startTailIndex + static_cast(count); + currentTailIndex = startTailIndex; + this->tailBlock = startBlock; + assert((startTailIndex & static_cast(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr || count == 0); + if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) == 0 && firstAllocatedBlock != nullptr) { + this->tailBlock = firstAllocatedBlock; + } + while (true) { + index_t stopIndex = (currentTailIndex & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + if (details::circular_less_than(newTailIndex, stopIndex)) { + stopIndex = newTailIndex; + } + MOODYCAMEL_CONSTEXPR_IF (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast(nullptr)) T(details::deref_noexcept(itemFirst)))) { + while (currentTailIndex != stopIndex) { + new ((*this->tailBlock)[currentTailIndex++]) T(*itemFirst++); + } + } + else { + MOODYCAMEL_TRY { + while (currentTailIndex != stopIndex) { + new ((*this->tailBlock)[currentTailIndex]) T(details::nomove_if(nullptr)) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst)); + ++currentTailIndex; + ++itemFirst; + } + } + MOODYCAMEL_CATCH (...) { + auto constructedStopIndex = currentTailIndex; + auto lastBlockEnqueued = this->tailBlock; + + if (!details::is_trivially_destructible::value) { + auto block = startBlock; + if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) == 0) { + block = firstAllocatedBlock; + } + currentTailIndex = startTailIndex; + while (true) { + stopIndex = (currentTailIndex & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + if (details::circular_less_than(constructedStopIndex, stopIndex)) { + stopIndex = constructedStopIndex; + } + while (currentTailIndex != stopIndex) { + (*block)[currentTailIndex++]->~T(); + } + if (block == lastBlockEnqueued) { + break; + } + block = block->next; + } + } + + currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); + for (auto block = firstAllocatedBlock; block != nullptr; block = block->next) { + currentTailIndex += static_cast(BLOCK_SIZE); + auto idxEntry = get_block_index_entry_for_index(currentTailIndex); + idxEntry->value.store(nullptr, std::memory_order_relaxed); + rewind_block_index_tail(); + } + this->parent->add_blocks_to_free_list(firstAllocatedBlock); + this->tailBlock = startBlock; + MOODYCAMEL_RETHROW; + } + } + + if (this->tailBlock == endBlock) { + assert(currentTailIndex == newTailIndex); + break; + } + this->tailBlock = this->tailBlock->next; + } + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + template + size_t dequeue_bulk(It& itemFirst, size_t max) + { + auto tail = this->tailIndex.load(std::memory_order_relaxed); + auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); + auto desiredCount = static_cast(tail - (this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit)); + if (details::circular_less_than(0, desiredCount)) { + desiredCount = desiredCount < max ? desiredCount : max; + std::atomic_thread_fence(std::memory_order_acquire); + + auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, std::memory_order_relaxed); + + tail = this->tailIndex.load(std::memory_order_acquire); + auto actualCount = static_cast(tail - (myDequeueCount - overcommit)); + if (details::circular_less_than(0, actualCount)) { + actualCount = desiredCount < actualCount ? desiredCount : actualCount; + if (actualCount < desiredCount) { + this->dequeueOvercommit.fetch_add(desiredCount - actualCount, std::memory_order_release); + } + + // Get the first index. Note that since there's guaranteed to be at least actualCount elements, this + // will never exceed tail. + auto firstIndex = this->headIndex.fetch_add(actualCount, std::memory_order_acq_rel); + + // Iterate the blocks and dequeue + auto index = firstIndex; + BlockIndexHeader* localBlockIndex; + auto indexIndex = get_block_index_index_for_index(index, localBlockIndex); + do { + auto blockStartIndex = index; + index_t endIndex = (index & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + endIndex = details::circular_less_than(firstIndex + static_cast(actualCount), endIndex) ? firstIndex + static_cast(actualCount) : endIndex; + + auto entry = localBlockIndex->index[indexIndex]; + auto block = entry->value.load(std::memory_order_relaxed); + if (MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, details::deref_noexcept(itemFirst) = std::move((*(*block)[index])))) { + while (index != endIndex) { + auto& el = *((*block)[index]); + *itemFirst++ = std::move(el); + el.~T(); + ++index; + } + } + else { + MOODYCAMEL_TRY { + while (index != endIndex) { + auto& el = *((*block)[index]); + *itemFirst = std::move(el); + ++itemFirst; + el.~T(); + ++index; + } + } + MOODYCAMEL_CATCH (...) { + do { + entry = localBlockIndex->index[indexIndex]; + block = entry->value.load(std::memory_order_relaxed); + while (index != endIndex) { + (*block)[index++]->~T(); + } + + if (block->ConcurrentQueue::Block::template set_many_empty(blockStartIndex, static_cast(endIndex - blockStartIndex))) { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + entry->value.store(nullptr, std::memory_order_relaxed); + this->parent->add_block_to_free_list(block); + } + indexIndex = (indexIndex + 1) & (localBlockIndex->capacity - 1); + + blockStartIndex = index; + endIndex = (index & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + endIndex = details::circular_less_than(firstIndex + static_cast(actualCount), endIndex) ? firstIndex + static_cast(actualCount) : endIndex; + } while (index != firstIndex + actualCount); + + MOODYCAMEL_RETHROW; + } + } + if (block->ConcurrentQueue::Block::template set_many_empty(blockStartIndex, static_cast(endIndex - blockStartIndex))) { + { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + // Note that the set_many_empty above did a release, meaning that anybody who acquires the block + // we're about to free can use it safely since our writes (and reads!) will have happened-before then. + entry->value.store(nullptr, std::memory_order_relaxed); + } + this->parent->add_block_to_free_list(block); // releases the above store + } + indexIndex = (indexIndex + 1) & (localBlockIndex->capacity - 1); + } while (index != firstIndex + actualCount); + + return actualCount; + } + else { + this->dequeueOvercommit.fetch_add(desiredCount, std::memory_order_release); + } + } + + return 0; + } + + private: + // The block size must be > 1, so any number with the low bit set is an invalid block base index + static const index_t INVALID_BLOCK_BASE = 1; + + struct BlockIndexEntry + { + std::atomic key; + std::atomic value; + }; + + struct BlockIndexHeader + { + size_t capacity; + std::atomic tail; + BlockIndexEntry* entries; + BlockIndexEntry** index; + BlockIndexHeader* prev; + }; + + template + inline bool insert_block_index_entry(BlockIndexEntry*& idxEntry, index_t blockStartIndex) + { + auto localBlockIndex = blockIndex.load(std::memory_order_relaxed); // We're the only writer thread, relaxed is OK + if (localBlockIndex == nullptr) { + return false; // this can happen if new_block_index failed in the constructor + } + size_t newTail = (localBlockIndex->tail.load(std::memory_order_relaxed) + 1) & (localBlockIndex->capacity - 1); + idxEntry = localBlockIndex->index[newTail]; + if (idxEntry->key.load(std::memory_order_relaxed) == INVALID_BLOCK_BASE || + idxEntry->value.load(std::memory_order_relaxed) == nullptr) { + + idxEntry->key.store(blockStartIndex, std::memory_order_relaxed); + localBlockIndex->tail.store(newTail, std::memory_order_release); + return true; + } + + // No room in the old block index, try to allocate another one! + MOODYCAMEL_CONSTEXPR_IF (allocMode == CannotAlloc) { + return false; + } + else if (!new_block_index()) { + return false; + } + else { + localBlockIndex = blockIndex.load(std::memory_order_relaxed); + newTail = (localBlockIndex->tail.load(std::memory_order_relaxed) + 1) & (localBlockIndex->capacity - 1); + idxEntry = localBlockIndex->index[newTail]; + assert(idxEntry->key.load(std::memory_order_relaxed) == INVALID_BLOCK_BASE); + idxEntry->key.store(blockStartIndex, std::memory_order_relaxed); + localBlockIndex->tail.store(newTail, std::memory_order_release); + return true; + } + } + + inline void rewind_block_index_tail() + { + auto localBlockIndex = blockIndex.load(std::memory_order_relaxed); + localBlockIndex->tail.store((localBlockIndex->tail.load(std::memory_order_relaxed) - 1) & (localBlockIndex->capacity - 1), std::memory_order_relaxed); + } + + inline BlockIndexEntry* get_block_index_entry_for_index(index_t index) const + { + BlockIndexHeader* localBlockIndex; + auto idx = get_block_index_index_for_index(index, localBlockIndex); + return localBlockIndex->index[idx]; + } + + inline size_t get_block_index_index_for_index(index_t index, BlockIndexHeader*& localBlockIndex) const + { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + index &= ~static_cast(BLOCK_SIZE - 1); + localBlockIndex = blockIndex.load(std::memory_order_acquire); + auto tail = localBlockIndex->tail.load(std::memory_order_acquire); + auto tailBase = localBlockIndex->index[tail]->key.load(std::memory_order_relaxed); + assert(tailBase != INVALID_BLOCK_BASE); + // Note: Must use division instead of shift because the index may wrap around, causing a negative + // offset, whose negativity we want to preserve + auto offset = static_cast(static_cast::type>(index - tailBase) / static_cast::type>(BLOCK_SIZE)); + size_t idx = (tail + offset) & (localBlockIndex->capacity - 1); + assert(localBlockIndex->index[idx]->key.load(std::memory_order_relaxed) == index && localBlockIndex->index[idx]->value.load(std::memory_order_relaxed) != nullptr); + return idx; + } + + bool new_block_index() + { + auto prev = blockIndex.load(std::memory_order_relaxed); + size_t prevCapacity = prev == nullptr ? 0 : prev->capacity; + auto entryCount = prev == nullptr ? nextBlockIndexCapacity : prevCapacity; + auto raw = static_cast((Traits::malloc)( + sizeof(BlockIndexHeader) + + std::alignment_of::value - 1 + sizeof(BlockIndexEntry) * entryCount + + std::alignment_of::value - 1 + sizeof(BlockIndexEntry*) * nextBlockIndexCapacity)); + if (raw == nullptr) { + return false; + } + + auto header = new (raw) BlockIndexHeader; + auto entries = reinterpret_cast(details::align_for(raw + sizeof(BlockIndexHeader))); + auto index = reinterpret_cast(details::align_for(reinterpret_cast(entries) + sizeof(BlockIndexEntry) * entryCount)); + if (prev != nullptr) { + auto prevTail = prev->tail.load(std::memory_order_relaxed); + auto prevPos = prevTail; + size_t i = 0; + do { + prevPos = (prevPos + 1) & (prev->capacity - 1); + index[i++] = prev->index[prevPos]; + } while (prevPos != prevTail); + assert(i == prevCapacity); + } + for (size_t i = 0; i != entryCount; ++i) { + new (entries + i) BlockIndexEntry; + entries[i].key.store(INVALID_BLOCK_BASE, std::memory_order_relaxed); + index[prevCapacity + i] = entries + i; + } + header->prev = prev; + header->entries = entries; + header->index = index; + header->capacity = nextBlockIndexCapacity; + header->tail.store((prevCapacity - 1) & (nextBlockIndexCapacity - 1), std::memory_order_relaxed); + + blockIndex.store(header, std::memory_order_release); + + nextBlockIndexCapacity <<= 1; + + return true; + } + + private: + size_t nextBlockIndexCapacity; + std::atomic blockIndex; + +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED + public: + details::ThreadExitListener threadExitListener; + private: +#endif + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + public: + ImplicitProducer* nextImplicitProducer; + private: +#endif + +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + mutable debug::DebugMutex mutex; +#endif +#ifdef MCDBGQ_TRACKMEM + friend struct MemStats; +#endif + }; + + + ////////////////////////////////// + // Block pool manipulation + ////////////////////////////////// + + void populate_initial_block_list(size_t blockCount) + { + initialBlockPoolSize = blockCount; + if (initialBlockPoolSize == 0) { + initialBlockPool = nullptr; + return; + } + + initialBlockPool = create_array(blockCount); + if (initialBlockPool == nullptr) { + initialBlockPoolSize = 0; + } + for (size_t i = 0; i < initialBlockPoolSize; ++i) { + initialBlockPool[i].dynamicallyAllocated = false; + } + } + + inline Block* try_get_block_from_initial_pool() + { + if (initialBlockPoolIndex.load(std::memory_order_relaxed) >= initialBlockPoolSize) { + return nullptr; + } + + auto index = initialBlockPoolIndex.fetch_add(1, std::memory_order_relaxed); + + return index < initialBlockPoolSize ? (initialBlockPool + index) : nullptr; + } + + inline void add_block_to_free_list(Block* block) + { +#ifdef MCDBGQ_TRACKMEM + block->owner = nullptr; +#endif + if (!Traits::RECYCLE_ALLOCATED_BLOCKS && block->dynamicallyAllocated) { + destroy(block); + } + else { + freeList.add(block); + } + } + + inline void add_blocks_to_free_list(Block* block) + { + while (block != nullptr) { + auto next = block->next; + add_block_to_free_list(block); + block = next; + } + } + + inline Block* try_get_block_from_free_list() + { + return freeList.try_get(); + } + + // Gets a free block from one of the memory pools, or allocates a new one (if applicable) + template + Block* requisition_block() + { + auto block = try_get_block_from_initial_pool(); + if (block != nullptr) { + return block; + } + + block = try_get_block_from_free_list(); + if (block != nullptr) { + return block; + } + + MOODYCAMEL_CONSTEXPR_IF (canAlloc == CanAlloc) { + return create(); + } + else { + return nullptr; + } + } + + +#ifdef MCDBGQ_TRACKMEM + public: + struct MemStats { + size_t allocatedBlocks; + size_t usedBlocks; + size_t freeBlocks; + size_t ownedBlocksExplicit; + size_t ownedBlocksImplicit; + size_t implicitProducers; + size_t explicitProducers; + size_t elementsEnqueued; + size_t blockClassBytes; + size_t queueClassBytes; + size_t implicitBlockIndexBytes; + size_t explicitBlockIndexBytes; + + friend class ConcurrentQueue; + + private: + static MemStats getFor(ConcurrentQueue* q) + { + MemStats stats = { 0 }; + + stats.elementsEnqueued = q->size_approx(); + + auto block = q->freeList.head_unsafe(); + while (block != nullptr) { + ++stats.allocatedBlocks; + ++stats.freeBlocks; + block = block->freeListNext.load(std::memory_order_relaxed); + } + + for (auto ptr = q->producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + bool implicit = dynamic_cast(ptr) != nullptr; + stats.implicitProducers += implicit ? 1 : 0; + stats.explicitProducers += implicit ? 0 : 1; + + if (implicit) { + auto prod = static_cast(ptr); + stats.queueClassBytes += sizeof(ImplicitProducer); + auto head = prod->headIndex.load(std::memory_order_relaxed); + auto tail = prod->tailIndex.load(std::memory_order_relaxed); + auto hash = prod->blockIndex.load(std::memory_order_relaxed); + if (hash != nullptr) { + for (size_t i = 0; i != hash->capacity; ++i) { + if (hash->index[i]->key.load(std::memory_order_relaxed) != ImplicitProducer::INVALID_BLOCK_BASE && hash->index[i]->value.load(std::memory_order_relaxed) != nullptr) { + ++stats.allocatedBlocks; + ++stats.ownedBlocksImplicit; + } + } + stats.implicitBlockIndexBytes += hash->capacity * sizeof(typename ImplicitProducer::BlockIndexEntry); + for (; hash != nullptr; hash = hash->prev) { + stats.implicitBlockIndexBytes += sizeof(typename ImplicitProducer::BlockIndexHeader) + hash->capacity * sizeof(typename ImplicitProducer::BlockIndexEntry*); + } + } + for (; details::circular_less_than(head, tail); head += BLOCK_SIZE) { + //auto block = prod->get_block_index_entry_for_index(head); + ++stats.usedBlocks; + } + } + else { + auto prod = static_cast(ptr); + stats.queueClassBytes += sizeof(ExplicitProducer); + auto tailBlock = prod->tailBlock; + bool wasNonEmpty = false; + if (tailBlock != nullptr) { + auto block = tailBlock; + do { + ++stats.allocatedBlocks; + if (!block->ConcurrentQueue::Block::template is_empty() || wasNonEmpty) { + ++stats.usedBlocks; + wasNonEmpty = wasNonEmpty || block != tailBlock; + } + ++stats.ownedBlocksExplicit; + block = block->next; + } while (block != tailBlock); + } + auto index = prod->blockIndex.load(std::memory_order_relaxed); + while (index != nullptr) { + stats.explicitBlockIndexBytes += sizeof(typename ExplicitProducer::BlockIndexHeader) + index->size * sizeof(typename ExplicitProducer::BlockIndexEntry); + index = static_cast(index->prev); + } + } + } + + auto freeOnInitialPool = q->initialBlockPoolIndex.load(std::memory_order_relaxed) >= q->initialBlockPoolSize ? 0 : q->initialBlockPoolSize - q->initialBlockPoolIndex.load(std::memory_order_relaxed); + stats.allocatedBlocks += freeOnInitialPool; + stats.freeBlocks += freeOnInitialPool; + + stats.blockClassBytes = sizeof(Block) * stats.allocatedBlocks; + stats.queueClassBytes += sizeof(ConcurrentQueue); + + return stats; + } + }; + + // For debugging only. Not thread-safe. + MemStats getMemStats() + { + return MemStats::getFor(this); + } + private: + friend struct MemStats; +#endif + + + ////////////////////////////////// + // Producer list manipulation + ////////////////////////////////// + + ProducerBase* recycle_or_create_producer(bool isExplicit) + { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH + debug::DebugLock lock(implicitProdMutex); +#endif + // Try to re-use one first + for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + if (ptr->inactive.load(std::memory_order_relaxed) && ptr->isExplicit == isExplicit) { + bool expected = true; + if (ptr->inactive.compare_exchange_strong(expected, /* desired */ false, std::memory_order_acquire, std::memory_order_relaxed)) { + // We caught one! It's been marked as activated, the caller can have it + return ptr; + } + } + } + + return add_producer(isExplicit ? static_cast(create(this)) : create(this)); + } + + ProducerBase* add_producer(ProducerBase* producer) + { + // Handle failed memory allocation + if (producer == nullptr) { + return nullptr; + } + + producerCount.fetch_add(1, std::memory_order_relaxed); + + // Add it to the lock-free list + auto prevTail = producerListTail.load(std::memory_order_relaxed); + do { + producer->next = prevTail; + } while (!producerListTail.compare_exchange_weak(prevTail, producer, std::memory_order_release, std::memory_order_relaxed)); + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + if (producer->isExplicit) { + auto prevTailExplicit = explicitProducers.load(std::memory_order_relaxed); + do { + static_cast(producer)->nextExplicitProducer = prevTailExplicit; + } while (!explicitProducers.compare_exchange_weak(prevTailExplicit, static_cast(producer), std::memory_order_release, std::memory_order_relaxed)); + } + else { + auto prevTailImplicit = implicitProducers.load(std::memory_order_relaxed); + do { + static_cast(producer)->nextImplicitProducer = prevTailImplicit; + } while (!implicitProducers.compare_exchange_weak(prevTailImplicit, static_cast(producer), std::memory_order_release, std::memory_order_relaxed)); + } +#endif + + return producer; + } + + void reown_producers() + { + // After another instance is moved-into/swapped-with this one, all the + // producers we stole still think their parents are the other queue. + // So fix them up! + for (auto ptr = producerListTail.load(std::memory_order_relaxed); ptr != nullptr; ptr = ptr->next_prod()) { + ptr->parent = this; + } + } + + + ////////////////////////////////// + // Implicit producer hash + ////////////////////////////////// + + struct ImplicitProducerKVP + { + std::atomic key; + ImplicitProducer* value; // No need for atomicity since it's only read by the thread that sets it in the first place + + ImplicitProducerKVP() : value(nullptr) { } + + ImplicitProducerKVP(ImplicitProducerKVP&& other) MOODYCAMEL_NOEXCEPT + { + key.store(other.key.load(std::memory_order_relaxed), std::memory_order_relaxed); + value = other.value; + } + + inline ImplicitProducerKVP& operator=(ImplicitProducerKVP&& other) MOODYCAMEL_NOEXCEPT + { + swap(other); + return *this; + } + + inline void swap(ImplicitProducerKVP& other) MOODYCAMEL_NOEXCEPT + { + if (this != &other) { + details::swap_relaxed(key, other.key); + std::swap(value, other.value); + } + } + }; + + template + friend void moodycamel::swap(typename ConcurrentQueue::ImplicitProducerKVP&, typename ConcurrentQueue::ImplicitProducerKVP&) MOODYCAMEL_NOEXCEPT; + + struct ImplicitProducerHash + { + size_t capacity; + ImplicitProducerKVP* entries; + ImplicitProducerHash* prev; + }; + + inline void populate_initial_implicit_producer_hash() + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) { + return; + } + else { + implicitProducerHashCount.store(0, std::memory_order_relaxed); + auto hash = &initialImplicitProducerHash; + hash->capacity = INITIAL_IMPLICIT_PRODUCER_HASH_SIZE; + hash->entries = &initialImplicitProducerHashEntries[0]; + for (size_t i = 0; i != INITIAL_IMPLICIT_PRODUCER_HASH_SIZE; ++i) { + initialImplicitProducerHashEntries[i].key.store(details::invalid_thread_id, std::memory_order_relaxed); + } + hash->prev = nullptr; + implicitProducerHash.store(hash, std::memory_order_relaxed); + } + } + + void swap_implicit_producer_hashes(ConcurrentQueue& other) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) { + return; + } + else { + // Swap (assumes our implicit producer hash is initialized) + initialImplicitProducerHashEntries.swap(other.initialImplicitProducerHashEntries); + initialImplicitProducerHash.entries = &initialImplicitProducerHashEntries[0]; + other.initialImplicitProducerHash.entries = &other.initialImplicitProducerHashEntries[0]; + + details::swap_relaxed(implicitProducerHashCount, other.implicitProducerHashCount); + + details::swap_relaxed(implicitProducerHash, other.implicitProducerHash); + if (implicitProducerHash.load(std::memory_order_relaxed) == &other.initialImplicitProducerHash) { + implicitProducerHash.store(&initialImplicitProducerHash, std::memory_order_relaxed); + } + else { + ImplicitProducerHash* hash; + for (hash = implicitProducerHash.load(std::memory_order_relaxed); hash->prev != &other.initialImplicitProducerHash; hash = hash->prev) { + continue; + } + hash->prev = &initialImplicitProducerHash; + } + if (other.implicitProducerHash.load(std::memory_order_relaxed) == &initialImplicitProducerHash) { + other.implicitProducerHash.store(&other.initialImplicitProducerHash, std::memory_order_relaxed); + } + else { + ImplicitProducerHash* hash; + for (hash = other.implicitProducerHash.load(std::memory_order_relaxed); hash->prev != &initialImplicitProducerHash; hash = hash->prev) { + continue; + } + hash->prev = &other.initialImplicitProducerHash; + } + } + } + + // Only fails (returns nullptr) if memory allocation fails + ImplicitProducer* get_or_add_implicit_producer() + { + // Note that since the data is essentially thread-local (key is thread ID), + // there's a reduced need for fences (memory ordering is already consistent + // for any individual thread), except for the current table itself. + + // Start by looking for the thread ID in the current and all previous hash tables. + // If it's not found, it must not be in there yet, since this same thread would + // have added it previously to one of the tables that we traversed. + + // Code and algorithm adapted from http://preshing.com/20130605/the-worlds-simplest-lock-free-hash-table + +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH + debug::DebugLock lock(implicitProdMutex); +#endif + + auto id = details::thread_id(); + auto hashedId = details::hash_thread_id(id); + + auto mainHash = implicitProducerHash.load(std::memory_order_acquire); + assert(mainHash != nullptr); // silence clang-tidy and MSVC warnings (hash cannot be null) + for (auto hash = mainHash; hash != nullptr; hash = hash->prev) { + // Look for the id in this hash + auto index = hashedId; + while (true) { // Not an infinite loop because at least one slot is free in the hash table + index &= hash->capacity - 1u; + + auto probedKey = hash->entries[index].key.load(std::memory_order_relaxed); + if (probedKey == id) { + // Found it! If we had to search several hashes deep, though, we should lazily add it + // to the current main hash table to avoid the extended search next time. + // Note there's guaranteed to be room in the current hash table since every subsequent + // table implicitly reserves space for all previous tables (there's only one + // implicitProducerHashCount). + auto value = hash->entries[index].value; + if (hash != mainHash) { + index = hashedId; + while (true) { + index &= mainHash->capacity - 1u; + auto empty = details::invalid_thread_id; +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED + auto reusable = details::invalid_thread_id2; + if (mainHash->entries[index].key.compare_exchange_strong(empty, id, std::memory_order_seq_cst, std::memory_order_relaxed) || + mainHash->entries[index].key.compare_exchange_strong(reusable, id, std::memory_order_seq_cst, std::memory_order_relaxed)) { +#else + if (mainHash->entries[index].key.compare_exchange_strong(empty, id, std::memory_order_seq_cst, std::memory_order_relaxed)) { +#endif + mainHash->entries[index].value = value; + break; + } + ++index; + } + } + + return value; + } + if (probedKey == details::invalid_thread_id) { + break; // Not in this hash table + } + ++index; + } + } + + // Insert! + auto newCount = 1 + implicitProducerHashCount.fetch_add(1, std::memory_order_relaxed); + while (true) { + // NOLINTNEXTLINE(clang-analyzer-core.NullDereference) + if (newCount >= (mainHash->capacity >> 1) && !implicitProducerHashResizeInProgress.test_and_set(std::memory_order_acquire)) { + // We've acquired the resize lock, try to allocate a bigger hash table. + // Note the acquire fence synchronizes with the release fence at the end of this block, and hence when + // we reload implicitProducerHash it must be the most recent version (it only gets changed within this + // locked block). + mainHash = implicitProducerHash.load(std::memory_order_acquire); + if (newCount >= (mainHash->capacity >> 1)) { + size_t newCapacity = mainHash->capacity << 1; + while (newCount >= (newCapacity >> 1)) { + newCapacity <<= 1; + } + auto raw = static_cast((Traits::malloc)(sizeof(ImplicitProducerHash) + std::alignment_of::value - 1 + sizeof(ImplicitProducerKVP) * newCapacity)); + if (raw == nullptr) { + // Allocation failed + implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed); + implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); + return nullptr; + } + + auto newHash = new (raw) ImplicitProducerHash; + newHash->capacity = static_cast(newCapacity); + newHash->entries = reinterpret_cast(details::align_for(raw + sizeof(ImplicitProducerHash))); + for (size_t i = 0; i != newCapacity; ++i) { + new (newHash->entries + i) ImplicitProducerKVP; + newHash->entries[i].key.store(details::invalid_thread_id, std::memory_order_relaxed); + } + newHash->prev = mainHash; + implicitProducerHash.store(newHash, std::memory_order_release); + implicitProducerHashResizeInProgress.clear(std::memory_order_release); + mainHash = newHash; + } + else { + implicitProducerHashResizeInProgress.clear(std::memory_order_release); + } + } + + // If it's < three-quarters full, add to the old one anyway so that we don't have to wait for the next table + // to finish being allocated by another thread (and if we just finished allocating above, the condition will + // always be true) + if (newCount < (mainHash->capacity >> 1) + (mainHash->capacity >> 2)) { + auto producer = static_cast(recycle_or_create_producer(false)); + if (producer == nullptr) { + implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed); + return nullptr; + } + +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED + producer->threadExitListener.callback = &ConcurrentQueue::implicit_producer_thread_exited_callback; + producer->threadExitListener.userData = producer; + details::ThreadExitNotifier::subscribe(&producer->threadExitListener); +#endif + + auto index = hashedId; + while (true) { + index &= mainHash->capacity - 1u; + auto empty = details::invalid_thread_id; +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED + auto reusable = details::invalid_thread_id2; + if (mainHash->entries[index].key.compare_exchange_strong(reusable, id, std::memory_order_seq_cst, std::memory_order_relaxed)) { + implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed); // already counted as a used slot + mainHash->entries[index].value = producer; + break; + } +#endif + if (mainHash->entries[index].key.compare_exchange_strong(empty, id, std::memory_order_seq_cst, std::memory_order_relaxed)) { + mainHash->entries[index].value = producer; + break; + } + ++index; + } + return producer; + } + + // Hmm, the old hash is quite full and somebody else is busy allocating a new one. + // We need to wait for the allocating thread to finish (if it succeeds, we add, if not, + // we try to allocate ourselves). + mainHash = implicitProducerHash.load(std::memory_order_acquire); + } + } + +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED + void implicit_producer_thread_exited(ImplicitProducer* producer) + { + // Remove from hash +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH + debug::DebugLock lock(implicitProdMutex); +#endif + auto hash = implicitProducerHash.load(std::memory_order_acquire); + assert(hash != nullptr); // The thread exit listener is only registered if we were added to a hash in the first place + auto id = details::thread_id(); + auto hashedId = details::hash_thread_id(id); + details::thread_id_t probedKey; + + // We need to traverse all the hashes just in case other threads aren't on the current one yet and are + // trying to add an entry thinking there's a free slot (because they reused a producer) + for (; hash != nullptr; hash = hash->prev) { + auto index = hashedId; + do { + index &= hash->capacity - 1u; + probedKey = id; + if (hash->entries[index].key.compare_exchange_strong(probedKey, details::invalid_thread_id2, std::memory_order_seq_cst, std::memory_order_relaxed)) { + break; + } + ++index; + } while (probedKey != details::invalid_thread_id); // Can happen if the hash has changed but we weren't put back in it yet, or if we weren't added to this hash in the first place + } + + // Mark the queue as being recyclable + producer->inactive.store(true, std::memory_order_release); + } + + static void implicit_producer_thread_exited_callback(void* userData) + { + auto producer = static_cast(userData); + auto queue = producer->parent; + queue->implicit_producer_thread_exited(producer); + } +#endif + + ////////////////////////////////// + // Utility functions + ////////////////////////////////// + + template + static inline void* aligned_malloc(size_t size) + { + MOODYCAMEL_CONSTEXPR_IF (std::alignment_of::value <= std::alignment_of::value) + return (Traits::malloc)(size); + else { + size_t alignment = std::alignment_of::value; + void* raw = (Traits::malloc)(size + alignment - 1 + sizeof(void*)); + if (!raw) + return nullptr; + char* ptr = details::align_for(reinterpret_cast(raw) + sizeof(void*)); + *(reinterpret_cast(ptr) - 1) = raw; + return ptr; + } + } + + template + static inline void aligned_free(void* ptr) + { + MOODYCAMEL_CONSTEXPR_IF (std::alignment_of::value <= std::alignment_of::value) + return (Traits::free)(ptr); + else + (Traits::free)(ptr ? *(reinterpret_cast(ptr) - 1) : nullptr); + } + + template + static inline U* create_array(size_t count) + { + assert(count > 0); + U* p = static_cast(aligned_malloc(sizeof(U) * count)); + if (p == nullptr) + return nullptr; + + for (size_t i = 0; i != count; ++i) + new (p + i) U(); + return p; + } + + template + static inline void destroy_array(U* p, size_t count) + { + if (p != nullptr) { + assert(count > 0); + for (size_t i = count; i != 0; ) + (p + --i)->~U(); + } + aligned_free(p); + } + + template + static inline U* create() + { + void* p = aligned_malloc(sizeof(U)); + return p != nullptr ? new (p) U : nullptr; + } + + template + static inline U* create(A1&& a1) + { + void* p = aligned_malloc(sizeof(U)); + return p != nullptr ? new (p) U(std::forward(a1)) : nullptr; + } + + template + static inline void destroy(U* p) + { + if (p != nullptr) + p->~U(); + aligned_free(p); + } + +private: + std::atomic producerListTail; + std::atomic producerCount; + + std::atomic initialBlockPoolIndex; + Block* initialBlockPool; + size_t initialBlockPoolSize; + +#ifndef MCDBGQ_USEDEBUGFREELIST + FreeList freeList; +#else + debug::DebugFreeList freeList; +#endif + + std::atomic implicitProducerHash; + std::atomic implicitProducerHashCount; // Number of slots logically used + ImplicitProducerHash initialImplicitProducerHash; + std::array initialImplicitProducerHashEntries; + std::atomic_flag implicitProducerHashResizeInProgress; + + std::atomic nextExplicitConsumerId; + std::atomic globalExplicitConsumerOffset; + +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH + debug::DebugMutex implicitProdMutex; +#endif + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + std::atomic explicitProducers; + std::atomic implicitProducers; +#endif +}; + + +template +ProducerToken::ProducerToken(ConcurrentQueue& queue) + : producer(queue.recycle_or_create_producer(true)) +{ + if (producer != nullptr) { + producer->token = this; + } +} + +template +ProducerToken::ProducerToken(BlockingConcurrentQueue& queue) + : producer(reinterpret_cast*>(&queue)->recycle_or_create_producer(true)) +{ + if (producer != nullptr) { + producer->token = this; + } +} + +template +ConsumerToken::ConsumerToken(ConcurrentQueue& queue) + : itemsConsumedFromCurrent(0), currentProducer(nullptr), desiredProducer(nullptr) +{ + initialOffset = queue.nextExplicitConsumerId.fetch_add(1, std::memory_order_release); + lastKnownGlobalOffset = static_cast(-1); +} + +template +ConsumerToken::ConsumerToken(BlockingConcurrentQueue& queue) + : itemsConsumedFromCurrent(0), currentProducer(nullptr), desiredProducer(nullptr) +{ + initialOffset = reinterpret_cast*>(&queue)->nextExplicitConsumerId.fetch_add(1, std::memory_order_release); + lastKnownGlobalOffset = static_cast(-1); +} + +template +inline void swap(ConcurrentQueue& a, ConcurrentQueue& b) MOODYCAMEL_NOEXCEPT +{ + a.swap(b); +} + +inline void swap(ProducerToken& a, ProducerToken& b) MOODYCAMEL_NOEXCEPT +{ + a.swap(b); +} + +inline void swap(ConsumerToken& a, ConsumerToken& b) MOODYCAMEL_NOEXCEPT +{ + a.swap(b); +} + +template +inline void swap(typename ConcurrentQueue::ImplicitProducerKVP& a, typename ConcurrentQueue::ImplicitProducerKVP& b) MOODYCAMEL_NOEXCEPT +{ + a.swap(b); +} + +} + +#if defined(_MSC_VER) && (!defined(_HAS_CXX17) || !_HAS_CXX17) +#pragma warning(pop) +#endif + +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) +#pragma GCC diagnostic pop +#endif diff --git a/duix-sdk/src/main/cpp/dhcore/dh_atomic.h b/duix-sdk/src/main/cpp/dhcore/dh_atomic.h new file mode 100644 index 0000000..4164930 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhcore/dh_atomic.h @@ -0,0 +1,1198 @@ +/** + * @file dh_atomic.h Atomic support + * + * Copyright (C) 2022 Sebastian Reimers + */ + +#ifndef DH_H_ATOMIC__ +#define DH_H_ATOMIC__ + +/* C11 */ +#if defined(HAVE_ATOMIC) && __STDC_VERSION__ >= 201112L && \ + !defined(__STDC_NO_ATOMICS__) + +#include + +#define DH_ATOMIC _Atomic + +#define DH_ATOMIC_BOOL_LOCK_FREE ATOMIC_BOOL_LOCK_FREE +#define DH_ATOMIC_CHAR_LOCK_FREE ATOMIC_CHAR_LOCK_FREE +#define DH_ATOMIC_WCHAR_T_LOCK_FREE ATOMIC_WCHAR_T_LOCK_FREE +#define DH_ATOMIC_SHORT_LOCK_FREE ATOMIC_SHORT_LOCK_FREE +#define DH_ATOMIC_INT_LOCK_FREE ATOMIC_INT_LOCK_FREE +#define DH_ATOMIC_LONG_LOCK_FREE ATOMIC_LONG_LOCK_FREE +#define DH_ATOMIC_LLONG_LOCK_FREE ATOMIC_LLONG_LOCK_FREE +#define DH_ATOMIC_POINTER_LOCK_FREE ATOMIC_POINTER_LOCK_FREE + +#define dh_memory_order_relaxed memory_order_relaxed +#define dh_memory_order_acquire memory_order_acquire +#define dh_memory_order_release memory_order_release +#define dh_memory_order_acq_rel memory_order_acq_rel +#define dh_memory_order_seq_cst memory_order_seq_cst + +#define dh_atomic_store(_a, _v, _mo) \ + atomic_stodh_explicit(_a, _v, _mo) + +#define dh_atomic_load(_a, _mo) \ + atomic_load_explicit(_a, _mo) + +#define dh_atomic_exchange(_a, _v, _mo) \ + atomic_exchange_explicit(_a, _v, _mo) + +#define dh_atomic_compadh_exchange_strong(\ + _a, _expected, _desired, _success_mo, _fail_mo) \ + atomic_compadh_exchange_strong_explicit(\ + _a, _expected, _desired, _success_mo, _fail_mo) + +#define dh_atomic_compadh_exchange_weak(\ + _a, _expected, _desired, _success_mo, _fail_mo) \ + atomic_compadh_exchange_weak_explicit(\ + _a, _expected, _desired, _success_mo, _fail_mo) + +#define dh_atomic_fetch_add(_a, _v, _mo) \ + atomic_fetch_add_explicit(_a, _v, _mo) + +#define dh_atomic_fetch_sub(_a, _v, _mo) \ + atomic_fetch_sub_explicit(_a, _v, _mo) + +#define dh_atomic_fetch_or(_a, _v, _mo) \ + atomic_fetch_or_explicit(_a, _v, _mo) + +#define dh_atomic_fetch_xor(_a, _v, _mo) \ + atomic_fetch_xor_explicit(_a, _v, _mo) + +#define dh_atomic_fetch_and(_a, _v, _mo) \ + atomic_fetch_and_explicit(_a, _v, _mo) + +/* gcc-style __atomic* intrinsics. + * Note: clang-cl also supports these, even though it impersonates MSVC. */ +#elif (defined(__GNUC__) || defined(__clang__)) && \ + defined(__GCC_ATOMIC_BOOL_LOCK_FREE) && \ + defined(__GCC_ATOMIC_CHAR_LOCK_FREE) && \ + defined(__GCC_ATOMIC_WCHAR_T_LOCK_FREE) && \ + defined(__GCC_ATOMIC_SHORT_LOCK_FREE) && \ + defined(__GCC_ATOMIC_INT_LOCK_FREE) && \ + defined(__GCC_ATOMIC_LONG_LOCK_FREE) && \ + defined(__GCC_ATOMIC_LLONG_LOCK_FREE) && \ + defined(__GCC_ATOMIC_POINTER_LOCK_FREE) && \ + defined(__ATOMIC_RELAXED) && defined(__ATOMIC_ACQUIRE) && \ + defined(__ATOMIC_RELEASE) && defined(__ATOMIC_ACQ_REL) && \ + defined(__ATOMIC_SEQ_CST) + +#define DH_ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE +#define DH_ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE +#define DH_ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE +#define DH_ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE +#define DH_ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE +#define DH_ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE +#define DH_ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE +#define DH_ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE + +#define dh_memory_order_relaxed __ATOMIC_RELAXED +#define dh_memory_order_acquire __ATOMIC_ACQUIRE +#define dh_memory_order_release __ATOMIC_RELEASE +#define dh_memory_order_acq_rel __ATOMIC_ACQ_REL +#define dh_memory_order_seq_cst __ATOMIC_SEQ_CST + +#define dh_atomic_store(_a, _v, _mo) \ + __atomic_store_n(_a, _v, _mo) + +#define dh_atomic_load(_a, _mo) \ + __atomic_load_n(_a, _mo) + +#define dh_atomic_exchange(_a, _v, _mo) \ + __atomic_exchange_n(_a, _v, _mo) + +#define dh_atomic_compadh_exchange_strong(\ + _a, _expected, _desired, _success_mo, _fail_mo) \ + __atomic_compadh_exchange_n(\ + _a, _expected, _desired, 0, _success_mo, _fail_mo) + +#define dh_atomic_compadh_exchange_weak(\ + _a, _expected, _desired, _success_mo, _fail_mo) \ + __atomic_compadh_exchange_n(\ + _a, _expected, _desired, 1, _success_mo, _fail_mo) + +#define dh_atomic_fetch_add(_a, _v, _mo) \ + __atomic_fetch_add(_a, _v, _mo) + +#define dh_atomic_fetch_sub(_a, _v, _mo) \ + __atomic_fetch_sub(_a, _v, _mo) + +#define dh_atomic_fetch_or(_a, _v, _mo) \ + __atomic_fetch_or(_a, _v, _mo) + +#define dh_atomic_fetch_xor(_a, _v, _mo) \ + __atomic_fetch_xor(_a, _v, _mo) + +#define dh_atomic_fetch_and(_a, _v, _mo) \ + __atomic_fetch_and(_a, _v, _mo) + +/* gcc-style __sync* intrinsics. */ +#elif defined(__GNUC__) && \ + (defined(__GCC_HAVE_SYNC_COMPADH_AND_SWAP_1) || \ + defined(__GCC_HAVE_SYNC_COMPADH_AND_SWAP_2) || \ + defined(__GCC_HAVE_SYNC_COMPADH_AND_SWAP_4) || \ + defined(__GCC_HAVE_SYNC_COMPADH_AND_SWAP_8)) + +#if !defined(__SIZEOF_SHORT__) || !defined(__SIZEOF_INT__) || \ + !defined(__SIZEOF_LONG__) || !defined(__SIZEOF_LONG_LONG__) +#include +#endif +#if !defined(__SIZEOF_POINTER__) +#include +#endif +#if !defined(__SIZEOF_WCHAR_T__) +#include +#endif + +#if defined(__GCC_HAVE_SYNC_COMPADH_AND_SWAP_1) +#define DH_ATOMIC_CHAR_LOCK_FREE 2 +#endif + +#if defined(__GCC_HAVE_SYNC_COMPADH_AND_SWAP_2) +#if (defined(__SIZEOF_SHORT__) && __SIZEOF_SHORT__ == 2) || \ + (defined(USHRT_MAX) && USHRT_MAX == 0xffffu) +#define DH_ATOMIC_SHORT_LOCK_FREE 2 +#endif +#if (defined(__SIZEOF_INT__) && __SIZEOF_INT__ == 2) || \ + (defined(UINT_MAX) && UINT_MAX == 0xffffu) +#define DH_ATOMIC_INT_LOCK_FREE 2 +#endif +#if (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 2) || \ + (defined(ULONG_MAX) && ULONG_MAX == 0xffffu) +#define DH_ATOMIC_LONG_LOCK_FREE 2 +#endif +#if (defined(__SIZEOF_LONG_LONG__) && __SIZEOF_LONG_LONG__ == 2) || \ + (defined(ULLONG_MAX) && ULLONG_MAX == 0xffffu) +#define DH_ATOMIC_LLONG_LOCK_FREE 2 +#endif +#if (defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 2) || \ + (defined(UINTPTR_MAX) && UINTPTR_MAX == 0xffffu) +#define DH_ATOMIC_POINTER_LOCK_FREE 2 +#endif +#if (defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) || \ + (defined(WCHAR_MAX) && (WCHAR_MAX == 0xffff || WCHAR_MAX == 0x7fff)) +#define DH_ATOMIC_WCHAR_T_LOCK_FREE 2 +#endif +#endif + +#if defined(__GCC_HAVE_SYNC_COMPADH_AND_SWAP_4) +#if (defined(__SIZEOF_SHORT__) && __SIZEOF_SHORT__ == 4) || \ + (defined(USHRT_MAX) && USHRT_MAX == 0xffffffffu) +#define DH_ATOMIC_SHORT_LOCK_FREE 2 +#endif +#if (defined(__SIZEOF_INT__) && __SIZEOF_INT__ == 4) || \ + (defined(UINT_MAX) && UINT_MAX == 0xffffffffu) +#define DH_ATOMIC_INT_LOCK_FREE 2 +#endif +#if (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4) || \ + (defined(ULONG_MAX) && ULONG_MAX == 0xffffffffu) +#define DH_ATOMIC_LONG_LOCK_FREE 2 +#endif +#if (defined(__SIZEOF_LONG_LONG__) && __SIZEOF_LONG_LONG__ == 4) || \ + (defined(ULLONG_MAX) && ULLONG_MAX == 0xffffffffu) +#define DH_ATOMIC_LLONG_LOCK_FREE 2 +#endif +#if (defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 4) || \ + (defined(UINTPTR_MAX) && UINTPTR_MAX == 0xffffffffu) +#define DH_ATOMIC_POINTER_LOCK_FREE 2 +#endif +#if (defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 4) || \ + (defined(WCHAR_MAX) && (WCHAR_MAX == 0xffffffff || \ + WCHAR_MAX == 0x7fffffff)) +#define DH_ATOMIC_WCHAR_T_LOCK_FREE 2 +#endif +#endif + +#if defined(__GCC_HAVE_SYNC_COMPADH_AND_SWAP_8) +#if (defined(__SIZEOF_SHORT__) && __SIZEOF_SHORT__ == 8) || \ + (defined(USHRT_MAX) && USHRT_MAX == 0xffffffffffffffffu) +#define DH_ATOMIC_SHORT_LOCK_FREE 2 +#endif +#if (defined(__SIZEOF_INT__) && __SIZEOF_INT__ == 8) || \ + (defined(UINT_MAX) && UINT_MAX == 0xffffffffffffffffu) +#define DH_ATOMIC_INT_LOCK_FREE 2 +#endif +#if (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 8) || \ + (defined(ULONG_MAX) && ULONG_MAX == 0xffffffffffffffffu) +#define DH_ATOMIC_LONG_LOCK_FREE 2 +#endif +#if (defined(__SIZEOF_LONG_LONG__) && __SIZEOF_LONG_LONG__ == 8) || \ + (defined(ULLONG_MAX) && ULLONG_MAX == 0xffffffffffffffffu) +#define DH_ATOMIC_LLONG_LOCK_FREE 2 +#endif +#if (defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 8) || \ + (defined(UINTPTR_MAX) && UINTPTR_MAX == 0xffffffffffffffffu) +#define DH_ATOMIC_POINTER_LOCK_FREE 2 +#endif +#if (defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 8) || \ + (defined(WCHAR_MAX) && (WCHAR_MAX == 0xffffffffffffffff || \ + WCHAR_MAX == 0x7fffffffffffffff)) +#define DH_ATOMIC_WCHAR_T_LOCK_FREE 2 +#endif +#endif + +#if !defined(DH_ATOMIC_CHAR_LOCK_FREE) +#define DH_ATOMIC_CHAR_LOCK_FREE 0 +#endif +#if !defined(DH_ATOMIC_SHORT_LOCK_FREE) +#define DH_ATOMIC_SHORT_LOCK_FREE 0 +#endif +#if !defined(DH_ATOMIC_INT_LOCK_FREE) +#define DH_ATOMIC_INT_LOCK_FREE 0 +#endif +#if !defined(DH_ATOMIC_LONG_LOCK_FREE) +#define DH_ATOMIC_LONG_LOCK_FREE 0 +#endif +#if !defined(DH_ATOMIC_LLONG_LOCK_FREE) +#define DH_ATOMIC_LLONG_LOCK_FREE 0 +#endif +#if !defined(DH_ATOMIC_POINTER_LOCK_FREE) +#define DH_ATOMIC_POINTER_LOCK_FREE 0 +#endif +#if !defined(DH_ATOMIC_WCHAR_T_LOCK_FREE) +#define DH_ATOMIC_WCHAR_T_LOCK_FREE 0 +#endif + +/* Assume bool is always 1 byte. Add platform-specific exceptions, + * if needed. */ +#define DH_ATOMIC_BOOL_LOCK_FREE DH_ATOMIC_CHAR_LOCK_FREE + +/* These constants match __ATOMIC_* predefined macros on + * gcc versions that support __atomic intrinsics. */ +#define dh_memory_order_relaxed 0 +#define dh_memory_order_acquire 2 +#define dh_memory_order_release 3 +#define dh_memory_order_acq_rel 4 +#define dh_memory_order_seq_cst 5 + +#if defined(__x86_64__) + +#define dh_atomic_store(_a, _v, _mo) \ + __extension__\ + ({\ + __typeof__(*(_a)) _val = (_v);\ + if ((_mo) != dh_memory_order_seq_cst) {\ + __asm__ __volatile__ ("mov %1, %0"\ + : "=m" (*(_a))\ + : "q" (_val)\ + : "memory");\ + }\ + else {\ + __asm__ __volatile__ ("xchg %1, %0"\ + : "=m" (*(_a)), "+q" (_val)\ + : \ + : "memory");\ + }\ + }) + +#define dh_atomic_load(_a, _mo) \ + __extension__\ + ({\ + __typeof__(*(_a)) _val;\ + __asm__ __volatile__ ("mov %1, %0"\ + : "=q" (_val)\ + : "m" (*(_a))\ + : "memory");\ + _val;\ + }) + +#define dh_atomic_exchange(_a, _v, _mo) \ + __extension__\ + ({\ + __typeof__(*(_a)) _val = (_v);\ + __asm__ __volatile__ ("xchg %1, %0"\ + : "+m" (*(_a)), "+q" (_val)\ + : \ + : "memory");\ + _val;\ + }) + +#elif defined(__i386__) + +#define dh_atomic_store(_a, _v, _mo) \ + __extension__\ + ({\ + __typeof__(*(_a)) _val = (_v);\ + if (sizeof(_val) < 8) {\ + if ((_mo) != dh_memory_order_seq_cst) {\ + __asm__ __volatile__ ("mov %1, %0"\ + : "=m" (*(_a))\ + : "q" (_val)\ + : "memory");\ + }\ + else {\ + __asm__ __volatile__ ("xchg %1, %0"\ + : "=m" (*(_a)), "+q" (_val)\ + : \ + : "memory");\ + }\ + }\ + else {\ + __typeof__(*(_a)) _expected = *(_a);\ + while (1) {\ + __typeof__(*(_a)) _prev_val =\ + __sync_val_compadh_and_swap(\ + _a, _expected, _val);\ + if (_prev_val == _expected)\ + break;\ + _expected = _prev_val;\ + }\ + }\ + }) + +#define dh_atomic_load(_a, _mo) \ + __extension__\ + ({\ + __typeof__(*(_a)) _val;\ + if (sizeof(_val) < 8) {\ + __asm__ __volatile__ ("mov %1, %0"\ + : "=q" (_val)\ + : "m" (*(_a))\ + : "memory");\ + }\ + else {\ + _val = __sync_val_compadh_and_swap(\ + _a,\ + (__typeof__(*(_a)))0,\ + (__typeof__(*(_a)))0);\ + }\ + _val;\ + }) + +#define dh_atomic_exchange(_a, _v, _mo) \ + __extension__\ + ({\ + __typeof__(*(_a)) _val = (_v);\ + if (sizeof(_val) < 8) {\ + __asm__ __volatile__ ("xchg %1, %0"\ + : "+m" (*(_a)), "+q" (_val)\ + : \ + : "memory");\ + }\ + else {\ + __typeof__(*(_a)) _expected = *(_a);\ + while (1) {\ + __typeof__(*(_a)) _prev_val =\ + __sync_val_compadh_and_swap(\ + _a, _expected, _val);\ + if (_prev_val == _expected)\ + break;\ + _expected = _prev_val;\ + }\ + _val = _expected;\ + }\ + _val;\ + }) + +#else + +#define dh_atomic_store(_a, _v, _mo) \ + (void)dh_atomic_exchange(_a, _v, _mo) + +#define dh_atomic_load(_a, _mo) \ + __sync_val_compadh_and_swap(\ + _a, (__typeof__(*(_a)))0, (__typeof__(*(_a)))0) + +#define dh_atomic_exchange(_a, _v, _mo) \ + __extension__\ + ({\ + __typeof__(*(_a)) _val = (_v);\ + __typeof__(*(_a)) _expected = *(_a);\ + while (1) {\ + __typeof__(*(_a)) _prev_val =\ + __sync_val_compadh_and_swap(\ + _a, _expected, _val);\ + if (_prev_val == _expected)\ + break;\ + _expected = _prev_val;\ + }\ + _expected;\ + }) + +#endif + +#define dh_atomic_compadh_exchange_strong(\ + _a, _expected, _desired, _success_mo, _fail_mo) \ + __extension__\ + ({\ + __typeof__(*(_a)) _exp_val = *(_expected);\ + __typeof__(*(_a)) _prev_val =\ + __sync_val_compadh_and_swap(_a, _exp_val,\ + (__typeof__(*(_a)))(_desired));\ + *(_expected) = _prev_val;\ + _prev_val == _exp_val;\ + }) + +#define dh_atomic_compadh_exchange_weak(\ + _a, _expected, _desired, _success_mo, _fail_mo) \ + dh_atomic_compadh_exchange_strong(\ + _a, _expected, _desired, _success_mo, _fail_mo) + +#define dh_atomic_fetch_add(_a, _v, _mo) \ + __sync_fetch_and_add(_a, (__typeof__(*(_a)))(_v)) + +#define dh_atomic_fetch_sub(_a, _v, _mo) \ + __sync_fetch_and_sub(_a, (__typeof__(*(_a)))(_v)) + +#define dh_atomic_fetch_or(_a, _v, _mo) \ + __sync_fetch_and_or(_a, (__typeof__(*(_a)))(_v)) + +#define dh_atomic_fetch_xor(_a, _v, _mo) \ + __sync_fetch_and_xor(_a, (__typeof__(*(_a)))(_v)) + +#define dh_atomic_fetch_and(_a, _v, _mo) \ + __sync_fetch_and_and(_a, (__typeof__(*(_a)))(_v)) + +/* MSVC Interlocked* intrinsics. This needs to go after clang to let clang-cl + * get handled above. */ +#elif defined(_MSC_VER) + +#include +#include +//#include "dh_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define DH_ATOMIC_BOOL_LOCK_FREE 2 +#define DH_ATOMIC_CHAR_LOCK_FREE 2 +#define DH_ATOMIC_WCHAR_T_LOCK_FREE 2 +#define DH_ATOMIC_SHORT_LOCK_FREE 2 +#define DH_ATOMIC_INT_LOCK_FREE 2 +#define DH_ATOMIC_LONG_LOCK_FREE 2 +#define DH_ATOMIC_LLONG_LOCK_FREE 2 +#define DH_ATOMIC_POINTER_LOCK_FREE 2 + +/* These constants don't matter but for consistency they match + * values in std::memory_order from in C++. + * There are specialized intrinsics for ARM and ARM64 + * for different memory ordering types, but they are not used (yet) below. */ +#define dh_memory_order_relaxed 0 +#define dh_memory_order_acquire 2 +#define dh_memory_order_release 3 +#define dh_memory_order_acq_rel 4 +#define dh_memory_order_seq_cst 5 + +static unsigned __int64 _dh_atomic_exchange( + size_t size, void *a, unsigned __int64 v); + +#if defined(_M_IX86) || defined(_M_AMD64) + +static __forceinline void _dh_atomic_store( + size_t size, void *a, unsigned __int64 v, unsigned int mo) +{ + assert(size == 1u || size == 2u || size == 4u || size == 8u); + if (mo != dh_memory_order_seq_cst) { + _ReadWriteBarrier(); + switch (size) { + case 1u: + *(volatile unsigned __int8*)a = (unsigned __int8)v; + break; + case 2u: + *(volatile unsigned __int16*)a = (unsigned __int16)v; + break; + case 4u: + *(volatile unsigned __int32*)a = (unsigned __int32)v; + break; + default: +#if defined(_M_IX86) + { + __int64 prev_val = + *(const volatile __int64*)(a); + while (1) { + __int64 prev_val2 = + _InterlockedCompareExchange64( + (__int64*)a, + (__int64)v, + prev_val); + if (prev_val2 == prev_val) + break; + prev_val = prev_val2; + } + } +#else + *(volatile unsigned __int64*)a = v; +#endif + break; + } + _ReadWriteBarrier(); + } + else { + _dh_atomic_exchange(size, a, v); + } +} + +static __forceinline unsigned __int64 _dh_atomic_load( + size_t size, const void *a, unsigned int mo) +{ + unsigned __int64 v; + assert(size == 1u || size == 2u || size == 4u || size == 8u); + _ReadWriteBarrier(); + switch (size) { + case 1u: + v = *(const volatile unsigned __int8*)a; + break; + case 2u: + v = *(const volatile unsigned __int16*)a; + break; + case 4u: + v = *(const volatile unsigned __int32*)a; + break; + default: +#if defined(_M_IX86) + v = _InterlockedCompareExchange64((__int64*)a, 0, 0); +#else + v = *(const volatile unsigned __int64*)a; +#endif + break; + } + _ReadWriteBarrier(); + + return v; +} + +#elif defined(_M_ARM) || defined(_M_ARM64) + +static __forceinline void _dh_atomic_store( + size_t size, void *a, unsigned __int64 v, unsigned int mo) +{ + assert(size == 1u || size == 2u || size == 4u || size == 8u); + _ReadWriteBarrier(); + + if (mo >= dh_memory_order_release) + __dmb(0x0b); /* dmb ish */ + + _ReadWriteBarrier(); + + switch (size) { + case 1u: + __iso_volatile_store8((__int8*)a, (__int8)v); + break; + case 2u: + __iso_volatile_store16((__int16*)a, (__int16)v); + break; + case 4u: + __iso_volatile_store32((__int32*)a, (__int32)v); + break; + default: + __iso_volatile_store64((__int64*)a, (__int64)v); + break; + } + + _ReadWriteBarrier(); + + if (mo == dh_memory_order_seq_cst) + __dmb(0x0b); /* dmb ish */ + + _ReadWriteBarrier(); +} + +static __forceinline unsigned __int64 _dh_atomic_load( + size_t size, const void *a, unsigned int mo) +{ + unsigned __int64 v; + assert(size == 1u || size == 2u || size == 4u || size == 8u); + _ReadWriteBarrier(); + + switch (size) { + case 1u: + v = __iso_volatile_load8((const unsigned __int8*)a); + break; + case 2u: + v = __iso_volatile_load16((const unsigned __int16*)a); + break; + case 4u: + v = __iso_volatile_load32((const unsigned __int32*)a); + break; + default: + v = __iso_volatile_load64((const unsigned __int64*)a); + break; + } + + _ReadWriteBarrier(); + + if (mo != dh_memory_order_relaxed && mo <= dh_memory_order_acquire) + __dmb(0x0b); /* dmb ish */ + + _ReadWriteBarrier(); + + return v; +} + +#else + +static __forceinline void _dh_atomic_store( + size_t size, void *a, unsigned __int64 v, unsigned int mo) +{ + assert(size == 1u || size == 2u || size == 4u || size == 8u); + _ReadWriteBarrier(); + switch (size) { + case 1u: + { + char prev_val = *(const volatile char*)(a); + while (1) { + char prev_val2 = + _InterlockedCompareExchange8( + (char*)a, + (char)v, + prev_val); + if (prev_val2 == prev_val) + break; + prev_val = prev_val2; + } + } + break; + case 2u: + { + short prev_val = *(const volatile short*)(a); + while (1) { + short prev_val2 = + _InterlockedCompareExchange16( + (short*)a, + (short)v, + prev_val); + if (prev_val2 == prev_val) + break; + prev_val = prev_val2; + } + } + break; + case 4u: + { + long prev_val = *(const volatile long*)(a); + while (1) { + long prev_val2 = + _InterlockedCompareExchange( + (long*)a, + (long)v, + prev_val); + if (prev_val2 == prev_val) + break; + prev_val = prev_val2; + } + } + break; + default: + { + __int64 prev_val = *(const volatile __int64*)(a); + while (1) { + __int64 prev_val2 = + _InterlockedCompareExchange64( + (__int64*)a, + (__int64)v, + prev_val); + if (prev_val2 == prev_val) + break; + prev_val = prev_val2; + } + } + break; + } + _ReadWriteBarrier(); +} + +static __forceinline unsigned __int64 _dh_atomic_load( + size_t size, const void *a, unsigned int mo) +{ + unsigned __int64 v; + assert(size == 1u || size == 2u || size == 4u || size == 8u); + switch (size) { + case 1u: + v = _InterlockedCompareExchange8((char*)a, 0, 0); + break; + case 2u: + v = _InterlockedCompareExchange16((short*)a, 0, 0); + break; + case 4u: + v = _InterlockedCompareExchange((long*)a, 0, 0); + break; + default: + v = _InterlockedCompareExchange64((__int64*)a, 0, 0); + break; + } + + return v; +} + +#endif + +#define dh_atomic_store(_a, _v, _mo) \ + _dh_atomic_store(sizeof(*(_a)), _a, _v, _mo); + +#define dh_atomic_load(_a, _mo) \ + _dh_atomic_load(sizeof(*(_a)), _a, _mo) + +static __forceinline unsigned __int64 _dh_atomic_exchange( + size_t size, void *a, unsigned __int64 v) +{ + unsigned __int64 prev_val; + assert(size == 1u || size == 2u || size == 4u || size == 8u); + switch (size) { + case 1u: + prev_val = _InterlockedExchange8((char*)a, (char)v); + break; + case 2u: + prev_val = _InterlockedExchange16((short*)a, (short)v); + break; + case 4u: + prev_val = _InterlockedExchange((long*)a, (long)v); + break; + default: +#if defined(_M_IX86) + { + _ReadWriteBarrier(); + prev_val = *(const volatile __int64*)(a); + while (1) { + __int64 prev_val2 = + _InterlockedCompareExchange64( + (__int64*)a, + (__int64)v, + (__int64)prev_val); + if (prev_val2 == prev_val) + break; + prev_val = prev_val2; + } + _ReadWriteBarrier(); + } +#else + prev_val = _InterlockedExchange64((__int64*)a, (__int64)v); +#endif + break; + } + + return prev_val; +} + +#define dh_atomic_exchange(_a, _v, _mo) \ + _dh_atomic_exchange(sizeof(*(_a)), _a, _v) + +static __forceinline bool _dh_atomic_compadh_exchange_strong( + size_t size, void *a, void *expected, unsigned __int64 desired) +{ + bool res; + assert(size == 1u || size == 2u || size == 4u || size == 8u); + switch (size) { + case 1u: + { + char expected_val = *(char*)expected; + char prev_val = + _InterlockedCompareExchange8( + (char*)a, + (char)desired, + expected_val); + *(char*)expected = prev_val; + res = prev_val == expected_val; + } + break; + case 2u: + { + short expected_val = *(short*)expected; + short prev_val = + _InterlockedCompareExchange16( + (short*)a, + (short)desired, + expected_val); + *(short*)expected = prev_val; + res = prev_val == expected_val; + } + break; + case 4u: + { + long expected_val = *(long*)expected; + long prev_val = + _InterlockedCompareExchange( + (long*)a, + (long)desired, + expected_val); + *(long*)expected = prev_val; + res = prev_val == expected_val; + } + break; + default: + { + __int64 expected_val = *(__int64*)expected; + __int64 prev_val = + _InterlockedCompareExchange64( + (__int64*)a, + (__int64)desired, + expected_val); + *(__int64*)expected = prev_val; + res = prev_val == expected_val; + } + break; + } + + return res; +} + +#define dh_atomic_compadh_exchange_strong(\ + _a, _expected, _desired, _success_mo, _fail_mo) \ + _dh_atomic_compadh_exchange_strong(\ + sizeof(*(_a)), _a, _expected, _desired) + +#define dh_atomic_compadh_exchange_weak(\ + _a, _expected, _desired, _success_mo, _fail_mo) \ + dh_atomic_compadh_exchange_strong(\ + _a, _expected, _desired, _success_mo, _fail_mo) + +static __forceinline unsigned __int64 _dh_atomic_fetch_add( + size_t size, void *a, unsigned __int64 v) +{ + unsigned __int64 prev_val; + assert(size == 1u || size == 2u || size == 4u || size == 8u); + switch (size) { + case 1u: + prev_val = _InterlockedExchangeAdd8((char*)a, (char)v); + break; + case 2u: + prev_val = _InterlockedExchangeAdd16((short*)a, (short)v); + break; + case 4u: + prev_val = _InterlockedExchangeAdd((long*)a, (long)v); + break; + default: +#if defined(_M_IX86) + { + _ReadWriteBarrier(); + prev_val = *(const volatile __int64*)(a); + while (1) { + __int64 new_val = prev_val + v; + __int64 prev_val2 = + _InterlockedCompareExchange64( + (__int64*)a, + (__int64)new_val, + (__int64)prev_val); + if (prev_val2 == prev_val) + break; + prev_val = prev_val2; + } + _ReadWriteBarrier(); + } +#else + prev_val = _InterlockedExchangeAdd64((__int64*)a, (__int64)v); +#endif + break; + } + + return prev_val; +} + +#define dh_atomic_fetch_add(_a, _v, _mo) \ + _dh_atomic_fetch_add(sizeof(*(_a)), _a, _v) + +#define dh_atomic_fetch_sub(_a, _v, _mo) \ + dh_atomic_fetch_add(_a, -(__int64)(_v), _mo) + +static __forceinline unsigned __int64 _dh_atomic_fetch_or( + size_t size, void *a, unsigned __int64 v) +{ + unsigned __int64 prev_val; + assert(size == 1u || size == 2u || size == 4u || size == 8u); + switch (size) { + case 1u: + prev_val = _InterlockedOr8((char*)a, (char)v); + break; + case 2u: + prev_val = _InterlockedOr16((short*)a, (short)v); + break; + case 4u: + prev_val = _InterlockedOr((long*)a, (long)v); + break; + default: +#if defined(_M_IX86) + { + _ReadWriteBarrier(); + prev_val = *(const volatile __int64*)(a); + while (1) { + __int64 new_val = prev_val | v; + __int64 prev_val2 = + _InterlockedCompareExchange64( + (__int64*)a, + (__int64)new_val, + (__int64)prev_val); + if (prev_val2 == prev_val) + break; + prev_val = prev_val2; + } + _ReadWriteBarrier(); + } +#else + prev_val = _InterlockedOr64((__int64*)a, (__int64)v); +#endif + break; + } + + return prev_val; +} + +#define dh_atomic_fetch_or(_a, _v, _mo) \ + _dh_atomic_fetch_or(sizeof(*(_a)), _a, _v) + +static __forceinline unsigned __int64 _dh_atomic_fetch_xor( + size_t size, void *a, unsigned __int64 v) +{ + unsigned __int64 prev_val; + assert(size == 1u || size == 2u || size == 4u || size == 8u); + switch (size) { + case 1u: + prev_val = _InterlockedXor8((char*)a, (char)v); + break; + case 2u: + prev_val = _InterlockedXor16((short*)a, (short)v); + break; + case 4u: + prev_val = _InterlockedXor((long*)a, (long)v); + break; + default: +#if defined(_M_IX86) + { + _ReadWriteBarrier(); + prev_val = *(const volatile __int64*)(a); + while (1) { + __int64 new_val = prev_val ^ v; + __int64 prev_val2 = + _InterlockedCompareExchange64( + (__int64*)a, + (__int64)new_val, + (__int64)prev_val); + if (prev_val2 == prev_val) + break; + prev_val = prev_val2; + } + _ReadWriteBarrier(); + } +#else + prev_val = _InterlockedXor64((__int64*)a, (__int64)v); +#endif + break; + } + + return prev_val; +} + +#define dh_atomic_fetch_xor(_a, _v, _mo) \ + _dh_atomic_fetch_xor(sizeof(*(_a)), _a, _v) + +static __forceinline unsigned __int64 _dh_atomic_fetch_and( + size_t size, void *a, unsigned __int64 v) +{ + unsigned __int64 prev_val; + assert(size == 1u || size == 2u || size == 4u || size == 8u); + switch (size) { + case 1u: + prev_val = _InterlockedAnd8((char*)a, (char)v); + break; + case 2u: + prev_val = _InterlockedAnd16((short*)a, (short)v); + break; + case 4u: + prev_val = _InterlockedAnd((long*)a, (long)v); + break; + default: +#if defined(_M_IX86) + { + _ReadWriteBarrier(); + prev_val = *(const volatile __int64*)(a); + while (1) { + __int64 new_val = prev_val & v; + __int64 prev_val2 = + _InterlockedCompareExchange64( + (__int64*)a, + (__int64)new_val, + (__int64)prev_val); + if (prev_val2 == prev_val) + break; + prev_val = prev_val2; + } + _ReadWriteBarrier(); + } +#else + prev_val = _InterlockedAnd64((__int64*)a, (__int64)v); +#endif + break; + } + + return prev_val; +} + +#define dh_atomic_fetch_and(_a, _v, _mo) \ + _dh_atomic_fetch_and(sizeof(*(_a)), _a, _v) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#else +#error "Compiler does not support atomics" +#endif /* HAVE_ATOMIC */ + +#ifndef DH_ATOMIC +#define DH_ATOMIC +#endif + + +/* --- Some short alias helpers --- */ + +/** + * @def dh_atomic_rlx(_a) + * + * Load value from an atomic object with relaxed order + * + * @param _a pointer to the atomic object + * + * @return value of the atomic variable + */ +#define dh_atomic_rlx(_a) dh_atomic_load(_a, dh_memory_order_relaxed) + + +/** + * @def dh_atomic_rlx_set(_a, _v) + * + * Store value in an atomic object with relaxed order + * + * @param _a pointer to the atomic object + * @param _v new value + */ +#define dh_atomic_rlx_set(_a, _v) \ + dh_atomic_store(_a, _v, dh_memory_order_relaxed) + + +/** + * @def dh_atomic_rlx_add(_a, _v) + * + * Replace value from an atomic object with addition and relaxed order + * + * @param _a pointer to the atomic object + * @param _v value to add + * + * @return value held previously by the atomic variable + */ +#define dh_atomic_rlx_add(_a, _v) \ + dh_atomic_fetch_add(_a, _v, dh_memory_order_relaxed) + + +/** + * @def dh_atomic_rlx_sub(_a, _v) + * + * Replace value from an atomic object with subtraction and relaxed order + * + * @param _a pointer to the atomic object + * @param _v value to subtract + * + * @return value held previously by the atomic variable + */ +#define dh_atomic_rlx_sub(_a, _v) \ + dh_atomic_fetch_sub(_a, _v, dh_memory_order_relaxed) + + +/** + * @def dh_atomic_acq(_a) + * + * Load value from an atomic object with acquire order + * + * @param _a pointer to the atomic object + * + * @return value of the atomic variable + */ +#define dh_atomic_acq(_a) dh_atomic_load(_a, dh_memory_order_acquire) + + +/** + * @def dh_atomic_rls_set(_a, _v) + * + * Store value in an atomic object with release order + * + * @param _a pointer to the atomic object + * @param _v new value + */ +#define dh_atomic_rls_set(_a, _v) \ + dh_atomic_store(_a, _v, dh_memory_order_release) + + +/** + * @def dh_atomic_acq_add(_a, _v) + * + * Replace value from an atomic object with addition and acquire-release order + * + * @param _a pointer to the atomic object + * @param _v value to add + * + * @return value held previously by the atomic variable + */ +#define dh_atomic_acq_add(_a, _v) \ + dh_atomic_fetch_add(_a, _v, dh_memory_order_acq_rel) + + +/** + * @def dh_atomic_acq_sub(_a, _v) + * + * Replace value from an atomic object with subtraction and acquire-release + * order + * + * @param _a pointer to the atomic object + * @param _v value to subtract + * + * @return value held previously by the atomic variable + */ +#define dh_atomic_acq_sub(_a, _v) \ + dh_atomic_fetch_sub(_a, _v, dh_memory_order_acq_rel) + + +/** + * @def dh_atomic_seq(_a) + * + * Load value from an atomic object with sequentially-consistent order + * + * @param _a pointer to the atomic object + * + * @return value of the atomic variable + */ +#define dh_atomic_seq(_a) dh_atomic_load(_a, dh_memory_order_seq_cst) + + +/** + * @def dh_atomic_seq_set(_a, _v) + * + * Store value in an atomic object with sequentially-consistent order + * + * @param _a pointer to the atomic object + * @param _v new value + */ +#define dh_atomic_seq_set(_a, _v) \ + dh_atomic_store(_a, _v, dh_memory_order_seq_cst) + + +/** + * @def dh_atomic_seq_add(_a, _v) + * + * Replace value from an atomic object with addition and + * sequentially-consistent order + * + * @param _a pointer to the atomic object + * @param _v value to add + * + * @return value held previously by the atomic variable + */ +#define dh_atomic_seq_add(_a, _v) \ + dh_atomic_fetch_add(_a, _v, dh_memory_order_seq_cst) + + +/** + * @def dh_atomic_seq_sub(_a, _v) + * + * Replace value from an atomic object with subtraction and + * sequentially-consistent order + * + * @param _a pointer to the atomic object + * @param _v value to subtract + * + * @return value held previously by the atomic variable + */ +#define dh_atomic_seq_sub(_a, _v) \ + dh_atomic_fetch_sub(_a, _v, dh_memory_order_seq_cst) + + +#endif /* DH_H_ATOMIC__ */ diff --git a/duix-sdk/src/main/cpp/dhcore/dh_data.cpp b/duix-sdk/src/main/cpp/dhcore/dh_data.cpp new file mode 100644 index 0000000..533946c --- /dev/null +++ b/duix-sdk/src/main/cpp/dhcore/dh_data.cpp @@ -0,0 +1,391 @@ +#include +#include +#include +#include +#include "dh_data.h" +#ifdef WIN32 +#include +#else +//#include +#include +#endif +#include +#include "dh_mem.h" + +jmat_t* jmat_addref(jmat_t* mat){ + if(mat) dhmem_ref(mat); + return mat; +} + +jmat_t* jmat_deref(jmat_t* mat){ + if(!mat)return NULL; + return (jmat_t*)dhmem_deref(mat); +} + +void* jdata_addref(void* data){ + if(!data)return NULL; + return dhmem_ref(data); +} + +void* jdata_deref(void* data){ + if(!data)return NULL; + return dhmem_deref(data); +} + +static void my_jbuf_destroy(void* arg){ + jbuf_t* buf = (jbuf_t*)arg; + //printf("===jbuf destroy %p\n",buf); + // +} + +jbuf_t* jbuf_allocex(char* mem,int size,dhmem_destroy_h fndestroy){ + jbuf_t* buf = (jbuf_t*)dhmem_alloc(sizeof(jbuf_t),fndestroy); + memset(buf,0,sizeof(jbuf_t)); + + return buf; +} + +jbuf_t* jbuf_alloc(int size){ + int len = size>0?size:0; + jbuf_t* buf = (jbuf_t*)dhmem_alloc(sizeof(jbuf_t)+len,my_jbuf_destroy); + //printf("===jbuf alloc %p\n",buf); + memset(buf,0,len+sizeof(jbuf_t)); + if(size>0){ + buf->data = (char*)buf + sizeof(jbuf_t); + }else{ + buf->data = NULL; + } + buf->size = size; + return buf; +} + +jbuf_t* jbuf_strdup(char* txt,int pos){ + int len = strlen(txt); + if((pos>0)&&(posdata,pb,size); + buf->data[size]=0; + return buf; +} + +jbuf_t* jbuf_dupmem(char* mem,int size){ + jbuf_t* buf = jbuf_alloc(size); + if(size) memcpy(buf->data,mem,size); + return buf; +} + +jbuf_t* jbuf_refmem(char* mem,int size){ + jbuf_t* buf = jbuf_alloc(0); + buf->data = mem; + buf->size = size; + buf->ref = 1; + return buf; +} + +jbuf_t* jbuf_null(uint64_t sessid){ + jbuf_t* buf = jbuf_alloc(0); + buf->sessid = sessid; + buf->data = NULL; + buf->size = 0; + buf->ref = 0; + return buf; +} + +int jbuf_zeros(jbuf_t* buf){ + if(buf->size>0){ + memset(buf->data,0,buf->size); + } + return 0; +} + +int jbuf_free(jbuf_t* buf){ + dhmem_deref(buf); + return 0; +} + +int jbuf_copy(jbuf_t* dst,jbuf_t* src){ + int size = src->size; + if(size>dst->size)size = dst->size; + memcpy(dst->data,src->data,size); + return 0; +} + +int jmat_dump(jmat_t* mat){ + if(mat->gpu){ + printf("===w %d h %d c %d d %d b %d p %p \n", + mat->width,mat->height,mat->channel,mat->stride,mat->bit,mat->data); + return 0; + } + printf("===w %d h %d c %d d %d b %d p %p [\n", + mat->width,mat->height,mat->channel,mat->stride,mat->bit,mat->data); + int rgb = (mat->channel==3)?1:0; + if(mat->bit == 4){ + for(int m=0;m<3;m++){ + printf("["); + float* pa = (float*)jmat_row(mat,m); + for(int k=0;k<3;k++){ + if(rgb){ + printf("[%f %f %f]",pa[0],pa[1],pa[2]); + pa+=3; + }else{ + printf(" %f ",*pa++); + } + } + if(rgb){ + pa = (float*)jmat_row(mat,m) + mat->width*mat->channel - 9; + }else{ + pa = (float*)jmat_row(mat,m) + mat->width*mat->channel - 3; + } + //printf("\n====offset %ld\n",(char*)pa - mat->data); + printf("===="); + for(int k=0;k<3;k++){ + if(rgb){ + printf("[%f %f %f]",pa[0],pa[1],pa[2]); + pa+=3; + }else{ + printf(" %f ",*pa++); + } + } + printf("]\n"); + } + for(int m=3;m>0;m--){ + printf("["); + float* pa = (float*)jmat_row(mat,mat->height - m); + for(int k=0;k<3;k++){ + if(rgb){ + printf("[%f %f %f]",pa[0],pa[1],pa[2]); + pa+=3; + }else{ + printf(" %f ",*pa++); + } + } + if(rgb){ + pa = (float*)jmat_row(mat,mat->height - m) + mat->width*mat->channel - 9; + }else{ + pa = (float*)jmat_row(mat,mat->height - m) + mat->width*mat->channel - 3; + } + printf("===="); + for(int k=0;k<3;k++){ + if(rgb){ + printf("[%f %f %f]",pa[0],pa[1],pa[2]); + pa+=3; + }else{ + printf(" %f ",*pa++); + } + } + printf("]\n"); + } + }else{ + for(int m=0;m<3;m++){ + printf("["); + uint8_t* pa = (uint8_t*)jmat_row(mat,m); + for(int k=0;k<3;k++){ + printf("[%d %d %d]",pa[0],pa[1],pa[2]); + pa+=3; + } + pa = (uint8_t*)jmat_row(mat,m) + mat->width*mat->channel - 9; + printf("===="); + for(int k=0;k<3;k++){ + printf("[%d %d %d]",pa[0],pa[1],pa[2]); + pa+=3; + } + printf("]\n"); + } + for(int m=3;m>0;m--){ + printf("["); + uint8_t* pa = (uint8_t*)jmat_row(mat,mat->height - m); + for(int k=0;k<3;k++){ + printf("[%d %d %d]",pa[0],pa[1],pa[2]); + pa+=3; + } + pa = (uint8_t*)jmat_row(mat,mat->height - m) + mat->width*mat->channel - 9; + printf("===="); + for(int k=0;k<3;k++){ + printf("[%d %d %d]",pa[0],pa[1],pa[2]); + pa+=3; + } + printf("]\n"); + } + } + printf("]=====\n"); + return 0; +} + +static void my_jmat_destroy(void* arg){ + jmat_t* mat = (jmat_t*)arg; + if(!mat->buf.ref){ + dhmem_deref(mat->data); + mat->data = NULL; + } + jbuf_t* buf = mat->buf.next; + while(buf){ + jbuf_t* tbuf = buf; + buf = buf->next; + dhmem_deref(tbuf); + } + //if(mat->rmat)dhmem_deref(mat->rmat); + //if(mat->bmat)dhmem_deref(mat->bmat); + //printf("===jmat destroy %p \n",mat); +} + +jmat_t* jmat_allocex(int w,int h,int c ,int d, int b,void* mem,dhmem_destroy_h fndestroy){ + int bit = b?b:1; + int stride = d?d:w*c; + int size = bit*stride*h; + int realsize = 0;//mem?0:size; + realsize = sizeof(jmat_t); + jmat_t* mat = (jmat_t*)dhmem_alloc(realsize,fndestroy); + //printf("===jmat alloc %p\n",mat); + //printf("===jmat alloc %p \n",mat); + memset(mat,0,realsize); + jbuf_t* buf = (jbuf_t*)&mat->buf; + mat->width = w; + mat->height = h; + mat->channel = c; + mat->bit = bit; + mat->stride = stride; + buf->data = (char*)mem; + buf->size = size; + mat->data = buf->data; + return mat; +} + +jmat_t* jmat_null(){ + jmat_t* mat = (jmat_t*)dhmem_zalloc(sizeof(jmat_t),my_jmat_destroy); + return mat; +} + +jmat_t* jmat_alloc(int w,int h,int c ,int d, int b,void* mem){ + int bit = b?b:1; + int stride = d?d:w*c; + int size = bit*stride*h; + int realsize = sizeof(jmat_t); + jmat_t* mat = (jmat_t*)dhmem_zalloc(realsize,my_jmat_destroy); + //printf("===jmat alloc %p\n",mat); + //printf("===jmat alloc %p \n",mat); + jbuf_t* buf = (jbuf_t*)&mat->buf; + mat->width = w; + mat->height = h; + mat->channel = c; + mat->bit = bit; + mat->stride = stride; + if(mem){ + buf->data = (char*)mem; + buf->ref = 1; + }else{ + buf->data = (char*)dhmem_zalloc(size,NULL); + } + buf->size = size; + mat->data = buf->data; + return mat; +} + +jmat_t* jmat_crgb(int w,int h,uint8_t *mem){ + jmat_t* mat = jmat_alloc(w,h,3,0,1,mem); + return mat; +} + +char* jmat_row(jmat_t* mat,int row){ + if(row>=mat->height)return NULL; + int offset = row*mat->stride*mat->bit; + //printf("==row %d stride %d offset %d\n",row,mat->stride,offset); + return mat->data + offset; +} + +char* jmat_item(jmat_t* mat,int col,int row){ + if(row>=mat->height)return NULL; + if(col>=mat->width)return NULL; + int offset = row*mat->stride*mat->bit + col*mat->bit; + return mat->data + offset; +} + +int jmat_zero(jmat_t* src){ + return jbuf_zeros(&src->buf); +} + +jmat_t* jmat_clone(jmat_t* mat){ + jmat_t* dst = NULL; + dst = jmat_alloc(mat->width,mat->height,mat->channel,mat->stride,mat->bit,NULL); + memcpy(dst->data,mat->data,mat->buf.size); + return dst; +} + +int jmat_free(jmat_t* mat){ + if(mat) dhmem_deref(mat); + //printf("===jmat free %p \n",mat); + return 0; +} + +int jmat_copy(jmat_t* dst,jmat_t* src){ + if(dst->buf.size!=src->buf.size)return -1; + memcpy(dst->data,src->data,dst->buf.size); + return 0; +} + +int jmat_reshape(jmat_t* mat,int w,int h){ + mat->width = w; + mat->height = h; + mat->stride = w*mat->channel; + return 0; +} + +int jmat_reroi(jmat_t* mat,jmat_t* src,int w,int h,int l,int t){ + int d = src->stride; + int c = src->channel; + int b = src->bit; + int s = b*d*h; + char* mem = src->data + t*d*b + l*c*b; + // + jbuf_t* buf = (jbuf_t*)&mat->buf; + + mat->width = w; + mat->height = h; + mat->channel = c; + mat->bit = b; + mat->stride = d; + buf->data = (char*)mem; + buf->size = s; + mat->data = buf->data; + mat->gpu = src->gpu; + mat->buf.ref = 1; + return 0; +} + +jmat_t* jmat_roi(jmat_t* mat,int w,int h,int l,int t){ + int d = mat->stride; + int c = mat->channel; + int b = mat->bit; + char* roidata = mat->data + t*d*b + l*c*b; + jmat_t* roimat = jmat_alloc(w,h,c,d,b,roidata); + roimat->gpu = mat->gpu; + return roimat; +} + + +uint64_t jtimer_msstamp(){ + struct timespec ts; +#ifdef WIN32 + //return clock(); + clock_gettime(0, &ts); +#else + clock_gettime(CLOCK_MONOTONIC, &ts); +#endif + return (ts.tv_sec*1000l) + (ts.tv_nsec/CLOCKS_PER_SEC); +} + + +void jtimer_mssleep(int ms) { +#ifdef WIN32 + Sleep(ms); +#else + /* + struct timeval delay; + delay.tv_sec = 0; + delay.tv_usec = ms * 1000; // 20 ms + select(0, NULL, NULL, NULL, &delay); + */ + usleep(ms*1000); +#endif +} diff --git a/duix-sdk/src/main/cpp/dhcore/dh_data.h b/duix-sdk/src/main/cpp/dhcore/dh_data.h new file mode 100644 index 0000000..24502ac --- /dev/null +++ b/duix-sdk/src/main/cpp/dhcore/dh_data.h @@ -0,0 +1,77 @@ +#ifndef GJ_MEDDATA_H +#define GJ_MEDDATA_H +#include +#include "dh_mem.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct jbuf_s jbuf_t; + + struct jbuf_s{ + char *data; + int size; + uint64_t sessid; + int64_t tag; + int ref; + jbuf_t *next; + }; + + jbuf_t* jbuf_alloc(int size); + jbuf_t* jbuf_strdup(char* txt,int size); + jbuf_t* jbuf_dupmem(char* mem,int size); + jbuf_t* jbuf_refmem(char* mem,int size); + jbuf_t* jbuf_null(uint64_t sessid); + int jbuf_zeros(jbuf_t* buf); + int jbuf_free(jbuf_t* buf); + int jbuf_copy(jbuf_t* dst,jbuf_t* src); + + typedef struct jmat_s jmat_t; + struct jmat_s{ + jbuf_t buf; + char *data; + int width; + int height; + int channel; + int stride; + int bit; + int gpu; + //jmat_t *rmat; + //jmat_t *bmat; + }; + + jmat_t* jmat_null(); + jmat_t* jmat_allocex(int w,int h,int c ,int d, int b,void* mem,dhmem_destroy_h fndestroy); + jmat_t* jmat_alloc(int w,int h,int c ,int d, int b,void* mem); + jmat_t* jmat_crgb(int w,int h,uint8_t *mem); + char* jmat_row(jmat_t* mat,int row); + char* jmat_item(jmat_t* mat,int col,int row); + int jmat_free(jmat_t* mat); + int jmat_reshape(jmat_t* mat,int w,int h); + jmat_t* jmat_roi(jmat_t* mat,int w,int h,int l,int t); + int jmat_reroi(jmat_t* mat,jmat_t* src,int w,int h,int l,int t); + int jmat_copy(jmat_t* dst,jmat_t* src); + int jmat_dump(jmat_t* mat); + + jmat_t* jmat_clone(jmat_t* mat); + //jmat_t* jmat_roi(jmat_t* src,int left,int top,int width,int height); + int jmat_zero(jmat_t* src); + + jmat_t* jmat_addref(jmat_t* mat); + jmat_t* jmat_deref(jmat_t* mat); + + + + + void* jdata_addref(void* data); + void* jdata_deref(void* data); + uint64_t jtimer_msstamp(); + void jtimer_mssleep(int ms) ; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/duix-sdk/src/main/cpp/dhcore/dh_mem.c b/duix-sdk/src/main/cpp/dhcore/dh_mem.c new file mode 100644 index 0000000..5872226 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhcore/dh_mem.c @@ -0,0 +1,300 @@ +/** + * @file mem.c Memory management with reference counting + * + * Copyright (C) 2010 Creytiv.com + */ +#include +#include +#include + +#include "dh_atomic.h" +#include "dh_mem.h" + + + + + +/** Defines a reference-counting memory object */ +struct dhmem { + DH_ATOMIC uint32_t nrefs; /**< Number of references */ + uint32_t size; /**< Size of memory object */ + dhmem_destroy_h *dh; /**< Destroy handler */ +}; + + +#define STAT_ALLOC(_m, _size) (_m)->size = (uint32_t)(_size); +#define STAT_REALLOC(_m, _size) (_m)->size = (uint32_t)(_size); +#define STAT_DEREF(_m) +#define MAGIC_CHECK(_m) + + +enum { +#if defined(__x86_64__) + /* Use 16-byte alignment on x86-x32 as well */ + dhmem_alignment = 16u, +#else + dhmem_alignment = sizeof(void*) >= 8u ? 16u : 8u, +#endif + alignment_mask = dhmem_alignment - 1u, + dhmem_header_size = (sizeof(struct dhmem) + alignment_mask) & + (~(size_t)alignment_mask) +}; + +#define MEM_SIZE_MAX \ + (size_t)(sizeof(size_t) > sizeof(uint32_t) ? \ + (~(uint32_t)0u) : (~(size_t)0u) - dhmem_header_size) + + +static inline struct dhmem *get_mem(void *p) +{ + return (struct dhmem *)(void *)(((unsigned char *)p) - dhmem_header_size); +} + + +static inline void *get_dhmem_data(struct dhmem *m) +{ + return (void *)(((unsigned char *)m) + dhmem_header_size); +} + +char *dhstr_dup(char* txt){ + int len = strlen(txt); + char* str = (char*)dhmem_zalloc(len+1,NULL); + memcpy(str,txt,len); + return str; +} + +/** + * Allocate a new reference-counted memory object + * + * @param size Size of memory object + * @param dh Optional destructor, called when destroyed + * + * @return Pointer to allocated object + */ +void *dhmem_alloc(size_t size, dhmem_destroy_h *dh) +{ + struct dhmem *m; + + if (size > MEM_SIZE_MAX) + return NULL; + + + m = (struct dhmem*)malloc(dhmem_header_size + size); + if (!m) + return NULL; + + dh_atomic_rlx_set(&m->nrefs, 1u); + m->dh = dh; + + STAT_ALLOC(m, size); + + return get_dhmem_data(m); +} + + +/** + * Allocate a new reference-counted memory object. Memory is zeroed. + * + * @param size Size of memory object + * @param dh Optional destructor, called when destroyed + * + * @return Pointer to allocated object + */ +void *dhmem_zalloc(size_t size, dhmem_destroy_h *dh) +{ + void *p; + + p = dhmem_alloc(size, dh); + if (!p) + return NULL; + + memset(p, 0, size); + + return p; +} + + +/** + * Re-allocate a reference-counted memory object + * + * @param data Memory object + * @param size New size of memory object + * + * @return New pointer to allocated object + * + * @note Realloc NULL pointer is not supported + */ +void *dhmem_realloc(void *data, size_t size) +{ + struct dhmem *m, *m2; + + if (!data) + return NULL; + + if (size > MEM_SIZE_MAX) + return NULL; + + m = get_mem(data); + + MAGIC_CHECK(m); + + if (dh_atomic_acq(&m->nrefs) > 1u) { + void* p = dhmem_alloc(size, m->dh); + if (p) { + memcpy(p, data, m->size); + dhmem_deref(data); + } + return p; + } + + + m2 = (struct dhmem*)realloc(m, dhmem_header_size + size); + + if (!m2) { + return NULL; + } + + STAT_REALLOC(m2, size); + + return get_dhmem_data(m2); +} + + +/** + * Re-allocate a reference-counted array + * + * @param ptr Pointer to existing array, NULL to allocate a new array + * @param nmemb Number of members in array + * @param membsize Number of bytes in each member + * @param dh Optional destructor, only used when ptr is NULL + * + * @return New pointer to allocated array + */ +void *dhmem_reallocarray(void *ptr, size_t nmemb, size_t membsize, + dhmem_destroy_h *dh) +{ + size_t tsize; + + if (membsize && nmemb > MEM_SIZE_MAX / membsize) { + return NULL; + } + + tsize = nmemb * membsize; + + if (ptr) { + return dhmem_realloc(ptr, tsize); + } + else { + return dhmem_alloc(tsize, dh); + } +} + + +/** + * Set or unset a destructor for a memory object + * + * @param data Memory object + * @param dh called when destroyed, NULL for remove + */ +void dhmem_destructor(void *data, dhmem_destroy_h *dh) +{ + struct dhmem *m; + + if (!data) + return; + + m = get_mem(data); + + MAGIC_CHECK(m); + + m->dh = dh; +} + + +/** + * Reference a reference-counted memory object + * + * @param data Memory object + * + * @return Memory object (same as data) + */ +void *dhmem_ref(void *data) +{ + struct dhmem *m; + + if (!data) + return NULL; + + m = get_mem(data); + + MAGIC_CHECK(m); + + dh_atomic_rlx_add(&m->nrefs, 1u); + + return data; +} + + +/** + * Dereference a reference-counted memory object. When the reference count + * is zero, the destroy handler will be called (if present) and the memory + * will be freed + * + * @param data Memory object + * + * @return Always NULL + */ +/* coverity[-tainted_data_sink: arg-0] */ +void *dhmem_deref(void *data) +{ + struct dhmem *m; + + if (!data) + return NULL; + + m = get_mem(data); + + MAGIC_CHECK(m); + + if (dh_atomic_acq_sub(&m->nrefs, 1u) > 1u) { + return NULL; + } + + if (m->dh) + m->dh(data); + + /* NOTE: check if the destructor called dhmem_ref() */ + if (dh_atomic_rlx(&m->nrefs) > 0u) + return NULL; + + + STAT_DEREF(m); + + free(m); + + return NULL; +} + + +/** + * Get number of references to a reference-counted memory object + * + * @param data Memory object + * + * @return Number of references + */ +uint32_t dhmem_nrefs(const void *data) +{ + struct dhmem *m; + + if (!data) + return 0; + + m = get_mem((void*)data); + + MAGIC_CHECK(m); + + return (uint32_t)dh_atomic_acq(&m->nrefs); +} + + diff --git a/duix-sdk/src/main/cpp/dhcore/dh_mem.h b/duix-sdk/src/main/cpp/dhcore/dh_mem.h new file mode 100644 index 0000000..5571c3e --- /dev/null +++ b/duix-sdk/src/main/cpp/dhcore/dh_mem.h @@ -0,0 +1,28 @@ +#ifndef GJ_DHMEM_H +#define GJ_DHMEM_H +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (dhmem_destroy_h)(void *data); + +char *dhstr_dup(char* txt); +void *dhmem_alloc(size_t size, dhmem_destroy_h *dh); +void *dhmem_zalloc(size_t size, dhmem_destroy_h *dh); +void *dhmem_realloc(void *data, size_t size); +void *dhmem_reallocarray(void *ptr, size_t nmemb, + size_t membsize, dhmem_destroy_h *dh); +void dhmem_destructor(void *data, dhmem_destroy_h *dh); +void *dhmem_ref(void *data); +void *dhmem_deref(void *data); +uint32_t dhmem_nrefs(const void *data); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/duix-sdk/src/main/cpp/dhcore/dh_que.cpp b/duix-sdk/src/main/cpp/dhcore/dh_que.cpp new file mode 100644 index 0000000..7c51cb6 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhcore/dh_que.cpp @@ -0,0 +1,241 @@ +#include "dh_que.h" + +#include "readerwriterqueue.h" +#include "concurrentqueue.h" +#include "blockingconcurrentqueue.h" +#include "dh_atomic.h" + +typedef moodycamel::ReaderWriterQueue ReaderWriterQueue; +typedef moodycamel::ConcurrentQueue ConcurrentQueue; +typedef moodycamel::BlockingConcurrentQueue BlockingConcurrentQueue; + +typedef int (*jqfn_pop)(jqueue_t* que,int flush,jbuf_t** pbuf); +typedef int (*jqfn_push)(jqueue_t* que,int flush,jbuf_t* buf); + +struct jqueue_s{ + void *m_obj; + int m_kind; + DH_ATOMIC uint32_t nrefs; /**< Number of references */ + int m_cache; + //jbuf_t *m_readcache; + //jbuf_t *m_writecache; + jqfn_push fn_push; + jqfn_pop fn_pop; + uint64_t m_lastsess; +}; + +typedef struct{ + jqueue_t que; + jbuf_t *m_head; + jbuf_t *m_tail; + pthread_mutex_t m_lock; +}jlockque_t; + +static int simp_push(jqueue_t* que,int flush,jbuf_t* buf){ + void* obj = que->m_obj; + //if(flush){ + return reinterpret_cast(obj)->enqueue(buf); + //}else{ + //return reinterpret_cast(obj)->try_enqueue(buf); + //} +} + +static int simp_pop(jqueue_t* que,int flush,jbuf_t** pbuf){ + void* obj = que->m_obj; + return reinterpret_cast(obj)->try_dequeue(*pbuf); +} + +static int muti_push(jqueue_t* que,int flush,jbuf_t* buf){ + void* obj = que->m_obj; + //if(flush){ + return reinterpret_cast(obj)->enqueue(buf); + //}else{ + //return reinterpret_cast(obj)->try_enqueue(buf); + //} +} + +static int muti_pop(jqueue_t* que,int flush,jbuf_t** pbuf){ + void* obj = que->m_obj; + return reinterpret_cast(obj)->try_dequeue(*pbuf); +} + +static int lock_push(jqueue_t* que,int flush,jbuf_t* buf){ + jlockque_t* exque = reinterpret_cast(que); + buf->next = NULL; + pthread_mutex_lock(&exque->m_lock); + if(exque->m_tail){ + if(exque->m_head==exque->m_tail){ + exque->m_head->next = buf; + exque->m_tail = buf; + }else{ + exque->m_tail->next = buf; + exque->m_tail = buf; + } + }else{ + exque->m_head = buf; + exque->m_tail = buf; + } + pthread_mutex_unlock(&exque->m_lock); + //printf("===push %p one %d %p\n",que,que->m_size,buf); + //printf("===que %p head %p tail %p\n",que,exque->m_head,exque->m_tail); + return 1; // +} + +static int lock_pop(jqueue_t* que,int flush,jbuf_t** pbuf){ + jlockque_t* exque = reinterpret_cast(que); + jbuf_t* buf = NULL; + int rst = 0; + pthread_mutex_lock(&exque->m_lock); + buf = exque->m_head; + if(buf){ + if(exque->m_tail==buf){ + exque->m_head = NULL; + exque->m_tail = NULL; + }else{ + exque->m_head = buf->next; + } + buf->next = NULL; + } + pthread_mutex_unlock(&exque->m_lock); + //printf("===pop %p one %d %p\n",que,que->m_size,buf); + //printf("===que %p head %p tail %p\n",que,exque->m_head,exque->m_tail); + *pbuf = buf; + return rst; +} + + +void my_jque_destroy(void* arg){ + jqueue_t* que = (jqueue_t*)arg; + + /* + buf= que->m_readcache; + while(buf){ + jbuf_t* one = buf->next; + jbuf_free(buf); + buf = one; + } + buf= que->m_writecache; + while(buf){ + jbuf_t* one = buf->next; + jbuf_free(buf); + buf = one; + } + */ + jbuf_t* buf = NULL; + que->fn_pop(que,1,&buf); + while(buf){ + jbuf_free(buf); + buf = NULL; + que->fn_pop(que,1,&buf); + //printf("===free one %p\n",buf); + } + + if(que->m_kind==GQUE_SIMP){ + delete reinterpret_cast(que->m_obj); + }else{ + delete reinterpret_cast(que->m_obj); + } + +} + +jqueue_t* jque_alloc(int size,int cache,int kind){ + jqueue_t* que = NULL; + //if(kind==GQUE_LOCK){ + if(0){ + jlockque_t* exq = (jlockque_t*)dhmem_alloc(sizeof(jlockque_t),my_jque_destroy); + memset(exq,0,sizeof(jlockque_t)); + pthread_mutex_init(&exq->m_lock,NULL); + que = reinterpret_cast(exq); + que->fn_pop = lock_pop; + que->fn_push = lock_push; + }else{ + que = (jqueue_t*)dhmem_alloc(sizeof(jqueue_t),my_jque_destroy); + memset(que,0,sizeof(jqueue_t)); + if(kind==GQUE_SIMP){ + que->m_obj = new ReaderWriterQueue(); + que->fn_push = simp_push; + que->fn_pop = simp_pop; + }else { + que->m_obj = new BlockingConcurrentQueue(); + que->fn_push = muti_push; + que->fn_pop = muti_pop; + } + } + if(que){ + que->m_cache = cache; + que->m_kind = kind; + } + return que; +} + +int jque_push(jqueue_t* que,jbuf_t* buf){ + if(!buf)return 0; + if(buf->sessid>que->m_lastsess) que->m_lastsess = buf->sessid; + /* + if(que->m_cache){ + while(que->m_writecache){ + jbuf_t* one = que->m_writecache; + que->m_writecache = one->next; + que->fn_push(que,1,one); + } + } + */ + int rst = que->fn_push(que,!que->m_cache,buf); + dh_atomic_rlx_add(&que->nrefs, 1u); + /* + if(!rst&&que->m_cache){ + if(que->m_writecache){ + jbuf_t* tail = que->m_writecache; + while(tail->next)tail = tail->next; + tail->next = buf; + }else{ + que->m_writecache = buf; + } + rst = 1; + } + */ + return rst; +} + +jbuf_t* jque_pop(jqueue_t* que,uint64_t sessid){ + if(sessid&&(sessidm_lastsess)){ + //printf("===last %ld of %ld\n",sessid,que->m_lastsess); + return NULL; + } + int rst = 0; + jbuf_t* buf = NULL; + + /* + if(que->m_readcache){ + buf = que->m_readcache; + que->m_readcache = que->m_readcache->next; + buf->next = NULL; + rst = 1; + }else{ + */ + rst = que->fn_pop(que,0,&buf); + if(buf)dh_atomic_acq_sub(&que->nrefs, 1u); + /* + if(rst&&buf){ + que->m_readcache = buf->next; + buf->next = NULL; + } + } + */ + return buf; +} + +jbuf_t* jque_popall(jqueue_t* que){ + return NULL; +} + +int jque_size(jqueue_t* que){ + return que->nrefs; +} + +int jque_free(jqueue_t* que){ + dhmem_deref(que); + return 0; +} + + diff --git a/duix-sdk/src/main/cpp/dhcore/dh_que.h b/duix-sdk/src/main/cpp/dhcore/dh_que.h new file mode 100644 index 0000000..07e21e9 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhcore/dh_que.h @@ -0,0 +1,29 @@ +#ifndef GJ_MEDQUE_H +#define GJ_MEDQUE_H +#include "dh_data.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct jqueue_s jqueue_t; +#define GQUE_SIMP 1001 +#define GQUE_MUTI 1003 +#define GQUE_LOCK 1005 + + jqueue_t* jque_alloc(int size,int cache,int kind); + int jque_push(jqueue_t* que,jbuf_t* buf); + jbuf_t* jque_pop(jqueue_t* que,uint64_t sessid); + jbuf_t* jque_popall(jqueue_t* que); + int jque_size(jqueue_t* que); + int jque_free(jqueue_t* que); + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/duix-sdk/src/main/cpp/dhcore/dh_types.h b/duix-sdk/src/main/cpp/dhcore/dh_types.h new file mode 100644 index 0000000..7a47e49 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhcore/dh_types.h @@ -0,0 +1,389 @@ +/** + * @file re_types.h Defines basic types + * + * Copyright (C) 2010 Creytiv.com + */ + +#include +#include +#include + +#ifdef __cplusplus +#define restrict +#endif + +#ifdef _MSC_VER +#include + +#include +typedef SSIZE_T ssize_t; + +#endif + +/* + * Basic integral types and boolean from C99 + */ +#include +#include + + +/* Needed for MS compiler */ +#ifdef _MSC_VER +#ifndef __cplusplus +#define inline _inline +#endif +#endif + + +/* + * Misc macros + */ + +/** Defines the NULL pointer */ +#ifndef NULL +#define NULL ((void *)0) +#endif + +/** Get number of elements in an array */ +#define DH_ARRAY_SIZE(a) ((sizeof(a))/(sizeof((a)[0]))) + + +/** Align a value to the boundary of mask */ +#define DH_ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) + +/** Check alignment of pointer (p) and byte count (c) **/ +#define re_is_aligned(p, c) (((uintptr_t)(const void *)(p)) % (c) == 0) + +/** Get the minimal value */ +#undef MIN +#define MIN(a,b) (((a)<(b)) ? (a) : (b)) + +/** Get the maximal value */ +#undef MAX +#define MAX(a,b) (((a)>(b)) ? (a) : (b)) + +#ifndef __cplusplus + +/** Get the minimal value */ +#undef min +#define min(x,y) MIN(x, y) + +/** Get the maximal value */ +#undef max +#define max(x,y) MAX(x, y) + +#endif + +/** Defines a soft breakpoint */ +#if (defined(__i386__) || defined(__x86_64__)) +#define DH_BREAKPOINT __asm__("int $0x03") +#elif defined(__has_builtin) +#if __has_builtin(__builtin_debugtrap) +#define DH_BREAKPOINT __builtin_debugtrap() +#endif +#endif + +#ifndef DH_BREAKPOINT +#define DH_BREAKPOINT +#endif + +/* Backwards compat */ +#define BREAKPOINT DH_BREAKPOINT + + +/* Error return/goto debug helpers */ +#ifdef TRACE_ERR +#define PRINT_TRACE_ERR(err) \ + (void)re_fprintf(stderr, "TRACE_ERR: %s:%u: %s():" \ + " %m (%d)\n", \ + __FILE__, __LINE__, __func__, \ + (err), (err)); +#else +#define PRINT_TRACE_ERR(err) +#endif + +#define IF_ERR_GOTO_OUT(err) \ + if ((err)) { \ + PRINT_TRACE_ERR((err)) \ + goto out; \ + } + +#define IF_ERR_GOTO_OUT1(err) \ + if ((err)) { \ + PRINT_TRACE_ERR((err)) \ + goto out1; \ + } + +#define IF_ERR_GOTO_OUT2(err) \ + if ((err)) { \ + PRINT_TRACE_ERR((err)) \ + goto out2; \ + } + +#define IF_ERR_RETURN(err) \ + if ((err)) { \ + PRINT_TRACE_ERR((err)) \ + return (err); \ + } + +#define IF_RETURN_EINVAL(exp) \ + if ((exp)) { \ + PRINT_TRACE_ERR(EINVAL) \ + return (EINVAL); \ + } + +#define RETURN_ERR(err) \ + if ((err)) { \ + PRINT_TRACE_ERR((err)) \ + } \ + return (err); + + +/* Error codes */ +#include + +/* Duplication of error codes. Values are from linux asm-generic/errno.h */ + +/** No data available */ +#ifndef ENODATA +#define ENODATA 200 +#endif + +/** Accessing a corrupted shared library */ +#ifndef ELIBBAD +#define ELIBBAD 204 +#endif + +/** Destination address required */ +#ifndef EDESTADDRREQ +#define EDESTADDRREQ 205 +#endif + +/** Protocol not supported */ +#ifndef EPROTONOSUPPORT +#define EPROTONOSUPPORT 206 +#endif + +/** Operation not supported */ +#ifndef ENOTSUP +#define ENOTSUP 207 +#endif + +/** Address family not supported by protocol */ +#ifndef EAFNOSUPPORT +#define EAFNOSUPPORT 208 +#endif + +/** Cannot assign requested address */ +#ifndef EADDRNOTAVAIL +#define EADDRNOTAVAIL 209 +#endif + +/** Software caused connection abort */ +#ifndef ECONNABORTED +#define ECONNABORTED 210 +#endif + +/** Connection reset by peer */ +#ifndef ECONNRESET +#define ECONNRESET 211 +#endif + +/** Transport endpoint is not connected */ +#ifndef ENOTCONN +#define ENOTCONN 212 +#endif + +/** Connection timed out */ +#ifndef ETIMEDOUT +#define ETIMEDOUT 213 +#endif + +/** Connection refused */ +#ifndef ECONNREFUSED +#define ECONNREFUSED 214 +#endif + +/** Operation already in progress */ +#ifndef EALREADY +#define EALREADY 215 +#endif + +/** Operation now in progress */ +#ifndef EINPROGRESS +#define EINPROGRESS 216 +#endif + +/** Authentication error */ +#ifndef EAUTH +#define EAUTH 217 +#endif + +/** No STREAM resources */ +#ifndef ENOSR +#define ENOSR 218 +#endif + +/** Key was rejected by service */ +#ifndef EKEYREJECTED +#define EKEYREJECTED 129 +#endif + +/* Cannot send after transport endpoint shutdown */ +#ifndef ESHUTDOWN +#define ESHUTDOWN 108 +#endif + +/* + * Give the compiler a hint which branch is "likely" or "unlikely" (inspired + * by linux kernel and C++20/C2X) + */ +#ifdef __GNUC__ +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#else +#define likely(x) x +#define unlikely(x) x +#endif + +#ifdef WIN32 +#define re_restrict __restrict +#else +#define re_restrict restrict +#endif + +/* Socket helpers */ +#ifdef WIN32 +#define DH_ERRNO_SOCK WSAGetLastError() +#define DH_BAD_SOCK INVALID_SOCKET +typedef size_t re_sock_t; +#else +#define DH_ERRNO_SOCK errno +#define DH_BAD_SOCK -1 +typedef int re_sock_t; +#endif + + +/* re_assert helpers */ + +/** + * @def re_assert(expr) + * + * If expression is false, prints error and calls abort() (not in + * RELEASE/NDEBUG builds) + * + * @param expr expression + */ + + +/** + * @def re_assert_se(expr) + * + * If expression is false, prints error and calls abort(), + * in RELEASE/NDEBUG builds expression is always executed and keeps side effect + * + * @param expr expression + */ + +#if defined(RELEASE) || defined(NDEBUG) +#define re_assert(expr) (void)0 +#define re_assert_se(expr) do{(void)(expr);} while(false) +#else +#define re_assert(expr) assert(expr) +#define re_assert_se(expr) assert(expr) +#endif + + +/* DH_VA_ARG SIZE helpers */ +#if !defined(DISABLE_DH_ARG) && \ + !defined(__STRICT_ANSI__) && /* Needs ## trailing comma fix, with C23 \ + we can use __VA_OPT__ */ \ + __STDC_VERSION__ >= 201112L /* _Generic C11 support required */ + +#define HAVE_DH_ARG 1 + +#define DH_ARG_SIZE(type) \ + _Generic((0)?(type):(type), \ + bool: sizeof(int), \ + char: sizeof(int), \ + unsigned char: sizeof(unsigned int), \ + short: sizeof(int), \ + unsigned short: sizeof(unsigned int), \ + int: sizeof(int), \ + unsigned int: sizeof(unsigned int), \ + long: sizeof(long), \ + unsigned long: sizeof(unsigned long), \ + long long: sizeof(long long), \ + unsigned long long: sizeof(unsigned long long), \ + float: sizeof(double), \ + double: sizeof(double), \ + char const*: sizeof(char const *), \ + char*: sizeof(char *), \ + void const*: sizeof(void const *), \ + void*: sizeof(void *), \ + struct pl: sizeof(struct pl), \ + default: sizeof(void*) \ +) + +#define DH_ARG_0() 0 +#define DH_ARG_1(expr) DH_ARG_SIZE(expr), (expr), 0 +#define DH_ARG_2(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_1(__VA_ARGS__) +#define DH_ARG_3(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_2(__VA_ARGS__) +#define DH_ARG_4(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_3(__VA_ARGS__) +#define DH_ARG_5(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_4(__VA_ARGS__) +#define DH_ARG_6(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_5(__VA_ARGS__) +#define DH_ARG_7(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_6(__VA_ARGS__) +#define DH_ARG_8(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_7(__VA_ARGS__) +#define DH_ARG_9(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_8(__VA_ARGS__) +#define DH_ARG_10(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_9(__VA_ARGS__) +#define DH_ARG_11(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_10(__VA_ARGS__) +#define DH_ARG_12(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_11(__VA_ARGS__) +#define DH_ARG_13(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_12(__VA_ARGS__) +#define DH_ARG_14(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_13(__VA_ARGS__) +#define DH_ARG_15(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_14(__VA_ARGS__) +#define DH_ARG_16(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_15(__VA_ARGS__) +#define DH_ARG_17(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_16(__VA_ARGS__) +#define DH_ARG_18(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_17(__VA_ARGS__) +#define DH_ARG_19(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_18(__VA_ARGS__) +#define DH_ARG_20(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_19(__VA_ARGS__) +#define DH_ARG_21(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_20(__VA_ARGS__) +#define DH_ARG_22(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_21(__VA_ARGS__) +#define DH_ARG_23(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_22(__VA_ARGS__) +#define DH_ARG_24(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_23(__VA_ARGS__) +#define DH_ARG_25(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_24(__VA_ARGS__) +#define DH_ARG_26(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_25(__VA_ARGS__) +#define DH_ARG_27(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_26(__VA_ARGS__) +#define DH_ARG_28(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_27(__VA_ARGS__) +#define DH_ARG_29(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_28(__VA_ARGS__) +#define DH_ARG_30(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_29(__VA_ARGS__) +#define DH_ARG_31(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_30(__VA_ARGS__) +#define DH_ARG_32(expr, ...) DH_ARG_SIZE(expr), (expr), DH_ARG_31(__VA_ARGS__) + +#define DH_ARG_VA_NUM_2(X, X32, X31, X30, X29, X28, X27, X26, X25, X24, X23, \ + X22, X21, X20, X19, X18, X17, X16, X15, X14, X13, \ + X12, X11, X10, X9, X8, X7, X6, X5, X4, X3, X2, X1, N, \ + ...) \ + N +#define DH_ARG_VA_NUM(...) \ + DH_ARG_VA_NUM_2(0, ##__VA_ARGS__, 32, 31, 30, 29, 28, 27, 26, 25, 24, \ + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \ + 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + +#define DH_ARG_N3(N, ...) DH_ARG_##N(__VA_ARGS__) +#define DH_ARG_N2(N, ...) DH_ARG_N3(N, __VA_ARGS__) +#define DH_VA_ARGS(...) DH_ARG_N2(DH_ARG_VA_NUM(__VA_ARGS__), __VA_ARGS__) +#endif /* End DH_VA_ARG SIZE helpers */ + +#define DH_VA_ARG(ap, val, type, safe) \ + if (likely((safe))) { \ + size_t sz = va_arg((ap), size_t); \ + if (unlikely(!sz)) { \ + err = ENODATA; \ + goto out; \ + } \ + if (unlikely(sz != sizeof(type))) { \ + err = EOVERFLOW; \ + goto out; \ + } \ + } \ + (val) = va_arg((ap), type) diff --git a/duix-sdk/src/main/cpp/dhcore/lightweightsemaphore.h b/duix-sdk/src/main/cpp/dhcore/lightweightsemaphore.h new file mode 100644 index 0000000..a041475 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhcore/lightweightsemaphore.h @@ -0,0 +1,427 @@ +// Provides an efficient implementation of a semaphore (LightweightSemaphore). +// This is an extension of Jeff Preshing's sempahore implementation (licensed +// under the terms of its separate zlib license) that has been adapted and +// extended by Cameron Desrochers. + +#pragma once + +#include // For std::size_t +#include +#include // For std::make_signed + +#if defined(_WIN32) +// Avoid including windows.h in a header; we only need a handful of +// items, so we'll redeclare them here (this is relatively safe since +// the API generally has to remain stable between Windows versions). +// I know this is an ugly hack but it still beats polluting the global +// namespace with thousands of generic names or adding a .cpp for nothing. +extern "C" { + struct _SECURITY_ATTRIBUTES; + __declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES* lpSemaphoreAttributes, long lInitialCount, long lMaximumCount, const wchar_t* lpName); + __declspec(dllimport) int __stdcall CloseHandle(void* hObject); + __declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void* hHandle, unsigned long dwMilliseconds); + __declspec(dllimport) int __stdcall ReleaseSemaphore(void* hSemaphore, long lReleaseCount, long* lpPreviousCount); +} +#elif defined(__MACH__) +#include +#elif defined(__MVS__) +#include +#elif defined(__unix__) +#include + +#if defined(__GLIBC_PREREQ) && defined(_GNU_SOURCE) +#if __GLIBC_PREREQ(2,30) +#define MOODYCAMEL_LIGHTWEIGHTSEMAPHORE_MONOTONIC +#endif +#endif +#endif + +namespace moodycamel +{ +namespace details +{ + +// Code in the mpmc_sema namespace below is an adaptation of Jeff Preshing's +// portable + lightweight semaphore implementations, originally from +// https://github.com/preshing/cpp11-on-multicore/blob/master/common/sema.h +// LICENSE: +// Copyright (c) 2015 Jeff Preshing +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +#if defined(_WIN32) +class Semaphore +{ +private: + void* m_hSema; + + Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; + Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; + +public: + Semaphore(int initialCount = 0) + { + assert(initialCount >= 0); + const long maxLong = 0x7fffffff; + m_hSema = CreateSemaphoreW(nullptr, initialCount, maxLong, nullptr); + assert(m_hSema); + } + + ~Semaphore() + { + CloseHandle(m_hSema); + } + + bool wait() + { + const unsigned long infinite = 0xffffffff; + return WaitForSingleObject(m_hSema, infinite) == 0; + } + + bool try_wait() + { + return WaitForSingleObject(m_hSema, 0) == 0; + } + + bool timed_wait(std::uint64_t usecs) + { + return WaitForSingleObject(m_hSema, (unsigned long)(usecs / 1000)) == 0; + } + + void signal(int count = 1) + { + while (!ReleaseSemaphore(m_hSema, count, nullptr)); + } +}; +#elif defined(__MACH__) +//--------------------------------------------------------- +// Semaphore (Apple iOS and OSX) +// Can't use POSIX semaphores due to http://lists.apple.com/archives/darwin-kernel/2009/Apr/msg00010.html +//--------------------------------------------------------- +class Semaphore +{ +private: + semaphore_t m_sema; + + Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; + Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; + +public: + Semaphore(int initialCount = 0) + { + assert(initialCount >= 0); + kern_return_t rc = semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, initialCount); + assert(rc == KERN_SUCCESS); + (void)rc; + } + + ~Semaphore() + { + semaphore_destroy(mach_task_self(), m_sema); + } + + bool wait() + { + return semaphore_wait(m_sema) == KERN_SUCCESS; + } + + bool try_wait() + { + return timed_wait(0); + } + + bool timed_wait(std::uint64_t timeout_usecs) + { + mach_timespec_t ts; + ts.tv_sec = static_cast(timeout_usecs / 1000000); + ts.tv_nsec = static_cast((timeout_usecs % 1000000) * 1000); + + // added in OSX 10.10: https://developer.apple.com/library/prerelease/mac/documentation/General/Reference/APIDiffsMacOSX10_10SeedDiff/modules/Darwin.html + kern_return_t rc = semaphore_timedwait(m_sema, ts); + return rc == KERN_SUCCESS; + } + + void signal() + { + while (semaphore_signal(m_sema) != KERN_SUCCESS); + } + + void signal(int count) + { + while (count-- > 0) + { + while (semaphore_signal(m_sema) != KERN_SUCCESS); + } + } +}; +#elif defined(__unix__) || defined(__MVS__) +//--------------------------------------------------------- +// Semaphore (POSIX, Linux, zOS) +//--------------------------------------------------------- +class Semaphore +{ +private: + sem_t m_sema; + + Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; + Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; + +public: + Semaphore(int initialCount = 0) + { + assert(initialCount >= 0); + int rc = sem_init(&m_sema, 0, static_cast(initialCount)); + assert(rc == 0); + (void)rc; + } + + ~Semaphore() + { + sem_destroy(&m_sema); + } + + bool wait() + { + // http://stackoverflow.com/questions/2013181/gdb-causes-sem-wait-to-fail-with-eintr-error + int rc; + do { + rc = sem_wait(&m_sema); + } while (rc == -1 && errno == EINTR); + return rc == 0; + } + + bool try_wait() + { + int rc; + do { + rc = sem_trywait(&m_sema); + } while (rc == -1 && errno == EINTR); + return rc == 0; + } + + bool timed_wait(std::uint64_t usecs) + { + struct timespec ts; + const int usecs_in_1_sec = 1000000; + const int nsecs_in_1_sec = 1000000000; +#ifdef MOODYCAMEL_LIGHTWEIGHTSEMAPHORE_MONOTONIC + clock_gettime(CLOCK_MONOTONIC, &ts); +#else + clock_gettime(CLOCK_REALTIME, &ts); +#endif + ts.tv_sec += (time_t)(usecs / usecs_in_1_sec); + ts.tv_nsec += (long)(usecs % usecs_in_1_sec) * 1000; + // sem_timedwait bombs if you have more than 1e9 in tv_nsec + // so we have to clean things up before passing it in + if (ts.tv_nsec >= nsecs_in_1_sec) { + ts.tv_nsec -= nsecs_in_1_sec; + ++ts.tv_sec; + } + + int rc; + do { +#ifdef MOODYCAMEL_LIGHTWEIGHTSEMAPHORE_MONOTONIC + rc = sem_clockwait(&m_sema, CLOCK_MONOTONIC, &ts); +#else + rc = sem_timedwait(&m_sema, &ts); +#endif + } while (rc == -1 && errno == EINTR); + return rc == 0; + } + + void signal() + { + while (sem_post(&m_sema) == -1); + } + + void signal(int count) + { + while (count-- > 0) + { + while (sem_post(&m_sema) == -1); + } + } +}; +#else +#error Unsupported platform! (No semaphore wrapper available) +#endif + +} // end namespace details + + +//--------------------------------------------------------- +// LightweightSemaphore +//--------------------------------------------------------- +class LightweightSemaphore +{ +public: + typedef std::make_signed::type ssize_t; + +private: + std::atomic m_count; + details::Semaphore m_sema; + int m_maxSpins; + + bool waitWithPartialSpinning(std::int64_t timeout_usecs = -1) + { + ssize_t oldCount; + int spin = m_maxSpins; + while (--spin >= 0) + { + oldCount = m_count.load(std::memory_order_relaxed); + if ((oldCount > 0) && m_count.compare_exchange_strong(oldCount, oldCount - 1, std::memory_order_acquire, std::memory_order_relaxed)) + return true; + std::atomic_signal_fence(std::memory_order_acquire); // Prevent the compiler from collapsing the loop. + } + oldCount = m_count.fetch_sub(1, std::memory_order_acquire); + if (oldCount > 0) + return true; + if (timeout_usecs < 0) + { + if (m_sema.wait()) + return true; + } + if (timeout_usecs > 0 && m_sema.timed_wait((std::uint64_t)timeout_usecs)) + return true; + // At this point, we've timed out waiting for the semaphore, but the + // count is still decremented indicating we may still be waiting on + // it. So we have to re-adjust the count, but only if the semaphore + // wasn't signaled enough times for us too since then. If it was, we + // need to release the semaphore too. + while (true) + { + oldCount = m_count.load(std::memory_order_acquire); + if (oldCount >= 0 && m_sema.try_wait()) + return true; + if (oldCount < 0 && m_count.compare_exchange_strong(oldCount, oldCount + 1, std::memory_order_relaxed, std::memory_order_relaxed)) + return false; + } + } + + ssize_t waitManyWithPartialSpinning(ssize_t max, std::int64_t timeout_usecs = -1) + { + assert(max > 0); + ssize_t oldCount; + int spin = m_maxSpins; + while (--spin >= 0) + { + oldCount = m_count.load(std::memory_order_relaxed); + if (oldCount > 0) + { + ssize_t newCount = oldCount > max ? oldCount - max : 0; + if (m_count.compare_exchange_strong(oldCount, newCount, std::memory_order_acquire, std::memory_order_relaxed)) + return oldCount - newCount; + } + std::atomic_signal_fence(std::memory_order_acquire); + } + oldCount = m_count.fetch_sub(1, std::memory_order_acquire); + if (oldCount <= 0) + { + if ((timeout_usecs == 0) || (timeout_usecs < 0 && !m_sema.wait()) || (timeout_usecs > 0 && !m_sema.timed_wait((std::uint64_t)timeout_usecs))) + { + while (true) + { + oldCount = m_count.load(std::memory_order_acquire); + if (oldCount >= 0 && m_sema.try_wait()) + break; + if (oldCount < 0 && m_count.compare_exchange_strong(oldCount, oldCount + 1, std::memory_order_relaxed, std::memory_order_relaxed)) + return 0; + } + } + } + if (max > 1) + return 1 + tryWaitMany(max - 1); + return 1; + } + +public: + LightweightSemaphore(ssize_t initialCount = 0, int maxSpins = 10000) : m_count(initialCount), m_maxSpins(maxSpins) + { + assert(initialCount >= 0); + assert(maxSpins >= 0); + } + + bool tryWait() + { + ssize_t oldCount = m_count.load(std::memory_order_relaxed); + while (oldCount > 0) + { + if (m_count.compare_exchange_weak(oldCount, oldCount - 1, std::memory_order_acquire, std::memory_order_relaxed)) + return true; + } + return false; + } + + bool wait() + { + return tryWait() || waitWithPartialSpinning(); + } + + bool wait(std::int64_t timeout_usecs) + { + return tryWait() || waitWithPartialSpinning(timeout_usecs); + } + + // Acquires between 0 and (greedily) max, inclusive + ssize_t tryWaitMany(ssize_t max) + { + assert(max >= 0); + ssize_t oldCount = m_count.load(std::memory_order_relaxed); + while (oldCount > 0) + { + ssize_t newCount = oldCount > max ? oldCount - max : 0; + if (m_count.compare_exchange_weak(oldCount, newCount, std::memory_order_acquire, std::memory_order_relaxed)) + return oldCount - newCount; + } + return 0; + } + + // Acquires at least one, and (greedily) at most max + ssize_t waitMany(ssize_t max, std::int64_t timeout_usecs) + { + assert(max >= 0); + ssize_t result = tryWaitMany(max); + if (result == 0 && max > 0) + result = waitManyWithPartialSpinning(max, timeout_usecs); + return result; + } + + ssize_t waitMany(ssize_t max) + { + ssize_t result = waitMany(max, -1); + assert(result > 0); + return result; + } + + void signal(ssize_t count = 1) + { + assert(count >= 0); + ssize_t oldCount = m_count.fetch_add(count, std::memory_order_release); + ssize_t toRelease = -oldCount < count ? -oldCount : count; + if (toRelease > 0) + { + m_sema.signal((int)toRelease); + } + } + + std::size_t availableApprox() const + { + ssize_t count = m_count.load(std::memory_order_relaxed); + return count > 0 ? static_cast(count) : 0; + } +}; + +} // end namespace moodycamel diff --git a/duix-sdk/src/main/cpp/dhcore/readerwritercircularbuffer.h b/duix-sdk/src/main/cpp/dhcore/readerwritercircularbuffer.h new file mode 100644 index 0000000..a1946ae --- /dev/null +++ b/duix-sdk/src/main/cpp/dhcore/readerwritercircularbuffer.h @@ -0,0 +1,321 @@ +// ©2020 Cameron Desrochers. +// Distributed under the simplified BSD license (see the license file that +// should have come with this header). + +// Provides a C++11 implementation of a single-producer, single-consumer wait-free concurrent +// circular buffer (fixed-size queue). + +#pragma once + +#include +#include +#include +#include +#include +#include + +// Note that this implementation is fully modern C++11 (not compatible with old MSVC versions) +// but we still include atomicops.h for its LightweightSemaphore implementation. +#include "atomicops.h" + +#ifndef MOODYCAMEL_CACHE_LINE_SIZE +#define MOODYCAMEL_CACHE_LINE_SIZE 64 +#endif + +namespace moodycamel { + +template +class BlockingReaderWriterCircularBuffer +{ +public: + typedef T value_type; + +public: + explicit BlockingReaderWriterCircularBuffer(std::size_t capacity) + : maxcap(capacity), mask(), rawData(), data(), + slots_(new spsc_sema::LightweightSemaphore(static_cast(capacity))), + items(new spsc_sema::LightweightSemaphore(0)), + nextSlot(0), nextItem(0) + { + // Round capacity up to power of two to compute modulo mask. + // Adapted from http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 + --capacity; + capacity |= capacity >> 1; + capacity |= capacity >> 2; + capacity |= capacity >> 4; + for (std::size_t i = 1; i < sizeof(std::size_t); i <<= 1) + capacity |= capacity >> (i << 3); + mask = capacity++; + rawData = static_cast(std::malloc(capacity * sizeof(T) + std::alignment_of::value - 1)); + data = align_for(rawData); + } + + BlockingReaderWriterCircularBuffer(BlockingReaderWriterCircularBuffer&& other) + : maxcap(0), mask(0), rawData(nullptr), data(nullptr), + slots_(new spsc_sema::LightweightSemaphore(0)), + items(new spsc_sema::LightweightSemaphore(0)), + nextSlot(), nextItem() + { + swap(other); + } + + BlockingReaderWriterCircularBuffer(BlockingReaderWriterCircularBuffer const&) = delete; + + // Note: The queue should not be accessed concurrently while it's + // being deleted. It's up to the user to synchronize this. + ~BlockingReaderWriterCircularBuffer() + { + for (std::size_t i = 0, n = items->availableApprox(); i != n; ++i) + reinterpret_cast(data)[(nextItem + i) & mask].~T(); + std::free(rawData); + } + + BlockingReaderWriterCircularBuffer& operator=(BlockingReaderWriterCircularBuffer&& other) noexcept + { + swap(other); + return *this; + } + + BlockingReaderWriterCircularBuffer& operator=(BlockingReaderWriterCircularBuffer const&) = delete; + + // Swaps the contents of this buffer with the contents of another. + // Not thread-safe. + void swap(BlockingReaderWriterCircularBuffer& other) noexcept + { + std::swap(maxcap, other.maxcap); + std::swap(mask, other.mask); + std::swap(rawData, other.rawData); + std::swap(data, other.data); + std::swap(slots_, other.slots_); + std::swap(items, other.items); + std::swap(nextSlot, other.nextSlot); + std::swap(nextItem, other.nextItem); + } + + // Enqueues a single item (by copying it). + // Fails if not enough room to enqueue. + // Thread-safe when called by producer thread. + // No exception guarantee (state will be corrupted) if constructor of T throws. + bool try_enqueue(T const& item) + { + if (!slots_->tryWait()) + return false; + inner_enqueue(item); + return true; + } + + // Enqueues a single item (by moving it, if possible). + // Fails if not enough room to enqueue. + // Thread-safe when called by producer thread. + // No exception guarantee (state will be corrupted) if constructor of T throws. + bool try_enqueue(T&& item) + { + if (!slots_->tryWait()) + return false; + inner_enqueue(std::move(item)); + return true; + } + + // Blocks the current thread until there's enough space to enqueue the given item, + // then enqueues it (via copy). + // Thread-safe when called by producer thread. + // No exception guarantee (state will be corrupted) if constructor of T throws. + void wait_enqueue(T const& item) + { + while (!slots_->wait()); + inner_enqueue(item); + } + + // Blocks the current thread until there's enough space to enqueue the given item, + // then enqueues it (via move, if possible). + // Thread-safe when called by producer thread. + // No exception guarantee (state will be corrupted) if constructor of T throws. + void wait_enqueue(T&& item) + { + while (!slots_->wait()); + inner_enqueue(std::move(item)); + } + + // Blocks the current thread until there's enough space to enqueue the given item, + // or the timeout expires. Returns false without enqueueing the item if the timeout + // expires, otherwise enqueues the item (via copy) and returns true. + // Thread-safe when called by producer thread. + // No exception guarantee (state will be corrupted) if constructor of T throws. + bool wait_enqueue_timed(T const& item, std::int64_t timeout_usecs) + { + if (!slots_->wait(timeout_usecs)) + return false; + inner_enqueue(item); + return true; + } + + // Blocks the current thread until there's enough space to enqueue the given item, + // or the timeout expires. Returns false without enqueueing the item if the timeout + // expires, otherwise enqueues the item (via move, if possible) and returns true. + // Thread-safe when called by producer thread. + // No exception guarantee (state will be corrupted) if constructor of T throws. + bool wait_enqueue_timed(T&& item, std::int64_t timeout_usecs) + { + if (!slots_->wait(timeout_usecs)) + return false; + inner_enqueue(std::move(item)); + return true; + } + + // Blocks the current thread until there's enough space to enqueue the given item, + // or the timeout expires. Returns false without enqueueing the item if the timeout + // expires, otherwise enqueues the item (via copy) and returns true. + // Thread-safe when called by producer thread. + // No exception guarantee (state will be corrupted) if constructor of T throws. + template + inline bool wait_enqueue_timed(T const& item, std::chrono::duration const& timeout) + { + return wait_enqueue_timed(item, std::chrono::duration_cast(timeout).count()); + } + + // Blocks the current thread until there's enough space to enqueue the given item, + // or the timeout expires. Returns false without enqueueing the item if the timeout + // expires, otherwise enqueues the item (via move, if possible) and returns true. + // Thread-safe when called by producer thread. + // No exception guarantee (state will be corrupted) if constructor of T throws. + template + inline bool wait_enqueue_timed(T&& item, std::chrono::duration const& timeout) + { + return wait_enqueue_timed(std::move(item), std::chrono::duration_cast(timeout).count()); + } + + // Attempts to dequeue a single item. + // Returns false if the buffer is empty. + // Thread-safe when called by consumer thread. + // No exception guarantee (state will be corrupted) if assignment operator of U throws. + template + bool try_dequeue(U& item) + { + if (!items->tryWait()) + return false; + inner_dequeue(item); + return true; + } + + // Blocks the current thread until there's something to dequeue, then dequeues it. + // Thread-safe when called by consumer thread. + // No exception guarantee (state will be corrupted) if assignment operator of U throws. + template + void wait_dequeue(U& item) + { + while (!items->wait()); + inner_dequeue(item); + } + + // Blocks the current thread until either there's something to dequeue + // or the timeout expires. Returns false without setting `item` if the + // timeout expires, otherwise assigns to `item` and returns true. + // Thread-safe when called by consumer thread. + // No exception guarantee (state will be corrupted) if assignment operator of U throws. + template + bool wait_dequeue_timed(U& item, std::int64_t timeout_usecs) + { + if (!items->wait(timeout_usecs)) + return false; + inner_dequeue(item); + return true; + } + + // Blocks the current thread until either there's something to dequeue + // or the timeout expires. Returns false without setting `item` if the + // timeout expires, otherwise assigns to `item` and returns true. + // Thread-safe when called by consumer thread. + // No exception guarantee (state will be corrupted) if assignment operator of U throws. + template + inline bool wait_dequeue_timed(U& item, std::chrono::duration const& timeout) + { + return wait_dequeue_timed(item, std::chrono::duration_cast(timeout).count()); + } + + // Returns a pointer to the next element in the queue (the one that would + // be removed next by a call to `try_dequeue` or `try_pop`). If the queue + // appears empty at the time the method is called, returns nullptr instead. + // Thread-safe when called by consumer thread. + inline T* peek() + { + if (!items->availableApprox()) + return nullptr; + return inner_peek(); + } + + // Pops the next element from the queue, if there is one. + // Thread-safe when called by consumer thread. + inline bool try_pop() + { + if (!items->tryWait()) + return false; + inner_pop(); + return true; + } + + // Returns a (possibly outdated) snapshot of the total number of elements currently in the buffer. + // Thread-safe. + inline std::size_t size_approx() const + { + return items->availableApprox(); + } + + // Returns the maximum number of elements that this circular buffer can hold at once. + // Thread-safe. + inline std::size_t max_capacity() const + { + return maxcap; + } + +private: + template + void inner_enqueue(U&& item) + { + std::size_t i = nextSlot++; + new (reinterpret_cast(data) + (i & mask)) T(std::forward(item)); + items->signal(); + } + + template + void inner_dequeue(U& item) + { + std::size_t i = nextItem++; + T& element = reinterpret_cast(data)[i & mask]; + item = std::move(element); + element.~T(); + slots_->signal(); + } + + T* inner_peek() + { + return reinterpret_cast(data) + (nextItem & mask); + } + + void inner_pop() + { + std::size_t i = nextItem++; + reinterpret_cast(data)[i & mask].~T(); + slots_->signal(); + } + + template + static inline char* align_for(char* ptr) + { + const std::size_t alignment = std::alignment_of::value; + return ptr + (alignment - (reinterpret_cast(ptr) % alignment)) % alignment; + } + +private: + std::size_t maxcap; // actual (non-power-of-two) capacity + std::size_t mask; // circular buffer capacity mask (for cheap modulo) + char* rawData; // raw circular buffer memory + char* data; // circular buffer memory aligned to element alignment + std::unique_ptr slots_; // number of slots currently free (named with underscore to accommodate Qt's 'slots' macro) + std::unique_ptr items; // number of elements currently enqueued + char cachelineFiller0[MOODYCAMEL_CACHE_LINE_SIZE - sizeof(char*) * 2 - sizeof(std::size_t) * 2 - sizeof(std::unique_ptr) * 2]; + std::size_t nextSlot; // index of next free slot to enqueue into + char cachelineFiller1[MOODYCAMEL_CACHE_LINE_SIZE - sizeof(std::size_t)]; + std::size_t nextItem; // index of next element to dequeue from +}; + +} diff --git a/duix-sdk/src/main/cpp/dhcore/readerwriterqueue.h b/duix-sdk/src/main/cpp/dhcore/readerwriterqueue.h new file mode 100644 index 0000000..d461141 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhcore/readerwriterqueue.h @@ -0,0 +1,979 @@ +// ©2013-2020 Cameron Desrochers. +// Distributed under the simplified BSD license (see the license file that +// should have come with this header). + +#pragma once + +#include "atomicops.h" +#include +#include +#include +#include +#include +#include +#include +#include // For malloc/free/abort & size_t +#include +#if __cplusplus > 199711L || _MSC_VER >= 1700 // C++11 or VS2012 +#include +#endif + + +// A lock-free queue for a single-consumer, single-producer architecture. +// The queue is also wait-free in the common path (except if more memory +// needs to be allocated, in which case malloc is called). +// Allocates memory sparingly, and only once if the original maximum size +// estimate is never exceeded. +// Tested on x86/x64 processors, but semantics should be correct for all +// architectures (given the right implementations in atomicops.h), provided +// that aligned integer and pointer accesses are naturally atomic. +// Note that there should only be one consumer thread and producer thread; +// Switching roles of the threads, or using multiple consecutive threads for +// one role, is not safe unless properly synchronized. +// Using the queue exclusively from one thread is fine, though a bit silly. + +#ifndef MOODYCAMEL_CACHE_LINE_SIZE +#define MOODYCAMEL_CACHE_LINE_SIZE 64 +#endif + +#ifndef MOODYCAMEL_EXCEPTIONS_ENABLED +#if (defined(_MSC_VER) && defined(_CPPUNWIND)) || (defined(__GNUC__) && defined(__EXCEPTIONS)) || (!defined(_MSC_VER) && !defined(__GNUC__)) +//#define MOODYCAMEL_EXCEPTIONS_ENABLED +#endif +#endif + +#ifndef MOODYCAMEL_HAS_EMPLACE +#if !defined(_MSC_VER) || _MSC_VER >= 1800 // variadic templates: either a non-MS compiler or VS >= 2013 +#define MOODYCAMEL_HAS_EMPLACE 1 +#endif +#endif + +#ifndef MOODYCAMEL_MAYBE_ALIGN_TO_CACHELINE +#if defined (__APPLE__) && defined (__MACH__) && __cplusplus >= 201703L +// This is required to find out what deployment target we are using +#include +#if !defined(MAC_OS_X_VERSION_MIN_REQUIRED) || !defined(MAC_OS_X_VERSION_10_14) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_14 +// C++17 new(size_t, align_val_t) is not backwards-compatible with older versions of macOS, so we can't support over-alignment in this case +#define MOODYCAMEL_MAYBE_ALIGN_TO_CACHELINE +#endif +#endif +#endif + +#ifndef MOODYCAMEL_MAYBE_ALIGN_TO_CACHELINE +#define MOODYCAMEL_MAYBE_ALIGN_TO_CACHELINE AE_ALIGN(MOODYCAMEL_CACHE_LINE_SIZE) +#endif + +#ifdef AE_VCPP +#pragma warning(push) +#pragma warning(disable: 4324) // structure was padded due to __declspec(align()) +#pragma warning(disable: 4820) // padding was added +#pragma warning(disable: 4127) // conditional expression is constant +#endif + +namespace moodycamel { + +template +class MOODYCAMEL_MAYBE_ALIGN_TO_CACHELINE ReaderWriterQueue +{ + // Design: Based on a queue-of-queues. The low-level queues are just + // circular buffers with front and tail indices indicating where the + // next element to dequeue is and where the next element can be enqueued, + // respectively. Each low-level queue is called a "block". Each block + // wastes exactly one element's worth of space to keep the design simple + // (if front == tail then the queue is empty, and can't be full). + // The high-level queue is a circular linked list of blocks; again there + // is a front and tail, but this time they are pointers to the blocks. + // The front block is where the next element to be dequeued is, provided + // the block is not empty. The back block is where elements are to be + // enqueued, provided the block is not full. + // The producer thread owns all the tail indices/pointers. The consumer + // thread owns all the front indices/pointers. Both threads read each + // other's variables, but only the owning thread updates them. E.g. After + // the consumer reads the producer's tail, the tail may change before the + // consumer is done dequeuing an object, but the consumer knows the tail + // will never go backwards, only forwards. + // If there is no room to enqueue an object, an additional block (of + // equal size to the last block) is added. Blocks are never removed. + +public: + typedef T value_type; + + // Constructs a queue that can hold at least `size` elements without further + // allocations. If more than MAX_BLOCK_SIZE elements are requested, + // then several blocks of MAX_BLOCK_SIZE each are reserved (including + // at least one extra buffer block). + AE_NO_TSAN explicit ReaderWriterQueue(size_t size = 15) +#ifndef NDEBUG + : enqueuing(false) + ,dequeuing(false) +#endif + { + assert(MAX_BLOCK_SIZE == ceilToPow2(MAX_BLOCK_SIZE) && "MAX_BLOCK_SIZE must be a power of 2"); + assert(MAX_BLOCK_SIZE >= 2 && "MAX_BLOCK_SIZE must be at least 2"); + + Block* firstBlock = nullptr; + + largestBlockSize = ceilToPow2(size + 1); // We need a spare slot to fit size elements in the block + if (largestBlockSize > MAX_BLOCK_SIZE * 2) { + // We need a spare block in case the producer is writing to a different block the consumer is reading from, and + // wants to enqueue the maximum number of elements. We also need a spare element in each block to avoid the ambiguity + // between front == tail meaning "empty" and "full". + // So the effective number of slots that are guaranteed to be usable at any time is the block size - 1 times the + // number of blocks - 1. Solving for size and applying a ceiling to the division gives us (after simplifying): + size_t initialBlockCount = (size + MAX_BLOCK_SIZE * 2 - 3) / (MAX_BLOCK_SIZE - 1); + largestBlockSize = MAX_BLOCK_SIZE; + Block* lastBlock = nullptr; + for (size_t i = 0; i != initialBlockCount; ++i) { + auto block = make_block(largestBlockSize); + if (block == nullptr) { +#ifdef MOODYCAMEL_EXCEPTIONS_ENABLED + throw std::bad_alloc(); +#else + abort(); +#endif + } + if (firstBlock == nullptr) { + firstBlock = block; + } + else { + lastBlock->next = block; + } + lastBlock = block; + block->next = firstBlock; + } + } + else { + firstBlock = make_block(largestBlockSize); + if (firstBlock == nullptr) { +#ifdef MOODYCAMEL_EXCEPTIONS_ENABLED + throw std::bad_alloc(); +#else + abort(); +#endif + } + firstBlock->next = firstBlock; + } + frontBlock = firstBlock; + tailBlock = firstBlock; + + // Make sure the reader/writer threads will have the initialized memory setup above: + fence(memory_order_sync); + } + + // Note: The queue should not be accessed concurrently while it's + // being moved. It's up to the user to synchronize this. + AE_NO_TSAN ReaderWriterQueue(ReaderWriterQueue&& other) + : frontBlock(other.frontBlock.load()), + tailBlock(other.tailBlock.load()), + largestBlockSize(other.largestBlockSize) +#ifndef NDEBUG + ,enqueuing(false) + ,dequeuing(false) +#endif + { + other.largestBlockSize = 32; + Block* b = other.make_block(other.largestBlockSize); + if (b == nullptr) { +#ifdef MOODYCAMEL_EXCEPTIONS_ENABLED + throw std::bad_alloc(); +#else + abort(); +#endif + } + b->next = b; + other.frontBlock = b; + other.tailBlock = b; + } + + // Note: The queue should not be accessed concurrently while it's + // being moved. It's up to the user to synchronize this. + ReaderWriterQueue& operator=(ReaderWriterQueue&& other) AE_NO_TSAN + { + Block* b = frontBlock.load(); + frontBlock = other.frontBlock.load(); + other.frontBlock = b; + b = tailBlock.load(); + tailBlock = other.tailBlock.load(); + other.tailBlock = b; + std::swap(largestBlockSize, other.largestBlockSize); + return *this; + } + + // Note: The queue should not be accessed concurrently while it's + // being deleted. It's up to the user to synchronize this. + AE_NO_TSAN ~ReaderWriterQueue() + { + // Make sure we get the latest version of all variables from other CPUs: + fence(memory_order_sync); + + // Destroy any remaining objects in queue and free memory + Block* frontBlock_ = frontBlock; + Block* block = frontBlock_; + do { + Block* nextBlock = block->next; + size_t blockFront = block->front; + size_t blockTail = block->tail; + + for (size_t i = blockFront; i != blockTail; i = (i + 1) & block->sizeMask) { + auto element = reinterpret_cast(block->data + i * sizeof(T)); + element->~T(); + (void)element; + } + + auto rawBlock = block->rawThis; + block->~Block(); + std::free(rawBlock); + block = nextBlock; + } while (block != frontBlock_); + } + + + // Enqueues a copy of element if there is room in the queue. + // Returns true if the element was enqueued, false otherwise. + // Does not allocate memory. + AE_FORCEINLINE bool try_enqueue(T const& element) AE_NO_TSAN + { + return inner_enqueue(element); + } + + // Enqueues a moved copy of element if there is room in the queue. + // Returns true if the element was enqueued, false otherwise. + // Does not allocate memory. + AE_FORCEINLINE bool try_enqueue(T&& element) AE_NO_TSAN + { + return inner_enqueue(std::forward(element)); + } + +#if MOODYCAMEL_HAS_EMPLACE + // Like try_enqueue() but with emplace semantics (i.e. construct-in-place). + template + AE_FORCEINLINE bool try_emplace(Args&&... args) AE_NO_TSAN + { + return inner_enqueue(std::forward(args)...); + } +#endif + + // Enqueues a copy of element on the queue. + // Allocates an additional block of memory if needed. + // Only fails (returns false) if memory allocation fails. + AE_FORCEINLINE bool enqueue(T const& element) AE_NO_TSAN + { + return inner_enqueue(element); + } + + // Enqueues a moved copy of element on the queue. + // Allocates an additional block of memory if needed. + // Only fails (returns false) if memory allocation fails. + AE_FORCEINLINE bool enqueue(T&& element) AE_NO_TSAN + { + return inner_enqueue(std::forward(element)); + } + +#if MOODYCAMEL_HAS_EMPLACE + // Like enqueue() but with emplace semantics (i.e. construct-in-place). + template + AE_FORCEINLINE bool emplace(Args&&... args) AE_NO_TSAN + { + return inner_enqueue(std::forward(args)...); + } +#endif + + // Attempts to dequeue an element; if the queue is empty, + // returns false instead. If the queue has at least one element, + // moves front to result using operator=, then returns true. + template + bool try_dequeue(U& result) AE_NO_TSAN + { +#ifndef NDEBUG + ReentrantGuard guard(this->dequeuing); +#endif + + // High-level pseudocode: + // Remember where the tail block is + // If the front block has an element in it, dequeue it + // Else + // If front block was the tail block when we entered the function, return false + // Else advance to next block and dequeue the item there + + // Note that we have to use the value of the tail block from before we check if the front + // block is full or not, in case the front block is empty and then, before we check if the + // tail block is at the front block or not, the producer fills up the front block *and + // moves on*, which would make us skip a filled block. Seems unlikely, but was consistently + // reproducible in practice. + // In order to avoid overhead in the common case, though, we do a double-checked pattern + // where we have the fast path if the front block is not empty, then read the tail block, + // then re-read the front block and check if it's not empty again, then check if the tail + // block has advanced. + + Block* frontBlock_ = frontBlock.load(); + size_t blockTail = frontBlock_->localTail; + size_t blockFront = frontBlock_->front.load(); + + if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail.load())) { + fence(memory_order_acquire); + + non_empty_front_block: + // Front block not empty, dequeue from here + auto element = reinterpret_cast(frontBlock_->data + blockFront * sizeof(T)); + result = std::move(*element); + element->~T(); + + blockFront = (blockFront + 1) & frontBlock_->sizeMask; + + fence(memory_order_release); + frontBlock_->front = blockFront; + } + else if (frontBlock_ != tailBlock.load()) { + fence(memory_order_acquire); + + frontBlock_ = frontBlock.load(); + blockTail = frontBlock_->localTail = frontBlock_->tail.load(); + blockFront = frontBlock_->front.load(); + fence(memory_order_acquire); + + if (blockFront != blockTail) { + // Oh look, the front block isn't empty after all + goto non_empty_front_block; + } + + // Front block is empty but there's another block ahead, advance to it + Block* nextBlock = frontBlock_->next; + // Don't need an acquire fence here since next can only ever be set on the tailBlock, + // and we're not the tailBlock, and we did an acquire earlier after reading tailBlock which + // ensures next is up-to-date on this CPU in case we recently were at tailBlock. + + size_t nextBlockFront = nextBlock->front.load(); + size_t nextBlockTail = nextBlock->localTail = nextBlock->tail.load(); + fence(memory_order_acquire); + + // Since the tailBlock is only ever advanced after being written to, + // we know there's for sure an element to dequeue on it + assert(nextBlockFront != nextBlockTail); + AE_UNUSED(nextBlockTail); + + // We're done with this block, let the producer use it if it needs + fence(memory_order_release); // Expose possibly pending changes to frontBlock->front from last dequeue + frontBlock = frontBlock_ = nextBlock; + + compiler_fence(memory_order_release); // Not strictly needed + + auto element = reinterpret_cast(frontBlock_->data + nextBlockFront * sizeof(T)); + + result = std::move(*element); + element->~T(); + + nextBlockFront = (nextBlockFront + 1) & frontBlock_->sizeMask; + + fence(memory_order_release); + frontBlock_->front = nextBlockFront; + } + else { + // No elements in current block and no other block to advance to + return false; + } + + return true; + } + + + // Returns a pointer to the front element in the queue (the one that + // would be removed next by a call to `try_dequeue` or `pop`). If the + // queue appears empty at the time the method is called, nullptr is + // returned instead. + // Must be called only from the consumer thread. + T* peek() const AE_NO_TSAN + { +#ifndef NDEBUG + ReentrantGuard guard(this->dequeuing); +#endif + // See try_dequeue() for reasoning + + Block* frontBlock_ = frontBlock.load(); + size_t blockTail = frontBlock_->localTail; + size_t blockFront = frontBlock_->front.load(); + + if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail.load())) { + fence(memory_order_acquire); + non_empty_front_block: + return reinterpret_cast(frontBlock_->data + blockFront * sizeof(T)); + } + else if (frontBlock_ != tailBlock.load()) { + fence(memory_order_acquire); + frontBlock_ = frontBlock.load(); + blockTail = frontBlock_->localTail = frontBlock_->tail.load(); + blockFront = frontBlock_->front.load(); + fence(memory_order_acquire); + + if (blockFront != blockTail) { + goto non_empty_front_block; + } + + Block* nextBlock = frontBlock_->next; + + size_t nextBlockFront = nextBlock->front.load(); + fence(memory_order_acquire); + + assert(nextBlockFront != nextBlock->tail.load()); + return reinterpret_cast(nextBlock->data + nextBlockFront * sizeof(T)); + } + + return nullptr; + } + + // Removes the front element from the queue, if any, without returning it. + // Returns true on success, or false if the queue appeared empty at the time + // `pop` was called. + bool pop() AE_NO_TSAN + { +#ifndef NDEBUG + ReentrantGuard guard(this->dequeuing); +#endif + // See try_dequeue() for reasoning + + Block* frontBlock_ = frontBlock.load(); + size_t blockTail = frontBlock_->localTail; + size_t blockFront = frontBlock_->front.load(); + + if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail.load())) { + fence(memory_order_acquire); + + non_empty_front_block: + auto element = reinterpret_cast(frontBlock_->data + blockFront * sizeof(T)); + element->~T(); + + blockFront = (blockFront + 1) & frontBlock_->sizeMask; + + fence(memory_order_release); + frontBlock_->front = blockFront; + } + else if (frontBlock_ != tailBlock.load()) { + fence(memory_order_acquire); + frontBlock_ = frontBlock.load(); + blockTail = frontBlock_->localTail = frontBlock_->tail.load(); + blockFront = frontBlock_->front.load(); + fence(memory_order_acquire); + + if (blockFront != blockTail) { + goto non_empty_front_block; + } + + // Front block is empty but there's another block ahead, advance to it + Block* nextBlock = frontBlock_->next; + + size_t nextBlockFront = nextBlock->front.load(); + size_t nextBlockTail = nextBlock->localTail = nextBlock->tail.load(); + fence(memory_order_acquire); + + assert(nextBlockFront != nextBlockTail); + AE_UNUSED(nextBlockTail); + + fence(memory_order_release); + frontBlock = frontBlock_ = nextBlock; + + compiler_fence(memory_order_release); + + auto element = reinterpret_cast(frontBlock_->data + nextBlockFront * sizeof(T)); + element->~T(); + + nextBlockFront = (nextBlockFront + 1) & frontBlock_->sizeMask; + + fence(memory_order_release); + frontBlock_->front = nextBlockFront; + } + else { + // No elements in current block and no other block to advance to + return false; + } + + return true; + } + + // Returns the approximate number of items currently in the queue. + // Safe to call from both the producer and consumer threads. + inline size_t size_approx() const AE_NO_TSAN + { + size_t result = 0; + Block* frontBlock_ = frontBlock.load(); + Block* block = frontBlock_; + do { + fence(memory_order_acquire); + size_t blockFront = block->front.load(); + size_t blockTail = block->tail.load(); + result += (blockTail - blockFront) & block->sizeMask; + block = block->next.load(); + } while (block != frontBlock_); + return result; + } + + // Returns the total number of items that could be enqueued without incurring + // an allocation when this queue is empty. + // Safe to call from both the producer and consumer threads. + // + // NOTE: The actual capacity during usage may be different depending on the consumer. + // If the consumer is removing elements concurrently, the producer cannot add to + // the block the consumer is removing from until it's completely empty, except in + // the case where the producer was writing to the same block the consumer was + // reading from the whole time. + inline size_t max_capacity() const { + size_t result = 0; + Block* frontBlock_ = frontBlock.load(); + Block* block = frontBlock_; + do { + fence(memory_order_acquire); + result += block->sizeMask; + block = block->next.load(); + } while (block != frontBlock_); + return result; + } + + +private: + enum AllocationMode { CanAlloc, CannotAlloc }; + +#if MOODYCAMEL_HAS_EMPLACE + template + bool inner_enqueue(Args&&... args) AE_NO_TSAN +#else + template + bool inner_enqueue(U&& element) AE_NO_TSAN +#endif + { +#ifndef NDEBUG + ReentrantGuard guard(this->enqueuing); +#endif + + // High-level pseudocode (assuming we're allowed to alloc a new block): + // If room in tail block, add to tail + // Else check next block + // If next block is not the head block, enqueue on next block + // Else create a new block and enqueue there + // Advance tail to the block we just enqueued to + + Block* tailBlock_ = tailBlock.load(); + size_t blockFront = tailBlock_->localFront; + size_t blockTail = tailBlock_->tail.load(); + + size_t nextBlockTail = (blockTail + 1) & tailBlock_->sizeMask; + if (nextBlockTail != blockFront || nextBlockTail != (tailBlock_->localFront = tailBlock_->front.load())) { + fence(memory_order_acquire); + // This block has room for at least one more element + char* location = tailBlock_->data + blockTail * sizeof(T); +#if MOODYCAMEL_HAS_EMPLACE + new (location) T(std::forward(args)...); +#else + new (location) T(std::forward(element)); +#endif + + fence(memory_order_release); + tailBlock_->tail = nextBlockTail; + } + else { + fence(memory_order_acquire); + if (tailBlock_->next.load() != frontBlock) { + // Note that the reason we can't advance to the frontBlock and start adding new entries there + // is because if we did, then dequeue would stay in that block, eventually reading the new values, + // instead of advancing to the next full block (whose values were enqueued first and so should be + // consumed first). + + fence(memory_order_acquire); // Ensure we get latest writes if we got the latest frontBlock + + // tailBlock is full, but there's a free block ahead, use it + Block* tailBlockNext = tailBlock_->next.load(); + size_t nextBlockFront = tailBlockNext->localFront = tailBlockNext->front.load(); + nextBlockTail = tailBlockNext->tail.load(); + fence(memory_order_acquire); + + // This block must be empty since it's not the head block and we + // go through the blocks in a circle + assert(nextBlockFront == nextBlockTail); + tailBlockNext->localFront = nextBlockFront; + + char* location = tailBlockNext->data + nextBlockTail * sizeof(T); +#if MOODYCAMEL_HAS_EMPLACE + new (location) T(std::forward(args)...); +#else + new (location) T(std::forward(element)); +#endif + + tailBlockNext->tail = (nextBlockTail + 1) & tailBlockNext->sizeMask; + + fence(memory_order_release); + tailBlock = tailBlockNext; + } + else if (canAlloc == CanAlloc) { + // tailBlock is full and there's no free block ahead; create a new block + auto newBlockSize = largestBlockSize >= MAX_BLOCK_SIZE ? largestBlockSize : largestBlockSize * 2; + auto newBlock = make_block(newBlockSize); + if (newBlock == nullptr) { + // Could not allocate a block! + return false; + } + largestBlockSize = newBlockSize; + +#if MOODYCAMEL_HAS_EMPLACE + new (newBlock->data) T(std::forward(args)...); +#else + new (newBlock->data) T(std::forward(element)); +#endif + assert(newBlock->front == 0); + newBlock->tail = newBlock->localTail = 1; + + newBlock->next = tailBlock_->next.load(); + tailBlock_->next = newBlock; + + // Might be possible for the dequeue thread to see the new tailBlock->next + // *without* seeing the new tailBlock value, but this is OK since it can't + // advance to the next block until tailBlock is set anyway (because the only + // case where it could try to read the next is if it's already at the tailBlock, + // and it won't advance past tailBlock in any circumstance). + + fence(memory_order_release); + tailBlock = newBlock; + } + else if (canAlloc == CannotAlloc) { + // Would have had to allocate a new block to enqueue, but not allowed + return false; + } + else { + assert(false && "Should be unreachable code"); + return false; + } + } + + return true; + } + + + // Disable copying + ReaderWriterQueue(ReaderWriterQueue const&) { } + + // Disable assignment + ReaderWriterQueue& operator=(ReaderWriterQueue const&) { } + + + AE_FORCEINLINE static size_t ceilToPow2(size_t x) + { + // From http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + for (size_t i = 1; i < sizeof(size_t); i <<= 1) { + x |= x >> (i << 3); + } + ++x; + return x; + } + + template + static AE_FORCEINLINE char* align_for(char* ptr) AE_NO_TSAN + { + const std::size_t alignment = std::alignment_of::value; + return ptr + (alignment - (reinterpret_cast(ptr) % alignment)) % alignment; + } +private: +#ifndef NDEBUG + struct ReentrantGuard + { + AE_NO_TSAN ReentrantGuard(weak_atomic& _inSection) + : inSection(_inSection) + { + assert(!inSection && "Concurrent (or re-entrant) enqueue or dequeue operation detected (only one thread at a time may hold the producer or consumer role)"); + inSection = true; + } + + AE_NO_TSAN ~ReentrantGuard() { inSection = false; } + + private: + ReentrantGuard& operator=(ReentrantGuard const&); + + private: + weak_atomic& inSection; + }; +#endif + + struct Block + { + // Avoid false-sharing by putting highly contended variables on their own cache lines + weak_atomic front; // (Atomic) Elements are read from here + size_t localTail; // An uncontended shadow copy of tail, owned by the consumer + + char cachelineFiller0[MOODYCAMEL_CACHE_LINE_SIZE - sizeof(weak_atomic) - sizeof(size_t)]; + weak_atomic tail; // (Atomic) Elements are enqueued here + size_t localFront; + + char cachelineFiller1[MOODYCAMEL_CACHE_LINE_SIZE - sizeof(weak_atomic) - sizeof(size_t)]; // next isn't very contended, but we don't want it on the same cache line as tail (which is) + weak_atomic next; // (Atomic) + + char* data; // Contents (on heap) are aligned to T's alignment + + const size_t sizeMask; + + + // size must be a power of two (and greater than 0) + AE_NO_TSAN Block(size_t const& _size, char* _rawThis, char* _data) + : front(0UL), localTail(0), tail(0UL), localFront(0), next(nullptr), data(_data), sizeMask(_size - 1), rawThis(_rawThis) + { + } + + private: + // C4512 - Assignment operator could not be generated + Block& operator=(Block const&); + + public: + char* rawThis; + }; + + + static Block* make_block(size_t capacity) AE_NO_TSAN + { + // Allocate enough memory for the block itself, as well as all the elements it will contain + auto size = sizeof(Block) + std::alignment_of::value - 1; + size += sizeof(T) * capacity + std::alignment_of::value - 1; + auto newBlockRaw = static_cast(std::malloc(size)); + if (newBlockRaw == nullptr) { + return nullptr; + } + + auto newBlockAligned = align_for(newBlockRaw); + auto newBlockData = align_for(newBlockAligned + sizeof(Block)); + return new (newBlockAligned) Block(capacity, newBlockRaw, newBlockData); + } + +private: + weak_atomic frontBlock; // (Atomic) Elements are dequeued from this block + + char cachelineFiller[MOODYCAMEL_CACHE_LINE_SIZE - sizeof(weak_atomic)]; + weak_atomic tailBlock; // (Atomic) Elements are enqueued to this block + + size_t largestBlockSize; + +#ifndef NDEBUG + weak_atomic enqueuing; + mutable weak_atomic dequeuing; +#endif +}; + +// Like ReaderWriterQueue, but also providees blocking operations +template +class BlockingReaderWriterQueue +{ +private: + typedef ::moodycamel::ReaderWriterQueue ReaderWriterQueue; + +public: + explicit BlockingReaderWriterQueue(size_t size = 15) AE_NO_TSAN + : inner(size), sema(new spsc_sema::LightweightSemaphore()) + { } + + BlockingReaderWriterQueue(BlockingReaderWriterQueue&& other) AE_NO_TSAN + : inner(std::move(other.inner)), sema(std::move(other.sema)) + { } + + BlockingReaderWriterQueue& operator=(BlockingReaderWriterQueue&& other) AE_NO_TSAN + { + std::swap(sema, other.sema); + std::swap(inner, other.inner); + return *this; + } + + + // Enqueues a copy of element if there is room in the queue. + // Returns true if the element was enqueued, false otherwise. + // Does not allocate memory. + AE_FORCEINLINE bool try_enqueue(T const& element) AE_NO_TSAN + { + if (inner.try_enqueue(element)) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues a moved copy of element if there is room in the queue. + // Returns true if the element was enqueued, false otherwise. + // Does not allocate memory. + AE_FORCEINLINE bool try_enqueue(T&& element) AE_NO_TSAN + { + if (inner.try_enqueue(std::forward(element))) { + sema->signal(); + return true; + } + return false; + } + +#if MOODYCAMEL_HAS_EMPLACE + // Like try_enqueue() but with emplace semantics (i.e. construct-in-place). + template + AE_FORCEINLINE bool try_emplace(Args&&... args) AE_NO_TSAN + { + if (inner.try_emplace(std::forward(args)...)) { + sema->signal(); + return true; + } + return false; + } +#endif + + + // Enqueues a copy of element on the queue. + // Allocates an additional block of memory if needed. + // Only fails (returns false) if memory allocation fails. + AE_FORCEINLINE bool enqueue(T const& element) AE_NO_TSAN + { + if (inner.enqueue(element)) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues a moved copy of element on the queue. + // Allocates an additional block of memory if needed. + // Only fails (returns false) if memory allocation fails. + AE_FORCEINLINE bool enqueue(T&& element) AE_NO_TSAN + { + if (inner.enqueue(std::forward(element))) { + sema->signal(); + return true; + } + return false; + } + +#if MOODYCAMEL_HAS_EMPLACE + // Like enqueue() but with emplace semantics (i.e. construct-in-place). + template + AE_FORCEINLINE bool emplace(Args&&... args) AE_NO_TSAN + { + if (inner.emplace(std::forward(args)...)) { + sema->signal(); + return true; + } + return false; + } +#endif + + + // Attempts to dequeue an element; if the queue is empty, + // returns false instead. If the queue has at least one element, + // moves front to result using operator=, then returns true. + template + bool try_dequeue(U& result) AE_NO_TSAN + { + if (sema->tryWait()) { + bool success = inner.try_dequeue(result); + assert(success); + AE_UNUSED(success); + return true; + } + return false; + } + + + // Attempts to dequeue an element; if the queue is empty, + // waits until an element is available, then dequeues it. + template + void wait_dequeue(U& result) AE_NO_TSAN + { + while (!sema->wait()); + bool success = inner.try_dequeue(result); + AE_UNUSED(result); + assert(success); + AE_UNUSED(success); + } + + + // Attempts to dequeue an element; if the queue is empty, + // waits until an element is available up to the specified timeout, + // then dequeues it and returns true, or returns false if the timeout + // expires before an element can be dequeued. + // Using a negative timeout indicates an indefinite timeout, + // and is thus functionally equivalent to calling wait_dequeue. + template + bool wait_dequeue_timed(U& result, std::int64_t timeout_usecs) AE_NO_TSAN + { + if (!sema->wait(timeout_usecs)) { + return false; + } + bool success = inner.try_dequeue(result); + AE_UNUSED(result); + assert(success); + AE_UNUSED(success); + return true; + } + + +#if __cplusplus > 199711L || _MSC_VER >= 1700 + // Attempts to dequeue an element; if the queue is empty, + // waits until an element is available up to the specified timeout, + // then dequeues it and returns true, or returns false if the timeout + // expires before an element can be dequeued. + // Using a negative timeout indicates an indefinite timeout, + // and is thus functionally equivalent to calling wait_dequeue. + template + inline bool wait_dequeue_timed(U& result, std::chrono::duration const& timeout) AE_NO_TSAN + { + return wait_dequeue_timed(result, std::chrono::duration_cast(timeout).count()); + } +#endif + + + // Returns a pointer to the front element in the queue (the one that + // would be removed next by a call to `try_dequeue` or `pop`). If the + // queue appears empty at the time the method is called, nullptr is + // returned instead. + // Must be called only from the consumer thread. + AE_FORCEINLINE T* peek() const AE_NO_TSAN + { + return inner.peek(); + } + + // Removes the front element from the queue, if any, without returning it. + // Returns true on success, or false if the queue appeared empty at the time + // `pop` was called. + AE_FORCEINLINE bool pop() AE_NO_TSAN + { + if (sema->tryWait()) { + bool result = inner.pop(); + assert(result); + AE_UNUSED(result); + return true; + } + return false; + } + + // Returns the approximate number of items currently in the queue. + // Safe to call from both the producer and consumer threads. + AE_FORCEINLINE size_t size_approx() const AE_NO_TSAN + { + return sema->availableApprox(); + } + + // Returns the total number of items that could be enqueued without incurring + // an allocation when this queue is empty. + // Safe to call from both the producer and consumer threads. + // + // NOTE: The actual capacity during usage may be different depending on the consumer. + // If the consumer is removing elements concurrently, the producer cannot add to + // the block the consumer is removing from until it's completely empty, except in + // the case where the producer was writing to the same block the consumer was + // reading from the whole time. + AE_FORCEINLINE size_t max_capacity() const { + return inner.max_capacity(); + } + +private: + // Disable copying & assignment + BlockingReaderWriterQueue(BlockingReaderWriterQueue const&) { } + BlockingReaderWriterQueue& operator=(BlockingReaderWriterQueue const&) { } + +private: + ReaderWriterQueue inner; + std::unique_ptr sema; +}; + +} // end namespace moodycamel + +#ifdef AE_VCPP +#pragma warning(pop) +#endif diff --git a/duix-sdk/src/main/cpp/dhmfcc/AudioFFT.cpp b/duix-sdk/src/main/cpp/dhmfcc/AudioFFT.cpp new file mode 100644 index 0000000..ad10b3d --- /dev/null +++ b/duix-sdk/src/main/cpp/dhmfcc/AudioFFT.cpp @@ -0,0 +1,1146 @@ +#include "mfcc/AudioFFT.hpp" + + +namespace audiofft +{ + + namespace detail + { + + + constexpr bool IsPowerOf2(size_t val) + { + return (val == 1 || (val & (val-1)) == 0); + } + + + template + void ConvertBuffer(TypeDest* dest, const TypeSrc* src, size_t len) + { + for (size_t i=0; i(src[i]); + } + } + + + template + void ScaleBuffer(TypeDest* dest, const TypeSrc* src, const TypeFactor factor, size_t len) + { + for (size_t i=0; i(static_cast(src[i]) * factor); + } + } + + } // End of namespace detail + + + // ================================================================ + + +#ifdef AUDIOFFT_OOURA_USED + + /** + * @internal + * @class OouraFFT + * @brief FFT implementation based on the great radix-4 routines by Takuya Ooura + */ + class OouraFFT : public detail::AudioFFTImpl + { + public: + OouraFFT() : + detail::AudioFFTImpl(), + _size(0), + _ip(), + _w(), + _buffer() + { + } + + OouraFFT(const OouraFFT&) = delete; + OouraFFT& operator=(const OouraFFT&) = delete; + + virtual void init(size_t size) override + { + if (_size != size) + { + _ip.resize(2 + static_cast(std::sqrt(static_cast(size)))); + _w.resize(size / 2); + _buffer.resize(size); + _size = size; + + const int size4 = static_cast(_size) / 4; + makewt(size4, _ip.data(), _w.data()); + makect(size4, _ip.data(), _w.data() + size4); + } + } + + virtual void fft(const float* data, float* re, float* im) override + { + // Convert into the format as required by the Ooura FFT + detail::ConvertBuffer(_buffer.data(), data, _size); + + rdft(static_cast(_size), +1, _buffer.data(), _ip.data(), _w.data()); + + // Convert back to split-complex + { + double* b = _buffer.data(); + double* bEnd = b + _size; + float *r = re; + float *i = im; + while (b != bEnd) + { + *(r++) = static_cast(*(b++)); + *(i++) = static_cast(-(*(b++))); + } + } + const size_t size2 = _size / 2; + re[size2] = -im[0]; + im[0] = 0.0; + im[size2] = 0.0; + } + + virtual void ifft(float* data, const float* re, const float* im) override + { + // Convert into the format as required by the Ooura FFT + { + double* b = _buffer.data(); + double* bEnd = b + _size; + const float *r = re; + const float *i = im; + while (b != bEnd) + { + *(b++) = static_cast(*(r++)); + *(b++) = -static_cast(*(i++)); + } + _buffer[1] = re[_size / 2]; + } + + rdft(static_cast(_size), -1, _buffer.data(), _ip.data(), _w.data()); + + // Convert back to split-complex + detail::ScaleBuffer(data, _buffer.data(), 2.0 / static_cast(_size), _size); + } + + private: + size_t _size; + std::vector _ip; + std::vector _w; + std::vector _buffer; + + void rdft(int n, int isgn, double *a, int *ip, double *w) + { + int nw = ip[0]; + int nc = ip[1]; + + if (isgn >= 0) + { + if (n > 4) + { + bitrv2(n, ip + 2, a); + cftfsub(n, a, w); + rftfsub(n, a, nc, w + nw); + } + else if (n == 4) + { + cftfsub(n, a, w); + } + double xi = a[0] - a[1]; + a[0] += a[1]; + a[1] = xi; + } + else + { + a[1] = 0.5 * (a[0] - a[1]); + a[0] -= a[1]; + if (n > 4) + { + rftbsub(n, a, nc, w + nw); + bitrv2(n, ip + 2, a); + cftbsub(n, a, w); + } + else if (n == 4) + { + cftfsub(n, a, w); + } + } + } + + + /* -------- initializing routines -------- */ + + void makewt(int nw, int *ip, double *w) + { + int j, nwh; + double delta, x, y; + + ip[0] = nw; + ip[1] = 1; + if (nw > 2) { + nwh = nw >> 1; + delta = atan(1.0) / nwh; + w[0] = 1; + w[1] = 0; + w[nwh] = cos(delta * nwh); + w[nwh + 1] = w[nwh]; + if (nwh > 2) { + for (j = 2; j < nwh; j += 2) { + x = cos(delta * j); + y = sin(delta * j); + w[j] = x; + w[j + 1] = y; + w[nw - j] = y; + w[nw - j + 1] = x; + } + bitrv2(nw, ip + 2, w); + } + } + } + + + void makect(int nc, int *ip, double *c) + { + int j, nch; + double delta; + + ip[1] = nc; + if (nc > 1) { + nch = nc >> 1; + delta = atan(1.0) / nch; + c[0] = cos(delta * nch); + c[nch] = 0.5 * c[0]; + for (j = 1; j < nch; j++) { + c[j] = 0.5 * cos(delta * j); + c[nc - j] = 0.5 * sin(delta * j); + } + } + } + + + /* -------- child routines -------- */ + + + void bitrv2(int n, int *ip, double *a) + { + int j, j1, k, k1, l, m, m2; + double xr, xi, yr, yi; + + ip[0] = 0; + l = n; + m = 1; + while ((m << 3) < l) { + l >>= 1; + for (j = 0; j < m; j++) { + ip[m + j] = ip[j] + l; + } + m <<= 1; + } + m2 = 2 * m; + if ((m << 3) == l) { + for (k = 0; k < m; k++) { + for (j = 0; j < k; j++) { + j1 = 2 * j + ip[k]; + k1 = 2 * k + ip[j]; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += 2 * m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 -= m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += 2 * m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + j1 = 2 * k + m2 + ip[k]; + k1 = j1 + m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + } else { + for (k = 1; k < m; k++) { + for (j = 0; j < k; j++) { + j1 = 2 * j + ip[k]; + k1 = 2 * k + ip[j]; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + } + } + } + + + void cftfsub(int n, double *a, double *w) + { + int j, j1, j2, j3, l; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + l = 2; + if (n > 8) { + cft1st(n, a, w); + l = 8; + while ((l << 2) < n) { + cftmdl(n, l, a, w); + l <<= 2; + } + } + if ((l << 2) == n) { + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i - x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i + x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i - x3r; + } + } else { + for (j = 0; j < l; j += 2) { + j1 = j + l; + x0r = a[j] - a[j1]; + x0i = a[j + 1] - a[j1 + 1]; + a[j] += a[j1]; + a[j + 1] += a[j1 + 1]; + a[j1] = x0r; + a[j1 + 1] = x0i; + } + } + } + + + void cftbsub(int n, double *a, double *w) + { + int j, j1, j2, j3, l; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + l = 2; + if (n > 8) { + cft1st(n, a, w); + l = 8; + while ((l << 2) < n) { + cftmdl(n, l, a, w); + l <<= 2; + } + } + if ((l << 2) == n) { + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = -a[j + 1] - a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = -a[j + 1] + a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i - x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i + x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i - x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i + x3r; + } + } else { + for (j = 0; j < l; j += 2) { + j1 = j + l; + x0r = a[j] - a[j1]; + x0i = -a[j + 1] + a[j1 + 1]; + a[j] += a[j1]; + a[j + 1] = -a[j + 1] - a[j1 + 1]; + a[j1] = x0r; + a[j1 + 1] = x0i; + } + } + } + + + void cft1st(int n, double *a, double *w) + { + int j, k1, k2; + double wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + x0r = a[0] + a[2]; + x0i = a[1] + a[3]; + x1r = a[0] - a[2]; + x1i = a[1] - a[3]; + x2r = a[4] + a[6]; + x2i = a[5] + a[7]; + x3r = a[4] - a[6]; + x3i = a[5] - a[7]; + a[0] = x0r + x2r; + a[1] = x0i + x2i; + a[4] = x0r - x2r; + a[5] = x0i - x2i; + a[2] = x1r - x3i; + a[3] = x1i + x3r; + a[6] = x1r + x3i; + a[7] = x1i - x3r; + wk1r = w[2]; + x0r = a[8] + a[10]; + x0i = a[9] + a[11]; + x1r = a[8] - a[10]; + x1i = a[9] - a[11]; + x2r = a[12] + a[14]; + x2i = a[13] + a[15]; + x3r = a[12] - a[14]; + x3i = a[13] - a[15]; + a[8] = x0r + x2r; + a[9] = x0i + x2i; + a[12] = x2i - x0i; + a[13] = x0r - x2r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[10] = wk1r * (x0r - x0i); + a[11] = wk1r * (x0r + x0i); + x0r = x3i + x1r; + x0i = x3r - x1i; + a[14] = wk1r * (x0i - x0r); + a[15] = wk1r * (x0i + x0r); + k1 = 0; + for (j = 16; j < n; j += 16) { + k1 += 2; + k2 = 2 * k1; + wk2r = w[k1]; + wk2i = w[k1 + 1]; + wk1r = w[k2]; + wk1i = w[k2 + 1]; + wk3r = wk1r - 2 * wk2i * wk1i; + wk3i = 2 * wk2i * wk1r - wk1i; + x0r = a[j] + a[j + 2]; + x0i = a[j + 1] + a[j + 3]; + x1r = a[j] - a[j + 2]; + x1i = a[j + 1] - a[j + 3]; + x2r = a[j + 4] + a[j + 6]; + x2i = a[j + 5] + a[j + 7]; + x3r = a[j + 4] - a[j + 6]; + x3i = a[j + 5] - a[j + 7]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j + 4] = wk2r * x0r - wk2i * x0i; + a[j + 5] = wk2r * x0i + wk2i * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j + 2] = wk1r * x0r - wk1i * x0i; + a[j + 3] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j + 6] = wk3r * x0r - wk3i * x0i; + a[j + 7] = wk3r * x0i + wk3i * x0r; + wk1r = w[k2 + 2]; + wk1i = w[k2 + 3]; + wk3r = wk1r - 2 * wk2r * wk1i; + wk3i = 2 * wk2r * wk1r - wk1i; + x0r = a[j + 8] + a[j + 10]; + x0i = a[j + 9] + a[j + 11]; + x1r = a[j + 8] - a[j + 10]; + x1i = a[j + 9] - a[j + 11]; + x2r = a[j + 12] + a[j + 14]; + x2i = a[j + 13] + a[j + 15]; + x3r = a[j + 12] - a[j + 14]; + x3i = a[j + 13] - a[j + 15]; + a[j + 8] = x0r + x2r; + a[j + 9] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j + 12] = -wk2i * x0r - wk2r * x0i; + a[j + 13] = -wk2i * x0i + wk2r * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j + 10] = wk1r * x0r - wk1i * x0i; + a[j + 11] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j + 14] = wk3r * x0r - wk3i * x0i; + a[j + 15] = wk3r * x0i + wk3i * x0r; + } + } + + + void cftmdl(int n, int l, double *a, double *w) + { + int j, j1, j2, j3, k, k1, k2, m, m2; + double wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + m = l << 2; + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i - x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i + x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i - x3r; + } + wk1r = w[2]; + for (j = m; j < l + m; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j2] = x2i - x0i; + a[j2 + 1] = x0r - x2r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1] = wk1r * (x0r - x0i); + a[j1 + 1] = wk1r * (x0r + x0i); + x0r = x3i + x1r; + x0i = x3r - x1i; + a[j3] = wk1r * (x0i - x0r); + a[j3 + 1] = wk1r * (x0i + x0r); + } + k1 = 0; + m2 = 2 * m; + for (k = m2; k < n; k += m2) { + k1 += 2; + k2 = 2 * k1; + wk2r = w[k1]; + wk2i = w[k1 + 1]; + wk1r = w[k2]; + wk1i = w[k2 + 1]; + wk3r = wk1r - 2 * wk2i * wk1i; + wk3i = 2 * wk2i * wk1r - wk1i; + for (j = k; j < l + k; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j2] = wk2r * x0r - wk2i * x0i; + a[j2 + 1] = wk2r * x0i + wk2i * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1] = wk1r * x0r - wk1i * x0i; + a[j1 + 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = wk3r * x0r - wk3i * x0i; + a[j3 + 1] = wk3r * x0i + wk3i * x0r; + } + wk1r = w[k2 + 2]; + wk1i = w[k2 + 3]; + wk3r = wk1r - 2 * wk2r * wk1i; + wk3i = 2 * wk2r * wk1r - wk1i; + for (j = k + m; j < l + (k + m); j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j2] = -wk2i * x0r - wk2r * x0i; + a[j2 + 1] = -wk2i * x0i + wk2r * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1] = wk1r * x0r - wk1i * x0i; + a[j1 + 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = wk3r * x0r - wk3i * x0i; + a[j3 + 1] = wk3r * x0i + wk3i * x0r; + } + } + } + + + void rftfsub(int n, double *a, int nc, double *c) + { + int j, k, kk, ks, m; + double wkr, wki, xr, xi, yr, yi; + + m = n >> 1; + ks = 2 * nc / m; + kk = 0; + for (j = 2; j < m; j += 2) { + k = n - j; + kk += ks; + wkr = 0.5 - c[nc - kk]; + wki = c[kk]; + xr = a[j] - a[k]; + xi = a[j + 1] + a[k + 1]; + yr = wkr * xr - wki * xi; + yi = wkr * xi + wki * xr; + a[j] -= yr; + a[j + 1] -= yi; + a[k] += yr; + a[k + 1] -= yi; + } + } + + + void rftbsub(int n, double *a, int nc, double *c) + { + int j, k, kk, ks, m; + double wkr, wki, xr, xi, yr, yi; + + a[1] = -a[1]; + m = n >> 1; + ks = 2 * nc / m; + kk = 0; + for (j = 2; j < m; j += 2) { + k = n - j; + kk += ks; + wkr = 0.5 - c[nc - kk]; + wki = c[kk]; + xr = a[j] - a[k]; + xi = a[j + 1] + a[k + 1]; + yr = wkr * xr + wki * xi; + yi = wkr * xi - wki * xr; + a[j] -= yr; + a[j + 1] = yi - a[j + 1]; + a[k] += yr; + a[k + 1] = yi - a[k + 1]; + } + a[m + 1] = -a[m + 1]; + } + }; + + + /** + * @internal + * @brief Concrete FFT implementation + */ + typedef OouraFFT AudioFFTImplementation; + + +#endif // AUDIOFFT_OOURA_USED + + + // ================================================================ + + +#ifdef AUDIOFFT_INTEL_IPP_USED + + + /** + * @internal + * @class IntelIppFFT + * @brief FFT implementation using the Intel Integrated Performance Primitives + */ + class IntelIppFFT : public detail::AudioFFTImpl + { + public: + IntelIppFFT() : + detail::AudioFFTImpl(), + _size(0), + _operationalBufferSize(0), + _powerOf2(0), + _fftSpec(nullptr), + _fftSpecBuf(0), + _fftWorkBuf(0), + _operationalBuffer(nullptr) + { + ippInit(); + } + + IntelIppFFT(const IntelIppFFT&) = delete; + IntelIppFFT& operator=(const IntelIppFFT&) = delete; + + virtual ~IntelIppFFT() + { + init(0); + } + + virtual void init(size_t size) override + { + if (_fftSpec) + { + if (_fftWorkBuf) ippFree(_fftWorkBuf); + if (_fftSpecBuf) ippFree(_fftSpecBuf); + ippFree(_operationalBuffer); + + _size = 0; + _operationalBufferSize = 0; + _powerOf2 = 0; + _fftSpec = 0; + } + + if (size > 0) + { + _size = size; + _operationalBufferSize = _size + 2; + _powerOf2 = (int)(log((double)_size)/log(2.0)); + + // Query to get buffer sizes + int sizeFFTSpec, + sizeFFTInitBuf, + sizeFFTWorkBuf; + ippsFFTGetSize_R_32f( + _powerOf2, + IPP_FFT_NODIV_BY_ANY, + ippAlgHintAccurate, + &sizeFFTSpec, + &sizeFFTInitBuf, + &sizeFFTWorkBuf + ); + + Ipp8u* fftInitBuf; + + // init buffers + _fftSpecBuf = ippsMalloc_8u(sizeFFTSpec); + _fftWorkBuf = ippsMalloc_8u(sizeFFTWorkBuf); + fftInitBuf = ippsMalloc_8u(sizeFFTInitBuf); + + // Initialize FFT + ippsFFTInit_R_32f( + &_fftSpec, + _powerOf2, + IPP_FFT_NODIV_BY_ANY, + ippAlgHintAccurate, + _fftSpecBuf, + fftInitBuf + ); + if (fftInitBuf) ippFree(fftInitBuf); + + // init operational buffer + _operationalBuffer = ippsMalloc_32f( + _operationalBufferSize + ); + } + } + + virtual void fft(const float* data, float* re, float* im) override + { + size_t complexNumbersCount = _operationalBufferSize / 2; + ippsFFTFwd_RToCCS_32f( + data, + _operationalBuffer, + _fftSpec, + _fftWorkBuf + ); + + // no need to scale + + size_t complexCounter = 0; + for (int i = 0; i < complexNumbersCount; ++i) + { + re[i] = _operationalBuffer[complexCounter++]; + im[i] = _operationalBuffer[complexCounter++]; + } + } + + virtual void ifft(float* data, const float* re, const float* im) override + { + size_t complexNumbersCount = _operationalBufferSize / 2; + + size_t complexCounter = 0; + for (int i = 0; i < complexNumbersCount; ++i) + { + _operationalBuffer[complexCounter++] = re[i]; + _operationalBuffer[complexCounter++] = im[i]; + } + + ippsFFTInv_CCSToR_32f( + _operationalBuffer, + data, + _fftSpec, + _fftWorkBuf + ); + + // scaling + const float factor = 1.0f / static_cast(_size); + ippsMulC_32f_I(factor, data, _size); + } + + private: + size_t _size; + size_t _operationalBufferSize; + size_t _powerOf2; + IppsFFTSpec_R_32f* _fftSpec; + Ipp8u* _fftSpecBuf; + Ipp8u* _fftWorkBuf; + Ipp32f* _operationalBuffer; + }; + + + /** + * @internal + * @brief Concrete FFT implementation + */ + typedef IntelIppFFT AudioFFTImplementation; + + +#endif // AUDIOFFT_INTEL_IPP_USED + + + // ================================================================ + + +#ifdef AUDIOFFT_APPLE_ACCELERATE_USED + + + /** + * @internal + * @class AppleAccelerateFFT + * @brief FFT implementation using the Apple Accelerate framework internally + */ + class AppleAccelerateFFT : public detail::AudioFFTImpl + { + public: + AppleAccelerateFFT() : + detail::AudioFFTImpl(), + _size(0), + _powerOf2(0), + _fftSetup(0), + _re(), + _im() + { + } + + AppleAccelerateFFT(const AppleAccelerateFFT&) = delete; + AppleAccelerateFFT& operator=(const AppleAccelerateFFT&) = delete; + + virtual ~AppleAccelerateFFT() + { + init(0); + } + + virtual void init(size_t size) override + { + if (_fftSetup) + { + vDSP_destroy_fftsetup(_fftSetup); + _size = 0; + _powerOf2 = 0; + _fftSetup = 0; + _re.clear(); + _im.clear(); + } + + if (size > 0) + { + _size = size; + _powerOf2 = 0; + while ((1 << _powerOf2) < _size) + { + ++_powerOf2; + } + _fftSetup = vDSP_create_fftsetup(_powerOf2, FFT_RADIX2); + _re.resize(_size / 2); + _im.resize(_size / 2); + } + } + + virtual void fft(const float* data, float* re, float* im) override + { + const size_t size2 = _size / 2; + DSPSplitComplex splitComplex; + splitComplex.realp = re; + splitComplex.imagp = im; + vDSP_ctoz(reinterpret_cast(data), 2, &splitComplex, 1, size2); + vDSP_fft_zrip(_fftSetup, &splitComplex, 1, _powerOf2, FFT_FORWARD); + const float factor = 0.5f; + vDSP_vsmul(re, 1, &factor, re, 1, size2); + vDSP_vsmul(im, 1, &factor, im, 1, size2); + re[size2] = im[0]; + im[0] = 0.0f; + im[size2] = 0.0f; + } + + virtual void ifft(float* data, const float* re, const float* im) override + { + const size_t size2 = _size / 2; + ::memcpy(_re.data(), re, size2 * sizeof(float)); + ::memcpy(_im.data(), im, size2 * sizeof(float)); + _im[0] = re[size2]; + DSPSplitComplex splitComplex; + splitComplex.realp = _re.data(); + splitComplex.imagp = _im.data(); + vDSP_fft_zrip(_fftSetup, &splitComplex, 1, _powerOf2, FFT_INVERSE); + vDSP_ztoc(&splitComplex, 1, reinterpret_cast(data), 2, size2); + const float factor = 1.0f / static_cast(_size); + vDSP_vsmul(data, 1, &factor, data, 1, _size); + } + + private: + size_t _size; + size_t _powerOf2; + FFTSetup _fftSetup; + std::vector _re; + std::vector _im; + }; + + + /** + * @internal + * @brief Concrete FFT implementation + */ + typedef AppleAccelerateFFT AudioFFTImplementation; + + +#endif // AUDIOFFT_APPLE_ACCELERATE_USED + + + // ================================================================ + + +#ifdef AUDIOFFT_FFTW3_USED + + + /** + * @internal + * @class FFTW3FFT + * @brief FFT implementation using FFTW3 internally (see fftw.org) + */ + class FFTW3FFT : public detail::AudioFFTImpl + { + public: + FFTW3FFT() : + detail::AudioFFTImpl(), + _size(0), + _complexSize(0), + _planForward(0), + _planBackward(0), + _data(0), + _re(0), + _im(0) + { + } + + FFTW3FFT(const FFTW3FFT&) = delete; + FFTW3FFT& operator=(const FFTW3FFT&) = delete; + + virtual ~FFTW3FFT() + { + init(0); + } + + virtual void init(size_t size) override + { + if (_size != size) + { + if (_size > 0) + { + fftwf_destroy_plan(_planForward); + fftwf_destroy_plan(_planBackward); + _planForward = 0; + _planBackward = 0; + _size = 0; + _complexSize = 0; + + if (_data) + { + fftwf_free(_data); + _data = 0; + } + + if (_re) + { + fftwf_free(_re); + _re = 0; + } + + if (_im) + { + fftwf_free(_im); + _im = 0; + } + } + + if (size > 0) + { + _size = size; + _complexSize = AudioFFT::ComplexSize(_size); + const size_t complexSize = AudioFFT::ComplexSize(_size); + _data = reinterpret_cast(fftwf_malloc(_size * sizeof(float))); + _re = reinterpret_cast(fftwf_malloc(complexSize * sizeof(float))); + _im = reinterpret_cast(fftwf_malloc(complexSize * sizeof(float))); + + fftw_iodim dim; + dim.n = static_cast(size); + dim.is = 1; + dim.os = 1; + _planForward = fftwf_plan_guru_split_dft_r2c(1, &dim, 0, 0, _data, _re, _im, FFTW_MEASURE); + _planBackward = fftwf_plan_guru_split_dft_c2r(1, &dim, 0, 0, _re, _im, _data, FFTW_MEASURE); + } + } + } + + virtual void fft(const float* data, float* re, float* im) override + { + ::memcpy(_data, data, _size * sizeof(float)); + fftwf_execute_split_dft_r2c(_planForward, _data, _re, _im); + ::memcpy(re, _re, _complexSize * sizeof(float)); + ::memcpy(im, _im, _complexSize * sizeof(float)); + } + + virtual void ifft(float* data, const float* re, const float* im) override + { + ::memcpy(_re, re, _complexSize * sizeof(float)); + ::memcpy(_im, im, _complexSize * sizeof(float)); + fftwf_execute_split_dft_c2r(_planBackward, _re, _im, _data); + detail::ScaleBuffer(data, _data, 1.0f / static_cast(_size), _size); + } + + private: + size_t _size; + size_t _complexSize; + fftwf_plan _planForward; + fftwf_plan _planBackward; + float* _data; + float* _re; + float* _im; + }; + + + /** + * @internal + * @brief Concrete FFT implementation + */ + typedef FFTW3FFT AudioFFTImplementation; + + +#endif // AUDIOFFT_FFTW3_USED + + + // ============================================================= + + + AudioFFT::AudioFFT() : + _impl(new AudioFFTImplementation()) + { + } + + + AudioFFT::~AudioFFT() + { + } + + + void AudioFFT::init(size_t size) + { + assert(detail::IsPowerOf2(size)); + _impl->init(size); + } + + + void AudioFFT::fft(const float* data, float* re, float* im) + { + _impl->fft(data, re, im); + } + + + void AudioFFT::ifft(float* data, const float* re, const float* im) + { + _impl->ifft(data, re, im); + } + + + size_t AudioFFT::ComplexSize(size_t size) + { + return (size / 2) + 1; + } + +} // End of namespace + + diff --git a/duix-sdk/src/main/cpp/dhmfcc/dhpcm.cpp b/duix-sdk/src/main/cpp/dhmfcc/dhpcm.cpp new file mode 100644 index 0000000..3069d42 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhmfcc/dhpcm.cpp @@ -0,0 +1,803 @@ +#include "dhpcm.h" +#include "mfcc/mfcc.hpp" +#include +#include "aicommon.h" +#include +#include +#include "opencv2/core.hpp" +#ifdef USE_HELPER +#include "dhdatahelper.h" +#endif + + + +PcmItem::PcmItem(int sentid,int minoff,int maxblock,int flip,int inx){ + m_flip = flip; + m_inx = inx; + m_sentid = sentid; + m_maxblock = maxblock; + //int dist = minoff - STREAM_MFCC_FILL; + //if(dist>0) m_minoff = dist; + m_minoff = minoff; + int allcnt = m_minoff + maxblock + 2*STREAM_MFCC_FILL; + pcm_allsamp = allcnt*STREAM_BASE_SAMP; + mel_allcnt = pcm_allsamp/160+1; + bnf_allcnt = mel_allcnt*0.25f - 0.75f; + //printf("==minoff %d max %d allcnt %d melcnt %d bnfcnt %d\n", minoff,maxblock,allcnt,mel_allcnt,bnf_allcnt ); + m_pcm = jmat_alloc(STREAM_BASE_SAMP,allcnt,1,0,4,NULL); + //m_pcm = new jmat_t(STREAM_BASE_SAMP,allcnt,1); + m_mel = jmat_alloc(STREAM_BASE_MEL,mel_allcnt,1,0,4,NULL); + //m_mel = new jmat_t(STREAM_BASE_MEL,mel_allcnt,1); + m_bnf = jmat_alloc(STREAM_BASE_BNF,bnf_allcnt,1,0,4,NULL); + m_bnfflip = jmat_alloc(STREAM_BASE_BNF,bnf_allcnt,1,0,4,NULL); + //m_bnf = new jmat_t(STREAM_BASE_BNF,bnf_allcnt,1); + //gjvad_alloc(&m_vad,STREAM_BASE_SAMP/2); + mat_flip = jmat_null(); +} + +PcmItem::~PcmItem(){ + if(m_pcm) jmat_free(m_pcm); + if(m_mel) jmat_free(m_mel); + if(m_bnf)jmat_free(m_bnf); + if(m_wav)jmat_free(m_wav); + if(m_mfcc)jmat_free(m_mfcc); + if(m_bnfflip)jmat_free(m_bnfflip); + jmat_deref(mat_flip); + //gjvad_free(&m_vad); +} + +int PcmItem::reset(){ + jbuf_zeros((jbuf_t*)m_pcm); + jbuf_zeros((jbuf_t*)m_mel); + jbuf_zeros((jbuf_t*)m_bnf); + return 0; +} + +int PcmItem::fillPcm(uint64_t sessid,uint64_t tickinx,jmat_t* premat,jmat_t* mat){ + m_wav = mat; + pcm_block = mat->height; + if(pcm_block>(m_maxblock+STREAM_MFCC_FILL))return -1; + pre_block = premat?premat->height:0; + int pcmcnt = pcm_block ; + + int allcnt = m_minoff + pcmcnt + 2*STREAM_MFCC_FILL; + //printf("===off %d pcm %d pad %d\n",m_minoff,pcmcnt,2*STREAM_MFCC_FILL); + pcm_allsamp = allcnt*STREAM_BASE_SAMP; + mel_allcnt = pcm_allsamp/160+1; + bnf_allcnt = mel_allcnt*0.25f - 0.75f; + + m_sessid = sessid; + m_pcminx = tickinx; + { + //fill pre + int dlen = m_minoff + STREAM_MFCC_FILL; + int blank = dlen - pre_block; + if(blank){ + float* pbuf = (float*)m_pcm->data; + int samp = blank*STREAM_BASE_SAMP; + memset(pbuf,0,samp*sizeof(float)); + } + if(pre_block){ + short* ps = (short*)premat->data; + for(int k=blank;kdata; + for(int k=0;kdata; + int samp = blank*STREAM_BASE_SAMP; + memset(pbuf,0,samp*sizeof(float)); + } + } + return 0; +} + +int PcmItem::checkValid(uint64_t tickinx){ + if(!tickinx)return 1; + return tickinx<=(m_pcminx+pcm_block);//&&(tickinx<=(m_pcminx+pcm_block)); +} + +jmat_t* PcmItem::readlast(int minoff){ + if(minoff>pcm_block)return NULL; + int start = pcm_block - minoff; + jmat_t* mpre = jmat_alloc(STREAM_BASE_PCM,minoff,1,0,1, m_wav->data + start); + return mpre; +} + +int PcmItem::readblock(){ + return pcm_read; +} + +int PcmItem::numblock(){ + return pcm_block; +} + +int PcmItem::readbnf(char* buf){ + if(!m_ready)return 0; + char* mdata = jmat_row(m_mfcc,0); + int cnt = pcm_block ; + memcpy(buf,mdata,STREAM_ALL_BNF*cnt); + return 0; +} + +int PcmItem::readblock(jmat_t* pcm,jmat_t* mfcc){ + if(!m_ready)return 0; + if(pcm_read>=pcm_block)return 0; + if(pcm){ + char* rdata = jmat_row(m_wav,pcm_read); + memcpy(pcm->data,rdata,STREAM_BASE_PCM); + } + int inx = pcm_read?pcm_read-1:0; + char* mdata = jmat_row(m_mfcc,inx); + //printf("===inx %d mfcc %d\n",inx,m_mfcc->height); + memcpy(mfcc->data,mdata,STREAM_ALL_BNF); + pcm_read++; + return 1; +} + +int PcmItem::readblock(int inx,jmat_t* pcm,jmat_t* mfcc){ + if(!m_ready)return 0; + if(inx>=pcm_block)return 0; + if(pcm){ + char* rdata = jmat_row(m_wav,inx); + memcpy(pcm->data,rdata,STREAM_BASE_PCM); + } + int newinx = inx?inx-1:0; + if(m_flip){ + jmat_reroi(mat_flip,m_mfcc,STREAM_BASE_BNF,20,0,newinx); +#ifdef USE_HELPER //jmat_dump(mat_flip); + cv::Mat sm = dh2cvmat(mat_flip); + jmat_reshape(mfcc,20,STREAM_BASE_BNF); + cv::Mat dm = dh2cvmat(mfcc); + cv::transpose(sm,dm); +#endif + //jmat_dump(mfcc); + }else{ + char* mdata = jmat_row(m_mfcc,newinx); + //printf("===inx %d mfcc %d\n",inx,m_mfcc->height); + memcpy(mfcc->data,mdata,STREAM_ALL_BNF); + } + return 1; +} + +void PcmItem::dump(FILE* dumpfile){ + printf("===dumpone %d\n",pcm_block); + for(int k=0;kdata; + float* mel = (float*)m_mel->data; + rst = DhWenet::calcmfcc(fwav,pcm_allsamp,mel,mel_allcnt); + + //float* bnf = m_flip? (float*)m_bnfflip->data:(float*)m_bnf->data; + float* bnf = (float*)m_bnf->data; + //tooken + uint64_t tick = jtimer_msstamp(); +#ifdef AIRUN_FLAG + rst = weai->run(mel,mel_allcnt,bnf,bnf_allcnt); +#endif + int dist = jtimer_msstamp()-tick; + if(0){ + float* pf = (float*)bnf; + for(int k=0;k<256;k++){ + printf("=%d==%f\n",k,*pf++); + } + } + + printf("===pcm %ld %d mel %d bnf %d dist %d \n",tick,m_pcm->height,mel_allcnt,bnf_allcnt,dist); + /* + if(m_flip){ + printf("==flip\n"); + cv::Mat matbnf = dh2cvmat(m_bnf) ; + cv::Mat matflip =dh2cvmat(m_bnfflip); + cv::transpose(matflip,matbnf); + //jmat_reshape(m_bnf,256,bnf_allcnt); + } + */ + + //printf("===bbb \n"); + int inxstart = m_minoff; + uint64_t tickinx = m_pcminx; + float* rbnf = (float*)jmat_row(m_bnf,inxstart); + int rcnt = pcm_block; + jmat_t* matbnf = jmat_alloc(STREAM_BASE_BNF,rcnt+19,1,0,4,NULL); + memcpy(matbnf->data,rbnf,matbnf->buf.size); + m_mfcc = matbnf; + /* + jmat_t* dmat = jmat_alloc(20,256,1,0,4,NULL); + cv::Mat bm =dh2cvmat(dmat); + for(int k=0;k<10;k++){ + printf("====k%d\n",k); + jmat_t* mat = jmat_roi(m_mfcc,256,20,0,k); + cv::Mat am = dh2cvmat(mat) ; + cv::transpose(am,bm); + jmat_deref(mat); + break; + } + */ + m_ready = 1; + return 0; +} + +PcmFile::PcmFile(int fps,int minoff,int mincnt,int maxcnt){ + m_fps = fps; + m_scale = fps*1.0f/25.0f; + m_adj = fps!=25; + m_minoff = minoff; + m_mincnt = mincnt; + m_maxcnt = maxcnt; + m_maxsize = maxcnt* STREAM_BASE_PCM; + m_minsize = mincnt* STREAM_BASE_PCM; + m_arrmax = (int*)malloc(sizeof(int)*1024); + memset(m_arrmax,0,sizeof(int)*1024); + m_arrmin = (int*)malloc(sizeof(int)*1024); + memset(m_arrmin,0,sizeof(int)*1024); +} + +PcmFile::~PcmFile(){ + for(int k=0;krunWenet(weai); + m_calcblock = m_calcblock + item->numblock(); + m_calccnt += 1; + } + return 0; + }else{ + if(inx>=vec_pcm.size())return -1; + PcmItem* item = vec_pcm[inx]; + int rst = item->runWenet(weai); + m_calcblock = m_calcblock + item->numblock(); + m_calccnt += 1; + return rst; + } +} + +int PcmFile::appenditem(jmat_t* mat,int noone){ + int chkblock = mat->height; + int chkmin = m_lastitem?m_minoff:0; + //printf("===chk min %d chkblock %d\n",chkmin,chkblock); + int inx = m_fileblock ; + PcmItem* item = new PcmItem(0,chkmin,chkblock,m_flip,inx); + jmat_t* mpre = NULL; + if(m_lastitem){ + mpre = m_lastitem->readlast(chkmin); + } + int rst = item->fillPcm(0,0,mpre,mat); + vec_pcm.push_back(item); + m_lastitem = item; + m_arrmin[vec_pcm.size()-1] = m_fileblock; + m_fileblock += item->numblock(); + //printf("===m_fileblock %d to %d \n",m_fileblock,fileBlock()); + m_arrmax[vec_pcm.size()-1] = m_fileblock; + + if(mpre)jmat_free(mpre); + return 0; +} + +int PcmFile::prepare(char* buf,int size,char* prebuf,int presize){ + int rst = 0; + m_presize = presize; + m_preblock = presize/STREAM_BASE_PCM; + int cursize = size; + char* curhead = buf; + if(m_preblock){ + jmat_t* mat = jmat_alloc(STREAM_BASE_PCM,m_preblock,1,0,1,prebuf); + int chkblock = mat->height; + int chkmin = m_lastitem?m_minoff:0; + int inx = 0; + PcmItem* item = new PcmItem(0,chkmin,chkblock,m_flip,inx); + m_preitem = item; + m_lastitem = item; + rst = item->fillPcm(0,0,NULL,mat); + } + while(cursize >= m_maxsize){ + jmat_t* mat = jmat_alloc(STREAM_BASE_PCM,m_maxcnt,1,0,1,NULL); + memcpy(mat->data ,curhead,m_maxsize); + rst += appenditem(mat); + cursize -= m_maxsize; + curhead += m_maxsize; + //printf("====cursize %d\n",cursize); + } + if(cursize>0){ + int block = cursize / STREAM_BASE_PCM; + if(blockdata ,curhead,block*STREAM_BASE_PCM); + rst += appenditem(mat); + } + return 0; +} + +int PcmFile::setflip(int flip){ + m_flip = flip; + return 0; +} + +int PcmFile::prepare(std::string& pcmfn){ + /* + void* fhnd = wav_read_open(pcmfn.c_str()); + if(!fhnd)return -1; + int format, channels, sr, bits_per_sample; + unsigned int data_length; + int res = wav_get_header(fhnd, &format, &channels, &sr, &bits_per_sample, &data_length); + if(data_length<1) return -2; + int sample = data_length/2; + jbuf_t* pcmbuf = jbuf_alloc(data_length); + int rst = wav_read_data(fhnd,(unsigned char*)pcmbuf->data,data_length); + wav_read_close(fhnd); + int cursize = data_length; + char* curhead = pcmbuf->data; + + rst = prepare(curhead,cursize); + dhmem_deref(pcmbuf); + return rst; + */ + return 0; +} + +jmat_t* PcmFile::readbnf(int sinx){ + jmat_t* bnf = jmat_alloc(STREAM_BASE_BNF,m_fileblock,1,0,4,NULL); + + return bnf; +} + +int PcmFile::readbnf(char* bnf,int bnfsize){ + int block = fileBlock(); + int allsize = block*STREAM_BASE_BNF*sizeof(float); + if(bnfsizereadbnf(buf); + inx += item->numblock(); + } + return block; +} + +int PcmFile::readblock(int sinx,jmat_t* pcm,jmat_t* feat){ + //if(pcm->width!=STREAM_BASE_PCM)return -2001; + //if(feat->width!=STREAM_BASE_BNF)return -2002; + int inx = sinx/m_scale; + if(inx>=m_fileblock)return -1; + printf("===inx %d calc %d\n",inx,m_calccnt); + if(inx>=m_calcblock)return 0; + int rst = 0; + PcmItem* curitem = NULL; + int newinx = 0; + for(int k=0;k=m_arrmin[k])){ + curitem = vec_pcm[k]; + newinx = inx - m_arrmin[k]; + break; + } + } + if(curitem){ + rst = curitem->readblock(newinx,pcm,feat); + if(rst){ + if(pcm)pcm->buf.sessid = inx; + feat->buf.sessid = inx; + } + return rst; + } + return 0; +} + +PcmSession::PcmSession(uint64_t sessid,int minoff,int mincnt,int maxcnt){ + m_sessid = sessid; + m_minoff = minoff; + m_mincnt = mincnt; + m_maxcnt = maxcnt; + m_checkcnt = (mincnt+maxcnt)/2; + m_maxsize = maxcnt* STREAM_BASE_PCM; + m_minsize = mincnt* STREAM_BASE_PCM; + int csize = STREAM_BASE_PCM; + m_pcmcache = (uint8_t*)malloc(STREAM_BASE_PCM*maxcnt*10); + m_cachepos = 0; + m_cachemax = STREAM_BASE_PCM*maxcnt*10; + m_lastitem = NULL; + m_arrflag = (int*)malloc(1024*sizeof(int)); + memset(m_arrflag,0,1024*sizeof(int)); + m_arrmax = (int*)malloc(sizeof(int)*1024000); + memset(m_arrmax,0,sizeof(int)*1024000); + m_arrmin = (int*)malloc(sizeof(int)*1024000); + memset(m_arrmin,0,sizeof(int)*1024000); +} + +PcmSession::~PcmSession(){ + //std::unique_lock lock(m_lock); + for(int k=0;kheight*STREAM_BASE_PCM); + //printf("===cur %d min %d max %d\n",m_curflag,m_minoff,m_maxcnt); + int chkblock = mat->height; + //printf("===chkblock %d\n",chkblock); + int chkmin = m_lastitem?m_minoff:0; + int inx = m_fileblock ; + PcmItem* item = new PcmItem(m_curflag,chkmin,chkblock,m_flip,inx); + //printf("===check cur %d off %d block %d\n",m_curflag,chkmin,chkblock); + jmat_t* mpre = NULL; + if(m_lastitem){ + mpre = m_lastitem->readlast(chkmin); + } + int rst = item->fillPcm(m_sessid,0,mpre,mat); + //printf("===fill %d\n",rst); + vec_pcm.push_back(item); + m_lastitem = item; + m_arrmin[vec_pcm.size()-1] = m_fileblock; + m_fileblock += item->numblock(); + m_arrmax[vec_pcm.size()-1] = m_fileblock; + + m_numpush += chkblock; + m_lastitem = item; + m_workcnt ++; + if(mpre)jmat_free(mpre); + return 1; +} + +int PcmSession::checkpcmcache(int flush){ + if(m_cacheposdata ,curhead,m_minsize); + rst += appenditem(mat); + cursize -= m_minsize; + curhead += m_minsize; + } + while(cursize >= m_maxsize){ + jmat_t* mat = jmat_alloc(STREAM_BASE_PCM,m_maxcnt,1,0,1,NULL); + memcpy(mat->data ,curhead,m_maxsize); + rst += appenditem(mat); + cursize -= m_maxsize; + curhead += m_maxsize; + } + int dist = m_calccnt - m_readcnt; + int force = dist<2;//distwait()=m_minsize){ + int chkblock = cursize / STREAM_BASE_PCM; + int chksize = chkblock * STREAM_BASE_PCM; + jmat_t* mat = jmat_alloc(STREAM_BASE_PCM,chkblock,1,0,1,NULL); + memcpy(mat->data ,curhead,chksize); + curhead += chksize; + cursize -= chksize; + rst += appenditem(mat); + } + } + if(curhead!=m_pcmcache){ + m_cachepos = cursize; + memmove(m_pcmcache,curhead,cursize); + } + return rst; +} + +int PcmSession::pushpcm(uint64_t sessid,uint8_t* buf,int len){ + if(m_finished)return -1; + if(m_sessid!=sessid)return -2; + + int rst = 0; + uint8_t* curhead = buf; + int cursize = len; + m_totalpush += len; + int allcnt = m_cachepos + cursize; + + while(allcnt >= m_cachemax){ + int cpsize = m_cachemax - m_cachepos; + memcpy(m_pcmcache + m_cachepos,curhead,cpsize); + m_cachepos = m_cachemax; + cursize -= cpsize; + curhead += cpsize; + allcnt -= m_cachemax; + rst += checkpcmcache(); + } + if(cursize){ + memcpy(m_pcmcache + m_cachepos,curhead,cursize); + m_cachepos += cursize; + rst += checkpcmcache(); + } + return rst; +} + + +int PcmSession::simppcm(uint64_t sessid,uint8_t* buf,int len){ + if(m_finished)return -1; + if(m_sessid!=sessid)return -2; + int rst = 0; + //printf("==curpos %d len %d\n",m_cachepos,len); + uint8_t* curhead = buf; + int cursize = len; + m_totalpush += len; + //int chkblock = m_first&&!m_lastitem?m_mincnt:m_maxcnt; + //int chksize = m_first&&!m_lastitem?m_firstsize:m_basesize; + //int chkfirst = m_first&&!m_lastitem; + if(m_cachepos){ + int cnt = m_cachepos + len; + if(cnt>=m_minsize){ + int chkblock = cnt / STREAM_BASE_PCM; + if(chkblock>m_maxcnt)chkblock = m_maxcnt; + int chksize = chkblock * STREAM_BASE_PCM; + jmat_t* mat = jmat_alloc(STREAM_BASE_PCM,chkblock,1,0,1,NULL); + int cpsize = (m_cachepos > chksize)?chksize:m_cachepos; + memcpy(mat->data,m_pcmcache,cpsize); + int left = chksize - cpsize; + if(left>0) memcpy(mat->data + cpsize,buf,left); + //printf("append a %d\n",left); + m_cachepos -= cpsize; + cursize -= left; + curhead += left; + rst = appenditem(mat); + }else{ + memcpy(m_pcmcache+ m_cachepos,buf,len); + m_cachepos += len; + return 0; + } + } + while(cursize>=m_minsize){ + //printf("pbbb\n"); + int chkblock = cursize / STREAM_BASE_PCM; + if(chkblock>m_maxcnt)chkblock = m_maxcnt; + int chksize = chkblock * STREAM_BASE_PCM; + + jmat_t* mat = jmat_alloc(STREAM_BASE_PCM,chkblock,1,0,1,NULL); + memcpy(mat->data ,curhead,chksize); + curhead += chksize; + cursize -= chksize; + rst = appenditem(mat); + } + if(cursize>0){ + //printf("==cursize %d\n",cursize); + memcpy(m_pcmcache,curhead,cursize); + m_cachepos = cursize; + } + return rst; +} + +int PcmSession::conpcm(uint64_t sessid){ + //if(m_finished)return -1; + if(m_sessid!=sessid)return -2; + m_cachepos = 0; + m_finished = 0; + m_curflag ++; + return 0; +} + +int PcmSession::finpcm(uint64_t sessid){ + if(m_finished)return -1; + if(m_sessid!=sessid)return -2; + checkpcmcache(); + if(m_cachepos){ + int block = m_cachepos / STREAM_BASE_PCM; + int left = m_cachepos % STREAM_BASE_PCM; + if(left)block++; + jmat_t* mat = jmat_alloc(STREAM_BASE_PCM,block,1,0,1,NULL); + memset(mat->data,0,STREAM_BASE_PCM*block); + memcpy(mat->data,m_pcmcache,m_cachepos); + appenditem(mat); + } + m_finished = 1; + return 0; +} + +int PcmSession::runfirst(uint64_t sessid,WeAI* weai){ + if(m_sessid!=sessid)return -2; + if(!m_first)return 0; + if(m_calccnt)return 0; + PcmItem* item = vec_pcm[m_calccnt]; + if(item){ + item->runWenet(weai); + m_numcalc += item->numblock(); + } + m_calccnt ++; + m_first = 0; + // + return 0; +} + +int PcmSession::runcalc(uint64_t sessid,WeAI* weai,int mincalc){ + if(m_sessid!=sessid)return -2; + if(m_first)return -1; + int rst = 0; + if(m_calccntrunWenet(weai); + m_numcalc += item->numblock(); + } + m_calccnt ++; + rst = 1; + } + }else if(m_finished){ + rst = -1; + }else{ + rst = 0; + } + if(rst<1){ + int dist = m_readcnt - m_clrcnt; + if(dist>5){ + for(int k=0;kdump(dumpfile); + } + fclose(dumpfile); +} + +int PcmSession::distwait(){ + printf("===calc %d read %d \n",m_numcalc,m_numread); + return m_numpush - m_numread; +} + +int PcmSession::readnext(uint64_t sessid,uint8_t* pcmbuf,int pcmlen,uint8_t* bnfbuf,int bnflen){ + if(m_sessid!=sessid)return -2; + if(pcmlen!=STREAM_BASE_PCM)return -1; + if(bnflen!=STREAM_ALL_BNF)return -2; + jmat_t* mpcm = jmat_alloc(STREAM_BASE_PCM,1,1,0,1,pcmbuf); + jmat_t* mbnf = jmat_alloc(STREAM_BASE_BNF,20,1,0,4,bnfbuf); + int rst = readnext(sessid,mpcm,mbnf); + jmat_free(mpcm); + jmat_free(mbnf); + return rst; +} + +int PcmSession::readblock(uint64_t sessid,uint8_t* bnfbuf,int bnflen,int inx){ + if(m_sessid!=sessid)return -2; + if(bnflen!=STREAM_ALL_BNF)return -2; + jmat_t* mbnf = jmat_alloc(STREAM_BASE_BNF,20,1,0,4,bnfbuf); + int rst = readblock(sessid,mbnf,inx); + jmat_free(mbnf); + return rst; + +} + +int PcmSession::readblock(uint64_t sessid,jmat_t* mbnf,int inx){ + if(m_sessid!=sessid)return -2; + if(mbnf->width!=STREAM_BASE_BNF)return -2002; + //if(inx>=m_calccnt)return -99; + //printf("===inx %d num %d\n",inx,m_numcalc); + if(inx>=m_numcalc)return -99; + int rst = 0; + PcmItem* curitem = NULL; + int newinx = 0; + if((inx=m_arrmin[m_readcnt])){ + curitem = vec_pcm[m_readcnt]; + newinx = inx - m_arrmin[m_readcnt]; + }else{ + for(int k=0;k=m_arrmin[k])){ + curitem = vec_pcm[k]; + m_readcnt = k; + newinx = inx - m_arrmin[k]; + break; + } + } + } + //printf("===curitem %p inx %d new %d\n",curitem,inx ,newinx); + if(curitem){ + rst = curitem->readblock(newinx,NULL,mbnf); + if(rst){ + mbnf->buf.sessid = inx; + } + return rst; + } + return 0; +} + +int PcmSession::readnext(uint64_t sessid,jmat_t* mpcm,jmat_t* mbnf){ + if(mpcm->width!=STREAM_BASE_PCM)return -2001; + if(mbnf->width!=STREAM_BASE_BNF)return -2002; + //printf("===p %d r %d\n",m_totalpush,m_totalread); + if(m_totalreadreadblock(mpcm,mbnf); + if(!rst){ + m_readcnt++; + return 0; + }else{ +#ifdef PCMDEBUG + if(1){ + char fn[255]; + sprintf(fn,"out_%d.data",++m_debugout); + FILE* df = fopen(fn,"wb"); + fwrite(mpcm->data,1,STREAM_BASE_PCM,df); + fclose(df); + } +#endif + m_numread += 1; + m_totalread+=STREAM_BASE_PCM; + return item->itemsentid(); + } + }else{ + return 0; + } + }else{ + return m_finished?-1:0; + } +} + + + diff --git a/duix-sdk/src/main/cpp/dhmfcc/dhpcm.h b/duix-sdk/src/main/cpp/dhmfcc/dhpcm.h new file mode 100644 index 0000000..b98150b --- /dev/null +++ b/duix-sdk/src/main/cpp/dhmfcc/dhpcm.h @@ -0,0 +1,168 @@ + ///* +#pragma once +#include "dh_data.h" +#include "aicommon.h" +#include +#include +#include "dhwenet.h" +#include "wenetai.h" + +//#define PCMDEBUG 1 +#define AIRUN_FLAG 1 +class PcmItem{ + private: + uint64_t m_sessid = 0; + int m_minoff = 0; + int m_maxblock = 0; + + int pcm_allsamp = 0; + int bnf_allcnt = 0; + int mel_allcnt = 0; + jmat_t* m_wav = NULL; + jmat_t* m_pcm = NULL; + jmat_t* m_mel = NULL; + jmat_t* m_bnf = NULL; + jmat_t* m_bnfflip = NULL; + jmat_t* m_mfcc = NULL; + int pcm_block = 0; + int pcm_read = 0; + int pre_block = 0; + uint64_t m_pcminx = 0; + //gjvad_t* m_vad = NULL; + int m_ready = 0; + int m_sentid = 1; + int m_flip = 0; + int m_inx = 0; + jmat_t* mat_flip = NULL; + public: + int itemsentid(){return m_sentid;}; + int blocks(){return pcm_block;}; + int ready(){return m_ready;}; + int finished(){return pcm_read>=pcm_block;}; + int reset(); + PcmItem(int sentid,int minoff ,int maxblock ,int flip,int inx); + int fillPcm(uint64_t sessid,uint64_t tickinx,jmat_t* premat,jmat_t* mat); + int checkValid(uint64_t tickinx); + jmat_t* readlast(int minoff); + int runWenet(WeAI* weai); + int readblock(jmat_t* pcm,jmat_t* mfcc); + int readblock(int inx,jmat_t* pcm,jmat_t* mfcc); + int readbnf(char* buf); + int numblock(); + int startinx(){return m_inx;}; + int endinx(){return m_inx+pcm_block;}; + int readblock(); + void dump(FILE* dumpfile); + ~PcmItem(); +}; + +class PcmFile{ + private: + int m_fps = 25; + int m_adj = 0; + float m_scale = 1.0f; + int m_minoff = 0; + int m_mincnt = 0; + int m_maxcnt = 0; + int m_minsize = 0; + int m_maxsize = 0; + + int m_fileblock = 0; + int m_calcblock = 0; + int m_clrcnt = 0; + int m_readcnt = 0; + int m_calccnt = 0; + int *m_arrmax = NULL; + int *m_arrmin = NULL; + std::vector vec_pcm ; + int appenditem(jmat_t* mat,int noone=0); + PcmItem *m_lastitem = NULL; + PcmItem *m_lastread = NULL; + int m_presize = 0; + int m_preblock = 0; + PcmItem *m_preitem = NULL;; + int m_flip = 0; + public: + PcmFile(int fps = 25,int minoff = STREAM_BASE_MINOFF,int mincnt = STREAM_BASE_MINBLOCK,int maxcnt = STREAM_BASE_MAXBLOCK); + int setflip(int flip); + int prepare(std::string& pcmfn); + int prepare(char* buf,int size,char* prebuf = NULL,int presize = 0); + int itemSize(); + int process(int inx,WeAI* ai); + int readblock(int sinx,jmat_t* pcm,jmat_t* feat); + jmat_t* readbnf(int sinx); + int readbnf(char* bnf,int bnfsize); + int fileBlock(){return m_fileblock*m_scale;}; + int calcBlock(){return m_calcblock*m_scale;}; + virtual ~PcmFile(); +}; + +class PcmSession{ + private: + int m_sessid = 0; + + int m_minoff = 0; + int m_mincnt = 0; + int m_maxcnt = 0; + int m_minsize = 0; + int m_maxsize = 0; + //int m_basesize = 0; + //int m_firstsize = 0; + + int m_cachepos = 0; + int m_cachemax = 0; + uint8_t *m_pcmcache = NULL; + + std::mutex m_lock; + int *m_arrflag; + int m_curflag = 1; + + std::vector vec_pcm ; + PcmItem *m_lastitem = NULL; + + volatile int m_clrcnt = 0; + volatile int m_workcnt = 0; + volatile int m_readcnt = 0; + volatile int m_calccnt = 0; + int appenditem(jmat_t* mat,int noone=0); + + volatile int m_totalpush = 0; + volatile int m_totalread = 0; + volatile int m_finished = 0; + int m_first = 1; + int m_debuginx = 0; + int m_debugout = 0; + int checkpcmcache(int flash=0); + int m_numcalc = 0; + int m_numread = 0; + int m_numpush = 0; + int distwait(); + int m_checkcnt = 0; + int m_flip = 0; + int *m_arrmax = NULL; + int *m_arrmin = NULL; + int m_fileblock = 0; + int m_calcblock = 0; + public: + int setflip(int flip); + uint64_t sessid(){return m_sessid;}; + int simppcm(uint64_t sessid,uint8_t* buf,int len); + int pushpcm(uint64_t sessid,uint8_t* buf,int len); + int finpcm(uint64_t sessid); + int conpcm(uint64_t sessid); + int runcalc(uint64_t sessid,WeAI* weai,int mincalc=1); + int runfirst(uint64_t sessid,WeAI* weai); + int readnext(uint64_t sessid,jmat_t* mpcm,jmat_t* mbnf); + int readnext(uint64_t sessid,uint8_t* pcmbuf,int pcmlen,uint8_t* bnfbuf,int bnflen); + int readblock(uint64_t sessid,jmat_t* mbnf,int index); + int readblock(uint64_t sessid,uint8_t* bnfbuf,int bnflen,int inx); + PcmSession(uint64_t sessid,int minoff = STREAM_BASE_MINOFF,int mincnt = STREAM_BASE_MINBLOCK,int maxcnt = STREAM_BASE_MAXBLOCK); + ~PcmSession(); + void dump(char* dumpfn); + int first(){return m_first;}; + int fileBlock(){return m_fileblock;}; + //int calcBlock(){return m_calcblock;}; + int calcBlock(){return m_numcalc;}; +}; + + diff --git a/duix-sdk/src/main/cpp/dhmfcc/dhwenet.cpp b/duix-sdk/src/main/cpp/dhmfcc/dhwenet.cpp new file mode 100644 index 0000000..4ef27a5 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhmfcc/dhwenet.cpp @@ -0,0 +1,44 @@ +#include "dhwenet.h" +#include +#include +#include +#include "aicommon.h" +#include "mfcc/mfcc.hpp" + + +int DhWenet::cntmel(int pcmblock){ + int allcnt = pcmblock + 2*STREAM_MFCC_FILL; + int pcm_allsamp = allcnt*STREAM_BASE_SAMP; + int mel_allcnt = pcm_allsamp/160+1; + return mel_allcnt; +} + +int DhWenet::cntbnf(int melblock){ + int bnf_allcnt = melblock*0.25f - 0.75f; + return bnf_allcnt; +} + +int DhWenet::calcmfcc(float* fwav,float* mel2){ + int rst = 0; + int melcnt = MFCC_WAVCHUNK/160+1; + rst = log_mel(fwav,MFCC_WAVCHUNK, 16000,mel2); + return rst; +} + +int DhWenet::calcmfcc(float* fwav,int fsample,float* mel2,int melcnt){ + int rst = 0; + rst = log_mel(fwav,fsample, 16000,mel2); + return rst; +} + +int DhWenet::calcmfcc(jmat_t* mwav,jmat_t* mmel){ + int rst = 0; + int melcnt = MFCC_WAVCHUNK/160+1; + for(size_t k=0;kheight;k++){ + float* fwav = (float*)jmat_row(mwav,k); + float* mel2 = (float*)jmat_row(mmel,k); + rst = log_mel(fwav,MFCC_WAVCHUNK, 16000,mel2); + } + return rst; +} + diff --git a/duix-sdk/src/main/cpp/dhmfcc/dhwenet.h b/duix-sdk/src/main/cpp/dhmfcc/dhwenet.h new file mode 100644 index 0000000..667a669 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhmfcc/dhwenet.h @@ -0,0 +1,14 @@ +#pragma once +#include "dh_data.h" +#include "wenetai.h" +#include + +class DhWenet{ + public: + static int calcmfcc(jmat_t* mwav,jmat_t* mmel); + static int calcmfcc(float* fwav,float* mel2); + static int calcmfcc(float* fwav,int fsample,float* mel2,int melcnt); + static int cntmel(int pcmblock); + static int cntbnf(int melblock); + +}; diff --git a/duix-sdk/src/main/cpp/dhmfcc/iir_filter.cpp b/duix-sdk/src/main/cpp/dhmfcc/iir_filter.cpp new file mode 100644 index 0000000..11e5e7b --- /dev/null +++ b/duix-sdk/src/main/cpp/dhmfcc/iir_filter.cpp @@ -0,0 +1,310 @@ +#include "mfcc/iir_filter.hpp" +#include + +#ifdef UES_IIR_I + +void IIR_I::reset() +{ + for(int i = 0; i <= m_num_order; i++) + { + m_pNum[i] = 0.0; + } + for(int i = 0; i <= m_den_order; i++) + { + m_pDen[i] = 0.0; + } +} +IIR_I::IIR_I() +{ + m_pNum = NULL; + m_pDen = NULL; + m_px = NULL; + m_py = NULL; + m_num_order = -1; + m_den_order = -1; +}; +IIR_I::~IIR_I() +{ + delete[] m_pNum; + delete[] m_pDen; + delete[] m_px; + delete[] m_py; + m_pNum = NULL; + m_pDen = NULL; + m_px = NULL; + m_py = NULL; +}; + +/** \brief + * + * \param num 分子多项式的系数,升序排列,num[0] 为常数项 + * \param m 分子多项式的阶数 + * \param den 分母多项式的系数,升序排列,den[0] 为常数项 + * \param m 分母多项式的阶数 + * \return + */ +void IIR_I::setPara(double num[], int num_order, double den[], int den_order) +{ + delete[] m_pNum; + delete[] m_pDen; + delete[] m_px; + delete[] m_py; + m_pNum = new double[num_order + 1]; + m_pDen = new double[den_order + 1]; + m_num_order = num_order; + m_den_order = den_order; + m_px = new double[num_order + 1]; + m_py = new double[den_order + 1]; + for(int i = 0; i < m_num_order; i++) + { + m_pNum[i] = num[i]; + m_px[i] = 0.0; + } + m_pNum[m_num_order] = 0.0; + m_px[m_num_order] = 0.0; + for(int i = 0; i < m_den_order; i++) + { + m_pDen[i] = den[i]; + m_py[i] = 0.0; + } + m_pDen[m_den_order] = 0.0; + m_py[m_den_order] = 0.0; +} + +/** \brief 计算 IIR 滤波器的时域响应,不影响滤波器的内部状态 + * \param data_in 为滤波器的输入,0 时刻之前的输入默认为 0,data_in[M] 及之后的输入默认为data_in[M-1] + * \param data_out 滤波器的输出 + * \param M 输入数据的长度 + * \param N 输出数据的长度 + * \return + */ +void IIR_I::resp(double data_in[], int M, double data_out[], int N) +{ + int i, k, il; + for(k = 0; k < N; k++) + { + data_out[k] = 0.0; + for(i = 0; i <= m_num_order; i++) + { + if( k - i >= 0) + { + il = ((k - i) < M) ? (k - i) : (M - 1); + data_out[k] = data_out[k] + m_pNum[i] * data_in[il]; + } + } + for(i = 1; i <= m_den_order; i++) + { + if( k - i >= 0) + { + data_out[k] = data_out[k] - m_pDen[i] * data_out[k - i]; + } + } + } +} + +/** \brief 滤波函数,采用直接I型结构 + * 注:该函数内部修改过,移植librosa.pcen时参照scipy.signal.lfilter所做的设计。 + * + * \param data_in[] 输入数据 + * \param data_out[] 保存滤波后的数据 + * \param len 数组的长度 + * \return + */ +void IIR_I::filter(double data_in[], double data_out[], int len) +{ + int i, k; + m_py[1] = 1; //修改的地方,因为公式中y[n-k],当为第一个元素时会出现y[-1],pcen中y[-1]会被认为为1。 + for(k = 0; k < len; k++) + { + m_px[0] = data_in[k]; + m_py[0] = 0.0; + for(i = 0; i <= m_num_order; i++) + { + m_py[0] = m_py[0] + m_pNum[i] * m_px[i]; + } + for(i = 1; i <= m_den_order; i++) + { + m_py[0] = m_py[0] - m_pDen[i] * m_py[i]; + } + for(i = m_num_order; i >= 1; i--) + { + m_px[i] = m_px[i-1]; + } + for(i = m_den_order; i >= 1; i--) + { + m_py[i] = m_py[i-1]; + } + data_out[k] = m_py[0]; + } +} + +#endif + +#ifdef UES_IIR_II + + +IIR_II::IIR_II() +{ +//ctor +m_pNum = NULL; +m_pDen = NULL; +m_pW = NULL; +m_num_order = -1; +m_den_order = -1; +m_N = 0; +}; + +void IIR_II::reset() +{ + for(int i = 0; i < m_N; i++) + { + m_pW[i] = 0.0; + } +} +/** \brief + * + * \param num 分子多项式的系数,升序排列,num[0] 为常数项 + * \param m 分子多项式的阶数 + * \param den 分母多项式的系数,升序排列,den[0] 为常数项 + * \param m 分母多项式的阶数 + * \return + */ +void IIR_II::setPara(double num[], int num_order, double den[], int den_order) +{ + delete[] m_pNum; + delete[] m_pDen; + delete[] m_pW; + m_num_order = num_order; + m_den_order = den_order; + m_N = fmax(num_order, den_order) + 1; + m_pNum = new double[m_N]; + m_pDen = new double[m_N]; + m_pW = new double[m_N]; + for(int i = 0; i < m_N; i++) + { + m_pNum[i] = 0.0; + m_pDen[i] = 0.0; + m_pW[i] = 0.0; + } + for(int i = 0; i <= num_order; i++) + { + m_pNum[i] = num[i]; + } + for(int i = 0; i <= den_order; i++) + { + m_pDen[i] = den[i]; + } +} +/** \brief 计算 IIR 滤波器的时域响应,不影响滤波器的内部状态 + * \param data_in 为滤波器的输入,0 时刻之前的输入默认为 0,data_in[M] 及之后的输入默认为data_in[M-1] + * \param data_out 滤波器的输出 + * \param M 输入数据的长度 + * \param N 输出数据的长度 + * \return + */ +void IIR_II::resp(double data_in[], int M, double data_out[], int N) +{ + int i, k, il; + for(k = 0; k < N; k++) + { + data_out[k] = 0.0; + for(i = 0; i <= m_num_order; i++) + { + if( k - i >= 0) + { + il = ((k - i) < M) ? (k - i) : (M - 1); + data_out[k] = data_out[k] + m_pNum[i] * data_in[il]; + } + } + for(i = 1; i <= m_den_order; i++) + { + if( k - i >= 0) + { + data_out[k] = data_out[k] - m_pDen[i] * data_out[k - i]; + } + } + } +} +/** \brief 滤波函数,采用直接II型结构 + * + * \param data 输入数据 + * \return 滤波后的结果 + */ +double IIR_II::filter(double data) +{ + m_pW[0] = data; + for(int i = 1; i <= m_den_order; i++) // 先更新 w[n] 的状态 + { + m_pW[0] = m_pW[0] - m_pDen[i] * m_pW[i]; + } + data = 0.0; + for(int i = 0; i <= m_num_order; i++) + { + data = data + m_pNum[i] * m_pW[i]; + } + for(int i = m_N - 1; i >= 1; i--) + { + m_pW[i] = m_pW[i-1]; + } + return data; +} +/** \brief 滤波函数,采用直接II型结构 + * + * \param data[] 传入输入数据,返回时给出滤波后的结果 + * \param len data[] 数组的长度 + * \return + */ +void IIR_II::filter(double data[], int len) +{ + int i, k; + for(k = 0; k < len; k++) + { + m_pW[0] = data[k]; + for(i = 1; i <= m_den_order; i++) // 先更新 w[n] 的状态 + { + m_pW[0] = m_pW[0] - m_pDen[i] * m_pW[i]; + } + data[k] = 0.0; + for(i = 0; i <= m_num_order; i++) + { + data[k] = data[k] + m_pNum[i] * m_pW[i]; + } + + for(i = m_N - 1; i >= 1; i--) + { + m_pW[i] = m_pW[i-1]; + } + } +} +/** \brief 滤波函数,采用直接II型结构 + * + * \param data_in[] 输入数据 + * \param data_out[] 保存滤波后的数据 + * \param len 数组的长度 + * \return + */ +void IIR_II::filter(double data_in[], double data_out[], int len) +{ + int i, k; + for(k = 0; k < len; k++) + { + m_pW[0] = data_in[k]; + for(i = 1; i <= m_den_order; i++) // 先更新 w[n] 的状态 + { + m_pW[0] = m_pW[0] - m_pDen[i] * m_pW[i]; + } + data_out[k] = 0.0; + for(i = 0; i <= m_num_order; i++) + { + data_out[k] = data_out[k] + m_pNum[i] * m_pW[i]; + } + + for(i = m_N - 1; i >= 1; i--) + { + m_pW[i] = m_pW[i-1]; + } + } +} + +#endif + diff --git a/duix-sdk/src/main/cpp/dhmfcc/mfcc.cpp b/duix-sdk/src/main/cpp/dhmfcc/mfcc.cpp new file mode 100644 index 0000000..fc93f89 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhmfcc/mfcc.cpp @@ -0,0 +1,369 @@ +#include "mfcc/mfcc.hpp" +#include "mfcc/AudioFFT.hpp" +#include "mfcc/iir_filter.hpp" +#include "opencv2/core.hpp" + +static int nSamplesPerSec = 16000; +static int length_DFT = 1024;//2048; +static int hop_length = 160;//int(0.05 * nSamplesPerSec); +static int win_length = 800;// int(0.1 * nSamplesPerSec); +static int number_filterbanks = 80; +static float preemphasis = 0.97; +static int max_db = 100; +static int ref_db = 20; +static int r = 1; +static double pi = 3.14159265358979323846; + +static cv::Mat_ mel_basis; +static cv::Mat_ hannWindow; + +static std::shared_ptr filter; + +//"""Convert Hz to Mels""" +static double hz_to_mel(double frequencies, bool htk = false) { + if (htk) { + return 2595.0 * log10(1.0 + frequencies / 700.0); + } + // Fill in the linear part + double f_min = 0.0; + double f_sp = 200.0 / 3; + double mels = (frequencies - f_min) / f_sp; + // Fill in the log-scale part + double min_log_hz = 1000.0; // beginning of log region (Hz) + double min_log_mel = (min_log_hz - f_min) / f_sp; // same (Mels) + double logstep = log(6.4) / 27.0; // step size for log region + + // 对照Python平台的librosa库,移植 + //如果是多维数列 +// if (frequencies.ndim) { +// // If we have array data, vectorize +// log_t = (frequencies >= min_log_hz) +// mels[log_t] = min_log_mel + np.log(frequencies[log_t] / min_log_hz) / logstep +// } else + if (frequencies >= min_log_hz) { + // If we have scalar data, heck directly + mels = min_log_mel + log(frequencies / min_log_hz) / logstep; + } + return mels; +} + +//"""Convert mel bin numbers to frequencies""" +static cv::Mat_ mel_to_hz(cv::Mat_ mels, bool htk = false) { +// if (htk) { +// return //python://700.0 * (10.0**(mels / 2595.0) - 1.0); +// } + // Fill in the linear scale + double f_min = 0.0; + double f_sp = 200.0 / 3; + cv::Mat_ freqs = mels * f_sp + f_min; + // And now the nonlinear scale + double min_log_hz = 1000.0; // beginning of log region (Hz) + double min_log_mel = (min_log_hz - f_min) / f_sp; // same (Mels) + double logstep = log(6.4) / 27.0; // step size for log region + // 对照Python平台的librosa库,移植 + //if (mels.ndim) { + // If we have vector data, vectorize + cv::Mat_ log_t = (mels >= min_log_mel); + for (int i = 0; i < log_t.cols; i++) { + if (log_t(0, i)) { + freqs(0, i) = cv::exp((mels(0, i) - min_log_mel) * logstep) * min_log_hz; + } + } + //} + return freqs; +} + +static cv::Mat_ cvlinspace(double min_, double max_, int length) { + auto cvmat = cv::Mat_(1, length); + for (int i = 0; i < length; i++) { + cvmat(0, i) = ((max_ - min_) / (length - 1) * i) + min_; + } + return cvmat; +} + +//"""Create a Filterbank matrix to combine FFT bins into Mel-frequency bins""" +static cv::Mat_ mel_spectrogram_create(int nps, int n_fft, int n_mels) { + double f_max = nps / 2.0; + double f_min = 0; + int n_fft_2 = 1 + n_fft / 2; + // Initialize the weights + //auto weights = nc::zeros(nc::uint32(n_mels), nc::uint32(n_fft_2)); + auto weights = cv::Mat_(n_mels, n_fft_2, 0.0); + // Center freqs of each FFT bin + //auto fftfreqs_ = nc::linspace(f_min, f_max, nc::uint32(n_fft_2), true); + auto fftfreqs = cvlinspace(f_min, f_max, n_fft_2); + + // 'Center freqs' of mel bands - uniformly spaced between limits + double min_mel = hz_to_mel(f_min, false); + double max_mel = hz_to_mel(f_max, false); + //auto mels_ = nc::linspace(min_mel, max_mel, nc::uint32(n_mels + 2)); + auto mels = cvlinspace(min_mel, max_mel, n_mels + 2); + auto mel_f = mel_to_hz(mels, false); + + //auto fdiff_ = nc::diff(mel_f_); //沿着指定轴计算第N维的离散差值(后一个元素减去前一个元素) + cv::Mat_ d1(1, mel_f.cols * mel_f.rows - 1, (double *) (mel_f.data) + 1); + cv::Mat_ d2(1, mel_f.cols * mel_f.rows - 1, (double *) (mel_f.data)); + cv::Mat_ fdiff = d1 - d2; + + //auto ramps = nc::subtract.outer(mel_f, fftfreqs); //nc没有subtract.outer + //nc::NdArray ramps = nc::zeros(mel_f.cols, fftfreqs.cols); + auto ramps = cv::Mat_(mel_f.cols, fftfreqs.cols); + for (int i = 0; i < mel_f.cols; i++) { + for (int j = 0; j < fftfreqs.cols; j++) { + ramps(i, j) = mel_f(0, i) - fftfreqs(0, j); + } + } + + for (int i = 0; i < n_mels; i++) { + // lower and upper slopes for all bins + //auto ramps_1 = nc::NdArray(1, ramps.cols); + auto ramps_1 = cv::Mat_(1, ramps.cols); + for (int j = 0; j < ramps.cols; j++) { + ramps_1(0, j) = ramps(i, j); + } + //auto ramps_2 = nc::NdArray(1, ramps.cols); + auto ramps_2 = cv::Mat_(1, ramps.cols); + for (int j = 0; j < ramps.cols; j++) { + ramps_2(0, j) = ramps(i + 2, j); + } + cv::Mat_ lower = ramps_1 * -1 / fdiff(0, i); + cv::Mat_ upper = ramps_2 / fdiff(0, i + 1); + // .. then intersect them with each other and zero + //auto weights_1 = nc::maximum(nc::zeros(1, ramps.cols), nc::minimum(lower, upper)); + cv::Mat weights_1 = cv::Mat_(1, lower.cols); + + cv::Mat c1 = lower;//(cv::Mat_(1,5) << 1,2,-3,4,-5); + cv::Mat c2 = upper; + cv::min(c1, c2, weights_1); + cv::max(weights_1, 0, weights_1); + + for (int j = 0; j < n_fft_2; j++) { + /* + double da = lower(0,j); + double db = upper(0,j); + double dc = da>db?db:da; + if(dc<0)dc = 0; + weights(i, j) = dc;//weights_1.at(0, j); + */ + weights(i, j) = weights_1.at(0, j); + } + } + + // Slaney-style mel is scaled to be approx constant energy per channel + auto enorm = cv::Mat_(1, n_mels); + for (int j = 0; j < n_mels; j++) { + enorm(0, j) = 2.0 / (mel_f(0, j + 2) - mel_f(0, j)); + } + for (int j = 0; j < n_mels; j++) { + for (int k = 0; k < n_fft_2; k++) { + weights(j, k) *= enorm(0, j); + } + } + return weights; +} + +//"""Short-time Fourier transform (STFT)""": 默认center=True, window='hann', pad_mode='reflect' +static cv::Mat_ MagnitudeSpectrogram(const cv::Mat_ *emphasis_data, int n_fft = 2048, int hop_length = 0, int win_length = 0) { + if (win_length == 0) { + win_length = n_fft; + } + if (hop_length == 0) { + hop_length = win_length / 4; + } + + int pad_lenght = n_fft / 2; + cv::Mat_ cv_padbuffer; + cv::copyMakeBorder(*emphasis_data, cv_padbuffer, 0, 0, pad_lenght, pad_lenght, cv::BORDER_REFLECT_101); + + if (hannWindow.empty()) { + hannWindow = cv::Mat_(1, n_fft, 0.0f); + int insert_cnt = 0; + if (n_fft > win_length) { + insert_cnt = (n_fft - win_length) / 2; + } else { + //std::cout << "\tn_fft:" << n_fft << " > win_length:" << n_fft << std::endl; + return cv::Mat_(0, 0); + } + for (int k = 1; k <= win_length; k++) { + hannWindow(0, k - 1 + insert_cnt) = float(0.5 * (1 - cos(2 * pi * k / (win_length + 1)))); + } + } + int size = cv_padbuffer.rows * cv_padbuffer.cols;//padbuffer.size() + int number_feature_vectors = (size - n_fft) / hop_length + 1; + int number_coefficients = n_fft / 2 + 1; + cv::Mat_ feature_vector(number_feature_vectors, number_coefficients, 0.0f); + + audiofft::AudioFFT fft; + fft.init(size_t(n_fft)); + for (int i = 0; i <= size - n_fft; i += hop_length) { + cv::Mat_ framef = cv::Mat_(1, n_fft, (float *) (cv_padbuffer.data) + i).clone(); + framef = framef.mul(hannWindow); + + cv::Mat_ Xrf(1, number_coefficients); + cv::Mat_ Xif(1, number_coefficients); + fft.fft((float *) (framef.data), (float *) (Xrf.data), (float *) (Xif.data)); + + cv::pow(Xrf, 2, Xrf); + cv::pow(Xif, 2, Xif); + cv::Mat_ cv_feature(1, number_coefficients, &(feature_vector[i / hop_length][0])); + cv::sqrt(Xrf + Xif, cv_feature); + } + cv::Mat_ cv_mag; + cv::transpose(feature_vector, cv_mag); + cv::Mat_ mag; + cv_mag.convertTo(mag, CV_64FC1); + + return mag; +} + +//cv::Mat_ log_mel(std::vector &ifile_data, int nSamples_per_sec) { +int log_mel(float* ifile_data, int ifile_length,int nSamples_per_sec,float* ofile_data) { + if (nSamples_per_sec != nSamplesPerSec) { + return -1;//cv::Mat_(0, 0); + } + cv::Mat_ d1(1, ifile_length - 1, (float *) (ifile_data) + 1); + cv::Mat_ d2(1, ifile_length-1 , (float *) (ifile_data)); + + cv::Mat_ cv_emphasis_data; + + cv::hconcat(cv::Mat_::zeros(1, 1), d1 - d2 * preemphasis, cv_emphasis_data); + auto mag = MagnitudeSpectrogram(&cv_emphasis_data, length_DFT, hop_length, win_length); + auto magb = cv::abs(mag); + cv::pow(magb,2,mag); + + //tooken + if (mel_basis.empty()) { + mel_basis = mel_spectrogram_create(nSamplesPerSec, length_DFT, number_filterbanks); + } + + cv::Mat cv_mel = mel_basis * mag; + cv::log(cv_mel+ 1e-5, cv_mel); + cv_mel = cv_mel / 2.3025850929940459 * 10; // 2.3025850929940459=log(10) + + cv_mel = cv_mel - ref_db; + cv::Mat cv_mel_r;//(cv_mel.cols,cv_mel.rows,CV_64FC1,ofile_data); + cv::transpose(cv_mel, cv_mel_r); + //cv::Mat rcv(cv_mel_r.cols,cv_mel_r.rows, CV_32FC1,ofile_data); + cv::Mat rrr(cv_mel.cols,cv_mel.rows,CV_32FC1,ofile_data); + cv_mel_r.convertTo(rrr, CV_32FC1); + + if (r == 1) { + // 原计算公式是: + // mel = mel[:len(mel) // hp.r * hp.r].reshape([len(mel) // hp.r, hp.r * hp.n_mels]) + // 当r=1的时候公式运算无任何数值改变。 + } else { + //std::cout << R"(the "r" is not 1.)" << std::endl; + } + return 0; +} + +/**--------------------------------- 以下是pcen运算方法 ---------------------------------**/ + +// scipy.signal.lfilter_zi() +static cv::Mat_ cvlfilter_zi(cv::Mat_ b, cv::Mat_ a) { + if ((b.rows != 1) || (a.rows != 1)) { + //std::cout << "Numerator b and Denominator a must be 1-D." << std::endl; + } + if (a(0, 0) != 1) { + // Normalize the coefficients so a[0] == 1. + b = b / a(0, 0); + a = a / a(0, 0); + } + int len_a = a.cols * a.rows; + int len_b = b.cols * b.rows; + int n = len_a > len_b ? len_a : len_b; + if (len_a < n) { + cv::hconcat(a, cv::Mat_::zeros(1, n - len_a), a); + } else if (len_b < n) { + cv::hconcat(b, cv::Mat_::zeros(1, n - len_b), b); + } + return cv::Mat_(0, 0); +} +/* +// scipy.signal.lfilter() +// Filter data along one-dimension with an IIR or FIR filter. +cv::Mat_ cvlfilter(cv::Mat_ &b, cv::Mat_ &a, cv::Mat_ &x, + cv::Mat_ &zi, int axis = -1) { + if (a.rows * a.cols == 1) { + // This path only supports types fdgFDGO to mirror _linear_filter below. + // Any of b, a, x, or zi can set the dtype, but there is no default + // casting of other types; instead a NotImplementedError is raised. + // 后续如果需要,则进行补充 + } else { + // return sigtools._linear_filter(b, a, x, axis, zi) + // sigtools._linear_filter() + // (y,Vf) = _linear_filter(b,a,X,Dim=-1,Vi=None) implemented using Direct Form II transposed flow diagram. + // If Vi is not given, Vf is not returned. + ; + } +} +*/ +/********************************************* + * 名称:pcen + * 功能:传入音频数据,输出pcen方式提取的特征数据。 + * 参数:@ifile_data 传入的音频数据 + * @nSamples_per_sec 音频采样率 + * 返回:cv::Mat_ 特征数据 +*********************************************/ +static cv::Mat_ pcen(std::vector &ifile_data, int nSamples_per_sec) { + //if (!(&ifile_data) || ifile_data.empty()) { + if (ifile_data.empty()) { + //std::cout << "error: invalid paramter: ifile_data" << std::endl; + return cv::Mat_(0, 0); + } + if (nSamples_per_sec != nSamplesPerSec) { +// std::cout << R"(error: the "nSamples_per_sec" is not 16000.)" << std::endl; + return cv::Mat_(0, 0); + } + int ifile_length = int(ifile_data.size() / 4); + cv::Mat_ cv_emphasis_data(1, ifile_length, (float *) (ifile_data.data())); +// std::cout< mel = mel_basis * mag; + +#if 1 + if (!filter) { + filter = std::make_shared(); + double iir_b[1] = {0.05638943879134889}; + double iir_a[2] = {1.0, -0.9436105612086512}; + //filter.reset(); + filter->setPara(iir_b, 1, iir_a, 2); + } + cv::Mat_ S_smooth = cv::Mat_(mel.rows, mel.cols); + for (int i = 0; i < mel.rows; i++) { + filter->filter(mel[i], S_smooth[i], mel.cols); + } + +#endif + double gain = 0.98; + double bias = 2.0; + double power = 0.5; + double eps = 1e-6; + //python: smooth = np.exp(-gain * (np.log(eps) + np.log1p(S_smooth / eps))) + cv::Mat_ S_smooth_log1p; + cv::log(S_smooth / eps + 1, S_smooth_log1p); + cv::Mat_ smooth; + cv::exp((S_smooth_log1p + cv::log(eps)) * (-gain), smooth); + //python: S_out = (bias ** power) * np.expm1(power * np.log1p(ref * smooth / bias)) + cv::Mat_ smooth_log1p; + cv::Mat_ smooth_log1p_exp; + cv::log(mel.mul(smooth) / bias + 1, smooth_log1p); + cv::exp(power * smooth_log1p, smooth_log1p_exp); + cv::Mat_ S_out = (smooth_log1p_exp - 1) * pow(bias, power); + // transpose + cv::Mat_ pcen; + cv::transpose(S_out, pcen); + + return pcen; +} diff --git a/duix-sdk/src/main/cpp/dhmfcc/mfcc/AudioFFT.hpp b/duix-sdk/src/main/cpp/dhmfcc/mfcc/AudioFFT.hpp new file mode 100644 index 0000000..ef1d6c4 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhmfcc/mfcc/AudioFFT.hpp @@ -0,0 +1,120 @@ +#pragma once + +#ifndef _AUDIOFFT_H +#define _AUDIOFFT_H + + + +#include +#include +#include +#include +#include + +//#define AUDIOFFT_APPLE_ACCELERATE //AUDIOFFT_INTEL_IPP//AUDIOFFT_FFTW3//AUDIOFFT_APPLE_ACCELERATE + +#if defined(AUDIOFFT_INTEL_IPP) +#define AUDIOFFT_INTEL_IPP_USED + #include +#elif defined(AUDIOFFT_APPLE_ACCELERATE) +#define AUDIOFFT_APPLE_ACCELERATE_USED + #include + #include +#elif defined (AUDIOFFT_FFTW3) +#define AUDIOFFT_FFTW3_USED + #include +#else +#if !defined(AUDIOFFT_OOURA) +#define AUDIOFFT_OOURA +#endif +#define AUDIOFFT_OOURA_USED +#include +#endif + +namespace audiofft +{ + + namespace detail + { + class AudioFFTImpl; + } + + /** + * @class AudioFFT + * @brief Performs 1D FFTs + */ + class AudioFFT + { + public: + /** + * @brief Constructor + */ + AudioFFT(); + + AudioFFT(const AudioFFT&) = delete; + AudioFFT& operator=(const AudioFFT&) = delete; + + /** + * @brief Destructor + */ + ~AudioFFT(); + + /** + * @brief Initializes the FFT object + * @param size Size of the real input (must be power 2) + */ + void init(size_t size); + + /** + * @brief Performs the forward FFT + * @param data The real input data (has to be of the length as specified in init()) + * @param re The real part of the complex output (has to be of length as returned by ComplexSize()) + * @param im The imaginary part of the complex output (has to be of length as returned by ComplexSize()) + */ + void fft(const float* data, float* re, float* im); + + /** + * @brief Performs the inverse FFT + * @param data The real output data (has to be of the length as specified in init()) + * @param re The real part of the complex input (has to be of length as returned by ComplexSize()) + * @param im The imaginary part of the complex input (has to be of length as returned by ComplexSize()) + */ + void ifft(float* data, const float* re, const float* im); + + /** + * @brief Calculates the necessary size of the real/imaginary complex arrays + * @param size The size of the real data + * @return The size of the real/imaginary complex arrays + */ + static size_t ComplexSize(size_t size); + + private: + std::unique_ptr _impl; + }; + + + /** + * @deprecated + * @brief Let's keep an AudioFFTBase type around for now because it has been here already in the 1st version in order to avoid breaking existing code. + */ + typedef AudioFFT AudioFFTBase; + + namespace detail + { + class AudioFFTImpl + { + public: + AudioFFTImpl() = default; + AudioFFTImpl(const AudioFFTImpl&) = delete; + AudioFFTImpl& operator=(const AudioFFTImpl&) = delete; + virtual ~AudioFFTImpl() = default; + virtual void init(size_t size) = 0; + virtual void fft(const float* data, float* re, float* im) = 0; + virtual void ifft(float* data, const float* re, const float* im) = 0; + }; + } + +} // End of namespace + + +#endif // Header guard diff --git a/duix-sdk/src/main/cpp/dhmfcc/mfcc/iir_filter.hpp b/duix-sdk/src/main/cpp/dhmfcc/mfcc/iir_filter.hpp new file mode 100644 index 0000000..cb133e9 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhmfcc/mfcc/iir_filter.hpp @@ -0,0 +1,69 @@ +#pragma once + +#ifndef SERVICESUPERVISOR_IIR_FILTER_H +#define SERVICESUPERVISOR_IIR_FILTER_H + +//E(t,f) is computed using a first-order in-finite impulse response (IIR) filter +#define UES_IIR_I +//#define UES_IIR_II + +#ifdef UES_IIR_I + +class IIR_I +{ +private: + double *m_pNum; + double *m_pDen; + double *m_px; + double *m_py; + int m_num_order; + int m_den_order; +public: + IIR_I(); + ~IIR_I(); + void reset(); + void setPara(double num[], int num_order, double den[], int den_order); + void resp(double data_in[], int m, double data_out[], int n); + void filter(double data_in[], double data_out[], int len); +}; + +#endif + +#ifdef UES_IIR_II +class IIR_II +{ +public: + IIR_II(); + void reset(); + void setPara(double num[], int num_order, double den[], int den_order); + void resp(double data_in[], int m, double data_out[], int n); + double filter(double data); + void filter(double data[], int len); + void filter(double data_in[], double data_out[], int len); +protected: +private: + double *m_pNum; + double *m_pDen; + double *m_pW; + int m_num_order; + int m_den_order; + int m_N; +}; + +class IIR_BODE +{ +private: + double *m_pNum; + double *m_pDen; + int m_num_order; + int m_den_order; + std::complex poly_val(double p[], int order, double omega); +public: + IIR_BODE(); + void setPara(double num[], int num_order, double den[], int den_order); + std::complex bode(double omega); + void bode(double omega[], int n, std::complex resp[]); +}; +#endif + +#endif diff --git a/duix-sdk/src/main/cpp/dhmfcc/mfcc/mfcc.hpp b/duix-sdk/src/main/cpp/dhmfcc/mfcc/mfcc.hpp new file mode 100644 index 0000000..93697a5 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhmfcc/mfcc/mfcc.hpp @@ -0,0 +1,7 @@ +#pragma once + +//#include"../third/numcpp/NumCpp.hpp" +//#include "sas_util.h" + + +int log_mel(float* ifile_data, int ifile_length,int nSamples_per_sec,float* ofile_data) ; diff --git a/duix-sdk/src/main/cpp/dhmfcc/mfcc/sas_util.h b/duix-sdk/src/main/cpp/dhmfcc/mfcc/sas_util.h new file mode 100644 index 0000000..ba23a83 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhmfcc/mfcc/sas_util.h @@ -0,0 +1,120 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include "opencv2/core.hpp" + +//using namespace std; +//using namespace std::chrono; + +class parambase +{ +public: + std::string name; + std::string help; + std::string strval; + parambase(){} + virtual ~parambase(){} + virtual bool set(const char* value) {return true;}; +}; + +/** + */ +class EnginePar +{ +public: + static int cs_timeout; //кŷɵijʱʱ(ĬһνкŴһ,Ĭֵ5) + static int cs_detecthandsup_time; //кźֵʱ(Ĭ10s) + static int cs_detecthandsup_interval ; //кźֵʱ(Ĭ11) + static int cs_detectsmile_interval; //кź΢Цʱ(Ĭ11) + static int cs_detectspeech_interval;//кźʱ(Ĭ20) + static int cs_detectpose_interval; //кź̬ʱ(Ĭ51) + static int detectpose_interval; //ǽкڼ̬ʱ(Ĭ51) + static int detectsmile_interval; //ǽкڼ΢Цʱ(Ĭ11) + static int detectappearance_interval; //װ + static float action_turnpen_thrd; //תֵ + static float action_turnchair_thrd; //תֵ + static float action_record_time; //¼ʱ + static float sit_supporthead_thrd; //ͷֵ + static float sit_layondesk_thrd; //ſֵ + static float sit_relyingonchair_thrd;//ֵ + static std::string log_path; + static std::string log_level; + static std::string temp_path; + static bool set(const char* key, const char* val); + static bool haskey(const char* key); + static const char* getvalue(const char* key); +}; +/** + */ +enum VideoScene +{ + SCENE_counter, // ̨ + SCENE_financial, // + SCENE_lobby, // + SCENE_hall // +}; +/** + */ +class VideoPar +{ +private: + std::vector> params; +public: + VideoScene scene; //: 1̨, 2, 3, 4(װ) + bool audio_enable ; //Ƶ 1,0 + int audio_channels ; //Ƶͨ 0,1,2,4,6 + int audio_sample_rate ; // 44100, 48000, 96000, 192000 + bool video_enable ; // Ƶ 1,0 + //int video_analyse_rate ; //Ƶ: >0,ÿ֡ + bool video_sample_keyframe; //ֻؼ֡ + bool video_record; //¼Ƶ 1,0 + int video_record_duration; //Ƶ¼ʱ,Ĭ10s + int video_record_reviewtime; //Ƶ¼ƻʱ,Ĭ5s + int face_minsize; //СС + VideoPar(); + //~VideoPar(); + bool set(const char* key, const char* val); + static bool haskey(const char* key); +}; + +template +inline int64_t NowTime() +{ + return std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(); +} + +/**--------------------------------- modelsģõķ ---------------------------------**/ + +inline bool detectFileExist(char *file_path) { + std::ifstream _ifstream; + _ifstream.open(file_path, std::ios::in); + if (!_ifstream) { + return false; + } + _ifstream.close(); + return true; +} + +// 任xyת +inline cv::Mat_ rotate_point(cv::Mat_ xy, double angle) { + cv::Mat rotate_matrix = (cv::Mat_(2, 2) << cos(angle), -sin(angle), sin(angle), cos(angle)); + cv::transpose(rotate_matrix, rotate_matrix); + auto rotate_xy = xy * rotate_matrix; + return rotate_xy; +} + +// Ƿڿ +inline bool check_point_in_rect(cv::Point point, cv::Rect rect) { + if ((rect.x < point.x && point.x < rect.x + rect.width) && + (rect.y < point.y && point.y < rect.y + rect.height)) { + return true;//rectڲ + } else { + return false;//rectϻⲿ + } +} + diff --git a/duix-sdk/src/main/cpp/dhmfcc/wenetai.cpp b/duix-sdk/src/main/cpp/dhmfcc/wenetai.cpp new file mode 100644 index 0000000..5ff3c56 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhmfcc/wenetai.cpp @@ -0,0 +1,119 @@ +#include "wenetai.h" +WeAI::WeAI(int melcnt,int bnfcnt,int trd){ + n_trd = trd; + dimin = melcnt; + dimout = bnfcnt; + sizein = melcnt*80*sizeof(float); + sizeout = bnfcnt*256*sizeof(float); + shapein[1] = melcnt; + shapeout[1] = bnfcnt; + buflen[0] = melcnt; + + bufin = (float*)malloc(sizein+1024); + bufout = (float*)malloc(sizeout+1024); +} + +WeAI::~WeAI(){ + free(bufin); + free(bufout); +} + +int WeAI::dorun(float* mel,int melcnt,float* bnf,int bnfcnt){ + return 0; +} + + +int WeAI::run(float* mel,int melcnt,float* bnf,int bnfcnt){ + dimin = melcnt; + dimout = bnfcnt; + sizein = melcnt*80*sizeof(float); + sizeout = bnfcnt*256*sizeof(float); + shapein[1] = melcnt; + shapeout[1] = bnfcnt; + buflen[0] = melcnt; + return dorun(mel,melcnt,bnf,bnfcnt); +} + +int WeAI::test(){ + return dorun(bufin,dimin,bufout,dimout); +} + +int WeOnnx::dorun(float* mel,int melcnt,float* bnf,int bnfcnt){ + // + Ort::Value arrin[2] = {Ort::Value::CreateTensor( memoryInfo, mel ,sizein , shapein, 3 ,ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT),Ort::Value::CreateTensor( memoryInfo, buflen ,sizelen , shapelen, 1 ,ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32)}; + Ort::Value arrout[1] = {Ort::Value::CreateTensor( memoryInfo, bnf ,sizeout , shapeout, 3 ,ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT)}; + session.Run(runOptions, names_in, arrin, 2, names_out,arrout, 1); + return 0; +} + +WeOnnx::WeOnnx(std::string modelfn,int mel,int bnf,int trd):WeAI(mel,bnf,trd){ + // + env = Ort::Env(OrtLoggingLevel::ORT_LOGGING_LEVEL_WARNING, "wenet"); + sessionOptions = Ort::SessionOptions(); +// sessionOptions.SetIntraOpNumThreads(n_trd); + sessionOptions.SetIntraOpNumThreads(2); +// todo jth add + //sessionOptions.SetIntraOpNumThreads(1); + //sessionOptions.SetInterOpNumThreads(1); + sessionOptions.AddConfigEntry("session.disable_prepacking", "1"); + sessionOptions.SetGraphOptimizationLevel( GraphOptimizationLevel::ORT_ENABLE_ALL); + session = Ort::Session(env, modelfn.c_str(), sessionOptions); + memoryInfo = Ort::MemoryInfo::CreateCpu( OrtAllocatorType::OrtDeviceAllocator, OrtMemType::OrtMemTypeCPU); + //Ort::MemoryInfo::CreateCpu( OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault); + //tensorin = Ort::Value::CreateTensor( memoryInfo, bufin ,sizein , shapein, 3 ,ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT); + //tensorlen = Ort::Value::CreateTensor( memoryInfo, buflen ,sizelen , shapelen, 1 ,ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32); + //tensorout = Ort::Value::CreateTensor( memoryInfo, bufout ,sizeout , shapeout, 3 ,ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT); +} + +WeOnnx::~WeOnnx(){ +} + + +#ifdef WENETOPENV +int WeOpvn::dorun(float* mel,int melcnt,float* bnf,int bnfcnt){ + printf("====opvn run %d \n",sizeout); + std::cout<(); + //memcpy(bnf,data,sizeout); + return 0; +} + +WeOpvn::WeOpvn(std::string modelfn,std::string xmlfn,int mel,int bnf,int trd):WeAI(mel,bnf,trd){ + std::shared_ptr model = core.read_model(xmlfn,modelfn); + ov::preprocess::PrePostProcessor ppp(model); + + ov::preprocess::InputInfo& ainfo = ppp.input(aname); + ov::preprocess::InputInfo& binfo = ppp.input(bname); + ainput_shape[1] = mel; + aoutput_shape[1] = bnf; + binput_data[0] = mel; + ainfo.tensor().set_element_type(ainput_type).set_shape(ainput_shape); + binfo.tensor().set_element_type(binput_type).set_shape(binput_shape); + ainfo.preprocess(); // + binfo.preprocess(); // + ov::preprocess::OutputInfo& aout = ppp.output(cname); + aout.tensor().set_element_type(aoutput_type); + + model = ppp.build(); + std::string device_name = "CPU"; + ov::CompiledModel compiled_model = core.compile_model(model, device_name, + ov::inference_num_threads(int(n_trd)) ); + + infer_request = compiled_model.create_infer_request(); + // + //model = nullptr; +} + +WeOpvn::~WeOpvn(){ + +} +#endif diff --git a/duix-sdk/src/main/cpp/dhmfcc/wenetai.h b/duix-sdk/src/main/cpp/dhmfcc/wenetai.h new file mode 100644 index 0000000..20b55a0 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhmfcc/wenetai.h @@ -0,0 +1,92 @@ +#pragma once +#include +#include +#include +#include + + +class WeAI{ + protected: + int n_trd = 4; + int dimin = 321; + int dimout = 78; + int dimlen = 1; + int64_t sizein = 321*80*sizeof(float); + int64_t sizeout = 78*256*sizeof(float); + int64_t sizelen = sizeof(int32_t); + float* bufin = NULL; + float* bufout = NULL; + int32_t buflen[1]; + int64_t shapein[3]={1,321,80}; + int64_t shapelen[1]={1}; + int64_t shapeout[3]={1,78,256}; + const char* names_in[2]={"speech","speech_lengths"}; + const char* names_out[1]={"encoder_out"}; + + virtual int dorun(float* mel,int melcnt,float* bnf,int bnfcnt); + public: + WeAI(int melcnt,int bnfcnt,int trd=4); + int run(float* mel,int melcnt,float* bnf,int bnfcnt); + int test(); + virtual ~WeAI(); +}; + + +#define WENETONNX 1 +#ifdef WENETONNX +#include "onnxruntime_cxx_api.h" +class WeOnnx:public WeAI{ + protected: + + //Ort::Value tensorin{nullptr}; + //Ort::Value tensorlen{nullptr}; + //Ort::Value tensorout{nullptr}; + + Ort::Env env{nullptr}; + Ort::SessionOptions sessionOptions{nullptr}; + Ort::RunOptions runOptions; + Ort::Session session{nullptr}; + Ort::MemoryInfo memoryInfo{nullptr}; + protected: + virtual int dorun(float* mel,int melcnt,float* bnf,int bnfcnt); + public: + WeOnnx(std::string modelfn,int mel,int bnf,int trd); + virtual ~WeOnnx(); +}; +#endif + +#ifdef WENETMNN +class WeMnn:public WeAI{ +}; +#endif + + +//#define WENETOPENV +#ifdef WENETOPENV +#include "openvino/openvino.hpp" +class WeOpvn:public WeAI{ + private: + ov::element::Type ainput_type = ov::element::f32; + ov::element::Type binput_type = ov::element::i32; + ov::element::Type aoutput_type = ov::element::f32; + + ov::Shape ainput_shape = {1, 321,80}; + ov::Shape binput_shape = {1}; + ov::Shape aoutput_shape = {1, 79,256}; + + + int32_t binput_data[1]; + + ov::Core core; + ov::InferRequest infer_request ; + std::string aname = "speech"; + std::string bname = "speech_lengths"; + std::string cname = "encoder_out"; + protected: + virtual int dorun(float* mel,int melcnt,float* bnf,int bnfcnt); + public: + WeOpvn(std::string modelfn,std::string xmlfn,int mel,int bnf,int trd); + virtual ~WeOpvn(); +}; +#endif + diff --git a/duix-sdk/src/main/cpp/dhmfcc/wenetov.cpp b/duix-sdk/src/main/cpp/dhmfcc/wenetov.cpp new file mode 100644 index 0000000..2fd97f8 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhmfcc/wenetov.cpp @@ -0,0 +1,134 @@ +// Copyright (C) 2018-2025 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include +#include +#include +#include +#include +#include +#include + +// clang-format off +#include "openvino/openvino.hpp" +#include "openvino/core/preprocess/input_info.hpp" + +uint64_t jtimer_msstamp(){ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (ts.tv_sec*1000l) + (ts.tv_nsec/CLOCKS_PER_SEC); +} + +// clang-format on + +/** + * @brief Main with support Unicode paths, wide strings + */ +int main(int argc, char* argv[]) { + + const std::string amodel_path = "wenet.xml"; + const std::string bmodel_path = "wenet.bin"; + + // -------- Step 1. Initialize OpenVINO Runtime Core -------- + ov::Core core; + + // -------- Step 2. Read a model -------- + printf("===aaa\n"); + std::shared_ptr model = core.read_model(amodel_path,bmodel_path); + printf("===bbb\n"); + //printInputAndOutputsInfo(*model); + + OPENVINO_ASSERT(model->inputs().size() == 2, "Sample supports models with 1 input only"); + OPENVINO_ASSERT(model->outputs().size() == 1, "Sample supports models with 1 output only"); + + // -------- Step 3. Set up input + + // Read input image to a tensor and set it to an infer request + // without resize and layout conversions + + ov::element::Type ainput_type = ov::element::f32; + ov::Shape ainput_shape = {1, 321,80}; + float* ainput_data = (float*)malloc(sizeof(float)*321*80); + memset(ainput_data,0,sizeof(float)*321*80); + ov::element::Type binput_type = ov::element::i32; + ov::Shape binput_shape = {1}; + int32_t* binput_data = (int32_t*)malloc(10); + *binput_data = 321; + + // just wrap image data by ov::Tensor without allocating of new memory + ov::Tensor ainput_tensor = ov::Tensor(ainput_type, ainput_shape, ainput_data); + ov::Tensor binput_tensor = ov::Tensor(binput_type, binput_shape, binput_data); + + //const ov::Layout tensor_layout{"NHWC"}; + + // -------- Step 4. Configure preprocessing -------- + + ov::preprocess::PrePostProcessor ppp(model); + + // 1) Set input tensor information: + // - input() provides information about a single model input + // - reuse precision and shape from already available `input_tensor` + // - layout of data is 'NHWC' + std::string aname = "speech"; + ov::preprocess::InputInfo& ainfo = ppp.input(aname); + ainfo.tensor().set_shape(ainput_shape).set_element_type(ainput_type);//set_layout(tensor_layout); + std::string bname = "speech_lengths"; + ov::preprocess::InputInfo& binfo = ppp.input(bname); + binfo.tensor().set_shape(binput_shape).set_element_type(binput_type);//set_layout(tensor_layout); + ainfo.preprocess(); // + binfo.preprocess(); // + ppp.output().tensor().set_element_type(ov::element::f32); + // + // + // + // + // 2) Adding explicit preprocessing steps: + // - convert layout to 'NCHW' (from 'NHWC' specified above at tensor layout) + // - apply linear resize from tensor spatial dims to model spatial dims + //ppp.input().preprocess().resize(ov::preprocess::ResizeAlgorithm::RESIZE_LINEAR); + // 4) Suppose model has 'NCHW' layout for input + //ppp.input().model().set_layout("NCHW"); + // 5) Set output tensor information: + // - precision of tensor is supposed to be 'f32' + + // 6) Apply preprocessing modifying the original 'model' + model = ppp.build(); + + std::string device_name = "CPU"; + // -------- Step 5. Loading a model to the device -------- + ov::CompiledModel compiled_model = core.compile_model(model, device_name, + ov::inference_num_threads(int(4)) + ); + + // -------- Step 6. Create an infer request -------- + ov::InferRequest infer_request = compiled_model.create_infer_request(); + // ----------------------------------------------------------------------------------------------------- + + // -------- Step 7. Prepare input -------- + infer_request.set_input_tensor(0,ainput_tensor); + infer_request.set_input_tensor(1,binput_tensor); + + // -------- Step 8. Do inference synchronously -------- + for(int k=0;k<10000;k++){ + uint64_t tick = jtimer_msstamp(); + infer_request.infer(); + int dist = jtimer_msstamp()-tick; + printf("===dist %d\n",dist); + usleep(1000); + } + + // -------- Step 9. Process output + const ov::Tensor& output_tensor = infer_request.get_output_tensor(); + const float* data = output_tensor.data(); + for(int k=0;k<10;k++){ + printf("===%f \n",data[k]); + } + // + + // Print classification results + // ----------------------------------------------------------------------------------------------------- + + return EXIT_SUCCESS; +} diff --git a/duix-sdk/src/main/cpp/dhunet/blendgram.cpp b/duix-sdk/src/main/cpp/dhunet/blendgram.cpp new file mode 100644 index 0000000..f0799c3 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhunet/blendgram.cpp @@ -0,0 +1,437 @@ +#include +#include +#include + +#include "blendgram.h" + + + void exColorBlend_Normal(uint8* T,uint8* A,uint8* B){ ColorBlend_Buffer(T,A,B,Normal); } + void exColorBlend_Lighten(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,Lighten);} + void exColorBlend_Darken(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,Darken);} + void exColorBlend_Multiply(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,Multiply);} + void exColorBlend_Average(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,Average);} + void exColorBlend_Add(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,Add);} + + void exColorBlend_Subtract(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,Subtract);} + void exColorBlend_Difference(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,Difference);} + void exColorBlend_Negation(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,Negation);} + void exColorBlend_Screen(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,Screen);} + void exColorBlend_Exclusion(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,Exclusion);} + + void exColorBlend_Overlay(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,Overlay);} + void exColorBlend_SoftLight(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,SoftLight);} + void exColorBlend_HardLight(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,HardLight);} + void exColorBlend_ColorDodge(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,ColorDodge);} + void exColorBlend_ColorBurn(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,ColorBurn);} + + void exColorBlend_LinearDodge(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,LinearDodge);} + void exColorBlend_LinearBurn(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,LinearBurn);} + void exColorBlend_LinearLight(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,LinearLight);} + void exColorBlend_VividLight(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,VividLight);} + void exColorBlend_PinLight(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,PinLight);} + + void exColorBlend_HardMix(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,HardMix);} + void exColorBlend_Reflect(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,Reflect);} + void exColorBlend_Glow(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,Glow);} + void exColorBlend_Phoenix(uint8* T,uint8* A,uint8* B) { ColorBlend_Buffer(T,A,B,Phoenix);} + +typedef void (*BlendFunc) (uint8* T,uint8* A,uint8* B); +static int MAX_FUNC = 25; +static BlendFunc blendfuncs[25]={ + &exColorBlend_Normal, + &exColorBlend_Lighten, + &exColorBlend_Darken, + &exColorBlend_Multiply, + &exColorBlend_Average, + &exColorBlend_Add, + + &exColorBlend_Subtract, + &exColorBlend_Difference, + &exColorBlend_Negation, + &exColorBlend_Screen, + &exColorBlend_Exclusion, + + &exColorBlend_Overlay, + &exColorBlend_SoftLight, + &exColorBlend_HardLight, + &exColorBlend_ColorDodge, + &exColorBlend_ColorBurn, + + &exColorBlend_LinearDodge, + &exColorBlend_LinearBurn, + &exColorBlend_LinearLight, + &exColorBlend_VividLight, + &exColorBlend_PinLight, + + &exColorBlend_HardMix, + &exColorBlend_Reflect, + &exColorBlend_Glow, + &exColorBlend_Phoenix +}; + +void BlendGramSimp(unsigned char *Src,unsigned char* Mask, unsigned char *Dest, int Width, int Height, int Mode) +{ + if(Mode<1)return; + if(Mode>=MAX_FUNC)return; + BlendFunc func=blendfuncs[Mode]; + unsigned char *LinePS, *LinePD,*LinePM; + for (int Y = 0; Y < Height; Y += 1) + { + LinePS = Src + Y * Width * 4; + LinePM = Mask + Y * Width * 4; + LinePD = Dest + Y * Width * 4; + for (int X = 0; X < Width; X += 1) + { + func(LinePD,LinePS,LinePM); + LinePS += 4; + LinePM += 4; + LinePD += 4; + } + } +} + +void BlendGramAlpha3(unsigned char *Src,unsigned char* Mask, unsigned char *Dest, int Width, int Height) +{ + //printf("w %d h %d\n",Width,Height); + unsigned char *LinePS, *LinePD,*LinePM; + for (int Y = 0; Y < Height; Y += 1) + { + LinePS = Src + Y * Width * 3; + LinePM = Mask + Y * Width * 3; + LinePD = Dest + Y * Width * 3; + for (int X = 0; X < Width; X += 1) + { + //func(LinePD,LinePS,LinePM); + //ColorBlend_Alpha(LinePD,LinePD,LinePS,*LinePM); + float alpha = *LinePM/255.0f; + float beta = 1.0f-alpha; + //if(beta<0.5f) printf("==alpha %f beta %f\n",alpha,beta); + //if(beta<0.5f) printf("od %u ps %u\n",LinePD[0],LinePS[0]); + LinePD[0] = CLAMPCOLOR( LinePD[0]*alpha+LinePS[0]*beta); + //if(beta<0.5f) printf("new %u ps%u \n",LinePD[0],LinePS[0]); + //if(beta<0.5f) getchar(); + LinePD[1] = CLAMPCOLOR(LinePD[1]*alpha+LinePS[1]*beta); + LinePD[2] = CLAMPCOLOR( LinePD[2]*alpha+LinePS[2]*beta); + LinePS += 3; + LinePM += 3; + LinePD += 3; + } + } +} + +void BlendGramAlpha(unsigned char *Src,unsigned char* Mask, unsigned char *Dest, int Width, int Height) +{ + unsigned char *LinePS, *LinePD,*LinePM; + for (int Y = 0; Y < Height; Y += 1) + { + LinePS = Src + Y * Width * 3; + LinePM = Mask + Y * Width * 1; + LinePD = Dest + Y * Width * 3; + for (int X = 0; X < Width; X += 1) + { + //func(LinePD,LinePS,LinePM); + ColorBlend_Alpha(LinePD,LinePD,LinePS,*LinePM); + /* + float alpha = *LinePM/255.0f; + float beta = 1.0f-alpha; + //printf("==alpha %f beta %f\n",alpha,beta); + LinePD[0] = LinePD[0]*alpha+LinePS[0]*beta; + LinePD[1] = LinePD[1]*alpha+LinePS[1]*beta; + LinePD[2] = LinePD[2]*alpha+LinePS[2]*beta; + */ + LinePS += 3; + LinePM += 1; + LinePD += 3; + } + } +} + +void BlendGramAlphaRev(unsigned char *Src,unsigned char* Mask, unsigned char *Dest, int Width, int Height) +{ + unsigned char *LinePS, *LinePD,*LinePM; + for (int Y = 0; Y < Height; Y += 1) + { + LinePS = Src + Y * Width * 3; + LinePM = Mask + Y * Width * 1; + LinePD = Dest + Y * Width * 3; + for (int X = 0; X < Width; X += 1) + { + //func(LinePD,LinePS,LinePM); + ColorBlend_Alpha(LinePD,LinePS,LinePD,*LinePM); + LinePS += 3; + LinePM += 1; + LinePD += 3; + } + } +} + + + + +/* +void BlendGram(CBitmap* image,CBitmap* mask,int mode) +{ + if(mode<1)return; + if(mode>=MAX_FUNC)return; + BlendFunc func=blendfuncs[mode]; + int Stride=image->width*4; + unsigned char *LinePS, *LinePD,*LinePM; + for (int Y = 0; Y < image->height; Y += 1) + { + LinePS = (unsigned char*)image->pixels +image->stride*Y; + LinePM = (unsigned char*)mask->pixels + mask->stride*Y; + LinePD = (unsigned char*)image->pixels +image->stride*Y; + for (int X = 0; X < image->width; X += 1) + { + func(LinePD,LinePS,LinePM); + LinePS += 4; + LinePM += 4; + LinePD += 4; + } + } +} + +void BlendImageAdjustWithMask(CBitmap* bmp,CBitmap* adj,CBitmap* dst ,CBitmap* msk,int mode) +{ + unsigned char* bmppixels=(unsigned char*)bmp->pixels; + unsigned char* mskpixels=(unsigned char*)msk->pixels; + unsigned char* dstpixels=(unsigned char*)dst->pixels; + unsigned char* adjpixels=(unsigned char*)adj->pixels; + int stride=bmp->stride; + int width=bmp->width; + int height=bmp->height; + int X,Y; + unsigned char* LinePS , * LinePM , * LinePD , * LinePA ; + #pragma omp parallel for private(LinePS,LinePM,LinePD,LinePA,X,Y) + for (Y = 0; Y < height; Y ++) + { + int offset=stride*Y; + LinePS = bmppixels +offset; + LinePM = mskpixels +offset; + LinePD = dstpixels +offset; + LinePA = adjpixels +offset; + for (X = 0; X < width; X ++) + { + unsigned char M=*LinePM; + if(M==0xFF){ + LinePD[0]=LinePS[0]; + LinePD[1]=LinePS[1]; + LinePD[2]=LinePS[2]; + }else if(M==0x00){ + LinePD[0]=LinePA[0]; + LinePD[1]=LinePA[1]; + LinePD[2]=LinePA[2]; + }else{ + ColorBlend_Alpha(LinePD,LinePS,LinePA,M); + } + LinePD[3]=LinePS[3]; + LinePS += 4; LinePM += 4; LinePD += 4; LinePA += 4; + } + } +} + + +void BlendImageAdjustWithMaskEx(CBitmap* bmp,CBitmap* adj,CBitmap* dst ,CBitmap* msk,int mode) +{ + unsigned char* bmppixels=(unsigned char*)bmp->pixels; + unsigned char* mskpixels=(unsigned char*)msk->pixels; + unsigned char* dstpixels=(unsigned char*)dst->pixels; + unsigned char* adjpixels=(unsigned char*)adj->pixels; + int stride=bmp->stride; + int width=bmp->width; + int height=bmp->height; + int X,Y; + unsigned char* LinePS , * LinePM , * LinePD , * LinePA ; + #pragma omp parallel for private(LinePS,LinePM,LinePD,LinePA,X,Y) + for (Y = 0; Y < height; Y ++) + { + int offset=stride*Y; + LinePS = bmppixels +offset; + LinePM = mskpixels +offset; + LinePD = dstpixels +offset; + LinePA = adjpixels +offset; + for (X = 0; X < width; X ++) + { + unsigned char M=*LinePM; + if(M==0xFF){ + LinePD[0]=LinePS[0]; + LinePD[1]=LinePS[1]; + LinePD[2]=LinePS[2]; + }else if(M==0x00){ + LinePD[0]=LinePA[0]; + LinePD[1]=LinePA[1]; + LinePD[2]=LinePA[2]; + }else{ + //ColorBlend_Alpha(LinePD,LinePS,LinePA,M); + LinePD[0]=LinePS[0]*M>>8; + LinePD[1]=LinePS[1]*M>>8; + LinePD[2]=LinePS[2]*M>>8; + } + LinePD[3]=M; + LinePS += 4; LinePM += 4; LinePD += 4; LinePA += 4; + } + } +} + + + + +void BlendImageAdjustWithAlpha(CBitmap* bmp,CBitmap* adj,CBitmap* dst ,int alpha,int mode){ + unsigned char* bmppixels=(unsigned char*)bmp->pixels; + unsigned char* dstpixels=(unsigned char*)dst->pixels; + unsigned char* adjpixels=(unsigned char*)adj->pixels; + int stride=bmp->stride; + int width=bmp->width; + int height=bmp->height; + int X,Y; + unsigned char M=CLAMPCOLOR(alpha); + unsigned char *LinePS , *LinePD , *LinePA ; + #pragma omp parallel for private(LinePS,LinePD,LinePA,X,Y) + for (Y = 0; Y < height; Y ++) + { + int offset=stride*Y; + LinePS = bmppixels +offset; + LinePD = dstpixels +offset; + LinePA = adjpixels +offset; + for (X = 0; X < width; X ++) + { + if(M==0xFF){ + LinePD[0]=LinePS[0]; + LinePD[1]=LinePS[1]; + LinePD[2]=LinePS[2]; + }else if(M==0x00){ + LinePD[0]=LinePA[0]; + LinePD[1]=LinePA[1]; + LinePD[2]=LinePA[2]; + }else{ + ColorBlend_Alpha(LinePD,LinePS,LinePA,M); + } + LinePD[3]=LinePS[3]; + LinePS += 4; LinePD += 4; LinePA += 4; + } + } +} + +void BlendImageAdjustWithAlphaMask(CBitmap* bmp,CBitmap* adj,CBitmap* dst ,CBitmap* msk,int alpha,int mode){ + unsigned char* bmppixels=(unsigned char*)bmp->pixels; + unsigned char* mskpixels=(unsigned char*)msk->pixels; + unsigned char* dstpixels=(unsigned char*)dst->pixels; + unsigned char* adjpixels=(unsigned char*)adj->pixels; + int stride=bmp->stride; + int width=bmp->width; + int height=bmp->height; + int X,Y; + unsigned char NM=CLAMPCOLOR(alpha); + unsigned char *LinePS , *LinePM , *LinePD , *LinePA ; + #pragma omp parallel for private(LinePS,LinePM,LinePD,LinePA,X,Y) + for (Y = 0; Y < height; Y ++) + { + int offset=stride*Y; + LinePS = bmppixels +offset; + LinePM = mskpixels +offset; + LinePD = dstpixels +offset; + LinePA = adjpixels +offset; + for (X = 0; X < width; X ++) + { + unsigned char M=*LinePM; + if(M==0xFF){ + LinePD[0]=LinePS[0]; + LinePD[1]=LinePS[1]; + LinePD[2]=LinePS[2]; + }else if(M==0x00){ + if(NM==0xFF){ + LinePD[0]=LinePS[0]; + LinePD[1]=LinePS[1]; + LinePD[2]=LinePS[2]; + }else { + if(NM==0x00){ + //none + LinePD[0]=LinePA[0]; + LinePD[1]=LinePA[1]; + LinePD[2]=LinePA[2]; + }else{ + ColorBlend_Alpha(LinePD,LinePS,LinePA,NM); + } + } + }else{ + // + if(NM==0xFF){ + LinePD[0]=LinePS[0]; + LinePD[1]=LinePS[1]; + LinePD[2]=LinePS[2]; + }else{ + if(NM==0x00){ + ColorBlend_Alpha(LinePD,LinePS,LinePA,M); + }else{ + ColorBlend_Alpha(LinePA,LinePS,LinePA,NM); + ColorBlend_Alpha(LinePD,LinePS,LinePA,M); + } + } + } + LinePD[3]=LinePS[3]; + LinePS += 4; LinePM += 4; LinePD += 4; LinePA += 4; + } + } +} + +void ReadAlphaBySrc(CBitmap* src,CBitmap* alpha){ + memcpy(alpha,src,sizeof(CBitmap)); + alpha->stride=src->width; + alpha->channel=1; + alpha->pixels=(CPixel*)malloc(alpha->width*alpha->height*sizeof(unsigned char)); + unsigned char* bmppixels=(unsigned char*)src->pixels; + unsigned char* alapixels=(unsigned char*)alpha->pixels; + int stride=src->stride; + int width=src->width; + int height=src->height; + int X,Y; + unsigned char *LinePS , *LinePA; + //#pragma omp parallel for private(LinePS,LinePA) + for (Y = 0; Y < height; Y ++) + { + LinePS = bmppixels +stride*Y; + LinePA = alapixels +width*Y; + for (X = 0; X < width; X ++) + { + LinePA[0]=LinePS[3]; + LinePS += 4; LinePA ++; + } + } +} + + +void CheckAlpha(CBitmap* bmp,CBitmap* alpha) +{ + unsigned char* bmppixels=(unsigned char*)bmp->pixels; + unsigned char* alapixels=(unsigned char*)alpha->pixels; + int stride=bmp->stride; + int width=bmp->width; + int height=bmp->height; + int X,Y; + unsigned char *LinePS , *LinePA; + //#pragma omp parallel for private(LinePS,LinePA) + for (Y = 0; Y < height; Y ++) + { + LinePS = bmppixels +stride*Y; + LinePA = alapixels +width*Y; + for (X = 0; X < width; X ++) + { + //unsigned char M=LinePA[0]; + if(*LinePA==0x00){ + LinePS[0]=0; + LinePS[1]=0; + LinePS[2]=0; + LinePS[3]=0; + //}else if(M<0xff){ + //if(LinePD[0]>M)LinePD[0]=M; + //if(LinePD[1]>M)LinePD[1]=M; + //if(LinePD[2]>M)LinePD[2]=M; + //LinePD[3]=M; + }else{ + } + LinePS += 4; LinePA++; + } + } +} +*/ + diff --git a/duix-sdk/src/main/cpp/dhunet/blendgram.h b/duix-sdk/src/main/cpp/dhunet/blendgram.h new file mode 100644 index 0000000..7e8ec8a --- /dev/null +++ b/duix-sdk/src/main/cpp/dhunet/blendgram.h @@ -0,0 +1,287 @@ +#ifndef __BLENDGRAM_H__ +#define __BLENDGRAM_H__ + +#include +#include +#include + +typedef unsigned char uchar; +#define CLAMPCOLOR(x) (uchar)((x)<(0)?(0):((x)>(255)?(255):(x))) + +#define MMAX(A,B) ((A)>(B)?(A):(B)) +#define MMIN(A,B) ((A)<(B)?(A):(B)) + +static int ConstBlend_Buffer = 0; +static int ConstBlend_Normal=ConstBlend_Buffer+1; +static int ConstBlend_Lighten=ConstBlend_Buffer+2; +static int ConstBlend_Darken=ConstBlend_Buffer+3; +static int ConstBlend_Multiply=ConstBlend_Buffer+4; +static int ConstBlend_Average=ConstBlend_Buffer+5; + +static int ConstBlend_Add=ConstBlend_Buffer+6; +static int ConstBlend_Subtract=ConstBlend_Buffer+7; +static int ConstBlend_Difference=ConstBlend_Buffer+8; +static int ConstBlend_Negation=ConstBlend_Buffer+9; +static int ConstBlend_Screen=ConstBlend_Buffer+10; +static int ConstBlend_Exclusion=ConstBlend_Buffer+11; +static int ConstBlend_Overlay=ConstBlend_Buffer+12; +static int ConstBlend_SoftLight=ConstBlend_Buffer+13; +static int ConstBlend_HardLight=ConstBlend_Buffer+14; +static int ConstBlend_ColorDodge=ConstBlend_Buffer+15; +static int ConstBlend_ColorBurn=ConstBlend_Buffer+16; +static int ConstBlend_LinearDodge=ConstBlend_Buffer+17; +static int ConstBlend_LinearBurn=ConstBlend_Buffer+18; +static int ConstBlend_LinearLight=ConstBlend_Buffer+19; +static int ConstBlend_VividLight=ConstBlend_Buffer+20; +static int ConstBlend_PinLight=ConstBlend_Buffer+21; +static int ConstBlend_HardMix=ConstBlend_Buffer+22; +static int ConstBlend_Reflect=ConstBlend_Buffer+23; +static int ConstBlend_Glow=ConstBlend_Buffer+24; +static int ConstBlend_Phoenix=ConstBlend_Buffer+25; + +//void BlendGram(CBitmap* immage,CBitmap* mask,int mode); + +//#typedef unsigned char uint8 +#define uint8 unsigned char +#define float64 double +#define TRUE 1 +#define FALSE 0 + +inline uint8 mmin(uint8 A,uint8 B){ + return AB?A:B; +} + +#define ChannelBlend_Normal(A,B) ((uint8)(A)) +#define ChannelBlend_Lighten(A,B) ((uint8)((B > A) ? B:A)) +#define ChannelBlend_Darken(A,B) ((uint8)((B > A) ? A:B)) +#define ChannelBlend_Multiply(A,B) ((uint8)((A * B) / 255)) +#define ChannelBlend_Average(A,B) ((uint8)((A + B) / 2)) +#define ChannelBlend_Add(A,B) ((uint8)(mmin(255, (A + B)))) +#define ChannelBlend_Subtract(A,B) ((uint8)((A + B < 255) ? 0:(A + B - 255))) +#define ChannelBlend_Difference(A,B) ((uint8)(abs(A - B))) +#define ChannelBlend_Negation(A,B) ((uint8)(255 - abs(255 - A - B))) +#define ChannelBlend_Screen(A,B) ((uint8)(255 - (((255 - A) * (255 - B)) >> 8))) +#define ChannelBlend_Exclusion(A,B) ((uint8)(A + B - 2 * A * B / 255)) +#define ChannelBlend_Overlay(A,B) ((uint8)((B < 128) ? (2 * A * B / 255):(255 - 2 * (255 - A) * (255 - B) / 255))) +#define ChannelBlend_SoftLight(A,B) ((uint8)((B < 128)?(2*((A>>1)+64))*((float)B/255):(255-(2*(255-((A>>1)+64))*(float)(255-B)/255)))) +#define ChannelBlend_HardLight(A,B) (ChannelBlend_Overlay(B,A)) +#define ChannelBlend_ColorDodge(A,B) ((uint8)((B == 255) ? B:mmin(255, ((A << 8 ) / (255 - B))))) +#define ChannelBlend_ColorBurn(A,B) ((uint8)((B == 0) ? B:mmax(0, (255 - ((255 - A) << 8 ) / B)))) +#define ChannelBlend_LinearDodge(A,B)(ChannelBlend_Add(A,B)) +#define ChannelBlend_LinearBurn(A,B) (ChannelBlend_Subtract(A,B)) +#define ChannelBlend_LinearLight(A,B)((uint8)(B < 128)?ChannelBlend_LinearBurn(A,(2 * B)):ChannelBlend_LinearDodge(A,(2 * (B - 128)))) +#define ChannelBlend_VividLight(A,B) ((uint8)(B < 128)?ChannelBlend_ColorBurn(A,(2 * B)):ChannelBlend_ColorDodge(A,(2 * (B - 128)))) +#define ChannelBlend_PinLight(A,B) ((uint8)(B < 128)?ChannelBlend_Darken(A,(2 * B)):ChannelBlend_Lighten(A,(2 * (B - 128)))) +#define ChannelBlend_HardMix(A,B) ((uint8)((ChannelBlend_VividLight(A,B) < 128) ? 0:255)) +#define ChannelBlend_Reflect(A,B) ((uint8)((B == 255) ? B:mmin(255, (A * A / (255 - B))))) +#define ChannelBlend_Glow(A,B) (ChannelBlend_Reflect(B,A)) +#define ChannelBlend_Phoenix(A,B) ((uint8)(mmin(A,B) - mmax(A,B) + 255)) +#define ChannelBlend_SoftEx(A,B) (A*B/255+A*(255-((255-A)*(255-B)/255)-A*B/255)/255) + +#define ChannelBlend_Alpha(A,B,O) ((uint8)(O * A + (1 - O) * B)) +#define ChannelBlend_AlphaEx(A,B,O) ((uint8)((O * A + (255 - O) * B)/255)) +#define ChannelBlend_AlphaF(A,B,F,O) (ChannelBlend_AlphaEx(F(A,B),A,O)) + +#define ColorBlend_Alpha(T,A,B,O) (T)[0] = ChannelBlend_AlphaEx((A)[0], (B)[0],O), (T)[1] = ChannelBlend_AlphaEx((A)[1], (B)[1],O), (T)[2] = ChannelBlend_AlphaEx((A)[2], (B)[2],O) +//, (T)[3] = ChannelBlend_AlphaEx((A)[3], (B)[3],O) +#define ColorBlend_AlphaF(T,A,B,F,O) (T)[0] = ChannelBlend_AlphaF((A)[0], (B)[0],F,O), (T)[1] = ChannelBlend_AlphaF((A)[1], (B)[1],F,O), (T)[2] = ChannelBlend_AlphaF((A)[2], (B )[2],F,O) , (T)[3] = ChannelBlend_AlphaEx((A)[3], (B)[3],O) + + +#define ColorBlend_Buffer(T,A,B,M) (T)[0] = ChannelBlend_##M((A)[0], (B)[0]), (T)[1] = ChannelBlend_##M((A)[1], (B)[1]), (T)[2] = ChannelBlend_##M((A)[2], (B)[2]) + +#define ColorBlend_Normal(T,A,B) (ColorBlend_Buffer(T,A,B,Normal)) +#define ColorBlend_Lighten(T,A,B) (ColorBlend_Buffer(T,A,B,Lighten)) +#define ColorBlend_Darken(T,A,B) (ColorBlend_Buffer(T,A,B,Darken)) +#define ColorBlend_Multiply(T,A,B) (ColorBlend_Buffer(T,A,B,Multiply)) +#define ColorBlend_Average(T,A,B) (ColorBlend_Buffer(T,A,B,Average)) +#define ColorBlend_Add(T,A,B) (ColorBlend_Buffer(T,A,B,Add)) +#define ColorBlend_Subtract(T,A,B) (ColorBlend_Buffer(T,A,B,Subtract)) +#define ColorBlend_Difference(T,A,B) (ColorBlend_Buffer(T,A,B,Difference)) +#define ColorBlend_Negation(T,A,B) (ColorBlend_Buffer(T,A,B,Negation)) +#define ColorBlend_Screen(T,A,B) (ColorBlend_Buffer(T,A,B,Screen)) +#define ColorBlend_Exclusion(T,A,B) (ColorBlend_Buffer(T,A,B,Exclusion)) +#define ColorBlend_Overlay(T,A,B) (ColorBlend_Buffer(T,A,B,Overlay)) +#define ColorBlend_SoftLight(T,A,B) (ColorBlend_Buffer(T,A,B,SoftLight)) +#define ColorBlend_HardLight(T,A,B) (ColorBlend_Buffer(T,A,B,HardLight)) +#define ColorBlend_ColorDodge(T,A,B) (ColorBlend_Buffer(T,A,B,ColorDodge)) +#define ColorBlend_ColorBurn(T,A,B) (ColorBlend_Buffer(T,A,B,ColorBurn)) +#define ColorBlend_LinearDodge(T,A,B) (ColorBlend_Buffer(T,A,B,LinearDodge)) +#define ColorBlend_LinearBurn(T,A,B) (ColorBlend_Buffer(T,A,B,LinearBurn)) +#define ColorBlend_LinearLight(T,A,B) (ColorBlend_Buffer(T,A,B,LinearLight)) +#define ColorBlend_VividLight(T,A,B) (ColorBlend_Buffer(T,A,B,VividLight)) +#define ColorBlend_PinLight(T,A,B) (ColorBlend_Buffer(T,A,B,PinLight)) +#define ColorBlend_HardMix(T,A,B) (ColorBlend_Buffer(T,A,B,HardMix)) +#define ColorBlend_Reflect(T,A,B) (ColorBlend_Buffer(T,A,B,Reflect)) +#define ColorBlend_Glow(T,A,B) (ColorBlend_Buffer(T,A,B,Glow)) +#define ColorBlend_Phoenix(T,A,B) (ColorBlend_Buffer(T,A,B,Phoenix)) + + +#define ColorBlend_Hue(T,B,L) ColorBlend_Hls(T,B,L,HueL,LuminationB,SaturationB) +#define ColorBlend_Saturation(T,B,L) ColorBlend_Hls(T,B,L,HueB,LuminationB,SaturationL) +#define ColorBlend_Color(T,B,L) ColorBlend_Hls(T,B,L,HueL,LuminationB,SaturationL) +#define ColorBlend_Luminosity(T,B,L) ColorBlend_Hls(T,B,L,HueB,LuminationL,SaturationB) + + + +#define ColorBlend_Hls(T,B,L,O1,O2,O3) { \ + float64 HueB, LuminationB, SaturationB; \ + float64 HueL, LuminationL, SaturationL; \ + Color_RgbToHls((B)[2],(B)[1],(B)[0], &HueB, &LuminationB, &SaturationB); \ + Color_RgbToHls((L)[2],(L)[1],(L)[0], &HueL, &LuminationL, &SaturationL); \ + Color_HlsToRgb(O1,O2,O3,&(T)[2],&(T)[1],&(T)[0]); \ + } + + +/*********************************************************************/ + +#define COLOR_OPAQUE (0) +#define COLOR_TRANSPARENT (127) + +#define RGB_SIZE (3) +#define RGB_BPP (24) +#define RGB_MAXRED (255) +#define RGB_MAXGREEN (255) +#define RGB_MAXBLUE (255) + +#define ARGB_SIZE (4) +#define ARGB_BPP (32) +#define ARGB_MAXALPHA (127) +#define ARGB_MAXRED (RGB_MAXRED) +#define ARGB_MAXGREEN (RGB_MAXGREEN) +#define ARGB_MAXBLUE (RGB_MAXBLUE) + +/*********************************************************************/ + +#define Color_GetChannel(c,shift) ((uint8)((c) >> (shift))) +#define Color_Reverse(c,bpp) ((((uint8)(c) << 24) | ((uint8)((c) >> 8 ) << 16) | ((uint8)((c) >> 16) << 8 ) | \ ((uint8)((c) >> 24))) >> (32 - (bpp))) + +#define Rgb_ByteWidth(width) ((width) * RGB_SIZE) +#define Rgb_PixelWidth(width) ((width) / RGB_SIZE) + +#define Rgb_GetRed(rgb) (Color_GetChannel(rgb, 0)) +#define Rgb_GetGreen(rgb) (Color_GetChannel(rgb, 8)) +#define Rgb_GetBlue(rgb) (Color_GetChannel(rgb, 16)) + +#define Rgba_GetRed(rgba) (Color_GetChannel(rgba, 24)) +#define Rgba_GetGreen(rgba) (Color_GetChannel(rgba, 16)) +#define Rgba_GetBlue(rgba) (Color_GetChannel(rgba, 8)) +#define Rgba_GetAlpha(rgba) (Color_GetChannel(rgba, 0)) + +#define Argb_GetAlpha(argb) (Color_GetChannel(argb, 24)) +#define Argb_GetRed(argb) (Color_GetChannel(argb, 16)) +#define Argb_GetGreen(argb) (Color_GetChannel(argb, 8)) +#define Argb_GetBlue(argb) (Color_GetChannel(argb, 0)) + +#define MakeRgb(r,g,b) (((uint32)(uint8)(b) << 16) | ((uint16)(uint8)(g) << 8 ) | (uint8)(r)) +#define MakeRgba(r,g,b,a) (((uint32)(uint8)(r) << 24) | ((uint16)(uint8)(g) << 16) | ((uint16)(uint8)(b) << 8 ) | (uint8)(a)) +#define MakeArgb(a,r,g,b) (((uint32)(uint8)(a) << 24) | ((uint32)(uint8)(r) << 16) | ((uint16)(uint8)(g) << 8 ) | (uint8)(b)) +#define HexToRgb(hex) (MakeRgb(((hex & 0xFF0000) >> 16), ((hex & 0x00FF00) >> 8 ), (hex & 0xFF))) + +inline int Color_HueToRgb(float64 M1, float64 M2, float64 Hue, float64 *Channel) +{ + if (Hue < 0.0) + Hue += 1.0; + else if (Hue > 1.0) + Hue -= 1.0; + + if ((6.0 * Hue) < 1.0) + *Channel = (M1 + (M2 - M1) * Hue * 6.0); + else if ((2.0 * Hue) < 1.0) + *Channel = (M2); + else if ((3.0 * Hue) < 2.0) + *Channel = (M1 + (M2 - M1) * ((2.0F / 3.0F) - Hue) * 6.0); + else + *Channel = (M1); + + return TRUE; +} + +inline void Color_RgbToHls(uint8 Red, uint8 Green, uint8 Blue, float64 *Hue, float64 *Lumination, float64 *Saturation) +{ + float64 Delta; + float64 Max, Min; + float64 Redf, Greenf, Bluef; + + Redf = (float64)Red / 255.0; + Greenf = (float64)Green / 255.0; + Bluef = (float64)Blue / 255.0; + + //Max = fmax(fmax(Redf, Greenf), Bluef); + //Min = fmin(fmin(Redf, Greenf), Bluef); + Max = MMAX(MMAX(Red, Green), Blue)/255.0; + Min = MMIN(MMIN(Red, Green), Blue)/255.0; + + *Hue = 0; + *Lumination = (Max + Min) / 2.0F; + *Saturation = 0; + + if (Max == Min) + return ; + + Delta = (Max - Min); + + if (*Lumination < 0.5) + *Saturation = Delta / (Max + Min); + else + *Saturation = Delta / (2.0 - Max - Min); + + if (Redf == Max) + *Hue = (Greenf - Bluef) / Delta; + else if (Greenf == Max) + *Hue = 2.0 + (Bluef - Redf) / Delta; + else + *Hue = 4.0 + (Redf - Greenf) / Delta; + + *Hue /= 6.0; + + if (*Hue < 0.0) + *Hue += 1.0; + +} + +inline void Color_HlsToRgb(float64 Hue, float64 Lumination, float64 Saturation, uint8 *Red, uint8 *Green, uint8 *Blue) +{ + float64 M1, M2; + float64 Redf, Greenf, Bluef; + + if (Saturation == 0) { + Redf = Lumination; + Greenf = Lumination; + Bluef = Lumination; + } else { + if (Lumination <= 0.5) + M2 = Lumination * (1.0 + Saturation); + else + M2 = Lumination + Saturation - Lumination * Saturation; + + M1 = (2.0 * Lumination - M2); + + Color_HueToRgb(M1, M2, Hue + (1.0F / 3.0F), &Redf); + Color_HueToRgb(M1, M2, Hue, &Greenf); + Color_HueToRgb(M1, M2, Hue - (1.0F / 3.0F), &Bluef); + } + + *Red = (uint8)(Redf * 255); + *Blue = (uint8)(Bluef * 255); + *Green = (uint8)(Greenf * 255); + +} + +void BlendGramSimp(unsigned char *Src,unsigned char* Mask, unsigned char *Dest, int Width, int Height, int Mode); +void BlendGramAlpha(unsigned char *Src,unsigned char* Mask, unsigned char *Dest, int Width, int Height); +void BlendGramAlpha3(unsigned char *Src,unsigned char* Mask, unsigned char *Dest, int Width, int Height); +void BlendGramAlphaRev(unsigned char *Src,unsigned char* Mask, unsigned char *Dest, int Width, int Height); +/* +void BlendImageAdjustWithMask(CBitmap* bmp,CBitmap* adj,CBitmap* dst ,CBitmap* msk,int mode); +void BlendImageAdjustWithMaskEx(CBitmap* bmp,CBitmap* adj,CBitmap* dst ,CBitmap* msk,int mode); +void BlendImageAdjustWithAlpha(CBitmap* bmp,CBitmap* adj,CBitmap* dst ,int alpha,int mode); +void BlendImageAdjustWithAlphaMask(CBitmap* bmp,CBitmap* adj,CBitmap* dst ,CBitmap* msk,int alpha,int mode); + +void CheckAlpha(CBitmap* bmp,CBitmap* alpha); +void ReadAlphaBySrc(CBitmap* src,CBitmap* alpha); +*/ + +#endif diff --git a/duix-sdk/src/main/cpp/dhunet/face_utils.cpp b/duix-sdk/src/main/cpp/dhunet/face_utils.cpp new file mode 100644 index 0000000..8c842f1 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhunet/face_utils.cpp @@ -0,0 +1,133 @@ +#include "face_utils.h" +//#include + +/* +cv::Mat resize_image(cv::Mat srcimg, int height, int width, int* top, int* left){ + cv::Mat dstimg; + int srch = srcimg.rows, srcw = srcimg.cols; + int neww = width; + int newh = height; + if (srch != srcw) { + float hw_scale = (float)srch / srcw; + if (hw_scale > 1) { + newh = height; + neww = int(width / hw_scale); + cv::resize(srcimg, dstimg, cv::Size(neww, newh), cv::INTER_AREA); + *left = int((width - neww) * 0.5); + cv::copyMakeBorder(dstimg, dstimg, 0, 0, *left, width - neww - *left, cv::BORDER_CONSTANT, 0); + } + else + { + newh = (int)height * hw_scale; + neww = width; + cv::resize(srcimg, dstimg,cv::Size(neww, newh), cv::INTER_AREA); + *top = (int)(height - newh) * 0.5; + cv::copyMakeBorder(dstimg, dstimg, *top, height - newh - *top, 0, 0, cv::BORDER_CONSTANT, 0); + + } + } else { + cv::resize(srcimg, dstimg, cv::Size(neww, newh), cv::INTER_AREA); + } + return dstimg; +} +*/ + + +int dumpfile(char* file,char** pbuf){ + std::string fname(file); + std::ifstream cache(fname,std::ios::binary); + cache.seekg(0,std::ios::end); + const int engSize = cache.tellg(); + printf("===engsize %d\n",engSize ); + cache.seekg(0,std::ios::beg); + char *modelMem = (char*)malloc(engSize+8000); + cache.read(modelMem,engSize); + cache.close(); + *pbuf = modelMem; + return engSize; +} + +void dumpchar(char* abuf,int len){ + uint8_t* buf = (uint8_t*)abuf; + printf("\n----------------------chardump------------------------\n"); + int i; + for(i = 0; i < len; i++) { + printf("=%u=", buf[i]); + if( (i+1) % 16 == 0) { + printf("\n"); + } + } + if(i%16 != 0) { + printf("\n"); + } + printf("\n----------------------chardump------------------------\n"); +} + + +void dumpfloat(float* abuf,int len){ + printf("\n----------------------floatdump------------------------\n"); + int i; + for(i = 0; i < len; i++) { + printf("=%f=", abuf[i]); + if( (i+1) % 16 == 0) { + printf("\n"); + } + } + if(i%16 != 0) { + printf("\n"); + } + printf("\n----------------------floatdump------------------------\n"); +} + +void dumpshort(short* abuf,int len){ + printf("\n----------------------floatdump------------------------\n"); + int i; + for(i = 0; i < len; i++) { + printf("=%d=", abuf[i]); + if( (i+1) % 16 == 0) { + printf("\n"); + } + } + if(i%16 != 0) { + printf("\n"); + } + printf("\n----------------------floatdump------------------------\n"); +} + + +void dumphex(char* abuf,int len){ + unsigned char* buf = (unsigned char*)abuf; + int i = 0; + printf("\n----------------------hexdump------------------------\n"); + for(i = 0; i < len; i++) { + printf("=%02x=", buf[i]); + if( (i+1) % 16 == 0) { + printf("\n"); + } + } + if(i%16 != 0) { + printf("\n"); + } + printf("---------------------hexdump-------------------------\n\n"); +} + +int diffbuf(char* abuf,char* bbuf,int size){ + char* pa = abuf; + char* pb = bbuf; + int diff = 0; + for(int k= 0;k +#include +#include +#include +#include +//#include +//#include +//#include + + +void dumpchar(char* abuf,int len); +void dumphex(char* abuf,int len); +void dumpshort(short* abuf,int len); +void dumpfloat(float* abuf,int len); +void dumpdouble(double* abuf,int len); +int dumpfile(char* file,char** pbuf); +int diffbuf(char* abuf,char* bbuf,int size); + +uint64_t aitimer_msstamp(); + diff --git a/duix-sdk/src/main/cpp/dhunet/jmat.cpp b/duix-sdk/src/main/cpp/dhunet/jmat.cpp new file mode 100644 index 0000000..044c468 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhunet/jmat.cpp @@ -0,0 +1,507 @@ +#include "jmat.h" + +extern "C"{ +#pragma pack(push) +#pragma pack(4) + + typedef struct _gpg_hdr { + char head[4]; + int box[4]; + int size[4]; + int width[4]; + int height[4]; + uint8_t channel[4]; + uint8_t bit[4]; + }gpg_hdr; +#pragma pack(pop) +} + + +int JBuf::zeros(uint8_t val){ + memset(m_buf,val,m_size); + return m_size; +} + +int JBuf::copyto(JBuf* dst){ + if(m_size!=dst->m_size)return -1; + memcpy(dst->m_buf,m_buf,m_size); + return m_size; +} + +int JBuf::copyfrom(JBuf* src){ + if(m_size!=src->m_size)return -1; + memcpy(m_buf,src->m_buf,src->m_size); + return m_size; +} + + +int JBuf::forceref(int bref){ + //if(m_ref!=bref){ + m_ref = bref; + //} + return 0; +} + +JBuf::JBuf(uint32_t size,void* buf ){ + if(buf){ + m_ref = true; + m_buf = buf; + m_size = size; + }else{ + m_ref = false; + m_size = size; + m_buf = malloc(size+1024); + } +} + +JBuf::~JBuf(){ + //printf("====%d free %p\n",m_ref,m_buf); + if(!m_ref){ + free(m_buf); + m_buf = nullptr; + } +} + +JBuf::JBuf(){ + m_size = 0; + m_buf = nullptr; +} + +JMat::JMat(){ + init_tagarr(); +} + +void JMat::init_tagarr(){ + memset(m_tagarr,0,512*sizeof(int)); +} + +int* JMat::tagarr(){ + return m_tagarr; +} + +int JMat::savegpg(std::string gpgfile){ + gpg_hdr ghead; + memset(&ghead,0,sizeof(gpg_hdr)); + ghead.head[0]='g'; + ghead.head[1]='p'; + ghead.head[2]='g'; + ghead.head[3]='1'; + ghead.size[0]=m_size; + ghead.width[0]=m_width; + ghead.height[0]=m_height; + ghead.channel[0]=m_channel; + ghead.bit[0]=m_bit; + + FILE *gpgFile = NULL; + const char* fn = gpgfile.c_str(); + if ((gpgFile = fopen(fn, "wb")) == NULL)return -1; + fwrite(&ghead,sizeof(gpg_hdr),1,gpgFile); + fwrite(m_buf, m_size, 1, gpgFile); + fclose(gpgFile); + return 0; +} + +int JMat::load(std::string picfile,int flag){ + const char* fn = picfile.c_str(); + size_t len = strlen(fn); + if(len<4)return -1; + fn+= len-3; + int gpg = (fn[0]=='g')&&(fn[1]=='p')&&(fn[2]=='g'); + if(gpg){ + return loadgpg(picfile); + }else{ + return loadjpg(picfile); + } + +} + +int JMat::loadgpg(std::string gpgfile){ + FILE *gpgFile = NULL; + const char* fn = gpgfile.c_str(); + if ((gpgFile = fopen(fn, "rb")) == NULL)return -1; + int rst = 0; + while(1){ + gpg_hdr ghead; + memset(&ghead,0,sizeof(gpg_hdr)); + fread(&ghead,sizeof(gpg_hdr),1,gpgFile); + char* arr=ghead.head; + if((arr[0]=='g')&& + (arr[1]=='p')&& + (arr[2]=='g')){ + + size_t imgSize = ghead.size[0]; + if(m_sizem_height)return NULL; + int channel = c?c:m_channel; + JMat* mat = NULL; + if(m_bit==1){ + uint8_t* buf = udata()+t*m_stride+l*m_channel; + mat= new JMat(w,h,buf,channel,m_stride); + }else{ + float* buf = fdata()+t*m_stride+l*m_channel; + mat= new JMat(w,h,buf,channel,m_stride); + } + return mat; +} + +JMat* JMat::refclone(int ref){ + if(ref){ + if(m_bit==1){ + return new JMat(m_width,m_height,(uint8_t*)m_buf,m_channel,m_stride); + }else{ + return new JMat(m_width,m_height,(float*)m_buf,m_channel,m_stride); + } + }else{ + JMat* cm = new JMat(m_width,m_height,m_channel,m_stride,m_bit); + //printf("m_buf %p m_size %d\n",m_buf,m_size); + //printf("====w %d h %d c %d s %d refclone %d\n",m_width,m_height,m_channel,m_stride,ref); + memcpy(cm->m_buf,m_buf,m_size); + memcpy(cm->m_tagarr,m_tagarr,512*sizeof(int)); + return cm; + } +} + +JMat JMat::clone(){ + JMat cm(m_width,m_height,m_channel,m_stride,m_bit); + memcpy(cm.m_buf,m_buf,m_size); + memcpy(cm.m_tagarr,m_tagarr,512*sizeof(int)); + return cm; +} + +#ifdef USE_OPENCV +JMat::JMat(std::string picfile,int flag):JBuf(){ + cv::Mat image ;//= cv::imread(picfile); + m_bit = flag?1:sizeof(float); + m_width = image.cols; + m_height = image.rows; + m_channel = 3;//image.channels(); + //printf("===channels %d\n",m_channel); + m_stride = m_width*m_channel; + m_size = m_bit*m_stride*m_height; + m_buf = malloc(m_size+m_bit*m_stride); + m_ref = 0; + if(flag){ + memcpy(m_buf,image.data,m_size); + //printf("===w %d h %d\n",image.cols,image.rows); + //cv::imshow("aaa",image); + //cv::waitKey(0); + //cv::Mat fmat(m_height,m_width,CV_8UC3,m_buf); + //float scale = 1.0f/255.0f; + //image.convertTo(fmat,CV_32F,scale); + }else{ + cv::Mat fmat(m_height,m_width,CV_32FC3,m_buf); + float scale = 1.0f/255.0f; + image.convertTo(fmat,CV_32F,scale); + } + image.release(); + init_tagarr(); +} +#else +JMat::JMat(std::string picfile,int flag):JBuf(){ + +} +#endif + +JMat::~JMat(){ + //printf("====%d free 1 %p\n",m_ref,m_buf); +} + +float* JMat::fdata(){ + return (float*)m_buf; +} + +float* JMat::frow(int row){ + return ((float*)m_buf)+ row*m_stride; +} + +char* JMat::row(int row){ + return ((char*)m_buf)+ row*m_stride*m_bit; +} + +float* JMat::fitem(int row,int col){ + return ((float*)m_buf)+ row*m_stride + col; + +} + +void JMat::dump(){ + printf("jmat %p size %d bit %d===\n",m_buf,m_size,m_bit); + printf("w %d h %d c %d s %d \n",m_width,m_height,m_channel,m_stride); + if(m_height!=1){ + if(m_bit==4){ + for(int k=0;k JMat::ncarray(){ + bool own = false; + nc::NdArray arr = nc::NdArray((float*)m_buf, m_height, m_width, own); + return arr; + } + */ + + +#ifdef USE_NCNN +ncnn::Mat JMat::packingmat(){ + ncnn::Mat in_pack(m_width,m_height,1,(void*)m_buf,(size_t)4u*3,3); + ncnn::Mat in ; + ncnn::convert_packing(in_pack,in,1); + return in; +} + +ncnn::Mat JMat::ncnnmat(){ + unsigned char* data = (unsigned char*)m_buf; + if(m_channel == 3){ + ncnn::Mat mat = ncnn::Mat::from_pixels(data, ncnn::Mat::PIXEL_BGR, m_width, m_height); + return mat; + }else if(m_channel == 4){ + ncnn::Mat mat = ncnn::Mat::from_pixels(data, ncnn::Mat::PIXEL_BGRA, m_width, m_height); + return mat; + }else if(m_channel == 1){ + ncnn::Mat mat = ncnn::Mat::from_pixels(data, ncnn::Mat::PIXEL_GRAY, m_width, m_height); + return mat; + }else { + ncnn::Mat mat = ncnn::Mat::from_pixels(data, ncnn::Mat::PIXEL_GRAY, m_width*m_channel, m_height); + return mat; + } +} + + +#endif + diff --git a/duix-sdk/src/main/cpp/dhunet/jmat.h b/duix-sdk/src/main/cpp/dhunet/jmat.h new file mode 100644 index 0000000..f402853 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhunet/jmat.h @@ -0,0 +1,99 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include + +//#include "NumCpp.hpp" +#define USE_OPENCV +#define USE_NCNN +#define USE_TURBOJPG +//#define USE_PPLCV + +#ifdef USE_OPENCV +#include "opencv2/core.hpp" +#include "opencv2/imgproc.hpp" +#include "opencv2/highgui.hpp" +#endif + +#ifdef USE_NCNN +#include "mat.h" +#endif + +#ifdef USE_EIGEN +#include "eigen3/Eigen/Core" +typedef Eigen::Matrix Vectorf; +typedef Eigen::Matrix, 1, Eigen::Dynamic, Eigen::RowMajor> Vectorcf; +typedef Eigen::Matrix Matrixf; +typedef Eigen::Matrix, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> Matrixcf; +#endif + +class JBuf{ + + public: + bool m_ref = 0; + uint32_t m_size = 0; + void* m_buf = NULL; + public: + uint32_t size(){return m_size;} ; + void* data(){return m_buf;}; + bool ref(){return m_ref;}; + int zeros(uint8_t val=0); + int copyfrom(JBuf* src); + int copyto(JBuf* dst); + int forceref(int bref); + JBuf(); + JBuf(uint32_t size,void* buf = nullptr); + virtual ~JBuf(); +}; + +class JMat:public JBuf{ + public: + int m_bit = 0; + int m_width = 0; + int m_height = 0; + int m_channel = 0; + int m_stride = 0; + int m_tagarr[512]; + void init_tagarr(); + public: + int height(){return m_height;} + int width(){return m_width;} + int stride(){return m_stride;} + int channel(){return m_channel;} + JMat(int w,int h,float *buf ,int c = 3 ,int d = 0); + JMat(int w,int h,uint8_t *buf ,int c = 3 ,int d = 0); + JMat(int w,int h,int c = 3,int d = 0,int b=0); + JMat(std::string picfile,int flag=0); + JMat(); + int load(std::string picfile,int flag=0); + int loadjpg(std::string picfile,int flag=0); + int savegpg(std::string gpgfile); + int loadgpg(std::string gpgfile); + float* fdata(); + char* row(int row); + float* frow(int row); + float* fitem(int row,int col); + int tojpg(const char* fn); + int tobin(const char* fn); + int show(const char* title,int inx = 0); + JMat clone(); + JMat* refclone(int ref=1); + JMat* reshape(int w,int h,int l,int t,int c=0); + uint8_t* udata(); + virtual ~JMat(); + int* tagarr(); + void dump(); + //nc::NdArray ncarray(); +#ifdef USE_OPENCV + cv::Mat cvmat(); +#endif +#ifdef USE_NCNN + ncnn::Mat ncnnmat(); + ncnn::Mat packingmat(); +#endif + //Matrixf tomatrix(); +}; diff --git a/duix-sdk/src/main/cpp/dhunet/malpha.cpp b/duix-sdk/src/main/cpp/dhunet/malpha.cpp new file mode 100644 index 0000000..d40fbf6 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhunet/malpha.cpp @@ -0,0 +1,184 @@ +#include "malpha.h" + +MWorkMat::MWorkMat(JMat* pic,JMat* msk,const int* boxs,int kind){ + m_boxx = boxs[0]; + m_boxy=boxs[1]; + m_boxwidth=boxs[2]-m_boxx; + m_boxheight=boxs[3]-m_boxy; + //printf("x %d y %d w %d h %d \n",m_boxx,m_boxy,m_boxwidth,m_boxheight); + m_pic = pic; + m_msk = msk; + + + if(kind==168){ + + srcw = 168; + edge = 4; + adjw = 160; + mskx = 5; + msky = 5; + mskw = 150; + mskh = 145; + + }else if(kind==128){ + srcw = 134; + edge = 3; + adjw = 128; + mskx = 4; + msky = 4; + mskw = 120; + mskh = 120; + + + } + + pic_realadjw = new JMat(adjw,adjw,3,0,1); + pic_maskadjw = new JMat(adjw,adjw,3,0,1); + //pic_cropadjw = new JMat(adjw,adjw,3,0,1); + + msk_realadjw = new JMat(adjw,adjw,1,0,1); + +} + +MWorkMat::~MWorkMat(){ + matpic_orgsrcw.release(); + matpic_roirst.release(); + delete pic_realadjw; + delete pic_maskadjw; + delete msk_realadjw; + if(pic_cloneadjw) delete pic_cloneadjw; +} + +int MWorkMat::munet(JMat** ppic,JMat** pmsk){ + + *ppic = pic_realadjw; + *pmsk = pic_maskadjw; + return 0; +} + +int MWorkMat::premunet(){ + matpic_roisrc = cv::Mat(m_pic->cvmat(),cv::Rect(m_boxx,m_boxy,m_boxwidth,m_boxheight)); + cv::resize(matpic_roisrc , matpic_orgsrcw, cv::Size(srcw, srcw), cv::INTER_AREA); + matpic_roiadjw = cv::Mat(matpic_orgsrcw,cv::Rect(edge,edge,adjw,adjw)); + cv::Mat cvmask = pic_maskadjw->cvmat(); + cv::Mat cvreal = pic_realadjw->cvmat(); + //printf("===matpic %d %d\n",matpic_roiadjw.cols,matpic_roiadjw.rows); + //printf("===cvreal %d %d\n",cvreal.cols,cvreal.rows); + //getchar(); + matpic_roiadjw.copyTo(cvreal); + matpic_roiadjw.copyTo(cvmask); + pic_cloneadjw = pic_realadjw->refclone(0); + cv::rectangle(cvmask,cv::Rect(mskx,msky,mskw,mskh),cv::Scalar(0,0,0),-1);//,cv::LineTypes::FILLED); + return 0; +} + +int MWorkMat::finmunet(JMat* fgpic){ + cv::Mat cvreal = pic_realadjw->cvmat(); + + //for(int k=0;k<16;k++){ + //cv::line(cvreal,cv::Point(0,k*10),cv::Point(adjw,k*10),cv::Scalar(0,255,0)); + //} + //for(int k=0;k<16;k++){ + //cv::line(cvreal,cv::Point(k*10,0),cv::Point(k*10,adjw),cv::Scalar(0,255,0)); + //} + cvreal.copyTo(matpic_roiadjw); + //cv::imwrite("accpre.bmp",matpic_orgsrcw); + if(m_msk) vtacc((uint8_t*)matpic_orgsrcw.data,srcw*srcw); + //cv::imwrite("accend.bmp",matpic_orgsrcw); + if(fgpic&&(fgpic->width()==srcw)){ + std::vector list; + cv::split(matpic_orgsrcw,list); + matmsk_roisrc = cv::Mat(m_msk->cvmat(),cv::Rect(m_boxx,m_boxy,m_boxwidth,m_boxheight)); + cv::resize(matmsk_roisrc , matmsk_orgsrcw, cv::Size(srcw, srcw), cv::INTER_AREA); + cv::Mat rrr(srcw,srcw,CV_8UC1); + cv::cvtColor(matmsk_orgsrcw,rrr,cv::COLOR_RGB2GRAY); + list.push_back(rrr); + cv::merge(list,fgpic->cvmat()); + }else{ + cv::resize(matpic_orgsrcw, matpic_roirst, cv::Size(m_boxwidth, m_boxheight), cv::INTER_AREA); + if(fgpic){ + matpic_roisrc = cv::Mat(fgpic->cvmat(),cv::Rect(m_boxx,m_boxy,m_boxwidth,m_boxheight)); + matpic_roirst.copyTo(matpic_roisrc); + }else{ + matpic_roirst.copyTo(matpic_roisrc); + } + } + return 0; +} + +int MWorkMat::alpha(JMat** preal,JMat** pimg,JMat** pmsk){ + *preal = pic_cloneadjw; + *pimg = pic_realadjw; + *pmsk = msk_realadjw; + return 0; +} + +int MWorkMat::prealpha(){ + printf("x %d y %d w %d h %d \n",m_boxx,m_boxy,m_boxwidth,m_boxheight); + matmsk_roisrc = cv::Mat(m_msk->cvmat(),cv::Rect(m_boxx,m_boxy,m_boxwidth,m_boxheight)); + cv::resize(matmsk_roisrc , matmsk_orgsrcw, cv::Size(srcw, srcw), cv::INTER_AREA); + + matmsk_roiadjw = cv::Mat(matmsk_orgsrcw,cv::Rect(edge,edge,adjw,adjw)); + cv::Mat cvmask = msk_realadjw->cvmat(); + cv::cvtColor(matmsk_roiadjw,cvmask,cv::COLOR_RGB2GRAY); + return 0; +} + +int MWorkMat::finalpha(){ + cv::Mat cvmask = msk_realadjw->cvmat(); + cv::cvtColor(cvmask,matmsk_roiadjw,cv::COLOR_GRAY2RGB); + // + cv::resize(matmsk_orgsrcw, matmsk_roirst, cv::Size(m_boxwidth, m_boxheight), cv::INTER_AREA); + matmsk_roirst.copyTo(matmsk_roisrc); + return 0; +} + +int MWorkMat::vtacc(uint8_t* buf,int count){ + /* + int avgr = 0; + int avgb = 0; + int avgg = 0; + if(1){ + uint8_t* pb = m_pic->udata(); + for(int k=0;k<10;k++){ + avgr += *pb++; + avgg += *pb++; + avgb += *pb++; + } + avgr =avgr/10 +10; + avgg =avgg/10 -20; + if(avgg<0)avgg=0; + avgb =avgb/10 + 10; + } + */ + uint8_t* pb = buf; + for(int k=0;k=sum){ + pb[1]=sum; + //pb[0]=0; + //pb[2]=0; + // }else if((pb[0]avgg)&&(pb[2]255.f)?255:mean; + //printf("sum %ld mean %f maxg %d\n",sum,mean,maxg); + //getchar(); + pb = buf +1; + for(int k=0;kmaxg){ + *pb = maxg; + } + pb+=3; + } + */ + return 0; +} + diff --git a/duix-sdk/src/main/cpp/dhunet/malpha.h b/duix-sdk/src/main/cpp/dhunet/malpha.h new file mode 100644 index 0000000..7ad86d2 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhunet/malpha.h @@ -0,0 +1,56 @@ +#pragma once +#include "jmat.h" +//#include +#include +#include +#include +#include + +class MWorkMat{ + private: + int srcw = 168; + int edge = 4; + int adjw = 160; + + int mskx = 5; + int msky = 5; + int mskw = 150; + int mskh = 145; + int m_boxx; + int m_boxy; + int m_boxwidth; + int m_boxheight; + JMat* m_pic; + JMat* m_msk; + + JMat* pic_realadjw;//blendimg + JMat* pic_maskadjw; + + cv::Mat matpic_roisrc;//box area + cv::Mat matpic_orgsrcw; + cv::Mat matpic_roiadjw; + JMat* pic_cloneadjw;//blendimg + cv::Mat matpic_roirst; + + // + JMat* msk_realadjw; + + cv::Mat matmsk_roisrc;//box area + cv::Mat matmsk_orgsrcw; + cv::Mat matmsk_roiadjw; + + cv::Mat matmsk_roirst; + + int vtacc(uint8_t* buf,int count); + public: + MWorkMat(JMat* pic,JMat* msk,const int* boxs,int kind=168); + int premunet(); + int munet(JMat** ppic,JMat** pmsk); + int finmunet(JMat* fgpic=NULL); + int prealpha(); + int alpha(JMat** preal,JMat** pimg,JMat** pmsk); + int finalpha(); + + virtual ~MWorkMat(); +}; + diff --git a/duix-sdk/src/main/cpp/dhunet/munet.cpp b/duix-sdk/src/main/cpp/dhunet/munet.cpp new file mode 100644 index 0000000..54faf27 --- /dev/null +++ b/duix-sdk/src/main/cpp/dhunet/munet.cpp @@ -0,0 +1,275 @@ +#include "munet.h" +#include "cpu.h" +#include "face_utils.h" +#include "blendgram.h" + +Mobunet::Mobunet(const char* fnbin,const char* fnparam,const char* fnmsk,int wenetstep,int rgb){ + m_rgb = rgb; + m_wenetstep = wenetstep; + initModel(fnbin,fnparam,fnmsk); +} + +Mobunet::Mobunet(const char* modeldir,const char* modelid,int rgb){ + m_rgb = rgb; + char fnbin[1024]; + char fnparam[1024]; + char fnmsk[1024]; + sprintf(fnbin,"%s/%s.bin",modeldir,modelid); + sprintf(fnparam,"%s/%s.param",modeldir,modelid); + sprintf(fnmsk,"%s/weight_168u.bin",modeldir); + initModel(fnbin,fnparam,fnmsk); +} + +int Mobunet::initModel(const char* binfn,const char* paramfn,const char* mskfn){ + unet.clear(); + //ncnn::set_cpu_powersave(2); + //ncnn::set_omp_num_threads(2);//ncnn::get_big_cpu_count()); + //unet.opt = ncnn::Option(); + unet.opt.use_vulkan_compute = false; + unet.opt.num_threads = ncnn::get_big_cpu_count(); // 1 + //unet.load_param("model/mobileunet_v5_wenet_sim.param"); + //unet.load_model("model/mobileunet_v5_wenet_sim.bin"); + unet.load_param(paramfn); + unet.load_model(binfn); + char* wbuf = NULL; + dumpfile((char*)mskfn,&wbuf); + printf("===mskfn %s\n",mskfn); + mat_weights = new JMat(160,160,(uint8_t*)wbuf,1); + mat_weights->forceref(0); + mat_weightmin = new JMat(128,128,1); + cv::Mat ma = mat_weights->cvmat(); + cv::Mat mb; + cv::resize(ma,mb,cv::Size(128,128)); + cv::Mat mc = mat_weightmin->cvmat(); + mb.copyTo(mc); + return 0; +} + +Mobunet::~Mobunet(){ + unet.clear(); + if(mat_weights){ + delete mat_weights; + mat_weights = nullptr; + } +} + +int Mobunet::domodelold(JMat* pic,JMat* msk,JMat* feat){ + JMat picall(160*160,2,3,0,1); + uint8_t* buf = picall.udata(); + int width = pic->width(); + int height = pic->height(); + + cv::Mat c1(height,width,CV_8UC3,buf); + cv::Mat c2(height,width,CV_8UC3,buf+width*height*3); + cv::cvtColor(pic->cvmat(),c1,cv::COLOR_RGB2BGR); + cv::cvtColor(msk->cvmat(),c2,cv::COLOR_RGB2BGR); + ncnn::Mat inall ; + inall = ncnn::Mat::from_pixels(buf, ncnn::Mat::PIXEL_BGR, 160*160, 2); + inall.substract_mean_normalize(mean_vals, norm_vals); + //inall.reshape(160,160,6); + ncnn::Mat inwenet(256,20,1,feat->data()); + ncnn::Mat outpic; + ncnn::Extractor ex = unet.create_extractor(); + ex.input("face", inall); + ex.input("audio", inwenet); + ex.extract("output", outpic); + float outmean_vals[3] = {-1.0f, -1.0f, -1.0f}; + float outnorm_vals[3] = { 0.5f, 0.5f, 0.5f}; + outpic.substract_mean_normalize(outmean_vals, outnorm_vals); + ncnn::Mat pakpic; + ncnn::convert_packing(outpic,pakpic,3); + cv::Mat cvadj(160,160,CV_32FC3,pakpic.data); + //dumpfloat((float*)cvadj.data,160*160*3); + cv::Mat cvreal; + float scale = 255.0f; + cvadj.convertTo(cvreal,CV_8UC3,scale); + cv::Mat cvmask; + cv::cvtColor(cvreal,cvmask,cv::COLOR_RGB2BGR); + BlendGramAlpha((uchar*)cvmask.data,(uchar*)mat_weights->data(),(uchar*)pic->data(),160,160); + return 0; +} + +int Mobunet::domodel(JMat* pic,JMat* msk,JMat* feat,int rect){ + int width = pic->width(); + int height = pic->height(); + ncnn::Mat inmask = ncnn::Mat::from_pixels(msk->udata(), m_rgb?ncnn::Mat::PIXEL_RGB:ncnn::Mat::PIXEL_BGR2RGB, rect, rect); + inmask.substract_mean_normalize(mean_vals, norm_vals); + ncnn::Mat inreal = ncnn::Mat::from_pixels(pic->udata(), m_rgb?ncnn::Mat::PIXEL_RGB:ncnn::Mat::PIXEL_BGR2RGB, rect, rect); + inreal.substract_mean_normalize(mean_vals, norm_vals); + ncnn::Mat inpic(width,height,6); + float* buf = (float*)inpic.data; + float* pr = (float*)inreal.data; + memcpy(buf,pr,inreal.cstep*sizeof(float)*inreal.c); + buf+= inpic.cstep*inreal.c; + float* pm = (float*)inmask.data; + memcpy(buf,pm,inmask.cstep*sizeof(float)*inmask.c); + float* pf = (float*)feat->data(); + if(m_wenetstep==10){ + pf+= 256*5; + } + ncnn::Mat inwenet(256,m_wenetstep,1,pf); + ncnn::Mat outpic; + ncnn::Extractor ex = unet.create_extractor(); + ex.input("face", inpic); + ex.input("audio", inwenet); + //printf("===debug ncnn\n"); + ex.extract("output", outpic); + float outmean_vals[3] = {-1.0f, -1.0f, -1.0f}; + float outnorm_vals[3] = { 127.5f, 127.5f, 127.5f}; + outpic.substract_mean_normalize(outmean_vals, outnorm_vals); + cv::Mat cvout(width,height,CV_8UC3); + outpic.to_pixels(cvout.data,m_rgb?ncnn::Mat::PIXEL_RGB:ncnn::Mat::PIXEL_RGB2BGR); + + if(rect==160){ + BlendGramAlpha((uchar*)cvout.data,(uchar*)mat_weights->data(),(uchar*)pic->data(),width,height); + }else{ + BlendGramAlpha((uchar*)cvout.data,(uchar*)mat_weightmin->data(),(uchar*)pic->data(),width,height); + } + return 0; +} + + +int Mobunet::preprocess(JMat* pic,JMat* feat){ + //pic 168 + cv::Mat roipic(pic->cvmat(),cv::Rect(4,4,160,160)); + JMat picmask(160,160,3,0,1); + JMat picreal(160,160,3,0,1); + cv::Mat cvmask = picmask.cvmat(); + cv::Mat cvreal = picreal.cvmat(); + roipic.copyTo(cvmask); + roipic.copyTo(cvreal); + cv::rectangle(cvmask,cv::Rect(5,5,150,145),cv::Scalar(0,0,0),-1);//,cv::LineTypes::FILLED); + domodel(&picreal,&picmask,feat); + cvreal.copyTo(roipic); + return 0; +} + +int Mobunet::fgprocess(JMat* pic,const int* boxs,JMat* feat,JMat* fg){ + int boxx, boxy ,boxwidth, boxheight ; + boxx = boxs[0];boxy=boxs[1];boxwidth=boxs[2]-boxx;boxheight=boxs[3]-boxy; + int stride = pic->stride(); + cv::Mat roisrc(pic->cvmat(),cv::Rect(boxx,boxy,boxwidth,boxheight)); + cv::Mat cvorig; + cv::resize(roisrc , cvorig, cv::Size(168, 168), cv::INTER_AREA); + JMat pic168(168,168,(uint8_t*)cvorig.data); + preprocess(&pic168,feat); + cv::Mat cvrst;; + cv::resize(cvorig , cvrst, cv::Size(boxwidth, boxheight), cv::INTER_AREA); + cv::Mat roidst(fg->cvmat(),cv::Rect(boxx,boxy,boxwidth,boxheight)); + cvrst.copyTo(roidst); + return 0; +} + +int Mobunet::process(JMat* pic,const int* boxs,JMat* feat){ + int boxx, boxy ,boxwidth, boxheight ; + boxx = boxs[0];boxy=boxs[1];boxwidth=boxs[2]-boxx;boxheight=boxs[3]-boxy; + int stride = pic->stride(); + cv::Mat roisrc(pic->cvmat(),cv::Rect(boxx,boxy,boxwidth,boxheight)); + cv::Mat cvorig; + cv::resize(roisrc , cvorig, cv::Size(168, 168), cv::INTER_AREA); + JMat pic168(168,168,(uint8_t*)cvorig.data); + preprocess(&pic168,feat); + cv::Mat cvrst;; + cv::resize(cvorig , cvrst, cv::Size(boxwidth, boxheight), cv::INTER_AREA); + cvrst.copyTo(roisrc); + return 0; +} + +int Mobunet::process2(JMat* pic,const int* boxs,JMat* feat){ + int boxx, boxy ,boxwidth, boxheight ; + boxx = boxs[0];boxy=boxs[1];boxwidth=boxs[2]-boxx;boxheight=boxs[3]-boxy; + int stride = pic->stride(); + + cv::Mat cvsrc = pic->cvmat(); + printf("cvsrc %d %d \n",cvsrc.cols,cvsrc.rows); + cv::Mat roisrc(cvsrc,cv::Rect(boxx,boxy,boxwidth,boxheight)); + cv::Mat cvorig; + cv::resize(roisrc , cvorig, cv::Size(168, 168), cv::INTER_AREA); + /* + uint8_t* data =(uint8_t*)pic->data() + boxy*stride + boxx*pic->channel(); + int scale_w = 168; + int scale_h = 168; + ncnn::Mat prepic = ncnn::Mat::from_pixels_resize(data, ncnn::Mat::PIXEL_BGR, boxwidth, boxheight, stride,scale_w, scale_h); + //pic 168 + cv::Mat cvorig(168,168,CV_8UC3,prepic.data); + */ + + cv::Mat roimask(cvorig,cv::Rect(4,4,160,160)); + JMat picmask(160,160,3,0,1); + JMat picreal(160,160,3,0,1); + cv::Mat cvmask = picmask.cvmat(); + cv::Mat cvreal = picreal.cvmat(); + roimask.copyTo(cvmask); + roimask.copyTo(cvreal); + + cv::rectangle(cvmask,cv::Rect(5,5,150,150),cv::Scalar(0,0,0),-1);//,cv::LineTypes::FILLED); + + ncnn::Mat inmask = ncnn::Mat::from_pixels(picmask.udata(), ncnn::Mat::PIXEL_BGR2RGB, 160, 160); + inmask.substract_mean_normalize(mean_vals, norm_vals); + ncnn::Mat inreal = ncnn::Mat::from_pixels(picreal.udata(), ncnn::Mat::PIXEL_BGR2RGB, 160, 160); + inreal.substract_mean_normalize(mean_vals, norm_vals); + + JMat picin(160*160,2,3); + char* pd = (char*)picin.data(); + memcpy(pd,inreal.data,160*160*3*4); + memcpy(pd+ 160*160*3*4,inmask.data,160*160*3*4); + +// char* pinpic = NULL; +// dumpfile("pic.bin",&pinpic); +// dumpfloat((float*)pd,10); +// dumpfloat((float*)pinpic,10); + //ncnn::Mat inpic(160,160,6,pd,4); + ncnn::Mat inpack(160,160,1,pd,(size_t)4u*6,6); + ncnn::Mat inpic; + ncnn::convert_packing(inpack,inpic,1); + +// char* pwenet = NULL; +// dumpfile("wenet.bin",&pwenet); + ncnn::Mat inwenet(256,20,1,feat->data(),4); + ncnn::Mat outpic; + ncnn::Extractor ex = unet.create_extractor(); + ex.input("face", inpic); + ex.input("audio", inwenet); + ex.extract("output", outpic); + + float outmean_vals[3] = {-1.0f, -1.0f, -1.0f}; +// float outnorm_vals[3] = { 2.0f, 2.0f, 2.0f}; + float outnorm_vals[3] = { 127.5f, 127.5f, 127.5f}; + outpic.substract_mean_normalize(outmean_vals, outnorm_vals); + + ncnn::Mat pakpic; + ncnn::convert_packing(outpic,pakpic,3); + + cv::Mat cvadj(160,160,CV_32FC3,pakpic.data); + cv::Mat cvout(160,160,CV_8UC3); + float scale = 1.0f; + cvadj.convertTo(cvout,CV_8UC3,scale); + //cv::imwrite("cvout.jpg",cvout); + cv::cvtColor(cvout,roimask,cv::COLOR_RGB2BGR); +// cvout.copyTo(roimask); + + //cv::imwrite("roimask.jpg",roimask); + //cv::imwrite("cvorig.jpg",cvorig); + //cv::waitKey(0); + cv::resize(cvorig , roisrc, cv::Size(boxwidth, boxheight), cv::INTER_AREA); + //cv::imwrite("roisrc.jpg",roisrc); + //cv::imshow("cvsrc",cvsrc); +// cv::imshow("roisrc",roisrc); +// cv::imshow("cvorig",cvorig); +// cv::waitKey(20); + /* + { + uint8_t *pr = (uint8_t *) cvoutc.data; + printf("==%u %u %u\n", pr[0], pr[1], pr[2]); + } + // + float* p = (float*)cvadj.data; + printf("==%f %f %f\n",p[0],p[1],p[2]); + p+=160*160; + printf("==%f %f %f\n",p[0],p[1],p[2]); + p+=160*160; + printf("==%f %f %f\n",p[0],p[1],p[2]); + */ + return 0; +} + diff --git a/duix-sdk/src/main/cpp/dhunet/munet.h b/duix-sdk/src/main/cpp/dhunet/munet.h new file mode 100644 index 0000000..c840e1b --- /dev/null +++ b/duix-sdk/src/main/cpp/dhunet/munet.h @@ -0,0 +1,31 @@ +#pragma once +#include "jmat.h" +#include "net.h" +#include +#include +#include +#include +#include + + +class Mobunet{ + private: + int m_wenetstep = 20; + int m_rgb =0; + ncnn::Net unet; + float mean_vals[3] = {127.5f, 127.5f, 127.5f}; + float norm_vals[3] = {1 / 127.5f, 1 / 127.5f, 1 / 127.5f}; + JMat* mat_weights = nullptr; + JMat* mat_weightmin = nullptr; + int initModel(const char* binfn,const char* paramfn,const char* mskfn); + public: + int domodel(JMat* pic,JMat* msk,JMat* feat,int rect = 160); + int domodelold(JMat* pic,JMat* msk,JMat* feat); + int preprocess(JMat* pic,JMat* feat); + int process(JMat* pic,const int* boxs,JMat* feat); + int fgprocess(JMat* pic,const int* boxs,JMat* feat,JMat* fg); + int process2(JMat* pic,const int* boxs,JMat* feat); + Mobunet(const char* modeldir,const char* modelid,int rgb = 0); + Mobunet(const char* fnbin,const char* fnparam,const char* fnmsk,int wenetstep = 20,int rgb = 0); + ~Mobunet(); +}; diff --git a/duix-sdk/src/main/cpp/duix/gjduix.cpp b/duix-sdk/src/main/cpp/duix/gjduix.cpp new file mode 100644 index 0000000..5e66165 --- /dev/null +++ b/duix-sdk/src/main/cpp/duix/gjduix.cpp @@ -0,0 +1,290 @@ +#include +#include +#include "gjduix.h" +#include "dhwenet.h" +#include "wenetai.h" +#include "dhpcm.h" +#include "munet.h" +#include "malpha.h" +#include "dhwenet.h" + +struct dhmfcc_s{ + int mincalc; + int minoff; + int minblock; + int maxblock; + int inited; + char* wenetfn; + + //DhWenet* wenet; + WeAI* weai_first; + WeAI* weai_common; + PcmSession* cursess; + PcmSession* presess; + volatile uint64_t sessid; + + volatile int running; + pthread_t *calcthread; + pthread_mutex_t pushmutex; + pthread_mutex_t readmutex; +}; + + +static void *calcworker(void *arg){ + dhmfcc_t* mfcc = (dhmfcc_t*)arg; + uint64_t sessid = 0; + while(mfcc->running){ + int rst = 0; + PcmSession* sess = mfcc->cursess; + if(sess &&(sess->sessid()==mfcc->sessid)){ + rst = sess->runcalc(mfcc->sessid,mfcc->weai_common,mfcc->mincalc); + } + if(rst!=1){ + jtimer_mssleep(20); + }else{ + jtimer_mssleep(10); + } + } + return NULL; +} + +int dhmfcc_alloc(dhmfcc_t** pdg,int mincalc){ + dhmfcc_t* mfcc = (dhmfcc_t*)malloc(sizeof(dhmfcc_t)); + memset(mfcc,0,sizeof(dhmfcc_t)); + mfcc->mincalc = mincalc?mincalc:1; + mfcc->minoff = STREAM_BASE_MINOFF; + mfcc->minblock = STREAM_BASE_MINBLOCK; + mfcc->maxblock = STREAM_BASE_MAXBLOCK; + pthread_mutex_init(&mfcc->pushmutex,NULL); + pthread_mutex_init(&mfcc->readmutex,NULL); + mfcc->calcthread = (pthread_t *)malloc(sizeof(pthread_t) ); + mfcc->running = 1; + pthread_create(mfcc->calcthread, NULL, calcworker, (void*)mfcc); + *pdg = mfcc; + return 0; +} + +int dhmfcc_initPcmex(dhmfcc_t* dg,int maxsize,int minoff ,int minblock ,int maxblock){ + dg->minoff = minoff; + dg->minblock = minblock; + dg->maxblock = maxblock; + dg->inited = 1; +#ifdef WENETOPENV + if(dg->wenetfn){ + // + std::string fnonnx(dg->wenetfn); + std::string fnovbin = fnonnx+"_ov.bin"; + std::string fnovxml = fnonnx+"_ov.xml"; + int melcnt = DhWenet::cntmel(dg->minblock); + int bnfcnt = DhWenet::cntbnf(melcnt); + WeAI* awenet ; + awenet = new WeOpvn(fnovbin,fnovxml,melcnt,bnfcnt,4); + if(dg->weai_first){ + WeAI* oldw = dg->weai_first; + dg->weai_first = awenet; + delete oldw; + }else{ + dg->weai_first = awenet; + } + awenet->test(); + } +#endif + return 0; +} + +int dhmfcc_initWenet(dhmfcc_t* dg,char* fnwenet){ + dg->wenetfn = strdup(fnwenet); + + std::string fnonnx(fnwenet); + WeAI* awenet ; + int melcnt = DhWenet::cntmel(dg->minblock); + int bnfcnt = DhWenet::cntbnf(melcnt); +#ifdef WENETOPENV + if(dg->inited){ + std::string fnovbin = fnonnx+"_ov.bin"; + std::string fnovxml = fnonnx+"_ov.xml"; + awenet = new WeOpvn(fnovbin,fnovxml,melcnt,bnfcnt,4); + }else{ + awenet = new WeOnnx(fnwenet,melcnt,bnfcnt,4); + } +#else + awenet = new WeOnnx(fnwenet,melcnt,bnfcnt,4); +#endif + WeAI* bwenet = new WeOnnx(fnwenet,321,79,4); + if(dg->weai_first){ + WeAI* oldw = dg->weai_first; + dg->weai_first = awenet; + delete oldw; + }else{ + dg->weai_first = awenet; + } + if(dg->weai_common){ + WeAI* oldw = dg->weai_common; + dg->weai_common = bwenet; + delete oldw; + }else{ + dg->weai_common = bwenet; + } + awenet->test(); + bwenet->test(); + return awenet?0:-1; +} + +uint64_t dhmfcc_newsession(dhmfcc_t* dg){ + uint64_t sessid = ++dg->sessid; + PcmSession* sess = new PcmSession(sessid,dg->minoff,dg->minblock,dg->maxblock); + PcmSession* olds = dg->presess; + dg->presess = dg->cursess; + dg->cursess = sess; + if(olds)delete olds; + return sessid; +} + +int dhmfcc_pushpcm(dhmfcc_t* dg,uint64_t sessid,char* buf,int size,int kind){ + if(sessid!=dg->sessid)return -1; + if(!dg->running)return -2; + PcmSession* sess = dg->cursess; + if(!sess)return -3; + int rst = 0; + pthread_mutex_lock(&dg->pushmutex); + rst = sess->pushpcm(sessid,(uint8_t*)buf,size); + pthread_mutex_unlock(&dg->pushmutex); + if(rst>0){ + if(sess->first()){ + sess->runfirst(sessid,dg->weai_first); + uint64_t tick = jtimer_msstamp(); + printf("====runfirst %ld %ld \n",sessid,tick); + } + return 0; + }else{ + return rst; + } +} + +int dhmfcc_readpcm(dhmfcc_t* dg,uint64_t sessid,char* pcmbuf,int pcmlen,char* bnfbuf,int bnflen){ + if(sessid!=dg->sessid)return -1; + if(!dg->running)return -2; + PcmSession* sess = dg->cursess; + if(!sess)return -3; + int rst = 0; + pthread_mutex_lock(&dg->readmutex); + rst = sess->readnext(sessid,(uint8_t*)pcmbuf,pcmlen,(uint8_t*)bnfbuf,bnflen); + pthread_mutex_unlock(&dg->readmutex); + return rst; +} + +int dhmfcc_consession(dhmfcc_t* dg,uint64_t sessid){ + if(sessid!=dg->sessid)return -1; + if(!dg->running)return -2; + PcmSession* sess = dg->cursess; + if(!sess)return -3; + return sess->conpcm(sessid); +} + +int dhmfcc_finsession(dhmfcc_t* dg,uint64_t sessid){ + if(sessid!=dg->sessid)return -1; + if(!dg->running)return -2; + PcmSession* sess = dg->cursess; + if(!sess)return -3; + return sess->finpcm(sessid); +} + +int dhmfcc_free(dhmfcc_t* dg){ + dg->running = 0; + pthread_join(*dg->calcthread, NULL); + if(dg->weai_first){ + delete dg->weai_first; + dg->weai_first = NULL; + } + if(dg->weai_common){ + delete dg->weai_common; + dg->weai_common = NULL; + } + if(dg->cursess){ + delete dg->cursess; + dg->cursess = NULL; + } + if(dg->presess){ + delete dg->presess; + dg->presess = NULL; + } + pthread_mutex_destroy(&dg->pushmutex); + pthread_mutex_destroy(&dg->readmutex); + free(dg->calcthread); + free(dg); + // + return 0; +} + +struct dhunet_s{ + int inited; + int rgb; + Mobunet *munet; +}; + +int dhunet_alloc(dhunet_t** pdg,int rgb){ + dhunet_t* unet = (dhunet_t*)malloc(sizeof(dhunet_t)); + memset(unet,0,sizeof(dhunet_t)); + unet->rgb = 1; + *pdg = unet; + return 0; +} + +int dhunet_initMunet(dhunet_t* dg,char* fnparam,char* fnbin,char* fnmsk){ + dg->munet = new Mobunet(fnbin,fnparam,fnmsk,20,dg->rgb); + dg->inited = 1; + printf("===init munet \n"); + return 0; +} + +#define AIRUN_FLAG 1 +int dhunet_simprst(dhunet_t* dg,uint64_t sessid,uint8_t* bpic,int width,int height,int* box,uint8_t* bmsk,uint8_t* bfg,uint8_t* bnfbuf,int bnflen){ + //printf("simprst gogogo %d \n",dg->inited); + if(!dg->inited)return -1; + if(bnflen!=STREAM_ALL_BNF)return -2; + if(!dg->munet)return -3; + int rst = 0; + JMat* mat_pic = new JMat(width,height,bpic); + JMat* mat_msk = bmsk?new JMat(width,height,bmsk):NULL; + JMat* mat_fg = bfg?new JMat(width,height,bfg):NULL; + JMat* feat = new JMat(STREAM_CNT_BNF,STREAM_BASE_BNF,(float*)bnfbuf,1); + + MWorkMat wmat(mat_pic,mat_msk,box); + wmat.premunet(); + JMat* mpic; + JMat* mmsk; + wmat.munet(&mpic,&mmsk); + //tooken +#ifdef AIRUN_FLAG + uint64_t ticka = jtimer_msstamp(); + rst = dg->munet->domodel(mpic, mmsk, feat); + uint64_t tickb = jtimer_msstamp(); + uint64_t dist = tickb-ticka; + if(dist>40){ + printf("===domodel %d dist %ld\n",rst,dist); + } +#endif + if(mat_fg){ + wmat.finmunet(mat_fg); + }else{ + wmat.finmunet(mat_pic); + } + if(feat)delete feat; + delete mat_pic; + if(mat_fg)delete mat_fg; + if(mat_msk)delete mat_msk; + return 0; +} + +int dhunet_free(dhunet_t* dg){ + dg->inited = 0; + if(dg->munet){ + delete dg->munet; + dg->munet = NULL; + } + free(dg); + return 0; + +} + + diff --git a/duix-sdk/src/main/cpp/duix/gjduix.h b/duix-sdk/src/main/cpp/duix/gjduix.h new file mode 100644 index 0000000..e2f058c --- /dev/null +++ b/duix-sdk/src/main/cpp/duix/gjduix.h @@ -0,0 +1,38 @@ +#ifndef GJDUIX_ +#define GJDUIX_ + +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +typedef struct dhmfcc_s dhmfcc_t;; + +int dhmfcc_alloc(dhmfcc_t** pdg,int mincalc); +int dhmfcc_initPcmex(dhmfcc_t* dg,int maxsize,int minoff ,int minblock ,int maxblock); +int dhmfcc_initWenet(dhmfcc_t* dg,char* fnwenet); + +uint64_t dhmfcc_newsession(dhmfcc_t* dg); +int dhmfcc_pushpcm(dhmfcc_t* dg,uint64_t sessid,char* buf,int size,int kind); +int dhmfcc_readpcm(dhmfcc_t* dg,uint64_t sessid,char* pcmbuf,int pcmlen,char* bnfbuf,int bnflen); +int dhmfcc_finsession(dhmfcc_t* dg,uint64_t sessid); +int dhmfcc_consession(dhmfcc_t* dg,uint64_t sessid); + +int dhmfcc_free(dhmfcc_t* dg); + + +typedef struct dhunet_s dhunet_t;; +int dhunet_alloc(dhunet_t** pdg,int minrender); +int dhunet_initMunet(dhunet_t* dg,char* fnparam,char* fnbin,char* fnmsk); +int dhunet_simprst(dhunet_t* dg,uint64_t sessid,uint8_t* bpic,int width,int height,int* box,uint8_t* bmsk,uint8_t* bfg,uint8_t* bnfbuf,int bnflen); +int dhunet_free(dhunet_t* pdg); + + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/duix-sdk/src/main/cpp/duix/gjsimp.cpp b/duix-sdk/src/main/cpp/duix/gjsimp.cpp new file mode 100644 index 0000000..79a7485 --- /dev/null +++ b/duix-sdk/src/main/cpp/duix/gjsimp.cpp @@ -0,0 +1,453 @@ +#include "gjsimp.h" +#include +#include +#include "dhwenet.h" +#include "wenetai.h" +#include "dhpcm.h" +#include "munet.h" +#include "malpha.h" +#include "dhwenet.h" +#include +//#include "Log.h" + + +struct dhduix_s{ + int kind; + int rect; + int width; + int height; + int mincalc; + int minoff; + int minblock; + int maxblock; + int inited; + char* wenetfn; + + //DhWenet* wenet; + WeAI* weai_first; + WeAI* weai_common; + PcmSession* cursess; + //PcmSession* presess; + volatile uint64_t sessid; + + jmat_t *mat_feat; + volatile int running; + pthread_t *calcthread; + pthread_mutex_t pushmutex; + pthread_mutex_t readmutex; + pthread_mutex_t freemutex; + std::queue *slist; + + int rgb; + Mobunet *munet; + JMat *mat_pic; + JMat *mat_fg; + JMat *mat_msk; +}; + +static void *calcworker(void *arg){ + dhduix_t* mfcc = (dhduix_t*)arg; + uint64_t sessid = 0; + while(mfcc->running){ + int rst = 0; + PcmSession* sess = mfcc->cursess; + if(sess &&(sess->sessid()==mfcc->sessid)){ + rst = sess->runcalc(mfcc->sessid,mfcc->weai_common,mfcc->mincalc); + } + if(rst!=1){ + if(!mfcc->slist->empty()){ + pthread_mutex_lock(&mfcc->freemutex); + PcmSession* sess = mfcc->slist->front(); + mfcc->slist->pop(); + delete sess; + pthread_mutex_unlock(&mfcc->freemutex); + jtimer_mssleep(10); + }else{ + jtimer_mssleep(20); + } + }else{ + jtimer_mssleep(10); + } + } + return NULL; +} + +int dhduix_alloc(dhduix_t** pdg,int mincalc,int width,int height){ + dhduix_t* duix = (dhduix_t*)malloc(sizeof(dhduix_t)); + memset(duix,0,sizeof(dhduix_t)); + duix->mincalc = mincalc?mincalc:1; + duix->minoff = STREAM_BASE_MINOFF; + duix->minblock = STREAM_BASE_MINBLOCK; + duix->maxblock = STREAM_BASE_MAXBLOCK; + pthread_mutex_init(&duix->pushmutex,NULL); + pthread_mutex_init(&duix->readmutex,NULL); + pthread_mutex_init(&duix->freemutex,NULL); + duix->slist = new std::queue(); + duix->calcthread = (pthread_t *)malloc(sizeof(pthread_t) ); + duix->running = 1; + pthread_create(duix->calcthread, NULL, calcworker, (void*)duix); + duix->rgb = 1; + duix->width = width; + duix->height = height; + duix->mat_msk = new JMat(width,height); + duix->mat_fg = new JMat(width,height); + duix->mat_pic = new JMat(width,height); + //duix->mat_feat = jmat_alloc(20,STREAM_BASE_BNF,1,0,4,NULL); + duix->mat_feat = jmat_alloc(STREAM_BASE_BNF,20,1,0,4,NULL); + duix->kind = 168; + duix->rect = 160; + *pdg = duix; + return 0; +} + +int dhduix_initPcmex(dhduix_t* dg,int maxsize,int minoff ,int minblock ,int maxblock,int rgb){ + dg->minoff = minoff; + dg->minblock = minblock; + dg->maxblock = maxblock; + dg->inited = 1; +#ifdef WENETOPENV + if(dg->wenetfn){ + // + std::string fnonnx(dg->wenetfn); + std::string fnovbin = fnonnx+"_ov.bin"; + std::string fnovxml = fnonnx+"_ov.xml"; + int melcnt = DhWenet::cntmel(dg->minblock); + int bnfcnt = DhWenet::cntbnf(melcnt); + WeAI* awenet ; + awenet = new WeOpvn(fnovbin,fnovxml,melcnt,bnfcnt,4); + if(dg->weai_first){ + WeAI* oldw = dg->weai_first; + dg->weai_first = awenet; + delete oldw; + }else{ + dg->weai_first = awenet; + } + awenet->test(); + } +#endif + dg->rgb = rgb; + return 0; +} + +int dhduix_initWenet(dhduix_t* dg,char* fnwenet){ + dg->wenetfn = strdup(fnwenet); + + std::string fnonnx(fnwenet); + WeAI* awenet ; + int melcnt = DhWenet::cntmel(dg->minblock); + int bnfcnt = DhWenet::cntbnf(melcnt); +#ifdef WENETOPENV + if(dg->inited){ + std::string fnovbin = fnonnx+"_ov.bin"; + std::string fnovxml = fnonnx+"_ov.xml"; + awenet = new WeOpvn(fnovbin,fnovxml,melcnt,bnfcnt,4); + }else{ + awenet = new WeOnnx(fnwenet,melcnt,bnfcnt,4); + } +#else + awenet = new WeOnnx(fnwenet,melcnt,bnfcnt,4); +#endif + WeAI* bwenet = new WeOnnx(fnwenet,321,79,4); + if(dg->weai_first){ + WeAI* oldw = dg->weai_first; + dg->weai_first = awenet; + delete oldw; + }else{ + dg->weai_first = awenet; + } + if(dg->weai_common){ + WeAI* oldw = dg->weai_common; + dg->weai_common = bwenet; + delete oldw; + }else{ + dg->weai_common = bwenet; + } + awenet->test(); + bwenet->test(); + return awenet?0:-1; +} + +uint64_t dhduix_newsession(dhduix_t* dg){ + uint64_t sessid = ++dg->sessid; + PcmSession* sess = new PcmSession(sessid,dg->minoff,dg->minblock,dg->maxblock); + //PcmSession* olds = dg->presess; + //dg->presess = dg->cursess; + //dg->cursess = sess; + //if(olds)delete olds; + pthread_mutex_lock(&dg->pushmutex); + pthread_mutex_lock(&dg->readmutex); + PcmSession* olds = dg->cursess; + dg->cursess = sess; + pthread_mutex_unlock(&dg->pushmutex); + pthread_mutex_unlock(&dg->readmutex); + pthread_mutex_lock(&dg->freemutex); + dg->slist->push(olds); + pthread_mutex_unlock(&dg->freemutex); + return sessid; +} + +int dhduix_pushpcm(dhduix_t* dg,uint64_t sessid,char* buf,int size,int kind){ + if(sessid!=dg->sessid)return -1; + if(!dg->running)return -2; + PcmSession* sess = dg->cursess; + if(!sess)return -3; + int rst = 0; + pthread_mutex_lock(&dg->pushmutex); + rst = sess->pushpcm(sessid,(uint8_t*)buf,size); + pthread_mutex_unlock(&dg->pushmutex); + if(rst>0){ + if(sess->first()){ + sess->runfirst(sessid,dg->weai_first); + uint64_t tick = jtimer_msstamp(); + printf("====runfirst %ld %ld \n",sessid,tick); + } + return 0; + }else{ + return rst; + } +} + +int dhduix_readpcm(dhduix_t* dg,uint64_t sessid,char* pcmbuf,int pcmlen,char* bnfbuf,int bnflen){ + if(sessid!=dg->sessid)return -1; + if(!dg->running)return -2; + PcmSession* sess = dg->cursess; + if(!sess)return -3; + int rst = 0; + pthread_mutex_lock(&dg->readmutex); + rst = sess->readnext(sessid,(uint8_t*)pcmbuf,pcmlen,(uint8_t*)bnfbuf,bnflen); + pthread_mutex_unlock(&dg->readmutex); + return rst; +} + +int dhduix_consession(dhduix_t* dg,uint64_t sessid){ + if(sessid!=dg->sessid)return -1; + if(!dg->running)return -2; + PcmSession* sess = dg->cursess; + if(!sess)return -3; + return sess->conpcm(sessid); +} + +int dhduix_finsession(dhduix_t* dg,uint64_t sessid){ + if(sessid!=dg->sessid)return -1; + if(!dg->running)return -2; + PcmSession* sess = dg->cursess; + if(!sess)return -3; + return sess->finpcm(sessid); +} + +int dhduix_free(dhduix_t* dg){ + dg->running = 0; + pthread_join(*dg->calcthread, NULL); + if(dg->slist){ + pthread_mutex_lock(&dg->freemutex); + while(!dg->slist->empty()){ + PcmSession* sess = dg->slist->front(); + dg->slist->pop(); + delete sess; + } + pthread_mutex_unlock(&dg->freemutex); + delete dg->slist; + } + + if(dg->weai_first){ + delete dg->weai_first; + dg->weai_first = NULL; + } + if(dg->weai_common){ + delete dg->weai_common; + dg->weai_common = NULL; + } + if(dg->cursess){ + delete dg->cursess; + dg->cursess = NULL; + } + //if(dg->presess){ + //delete dg->presess; + //dg->presess = NULL; + //} + if(dg->munet){ + delete dg->munet; + dg->munet = NULL; + } + if(dg->mat_fg){ + delete dg->mat_fg; + dg->mat_fg = NULL; + } + if(dg->mat_pic){ + delete dg->mat_pic; + dg->mat_pic = NULL; + } + if(dg->mat_msk){ + delete dg->mat_msk; + dg->mat_msk = NULL; + } + pthread_mutex_destroy(&dg->pushmutex); + pthread_mutex_destroy(&dg->readmutex); + pthread_mutex_destroy(&dg->freemutex); + free(dg->calcthread); + jmat_free(dg->mat_feat); + free(dg); + // + return 0; +} + + +int dhduix_initMunet(dhduix_t* dg,char* fnparam,char* fnbin,char* fnmsk){ + dg->munet = new Mobunet(fnbin,fnparam,fnmsk,20,dg->rgb); + dg->inited = 1; + printf("===init munet \n"); + dg->kind = 168; + dg->rect = 160; + return 0; +} + +int dhduix_initMunetex(dhduix_t* dg,char* fnparam,char* fnbin,char* fnmsk,int rect){ + dg->munet = new Mobunet(fnbin,fnparam,fnmsk,20,dg->rgb); + dg->inited = 1; + if(rect==128){ + dg->kind = 128; + dg->rect = 128; + }else{ + dg->kind = 168; + dg->rect = 160; + } + printf("===init munet \n"); + return 0; +} + +int dhduix_simppcm(dhduix_t* dg,char* buf,int size,char* pre,int presize,char* bnf,int bnfsize){ + if(!dg->running)return -2; + PcmFile* mfcc = new PcmFile(25,10,STREAM_BASE_MAXBLOCK,STREAM_BASE_MAXBLOCK*20); + mfcc->prepare(buf,size,pre,presize); + mfcc->process(-1,dg->weai_first); + int rst = mfcc->readbnf(buf,size); + + return rst; +} + +int dhduix_allcnt(dhduix_t* dg,uint64_t sessid){ + PcmSession* sess = dg->cursess; + if(!sess)return -3; + if(sess->sessid()!=sessid)return 0; + return sess->fileBlock(); +} + +int dhduix_readycnt(dhduix_t* dg,uint64_t sessid){ + PcmSession* sess = dg->cursess; + if(!sess)return -3; + if(sess->sessid()!=sessid)return 0; + return sess->calcBlock(); +} + + +#define AIRUN_FLAG 1 +int dhduix_fileinx(dhduix_t* dg,uint64_t sessid,char* fnpic,int* box,char* fnmsk,char* fnfg,int bnfinx,char* bimg,char* mskbuf,int imgsize){ + if(sessid!=dg->sessid)return -1; + if(!dg->running)return -2; + + uint64_t ticka = jtimer_msstamp(); + std::string sfnpic(fnpic); + std::string sfnmsk(fnmsk); + std::string sfnfg(fnfg); + JMat* mat_pic = dg->mat_pic; + mat_pic->loadjpg(sfnpic,1); + uint8_t* bpic = (uint8_t*)mat_pic->data(); + uint8_t* bmsk = NULL; + uint8_t* bfg = NULL; + JMat* mat_msk = NULL; + if(sfnmsk.length()){ + mat_msk = dg->mat_msk; + mat_msk->loadjpg(sfnmsk,1); + bmsk = (uint8_t*)mat_msk->data(); + memcpy(mskbuf,bmsk,dg->width*dg->height*3); + } + JMat* mat_fg = NULL; + if(sfnfg.length()){ + mat_fg = dg->mat_fg; + mat_fg->loadjpg(sfnfg,1); + bfg = (uint8_t*)mat_fg->data(); + } + uint64_t tickb = jtimer_msstamp(); + uint64_t dist = tickb-ticka; + //LOGD("tooken","===loadjpg %ld\n",dist); + int rst = 0; + if(box){ + rst = dhduix_simpinx(dg,sessid, bpic,dg->width,dg->height, box, bmsk, bfg,bnfinx); + }else{ + rst = dhduix_simpblend(dg,sessid, bpic,dg->width,dg->height, bmsk, bfg); + } + int size = dg->width*dg->height*3; + if(bfg){ + memcpy(bimg,bfg,size); + }else{ + memcpy(bimg,bpic,size); + } + if(bmsk) memcpy(mskbuf,bmsk,size); + return rst; +} + +int dhduix_simpinx(dhduix_t* dg,uint64_t sessid,uint8_t* bpic,int width,int height,int* box,uint8_t* bmsk,uint8_t* bfg,int inx){ + if(sessid!=dg->sessid)return -1; + if(!dg->running)return -2; + PcmSession* sess = dg->cursess; + if(!sess)return -3; + int rst = 0; + int w = width?width:dg->width; + int h = height?height:dg->height; + pthread_mutex_lock(&dg->readmutex); + rst = sess->readblock(sessid,dg->mat_feat,inx); + pthread_mutex_unlock(&dg->readmutex); + //printf("===readblock %d\n",rst); + if(rst>0){ + rst = dhduix_simprst(dg,sessid, bpic,w,h, box, bmsk, bfg,(uint8_t*)dg->mat_feat->data,STREAM_ALL_BNF); + return 1; + } + return rst; +} + +int dhduix_simpblend(dhduix_t* dg,uint64_t sessid,uint8_t* bpic,int width,int height,uint8_t* bmsk,uint8_t* bfg){ + // + return 0; +} + +int dhduix_simprst(dhduix_t* dg,uint64_t sessid,uint8_t* bpic,int width,int height,int* box,uint8_t* bmsk,uint8_t* bfg,uint8_t* bnfbuf,int bnflen){ + //printf("simprst gogogo %d \n",dg->inited); + if(!dg->inited)return -1; + if(!dg->munet)return -3; + int rst = 0; + JMat* mat_pic = new JMat(width,height,bpic); + JMat* mat_msk = bmsk?new JMat(width,height,bmsk):NULL; + JMat* mat_fg = bfg?new JMat(width,height,bfg):NULL; + //read pcm + JMat* feat = new JMat(STREAM_CNT_BNF,STREAM_BASE_BNF,(float*)bnfbuf,1); + +// MWorkMat wmat(mat_pic,mat_msk,box); + MWorkMat wmat(mat_pic, NULL,box,dg->kind); + wmat.premunet(); + JMat* mpic; + JMat* mmsk; + wmat.munet(&mpic,&mmsk); + //tooken +#ifdef AIRUN_FLAG + uint64_t ticka = jtimer_msstamp(); + rst = dg->munet->domodel(mpic, mmsk, feat,dg->rect); + uint64_t tickb = jtimer_msstamp(); + uint64_t dist = tickb-ticka; + //LOGD("tooken","===domodel %ld\n",dist); + if(dist>40){ + printf("===domodel %d dist %ld\n",rst,dist); + } +#endif + if(mat_fg){ + wmat.finmunet(mat_fg); + }else{ + wmat.finmunet(mat_pic); + } + if(feat)delete feat; + delete mat_pic; + if(mat_fg)delete mat_fg; + if(mat_msk)delete mat_msk; + return 0; +} + + diff --git a/duix-sdk/src/main/cpp/include/aicommon.h b/duix-sdk/src/main/cpp/include/aicommon.h new file mode 100644 index 0000000..bb62453 --- /dev/null +++ b/duix-sdk/src/main/cpp/include/aicommon.h @@ -0,0 +1,39 @@ +#pragma once + +//#define MFCC_OFFSET 6436 +#define MFCC_OFFSET 6400 +//##define MFCC_OFFSET 0 +#define MFCC_DEFRMS 0.1f +#define MFCC_FPS 25 +#define MFCC_RATE 16000 +//#define MFCC_WAVCHUNK 960000 +#define MFCC_WAVCHUNK 560000 +//#define MFCC_WAVCHUNK 512 + +//#define MFCC_MELBASE 6001 +#define MFCC_MELBASE 3501 +#define MFCC_MELCHUNK 80 +//#define MFCC_MELCHUNK 20 + +//#define MFCC_BNFBASE 1499 +#define MFCC_BNFBASE 874 +#define MFCC_BNFCHUNK 256 +//input==== NodeArg(name='speech', type='tensor(float)', shape=['B', 'T', 80]) +//input==== NodeArg(name='speech_lengths', type='tensor(int32)', shape=['B']) +//output==== NodeArg(name='encoder_out', type='tensor(float)', shape=['B', 'T_OUT', 'Addencoder_out_dim_2']) +#define STREAM_BASE_MINOFF 10 +#define STREAM_BASE_MINBLOCK 20 +#define STREAM_BASE_MAXBLOCK 50 +#define STREAM_BASE_TICK 40 +#define STREAM_BASE_PCM 1280 +#define STREAM_BASE_SAMP 640 +#define STREAM_BASE_BNF 256 +#define STREAM_CNT_BNF 20 +#define STREAM_OFF_BNF 20 +#define STREAM_ALL_BNF 20480 +#define STREAM_BASE_MEL 80 +#define STREAM_BASE_CNT 1500 +//#define STREAM_BASE_CNT 050 +#define STREAM_MFCC_FILL 10 +//#define STREAM_MFCC_FILL 5 + diff --git a/duix-sdk/src/main/cpp/include/dhextctrl.h b/duix-sdk/src/main/cpp/include/dhextctrl.h new file mode 100644 index 0000000..322f8a0 --- /dev/null +++ b/duix-sdk/src/main/cpp/include/dhextctrl.h @@ -0,0 +1,55 @@ +#ifndef GJ_EXTCTRL +#define GJ_EXTCTRL + +#include +#include "dhextend.h" +#include "gj_threadpool.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + typedef void (*func_extprocess)(void *data); + typedef struct{ + ext_env_t* env;; + jqueue_t* q_msg; + jqueue_t* q_input; + jqueue_t* q_output; + uint64_t tick_process; + ext_handle_t* hnd_process; + func_extrun fn_run; + func_extprocess fn_process; + }ext_process_t; + + typedef struct{ + ext_model_t* asr_model; + ext_model_t* chat_model; + ext_model_t* tts_model; + ext_model_t* bnf_model; + ext_model_t* render_model; + }extmain_t; + + typedef struct{ + volatile uint64_t m_sessid; + volatile int m_running; + ext_env_t* env_sess; + ext_process_t* asr_proc; + ext_process_t* chat_proc; + ext_process_t* tts_proc; + threadpool_t* pool; + }extsess_t; + + typedef int (*func_inout)(uint64_t looptick,void* arg); + + int ext_createsess( extmain_t* extmain,char* uuid,extsess_t** pext); + int ext_startsess(extsess_t* ext,func_inout fn_input,func_inout fn_output,void* tag); + int ext_stopsess(extsess_t* ext); + int ext_destroysess(extsess_t** pext); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/duix-sdk/src/main/cpp/include/dhextend.h b/duix-sdk/src/main/cpp/include/dhextend.h new file mode 100644 index 0000000..dde12c8 --- /dev/null +++ b/duix-sdk/src/main/cpp/include/dhextend.h @@ -0,0 +1,62 @@ + +#ifndef GJ_BOTCORE +#define GJ_BOTCORE +#include "dh_mem.h" +#include "dh_data.h" +#include "dh_que.h" + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct ext_handle_t ext_handle_t; + typedef struct ext_env_t ext_env_t;; + + typedef ext_handle_t* (*func_extcreate)(char* uuid,void* env,void* tag); + typedef int (*func_extdestroy)(ext_handle_t *exthandle); + typedef int (*func_extupsess)(ext_handle_t *handle,uint64_t sessid); + typedef int (*func_extstart)(ext_handle_t *handle); + typedef int (*func_extstop)(ext_handle_t *handle); + typedef int (*func_extrun)(ext_handle_t *handle,uint64_t sessid,jbuf_t* buf); + typedef int (*func_extrunex)(ext_handle_t *handle,uint64_t sessid,jbuf_t** buf); + + typedef struct ext_model_t{ + int m_id; + char* m_name; + func_extcreate fn_create; + func_extdestroy fn_destroy; + }ext_model_t; + + + struct ext_handle_t{ + void *ext_tag; + char *m_uuid; + uint64_t m_sessid; + func_extstart fn_start; + func_extstop fn_stop; + func_extupsess fn_upsess; + func_extrun fn_extrun; + func_extrun fn_extrunex; + }; + + struct ext_env_t{ + uint64_t m_sessid; + volatile int m_running; + jqueue_t* q_arrext[16];//msg pcm asr chat tts mfcc render + }; + +#define INX_QMSG 0 +#define INX_QPCM 1 +#define INX_QASR 2 +#define INX_QCHAT 3 +#define INX_QANSWER 4 +#define INX_QTTS 5 +#define INX_QMFCC 6 +#define INX_QRENDER 7 + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/duix-sdk/src/main/cpp/include/dhextinc.h b/duix-sdk/src/main/cpp/include/dhextinc.h new file mode 100644 index 0000000..2831225 --- /dev/null +++ b/duix-sdk/src/main/cpp/include/dhextinc.h @@ -0,0 +1,22 @@ + +#ifndef GJ_EXTINC +#define GJ_EXTINC +#include "dhextend.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +ext_model_t* load_funasrext(char* cfg); +ext_model_t* load_chatggmlext(char* cfg); +ext_model_t* load_piperext(char* cfg); +ext_model_t* load_msasrext(char* cfg); + +ext_model_t* load_aliasrext(char* cfg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/duix-sdk/src/main/cpp/include/gj_dll.h b/duix-sdk/src/main/cpp/include/gj_dll.h new file mode 100644 index 0000000..9d1c953 --- /dev/null +++ b/duix-sdk/src/main/cpp/include/gj_dll.h @@ -0,0 +1,21 @@ +#ifndef __GJ_DLL_H__ +#define __GJ_DLL_H__ + +#ifdef __cplusplus +extern "C" { +#endif +#define GJLIB_EXPORT 1 +#if defined(GJLIB_EXPORT) + #if defined _WIN32 || defined __CYGWIN__ + #define GJLIBAPI __declspec(dllexport) + #else + #define GJLIBAPI __attribute__((visibility("default"))) + #endif +#else + #define GJLIBAPI +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/duix-sdk/src/main/cpp/include/gjduix.h b/duix-sdk/src/main/cpp/include/gjduix.h new file mode 100644 index 0000000..4cbd3b6 --- /dev/null +++ b/duix-sdk/src/main/cpp/include/gjduix.h @@ -0,0 +1,38 @@ +#ifndef GJDUIX_ +#define GJDUIX_ + +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +typedef struct dhmfcc_s dhmfcc_t; + +int dhmfcc_alloc(dhmfcc_t** pdg,int mincalc); +int dhmfcc_initPcmex(dhmfcc_t* dg,int maxsize,int minoff ,int minblock ,int maxblock); +int dhmfcc_initWenet(dhmfcc_t* dg,char* fnwenet); + +uint64_t dhmfcc_newsession(dhmfcc_t* dg); +int dhmfcc_pushpcm(dhmfcc_t* dg,uint64_t sessid,char* buf,int size,int kind); +int dhmfcc_readpcm(dhmfcc_t* dg,uint64_t sessid,char* pcmbuf,int pcmlen,char* bnfbuf,int bnflen); +int dhmfcc_finsession(dhmfcc_t* dg,uint64_t sessid); +int dhmfcc_consession(dhmfcc_t* dg,uint64_t sessid); + +int dhmfcc_free(dhmfcc_t* dg); + + +typedef struct dhunet_s dhunet_t;; +int dhunet_alloc(dhunet_t** pdg,int minrender); +int dhunet_initMunet(dhunet_t* dg,char* fnparam,char* fnbin,char* fnmsk); +int dhunet_simprst(dhunet_t* dg,uint64_t sessid,uint8_t* bpic,int width,int height,int* box,uint8_t* bmsk,uint8_t* bfg,uint8_t* bnfbuf,int bnflen); +int dhunet_free(dhunet_t* pdg); + + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/duix-sdk/src/main/cpp/include/gjsimp.h b/duix-sdk/src/main/cpp/include/gjsimp.h new file mode 100644 index 0000000..abb3838 --- /dev/null +++ b/duix-sdk/src/main/cpp/include/gjsimp.h @@ -0,0 +1,52 @@ +#ifndef GJSIMP +#define GJSIMP + +#include +#ifdef __cplusplus +extern "C"{ +#endif + + +typedef struct dhduix_s dhduix_t; + +int dhduix_alloc(dhduix_t** pdg,int mincalc,int width,int height); +int dhduix_initPcmex(dhduix_t* dg,int maxsize,int minoff ,int minblock ,int maxblock,int rgb); +int dhduix_initWenet(dhduix_t* dg,char* fnwenet); +int dhduix_initMunet(dhduix_t* dg,char* fnparam,char* fnbin,char* fnmsk); +int dhduix_initMunetex(dhduix_t* dg,char* fnparam,char* fnbin,char* fnmsk,int rect); + +uint64_t dhduix_newsession(dhduix_t* dg); + +int dhduix_pushpcm(dhduix_t* dg,uint64_t sessid,char* buf,int size,int kind); +int dhduix_readpcm(dhduix_t* dg,uint64_t sessid,char* pcmbuf,int pcmlen,char* bnfbuf,int bnflen); +int dhduix_simprst(dhduix_t* dg,uint64_t sessid,uint8_t* bpic,int width,int height,int* box,uint8_t* bmsk,uint8_t* bfg,uint8_t* bnfbuf,int bnflen); + +int dhduix_allcnt(dhduix_t* dg,uint64_t sessid); +int dhduix_readycnt(dhduix_t* dg,uint64_t sessid); +int dhduix_simpinx(dhduix_t* dg,uint64_t sessid,uint8_t* bpic,int width,int height,int* box,uint8_t* bmsk,uint8_t* bfg,int bnfinx); +int dhduix_fileinx(dhduix_t* dg,uint64_t sessid,char* fnpic,int* box,char* fnmsk,char* fnfg,int bnfinx,char* bimg,char* mskbuf,int imgsize); +int dhduix_simpblend(dhduix_t* dg,uint64_t sessid,uint8_t* bpic,int width,int height,uint8_t* bmsk,uint8_t* bfg); + +int dhduix_simppcm(dhduix_t* dg,char* buf,int size,char* pre,int presize,char* bnf,int bnfsize); + + +int dhduix_finsession(dhduix_t* dg,uint64_t sessid); +int dhduix_consession(dhduix_t* dg,uint64_t sessid); + + + +int dhduix_free(dhduix_t* dg); + + + + + + + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/duix-sdk/src/main/cpp/iostest/testduix.cpp b/duix-sdk/src/main/cpp/iostest/testduix.cpp new file mode 100644 index 0000000..3f847bb --- /dev/null +++ b/duix-sdk/src/main/cpp/iostest/testduix.cpp @@ -0,0 +1,129 @@ +#include +#include +#include +#include "gjduix.h" +#include "jmat.h" +#include +#include "dh_data.h" + + +static volatile int g_running = 0; +static volatile uint64_t g_sessid = 0; +static void* mfccworker(void* arg){ + + static uint64_t sessid ; + for(int k=0;k<1;k++){ + dhmfcc_t* mfcc = (dhmfcc_t*)arg; + FILE* g_wavfile = fopen("data/b10.wav","rb"); + fseek(g_wavfile,44,0); + sessid = dhmfcc_newsession(mfcc); + g_sessid = sessid; + int psize = 1000; + int tickcnt = 0; + int kkk = 0; + char* pcm = (char*)malloc(psize); + while(sessid == g_sessid){ + int readpcm = fread(pcm,1,psize,g_wavfile); + if(readpcm<1)break; + dhmfcc_pushpcm(mfcc,sessid,pcm,readpcm,0); + tickcnt += readpcm; + uint64_t tick = jtimer_msstamp(); + //printf("====push %d %ld \n",tickcnt,tick); + kkk++; + /* + if(kkk%100==99){ + sessid = dhmfcc_newsession(mfcc); + g_sessid = sessid; + } + */ + jtimer_mssleep(5); + } + jtimer_mssleep(10000); + dhmfcc_finsession(mfcc,sessid); + free(pcm); + fclose(g_wavfile); + printf("===finish\n"); + } + return NULL; +} + + +int main(int argc,char** argv){ + dhmfcc_t* mfcc = NULL; + int rst = 0; + rst = dhmfcc_alloc(&mfcc,2); + //char* fnwenet = "model/wenet.onnx"; + char* fnwenet = "model/wenet.onnx"; + rst = dhmfcc_initWenet(mfcc,fnwenet); + rst = dhmfcc_initPcmex(mfcc,0,10,20,50); + dhunet_t* unet = NULL; + rst = dhunet_alloc(&unet,20); + rst = dhunet_initMunet(unet,"model/xinyan_opt.param","model/xinyan_opt.bin","model/weight_168u.bin"); + + std::string fnpic = "data/xinyan.jpg"; + std::string fnmsk = "data/m1.jpg"; + std::string fnfg = "data/xinyan.jpg"; + JMat* mat_msk = new JMat(); + mat_msk->loadjpg(fnmsk,1); + JMat* mat_pic = new JMat(); + mat_pic->loadjpg(fnpic,1); + JMat* mat_fg = new JMat(); + mat_fg->loadjpg(fnfg,1); + int width = mat_pic->width(); + int height = mat_pic->height(); + int m_boxs[4]; + m_boxs[0]=170;m_boxs[2]=382;m_boxs[1]=382;m_boxs[3]=592; + uint8_t* bpic = (uint8_t*)mat_pic->data(); + uint8_t* bmsk = (uint8_t*)mat_msk->data(); + uint8_t* bfg = (uint8_t*)mat_fg->data(); + int* box = m_boxs; + int pcmsize = 1280; + char* pcm = (char*)malloc(1280); + int bnfsize = 1024*20; + char* bnf = (char*)malloc(1024*20); + pthread_t audtrd; + pthread_create(&audtrd, NULL, mfccworker, (void*)mfcc); + //mfccworker(mfcc); + + printf("====render\n"); + //getchar(); + while(1){ + if(!g_sessid){ + printf("+"); + //cv::waitKey(40); + jtimer_mssleep(40); + continue; + } + rst = dhmfcc_readpcm(mfcc,g_sessid,pcm,pcmsize,bnf,bnfsize); + printf("===readpcm %ld %d\n",g_sessid,rst); + if(rst>0){ + uint64_t tick = jtimer_msstamp(); + printf("====read %ld \n",tick); + rst = dhunet_simprst(unet,g_sessid, bpic,width,height, box, bmsk, bfg, (uint8_t*)bnf,bnfsize); + printf("===simprst %d\n",rst); + mat_fg->show("aaa"); + cv::waitKey(30); + jtimer_mssleep(40); + }else if(rst < 0){ + break; + }else{ + //cv::waitKey(40); + jtimer_mssleep(40); + } + } + g_sessid = 0; + pthread_join(audtrd,NULL); + printf("====exit\n"); + // + rst = dhmfcc_free(mfcc); + printf("====exitmfcc\n"); + /* + rst = dhunet_free(unet); + delete mat_pic; + delete mat_msk; + delete mat_fg; + */ + free(pcm); + free(bnf); + return 0; +} diff --git a/duix-sdk/src/main/cpp/iostest/testsimp.cpp b/duix-sdk/src/main/cpp/iostest/testsimp.cpp new file mode 100644 index 0000000..8536c6c --- /dev/null +++ b/duix-sdk/src/main/cpp/iostest/testsimp.cpp @@ -0,0 +1,200 @@ +#include +#include +#include +#include "gjsimp.h" +#include "jmat.h" +#include +#include "dh_data.h" + + +static volatile int g_running = 0; +static volatile uint64_t g_sessid = 0; +static void* mfccworker(void* arg){ + + static uint64_t sessid ; + for(int k=0;k<1;k++){ + dhduix_t* mfcc = (dhduix_t*)arg; + FILE* g_wavfile = fopen("data/b10.wav","rb"); + fseek(g_wavfile,44,0); + sessid = dhduix_newsession(mfcc); + g_sessid = sessid; + int psize = 1000; + int tickcnt = 0; + int kkk = 0; + char* pcm = (char*)malloc(psize); + while(sessid == g_sessid){ + int readpcm = fread(pcm,1,psize,g_wavfile); + if(readpcm<1)break; + dhduix_pushpcm(mfcc,sessid,pcm,readpcm,0); + tickcnt += readpcm; + uint64_t tick = jtimer_msstamp(); + //printf("====push %d %ld \n",tickcnt,tick); + kkk++; + /* + if(kkk%100==99){ + sessid = dhduix_newsession(mfcc); + g_sessid = sessid; + } + */ + jtimer_mssleep(5); + } + jtimer_mssleep(10000); + dhduix_finsession(mfcc,sessid); + free(pcm); + fclose(g_wavfile); + printf("===finish\n"); + } + return NULL; +} + + +int mainmemcheck(int argc,char** argv){ + dhduix_t* dg = NULL; + int rst = 0; + int width = 540; + int height = 720; + rst = dhduix_alloc(&dg,20,width,height); + //char* fnwenet = "model/wenet.onnx"; + rst = dhduix_initPcmex(dg,0,10,20,50,0); + rst = dhduix_initMunetex(dg,"model/xinyan_opt.param","model/xinyan_opt.bin","model/weight_168u.bin",128); + //char* fnwenet = "model/wenet.onnx"; + char* fnwenet = "model/wenet.onnx"; + rst = dhduix_initWenet(dg,fnwenet); + char* pcm = (char*)malloc(102400); + + std::string fnpic = "data/xinyan.jpg"; + std::string fnmsk = "data/m1.jpg"; + std::string fnfg = "data/xinyan.jpg"; + JMat* mat_msk = new JMat(); + mat_msk->loadjpg(fnmsk,1); + JMat* mat_pic = new JMat(); + mat_pic->loadjpg(fnpic,1); + JMat* mat_fg = new JMat(); + mat_fg->loadjpg(fnfg,1); + int m_boxs[4]; + m_boxs[0]=170;m_boxs[2]=382;m_boxs[1]=382;m_boxs[3]=592; + uint8_t* bpic = (uint8_t*)mat_pic->data(); + uint8_t* bmsk = (uint8_t*)mat_msk->data(); + uint8_t* bfg = (uint8_t*)mat_fg->data(); + int* box = m_boxs; + for(int m=0;m<10;m++){ + g_sessid = dhduix_newsession(dg); + for(int k=0;k<100;k++){ + dhduix_pushpcm(dg,g_sessid,pcm,102400,0); + int allcnt = dhduix_allcnt(dg,g_sessid); + printf("===allcnt %d\n",allcnt); + } + int readycnt = dhduix_readycnt(dg,g_sessid); + while(readycnt<1){ + jtimer_mssleep(10); + } + for(int i=0;i<100;i++){ + readycnt = dhduix_readycnt(dg,g_sessid); + //printf("===readycnt %d\n",readycnt); + rst = dhduix_simpinx(dg,g_sessid, bpic,width,height, box, bmsk, bfg, i); + printf("==simp %d\n",rst); + jtimer_mssleep(10); + if(rst<0)break; + } + dhduix_finsession(dg,g_sessid); + } + free(pcm); + delete mat_pic; + delete mat_msk; + delete mat_fg; + dhduix_free(dg); + return 0; +} + +int main(int argc,char** argv){ + dhduix_t* dg = NULL; + int rst = 0; + int width = 1080; + int height = 1920; + rst = dhduix_alloc(&dg,20,width,height); + //char* fnwenet = "model/wenet.onnx"; + char* fnwenet = "model/wenet.onnx"; + rst = dhduix_initWenet(dg,fnwenet); + rst = dhduix_initPcmex(dg,0,10,20,50,0); + rst = dhduix_initMunetex(dg, + "mdl128/pro128/dh_model.param", + "mdl128/pro128/dh_model.bin","model/weight_168u.bin",128); + + //std::string fnpic = "data/xinyan.jpg"; + //std::string fnmsk = "data/m1.jpg"; + std::string fnpic = "mdl128/pro128/raw_jpgs/1.sij"; + std::string fnmsk = "mdl128/pro128/pha/1.sij"; + std::string fnfg = "mdl128/pro128/raw_sg/1.sij"; + //std::string fnfg = "data/xinyan.jpg"; + JMat* mat_msk = new JMat(); + mat_msk->loadjpg(fnmsk,1); + JMat* mat_pic = new JMat(); + mat_pic->loadjpg(fnpic,1); + JMat* mat_fg = new JMat(); + mat_fg->loadjpg(fnfg,1); + int m_boxs[4]; + //m_boxs[0]=170;m_boxs[2]=382;m_boxs[1]=382;m_boxs[3]=592; + m_boxs[0]=414;m_boxs[2]=669;m_boxs[1]=925;m_boxs[3]=1180; + uint8_t* bpic = (uint8_t*)mat_pic->data(); + uint8_t* bmsk = (uint8_t*)mat_msk->data(); + uint8_t* bfg = (uint8_t*)mat_fg->data(); + int* box = m_boxs; + int pcmsize = 1280; + char* pcm = (char*)malloc(1280); + int bnfsize = 1024*20; + char* bnf = (char*)malloc(1024*20); + pthread_t audtrd; + pthread_create(&audtrd, NULL, mfccworker, (void*)dg); + //mfccworker(mfcc); + + printf("====render\n"); + //getchar(); + int bnfinx = 0; + while(1){ + if(!g_sessid){ + printf("+"); + //cv::waitKey(40); + jtimer_mssleep(40); + continue; + } + int readycnt = dhduix_readycnt(dg,g_sessid); + printf("====readycnt %d\n",readycnt); + if(!readycnt){ + jtimer_mssleep(40); + continue; + } + rst = 1;//dhduix_readpcm(dg,g_sessid,pcm,pcmsize,bnf,bnfsize); + printf("===readpcm %ld %d\n",g_sessid,rst); + if(rst>0){ + uint64_t tick = jtimer_msstamp(); + //printf("====read %ld \n",tick); + //rst = dhduix_simprst(dg,g_sessid, bpic,width,height, box, bmsk, bfg, (uint8_t*)bnf,bnfsize); + rst = dhduix_simpinx(dg,g_sessid, bpic,width,height, box, bmsk, bfg, bnfinx); + if(rst>0)bnfinx ++; + printf("===simprst %d\n",rst); + mat_fg->show("aaa"); + cv::waitKey(20); + //jtimer_mssleep(40); + }else if(rst < 0){ + break; + }else{ + //cv::waitKey(40); + jtimer_mssleep(40); + } + } + g_sessid = 0; + pthread_join(audtrd,NULL); + printf("====exit\n"); + // + rst = dhduix_free(dg); + printf("====exitmfcc\n"); + /* + rst = dhduix_free(unet); + delete mat_pic; + delete mat_msk; + delete mat_fg; + */ + free(pcm); + free(bnf); + return 0; +} diff --git a/duix-sdk/src/main/cpp/mk/Android.mk64 b/duix-sdk/src/main/cpp/mk/Android.mk64 new file mode 100644 index 0000000..c7c3065 --- /dev/null +++ b/duix-sdk/src/main/cpp/mk/Android.mk64 @@ -0,0 +1,37 @@ +#/**************************************************************************** +#* Cartoonifier, for Android. +#***************************************************************************** +#* by Shervin Emami, 5th Dec 2012 (shervin.emami@gmail.com) +#* http://www.shervinemami.info/ +#***************************************************************************** +#* Ch1 of the book "Mastering OpenCV with Practical Computer Vision Projects" +#* Copyright Packt Publishing 2012. +#* http://www.packtpub.com/cool-projects-with-opencv/book +#****************************************************************************/ + + +LOCAL_PATH := $(call my-dir) + + +include $(CLEAR_VARS) + + + +LOCAL_SRC_FILES += src/kmatarm.cpp + +LOCAL_ARM_NEON := true +LOCAL_MODULE := facedetect +LOCAL_LDLIBS += -llog -ldl -lm -lmediandk +LOCAL_LDLIBS += -ljnigraphics -fopenmp +LOCAL_CFLAGS += -fpermissive +LOCAL_CPPFLAGS += -fpermissive +#LOCAL_CFLAGS += -ftree-vectorizer-verbose=2 +LOCAL_CPPFLAGS += -std=c++17 +LOCAL_LDLIBS += -lstdc++ + +LOCAL_C_INCLUDES += $(LOCAL_PATH) +LOCAL_C_INCLUDES += include +LOCAL_C_INCLUDES += opencv-mobile-4.6.0-android/sdk/native/jni/include/ +LOCAL_C_INCLUDES += ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn + +include $(BUILD_SHARED_LIBRARY) diff --git a/duix-sdk/src/main/cpp/mk/android.sh b/duix-sdk/src/main/cpp/mk/android.sh new file mode 100644 index 0000000..16da804 --- /dev/null +++ b/duix-sdk/src/main/cpp/mk/android.sh @@ -0,0 +1,17 @@ +ANDROID_NDK=~/tools/android-ndk-r25c +TOOLCHAIN=$ANDROID_NDK/build/cmake/android.toolchain.cmake +BUILD_DIR=android-arm64 +mkdir -p $BUILD_DIR +cd $BUILD_DIR +#-G Ninja # fail +cmake \ + -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN \ + -DANDROID_LD=lld \ + -DANDROID_ABI="arm64-v8a" \ + -DANDROID_PLATFORM=android-24 \ + -DCMAKE_BUILD_TYPE=Release \ + -DPPLCV_USE_AARCH64=ON \ + .. + +# -DHPCC_USE_AARCH64=ON \ + diff --git a/duix-sdk/src/main/cpp/mk/bt b/duix-sdk/src/main/cpp/mk/bt new file mode 100644 index 0000000..f469b21 --- /dev/null +++ b/duix-sdk/src/main/cpp/mk/bt @@ -0,0 +1,58 @@ +g++ -g \ + -Iinclude -Ibase -Irender -Idigit -Iaisdk \ + -I/usr/include/opencv4/ \ + -Ithird/x86/include/ \ + -Ithird/x86/include/ncnn/ \ + -Ithird/x86/include/onnx/ \ + -Ithird/x86/include/turbojpeg/ \ + aisdk/jmat.cpp \ + src/kmatx86.cpp \ + aisdk/wavreader.cpp \ + aisdk/wenet.cpp \ + aisdk/aimodel.cpp \ + aisdk/scrfd.cpp \ + aisdk/pfpld.cpp \ + aisdk/munet.cpp \ + aisdk/malpha.cpp \ + aisdk/wavcache.cpp \ + aisdk/blendgram.cpp \ + aisdk/face_utils.cpp \ + digit/netwav.cpp \ + digit/looper.cpp \ + digit/netcurl.cpp \ + digit/GRender.cpp \ + digit/GDigit.cpp \ + digit/dispatchqueue.cpp \ + base/BaseRenderHelper.cpp \ + base/AudioTrack.cpp \ + render/EglRenderer.cpp \ + render/RgbVideoRenderer.cpp \ + render/SurfaceVideoRenderer.cpp \ + render/RenderHelper.cpp \ + render/AudioRenderer.cpp \ + render/GlesProgram.cpp \ + base/Log.cpp \ + base/FrameSource.cpp \ + base/MediaData.cpp \ + base/MessageSource.cpp \ + base/MessageHelper.cpp \ + base/LoopThread.cpp \ + base/XThread.cpp \ + base/XTick.c \ + base/cJSON.c \ + base/dh_mem.c \ + digit/grtcfg.c \ + base/LoopThreadHelper.cpp \ + linux/linuxtest.cpp \ + lib/libpplcv_static.a \ + lib/libpplcommon_static.a \ + -fpermissive -Wwrite-strings \ + -Llib \ + -L/usr/lib/x86_64-linux-gnu/ \ + -Lthird/ncnn-20221128-android-vulkan-shared/x86_64/lib/ \ + -Lthird/x86/lib \ + -ljpeg -lturbojpeg \ + -lopencv_core -lopencv_dnn -lopencv_imgcodecs -lopencv_imgproc -lopencv_highgui -lopencv_videoio \ + -lonnxruntime -lncnn -lcurl \ + -lEGL -lOpenGL -lGLESv2 -lX11 \ + -fopenmp diff --git a/duix-sdk/src/main/cpp/mk/exbuildso64 b/duix-sdk/src/main/cpp/mk/exbuildso64 new file mode 100644 index 0000000..0728800 --- /dev/null +++ b/duix-sdk/src/main/cpp/mk/exbuildso64 @@ -0,0 +1,4 @@ +ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk64 APP_PLATFORM=android-26 APP_STL=c++_static APP_CPPFLAGS=-fexceptions APP_CFLAGS=-Wno-error APP_ABI=arm64-v8a +#arm64-v8a +#armeabi-v7a + diff --git a/duix-sdk/src/main/cpp/third/arm/arm64-v8a/ffmpeg-lite/build_free_arm64_lite.sh b/duix-sdk/src/main/cpp/third/arm/arm64-v8a/ffmpeg-lite/build_free_arm64_lite.sh new file mode 100644 index 0000000..371b3be --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/arm64-v8a/ffmpeg-lite/build_free_arm64_lite.sh @@ -0,0 +1,119 @@ +# build.sh +# 在Linux下编译FFmpeg成功的脚本 +# 注意Linux和windows的换行符\r\n不太一样,要转换(dos2unix) +#!/bin/sh +make clean +export NDK=~/work/android-ndk-r15c-linux-x86_64/android-ndk-r15c +export PREBUILT=$NDK/toolchains/aarch64-linux-android-4.9/prebuilt +export PLATFORM=$NDK/platforms/android-21/arch-arm64 +export PREFIX=../fflib/free-arm64-lite +build_one(){ +./configure --target-os=android --prefix=$PREFIX \ +--enable-cross-compile \ +--enable-runtime-cpudetect \ +--arch=aarch64 \ +--cross-prefix=$PREBUILT/linux-x86_64/bin/aarch64-linux-android- \ +--cc=$PREBUILT/linux-x86_64/bin/aarch64-linux-android-gcc \ +--nm=$PREBUILT/linux-x86_64/bin/aarch64-linux-android-nm \ +--sysroot=$PLATFORM \ +--disable-gpl --disable-nonfree \ +--enable-shared --enable-static --enable-small \ +--disable-doc --disable-ffprobe --disable-ffplay --disable-debug \ +--enable-jni \ +--enable-mediacodec \ +--disable-avdevice \ +--enable-avcodec \ +--enable-avformat \ +--enable-avutil \ +--enable-swresample \ +--enable-swscale \ +--disable-postproc \ +--enable-avfilter \ +--disable-avresample \ +--disable-decoders \ +--enable-decoder=aac \ +--enable-decoder=aac_latm \ +--enable-decoder=flv \ +--enable-decoder=h264 \ +--enable-decoder=mp3* \ +--enable-decoder=vp6f \ +--enable-decoder=flac \ +--enable-decoder=hevc \ +--enable-decoder=vp8 \ +--enable-decoder=vp9 \ +--enable-decoder=amrnb \ +--enable-decoder=amrwb \ +--enable-decoder=mjpeg \ +--enable-decoder=png \ +--enable-decoder=h264_mediacodec \ +--enable-hwaccel=h264_mediacodec \ +--disable-encoders \ +--enable-encoder=aac \ +--enable-encoder=h264 \ +--enable-encoder=hevc \ +--enable-encoder=png \ +--enable-encoder=mjpeg \ +--disable-demuxers \ +--enable-demuxer=aac \ +--enable-demuxer=concat \ +--enable-demuxer=data \ +--enable-demuxer=flv \ +--enable-demuxer=hls \ +--enable-demuxer=live_flv \ +--enable-demuxer=mov \ +--enable-demuxer=mp3 \ +--enable-demuxer=mpegps \ +--enable-demuxer=mpegts \ +--enable-demuxer=mpegvideo \ +--enable-demuxer=flac \ +--enable-demuxer=hevc \ +--enable-demuxer=webm_dash_manifest \ +--enable-demuxer=rtsp \ +--enable-demuxer=rtp \ +--enable-demuxer=h264 \ +--enable-demuxer=mp4 \ +--enable-demuxer=image2 \ +--disable-muxers \ +--enable-muxer=rtsp \ +--enable-muxer=rtp \ +--enable-muxer=flv \ +--enable-muxer=h264 \ +--enable-muxer=mp4 \ +--enable-muxer=hevc \ +--enable-muxer=image2 \ +--disable-parsers \ +--enable-parser=aac \ +--enable-parser=aac_latm \ +--enable-parser=h264 \ +--enable-parser=flac \ +--enable-parser=hevc \ +--enable-protocols \ +--enable-protocol=async \ +--disable-protocol=bluray \ +--disable-protocol=concat \ +--disable-protocol=crypto \ +--disable-protocol=ffrtmpcrypt \ +--enable-protocol=ffrtmphttp \ +--disable-protocol=gopher \ +--disable-protocol=icecast \ +--disable-protocol=librtmp* \ +--disable-protocol=libssh \ +--disable-protocol=md5 \ +--disable-protocol=mmsh \ +--disable-protocol=mmst \ +--disable-protocol=rtmp* \ +--enable-protocol=rtmp \ +--enable-protocol=rtmpt \ +--disable-protocol=rtp \ +--disable-protocol=sctp \ +--disable-protocol=srtp \ +--disable-protocol=subfile \ +--disable-protocol=unix \ +--disable-indevs \ +--disable-outdevs \ +--disable-stripping \ +--enable-asm +} +build_one +make +make install diff --git a/duix-sdk/src/main/cpp/third/arm/armeabi-v7a/ffmpeg-lite/build_free_arm_lite.sh b/duix-sdk/src/main/cpp/third/arm/armeabi-v7a/ffmpeg-lite/build_free_arm_lite.sh new file mode 100644 index 0000000..cb8d6f8 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/armeabi-v7a/ffmpeg-lite/build_free_arm_lite.sh @@ -0,0 +1,119 @@ +# build.sh +# 在Linux下编译FFmpeg成功的脚本 +# 注意Linux和windows的换行符\r\n不太一样,要转换(dos2unix) +#!/bin/sh +make clean +export NDK=~/work/android-ndk-r15c-linux-x86_64/android-ndk-r15c +export PREBUILT=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt +export PLATFORM=$NDK/platforms/android-21/arch-arm +export PREFIX=../fflib/free-arm-lite +build_one(){ +./configure --target-os=android --prefix=$PREFIX \ +--enable-cross-compile \ +--enable-runtime-cpudetect \ +--arch=arm \ +--cross-prefix=$PREBUILT/linux-x86_64/bin/arm-linux-androideabi- \ +--cc=$PREBUILT/linux-x86_64/bin/arm-linux-androideabi-gcc \ +--nm=$PREBUILT/linux-x86_64/bin/arm-linux-androideabi-nm \ +--sysroot=$PLATFORM \ +--disable-gpl --disable-nonfree \ +--enable-shared --enable-static --enable-small \ +--disable-doc --disable-ffprobe --disable-ffplay --disable-debug \ +--enable-jni \ +--enable-mediacodec \ +--disable-avdevice \ +--enable-avcodec \ +--enable-avformat \ +--enable-avutil \ +--enable-swresample \ +--enable-swscale \ +--disable-postproc \ +--enable-avfilter \ +--disable-avresample \ +--disable-decoders \ +--enable-decoder=aac \ +--enable-decoder=aac_latm \ +--enable-decoder=flv \ +--enable-decoder=h264 \ +--enable-decoder=mp3* \ +--enable-decoder=vp6f \ +--enable-decoder=flac \ +--enable-decoder=hevc \ +--enable-decoder=vp8 \ +--enable-decoder=vp9 \ +--enable-decoder=amrnb \ +--enable-decoder=amrwb \ +--enable-decoder=mjpeg \ +--enable-decoder=png \ +--enable-decoder=h264_mediacodec \ +--enable-hwaccel=h264_mediacodec \ +--disable-encoders \ +--enable-encoder=aac \ +--enable-encoder=h264 \ +--enable-encoder=hevc \ +--enable-encoder=png \ +--enable-encoder=mjpeg \ +--disable-demuxers \ +--enable-demuxer=aac \ +--enable-demuxer=concat \ +--enable-demuxer=data \ +--enable-demuxer=flv \ +--enable-demuxer=hls \ +--enable-demuxer=live_flv \ +--enable-demuxer=mov \ +--enable-demuxer=mp3 \ +--enable-demuxer=mpegps \ +--enable-demuxer=mpegts \ +--enable-demuxer=mpegvideo \ +--enable-demuxer=flac \ +--enable-demuxer=hevc \ +--enable-demuxer=webm_dash_manifest \ +--enable-demuxer=rtsp \ +--enable-demuxer=rtp \ +--enable-demuxer=h264 \ +--enable-demuxer=mp4 \ +--enable-demuxer=image2 \ +--disable-muxers \ +--enable-muxer=rtsp \ +--enable-muxer=rtp \ +--enable-muxer=flv \ +--enable-muxer=h264 \ +--enable-muxer=mp4 \ +--enable-muxer=hevc \ +--enable-muxer=image2 \ +--disable-parsers \ +--enable-parser=aac \ +--enable-parser=aac_latm \ +--enable-parser=h264 \ +--enable-parser=flac \ +--enable-parser=hevc \ +--enable-protocols \ +--enable-protocol=async \ +--disable-protocol=bluray \ +--disable-protocol=concat \ +--disable-protocol=crypto \ +--disable-protocol=ffrtmpcrypt \ +--enable-protocol=ffrtmphttp \ +--disable-protocol=gopher \ +--disable-protocol=icecast \ +--disable-protocol=librtmp* \ +--disable-protocol=libssh \ +--disable-protocol=md5 \ +--disable-protocol=mmsh \ +--disable-protocol=mmst \ +--disable-protocol=rtmp* \ +--enable-protocol=rtmp \ +--enable-protocol=rtmpt \ +--disable-protocol=rtp \ +--disable-protocol=sctp \ +--disable-protocol=srtp \ +--disable-protocol=subfile \ +--disable-protocol=unix \ +--disable-indevs \ +--disable-outdevs \ +--disable-stripping \ +--enable-asm +} +build_one +make +make install diff --git a/duix-sdk/src/main/cpp/third/arm/armeabi-v7a/libcurl.la b/duix-sdk/src/main/cpp/third/arm/armeabi-v7a/libcurl.la new file mode 100644 index 0000000..a4accf9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/armeabi-v7a/libcurl.la @@ -0,0 +1,41 @@ +# libcurl.la - a libtool library file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='' + +# Names of this library. +library_names='' + +# The name of the static archive. +old_library='libcurl.a' + +# Linker flags that cannot go in dependency_libs. +inherited_linker_flags='' + +# Libraries that this one depends upon. +dependency_libs=' -L/Users/rying/repo/openssl-curl-android/openssl/build/armeabi-v7a/lib -lssl -lcrypto -lz' + +# Names of additional weak libraries provided by this library +weak_library_names='' + +# Version information for libcurl. +current=0 +age=0 +revision=0 + +# Is this an already installed library? +installed=yes + +# Should we warn about portability when linking against -modules? +shouldnotlink=no + +# Files to dlopen/dlpreopen +dlopen='' +dlpreopen='' + +# Directory that this library needs to be installed in: +libdir='/Users/rying/repo/openssl-curl-android/curl/build/armeabi-v7a/lib' diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/avcodec.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/avcodec.h new file mode 100644 index 0000000..57334df --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/avcodec.h @@ -0,0 +1,6342 @@ +/* + * copyright (c) 2001 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AVCODEC_H +#define AVCODEC_AVCODEC_H + +/** + * @file + * @ingroup libavc + * Libavcodec external API header + */ + +#include +#include "libavutil/samplefmt.h" +#include "libavutil/attributes.h" +#include "libavutil/avutil.h" +#include "libavutil/buffer.h" +#include "libavutil/cpu.h" +#include "libavutil/channel_layout.h" +#include "libavutil/dict.h" +#include "libavutil/frame.h" +#include "libavutil/log.h" +#include "libavutil/pixfmt.h" +#include "libavutil/rational.h" + +#include "version.h" + +/** + * @defgroup libavc libavcodec + * Encoding/Decoding Library + * + * @{ + * + * @defgroup lavc_decoding Decoding + * @{ + * @} + * + * @defgroup lavc_encoding Encoding + * @{ + * @} + * + * @defgroup lavc_codec Codecs + * @{ + * @defgroup lavc_codec_native Native Codecs + * @{ + * @} + * @defgroup lavc_codec_wrappers External library wrappers + * @{ + * @} + * @defgroup lavc_codec_hwaccel Hardware Accelerators bridge + * @{ + * @} + * @} + * @defgroup lavc_internal Internal + * @{ + * @} + * @} + */ + +/** + * @ingroup libavc + * @defgroup lavc_encdec send/receive encoding and decoding API overview + * @{ + * + * The avcodec_send_packet()/avcodec_receive_frame()/avcodec_send_frame()/ + * avcodec_receive_packet() functions provide an encode/decode API, which + * decouples input and output. + * + * The API is very similar for encoding/decoding and audio/video, and works as + * follows: + * - Set up and open the AVCodecContext as usual. + * - Send valid input: + * - For decoding, call avcodec_send_packet() to give the decoder raw + * compressed data in an AVPacket. + * - For encoding, call avcodec_send_frame() to give the encoder an AVFrame + * containing uncompressed audio or video. + * In both cases, it is recommended that AVPackets and AVFrames are + * refcounted, or libavcodec might have to copy the input data. (libavformat + * always returns refcounted AVPackets, and av_frame_get_buffer() allocates + * refcounted AVFrames.) + * - Receive output in a loop. Periodically call one of the avcodec_receive_*() + * functions and process their output: + * - For decoding, call avcodec_receive_frame(). On success, it will return + * an AVFrame containing uncompressed audio or video data. + * - For encoding, call avcodec_receive_packet(). On success, it will return + * an AVPacket with a compressed frame. + * Repeat this call until it returns AVERROR(EAGAIN) or an error. The + * AVERROR(EAGAIN) return value means that new input data is required to + * return new output. In this case, continue with sending input. For each + * input frame/packet, the codec will typically return 1 output frame/packet, + * but it can also be 0 or more than 1. + * + * At the beginning of decoding or encoding, the codec might accept multiple + * input frames/packets without returning a frame, until its internal buffers + * are filled. This situation is handled transparently if you follow the steps + * outlined above. + * + * In theory, sending input can result in EAGAIN - this should happen only if + * not all output was received. You can use this to structure alternative decode + * or encode loops other than the one suggested above. For example, you could + * try sending new input on each iteration, and try to receive output if that + * returns EAGAIN. + * + * End of stream situations. These require "flushing" (aka draining) the codec, + * as the codec might buffer multiple frames or packets internally for + * performance or out of necessity (consider B-frames). + * This is handled as follows: + * - Instead of valid input, send NULL to the avcodec_send_packet() (decoding) + * or avcodec_send_frame() (encoding) functions. This will enter draining + * mode. + * - Call avcodec_receive_frame() (decoding) or avcodec_receive_packet() + * (encoding) in a loop until AVERROR_EOF is returned. The functions will + * not return AVERROR(EAGAIN), unless you forgot to enter draining mode. + * - Before decoding can be resumed again, the codec has to be reset with + * avcodec_flush_buffers(). + * + * Using the API as outlined above is highly recommended. But it is also + * possible to call functions outside of this rigid schema. For example, you can + * call avcodec_send_packet() repeatedly without calling + * avcodec_receive_frame(). In this case, avcodec_send_packet() will succeed + * until the codec's internal buffer has been filled up (which is typically of + * size 1 per output frame, after initial input), and then reject input with + * AVERROR(EAGAIN). Once it starts rejecting input, you have no choice but to + * read at least some output. + * + * Not all codecs will follow a rigid and predictable dataflow; the only + * guarantee is that an AVERROR(EAGAIN) return value on a send/receive call on + * one end implies that a receive/send call on the other end will succeed, or + * at least will not fail with AVERROR(EAGAIN). In general, no codec will + * permit unlimited buffering of input or output. + * + * This API replaces the following legacy functions: + * - avcodec_decode_video2() and avcodec_decode_audio4(): + * Use avcodec_send_packet() to feed input to the decoder, then use + * avcodec_receive_frame() to receive decoded frames after each packet. + * Unlike with the old video decoding API, multiple frames might result from + * a packet. For audio, splitting the input packet into frames by partially + * decoding packets becomes transparent to the API user. You never need to + * feed an AVPacket to the API twice (unless it is rejected with AVERROR(EAGAIN) - then + * no data was read from the packet). + * Additionally, sending a flush/draining packet is required only once. + * - avcodec_encode_video2()/avcodec_encode_audio2(): + * Use avcodec_send_frame() to feed input to the encoder, then use + * avcodec_receive_packet() to receive encoded packets. + * Providing user-allocated buffers for avcodec_receive_packet() is not + * possible. + * - The new API does not handle subtitles yet. + * + * Mixing new and old function calls on the same AVCodecContext is not allowed, + * and will result in undefined behavior. + * + * Some codecs might require using the new API; using the old API will return + * an error when calling it. All codecs support the new API. + * + * A codec is not allowed to return AVERROR(EAGAIN) for both sending and receiving. This + * would be an invalid state, which could put the codec user into an endless + * loop. The API has no concept of time either: it cannot happen that trying to + * do avcodec_send_packet() results in AVERROR(EAGAIN), but a repeated call 1 second + * later accepts the packet (with no other receive/flush API calls involved). + * The API is a strict state machine, and the passage of time is not supposed + * to influence it. Some timing-dependent behavior might still be deemed + * acceptable in certain cases. But it must never result in both send/receive + * returning EAGAIN at the same time at any point. It must also absolutely be + * avoided that the current state is "unstable" and can "flip-flop" between + * the send/receive APIs allowing progress. For example, it's not allowed that + * the codec randomly decides that it actually wants to consume a packet now + * instead of returning a frame, after it just returned AVERROR(EAGAIN) on an + * avcodec_send_packet() call. + * @} + */ + +/** + * @defgroup lavc_core Core functions/structures. + * @ingroup libavc + * + * Basic definitions, functions for querying libavcodec capabilities, + * allocating core structures, etc. + * @{ + */ + + +/** + * Identify the syntax and semantics of the bitstream. + * The principle is roughly: + * Two decoders with the same ID can decode the same streams. + * Two encoders with the same ID can encode compatible streams. + * There may be slight deviations from the principle due to implementation + * details. + * + * If you add a codec ID to this list, add it so that + * 1. no value of an existing codec ID changes (that would break ABI), + * 2. it is as close as possible to similar codecs + * + * After adding new codec IDs, do not forget to add an entry to the codec + * descriptor list and bump libavcodec minor version. + */ +enum AVCodecID { + AV_CODEC_ID_NONE, + + /* video codecs */ + AV_CODEC_ID_MPEG1VIDEO, + AV_CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding +#if FF_API_XVMC + AV_CODEC_ID_MPEG2VIDEO_XVMC, +#endif /* FF_API_XVMC */ + AV_CODEC_ID_H261, + AV_CODEC_ID_H263, + AV_CODEC_ID_RV10, + AV_CODEC_ID_RV20, + AV_CODEC_ID_MJPEG, + AV_CODEC_ID_MJPEGB, + AV_CODEC_ID_LJPEG, + AV_CODEC_ID_SP5X, + AV_CODEC_ID_JPEGLS, + AV_CODEC_ID_MPEG4, + AV_CODEC_ID_RAWVIDEO, + AV_CODEC_ID_MSMPEG4V1, + AV_CODEC_ID_MSMPEG4V2, + AV_CODEC_ID_MSMPEG4V3, + AV_CODEC_ID_WMV1, + AV_CODEC_ID_WMV2, + AV_CODEC_ID_H263P, + AV_CODEC_ID_H263I, + AV_CODEC_ID_FLV1, + AV_CODEC_ID_SVQ1, + AV_CODEC_ID_SVQ3, + AV_CODEC_ID_DVVIDEO, + AV_CODEC_ID_HUFFYUV, + AV_CODEC_ID_CYUV, + AV_CODEC_ID_H264, + AV_CODEC_ID_INDEO3, + AV_CODEC_ID_VP3, + AV_CODEC_ID_THEORA, + AV_CODEC_ID_ASV1, + AV_CODEC_ID_ASV2, + AV_CODEC_ID_FFV1, + AV_CODEC_ID_4XM, + AV_CODEC_ID_VCR1, + AV_CODEC_ID_CLJR, + AV_CODEC_ID_MDEC, + AV_CODEC_ID_ROQ, + AV_CODEC_ID_INTERPLAY_VIDEO, + AV_CODEC_ID_XAN_WC3, + AV_CODEC_ID_XAN_WC4, + AV_CODEC_ID_RPZA, + AV_CODEC_ID_CINEPAK, + AV_CODEC_ID_WS_VQA, + AV_CODEC_ID_MSRLE, + AV_CODEC_ID_MSVIDEO1, + AV_CODEC_ID_IDCIN, + AV_CODEC_ID_8BPS, + AV_CODEC_ID_SMC, + AV_CODEC_ID_FLIC, + AV_CODEC_ID_TRUEMOTION1, + AV_CODEC_ID_VMDVIDEO, + AV_CODEC_ID_MSZH, + AV_CODEC_ID_ZLIB, + AV_CODEC_ID_QTRLE, + AV_CODEC_ID_TSCC, + AV_CODEC_ID_ULTI, + AV_CODEC_ID_QDRAW, + AV_CODEC_ID_VIXL, + AV_CODEC_ID_QPEG, + AV_CODEC_ID_PNG, + AV_CODEC_ID_PPM, + AV_CODEC_ID_PBM, + AV_CODEC_ID_PGM, + AV_CODEC_ID_PGMYUV, + AV_CODEC_ID_PAM, + AV_CODEC_ID_FFVHUFF, + AV_CODEC_ID_RV30, + AV_CODEC_ID_RV40, + AV_CODEC_ID_VC1, + AV_CODEC_ID_WMV3, + AV_CODEC_ID_LOCO, + AV_CODEC_ID_WNV1, + AV_CODEC_ID_AASC, + AV_CODEC_ID_INDEO2, + AV_CODEC_ID_FRAPS, + AV_CODEC_ID_TRUEMOTION2, + AV_CODEC_ID_BMP, + AV_CODEC_ID_CSCD, + AV_CODEC_ID_MMVIDEO, + AV_CODEC_ID_ZMBV, + AV_CODEC_ID_AVS, + AV_CODEC_ID_SMACKVIDEO, + AV_CODEC_ID_NUV, + AV_CODEC_ID_KMVC, + AV_CODEC_ID_FLASHSV, + AV_CODEC_ID_CAVS, + AV_CODEC_ID_JPEG2000, + AV_CODEC_ID_VMNC, + AV_CODEC_ID_VP5, + AV_CODEC_ID_VP6, + AV_CODEC_ID_VP6F, + AV_CODEC_ID_TARGA, + AV_CODEC_ID_DSICINVIDEO, + AV_CODEC_ID_TIERTEXSEQVIDEO, + AV_CODEC_ID_TIFF, + AV_CODEC_ID_GIF, + AV_CODEC_ID_DXA, + AV_CODEC_ID_DNXHD, + AV_CODEC_ID_THP, + AV_CODEC_ID_SGI, + AV_CODEC_ID_C93, + AV_CODEC_ID_BETHSOFTVID, + AV_CODEC_ID_PTX, + AV_CODEC_ID_TXD, + AV_CODEC_ID_VP6A, + AV_CODEC_ID_AMV, + AV_CODEC_ID_VB, + AV_CODEC_ID_PCX, + AV_CODEC_ID_SUNRAST, + AV_CODEC_ID_INDEO4, + AV_CODEC_ID_INDEO5, + AV_CODEC_ID_MIMIC, + AV_CODEC_ID_RL2, + AV_CODEC_ID_ESCAPE124, + AV_CODEC_ID_DIRAC, + AV_CODEC_ID_BFI, + AV_CODEC_ID_CMV, + AV_CODEC_ID_MOTIONPIXELS, + AV_CODEC_ID_TGV, + AV_CODEC_ID_TGQ, + AV_CODEC_ID_TQI, + AV_CODEC_ID_AURA, + AV_CODEC_ID_AURA2, + AV_CODEC_ID_V210X, + AV_CODEC_ID_TMV, + AV_CODEC_ID_V210, + AV_CODEC_ID_DPX, + AV_CODEC_ID_MAD, + AV_CODEC_ID_FRWU, + AV_CODEC_ID_FLASHSV2, + AV_CODEC_ID_CDGRAPHICS, + AV_CODEC_ID_R210, + AV_CODEC_ID_ANM, + AV_CODEC_ID_BINKVIDEO, + AV_CODEC_ID_IFF_ILBM, +#define AV_CODEC_ID_IFF_BYTERUN1 AV_CODEC_ID_IFF_ILBM + AV_CODEC_ID_KGV1, + AV_CODEC_ID_YOP, + AV_CODEC_ID_VP8, + AV_CODEC_ID_PICTOR, + AV_CODEC_ID_ANSI, + AV_CODEC_ID_A64_MULTI, + AV_CODEC_ID_A64_MULTI5, + AV_CODEC_ID_R10K, + AV_CODEC_ID_MXPEG, + AV_CODEC_ID_LAGARITH, + AV_CODEC_ID_PRORES, + AV_CODEC_ID_JV, + AV_CODEC_ID_DFA, + AV_CODEC_ID_WMV3IMAGE, + AV_CODEC_ID_VC1IMAGE, + AV_CODEC_ID_UTVIDEO, + AV_CODEC_ID_BMV_VIDEO, + AV_CODEC_ID_VBLE, + AV_CODEC_ID_DXTORY, + AV_CODEC_ID_V410, + AV_CODEC_ID_XWD, + AV_CODEC_ID_CDXL, + AV_CODEC_ID_XBM, + AV_CODEC_ID_ZEROCODEC, + AV_CODEC_ID_MSS1, + AV_CODEC_ID_MSA1, + AV_CODEC_ID_TSCC2, + AV_CODEC_ID_MTS2, + AV_CODEC_ID_CLLC, + AV_CODEC_ID_MSS2, + AV_CODEC_ID_VP9, + AV_CODEC_ID_AIC, + AV_CODEC_ID_ESCAPE130, + AV_CODEC_ID_G2M, + AV_CODEC_ID_WEBP, + AV_CODEC_ID_HNM4_VIDEO, + AV_CODEC_ID_HEVC, +#define AV_CODEC_ID_H265 AV_CODEC_ID_HEVC + AV_CODEC_ID_FIC, + AV_CODEC_ID_ALIAS_PIX, + AV_CODEC_ID_BRENDER_PIX, + AV_CODEC_ID_PAF_VIDEO, + AV_CODEC_ID_EXR, + AV_CODEC_ID_VP7, + AV_CODEC_ID_SANM, + AV_CODEC_ID_SGIRLE, + AV_CODEC_ID_MVC1, + AV_CODEC_ID_MVC2, + AV_CODEC_ID_HQX, + AV_CODEC_ID_TDSC, + AV_CODEC_ID_HQ_HQA, + AV_CODEC_ID_HAP, + AV_CODEC_ID_DDS, + AV_CODEC_ID_DXV, + AV_CODEC_ID_SCREENPRESSO, + AV_CODEC_ID_RSCC, + + AV_CODEC_ID_Y41P = 0x8000, + AV_CODEC_ID_AVRP, + AV_CODEC_ID_012V, + AV_CODEC_ID_AVUI, + AV_CODEC_ID_AYUV, + AV_CODEC_ID_TARGA_Y216, + AV_CODEC_ID_V308, + AV_CODEC_ID_V408, + AV_CODEC_ID_YUV4, + AV_CODEC_ID_AVRN, + AV_CODEC_ID_CPIA, + AV_CODEC_ID_XFACE, + AV_CODEC_ID_SNOW, + AV_CODEC_ID_SMVJPEG, + AV_CODEC_ID_APNG, + AV_CODEC_ID_DAALA, + AV_CODEC_ID_CFHD, + AV_CODEC_ID_TRUEMOTION2RT, + AV_CODEC_ID_M101, + AV_CODEC_ID_MAGICYUV, + AV_CODEC_ID_SHEERVIDEO, + AV_CODEC_ID_YLC, + AV_CODEC_ID_PSD, + AV_CODEC_ID_PIXLET, + AV_CODEC_ID_SPEEDHQ, + AV_CODEC_ID_FMVC, + AV_CODEC_ID_SCPR, + AV_CODEC_ID_CLEARVIDEO, + AV_CODEC_ID_XPM, + AV_CODEC_ID_AV1, + + /* various PCM "codecs" */ + AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs + AV_CODEC_ID_PCM_S16LE = 0x10000, + AV_CODEC_ID_PCM_S16BE, + AV_CODEC_ID_PCM_U16LE, + AV_CODEC_ID_PCM_U16BE, + AV_CODEC_ID_PCM_S8, + AV_CODEC_ID_PCM_U8, + AV_CODEC_ID_PCM_MULAW, + AV_CODEC_ID_PCM_ALAW, + AV_CODEC_ID_PCM_S32LE, + AV_CODEC_ID_PCM_S32BE, + AV_CODEC_ID_PCM_U32LE, + AV_CODEC_ID_PCM_U32BE, + AV_CODEC_ID_PCM_S24LE, + AV_CODEC_ID_PCM_S24BE, + AV_CODEC_ID_PCM_U24LE, + AV_CODEC_ID_PCM_U24BE, + AV_CODEC_ID_PCM_S24DAUD, + AV_CODEC_ID_PCM_ZORK, + AV_CODEC_ID_PCM_S16LE_PLANAR, + AV_CODEC_ID_PCM_DVD, + AV_CODEC_ID_PCM_F32BE, + AV_CODEC_ID_PCM_F32LE, + AV_CODEC_ID_PCM_F64BE, + AV_CODEC_ID_PCM_F64LE, + AV_CODEC_ID_PCM_BLURAY, + AV_CODEC_ID_PCM_LXF, + AV_CODEC_ID_S302M, + AV_CODEC_ID_PCM_S8_PLANAR, + AV_CODEC_ID_PCM_S24LE_PLANAR, + AV_CODEC_ID_PCM_S32LE_PLANAR, + AV_CODEC_ID_PCM_S16BE_PLANAR, + + AV_CODEC_ID_PCM_S64LE = 0x10800, + AV_CODEC_ID_PCM_S64BE, + AV_CODEC_ID_PCM_F16LE, + AV_CODEC_ID_PCM_F24LE, + + /* various ADPCM codecs */ + AV_CODEC_ID_ADPCM_IMA_QT = 0x11000, + AV_CODEC_ID_ADPCM_IMA_WAV, + AV_CODEC_ID_ADPCM_IMA_DK3, + AV_CODEC_ID_ADPCM_IMA_DK4, + AV_CODEC_ID_ADPCM_IMA_WS, + AV_CODEC_ID_ADPCM_IMA_SMJPEG, + AV_CODEC_ID_ADPCM_MS, + AV_CODEC_ID_ADPCM_4XM, + AV_CODEC_ID_ADPCM_XA, + AV_CODEC_ID_ADPCM_ADX, + AV_CODEC_ID_ADPCM_EA, + AV_CODEC_ID_ADPCM_G726, + AV_CODEC_ID_ADPCM_CT, + AV_CODEC_ID_ADPCM_SWF, + AV_CODEC_ID_ADPCM_YAMAHA, + AV_CODEC_ID_ADPCM_SBPRO_4, + AV_CODEC_ID_ADPCM_SBPRO_3, + AV_CODEC_ID_ADPCM_SBPRO_2, + AV_CODEC_ID_ADPCM_THP, + AV_CODEC_ID_ADPCM_IMA_AMV, + AV_CODEC_ID_ADPCM_EA_R1, + AV_CODEC_ID_ADPCM_EA_R3, + AV_CODEC_ID_ADPCM_EA_R2, + AV_CODEC_ID_ADPCM_IMA_EA_SEAD, + AV_CODEC_ID_ADPCM_IMA_EA_EACS, + AV_CODEC_ID_ADPCM_EA_XAS, + AV_CODEC_ID_ADPCM_EA_MAXIS_XA, + AV_CODEC_ID_ADPCM_IMA_ISS, + AV_CODEC_ID_ADPCM_G722, + AV_CODEC_ID_ADPCM_IMA_APC, + AV_CODEC_ID_ADPCM_VIMA, +#if FF_API_VIMA_DECODER + AV_CODEC_ID_VIMA = AV_CODEC_ID_ADPCM_VIMA, +#endif + + AV_CODEC_ID_ADPCM_AFC = 0x11800, + AV_CODEC_ID_ADPCM_IMA_OKI, + AV_CODEC_ID_ADPCM_DTK, + AV_CODEC_ID_ADPCM_IMA_RAD, + AV_CODEC_ID_ADPCM_G726LE, + AV_CODEC_ID_ADPCM_THP_LE, + AV_CODEC_ID_ADPCM_PSX, + AV_CODEC_ID_ADPCM_AICA, + AV_CODEC_ID_ADPCM_IMA_DAT4, + AV_CODEC_ID_ADPCM_MTAF, + + /* AMR */ + AV_CODEC_ID_AMR_NB = 0x12000, + AV_CODEC_ID_AMR_WB, + + /* RealAudio codecs*/ + AV_CODEC_ID_RA_144 = 0x13000, + AV_CODEC_ID_RA_288, + + /* various DPCM codecs */ + AV_CODEC_ID_ROQ_DPCM = 0x14000, + AV_CODEC_ID_INTERPLAY_DPCM, + AV_CODEC_ID_XAN_DPCM, + AV_CODEC_ID_SOL_DPCM, + + AV_CODEC_ID_SDX2_DPCM = 0x14800, + + /* audio codecs */ + AV_CODEC_ID_MP2 = 0x15000, + AV_CODEC_ID_MP3, ///< preferred ID for decoding MPEG audio layer 1, 2 or 3 + AV_CODEC_ID_AAC, + AV_CODEC_ID_AC3, + AV_CODEC_ID_DTS, + AV_CODEC_ID_VORBIS, + AV_CODEC_ID_DVAUDIO, + AV_CODEC_ID_WMAV1, + AV_CODEC_ID_WMAV2, + AV_CODEC_ID_MACE3, + AV_CODEC_ID_MACE6, + AV_CODEC_ID_VMDAUDIO, + AV_CODEC_ID_FLAC, + AV_CODEC_ID_MP3ADU, + AV_CODEC_ID_MP3ON4, + AV_CODEC_ID_SHORTEN, + AV_CODEC_ID_ALAC, + AV_CODEC_ID_WESTWOOD_SND1, + AV_CODEC_ID_GSM, ///< as in Berlin toast format + AV_CODEC_ID_QDM2, + AV_CODEC_ID_COOK, + AV_CODEC_ID_TRUESPEECH, + AV_CODEC_ID_TTA, + AV_CODEC_ID_SMACKAUDIO, + AV_CODEC_ID_QCELP, + AV_CODEC_ID_WAVPACK, + AV_CODEC_ID_DSICINAUDIO, + AV_CODEC_ID_IMC, + AV_CODEC_ID_MUSEPACK7, + AV_CODEC_ID_MLP, + AV_CODEC_ID_GSM_MS, /* as found in WAV */ + AV_CODEC_ID_ATRAC3, +#if FF_API_VOXWARE + AV_CODEC_ID_VOXWARE, +#endif + AV_CODEC_ID_APE, + AV_CODEC_ID_NELLYMOSER, + AV_CODEC_ID_MUSEPACK8, + AV_CODEC_ID_SPEEX, + AV_CODEC_ID_WMAVOICE, + AV_CODEC_ID_WMAPRO, + AV_CODEC_ID_WMALOSSLESS, + AV_CODEC_ID_ATRAC3P, + AV_CODEC_ID_EAC3, + AV_CODEC_ID_SIPR, + AV_CODEC_ID_MP1, + AV_CODEC_ID_TWINVQ, + AV_CODEC_ID_TRUEHD, + AV_CODEC_ID_MP4ALS, + AV_CODEC_ID_ATRAC1, + AV_CODEC_ID_BINKAUDIO_RDFT, + AV_CODEC_ID_BINKAUDIO_DCT, + AV_CODEC_ID_AAC_LATM, + AV_CODEC_ID_QDMC, + AV_CODEC_ID_CELT, + AV_CODEC_ID_G723_1, + AV_CODEC_ID_G729, + AV_CODEC_ID_8SVX_EXP, + AV_CODEC_ID_8SVX_FIB, + AV_CODEC_ID_BMV_AUDIO, + AV_CODEC_ID_RALF, + AV_CODEC_ID_IAC, + AV_CODEC_ID_ILBC, + AV_CODEC_ID_OPUS, + AV_CODEC_ID_COMFORT_NOISE, + AV_CODEC_ID_TAK, + AV_CODEC_ID_METASOUND, + AV_CODEC_ID_PAF_AUDIO, + AV_CODEC_ID_ON2AVC, + AV_CODEC_ID_DSS_SP, + + AV_CODEC_ID_FFWAVESYNTH = 0x15800, + AV_CODEC_ID_SONIC, + AV_CODEC_ID_SONIC_LS, + AV_CODEC_ID_EVRC, + AV_CODEC_ID_SMV, + AV_CODEC_ID_DSD_LSBF, + AV_CODEC_ID_DSD_MSBF, + AV_CODEC_ID_DSD_LSBF_PLANAR, + AV_CODEC_ID_DSD_MSBF_PLANAR, + AV_CODEC_ID_4GV, + AV_CODEC_ID_INTERPLAY_ACM, + AV_CODEC_ID_XMA1, + AV_CODEC_ID_XMA2, + AV_CODEC_ID_DST, + AV_CODEC_ID_ATRAC3AL, + AV_CODEC_ID_ATRAC3PAL, + + /* subtitle codecs */ + AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. + AV_CODEC_ID_DVD_SUBTITLE = 0x17000, + AV_CODEC_ID_DVB_SUBTITLE, + AV_CODEC_ID_TEXT, ///< raw UTF-8 text + AV_CODEC_ID_XSUB, + AV_CODEC_ID_SSA, + AV_CODEC_ID_MOV_TEXT, + AV_CODEC_ID_HDMV_PGS_SUBTITLE, + AV_CODEC_ID_DVB_TELETEXT, + AV_CODEC_ID_SRT, + + AV_CODEC_ID_MICRODVD = 0x17800, + AV_CODEC_ID_EIA_608, + AV_CODEC_ID_JACOSUB, + AV_CODEC_ID_SAMI, + AV_CODEC_ID_REALTEXT, + AV_CODEC_ID_STL, + AV_CODEC_ID_SUBVIEWER1, + AV_CODEC_ID_SUBVIEWER, + AV_CODEC_ID_SUBRIP, + AV_CODEC_ID_WEBVTT, + AV_CODEC_ID_MPL2, + AV_CODEC_ID_VPLAYER, + AV_CODEC_ID_PJS, + AV_CODEC_ID_ASS, + AV_CODEC_ID_HDMV_TEXT_SUBTITLE, + + /* other specific kind of codecs (generally used for attachments) */ + AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs. + AV_CODEC_ID_TTF = 0x18000, + + AV_CODEC_ID_SCTE_35, ///< Contain timestamp estimated through PCR of program stream. + AV_CODEC_ID_BINTEXT = 0x18800, + AV_CODEC_ID_XBIN, + AV_CODEC_ID_IDF, + AV_CODEC_ID_OTF, + AV_CODEC_ID_SMPTE_KLV, + AV_CODEC_ID_DVD_NAV, + AV_CODEC_ID_TIMED_ID3, + AV_CODEC_ID_BIN_DATA, + + + AV_CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like AV_CODEC_ID_NONE) but lavf should attempt to identify it + + AV_CODEC_ID_MPEG2TS = 0x20000, /**< _FAKE_ codec to indicate a raw MPEG-2 TS + * stream (only used by libavformat) */ + AV_CODEC_ID_MPEG4SYSTEMS = 0x20001, /**< _FAKE_ codec to indicate a MPEG-4 Systems + * stream (only used by libavformat) */ + AV_CODEC_ID_FFMETADATA = 0x21000, ///< Dummy codec for streams containing only metadata information. + AV_CODEC_ID_WRAPPED_AVFRAME = 0x21001, ///< Passthrough codec, AVFrames wrapped in AVPacket +}; + +/** + * This struct describes the properties of a single codec described by an + * AVCodecID. + * @see avcodec_descriptor_get() + */ +typedef struct AVCodecDescriptor { + enum AVCodecID id; + enum AVMediaType type; + /** + * Name of the codec described by this descriptor. It is non-empty and + * unique for each codec descriptor. It should contain alphanumeric + * characters and '_' only. + */ + const char *name; + /** + * A more descriptive name for this codec. May be NULL. + */ + const char *long_name; + /** + * Codec properties, a combination of AV_CODEC_PROP_* flags. + */ + int props; + /** + * MIME type(s) associated with the codec. + * May be NULL; if not, a NULL-terminated array of MIME types. + * The first item is always non-NULL and is the preferred MIME type. + */ + const char *const *mime_types; + /** + * If non-NULL, an array of profiles recognized for this codec. + * Terminated with FF_PROFILE_UNKNOWN. + */ + const struct AVProfile *profiles; +} AVCodecDescriptor; + +/** + * Codec uses only intra compression. + * Video codecs only. + */ +#define AV_CODEC_PROP_INTRA_ONLY (1 << 0) +/** + * Codec supports lossy compression. Audio and video codecs only. + * @note a codec may support both lossy and lossless + * compression modes + */ +#define AV_CODEC_PROP_LOSSY (1 << 1) +/** + * Codec supports lossless compression. Audio and video codecs only. + */ +#define AV_CODEC_PROP_LOSSLESS (1 << 2) +/** + * Codec supports frame reordering. That is, the coded order (the order in which + * the encoded packets are output by the encoders / stored / input to the + * decoders) may be different from the presentation order of the corresponding + * frames. + * + * For codecs that do not have this property set, PTS and DTS should always be + * equal. + */ +#define AV_CODEC_PROP_REORDER (1 << 3) +/** + * Subtitle codec is bitmap based + * Decoded AVSubtitle data can be read from the AVSubtitleRect->pict field. + */ +#define AV_CODEC_PROP_BITMAP_SUB (1 << 16) +/** + * Subtitle codec is text based. + * Decoded AVSubtitle data can be read from the AVSubtitleRect->ass field. + */ +#define AV_CODEC_PROP_TEXT_SUB (1 << 17) + +/** + * @ingroup lavc_decoding + * Required number of additionally allocated bytes at the end of the input bitstream for decoding. + * This is mainly needed because some optimized bitstream readers read + * 32 or 64 bit at once and could read over the end.
+ * Note: If the first 23 bits of the additional bytes are not 0, then damaged + * MPEG bitstreams could cause overread and segfault. + */ +#define AV_INPUT_BUFFER_PADDING_SIZE 32 + +/** + * @ingroup lavc_encoding + * minimum encoding buffer size + * Used to avoid some checks during header writing. + */ +#define AV_INPUT_BUFFER_MIN_SIZE 16384 + +#if FF_API_WITHOUT_PREFIX +/** + * @deprecated use AV_INPUT_BUFFER_PADDING_SIZE instead + */ +#define FF_INPUT_BUFFER_PADDING_SIZE 32 + +/** + * @deprecated use AV_INPUT_BUFFER_MIN_SIZE instead + */ +#define FF_MIN_BUFFER_SIZE 16384 +#endif /* FF_API_WITHOUT_PREFIX */ + +/** + * @ingroup lavc_encoding + * motion estimation type. + * @deprecated use codec private option instead + */ +#if FF_API_MOTION_EST +enum Motion_Est_ID { + ME_ZERO = 1, ///< no search, that is use 0,0 vector whenever one is needed + ME_FULL, + ME_LOG, + ME_PHODS, + ME_EPZS, ///< enhanced predictive zonal search + ME_X1, ///< reserved for experiments + ME_HEX, ///< hexagon based search + ME_UMH, ///< uneven multi-hexagon search + ME_TESA, ///< transformed exhaustive search algorithm + ME_ITER=50, ///< iterative search +}; +#endif + +/** + * @ingroup lavc_decoding + */ +enum AVDiscard{ + /* We leave some space between them for extensions (drop some + * keyframes for intra-only or drop just some bidir frames). */ + AVDISCARD_NONE =-16, ///< discard nothing + AVDISCARD_DEFAULT = 0, ///< discard useless packets like 0 size packets in avi + AVDISCARD_NONREF = 8, ///< discard all non reference + AVDISCARD_BIDIR = 16, ///< discard all bidirectional frames + AVDISCARD_NONINTRA= 24, ///< discard all non intra frames + AVDISCARD_NONKEY = 32, ///< discard all frames except keyframes + AVDISCARD_ALL = 48, ///< discard all +}; + +enum AVAudioServiceType { + AV_AUDIO_SERVICE_TYPE_MAIN = 0, + AV_AUDIO_SERVICE_TYPE_EFFECTS = 1, + AV_AUDIO_SERVICE_TYPE_VISUALLY_IMPAIRED = 2, + AV_AUDIO_SERVICE_TYPE_HEARING_IMPAIRED = 3, + AV_AUDIO_SERVICE_TYPE_DIALOGUE = 4, + AV_AUDIO_SERVICE_TYPE_COMMENTARY = 5, + AV_AUDIO_SERVICE_TYPE_EMERGENCY = 6, + AV_AUDIO_SERVICE_TYPE_VOICE_OVER = 7, + AV_AUDIO_SERVICE_TYPE_KARAOKE = 8, + AV_AUDIO_SERVICE_TYPE_NB , ///< Not part of ABI +}; + +/** + * @ingroup lavc_encoding + */ +typedef struct RcOverride{ + int start_frame; + int end_frame; + int qscale; // If this is 0 then quality_factor will be used instead. + float quality_factor; +} RcOverride; + +#if FF_API_MAX_BFRAMES +/** + * @deprecated there is no libavcodec-wide limit on the number of B-frames + */ +#define FF_MAX_B_FRAMES 16 +#endif + +/* encoding support + These flags can be passed in AVCodecContext.flags before initialization. + Note: Not everything is supported yet. +*/ + +/** + * Allow decoders to produce frames with data planes that are not aligned + * to CPU requirements (e.g. due to cropping). + */ +#define AV_CODEC_FLAG_UNALIGNED (1 << 0) +/** + * Use fixed qscale. + */ +#define AV_CODEC_FLAG_QSCALE (1 << 1) +/** + * 4 MV per MB allowed / advanced prediction for H.263. + */ +#define AV_CODEC_FLAG_4MV (1 << 2) +/** + * Output even those frames that might be corrupted. + */ +#define AV_CODEC_FLAG_OUTPUT_CORRUPT (1 << 3) +/** + * Use qpel MC. + */ +#define AV_CODEC_FLAG_QPEL (1 << 4) +/** + * Use internal 2pass ratecontrol in first pass mode. + */ +#define AV_CODEC_FLAG_PASS1 (1 << 9) +/** + * Use internal 2pass ratecontrol in second pass mode. + */ +#define AV_CODEC_FLAG_PASS2 (1 << 10) +/** + * loop filter. + */ +#define AV_CODEC_FLAG_LOOP_FILTER (1 << 11) +/** + * Only decode/encode grayscale. + */ +#define AV_CODEC_FLAG_GRAY (1 << 13) +/** + * error[?] variables will be set during encoding. + */ +#define AV_CODEC_FLAG_PSNR (1 << 15) +/** + * Input bitstream might be truncated at a random location + * instead of only at frame boundaries. + */ +#define AV_CODEC_FLAG_TRUNCATED (1 << 16) +/** + * Use interlaced DCT. + */ +#define AV_CODEC_FLAG_INTERLACED_DCT (1 << 18) +/** + * Force low delay. + */ +#define AV_CODEC_FLAG_LOW_DELAY (1 << 19) +/** + * Place global headers in extradata instead of every keyframe. + */ +#define AV_CODEC_FLAG_GLOBAL_HEADER (1 << 22) +/** + * Use only bitexact stuff (except (I)DCT). + */ +#define AV_CODEC_FLAG_BITEXACT (1 << 23) +/* Fx : Flag for H.263+ extra options */ +/** + * H.263 advanced intra coding / MPEG-4 AC prediction + */ +#define AV_CODEC_FLAG_AC_PRED (1 << 24) +/** + * interlaced motion estimation + */ +#define AV_CODEC_FLAG_INTERLACED_ME (1 << 29) +#define AV_CODEC_FLAG_CLOSED_GOP (1U << 31) + +/** + * Allow non spec compliant speedup tricks. + */ +#define AV_CODEC_FLAG2_FAST (1 << 0) +/** + * Skip bitstream encoding. + */ +#define AV_CODEC_FLAG2_NO_OUTPUT (1 << 2) +/** + * Place global headers at every keyframe instead of in extradata. + */ +#define AV_CODEC_FLAG2_LOCAL_HEADER (1 << 3) + +/** + * timecode is in drop frame format. DEPRECATED!!!! + */ +#define AV_CODEC_FLAG2_DROP_FRAME_TIMECODE (1 << 13) + +/** + * Input bitstream might be truncated at a packet boundaries + * instead of only at frame boundaries. + */ +#define AV_CODEC_FLAG2_CHUNKS (1 << 15) +/** + * Discard cropping information from SPS. + */ +#define AV_CODEC_FLAG2_IGNORE_CROP (1 << 16) + +/** + * Show all frames before the first keyframe + */ +#define AV_CODEC_FLAG2_SHOW_ALL (1 << 22) +/** + * Export motion vectors through frame side data + */ +#define AV_CODEC_FLAG2_EXPORT_MVS (1 << 28) +/** + * Do not skip samples and export skip information as frame side data + */ +#define AV_CODEC_FLAG2_SKIP_MANUAL (1 << 29) +/** + * Do not reset ASS ReadOrder field on flush (subtitles decoding) + */ +#define AV_CODEC_FLAG2_RO_FLUSH_NOOP (1 << 30) + +/* Unsupported options : + * Syntax Arithmetic coding (SAC) + * Reference Picture Selection + * Independent Segment Decoding */ +/* /Fx */ +/* codec capabilities */ + +/** + * Decoder can use draw_horiz_band callback. + */ +#define AV_CODEC_CAP_DRAW_HORIZ_BAND (1 << 0) +/** + * Codec uses get_buffer() for allocating buffers and supports custom allocators. + * If not set, it might not use get_buffer() at all or use operations that + * assume the buffer was allocated by avcodec_default_get_buffer. + */ +#define AV_CODEC_CAP_DR1 (1 << 1) +#define AV_CODEC_CAP_TRUNCATED (1 << 3) +/** + * Encoder or decoder requires flushing with NULL input at the end in order to + * give the complete and correct output. + * + * NOTE: If this flag is not set, the codec is guaranteed to never be fed with + * with NULL data. The user can still send NULL data to the public encode + * or decode function, but libavcodec will not pass it along to the codec + * unless this flag is set. + * + * Decoders: + * The decoder has a non-zero delay and needs to be fed with avpkt->data=NULL, + * avpkt->size=0 at the end to get the delayed data until the decoder no longer + * returns frames. + * + * Encoders: + * The encoder needs to be fed with NULL data at the end of encoding until the + * encoder no longer returns data. + * + * NOTE: For encoders implementing the AVCodec.encode2() function, setting this + * flag also means that the encoder must set the pts and duration for + * each output packet. If this flag is not set, the pts and duration will + * be determined by libavcodec from the input frame. + */ +#define AV_CODEC_CAP_DELAY (1 << 5) +/** + * Codec can be fed a final frame with a smaller size. + * This can be used to prevent truncation of the last audio samples. + */ +#define AV_CODEC_CAP_SMALL_LAST_FRAME (1 << 6) + +#if FF_API_CAP_VDPAU +/** + * Codec can export data for HW decoding (VDPAU). + */ +#define AV_CODEC_CAP_HWACCEL_VDPAU (1 << 7) +#endif + +/** + * Codec can output multiple frames per AVPacket + * Normally demuxers return one frame at a time, demuxers which do not do + * are connected to a parser to split what they return into proper frames. + * This flag is reserved to the very rare category of codecs which have a + * bitstream that cannot be split into frames without timeconsuming + * operations like full decoding. Demuxers carrying such bitstreams thus + * may return multiple frames in a packet. This has many disadvantages like + * prohibiting stream copy in many cases thus it should only be considered + * as a last resort. + */ +#define AV_CODEC_CAP_SUBFRAMES (1 << 8) +/** + * Codec is experimental and is thus avoided in favor of non experimental + * encoders + */ +#define AV_CODEC_CAP_EXPERIMENTAL (1 << 9) +/** + * Codec should fill in channel configuration and samplerate instead of container + */ +#define AV_CODEC_CAP_CHANNEL_CONF (1 << 10) +/** + * Codec supports frame-level multithreading. + */ +#define AV_CODEC_CAP_FRAME_THREADS (1 << 12) +/** + * Codec supports slice-based (or partition-based) multithreading. + */ +#define AV_CODEC_CAP_SLICE_THREADS (1 << 13) +/** + * Codec supports changed parameters at any point. + */ +#define AV_CODEC_CAP_PARAM_CHANGE (1 << 14) +/** + * Codec supports avctx->thread_count == 0 (auto). + */ +#define AV_CODEC_CAP_AUTO_THREADS (1 << 15) +/** + * Audio encoder supports receiving a different number of samples in each call. + */ +#define AV_CODEC_CAP_VARIABLE_FRAME_SIZE (1 << 16) +/** + * Decoder is not a preferred choice for probing. + * This indicates that the decoder is not a good choice for probing. + * It could for example be an expensive to spin up hardware decoder, + * or it could simply not provide a lot of useful information about + * the stream. + * A decoder marked with this flag should only be used as last resort + * choice for probing. + */ +#define AV_CODEC_CAP_AVOID_PROBING (1 << 17) +/** + * Codec is intra only. + */ +#define AV_CODEC_CAP_INTRA_ONLY 0x40000000 +/** + * Codec is lossless. + */ +#define AV_CODEC_CAP_LOSSLESS 0x80000000 + + +#if FF_API_WITHOUT_PREFIX +/** + * Allow decoders to produce frames with data planes that are not aligned + * to CPU requirements (e.g. due to cropping). + */ +#define CODEC_FLAG_UNALIGNED AV_CODEC_FLAG_UNALIGNED +#define CODEC_FLAG_QSCALE AV_CODEC_FLAG_QSCALE +#define CODEC_FLAG_4MV AV_CODEC_FLAG_4MV +#define CODEC_FLAG_OUTPUT_CORRUPT AV_CODEC_FLAG_OUTPUT_CORRUPT +#define CODEC_FLAG_QPEL AV_CODEC_FLAG_QPEL +#if FF_API_GMC +/** + * @deprecated use the "gmc" private option of the libxvid encoder + */ +#define CODEC_FLAG_GMC 0x0020 ///< Use GMC. +#endif +#if FF_API_MV0 +/** + * @deprecated use the flag "mv0" in the "mpv_flags" private option of the + * mpegvideo encoders + */ +#define CODEC_FLAG_MV0 0x0040 +#endif +#if FF_API_INPUT_PRESERVED +/** + * @deprecated passing reference-counted frames to the encoders replaces this + * flag + */ +#define CODEC_FLAG_INPUT_PRESERVED 0x0100 +#endif +#define CODEC_FLAG_PASS1 AV_CODEC_FLAG_PASS1 +#define CODEC_FLAG_PASS2 AV_CODEC_FLAG_PASS2 +#define CODEC_FLAG_GRAY AV_CODEC_FLAG_GRAY +#if FF_API_EMU_EDGE +/** + * @deprecated edges are not used/required anymore. I.e. this flag is now always + * set. + */ +#define CODEC_FLAG_EMU_EDGE 0x4000 +#endif +#define CODEC_FLAG_PSNR AV_CODEC_FLAG_PSNR +#define CODEC_FLAG_TRUNCATED AV_CODEC_FLAG_TRUNCATED + +#if FF_API_NORMALIZE_AQP +/** + * @deprecated use the flag "naq" in the "mpv_flags" private option of the + * mpegvideo encoders + */ +#define CODEC_FLAG_NORMALIZE_AQP 0x00020000 +#endif +#define CODEC_FLAG_INTERLACED_DCT AV_CODEC_FLAG_INTERLACED_DCT +#define CODEC_FLAG_LOW_DELAY AV_CODEC_FLAG_LOW_DELAY +#define CODEC_FLAG_GLOBAL_HEADER AV_CODEC_FLAG_GLOBAL_HEADER +#define CODEC_FLAG_BITEXACT AV_CODEC_FLAG_BITEXACT +#define CODEC_FLAG_AC_PRED AV_CODEC_FLAG_AC_PRED +#define CODEC_FLAG_LOOP_FILTER AV_CODEC_FLAG_LOOP_FILTER +#define CODEC_FLAG_INTERLACED_ME AV_CODEC_FLAG_INTERLACED_ME +#define CODEC_FLAG_CLOSED_GOP AV_CODEC_FLAG_CLOSED_GOP +#define CODEC_FLAG2_FAST AV_CODEC_FLAG2_FAST +#define CODEC_FLAG2_NO_OUTPUT AV_CODEC_FLAG2_NO_OUTPUT +#define CODEC_FLAG2_LOCAL_HEADER AV_CODEC_FLAG2_LOCAL_HEADER +#define CODEC_FLAG2_DROP_FRAME_TIMECODE AV_CODEC_FLAG2_DROP_FRAME_TIMECODE +#define CODEC_FLAG2_IGNORE_CROP AV_CODEC_FLAG2_IGNORE_CROP + +#define CODEC_FLAG2_CHUNKS AV_CODEC_FLAG2_CHUNKS +#define CODEC_FLAG2_SHOW_ALL AV_CODEC_FLAG2_SHOW_ALL +#define CODEC_FLAG2_EXPORT_MVS AV_CODEC_FLAG2_EXPORT_MVS +#define CODEC_FLAG2_SKIP_MANUAL AV_CODEC_FLAG2_SKIP_MANUAL + +/* Unsupported options : + * Syntax Arithmetic coding (SAC) + * Reference Picture Selection + * Independent Segment Decoding */ +/* /Fx */ +/* codec capabilities */ + +#define CODEC_CAP_DRAW_HORIZ_BAND AV_CODEC_CAP_DRAW_HORIZ_BAND ///< Decoder can use draw_horiz_band callback. +/** + * Codec uses get_buffer() for allocating buffers and supports custom allocators. + * If not set, it might not use get_buffer() at all or use operations that + * assume the buffer was allocated by avcodec_default_get_buffer. + */ +#define CODEC_CAP_DR1 AV_CODEC_CAP_DR1 +#define CODEC_CAP_TRUNCATED AV_CODEC_CAP_TRUNCATED +#if FF_API_XVMC +/* Codec can export data for HW decoding. This flag indicates that + * the codec would call get_format() with list that might contain HW accelerated + * pixel formats (XvMC, VDPAU, VAAPI, etc). The application can pick any of them + * including raw image format. + * The application can use the passed context to determine bitstream version, + * chroma format, resolution etc. + */ +#define CODEC_CAP_HWACCEL 0x0010 +#endif /* FF_API_XVMC */ +/** + * Encoder or decoder requires flushing with NULL input at the end in order to + * give the complete and correct output. + * + * NOTE: If this flag is not set, the codec is guaranteed to never be fed with + * with NULL data. The user can still send NULL data to the public encode + * or decode function, but libavcodec will not pass it along to the codec + * unless this flag is set. + * + * Decoders: + * The decoder has a non-zero delay and needs to be fed with avpkt->data=NULL, + * avpkt->size=0 at the end to get the delayed data until the decoder no longer + * returns frames. + * + * Encoders: + * The encoder needs to be fed with NULL data at the end of encoding until the + * encoder no longer returns data. + * + * NOTE: For encoders implementing the AVCodec.encode2() function, setting this + * flag also means that the encoder must set the pts and duration for + * each output packet. If this flag is not set, the pts and duration will + * be determined by libavcodec from the input frame. + */ +#define CODEC_CAP_DELAY AV_CODEC_CAP_DELAY +/** + * Codec can be fed a final frame with a smaller size. + * This can be used to prevent truncation of the last audio samples. + */ +#define CODEC_CAP_SMALL_LAST_FRAME AV_CODEC_CAP_SMALL_LAST_FRAME +#if FF_API_CAP_VDPAU +/** + * Codec can export data for HW decoding (VDPAU). + */ +#define CODEC_CAP_HWACCEL_VDPAU AV_CODEC_CAP_HWACCEL_VDPAU +#endif +/** + * Codec can output multiple frames per AVPacket + * Normally demuxers return one frame at a time, demuxers which do not do + * are connected to a parser to split what they return into proper frames. + * This flag is reserved to the very rare category of codecs which have a + * bitstream that cannot be split into frames without timeconsuming + * operations like full decoding. Demuxers carrying such bitstreams thus + * may return multiple frames in a packet. This has many disadvantages like + * prohibiting stream copy in many cases thus it should only be considered + * as a last resort. + */ +#define CODEC_CAP_SUBFRAMES AV_CODEC_CAP_SUBFRAMES +/** + * Codec is experimental and is thus avoided in favor of non experimental + * encoders + */ +#define CODEC_CAP_EXPERIMENTAL AV_CODEC_CAP_EXPERIMENTAL +/** + * Codec should fill in channel configuration and samplerate instead of container + */ +#define CODEC_CAP_CHANNEL_CONF AV_CODEC_CAP_CHANNEL_CONF +#if FF_API_NEG_LINESIZES +/** + * @deprecated no codecs use this capability + */ +#define CODEC_CAP_NEG_LINESIZES 0x0800 +#endif +/** + * Codec supports frame-level multithreading. + */ +#define CODEC_CAP_FRAME_THREADS AV_CODEC_CAP_FRAME_THREADS +/** + * Codec supports slice-based (or partition-based) multithreading. + */ +#define CODEC_CAP_SLICE_THREADS AV_CODEC_CAP_SLICE_THREADS +/** + * Codec supports changed parameters at any point. + */ +#define CODEC_CAP_PARAM_CHANGE AV_CODEC_CAP_PARAM_CHANGE +/** + * Codec supports avctx->thread_count == 0 (auto). + */ +#define CODEC_CAP_AUTO_THREADS AV_CODEC_CAP_AUTO_THREADS +/** + * Audio encoder supports receiving a different number of samples in each call. + */ +#define CODEC_CAP_VARIABLE_FRAME_SIZE AV_CODEC_CAP_VARIABLE_FRAME_SIZE +/** + * Codec is intra only. + */ +#define CODEC_CAP_INTRA_ONLY AV_CODEC_CAP_INTRA_ONLY +/** + * Codec is lossless. + */ +#define CODEC_CAP_LOSSLESS AV_CODEC_CAP_LOSSLESS + +/** + * HWAccel is experimental and is thus avoided in favor of non experimental + * codecs + */ +#define HWACCEL_CODEC_CAP_EXPERIMENTAL 0x0200 +#endif /* FF_API_WITHOUT_PREFIX */ + +#if FF_API_MB_TYPE +//The following defines may change, don't expect compatibility if you use them. +#define MB_TYPE_INTRA4x4 0x0001 +#define MB_TYPE_INTRA16x16 0x0002 //FIXME H.264-specific +#define MB_TYPE_INTRA_PCM 0x0004 //FIXME H.264-specific +#define MB_TYPE_16x16 0x0008 +#define MB_TYPE_16x8 0x0010 +#define MB_TYPE_8x16 0x0020 +#define MB_TYPE_8x8 0x0040 +#define MB_TYPE_INTERLACED 0x0080 +#define MB_TYPE_DIRECT2 0x0100 //FIXME +#define MB_TYPE_ACPRED 0x0200 +#define MB_TYPE_GMC 0x0400 +#define MB_TYPE_SKIP 0x0800 +#define MB_TYPE_P0L0 0x1000 +#define MB_TYPE_P1L0 0x2000 +#define MB_TYPE_P0L1 0x4000 +#define MB_TYPE_P1L1 0x8000 +#define MB_TYPE_L0 (MB_TYPE_P0L0 | MB_TYPE_P1L0) +#define MB_TYPE_L1 (MB_TYPE_P0L1 | MB_TYPE_P1L1) +#define MB_TYPE_L0L1 (MB_TYPE_L0 | MB_TYPE_L1) +#define MB_TYPE_QUANT 0x00010000 +#define MB_TYPE_CBP 0x00020000 +// Note bits 24-31 are reserved for codec specific use (H.264 ref0, MPEG-1 0mv, ...) +#endif + +/** + * Pan Scan area. + * This specifies the area which should be displayed. + * Note there may be multiple such areas for one frame. + */ +typedef struct AVPanScan{ + /** + * id + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int id; + + /** + * width and height in 1/16 pel + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int width; + int height; + + /** + * position of the top left corner in 1/16 pel for up to 3 fields/frames + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int16_t position[3][2]; +}AVPanScan; + +/** + * This structure describes the bitrate properties of an encoded bitstream. It + * roughly corresponds to a subset the VBV parameters for MPEG-2 or HRD + * parameters for H.264/HEVC. + */ +typedef struct AVCPBProperties { + /** + * Maximum bitrate of the stream, in bits per second. + * Zero if unknown or unspecified. + */ + int max_bitrate; + /** + * Minimum bitrate of the stream, in bits per second. + * Zero if unknown or unspecified. + */ + int min_bitrate; + /** + * Average bitrate of the stream, in bits per second. + * Zero if unknown or unspecified. + */ + int avg_bitrate; + + /** + * The size of the buffer to which the ratecontrol is applied, in bits. + * Zero if unknown or unspecified. + */ + int buffer_size; + + /** + * The delay between the time the packet this structure is associated with + * is received and the time when it should be decoded, in periods of a 27MHz + * clock. + * + * UINT64_MAX when unknown or unspecified. + */ + uint64_t vbv_delay; +} AVCPBProperties; + +#if FF_API_QSCALE_TYPE +#define FF_QSCALE_TYPE_MPEG1 0 +#define FF_QSCALE_TYPE_MPEG2 1 +#define FF_QSCALE_TYPE_H264 2 +#define FF_QSCALE_TYPE_VP56 3 +#endif + +/** + * The decoder will keep a reference to the frame and may reuse it later. + */ +#define AV_GET_BUFFER_FLAG_REF (1 << 0) + +/** + * @defgroup lavc_packet AVPacket + * + * Types and functions for working with AVPacket. + * @{ + */ +enum AVPacketSideDataType { + /** + * An AV_PKT_DATA_PALETTE side data packet contains exactly AVPALETTE_SIZE + * bytes worth of palette. This side data signals that a new palette is + * present. + */ + AV_PKT_DATA_PALETTE, + + /** + * The AV_PKT_DATA_NEW_EXTRADATA is used to notify the codec or the format + * that the extradata buffer was changed and the receiving side should + * act upon it appropriately. The new extradata is embedded in the side + * data buffer and should be immediately used for processing the current + * frame or packet. + */ + AV_PKT_DATA_NEW_EXTRADATA, + + /** + * An AV_PKT_DATA_PARAM_CHANGE side data packet is laid out as follows: + * @code + * u32le param_flags + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT) + * s32le channel_count + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT) + * u64le channel_layout + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE) + * s32le sample_rate + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS) + * s32le width + * s32le height + * @endcode + */ + AV_PKT_DATA_PARAM_CHANGE, + + /** + * An AV_PKT_DATA_H263_MB_INFO side data packet contains a number of + * structures with info about macroblocks relevant to splitting the + * packet into smaller packets on macroblock edges (e.g. as for RFC 2190). + * That is, it does not necessarily contain info about all macroblocks, + * as long as the distance between macroblocks in the info is smaller + * than the target payload size. + * Each MB info structure is 12 bytes, and is laid out as follows: + * @code + * u32le bit offset from the start of the packet + * u8 current quantizer at the start of the macroblock + * u8 GOB number + * u16le macroblock address within the GOB + * u8 horizontal MV predictor + * u8 vertical MV predictor + * u8 horizontal MV predictor for block number 3 + * u8 vertical MV predictor for block number 3 + * @endcode + */ + AV_PKT_DATA_H263_MB_INFO, + + /** + * This side data should be associated with an audio stream and contains + * ReplayGain information in form of the AVReplayGain struct. + */ + AV_PKT_DATA_REPLAYGAIN, + + /** + * This side data contains a 3x3 transformation matrix describing an affine + * transformation that needs to be applied to the decoded video frames for + * correct presentation. + * + * See libavutil/display.h for a detailed description of the data. + */ + AV_PKT_DATA_DISPLAYMATRIX, + + /** + * This side data should be associated with a video stream and contains + * Stereoscopic 3D information in form of the AVStereo3D struct. + */ + AV_PKT_DATA_STEREO3D, + + /** + * This side data should be associated with an audio stream and corresponds + * to enum AVAudioServiceType. + */ + AV_PKT_DATA_AUDIO_SERVICE_TYPE, + + /** + * This side data contains quality related information from the encoder. + * @code + * u32le quality factor of the compressed frame. Allowed range is between 1 (good) and FF_LAMBDA_MAX (bad). + * u8 picture type + * u8 error count + * u16 reserved + * u64le[error count] sum of squared differences between encoder in and output + * @endcode + */ + AV_PKT_DATA_QUALITY_STATS, + + /** + * This side data contains an integer value representing the stream index + * of a "fallback" track. A fallback track indicates an alternate + * track to use when the current track can not be decoded for some reason. + * e.g. no decoder available for codec. + */ + AV_PKT_DATA_FALLBACK_TRACK, + + /** + * This side data corresponds to the AVCPBProperties struct. + */ + AV_PKT_DATA_CPB_PROPERTIES, + + /** + * Recommmends skipping the specified number of samples + * @code + * u32le number of samples to skip from start of this packet + * u32le number of samples to skip from end of this packet + * u8 reason for start skip + * u8 reason for end skip (0=padding silence, 1=convergence) + * @endcode + */ + AV_PKT_DATA_SKIP_SAMPLES=70, + + /** + * An AV_PKT_DATA_JP_DUALMONO side data packet indicates that + * the packet may contain "dual mono" audio specific to Japanese DTV + * and if it is true, recommends only the selected channel to be used. + * @code + * u8 selected channels (0=mail/left, 1=sub/right, 2=both) + * @endcode + */ + AV_PKT_DATA_JP_DUALMONO, + + /** + * A list of zero terminated key/value strings. There is no end marker for + * the list, so it is required to rely on the side data size to stop. + */ + AV_PKT_DATA_STRINGS_METADATA, + + /** + * Subtitle event position + * @code + * u32le x1 + * u32le y1 + * u32le x2 + * u32le y2 + * @endcode + */ + AV_PKT_DATA_SUBTITLE_POSITION, + + /** + * Data found in BlockAdditional element of matroska container. There is + * no end marker for the data, so it is required to rely on the side data + * size to recognize the end. 8 byte id (as found in BlockAddId) followed + * by data. + */ + AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL, + + /** + * The optional first identifier line of a WebVTT cue. + */ + AV_PKT_DATA_WEBVTT_IDENTIFIER, + + /** + * The optional settings (rendering instructions) that immediately + * follow the timestamp specifier of a WebVTT cue. + */ + AV_PKT_DATA_WEBVTT_SETTINGS, + + /** + * A list of zero terminated key/value strings. There is no end marker for + * the list, so it is required to rely on the side data size to stop. This + * side data includes updated metadata which appeared in the stream. + */ + AV_PKT_DATA_METADATA_UPDATE, + + /** + * MPEGTS stream ID, this is required to pass the stream ID + * information from the demuxer to the corresponding muxer. + */ + AV_PKT_DATA_MPEGTS_STREAM_ID, + + /** + * Mastering display metadata (based on SMPTE-2086:2014). This metadata + * should be associated with a video stream and containts data in the form + * of the AVMasteringDisplayMetadata struct. + */ + AV_PKT_DATA_MASTERING_DISPLAY_METADATA, + + /** + * This side data should be associated with a video stream and corresponds + * to the AVSphericalMapping structure. + */ + AV_PKT_DATA_SPHERICAL, + + /** + * The number of side data elements (in fact a bit more than it). + * This is not part of the public API/ABI in the sense that it may + * change when new side data types are added. + * This must stay the last enum value. + * If its value becomes huge, some code using it + * needs to be updated as it assumes it to be smaller than other limits. + */ + AV_PKT_DATA_NB +}; + +#define AV_PKT_DATA_QUALITY_FACTOR AV_PKT_DATA_QUALITY_STATS //DEPRECATED + +typedef struct AVPacketSideData { + uint8_t *data; + int size; + enum AVPacketSideDataType type; +} AVPacketSideData; + +/** + * This structure stores compressed data. It is typically exported by demuxers + * and then passed as input to decoders, or received as output from encoders and + * then passed to muxers. + * + * For video, it should typically contain one compressed frame. For audio it may + * contain several compressed frames. Encoders are allowed to output empty + * packets, with no compressed data, containing only side data + * (e.g. to update some stream parameters at the end of encoding). + * + * AVPacket is one of the few structs in FFmpeg, whose size is a part of public + * ABI. Thus it may be allocated on stack and no new fields can be added to it + * without libavcodec and libavformat major bump. + * + * The semantics of data ownership depends on the buf field. + * If it is set, the packet data is dynamically allocated and is + * valid indefinitely until a call to av_packet_unref() reduces the + * reference count to 0. + * + * If the buf field is not set av_packet_ref() would make a copy instead + * of increasing the reference count. + * + * The side data is always allocated with av_malloc(), copied by + * av_packet_ref() and freed by av_packet_unref(). + * + * @see av_packet_ref + * @see av_packet_unref + */ +typedef struct AVPacket { + /** + * A reference to the reference-counted buffer where the packet data is + * stored. + * May be NULL, then the packet data is not reference-counted. + */ + AVBufferRef *buf; + /** + * Presentation timestamp in AVStream->time_base units; the time at which + * the decompressed packet will be presented to the user. + * Can be AV_NOPTS_VALUE if it is not stored in the file. + * pts MUST be larger or equal to dts as presentation cannot happen before + * decompression, unless one wants to view hex dumps. Some formats misuse + * the terms dts and pts/cts to mean something different. Such timestamps + * must be converted to true pts/dts before they are stored in AVPacket. + */ + int64_t pts; + /** + * Decompression timestamp in AVStream->time_base units; the time at which + * the packet is decompressed. + * Can be AV_NOPTS_VALUE if it is not stored in the file. + */ + int64_t dts; + uint8_t *data; + int size; + int stream_index; + /** + * A combination of AV_PKT_FLAG values + */ + int flags; + /** + * Additional packet data that can be provided by the container. + * Packet can contain several types of side information. + */ + AVPacketSideData *side_data; + int side_data_elems; + + /** + * Duration of this packet in AVStream->time_base units, 0 if unknown. + * Equals next_pts - this_pts in presentation order. + */ + int64_t duration; + + int64_t pos; ///< byte position in stream, -1 if unknown + +#if FF_API_CONVERGENCE_DURATION + /** + * @deprecated Same as the duration field, but as int64_t. This was required + * for Matroska subtitles, whose duration values could overflow when the + * duration field was still an int. + */ + attribute_deprecated + int64_t convergence_duration; +#endif +} AVPacket; +#define AV_PKT_FLAG_KEY 0x0001 ///< The packet contains a keyframe +#define AV_PKT_FLAG_CORRUPT 0x0002 ///< The packet content is corrupted +/** + * Flag is used to discard packets which are required to maintain valid + * decoder state but are not required for output and should be dropped + * after decoding. + **/ +#define AV_PKT_FLAG_DISCARD 0x0004 + +enum AVSideDataParamChangeFlags { + AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT = 0x0001, + AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT = 0x0002, + AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE = 0x0004, + AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS = 0x0008, +}; +/** + * @} + */ + +struct AVCodecInternal; + +enum AVFieldOrder { + AV_FIELD_UNKNOWN, + AV_FIELD_PROGRESSIVE, + AV_FIELD_TT, //< Top coded_first, top displayed first + AV_FIELD_BB, //< Bottom coded first, bottom displayed first + AV_FIELD_TB, //< Top coded first, bottom displayed first + AV_FIELD_BT, //< Bottom coded first, top displayed first +}; + +/** + * main external API structure. + * New fields can be added to the end with minor version bumps. + * Removal, reordering and changes to existing fields require a major + * version bump. + * You can use AVOptions (av_opt* / av_set/get*()) to access these fields from user + * applications. + * The name string for AVOptions options matches the associated command line + * parameter name and can be found in libavcodec/options_table.h + * The AVOption/command line parameter names differ in some cases from the C + * structure field names for historic reasons or brevity. + * sizeof(AVCodecContext) must not be used outside libav*. + */ +typedef struct AVCodecContext { + /** + * information on struct for av_log + * - set by avcodec_alloc_context3 + */ + const AVClass *av_class; + int log_level_offset; + + enum AVMediaType codec_type; /* see AVMEDIA_TYPE_xxx */ + const struct AVCodec *codec; +#if FF_API_CODEC_NAME + /** + * @deprecated this field is not used for anything in libavcodec + */ + attribute_deprecated + char codec_name[32]; +#endif + enum AVCodecID codec_id; /* see AV_CODEC_ID_xxx */ + + /** + * fourcc (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A'). + * This is used to work around some encoder bugs. + * A demuxer should set this to what is stored in the field used to identify the codec. + * If there are multiple such fields in a container then the demuxer should choose the one + * which maximizes the information about the used codec. + * If the codec tag field in a container is larger than 32 bits then the demuxer should + * remap the longer ID to 32 bits with a table or other structure. Alternatively a new + * extra_codec_tag + size could be added but for this a clear advantage must be demonstrated + * first. + * - encoding: Set by user, if not then the default based on codec_id will be used. + * - decoding: Set by user, will be converted to uppercase by libavcodec during init. + */ + unsigned int codec_tag; + +#if FF_API_STREAM_CODEC_TAG + /** + * @deprecated this field is unused + */ + attribute_deprecated + unsigned int stream_codec_tag; +#endif + + void *priv_data; + + /** + * Private context used for internal data. + * + * Unlike priv_data, this is not codec-specific. It is used in general + * libavcodec functions. + */ + struct AVCodecInternal *internal; + + /** + * Private data of the user, can be used to carry app specific stuff. + * - encoding: Set by user. + * - decoding: Set by user. + */ + void *opaque; + + /** + * the average bitrate + * - encoding: Set by user; unused for constant quantizer encoding. + * - decoding: Set by user, may be overwritten by libavcodec + * if this info is available in the stream + */ + int64_t bit_rate; + + /** + * number of bits the bitstream is allowed to diverge from the reference. + * the reference can be CBR (for CBR pass1) or VBR (for pass2) + * - encoding: Set by user; unused for constant quantizer encoding. + * - decoding: unused + */ + int bit_rate_tolerance; + + /** + * Global quality for codecs which cannot change it per frame. + * This should be proportional to MPEG-1/2/4 qscale. + * - encoding: Set by user. + * - decoding: unused + */ + int global_quality; + + /** + * - encoding: Set by user. + * - decoding: unused + */ + int compression_level; +#define FF_COMPRESSION_DEFAULT -1 + + /** + * AV_CODEC_FLAG_*. + * - encoding: Set by user. + * - decoding: Set by user. + */ + int flags; + + /** + * AV_CODEC_FLAG2_* + * - encoding: Set by user. + * - decoding: Set by user. + */ + int flags2; + + /** + * some codecs need / can use extradata like Huffman tables. + * MJPEG: Huffman tables + * rv10: additional flags + * MPEG-4: global headers (they can be in the bitstream or here) + * The allocated memory should be AV_INPUT_BUFFER_PADDING_SIZE bytes larger + * than extradata_size to avoid problems if it is read with the bitstream reader. + * The bytewise contents of extradata must not depend on the architecture or CPU endianness. + * - encoding: Set/allocated/freed by libavcodec. + * - decoding: Set/allocated/freed by user. + */ + uint8_t *extradata; + int extradata_size; + + /** + * This is the fundamental unit of time (in seconds) in terms + * of which frame timestamps are represented. For fixed-fps content, + * timebase should be 1/framerate and timestamp increments should be + * identically 1. + * This often, but not always is the inverse of the frame rate or field rate + * for video. 1/time_base is not the average frame rate if the frame rate is not + * constant. + * + * Like containers, elementary streams also can store timestamps, 1/time_base + * is the unit in which these timestamps are specified. + * As example of such codec time base see ISO/IEC 14496-2:2001(E) + * vop_time_increment_resolution and fixed_vop_rate + * (fixed_vop_rate == 0 implies that it is different from the framerate) + * + * - encoding: MUST be set by user. + * - decoding: the use of this field for decoding is deprecated. + * Use framerate instead. + */ + AVRational time_base; + + /** + * For some codecs, the time base is closer to the field rate than the frame rate. + * Most notably, H.264 and MPEG-2 specify time_base as half of frame duration + * if no telecine is used ... + * + * Set to time_base ticks per frame. Default 1, e.g., H.264/MPEG-2 set it to 2. + */ + int ticks_per_frame; + + /** + * Codec delay. + * + * Encoding: Number of frames delay there will be from the encoder input to + * the decoder output. (we assume the decoder matches the spec) + * Decoding: Number of frames delay in addition to what a standard decoder + * as specified in the spec would produce. + * + * Video: + * Number of frames the decoded output will be delayed relative to the + * encoded input. + * + * Audio: + * For encoding, this field is unused (see initial_padding). + * + * For decoding, this is the number of samples the decoder needs to + * output before the decoder's output is valid. When seeking, you should + * start decoding this many samples prior to your desired seek point. + * + * - encoding: Set by libavcodec. + * - decoding: Set by libavcodec. + */ + int delay; + + + /* video only */ + /** + * picture width / height. + * + * @note Those fields may not match the values of the last + * AVFrame output by avcodec_decode_video2 due frame + * reordering. + * + * - encoding: MUST be set by user. + * - decoding: May be set by the user before opening the decoder if known e.g. + * from the container. Some decoders will require the dimensions + * to be set by the caller. During decoding, the decoder may + * overwrite those values as required while parsing the data. + */ + int width, height; + + /** + * Bitstream width / height, may be different from width/height e.g. when + * the decoded frame is cropped before being output or lowres is enabled. + * + * @note Those field may not match the value of the last + * AVFrame output by avcodec_receive_frame() due frame + * reordering. + * + * - encoding: unused + * - decoding: May be set by the user before opening the decoder if known + * e.g. from the container. During decoding, the decoder may + * overwrite those values as required while parsing the data. + */ + int coded_width, coded_height; + +#if FF_API_ASPECT_EXTENDED +#define FF_ASPECT_EXTENDED 15 +#endif + + /** + * the number of pictures in a group of pictures, or 0 for intra_only + * - encoding: Set by user. + * - decoding: unused + */ + int gop_size; + + /** + * Pixel format, see AV_PIX_FMT_xxx. + * May be set by the demuxer if known from headers. + * May be overridden by the decoder if it knows better. + * + * @note This field may not match the value of the last + * AVFrame output by avcodec_receive_frame() due frame + * reordering. + * + * - encoding: Set by user. + * - decoding: Set by user if known, overridden by libavcodec while + * parsing the data. + */ + enum AVPixelFormat pix_fmt; + +#if FF_API_MOTION_EST + /** + * This option does nothing + * @deprecated use codec private options instead + */ + attribute_deprecated int me_method; +#endif + + /** + * If non NULL, 'draw_horiz_band' is called by the libavcodec + * decoder to draw a horizontal band. It improves cache usage. Not + * all codecs can do that. You must check the codec capabilities + * beforehand. + * When multithreading is used, it may be called from multiple threads + * at the same time; threads might draw different parts of the same AVFrame, + * or multiple AVFrames, and there is no guarantee that slices will be drawn + * in order. + * The function is also used by hardware acceleration APIs. + * It is called at least once during frame decoding to pass + * the data needed for hardware render. + * In that mode instead of pixel data, AVFrame points to + * a structure specific to the acceleration API. The application + * reads the structure and can change some fields to indicate progress + * or mark state. + * - encoding: unused + * - decoding: Set by user. + * @param height the height of the slice + * @param y the y position of the slice + * @param type 1->top field, 2->bottom field, 3->frame + * @param offset offset into the AVFrame.data from which the slice should be read + */ + void (*draw_horiz_band)(struct AVCodecContext *s, + const AVFrame *src, int offset[AV_NUM_DATA_POINTERS], + int y, int type, int height); + + /** + * callback to negotiate the pixelFormat + * @param fmt is the list of formats which are supported by the codec, + * it is terminated by -1 as 0 is a valid format, the formats are ordered by quality. + * The first is always the native one. + * @note The callback may be called again immediately if initialization for + * the selected (hardware-accelerated) pixel format failed. + * @warning Behavior is undefined if the callback returns a value not + * in the fmt list of formats. + * @return the chosen format + * - encoding: unused + * - decoding: Set by user, if not set the native format will be chosen. + */ + enum AVPixelFormat (*get_format)(struct AVCodecContext *s, const enum AVPixelFormat * fmt); + + /** + * maximum number of B-frames between non-B-frames + * Note: The output will be delayed by max_b_frames+1 relative to the input. + * - encoding: Set by user. + * - decoding: unused + */ + int max_b_frames; + + /** + * qscale factor between IP and B-frames + * If > 0 then the last P-frame quantizer will be used (q= lastp_q*factor+offset). + * If < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset). + * - encoding: Set by user. + * - decoding: unused + */ + float b_quant_factor; + +#if FF_API_RC_STRATEGY + /** @deprecated use codec private option instead */ + attribute_deprecated int rc_strategy; +#define FF_RC_STRATEGY_XVID 1 +#endif + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int b_frame_strategy; +#endif + + /** + * qscale offset between IP and B-frames + * - encoding: Set by user. + * - decoding: unused + */ + float b_quant_offset; + + /** + * Size of the frame reordering buffer in the decoder. + * For MPEG-2 it is 1 IPB or 0 low delay IP. + * - encoding: Set by libavcodec. + * - decoding: Set by libavcodec. + */ + int has_b_frames; + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int mpeg_quant; +#endif + + /** + * qscale factor between P- and I-frames + * If > 0 then the last P-frame quantizer will be used (q = lastp_q * factor + offset). + * If < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset). + * - encoding: Set by user. + * - decoding: unused + */ + float i_quant_factor; + + /** + * qscale offset between P and I-frames + * - encoding: Set by user. + * - decoding: unused + */ + float i_quant_offset; + + /** + * luminance masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float lumi_masking; + + /** + * temporary complexity masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float temporal_cplx_masking; + + /** + * spatial complexity masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float spatial_cplx_masking; + + /** + * p block masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float p_masking; + + /** + * darkness masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float dark_masking; + + /** + * slice count + * - encoding: Set by libavcodec. + * - decoding: Set by user (or 0). + */ + int slice_count; + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int prediction_method; +#define FF_PRED_LEFT 0 +#define FF_PRED_PLANE 1 +#define FF_PRED_MEDIAN 2 +#endif + + /** + * slice offsets in the frame in bytes + * - encoding: Set/allocated by libavcodec. + * - decoding: Set/allocated by user (or NULL). + */ + int *slice_offset; + + /** + * sample aspect ratio (0 if unknown) + * That is the width of a pixel divided by the height of the pixel. + * Numerator and denominator must be relatively prime and smaller than 256 for some video standards. + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + AVRational sample_aspect_ratio; + + /** + * motion estimation comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int me_cmp; + /** + * subpixel motion estimation comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int me_sub_cmp; + /** + * macroblock comparison function (not supported yet) + * - encoding: Set by user. + * - decoding: unused + */ + int mb_cmp; + /** + * interlaced DCT comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int ildct_cmp; +#define FF_CMP_SAD 0 +#define FF_CMP_SSE 1 +#define FF_CMP_SATD 2 +#define FF_CMP_DCT 3 +#define FF_CMP_PSNR 4 +#define FF_CMP_BIT 5 +#define FF_CMP_RD 6 +#define FF_CMP_ZERO 7 +#define FF_CMP_VSAD 8 +#define FF_CMP_VSSE 9 +#define FF_CMP_NSSE 10 +#define FF_CMP_W53 11 +#define FF_CMP_W97 12 +#define FF_CMP_DCTMAX 13 +#define FF_CMP_DCT264 14 +#define FF_CMP_MEDIAN_SAD 15 +#define FF_CMP_CHROMA 256 + + /** + * ME diamond size & shape + * - encoding: Set by user. + * - decoding: unused + */ + int dia_size; + + /** + * amount of previous MV predictors (2a+1 x 2a+1 square) + * - encoding: Set by user. + * - decoding: unused + */ + int last_predictor_count; + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int pre_me; +#endif + + /** + * motion estimation prepass comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int me_pre_cmp; + + /** + * ME prepass diamond size & shape + * - encoding: Set by user. + * - decoding: unused + */ + int pre_dia_size; + + /** + * subpel ME quality + * - encoding: Set by user. + * - decoding: unused + */ + int me_subpel_quality; + +#if FF_API_AFD + /** + * DTG active format information (additional aspect ratio + * information only used in DVB MPEG-2 transport streams) + * 0 if not set. + * + * - encoding: unused + * - decoding: Set by decoder. + * @deprecated Deprecated in favor of AVSideData + */ + attribute_deprecated int dtg_active_format; +#define FF_DTG_AFD_SAME 8 +#define FF_DTG_AFD_4_3 9 +#define FF_DTG_AFD_16_9 10 +#define FF_DTG_AFD_14_9 11 +#define FF_DTG_AFD_4_3_SP_14_9 13 +#define FF_DTG_AFD_16_9_SP_14_9 14 +#define FF_DTG_AFD_SP_4_3 15 +#endif /* FF_API_AFD */ + + /** + * maximum motion estimation search range in subpel units + * If 0 then no limit. + * + * - encoding: Set by user. + * - decoding: unused + */ + int me_range; + +#if FF_API_QUANT_BIAS + /** + * @deprecated use encoder private option instead + */ + attribute_deprecated int intra_quant_bias; +#define FF_DEFAULT_QUANT_BIAS 999999 + + /** + * @deprecated use encoder private option instead + */ + attribute_deprecated int inter_quant_bias; +#endif + + /** + * slice flags + * - encoding: unused + * - decoding: Set by user. + */ + int slice_flags; +#define SLICE_FLAG_CODED_ORDER 0x0001 ///< draw_horiz_band() is called in coded order instead of display +#define SLICE_FLAG_ALLOW_FIELD 0x0002 ///< allow draw_horiz_band() with field slices (MPEG-2 field pics) +#define SLICE_FLAG_ALLOW_PLANE 0x0004 ///< allow draw_horiz_band() with 1 component at a time (SVQ1) + +#if FF_API_XVMC + /** + * XVideo Motion Acceleration + * - encoding: forbidden + * - decoding: set by decoder + * @deprecated XvMC doesn't need it anymore. + */ + attribute_deprecated int xvmc_acceleration; +#endif /* FF_API_XVMC */ + + /** + * macroblock decision mode + * - encoding: Set by user. + * - decoding: unused + */ + int mb_decision; +#define FF_MB_DECISION_SIMPLE 0 ///< uses mb_cmp +#define FF_MB_DECISION_BITS 1 ///< chooses the one which needs the fewest bits +#define FF_MB_DECISION_RD 2 ///< rate distortion + + /** + * custom intra quantization matrix + * - encoding: Set by user, can be NULL. + * - decoding: Set by libavcodec. + */ + uint16_t *intra_matrix; + + /** + * custom inter quantization matrix + * - encoding: Set by user, can be NULL. + * - decoding: Set by libavcodec. + */ + uint16_t *inter_matrix; + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int scenechange_threshold; + + /** @deprecated use encoder private options instead */ + attribute_deprecated + int noise_reduction; +#endif + +#if FF_API_MPV_OPT + /** + * @deprecated this field is unused + */ + attribute_deprecated + int me_threshold; + + /** + * @deprecated this field is unused + */ + attribute_deprecated + int mb_threshold; +#endif + + /** + * precision of the intra DC coefficient - 8 + * - encoding: Set by user. + * - decoding: Set by libavcodec + */ + int intra_dc_precision; + + /** + * Number of macroblock rows at the top which are skipped. + * - encoding: unused + * - decoding: Set by user. + */ + int skip_top; + + /** + * Number of macroblock rows at the bottom which are skipped. + * - encoding: unused + * - decoding: Set by user. + */ + int skip_bottom; + +#if FF_API_MPV_OPT + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + float border_masking; +#endif + + /** + * minimum MB Lagrange multiplier + * - encoding: Set by user. + * - decoding: unused + */ + int mb_lmin; + + /** + * maximum MB Lagrange multiplier + * - encoding: Set by user. + * - decoding: unused + */ + int mb_lmax; + +#if FF_API_PRIVATE_OPT + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + int me_penalty_compensation; +#endif + + /** + * - encoding: Set by user. + * - decoding: unused + */ + int bidir_refine; + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int brd_scale; +#endif + + /** + * minimum GOP size + * - encoding: Set by user. + * - decoding: unused + */ + int keyint_min; + + /** + * number of reference frames + * - encoding: Set by user. + * - decoding: Set by lavc. + */ + int refs; + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int chromaoffset; +#endif + +#if FF_API_UNUSED_MEMBERS + /** + * Multiplied by qscale for each frame and added to scene_change_score. + * - encoding: Set by user. + * - decoding: unused + */ + attribute_deprecated int scenechange_factor; +#endif + + /** + * Note: Value depends upon the compare function used for fullpel ME. + * - encoding: Set by user. + * - decoding: unused + */ + int mv0_threshold; + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int b_sensitivity; +#endif + + /** + * Chromaticity coordinates of the source primaries. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorPrimaries color_primaries; + + /** + * Color Transfer Characteristic. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorTransferCharacteristic color_trc; + + /** + * YUV colorspace type. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorSpace colorspace; + + /** + * MPEG vs JPEG YUV range. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorRange color_range; + + /** + * This defines the location of chroma samples. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVChromaLocation chroma_sample_location; + + /** + * Number of slices. + * Indicates number of picture subdivisions. Used for parallelized + * decoding. + * - encoding: Set by user + * - decoding: unused + */ + int slices; + + /** Field order + * - encoding: set by libavcodec + * - decoding: Set by user. + */ + enum AVFieldOrder field_order; + + /* audio only */ + int sample_rate; ///< samples per second + int channels; ///< number of audio channels + + /** + * audio sample format + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + enum AVSampleFormat sample_fmt; ///< sample format + + /* The following data should not be initialized. */ + /** + * Number of samples per channel in an audio frame. + * + * - encoding: set by libavcodec in avcodec_open2(). Each submitted frame + * except the last must contain exactly frame_size samples per channel. + * May be 0 when the codec has AV_CODEC_CAP_VARIABLE_FRAME_SIZE set, then the + * frame size is not restricted. + * - decoding: may be set by some decoders to indicate constant frame size + */ + int frame_size; + + /** + * Frame counter, set by libavcodec. + * + * - decoding: total number of frames returned from the decoder so far. + * - encoding: total number of frames passed to the encoder so far. + * + * @note the counter is not incremented if encoding/decoding resulted in + * an error. + */ + int frame_number; + + /** + * number of bytes per packet if constant and known or 0 + * Used by some WAV based audio codecs. + */ + int block_align; + + /** + * Audio cutoff bandwidth (0 means "automatic") + * - encoding: Set by user. + * - decoding: unused + */ + int cutoff; + + /** + * Audio channel layout. + * - encoding: set by user. + * - decoding: set by user, may be overwritten by libavcodec. + */ + uint64_t channel_layout; + + /** + * Request decoder to use this channel layout if it can (0 for default) + * - encoding: unused + * - decoding: Set by user. + */ + uint64_t request_channel_layout; + + /** + * Type of service that the audio stream conveys. + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + enum AVAudioServiceType audio_service_type; + + /** + * desired sample format + * - encoding: Not used. + * - decoding: Set by user. + * Decoder will decode to this format if it can. + */ + enum AVSampleFormat request_sample_fmt; + + /** + * This callback is called at the beginning of each frame to get data + * buffer(s) for it. There may be one contiguous buffer for all the data or + * there may be a buffer per each data plane or anything in between. What + * this means is, you may set however many entries in buf[] you feel necessary. + * Each buffer must be reference-counted using the AVBuffer API (see description + * of buf[] below). + * + * The following fields will be set in the frame before this callback is + * called: + * - format + * - width, height (video only) + * - sample_rate, channel_layout, nb_samples (audio only) + * Their values may differ from the corresponding values in + * AVCodecContext. This callback must use the frame values, not the codec + * context values, to calculate the required buffer size. + * + * This callback must fill the following fields in the frame: + * - data[] + * - linesize[] + * - extended_data: + * * if the data is planar audio with more than 8 channels, then this + * callback must allocate and fill extended_data to contain all pointers + * to all data planes. data[] must hold as many pointers as it can. + * extended_data must be allocated with av_malloc() and will be freed in + * av_frame_unref(). + * * otherwise extended_data must point to data + * - buf[] must contain one or more pointers to AVBufferRef structures. Each of + * the frame's data and extended_data pointers must be contained in these. That + * is, one AVBufferRef for each allocated chunk of memory, not necessarily one + * AVBufferRef per data[] entry. See: av_buffer_create(), av_buffer_alloc(), + * and av_buffer_ref(). + * - extended_buf and nb_extended_buf must be allocated with av_malloc() by + * this callback and filled with the extra buffers if there are more + * buffers than buf[] can hold. extended_buf will be freed in + * av_frame_unref(). + * + * If AV_CODEC_CAP_DR1 is not set then get_buffer2() must call + * avcodec_default_get_buffer2() instead of providing buffers allocated by + * some other means. + * + * Each data plane must be aligned to the maximum required by the target + * CPU. + * + * @see avcodec_default_get_buffer2() + * + * Video: + * + * If AV_GET_BUFFER_FLAG_REF is set in flags then the frame may be reused + * (read and/or written to if it is writable) later by libavcodec. + * + * avcodec_align_dimensions2() should be used to find the required width and + * height, as they normally need to be rounded up to the next multiple of 16. + * + * Some decoders do not support linesizes changing between frames. + * + * If frame multithreading is used and thread_safe_callbacks is set, + * this callback may be called from a different thread, but not from more + * than one at once. Does not need to be reentrant. + * + * @see avcodec_align_dimensions2() + * + * Audio: + * + * Decoders request a buffer of a particular size by setting + * AVFrame.nb_samples prior to calling get_buffer2(). The decoder may, + * however, utilize only part of the buffer by setting AVFrame.nb_samples + * to a smaller value in the output frame. + * + * As a convenience, av_samples_get_buffer_size() and + * av_samples_fill_arrays() in libavutil may be used by custom get_buffer2() + * functions to find the required data size and to fill data pointers and + * linesize. In AVFrame.linesize, only linesize[0] may be set for audio + * since all planes must be the same size. + * + * @see av_samples_get_buffer_size(), av_samples_fill_arrays() + * + * - encoding: unused + * - decoding: Set by libavcodec, user can override. + */ + int (*get_buffer2)(struct AVCodecContext *s, AVFrame *frame, int flags); + + /** + * If non-zero, the decoded audio and video frames returned from + * avcodec_decode_video2() and avcodec_decode_audio4() are reference-counted + * and are valid indefinitely. The caller must free them with + * av_frame_unref() when they are not needed anymore. + * Otherwise, the decoded frames must not be freed by the caller and are + * only valid until the next decode call. + * + * This is always automatically enabled if avcodec_receive_frame() is used. + * + * - encoding: unused + * - decoding: set by the caller before avcodec_open2(). + */ + int refcounted_frames; + + /* - encoding parameters */ + float qcompress; ///< amount of qscale change between easy & hard scenes (0.0-1.0) + float qblur; ///< amount of qscale smoothing over time (0.0-1.0) + + /** + * minimum quantizer + * - encoding: Set by user. + * - decoding: unused + */ + int qmin; + + /** + * maximum quantizer + * - encoding: Set by user. + * - decoding: unused + */ + int qmax; + + /** + * maximum quantizer difference between frames + * - encoding: Set by user. + * - decoding: unused + */ + int max_qdiff; + +#if FF_API_MPV_OPT + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + float rc_qsquish; + + attribute_deprecated + float rc_qmod_amp; + attribute_deprecated + int rc_qmod_freq; +#endif + + /** + * decoder bitstream buffer size + * - encoding: Set by user. + * - decoding: unused + */ + int rc_buffer_size; + + /** + * ratecontrol override, see RcOverride + * - encoding: Allocated/set/freed by user. + * - decoding: unused + */ + int rc_override_count; + RcOverride *rc_override; + +#if FF_API_MPV_OPT + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + const char *rc_eq; +#endif + + /** + * maximum bitrate + * - encoding: Set by user. + * - decoding: Set by user, may be overwritten by libavcodec. + */ + int64_t rc_max_rate; + + /** + * minimum bitrate + * - encoding: Set by user. + * - decoding: unused + */ + int64_t rc_min_rate; + +#if FF_API_MPV_OPT + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + float rc_buffer_aggressivity; + + attribute_deprecated + float rc_initial_cplx; +#endif + + /** + * Ratecontrol attempt to use, at maximum, of what can be used without an underflow. + * - encoding: Set by user. + * - decoding: unused. + */ + float rc_max_available_vbv_use; + + /** + * Ratecontrol attempt to use, at least, times the amount needed to prevent a vbv overflow. + * - encoding: Set by user. + * - decoding: unused. + */ + float rc_min_vbv_overflow_use; + + /** + * Number of bits which should be loaded into the rc buffer before decoding starts. + * - encoding: Set by user. + * - decoding: unused + */ + int rc_initial_buffer_occupancy; + +#if FF_API_CODER_TYPE +#define FF_CODER_TYPE_VLC 0 +#define FF_CODER_TYPE_AC 1 +#define FF_CODER_TYPE_RAW 2 +#define FF_CODER_TYPE_RLE 3 +#if FF_API_UNUSED_MEMBERS +#define FF_CODER_TYPE_DEFLATE 4 +#endif /* FF_API_UNUSED_MEMBERS */ + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + int coder_type; +#endif /* FF_API_CODER_TYPE */ + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int context_model; +#endif + +#if FF_API_MPV_OPT + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + int lmin; + + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + int lmax; +#endif + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int frame_skip_threshold; + + /** @deprecated use encoder private options instead */ + attribute_deprecated + int frame_skip_factor; + + /** @deprecated use encoder private options instead */ + attribute_deprecated + int frame_skip_exp; + + /** @deprecated use encoder private options instead */ + attribute_deprecated + int frame_skip_cmp; +#endif /* FF_API_PRIVATE_OPT */ + + /** + * trellis RD quantization + * - encoding: Set by user. + * - decoding: unused + */ + int trellis; + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int min_prediction_order; + + /** @deprecated use encoder private options instead */ + attribute_deprecated + int max_prediction_order; + + /** @deprecated use encoder private options instead */ + attribute_deprecated + int64_t timecode_frame_start; +#endif + +#if FF_API_RTP_CALLBACK + /** + * @deprecated unused + */ + /* The RTP callback: This function is called */ + /* every time the encoder has a packet to send. */ + /* It depends on the encoder if the data starts */ + /* with a Start Code (it should). H.263 does. */ + /* mb_nb contains the number of macroblocks */ + /* encoded in the RTP payload. */ + attribute_deprecated + void (*rtp_callback)(struct AVCodecContext *avctx, void *data, int size, int mb_nb); +#endif + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int rtp_payload_size; /* The size of the RTP payload: the coder will */ + /* do its best to deliver a chunk with size */ + /* below rtp_payload_size, the chunk will start */ + /* with a start code on some codecs like H.263. */ + /* This doesn't take account of any particular */ + /* headers inside the transmitted RTP payload. */ +#endif + +#if FF_API_STAT_BITS + /* statistics, used for 2-pass encoding */ + attribute_deprecated + int mv_bits; + attribute_deprecated + int header_bits; + attribute_deprecated + int i_tex_bits; + attribute_deprecated + int p_tex_bits; + attribute_deprecated + int i_count; + attribute_deprecated + int p_count; + attribute_deprecated + int skip_count; + attribute_deprecated + int misc_bits; + + /** @deprecated this field is unused */ + attribute_deprecated + int frame_bits; +#endif + + /** + * pass1 encoding statistics output buffer + * - encoding: Set by libavcodec. + * - decoding: unused + */ + char *stats_out; + + /** + * pass2 encoding statistics input buffer + * Concatenated stuff from stats_out of pass1 should be placed here. + * - encoding: Allocated/set/freed by user. + * - decoding: unused + */ + char *stats_in; + + /** + * Work around bugs in encoders which sometimes cannot be detected automatically. + * - encoding: Set by user + * - decoding: Set by user + */ + int workaround_bugs; +#define FF_BUG_AUTODETECT 1 ///< autodetection +#if FF_API_OLD_MSMPEG4 +#define FF_BUG_OLD_MSMPEG4 2 +#endif +#define FF_BUG_XVID_ILACE 4 +#define FF_BUG_UMP4 8 +#define FF_BUG_NO_PADDING 16 +#define FF_BUG_AMV 32 +#if FF_API_AC_VLC +#define FF_BUG_AC_VLC 0 ///< Will be removed, libavcodec can now handle these non-compliant files by default. +#endif +#define FF_BUG_QPEL_CHROMA 64 +#define FF_BUG_STD_QPEL 128 +#define FF_BUG_QPEL_CHROMA2 256 +#define FF_BUG_DIRECT_BLOCKSIZE 512 +#define FF_BUG_EDGE 1024 +#define FF_BUG_HPEL_CHROMA 2048 +#define FF_BUG_DC_CLIP 4096 +#define FF_BUG_MS 8192 ///< Work around various bugs in Microsoft's broken decoders. +#define FF_BUG_TRUNCATED 16384 +#define FF_BUG_IEDGE 32768 + + /** + * strictly follow the standard (MPEG-4, ...). + * - encoding: Set by user. + * - decoding: Set by user. + * Setting this to STRICT or higher means the encoder and decoder will + * generally do stupid things, whereas setting it to unofficial or lower + * will mean the encoder might produce output that is not supported by all + * spec-compliant decoders. Decoders don't differentiate between normal, + * unofficial and experimental (that is, they always try to decode things + * when they can) unless they are explicitly asked to behave stupidly + * (=strictly conform to the specs) + */ + int strict_std_compliance; +#define FF_COMPLIANCE_VERY_STRICT 2 ///< Strictly conform to an older more strict version of the spec or reference software. +#define FF_COMPLIANCE_STRICT 1 ///< Strictly conform to all the things in the spec no matter what consequences. +#define FF_COMPLIANCE_NORMAL 0 +#define FF_COMPLIANCE_UNOFFICIAL -1 ///< Allow unofficial extensions +#define FF_COMPLIANCE_EXPERIMENTAL -2 ///< Allow nonstandardized experimental things. + + /** + * error concealment flags + * - encoding: unused + * - decoding: Set by user. + */ + int error_concealment; +#define FF_EC_GUESS_MVS 1 +#define FF_EC_DEBLOCK 2 +#define FF_EC_FAVOR_INTER 256 + + /** + * debug + * - encoding: Set by user. + * - decoding: Set by user. + */ + int debug; +#define FF_DEBUG_PICT_INFO 1 +#define FF_DEBUG_RC 2 +#define FF_DEBUG_BITSTREAM 4 +#define FF_DEBUG_MB_TYPE 8 +#define FF_DEBUG_QP 16 +#if FF_API_DEBUG_MV +/** + * @deprecated this option does nothing + */ +#define FF_DEBUG_MV 32 +#endif +#define FF_DEBUG_DCT_COEFF 0x00000040 +#define FF_DEBUG_SKIP 0x00000080 +#define FF_DEBUG_STARTCODE 0x00000100 +#if FF_API_UNUSED_MEMBERS +#define FF_DEBUG_PTS 0x00000200 +#endif /* FF_API_UNUSED_MEMBERS */ +#define FF_DEBUG_ER 0x00000400 +#define FF_DEBUG_MMCO 0x00000800 +#define FF_DEBUG_BUGS 0x00001000 +#if FF_API_DEBUG_MV +#define FF_DEBUG_VIS_QP 0x00002000 +#define FF_DEBUG_VIS_MB_TYPE 0x00004000 +#endif +#define FF_DEBUG_BUFFERS 0x00008000 +#define FF_DEBUG_THREADS 0x00010000 +#define FF_DEBUG_GREEN_MD 0x00800000 +#define FF_DEBUG_NOMC 0x01000000 + +#if FF_API_DEBUG_MV + /** + * debug + * - encoding: Set by user. + * - decoding: Set by user. + */ + int debug_mv; +#define FF_DEBUG_VIS_MV_P_FOR 0x00000001 // visualize forward predicted MVs of P-frames +#define FF_DEBUG_VIS_MV_B_FOR 0x00000002 // visualize forward predicted MVs of B-frames +#define FF_DEBUG_VIS_MV_B_BACK 0x00000004 // visualize backward predicted MVs of B-frames +#endif + + /** + * Error recognition; may misdetect some more or less valid parts as errors. + * - encoding: unused + * - decoding: Set by user. + */ + int err_recognition; + +/** + * Verify checksums embedded in the bitstream (could be of either encoded or + * decoded data, depending on the codec) and print an error message on mismatch. + * If AV_EF_EXPLODE is also set, a mismatching checksum will result in the + * decoder returning an error. + */ +#define AV_EF_CRCCHECK (1<<0) +#define AV_EF_BITSTREAM (1<<1) ///< detect bitstream specification deviations +#define AV_EF_BUFFER (1<<2) ///< detect improper bitstream length +#define AV_EF_EXPLODE (1<<3) ///< abort decoding on minor error detection + +#define AV_EF_IGNORE_ERR (1<<15) ///< ignore errors and continue +#define AV_EF_CAREFUL (1<<16) ///< consider things that violate the spec, are fast to calculate and have not been seen in the wild as errors +#define AV_EF_COMPLIANT (1<<17) ///< consider all spec non compliances as errors +#define AV_EF_AGGRESSIVE (1<<18) ///< consider things that a sane encoder should not do as an error + + + /** + * opaque 64-bit number (generally a PTS) that will be reordered and + * output in AVFrame.reordered_opaque + * - encoding: unused + * - decoding: Set by user. + */ + int64_t reordered_opaque; + + /** + * Hardware accelerator in use + * - encoding: unused. + * - decoding: Set by libavcodec + */ + struct AVHWAccel *hwaccel; + + /** + * Hardware accelerator context. + * For some hardware accelerators, a global context needs to be + * provided by the user. In that case, this holds display-dependent + * data FFmpeg cannot instantiate itself. Please refer to the + * FFmpeg HW accelerator documentation to know how to fill this + * is. e.g. for VA API, this is a struct vaapi_context. + * - encoding: unused + * - decoding: Set by user + */ + void *hwaccel_context; + + /** + * error + * - encoding: Set by libavcodec if flags & AV_CODEC_FLAG_PSNR. + * - decoding: unused + */ + uint64_t error[AV_NUM_DATA_POINTERS]; + + /** + * DCT algorithm, see FF_DCT_* below + * - encoding: Set by user. + * - decoding: unused + */ + int dct_algo; +#define FF_DCT_AUTO 0 +#define FF_DCT_FASTINT 1 +#define FF_DCT_INT 2 +#define FF_DCT_MMX 3 +#define FF_DCT_ALTIVEC 5 +#define FF_DCT_FAAN 6 + + /** + * IDCT algorithm, see FF_IDCT_* below. + * - encoding: Set by user. + * - decoding: Set by user. + */ + int idct_algo; +#define FF_IDCT_AUTO 0 +#define FF_IDCT_INT 1 +#define FF_IDCT_SIMPLE 2 +#define FF_IDCT_SIMPLEMMX 3 +#define FF_IDCT_ARM 7 +#define FF_IDCT_ALTIVEC 8 +#if FF_API_ARCH_SH4 +#define FF_IDCT_SH4 9 +#endif +#define FF_IDCT_SIMPLEARM 10 +#if FF_API_UNUSED_MEMBERS +#define FF_IDCT_IPP 13 +#endif /* FF_API_UNUSED_MEMBERS */ +#define FF_IDCT_XVID 14 +#if FF_API_IDCT_XVIDMMX +#define FF_IDCT_XVIDMMX 14 +#endif /* FF_API_IDCT_XVIDMMX */ +#define FF_IDCT_SIMPLEARMV5TE 16 +#define FF_IDCT_SIMPLEARMV6 17 +#if FF_API_ARCH_SPARC +#define FF_IDCT_SIMPLEVIS 18 +#endif +#define FF_IDCT_FAAN 20 +#define FF_IDCT_SIMPLENEON 22 +#if FF_API_ARCH_ALPHA +#define FF_IDCT_SIMPLEALPHA 23 +#endif +#define FF_IDCT_SIMPLEAUTO 128 + + /** + * bits per sample/pixel from the demuxer (needed for huffyuv). + * - encoding: Set by libavcodec. + * - decoding: Set by user. + */ + int bits_per_coded_sample; + + /** + * Bits per sample/pixel of internal libavcodec pixel/sample format. + * - encoding: set by user. + * - decoding: set by libavcodec. + */ + int bits_per_raw_sample; + +#if FF_API_LOWRES + /** + * low resolution decoding, 1-> 1/2 size, 2->1/4 size + * - encoding: unused + * - decoding: Set by user. + */ + int lowres; +#endif + +#if FF_API_CODED_FRAME + /** + * the picture in the bitstream + * - encoding: Set by libavcodec. + * - decoding: unused + * + * @deprecated use the quality factor packet side data instead + */ + attribute_deprecated AVFrame *coded_frame; +#endif + + /** + * thread count + * is used to decide how many independent tasks should be passed to execute() + * - encoding: Set by user. + * - decoding: Set by user. + */ + int thread_count; + + /** + * Which multithreading methods to use. + * Use of FF_THREAD_FRAME will increase decoding delay by one frame per thread, + * so clients which cannot provide future frames should not use it. + * + * - encoding: Set by user, otherwise the default is used. + * - decoding: Set by user, otherwise the default is used. + */ + int thread_type; +#define FF_THREAD_FRAME 1 ///< Decode more than one frame at once +#define FF_THREAD_SLICE 2 ///< Decode more than one part of a single frame at once + + /** + * Which multithreading methods are in use by the codec. + * - encoding: Set by libavcodec. + * - decoding: Set by libavcodec. + */ + int active_thread_type; + + /** + * Set by the client if its custom get_buffer() callback can be called + * synchronously from another thread, which allows faster multithreaded decoding. + * draw_horiz_band() will be called from other threads regardless of this setting. + * Ignored if the default get_buffer() is used. + * - encoding: Set by user. + * - decoding: Set by user. + */ + int thread_safe_callbacks; + + /** + * The codec may call this to execute several independent things. + * It will return only after finishing all tasks. + * The user may replace this with some multithreaded implementation, + * the default implementation will execute the parts serially. + * @param count the number of things to execute + * - encoding: Set by libavcodec, user can override. + * - decoding: Set by libavcodec, user can override. + */ + int (*execute)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg), void *arg2, int *ret, int count, int size); + + /** + * The codec may call this to execute several independent things. + * It will return only after finishing all tasks. + * The user may replace this with some multithreaded implementation, + * the default implementation will execute the parts serially. + * Also see avcodec_thread_init and e.g. the --enable-pthread configure option. + * @param c context passed also to func + * @param count the number of things to execute + * @param arg2 argument passed unchanged to func + * @param ret return values of executed functions, must have space for "count" values. May be NULL. + * @param func function that will be called count times, with jobnr from 0 to count-1. + * threadnr will be in the range 0 to c->thread_count-1 < MAX_THREADS and so that no + * two instances of func executing at the same time will have the same threadnr. + * @return always 0 currently, but code should handle a future improvement where when any call to func + * returns < 0 no further calls to func may be done and < 0 is returned. + * - encoding: Set by libavcodec, user can override. + * - decoding: Set by libavcodec, user can override. + */ + int (*execute2)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg, int jobnr, int threadnr), void *arg2, int *ret, int count); + + /** + * noise vs. sse weight for the nsse comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int nsse_weight; + + /** + * profile + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int profile; +#define FF_PROFILE_UNKNOWN -99 +#define FF_PROFILE_RESERVED -100 + +#define FF_PROFILE_AAC_MAIN 0 +#define FF_PROFILE_AAC_LOW 1 +#define FF_PROFILE_AAC_SSR 2 +#define FF_PROFILE_AAC_LTP 3 +#define FF_PROFILE_AAC_HE 4 +#define FF_PROFILE_AAC_HE_V2 28 +#define FF_PROFILE_AAC_LD 22 +#define FF_PROFILE_AAC_ELD 38 +#define FF_PROFILE_MPEG2_AAC_LOW 128 +#define FF_PROFILE_MPEG2_AAC_HE 131 + +#define FF_PROFILE_DNXHD 0 +#define FF_PROFILE_DNXHR_LB 1 +#define FF_PROFILE_DNXHR_SQ 2 +#define FF_PROFILE_DNXHR_HQ 3 +#define FF_PROFILE_DNXHR_HQX 4 +#define FF_PROFILE_DNXHR_444 5 + +#define FF_PROFILE_DTS 20 +#define FF_PROFILE_DTS_ES 30 +#define FF_PROFILE_DTS_96_24 40 +#define FF_PROFILE_DTS_HD_HRA 50 +#define FF_PROFILE_DTS_HD_MA 60 +#define FF_PROFILE_DTS_EXPRESS 70 + +#define FF_PROFILE_MPEG2_422 0 +#define FF_PROFILE_MPEG2_HIGH 1 +#define FF_PROFILE_MPEG2_SS 2 +#define FF_PROFILE_MPEG2_SNR_SCALABLE 3 +#define FF_PROFILE_MPEG2_MAIN 4 +#define FF_PROFILE_MPEG2_SIMPLE 5 + +#define FF_PROFILE_H264_CONSTRAINED (1<<9) // 8+1; constraint_set1_flag +#define FF_PROFILE_H264_INTRA (1<<11) // 8+3; constraint_set3_flag + +#define FF_PROFILE_H264_BASELINE 66 +#define FF_PROFILE_H264_CONSTRAINED_BASELINE (66|FF_PROFILE_H264_CONSTRAINED) +#define FF_PROFILE_H264_MAIN 77 +#define FF_PROFILE_H264_EXTENDED 88 +#define FF_PROFILE_H264_HIGH 100 +#define FF_PROFILE_H264_HIGH_10 110 +#define FF_PROFILE_H264_HIGH_10_INTRA (110|FF_PROFILE_H264_INTRA) +#define FF_PROFILE_H264_MULTIVIEW_HIGH 118 +#define FF_PROFILE_H264_HIGH_422 122 +#define FF_PROFILE_H264_HIGH_422_INTRA (122|FF_PROFILE_H264_INTRA) +#define FF_PROFILE_H264_STEREO_HIGH 128 +#define FF_PROFILE_H264_HIGH_444 144 +#define FF_PROFILE_H264_HIGH_444_PREDICTIVE 244 +#define FF_PROFILE_H264_HIGH_444_INTRA (244|FF_PROFILE_H264_INTRA) +#define FF_PROFILE_H264_CAVLC_444 44 + +#define FF_PROFILE_VC1_SIMPLE 0 +#define FF_PROFILE_VC1_MAIN 1 +#define FF_PROFILE_VC1_COMPLEX 2 +#define FF_PROFILE_VC1_ADVANCED 3 + +#define FF_PROFILE_MPEG4_SIMPLE 0 +#define FF_PROFILE_MPEG4_SIMPLE_SCALABLE 1 +#define FF_PROFILE_MPEG4_CORE 2 +#define FF_PROFILE_MPEG4_MAIN 3 +#define FF_PROFILE_MPEG4_N_BIT 4 +#define FF_PROFILE_MPEG4_SCALABLE_TEXTURE 5 +#define FF_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION 6 +#define FF_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE 7 +#define FF_PROFILE_MPEG4_HYBRID 8 +#define FF_PROFILE_MPEG4_ADVANCED_REAL_TIME 9 +#define FF_PROFILE_MPEG4_CORE_SCALABLE 10 +#define FF_PROFILE_MPEG4_ADVANCED_CODING 11 +#define FF_PROFILE_MPEG4_ADVANCED_CORE 12 +#define FF_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE 13 +#define FF_PROFILE_MPEG4_SIMPLE_STUDIO 14 +#define FF_PROFILE_MPEG4_ADVANCED_SIMPLE 15 + +#define FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_0 1 +#define FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_1 2 +#define FF_PROFILE_JPEG2000_CSTREAM_NO_RESTRICTION 32768 +#define FF_PROFILE_JPEG2000_DCINEMA_2K 3 +#define FF_PROFILE_JPEG2000_DCINEMA_4K 4 + +#define FF_PROFILE_VP9_0 0 +#define FF_PROFILE_VP9_1 1 +#define FF_PROFILE_VP9_2 2 +#define FF_PROFILE_VP9_3 3 + +#define FF_PROFILE_HEVC_MAIN 1 +#define FF_PROFILE_HEVC_MAIN_10 2 +#define FF_PROFILE_HEVC_MAIN_STILL_PICTURE 3 +#define FF_PROFILE_HEVC_REXT 4 + + /** + * level + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int level; +#define FF_LEVEL_UNKNOWN -99 + + /** + * Skip loop filtering for selected frames. + * - encoding: unused + * - decoding: Set by user. + */ + enum AVDiscard skip_loop_filter; + + /** + * Skip IDCT/dequantization for selected frames. + * - encoding: unused + * - decoding: Set by user. + */ + enum AVDiscard skip_idct; + + /** + * Skip decoding for selected frames. + * - encoding: unused + * - decoding: Set by user. + */ + enum AVDiscard skip_frame; + + /** + * Header containing style information for text subtitles. + * For SUBTITLE_ASS subtitle type, it should contain the whole ASS + * [Script Info] and [V4+ Styles] section, plus the [Events] line and + * the Format line following. It shouldn't include any Dialogue line. + * - encoding: Set/allocated/freed by user (before avcodec_open2()) + * - decoding: Set/allocated/freed by libavcodec (by avcodec_open2()) + */ + uint8_t *subtitle_header; + int subtitle_header_size; + +#if FF_API_ERROR_RATE + /** + * @deprecated use the 'error_rate' private AVOption of the mpegvideo + * encoders + */ + attribute_deprecated + int error_rate; +#endif + +#if FF_API_VBV_DELAY + /** + * VBV delay coded in the last frame (in periods of a 27 MHz clock). + * Used for compliant TS muxing. + * - encoding: Set by libavcodec. + * - decoding: unused. + * @deprecated this value is now exported as a part of + * AV_PKT_DATA_CPB_PROPERTIES packet side data + */ + attribute_deprecated + uint64_t vbv_delay; +#endif + +#if FF_API_SIDEDATA_ONLY_PKT + /** + * Encoding only and set by default. Allow encoders to output packets + * that do not contain any encoded data, only side data. + * + * Some encoders need to output such packets, e.g. to update some stream + * parameters at the end of encoding. + * + * @deprecated this field disables the default behaviour and + * it is kept only for compatibility. + */ + attribute_deprecated + int side_data_only_packets; +#endif + + /** + * Audio only. The number of "priming" samples (padding) inserted by the + * encoder at the beginning of the audio. I.e. this number of leading + * decoded samples must be discarded by the caller to get the original audio + * without leading padding. + * + * - decoding: unused + * - encoding: Set by libavcodec. The timestamps on the output packets are + * adjusted by the encoder so that they always refer to the + * first sample of the data actually contained in the packet, + * including any added padding. E.g. if the timebase is + * 1/samplerate and the timestamp of the first input sample is + * 0, the timestamp of the first output packet will be + * -initial_padding. + */ + int initial_padding; + + /** + * - decoding: For codecs that store a framerate value in the compressed + * bitstream, the decoder may export it here. { 0, 1} when + * unknown. + * - encoding: May be used to signal the framerate of CFR content to an + * encoder. + */ + AVRational framerate; + + /** + * Nominal unaccelerated pixel format, see AV_PIX_FMT_xxx. + * - encoding: unused. + * - decoding: Set by libavcodec before calling get_format() + */ + enum AVPixelFormat sw_pix_fmt; + + /** + * Timebase in which pkt_dts/pts and AVPacket.dts/pts are. + * - encoding unused. + * - decoding set by user. + */ + AVRational pkt_timebase; + + /** + * AVCodecDescriptor + * - encoding: unused. + * - decoding: set by libavcodec. + */ + const AVCodecDescriptor *codec_descriptor; + +#if !FF_API_LOWRES + /** + * low resolution decoding, 1-> 1/2 size, 2->1/4 size + * - encoding: unused + * - decoding: Set by user. + */ + int lowres; +#endif + + /** + * Current statistics for PTS correction. + * - decoding: maintained and used by libavcodec, not intended to be used by user apps + * - encoding: unused + */ + int64_t pts_correction_num_faulty_pts; /// Number of incorrect PTS values so far + int64_t pts_correction_num_faulty_dts; /// Number of incorrect DTS values so far + int64_t pts_correction_last_pts; /// PTS of the last frame + int64_t pts_correction_last_dts; /// DTS of the last frame + + /** + * Character encoding of the input subtitles file. + * - decoding: set by user + * - encoding: unused + */ + char *sub_charenc; + + /** + * Subtitles character encoding mode. Formats or codecs might be adjusting + * this setting (if they are doing the conversion themselves for instance). + * - decoding: set by libavcodec + * - encoding: unused + */ + int sub_charenc_mode; +#define FF_SUB_CHARENC_MODE_DO_NOTHING -1 ///< do nothing (demuxer outputs a stream supposed to be already in UTF-8, or the codec is bitmap for instance) +#define FF_SUB_CHARENC_MODE_AUTOMATIC 0 ///< libavcodec will select the mode itself +#define FF_SUB_CHARENC_MODE_PRE_DECODER 1 ///< the AVPacket data needs to be recoded to UTF-8 before being fed to the decoder, requires iconv + + /** + * Skip processing alpha if supported by codec. + * Note that if the format uses pre-multiplied alpha (common with VP6, + * and recommended due to better video quality/compression) + * the image will look as if alpha-blended onto a black background. + * However for formats that do not use pre-multiplied alpha + * there might be serious artefacts (though e.g. libswscale currently + * assumes pre-multiplied alpha anyway). + * + * - decoding: set by user + * - encoding: unused + */ + int skip_alpha; + + /** + * Number of samples to skip after a discontinuity + * - decoding: unused + * - encoding: set by libavcodec + */ + int seek_preroll; + +#if !FF_API_DEBUG_MV + /** + * debug motion vectors + * - encoding: Set by user. + * - decoding: Set by user. + */ + int debug_mv; +#define FF_DEBUG_VIS_MV_P_FOR 0x00000001 //visualize forward predicted MVs of P frames +#define FF_DEBUG_VIS_MV_B_FOR 0x00000002 //visualize forward predicted MVs of B frames +#define FF_DEBUG_VIS_MV_B_BACK 0x00000004 //visualize backward predicted MVs of B frames +#endif + + /** + * custom intra quantization matrix + * - encoding: Set by user, can be NULL. + * - decoding: unused. + */ + uint16_t *chroma_intra_matrix; + + /** + * dump format separator. + * can be ", " or "\n " or anything else + * - encoding: Set by user. + * - decoding: Set by user. + */ + uint8_t *dump_separator; + + /** + * ',' separated list of allowed decoders. + * If NULL then all are allowed + * - encoding: unused + * - decoding: set by user + */ + char *codec_whitelist; + + /* + * Properties of the stream that gets decoded + * - encoding: unused + * - decoding: set by libavcodec + */ + unsigned properties; +#define FF_CODEC_PROPERTY_LOSSLESS 0x00000001 +#define FF_CODEC_PROPERTY_CLOSED_CAPTIONS 0x00000002 + + /** + * Additional data associated with the entire coded stream. + * + * - decoding: unused + * - encoding: may be set by libavcodec after avcodec_open2(). + */ + AVPacketSideData *coded_side_data; + int nb_coded_side_data; + + /** + * A reference to the AVHWFramesContext describing the input (for encoding) + * or output (decoding) frames. The reference is set by the caller and + * afterwards owned (and freed) by libavcodec - it should never be read by + * the caller after being set. + * + * - decoding: This field should be set by the caller from the get_format() + * callback. The previous reference (if any) will always be + * unreffed by libavcodec before the get_format() call. + * + * If the default get_buffer2() is used with a hwaccel pixel + * format, then this AVHWFramesContext will be used for + * allocating the frame buffers. + * + * - encoding: For hardware encoders configured to use a hwaccel pixel + * format, this field should be set by the caller to a reference + * to the AVHWFramesContext describing input frames. + * AVHWFramesContext.format must be equal to + * AVCodecContext.pix_fmt. + * + * This field should be set before avcodec_open2() is called. + */ + AVBufferRef *hw_frames_ctx; + + /** + * Control the form of AVSubtitle.rects[N]->ass + * - decoding: set by user + * - encoding: unused + */ + int sub_text_format; +#define FF_SUB_TEXT_FMT_ASS 0 +#if FF_API_ASS_TIMING +#define FF_SUB_TEXT_FMT_ASS_WITH_TIMINGS 1 +#endif + + /** + * Audio only. The amount of padding (in samples) appended by the encoder to + * the end of the audio. I.e. this number of decoded samples must be + * discarded by the caller from the end of the stream to get the original + * audio without any trailing padding. + * + * - decoding: unused + * - encoding: unused + */ + int trailing_padding; + + /** + * The number of pixels per image to maximally accept. + * + * - decoding: set by user + * - encoding: set by user + */ + int64_t max_pixels; + + /** + * A reference to the AVHWDeviceContext describing the device which will + * be used by a hardware encoder/decoder. The reference is set by the + * caller and afterwards owned (and freed) by libavcodec. + * + * This should be used if either the codec device does not require + * hardware frames or any that are used are to be allocated internally by + * libavcodec. If the user wishes to supply any of the frames used as + * encoder input or decoder output then hw_frames_ctx should be used + * instead. When hw_frames_ctx is set in get_format() for a decoder, this + * field will be ignored while decoding the associated stream segment, but + * may again be used on a following one after another get_format() call. + * + * For both encoders and decoders this field should be set before + * avcodec_open2() is called and must not be written to thereafter. + * + * Note that some decoders may require this field to be set initially in + * order to support hw_frames_ctx at all - in that case, all frames + * contexts used must be created on the same device. + */ + AVBufferRef *hw_device_ctx; + + /** + * Bit set of AV_HWACCEL_FLAG_* flags, which affect hardware accelerated + * decoding (if active). + * - encoding: unused + * - decoding: Set by user (either before avcodec_open2(), or in the + * AVCodecContext.get_format callback) + */ + int hwaccel_flags; +} AVCodecContext; + +AVRational av_codec_get_pkt_timebase (const AVCodecContext *avctx); +void av_codec_set_pkt_timebase (AVCodecContext *avctx, AVRational val); + +const AVCodecDescriptor *av_codec_get_codec_descriptor(const AVCodecContext *avctx); +void av_codec_set_codec_descriptor(AVCodecContext *avctx, const AVCodecDescriptor *desc); + +unsigned av_codec_get_codec_properties(const AVCodecContext *avctx); + +int av_codec_get_lowres(const AVCodecContext *avctx); +void av_codec_set_lowres(AVCodecContext *avctx, int val); + +int av_codec_get_seek_preroll(const AVCodecContext *avctx); +void av_codec_set_seek_preroll(AVCodecContext *avctx, int val); + +uint16_t *av_codec_get_chroma_intra_matrix(const AVCodecContext *avctx); +void av_codec_set_chroma_intra_matrix(AVCodecContext *avctx, uint16_t *val); + +/** + * AVProfile. + */ +typedef struct AVProfile { + int profile; + const char *name; ///< short name for the profile +} AVProfile; + +typedef struct AVCodecDefault AVCodecDefault; + +struct AVSubtitle; + +/** + * AVCodec. + */ +typedef struct AVCodec { + /** + * Name of the codec implementation. + * The name is globally unique among encoders and among decoders (but an + * encoder and a decoder can share the same name). + * This is the primary way to find a codec from the user perspective. + */ + const char *name; + /** + * Descriptive name for the codec, meant to be more human readable than name. + * You should use the NULL_IF_CONFIG_SMALL() macro to define it. + */ + const char *long_name; + enum AVMediaType type; + enum AVCodecID id; + /** + * Codec capabilities. + * see AV_CODEC_CAP_* + */ + int capabilities; + const AVRational *supported_framerates; ///< array of supported framerates, or NULL if any, array is terminated by {0,0} + const enum AVPixelFormat *pix_fmts; ///< array of supported pixel formats, or NULL if unknown, array is terminated by -1 + const int *supported_samplerates; ///< array of supported audio samplerates, or NULL if unknown, array is terminated by 0 + const enum AVSampleFormat *sample_fmts; ///< array of supported sample formats, or NULL if unknown, array is terminated by -1 + const uint64_t *channel_layouts; ///< array of support channel layouts, or NULL if unknown. array is terminated by 0 + uint8_t max_lowres; ///< maximum value for lowres supported by the decoder + const AVClass *priv_class; ///< AVClass for the private context + const AVProfile *profiles; ///< array of recognized profiles, or NULL if unknown, array is terminated by {FF_PROFILE_UNKNOWN} + + /***************************************************************** + * No fields below this line are part of the public API. They + * may not be used outside of libavcodec and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + int priv_data_size; + struct AVCodec *next; + /** + * @name Frame-level threading support functions + * @{ + */ + /** + * If defined, called on thread contexts when they are created. + * If the codec allocates writable tables in init(), re-allocate them here. + * priv_data will be set to a copy of the original. + */ + int (*init_thread_copy)(AVCodecContext *); + /** + * Copy necessary context variables from a previous thread context to the current one. + * If not defined, the next thread will start automatically; otherwise, the codec + * must call ff_thread_finish_setup(). + * + * dst and src will (rarely) point to the same context, in which case memcpy should be skipped. + */ + int (*update_thread_context)(AVCodecContext *dst, const AVCodecContext *src); + /** @} */ + + /** + * Private codec-specific defaults. + */ + const AVCodecDefault *defaults; + + /** + * Initialize codec static data, called from avcodec_register(). + */ + void (*init_static_data)(struct AVCodec *codec); + + int (*init)(AVCodecContext *); + int (*encode_sub)(AVCodecContext *, uint8_t *buf, int buf_size, + const struct AVSubtitle *sub); + /** + * Encode data to an AVPacket. + * + * @param avctx codec context + * @param avpkt output AVPacket (may contain a user-provided buffer) + * @param[in] frame AVFrame containing the raw data to be encoded + * @param[out] got_packet_ptr encoder sets to 0 or 1 to indicate that a + * non-empty packet was returned in avpkt. + * @return 0 on success, negative error code on failure + */ + int (*encode2)(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, + int *got_packet_ptr); + int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, AVPacket *avpkt); + int (*close)(AVCodecContext *); + /** + * Decode/encode API with decoupled packet/frame dataflow. The API is the + * same as the avcodec_ prefixed APIs (avcodec_send_frame() etc.), except + * that: + * - never called if the codec is closed or the wrong type, + * - AVPacket parameter change side data is applied right before calling + * AVCodec->send_packet, + * - if AV_CODEC_CAP_DELAY is not set, drain packets or frames are never sent, + * - only one drain packet is ever passed down (until the next flush()), + * - a drain AVPacket is always NULL (no need to check for avpkt->size). + */ + int (*send_frame)(AVCodecContext *avctx, const AVFrame *frame); + int (*send_packet)(AVCodecContext *avctx, const AVPacket *avpkt); + int (*receive_frame)(AVCodecContext *avctx, AVFrame *frame); + int (*receive_packet)(AVCodecContext *avctx, AVPacket *avpkt); + /** + * Flush buffers. + * Will be called when seeking + */ + void (*flush)(AVCodecContext *); + /** + * Internal codec capabilities. + * See FF_CODEC_CAP_* in internal.h + */ + int caps_internal; +} AVCodec; + +int av_codec_get_max_lowres(const AVCodec *codec); + +struct MpegEncContext; + +/** + * @defgroup lavc_hwaccel AVHWAccel + * @{ + */ +typedef struct AVHWAccel { + /** + * Name of the hardware accelerated codec. + * The name is globally unique among encoders and among decoders (but an + * encoder and a decoder can share the same name). + */ + const char *name; + + /** + * Type of codec implemented by the hardware accelerator. + * + * See AVMEDIA_TYPE_xxx + */ + enum AVMediaType type; + + /** + * Codec implemented by the hardware accelerator. + * + * See AV_CODEC_ID_xxx + */ + enum AVCodecID id; + + /** + * Supported pixel format. + * + * Only hardware accelerated formats are supported here. + */ + enum AVPixelFormat pix_fmt; + + /** + * Hardware accelerated codec capabilities. + * see HWACCEL_CODEC_CAP_* + */ + int capabilities; + + /***************************************************************** + * No fields below this line are part of the public API. They + * may not be used outside of libavcodec and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + struct AVHWAccel *next; + + /** + * Allocate a custom buffer + */ + int (*alloc_frame)(AVCodecContext *avctx, AVFrame *frame); + + /** + * Called at the beginning of each frame or field picture. + * + * Meaningful frame information (codec specific) is guaranteed to + * be parsed at this point. This function is mandatory. + * + * Note that buf can be NULL along with buf_size set to 0. + * Otherwise, this means the whole frame is available at this point. + * + * @param avctx the codec context + * @param buf the frame data buffer base + * @param buf_size the size of the frame in bytes + * @return zero if successful, a negative value otherwise + */ + int (*start_frame)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size); + + /** + * Callback for each slice. + * + * Meaningful slice information (codec specific) is guaranteed to + * be parsed at this point. This function is mandatory. + * The only exception is XvMC, that works on MB level. + * + * @param avctx the codec context + * @param buf the slice data buffer base + * @param buf_size the size of the slice in bytes + * @return zero if successful, a negative value otherwise + */ + int (*decode_slice)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size); + + /** + * Called at the end of each frame or field picture. + * + * The whole picture is parsed at this point and can now be sent + * to the hardware accelerator. This function is mandatory. + * + * @param avctx the codec context + * @return zero if successful, a negative value otherwise + */ + int (*end_frame)(AVCodecContext *avctx); + + /** + * Size of per-frame hardware accelerator private data. + * + * Private data is allocated with av_mallocz() before + * AVCodecContext.get_buffer() and deallocated after + * AVCodecContext.release_buffer(). + */ + int frame_priv_data_size; + + /** + * Called for every Macroblock in a slice. + * + * XvMC uses it to replace the ff_mpv_decode_mb(). + * Instead of decoding to raw picture, MB parameters are + * stored in an array provided by the video driver. + * + * @param s the mpeg context + */ + void (*decode_mb)(struct MpegEncContext *s); + + /** + * Initialize the hwaccel private data. + * + * This will be called from ff_get_format(), after hwaccel and + * hwaccel_context are set and the hwaccel private data in AVCodecInternal + * is allocated. + */ + int (*init)(AVCodecContext *avctx); + + /** + * Uninitialize the hwaccel private data. + * + * This will be called from get_format() or avcodec_close(), after hwaccel + * and hwaccel_context are already uninitialized. + */ + int (*uninit)(AVCodecContext *avctx); + + /** + * Size of the private data to allocate in + * AVCodecInternal.hwaccel_priv_data. + */ + int priv_data_size; + + /** + * Internal hwaccel capabilities. + */ + int caps_internal; +} AVHWAccel; + +/** + * Hardware acceleration should be used for decoding even if the codec level + * used is unknown or higher than the maximum supported level reported by the + * hardware driver. + * + * It's generally a good idea to pass this flag unless you have a specific + * reason not to, as hardware tends to under-report supported levels. + */ +#define AV_HWACCEL_FLAG_IGNORE_LEVEL (1 << 0) + +/** + * Hardware acceleration can output YUV pixel formats with a different chroma + * sampling than 4:2:0 and/or other than 8 bits per component. + */ +#define AV_HWACCEL_FLAG_ALLOW_HIGH_DEPTH (1 << 1) + +/** + * @} + */ + +#if FF_API_AVPICTURE +/** + * @defgroup lavc_picture AVPicture + * + * Functions for working with AVPicture + * @{ + */ + +/** + * Picture data structure. + * + * Up to four components can be stored into it, the last component is + * alpha. + * @deprecated use AVFrame or imgutils functions instead + */ +typedef struct AVPicture { + attribute_deprecated + uint8_t *data[AV_NUM_DATA_POINTERS]; ///< pointers to the image data planes + attribute_deprecated + int linesize[AV_NUM_DATA_POINTERS]; ///< number of bytes per line +} AVPicture; + +/** + * @} + */ +#endif + +enum AVSubtitleType { + SUBTITLE_NONE, + + SUBTITLE_BITMAP, ///< A bitmap, pict will be set + + /** + * Plain text, the text field must be set by the decoder and is + * authoritative. ass and pict fields may contain approximations. + */ + SUBTITLE_TEXT, + + /** + * Formatted text, the ass field must be set by the decoder and is + * authoritative. pict and text fields may contain approximations. + */ + SUBTITLE_ASS, +}; + +#define AV_SUBTITLE_FLAG_FORCED 0x00000001 + +typedef struct AVSubtitleRect { + int x; ///< top left corner of pict, undefined when pict is not set + int y; ///< top left corner of pict, undefined when pict is not set + int w; ///< width of pict, undefined when pict is not set + int h; ///< height of pict, undefined when pict is not set + int nb_colors; ///< number of colors in pict, undefined when pict is not set + +#if FF_API_AVPICTURE + /** + * @deprecated unused + */ + attribute_deprecated + AVPicture pict; +#endif + /** + * data+linesize for the bitmap of this subtitle. + * Can be set for text/ass as well once they are rendered. + */ + uint8_t *data[4]; + int linesize[4]; + + enum AVSubtitleType type; + + char *text; ///< 0 terminated plain UTF-8 text + + /** + * 0 terminated ASS/SSA compatible event line. + * The presentation of this is unaffected by the other values in this + * struct. + */ + char *ass; + + int flags; +} AVSubtitleRect; + +typedef struct AVSubtitle { + uint16_t format; /* 0 = graphics */ + uint32_t start_display_time; /* relative to packet pts, in ms */ + uint32_t end_display_time; /* relative to packet pts, in ms */ + unsigned num_rects; + AVSubtitleRect **rects; + int64_t pts; ///< Same as packet pts, in AV_TIME_BASE +} AVSubtitle; + +/** + * This struct describes the properties of an encoded stream. + * + * sizeof(AVCodecParameters) is not a part of the public ABI, this struct must + * be allocated with avcodec_parameters_alloc() and freed with + * avcodec_parameters_free(). + */ +typedef struct AVCodecParameters { + /** + * General type of the encoded data. + */ + enum AVMediaType codec_type; + /** + * Specific type of the encoded data (the codec used). + */ + enum AVCodecID codec_id; + /** + * Additional information about the codec (corresponds to the AVI FOURCC). + */ + uint32_t codec_tag; + + /** + * Extra binary data needed for initializing the decoder, codec-dependent. + * + * Must be allocated with av_malloc() and will be freed by + * avcodec_parameters_free(). The allocated size of extradata must be at + * least extradata_size + AV_INPUT_BUFFER_PADDING_SIZE, with the padding + * bytes zeroed. + */ + uint8_t *extradata; + /** + * Size of the extradata content in bytes. + */ + int extradata_size; + + /** + * - video: the pixel format, the value corresponds to enum AVPixelFormat. + * - audio: the sample format, the value corresponds to enum AVSampleFormat. + */ + int format; + + /** + * The average bitrate of the encoded data (in bits per second). + */ + int64_t bit_rate; + + /** + * The number of bits per sample in the codedwords. + * + * This is basically the bitrate per sample. It is mandatory for a bunch of + * formats to actually decode them. It's the number of bits for one sample in + * the actual coded bitstream. + * + * This could be for example 4 for ADPCM + * For PCM formats this matches bits_per_raw_sample + * Can be 0 + */ + int bits_per_coded_sample; + + /** + * This is the number of valid bits in each output sample. If the + * sample format has more bits, the least significant bits are additional + * padding bits, which are always 0. Use right shifts to reduce the sample + * to its actual size. For example, audio formats with 24 bit samples will + * have bits_per_raw_sample set to 24, and format set to AV_SAMPLE_FMT_S32. + * To get the original sample use "(int32_t)sample >> 8"." + * + * For ADPCM this might be 12 or 16 or similar + * Can be 0 + */ + int bits_per_raw_sample; + + /** + * Codec-specific bitstream restrictions that the stream conforms to. + */ + int profile; + int level; + + /** + * Video only. The dimensions of the video frame in pixels. + */ + int width; + int height; + + /** + * Video only. The aspect ratio (width / height) which a single pixel + * should have when displayed. + * + * When the aspect ratio is unknown / undefined, the numerator should be + * set to 0 (the denominator may have any value). + */ + AVRational sample_aspect_ratio; + + /** + * Video only. The order of the fields in interlaced video. + */ + enum AVFieldOrder field_order; + + /** + * Video only. Additional colorspace characteristics. + */ + enum AVColorRange color_range; + enum AVColorPrimaries color_primaries; + enum AVColorTransferCharacteristic color_trc; + enum AVColorSpace color_space; + enum AVChromaLocation chroma_location; + + /** + * Video only. Number of delayed frames. + */ + int video_delay; + + /** + * Audio only. The channel layout bitmask. May be 0 if the channel layout is + * unknown or unspecified, otherwise the number of bits set must be equal to + * the channels field. + */ + uint64_t channel_layout; + /** + * Audio only. The number of audio channels. + */ + int channels; + /** + * Audio only. The number of audio samples per second. + */ + int sample_rate; + /** + * Audio only. The number of bytes per coded audio frame, required by some + * formats. + * + * Corresponds to nBlockAlign in WAVEFORMATEX. + */ + int block_align; + /** + * Audio only. Audio frame size, if known. Required by some formats to be static. + */ + int frame_size; + + /** + * Audio only. The amount of padding (in samples) inserted by the encoder at + * the beginning of the audio. I.e. this number of leading decoded samples + * must be discarded by the caller to get the original audio without leading + * padding. + */ + int initial_padding; + /** + * Audio only. The amount of padding (in samples) appended by the encoder to + * the end of the audio. I.e. this number of decoded samples must be + * discarded by the caller from the end of the stream to get the original + * audio without any trailing padding. + */ + int trailing_padding; + /** + * Audio only. Number of samples to skip after a discontinuity. + */ + int seek_preroll; +} AVCodecParameters; + +/** + * If c is NULL, returns the first registered codec, + * if c is non-NULL, returns the next registered codec after c, + * or NULL if c is the last one. + */ +AVCodec *av_codec_next(const AVCodec *c); + +/** + * Return the LIBAVCODEC_VERSION_INT constant. + */ +unsigned avcodec_version(void); + +/** + * Return the libavcodec build-time configuration. + */ +const char *avcodec_configuration(void); + +/** + * Return the libavcodec license. + */ +const char *avcodec_license(void); + +/** + * Register the codec codec and initialize libavcodec. + * + * @warning either this function or avcodec_register_all() must be called + * before any other libavcodec functions. + * + * @see avcodec_register_all() + */ +void avcodec_register(AVCodec *codec); + +/** + * Register all the codecs, parsers and bitstream filters which were enabled at + * configuration time. If you do not call this function you can select exactly + * which formats you want to support, by using the individual registration + * functions. + * + * @see avcodec_register + * @see av_register_codec_parser + * @see av_register_bitstream_filter + */ +void avcodec_register_all(void); + +/** + * Allocate an AVCodecContext and set its fields to default values. The + * resulting struct should be freed with avcodec_free_context(). + * + * @param codec if non-NULL, allocate private data and initialize defaults + * for the given codec. It is illegal to then call avcodec_open2() + * with a different codec. + * If NULL, then the codec-specific defaults won't be initialized, + * which may result in suboptimal default settings (this is + * important mainly for encoders, e.g. libx264). + * + * @return An AVCodecContext filled with default values or NULL on failure. + */ +AVCodecContext *avcodec_alloc_context3(const AVCodec *codec); + +/** + * Free the codec context and everything associated with it and write NULL to + * the provided pointer. + */ +void avcodec_free_context(AVCodecContext **avctx); + +#if FF_API_GET_CONTEXT_DEFAULTS +/** + * @deprecated This function should not be used, as closing and opening a codec + * context multiple time is not supported. A new codec context should be + * allocated for each new use. + */ +int avcodec_get_context_defaults3(AVCodecContext *s, const AVCodec *codec); +#endif + +/** + * Get the AVClass for AVCodecContext. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *avcodec_get_class(void); + +#if FF_API_COPY_CONTEXT +/** + * Get the AVClass for AVFrame. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *avcodec_get_frame_class(void); + +/** + * Get the AVClass for AVSubtitleRect. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *avcodec_get_subtitle_rect_class(void); + +/** + * Copy the settings of the source AVCodecContext into the destination + * AVCodecContext. The resulting destination codec context will be + * unopened, i.e. you are required to call avcodec_open2() before you + * can use this AVCodecContext to decode/encode video/audio data. + * + * @param dest target codec context, should be initialized with + * avcodec_alloc_context3(NULL), but otherwise uninitialized + * @param src source codec context + * @return AVERROR() on error (e.g. memory allocation error), 0 on success + * + * @deprecated The semantics of this function are ill-defined and it should not + * be used. If you need to transfer the stream parameters from one codec context + * to another, use an intermediate AVCodecParameters instance and the + * avcodec_parameters_from_context() / avcodec_parameters_to_context() + * functions. + */ +attribute_deprecated +int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src); +#endif + +/** + * Allocate a new AVCodecParameters and set its fields to default values + * (unknown/invalid/0). The returned struct must be freed with + * avcodec_parameters_free(). + */ +AVCodecParameters *avcodec_parameters_alloc(void); + +/** + * Free an AVCodecParameters instance and everything associated with it and + * write NULL to the supplied pointer. + */ +void avcodec_parameters_free(AVCodecParameters **par); + +/** + * Copy the contents of src to dst. Any allocated fields in dst are freed and + * replaced with newly allocated duplicates of the corresponding fields in src. + * + * @return >= 0 on success, a negative AVERROR code on failure. + */ +int avcodec_parameters_copy(AVCodecParameters *dst, const AVCodecParameters *src); + +/** + * Fill the parameters struct based on the values from the supplied codec + * context. Any allocated fields in par are freed and replaced with duplicates + * of the corresponding fields in codec. + * + * @return >= 0 on success, a negative AVERROR code on failure + */ +int avcodec_parameters_from_context(AVCodecParameters *par, + const AVCodecContext *codec); + +/** + * Fill the codec context based on the values from the supplied codec + * parameters. Any allocated fields in codec that have a corresponding field in + * par are freed and replaced with duplicates of the corresponding field in par. + * Fields in codec that do not have a counterpart in par are not touched. + * + * @return >= 0 on success, a negative AVERROR code on failure. + */ +int avcodec_parameters_to_context(AVCodecContext *codec, + const AVCodecParameters *par); + +/** + * Initialize the AVCodecContext to use the given AVCodec. Prior to using this + * function the context has to be allocated with avcodec_alloc_context3(). + * + * The functions avcodec_find_decoder_by_name(), avcodec_find_encoder_by_name(), + * avcodec_find_decoder() and avcodec_find_encoder() provide an easy way for + * retrieving a codec. + * + * @warning This function is not thread safe! + * + * @note Always call this function before using decoding routines (such as + * @ref avcodec_receive_frame()). + * + * @code + * avcodec_register_all(); + * av_dict_set(&opts, "b", "2.5M", 0); + * codec = avcodec_find_decoder(AV_CODEC_ID_H264); + * if (!codec) + * exit(1); + * + * context = avcodec_alloc_context3(codec); + * + * if (avcodec_open2(context, codec, opts) < 0) + * exit(1); + * @endcode + * + * @param avctx The context to initialize. + * @param codec The codec to open this context for. If a non-NULL codec has been + * previously passed to avcodec_alloc_context3() or + * for this context, then this parameter MUST be either NULL or + * equal to the previously passed codec. + * @param options A dictionary filled with AVCodecContext and codec-private options. + * On return this object will be filled with options that were not found. + * + * @return zero on success, a negative value on error + * @see avcodec_alloc_context3(), avcodec_find_decoder(), avcodec_find_encoder(), + * av_dict_set(), av_opt_find(). + */ +int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options); + +/** + * Close a given AVCodecContext and free all the data associated with it + * (but not the AVCodecContext itself). + * + * Calling this function on an AVCodecContext that hasn't been opened will free + * the codec-specific data allocated in avcodec_alloc_context3() with a non-NULL + * codec. Subsequent calls will do nothing. + * + * @note Do not use this function. Use avcodec_free_context() to destroy a + * codec context (either open or closed). Opening and closing a codec context + * multiple times is not supported anymore -- use multiple codec contexts + * instead. + */ +int avcodec_close(AVCodecContext *avctx); + +/** + * Free all allocated data in the given subtitle struct. + * + * @param sub AVSubtitle to free. + */ +void avsubtitle_free(AVSubtitle *sub); + +/** + * @} + */ + +/** + * @addtogroup lavc_packet + * @{ + */ + +/** + * Allocate an AVPacket and set its fields to default values. The resulting + * struct must be freed using av_packet_free(). + * + * @return An AVPacket filled with default values or NULL on failure. + * + * @note this only allocates the AVPacket itself, not the data buffers. Those + * must be allocated through other means such as av_new_packet. + * + * @see av_new_packet + */ +AVPacket *av_packet_alloc(void); + +/** + * Create a new packet that references the same data as src. + * + * This is a shortcut for av_packet_alloc()+av_packet_ref(). + * + * @return newly created AVPacket on success, NULL on error. + * + * @see av_packet_alloc + * @see av_packet_ref + */ +AVPacket *av_packet_clone(const AVPacket *src); + +/** + * Free the packet, if the packet is reference counted, it will be + * unreferenced first. + * + * @param packet packet to be freed. The pointer will be set to NULL. + * @note passing NULL is a no-op. + */ +void av_packet_free(AVPacket **pkt); + +/** + * Initialize optional fields of a packet with default values. + * + * Note, this does not touch the data and size members, which have to be + * initialized separately. + * + * @param pkt packet + */ +void av_init_packet(AVPacket *pkt); + +/** + * Allocate the payload of a packet and initialize its fields with + * default values. + * + * @param pkt packet + * @param size wanted payload size + * @return 0 if OK, AVERROR_xxx otherwise + */ +int av_new_packet(AVPacket *pkt, int size); + +/** + * Reduce packet size, correctly zeroing padding + * + * @param pkt packet + * @param size new size + */ +void av_shrink_packet(AVPacket *pkt, int size); + +/** + * Increase packet size, correctly zeroing padding + * + * @param pkt packet + * @param grow_by number of bytes by which to increase the size of the packet + */ +int av_grow_packet(AVPacket *pkt, int grow_by); + +/** + * Initialize a reference-counted packet from av_malloc()ed data. + * + * @param pkt packet to be initialized. This function will set the data, size, + * buf and destruct fields, all others are left untouched. + * @param data Data allocated by av_malloc() to be used as packet data. If this + * function returns successfully, the data is owned by the underlying AVBuffer. + * The caller may not access the data through other means. + * @param size size of data in bytes, without the padding. I.e. the full buffer + * size is assumed to be size + AV_INPUT_BUFFER_PADDING_SIZE. + * + * @return 0 on success, a negative AVERROR on error + */ +int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size); + +#if FF_API_AVPACKET_OLD_API +/** + * @warning This is a hack - the packet memory allocation stuff is broken. The + * packet is allocated if it was not really allocated. + * + * @deprecated Use av_packet_ref + */ +attribute_deprecated +int av_dup_packet(AVPacket *pkt); +/** + * Copy packet, including contents + * + * @return 0 on success, negative AVERROR on fail + */ +int av_copy_packet(AVPacket *dst, const AVPacket *src); + +/** + * Copy packet side data + * + * @return 0 on success, negative AVERROR on fail + */ +int av_copy_packet_side_data(AVPacket *dst, const AVPacket *src); + +/** + * Free a packet. + * + * @deprecated Use av_packet_unref + * + * @param pkt packet to free + */ +attribute_deprecated +void av_free_packet(AVPacket *pkt); +#endif +/** + * Allocate new information of a packet. + * + * @param pkt packet + * @param type side information type + * @param size side information size + * @return pointer to fresh allocated data or NULL otherwise + */ +uint8_t* av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + int size); + +/** + * Wrap an existing array as a packet side data. + * + * @param pkt packet + * @param type side information type + * @param data the side data array. It must be allocated with the av_malloc() + * family of functions. The ownership of the data is transferred to + * pkt. + * @param size side information size + * @return a non-negative number on success, a negative AVERROR code on + * failure. On failure, the packet is unchanged and the data remains + * owned by the caller. + */ +int av_packet_add_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + uint8_t *data, size_t size); + +/** + * Shrink the already allocated side data buffer + * + * @param pkt packet + * @param type side information type + * @param size new side information size + * @return 0 on success, < 0 on failure + */ +int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + int size); + +/** + * Get side information from packet. + * + * @param pkt packet + * @param type desired side information type + * @param size pointer for side information size to store (optional) + * @return pointer to data if present or NULL otherwise + */ +uint8_t* av_packet_get_side_data(const AVPacket *pkt, enum AVPacketSideDataType type, + int *size); + +#if FF_API_MERGE_SD_API +attribute_deprecated +int av_packet_merge_side_data(AVPacket *pkt); + +attribute_deprecated +int av_packet_split_side_data(AVPacket *pkt); +#endif + +const char *av_packet_side_data_name(enum AVPacketSideDataType type); + +/** + * Pack a dictionary for use in side_data. + * + * @param dict The dictionary to pack. + * @param size pointer to store the size of the returned data + * @return pointer to data if successful, NULL otherwise + */ +uint8_t *av_packet_pack_dictionary(AVDictionary *dict, int *size); +/** + * Unpack a dictionary from side_data. + * + * @param data data from side_data + * @param size size of the data + * @param dict the metadata storage dictionary + * @return 0 on success, < 0 on failure + */ +int av_packet_unpack_dictionary(const uint8_t *data, int size, AVDictionary **dict); + + +/** + * Convenience function to free all the side data stored. + * All the other fields stay untouched. + * + * @param pkt packet + */ +void av_packet_free_side_data(AVPacket *pkt); + +/** + * Setup a new reference to the data described by a given packet + * + * If src is reference-counted, setup dst as a new reference to the + * buffer in src. Otherwise allocate a new buffer in dst and copy the + * data from src into it. + * + * All the other fields are copied from src. + * + * @see av_packet_unref + * + * @param dst Destination packet + * @param src Source packet + * + * @return 0 on success, a negative AVERROR on error. + */ +int av_packet_ref(AVPacket *dst, const AVPacket *src); + +/** + * Wipe the packet. + * + * Unreference the buffer referenced by the packet and reset the + * remaining packet fields to their default values. + * + * @param pkt The packet to be unreferenced. + */ +void av_packet_unref(AVPacket *pkt); + +/** + * Move every field in src to dst and reset src. + * + * @see av_packet_unref + * + * @param src Source packet, will be reset + * @param dst Destination packet + */ +void av_packet_move_ref(AVPacket *dst, AVPacket *src); + +/** + * Copy only "properties" fields from src to dst. + * + * Properties for the purpose of this function are all the fields + * beside those related to the packet data (buf, data, size) + * + * @param dst Destination packet + * @param src Source packet + * + * @return 0 on success AVERROR on failure. + */ +int av_packet_copy_props(AVPacket *dst, const AVPacket *src); + +/** + * Convert valid timing fields (timestamps / durations) in a packet from one + * timebase to another. Timestamps with unknown values (AV_NOPTS_VALUE) will be + * ignored. + * + * @param pkt packet on which the conversion will be performed + * @param tb_src source timebase, in which the timing fields in pkt are + * expressed + * @param tb_dst destination timebase, to which the timing fields will be + * converted + */ +void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst); + +/** + * @} + */ + +/** + * @addtogroup lavc_decoding + * @{ + */ + +/** + * Find a registered decoder with a matching codec ID. + * + * @param id AVCodecID of the requested decoder + * @return A decoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_decoder(enum AVCodecID id); + +/** + * Find a registered decoder with the specified name. + * + * @param name name of the requested decoder + * @return A decoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_decoder_by_name(const char *name); + +/** + * The default callback for AVCodecContext.get_buffer2(). It is made public so + * it can be called by custom get_buffer2() implementations for decoders without + * AV_CODEC_CAP_DR1 set. + */ +int avcodec_default_get_buffer2(AVCodecContext *s, AVFrame *frame, int flags); + +#if FF_API_EMU_EDGE +/** + * Return the amount of padding in pixels which the get_buffer callback must + * provide around the edge of the image for codecs which do not have the + * CODEC_FLAG_EMU_EDGE flag. + * + * @return Required padding in pixels. + * + * @deprecated CODEC_FLAG_EMU_EDGE is deprecated, so this function is no longer + * needed + */ +attribute_deprecated +unsigned avcodec_get_edge_width(void); +#endif + +/** + * Modify width and height values so that they will result in a memory + * buffer that is acceptable for the codec if you do not use any horizontal + * padding. + * + * May only be used if a codec with AV_CODEC_CAP_DR1 has been opened. + */ +void avcodec_align_dimensions(AVCodecContext *s, int *width, int *height); + +/** + * Modify width and height values so that they will result in a memory + * buffer that is acceptable for the codec if you also ensure that all + * line sizes are a multiple of the respective linesize_align[i]. + * + * May only be used if a codec with AV_CODEC_CAP_DR1 has been opened. + */ +void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height, + int linesize_align[AV_NUM_DATA_POINTERS]); + +/** + * Converts AVChromaLocation to swscale x/y chroma position. + * + * The positions represent the chroma (0,0) position in a coordinates system + * with luma (0,0) representing the origin and luma(1,1) representing 256,256 + * + * @param xpos horizontal chroma sample position + * @param ypos vertical chroma sample position + */ +int avcodec_enum_to_chroma_pos(int *xpos, int *ypos, enum AVChromaLocation pos); + +/** + * Converts swscale x/y chroma position to AVChromaLocation. + * + * The positions represent the chroma (0,0) position in a coordinates system + * with luma (0,0) representing the origin and luma(1,1) representing 256,256 + * + * @param xpos horizontal chroma sample position + * @param ypos vertical chroma sample position + */ +enum AVChromaLocation avcodec_chroma_pos_to_enum(int xpos, int ypos); + +/** + * Decode the audio frame of size avpkt->size from avpkt->data into frame. + * + * Some decoders may support multiple frames in a single AVPacket. Such + * decoders would then just decode the first frame and the return value would be + * less than the packet size. In this case, avcodec_decode_audio4 has to be + * called again with an AVPacket containing the remaining data in order to + * decode the second frame, etc... Even if no frames are returned, the packet + * needs to be fed to the decoder with remaining data until it is completely + * consumed or an error occurs. + * + * Some decoders (those marked with AV_CODEC_CAP_DELAY) have a delay between input + * and output. This means that for some packets they will not immediately + * produce decoded output and need to be flushed at the end of decoding to get + * all the decoded data. Flushing is done by calling this function with packets + * with avpkt->data set to NULL and avpkt->size set to 0 until it stops + * returning samples. It is safe to flush even those decoders that are not + * marked with AV_CODEC_CAP_DELAY, then no samples will be returned. + * + * @warning The input buffer, avpkt->data must be AV_INPUT_BUFFER_PADDING_SIZE + * larger than the actual read bytes because some optimized bitstream + * readers read 32 or 64 bits at once and could read over the end. + * + * @note The AVCodecContext MUST have been opened with @ref avcodec_open2() + * before packets may be fed to the decoder. + * + * @param avctx the codec context + * @param[out] frame The AVFrame in which to store decoded audio samples. + * The decoder will allocate a buffer for the decoded frame by + * calling the AVCodecContext.get_buffer2() callback. + * When AVCodecContext.refcounted_frames is set to 1, the frame is + * reference counted and the returned reference belongs to the + * caller. The caller must release the frame using av_frame_unref() + * when the frame is no longer needed. The caller may safely write + * to the frame if av_frame_is_writable() returns 1. + * When AVCodecContext.refcounted_frames is set to 0, the returned + * reference belongs to the decoder and is valid only until the + * next call to this function or until closing or flushing the + * decoder. The caller may not write to it. + * @param[out] got_frame_ptr Zero if no frame could be decoded, otherwise it is + * non-zero. Note that this field being set to zero + * does not mean that an error has occurred. For + * decoders with AV_CODEC_CAP_DELAY set, no given decode + * call is guaranteed to produce a frame. + * @param[in] avpkt The input AVPacket containing the input buffer. + * At least avpkt->data and avpkt->size should be set. Some + * decoders might also require additional fields to be set. + * @return A negative error code is returned if an error occurred during + * decoding, otherwise the number of bytes consumed from the input + * AVPacket is returned. + * +* @deprecated Use avcodec_send_packet() and avcodec_receive_frame(). + */ +attribute_deprecated +int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame, + int *got_frame_ptr, const AVPacket *avpkt); + +/** + * Decode the video frame of size avpkt->size from avpkt->data into picture. + * Some decoders may support multiple frames in a single AVPacket, such + * decoders would then just decode the first frame. + * + * @warning The input buffer must be AV_INPUT_BUFFER_PADDING_SIZE larger than + * the actual read bytes because some optimized bitstream readers read 32 or 64 + * bits at once and could read over the end. + * + * @warning The end of the input buffer buf should be set to 0 to ensure that + * no overreading happens for damaged MPEG streams. + * + * @note Codecs which have the AV_CODEC_CAP_DELAY capability set have a delay + * between input and output, these need to be fed with avpkt->data=NULL, + * avpkt->size=0 at the end to return the remaining frames. + * + * @note The AVCodecContext MUST have been opened with @ref avcodec_open2() + * before packets may be fed to the decoder. + * + * @param avctx the codec context + * @param[out] picture The AVFrame in which the decoded video frame will be stored. + * Use av_frame_alloc() to get an AVFrame. The codec will + * allocate memory for the actual bitmap by calling the + * AVCodecContext.get_buffer2() callback. + * When AVCodecContext.refcounted_frames is set to 1, the frame is + * reference counted and the returned reference belongs to the + * caller. The caller must release the frame using av_frame_unref() + * when the frame is no longer needed. The caller may safely write + * to the frame if av_frame_is_writable() returns 1. + * When AVCodecContext.refcounted_frames is set to 0, the returned + * reference belongs to the decoder and is valid only until the + * next call to this function or until closing or flushing the + * decoder. The caller may not write to it. + * + * @param[in] avpkt The input AVPacket containing the input buffer. + * You can create such packet with av_init_packet() and by then setting + * data and size, some decoders might in addition need other fields like + * flags&AV_PKT_FLAG_KEY. All decoders are designed to use the least + * fields possible. + * @param[in,out] got_picture_ptr Zero if no frame could be decompressed, otherwise, it is nonzero. + * @return On error a negative value is returned, otherwise the number of bytes + * used or zero if no frame could be decompressed. + * + * @deprecated Use avcodec_send_packet() and avcodec_receive_frame(). + */ +attribute_deprecated +int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, + int *got_picture_ptr, + const AVPacket *avpkt); + +/** + * Decode a subtitle message. + * Return a negative value on error, otherwise return the number of bytes used. + * If no subtitle could be decompressed, got_sub_ptr is zero. + * Otherwise, the subtitle is stored in *sub. + * Note that AV_CODEC_CAP_DR1 is not available for subtitle codecs. This is for + * simplicity, because the performance difference is expect to be negligible + * and reusing a get_buffer written for video codecs would probably perform badly + * due to a potentially very different allocation pattern. + * + * Some decoders (those marked with CODEC_CAP_DELAY) have a delay between input + * and output. This means that for some packets they will not immediately + * produce decoded output and need to be flushed at the end of decoding to get + * all the decoded data. Flushing is done by calling this function with packets + * with avpkt->data set to NULL and avpkt->size set to 0 until it stops + * returning subtitles. It is safe to flush even those decoders that are not + * marked with CODEC_CAP_DELAY, then no subtitles will be returned. + * + * @note The AVCodecContext MUST have been opened with @ref avcodec_open2() + * before packets may be fed to the decoder. + * + * @param avctx the codec context + * @param[out] sub The Preallocated AVSubtitle in which the decoded subtitle will be stored, + * must be freed with avsubtitle_free if *got_sub_ptr is set. + * @param[in,out] got_sub_ptr Zero if no subtitle could be decompressed, otherwise, it is nonzero. + * @param[in] avpkt The input AVPacket containing the input buffer. + */ +int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, + int *got_sub_ptr, + AVPacket *avpkt); + +/** + * Supply raw packet data as input to a decoder. + * + * Internally, this call will copy relevant AVCodecContext fields, which can + * influence decoding per-packet, and apply them when the packet is actually + * decoded. (For example AVCodecContext.skip_frame, which might direct the + * decoder to drop the frame contained by the packet sent with this function.) + * + * @warning The input buffer, avpkt->data must be AV_INPUT_BUFFER_PADDING_SIZE + * larger than the actual read bytes because some optimized bitstream + * readers read 32 or 64 bits at once and could read over the end. + * + * @warning Do not mix this API with the legacy API (like avcodec_decode_video2()) + * on the same AVCodecContext. It will return unexpected results now + * or in future libavcodec versions. + * + * @note The AVCodecContext MUST have been opened with @ref avcodec_open2() + * before packets may be fed to the decoder. + * + * @param avctx codec context + * @param[in] avpkt The input AVPacket. Usually, this will be a single video + * frame, or several complete audio frames. + * Ownership of the packet remains with the caller, and the + * decoder will not write to the packet. The decoder may create + * a reference to the packet data (or copy it if the packet is + * not reference-counted). + * Unlike with older APIs, the packet is always fully consumed, + * and if it contains multiple frames (e.g. some audio codecs), + * will require you to call avcodec_receive_frame() multiple + * times afterwards before you can send a new packet. + * It can be NULL (or an AVPacket with data set to NULL and + * size set to 0); in this case, it is considered a flush + * packet, which signals the end of the stream. Sending the + * first flush packet will return success. Subsequent ones are + * unnecessary and will return AVERROR_EOF. If the decoder + * still has frames buffered, it will return them after sending + * a flush packet. + * + * @return 0 on success, otherwise negative error code: + * AVERROR(EAGAIN): input is not accepted in the current state - user + * must read output with avcodec_receive_frame() (once + * all output is read, the packet should be resent, and + * the call will not fail with EAGAIN). + * AVERROR_EOF: the decoder has been flushed, and no new packets can + * be sent to it (also returned if more than 1 flush + * packet is sent) + * AVERROR(EINVAL): codec not opened, it is an encoder, or requires flush + * AVERROR(ENOMEM): failed to add packet to internal queue, or similar + * other errors: legitimate decoding errors + */ +int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt); + +/** + * Return decoded output data from a decoder. + * + * @param avctx codec context + * @param frame This will be set to a reference-counted video or audio + * frame (depending on the decoder type) allocated by the + * decoder. Note that the function will always call + * av_frame_unref(frame) before doing anything else. + * + * @return + * 0: success, a frame was returned + * AVERROR(EAGAIN): output is not available in this state - user must try + * to send new input + * AVERROR_EOF: the decoder has been fully flushed, and there will be + * no more output frames + * AVERROR(EINVAL): codec not opened, or it is an encoder + * other negative values: legitimate decoding errors + */ +int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame); + +/** + * Supply a raw video or audio frame to the encoder. Use avcodec_receive_packet() + * to retrieve buffered output packets. + * + * @param avctx codec context + * @param[in] frame AVFrame containing the raw audio or video frame to be encoded. + * Ownership of the frame remains with the caller, and the + * encoder will not write to the frame. The encoder may create + * a reference to the frame data (or copy it if the frame is + * not reference-counted). + * It can be NULL, in which case it is considered a flush + * packet. This signals the end of the stream. If the encoder + * still has packets buffered, it will return them after this + * call. Once flushing mode has been entered, additional flush + * packets are ignored, and sending frames will return + * AVERROR_EOF. + * + * For audio: + * If AV_CODEC_CAP_VARIABLE_FRAME_SIZE is set, then each frame + * can have any number of samples. + * If it is not set, frame->nb_samples must be equal to + * avctx->frame_size for all frames except the last. + * The final frame may be smaller than avctx->frame_size. + * @return 0 on success, otherwise negative error code: + * AVERROR(EAGAIN): input is not accepted in the current state - user + * must read output with avcodec_receive_packet() (once + * all output is read, the packet should be resent, and + * the call will not fail with EAGAIN). + * AVERROR_EOF: the encoder has been flushed, and no new frames can + * be sent to it + * AVERROR(EINVAL): codec not opened, refcounted_frames not set, it is a + * decoder, or requires flush + * AVERROR(ENOMEM): failed to add packet to internal queue, or similar + * other errors: legitimate decoding errors + */ +int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame); + +/** + * Read encoded data from the encoder. + * + * @param avctx codec context + * @param avpkt This will be set to a reference-counted packet allocated by the + * encoder. Note that the function will always call + * av_frame_unref(frame) before doing anything else. + * @return 0 on success, otherwise negative error code: + * AVERROR(EAGAIN): output is not available in the current state - user + * must try to send input + * AVERROR_EOF: the encoder has been fully flushed, and there will be + * no more output packets + * AVERROR(EINVAL): codec not opened, or it is an encoder + * other errors: legitimate decoding errors + */ +int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt); + + +/** + * @defgroup lavc_parsing Frame parsing + * @{ + */ + +enum AVPictureStructure { + AV_PICTURE_STRUCTURE_UNKNOWN, //< unknown + AV_PICTURE_STRUCTURE_TOP_FIELD, //< coded as top field + AV_PICTURE_STRUCTURE_BOTTOM_FIELD, //< coded as bottom field + AV_PICTURE_STRUCTURE_FRAME, //< coded as frame +}; + +typedef struct AVCodecParserContext { + void *priv_data; + struct AVCodecParser *parser; + int64_t frame_offset; /* offset of the current frame */ + int64_t cur_offset; /* current offset + (incremented by each av_parser_parse()) */ + int64_t next_frame_offset; /* offset of the next frame */ + /* video info */ + int pict_type; /* XXX: Put it back in AVCodecContext. */ + /** + * This field is used for proper frame duration computation in lavf. + * It signals, how much longer the frame duration of the current frame + * is compared to normal frame duration. + * + * frame_duration = (1 + repeat_pict) * time_base + * + * It is used by codecs like H.264 to display telecined material. + */ + int repeat_pict; /* XXX: Put it back in AVCodecContext. */ + int64_t pts; /* pts of the current frame */ + int64_t dts; /* dts of the current frame */ + + /* private data */ + int64_t last_pts; + int64_t last_dts; + int fetch_timestamp; + +#define AV_PARSER_PTS_NB 4 + int cur_frame_start_index; + int64_t cur_frame_offset[AV_PARSER_PTS_NB]; + int64_t cur_frame_pts[AV_PARSER_PTS_NB]; + int64_t cur_frame_dts[AV_PARSER_PTS_NB]; + + int flags; +#define PARSER_FLAG_COMPLETE_FRAMES 0x0001 +#define PARSER_FLAG_ONCE 0x0002 +/// Set if the parser has a valid file offset +#define PARSER_FLAG_FETCHED_OFFSET 0x0004 +#define PARSER_FLAG_USE_CODEC_TS 0x1000 + + int64_t offset; ///< byte offset from starting packet start + int64_t cur_frame_end[AV_PARSER_PTS_NB]; + + /** + * Set by parser to 1 for key frames and 0 for non-key frames. + * It is initialized to -1, so if the parser doesn't set this flag, + * old-style fallback using AV_PICTURE_TYPE_I picture type as key frames + * will be used. + */ + int key_frame; + +#if FF_API_CONVERGENCE_DURATION + /** + * @deprecated unused + */ + attribute_deprecated + int64_t convergence_duration; +#endif + + // Timestamp generation support: + /** + * Synchronization point for start of timestamp generation. + * + * Set to >0 for sync point, 0 for no sync point and <0 for undefined + * (default). + * + * For example, this corresponds to presence of H.264 buffering period + * SEI message. + */ + int dts_sync_point; + + /** + * Offset of the current timestamp against last timestamp sync point in + * units of AVCodecContext.time_base. + * + * Set to INT_MIN when dts_sync_point unused. Otherwise, it must + * contain a valid timestamp offset. + * + * Note that the timestamp of sync point has usually a nonzero + * dts_ref_dts_delta, which refers to the previous sync point. Offset of + * the next frame after timestamp sync point will be usually 1. + * + * For example, this corresponds to H.264 cpb_removal_delay. + */ + int dts_ref_dts_delta; + + /** + * Presentation delay of current frame in units of AVCodecContext.time_base. + * + * Set to INT_MIN when dts_sync_point unused. Otherwise, it must + * contain valid non-negative timestamp delta (presentation time of a frame + * must not lie in the past). + * + * This delay represents the difference between decoding and presentation + * time of the frame. + * + * For example, this corresponds to H.264 dpb_output_delay. + */ + int pts_dts_delta; + + /** + * Position of the packet in file. + * + * Analogous to cur_frame_pts/dts + */ + int64_t cur_frame_pos[AV_PARSER_PTS_NB]; + + /** + * Byte position of currently parsed frame in stream. + */ + int64_t pos; + + /** + * Previous frame byte position. + */ + int64_t last_pos; + + /** + * Duration of the current frame. + * For audio, this is in units of 1 / AVCodecContext.sample_rate. + * For all other types, this is in units of AVCodecContext.time_base. + */ + int duration; + + enum AVFieldOrder field_order; + + /** + * Indicate whether a picture is coded as a frame, top field or bottom field. + * + * For example, H.264 field_pic_flag equal to 0 corresponds to + * AV_PICTURE_STRUCTURE_FRAME. An H.264 picture with field_pic_flag + * equal to 1 and bottom_field_flag equal to 0 corresponds to + * AV_PICTURE_STRUCTURE_TOP_FIELD. + */ + enum AVPictureStructure picture_structure; + + /** + * Picture number incremented in presentation or output order. + * This field may be reinitialized at the first picture of a new sequence. + * + * For example, this corresponds to H.264 PicOrderCnt. + */ + int output_picture_number; + + /** + * Dimensions of the decoded video intended for presentation. + */ + int width; + int height; + + /** + * Dimensions of the coded video. + */ + int coded_width; + int coded_height; + + /** + * The format of the coded data, corresponds to enum AVPixelFormat for video + * and for enum AVSampleFormat for audio. + * + * Note that a decoder can have considerable freedom in how exactly it + * decodes the data, so the format reported here might be different from the + * one returned by a decoder. + */ + int format; +} AVCodecParserContext; + +typedef struct AVCodecParser { + int codec_ids[5]; /* several codec IDs are permitted */ + int priv_data_size; + int (*parser_init)(AVCodecParserContext *s); + /* This callback never returns an error, a negative value means that + * the frame start was in a previous packet. */ + int (*parser_parse)(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size); + void (*parser_close)(AVCodecParserContext *s); + int (*split)(AVCodecContext *avctx, const uint8_t *buf, int buf_size); + struct AVCodecParser *next; +} AVCodecParser; + +AVCodecParser *av_parser_next(const AVCodecParser *c); + +void av_register_codec_parser(AVCodecParser *parser); +AVCodecParserContext *av_parser_init(int codec_id); + +/** + * Parse a packet. + * + * @param s parser context. + * @param avctx codec context. + * @param poutbuf set to pointer to parsed buffer or NULL if not yet finished. + * @param poutbuf_size set to size of parsed buffer or zero if not yet finished. + * @param buf input buffer. + * @param buf_size buffer size in bytes without the padding. I.e. the full buffer + size is assumed to be buf_size + AV_INPUT_BUFFER_PADDING_SIZE. + To signal EOF, this should be 0 (so that the last frame + can be output). + * @param pts input presentation timestamp. + * @param dts input decoding timestamp. + * @param pos input byte position in stream. + * @return the number of bytes of the input bitstream used. + * + * Example: + * @code + * while(in_len){ + * len = av_parser_parse2(myparser, AVCodecContext, &data, &size, + * in_data, in_len, + * pts, dts, pos); + * in_data += len; + * in_len -= len; + * + * if(size) + * decode_frame(data, size); + * } + * @endcode + */ +int av_parser_parse2(AVCodecParserContext *s, + AVCodecContext *avctx, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, + int64_t pts, int64_t dts, + int64_t pos); + +/** + * @return 0 if the output buffer is a subset of the input, 1 if it is allocated and must be freed + * @deprecated use AVBitStreamFilter + */ +int av_parser_change(AVCodecParserContext *s, + AVCodecContext *avctx, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, int keyframe); +void av_parser_close(AVCodecParserContext *s); + +/** + * @} + * @} + */ + +/** + * @addtogroup lavc_encoding + * @{ + */ + +/** + * Find a registered encoder with a matching codec ID. + * + * @param id AVCodecID of the requested encoder + * @return An encoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_encoder(enum AVCodecID id); + +/** + * Find a registered encoder with the specified name. + * + * @param name name of the requested encoder + * @return An encoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_encoder_by_name(const char *name); + +/** + * Encode a frame of audio. + * + * Takes input samples from frame and writes the next output packet, if + * available, to avpkt. The output packet does not necessarily contain data for + * the most recent frame, as encoders can delay, split, and combine input frames + * internally as needed. + * + * @param avctx codec context + * @param avpkt output AVPacket. + * The user can supply an output buffer by setting + * avpkt->data and avpkt->size prior to calling the + * function, but if the size of the user-provided data is not + * large enough, encoding will fail. If avpkt->data and + * avpkt->size are set, avpkt->destruct must also be set. All + * other AVPacket fields will be reset by the encoder using + * av_init_packet(). If avpkt->data is NULL, the encoder will + * allocate it. The encoder will set avpkt->size to the size + * of the output packet. + * + * If this function fails or produces no output, avpkt will be + * freed using av_packet_unref(). + * @param[in] frame AVFrame containing the raw audio data to be encoded. + * May be NULL when flushing an encoder that has the + * AV_CODEC_CAP_DELAY capability set. + * If AV_CODEC_CAP_VARIABLE_FRAME_SIZE is set, then each frame + * can have any number of samples. + * If it is not set, frame->nb_samples must be equal to + * avctx->frame_size for all frames except the last. + * The final frame may be smaller than avctx->frame_size. + * @param[out] got_packet_ptr This field is set to 1 by libavcodec if the + * output packet is non-empty, and to 0 if it is + * empty. If the function returns an error, the + * packet can be assumed to be invalid, and the + * value of got_packet_ptr is undefined and should + * not be used. + * @return 0 on success, negative error code on failure + * + * @deprecated use avcodec_send_frame()/avcodec_receive_packet() instead + */ +attribute_deprecated +int avcodec_encode_audio2(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr); + +/** + * Encode a frame of video. + * + * Takes input raw video data from frame and writes the next output packet, if + * available, to avpkt. The output packet does not necessarily contain data for + * the most recent frame, as encoders can delay and reorder input frames + * internally as needed. + * + * @param avctx codec context + * @param avpkt output AVPacket. + * The user can supply an output buffer by setting + * avpkt->data and avpkt->size prior to calling the + * function, but if the size of the user-provided data is not + * large enough, encoding will fail. All other AVPacket fields + * will be reset by the encoder using av_init_packet(). If + * avpkt->data is NULL, the encoder will allocate it. + * The encoder will set avpkt->size to the size of the + * output packet. The returned data (if any) belongs to the + * caller, he is responsible for freeing it. + * + * If this function fails or produces no output, avpkt will be + * freed using av_packet_unref(). + * @param[in] frame AVFrame containing the raw video data to be encoded. + * May be NULL when flushing an encoder that has the + * AV_CODEC_CAP_DELAY capability set. + * @param[out] got_packet_ptr This field is set to 1 by libavcodec if the + * output packet is non-empty, and to 0 if it is + * empty. If the function returns an error, the + * packet can be assumed to be invalid, and the + * value of got_packet_ptr is undefined and should + * not be used. + * @return 0 on success, negative error code on failure + * + * @deprecated use avcodec_send_frame()/avcodec_receive_packet() instead + */ +attribute_deprecated +int avcodec_encode_video2(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr); + +int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size, + const AVSubtitle *sub); + + +/** + * @} + */ + +#if FF_API_AVCODEC_RESAMPLE +/** + * @defgroup lavc_resample Audio resampling + * @ingroup libavc + * @deprecated use libswresample instead + * + * @{ + */ +struct ReSampleContext; +struct AVResampleContext; + +typedef struct ReSampleContext ReSampleContext; + +/** + * Initialize audio resampling context. + * + * @param output_channels number of output channels + * @param input_channels number of input channels + * @param output_rate output sample rate + * @param input_rate input sample rate + * @param sample_fmt_out requested output sample format + * @param sample_fmt_in input sample format + * @param filter_length length of each FIR filter in the filterbank relative to the cutoff frequency + * @param log2_phase_count log2 of the number of entries in the polyphase filterbank + * @param linear if 1 then the used FIR filter will be linearly interpolated + between the 2 closest, if 0 the closest will be used + * @param cutoff cutoff frequency, 1.0 corresponds to half the output sampling rate + * @return allocated ReSampleContext, NULL if error occurred + */ +attribute_deprecated +ReSampleContext *av_audio_resample_init(int output_channels, int input_channels, + int output_rate, int input_rate, + enum AVSampleFormat sample_fmt_out, + enum AVSampleFormat sample_fmt_in, + int filter_length, int log2_phase_count, + int linear, double cutoff); + +attribute_deprecated +int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples); + +/** + * Free resample context. + * + * @param s a non-NULL pointer to a resample context previously + * created with av_audio_resample_init() + */ +attribute_deprecated +void audio_resample_close(ReSampleContext *s); + + +/** + * Initialize an audio resampler. + * Note, if either rate is not an integer then simply scale both rates up so they are. + * @param filter_length length of each FIR filter in the filterbank relative to the cutoff freq + * @param log2_phase_count log2 of the number of entries in the polyphase filterbank + * @param linear If 1 then the used FIR filter will be linearly interpolated + between the 2 closest, if 0 the closest will be used + * @param cutoff cutoff frequency, 1.0 corresponds to half the output sampling rate + */ +attribute_deprecated +struct AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_length, int log2_phase_count, int linear, double cutoff); + +/** + * Resample an array of samples using a previously configured context. + * @param src an array of unconsumed samples + * @param consumed the number of samples of src which have been consumed are returned here + * @param src_size the number of unconsumed samples available + * @param dst_size the amount of space in samples available in dst + * @param update_ctx If this is 0 then the context will not be modified, that way several channels can be resampled with the same context. + * @return the number of samples written in dst or -1 if an error occurred + */ +attribute_deprecated +int av_resample(struct AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx); + + +/** + * Compensate samplerate/timestamp drift. The compensation is done by changing + * the resampler parameters, so no audible clicks or similar distortions occur + * @param compensation_distance distance in output samples over which the compensation should be performed + * @param sample_delta number of output samples which should be output less + * + * example: av_resample_compensate(c, 10, 500) + * here instead of 510 samples only 500 samples would be output + * + * note, due to rounding the actual compensation might be slightly different, + * especially if the compensation_distance is large and the in_rate used during init is small + */ +attribute_deprecated +void av_resample_compensate(struct AVResampleContext *c, int sample_delta, int compensation_distance); +attribute_deprecated +void av_resample_close(struct AVResampleContext *c); + +/** + * @} + */ +#endif + +#if FF_API_AVPICTURE +/** + * @addtogroup lavc_picture + * @{ + */ + +/** + * @deprecated unused + */ +attribute_deprecated +int avpicture_alloc(AVPicture *picture, enum AVPixelFormat pix_fmt, int width, int height); + +/** + * @deprecated unused + */ +attribute_deprecated +void avpicture_free(AVPicture *picture); + +/** + * @deprecated use av_image_fill_arrays() instead. + */ +attribute_deprecated +int avpicture_fill(AVPicture *picture, const uint8_t *ptr, + enum AVPixelFormat pix_fmt, int width, int height); + +/** + * @deprecated use av_image_copy_to_buffer() instead. + */ +attribute_deprecated +int avpicture_layout(const AVPicture *src, enum AVPixelFormat pix_fmt, + int width, int height, + unsigned char *dest, int dest_size); + +/** + * @deprecated use av_image_get_buffer_size() instead. + */ +attribute_deprecated +int avpicture_get_size(enum AVPixelFormat pix_fmt, int width, int height); + +/** + * @deprecated av_image_copy() instead. + */ +attribute_deprecated +void av_picture_copy(AVPicture *dst, const AVPicture *src, + enum AVPixelFormat pix_fmt, int width, int height); + +/** + * @deprecated unused + */ +attribute_deprecated +int av_picture_crop(AVPicture *dst, const AVPicture *src, + enum AVPixelFormat pix_fmt, int top_band, int left_band); + +/** + * @deprecated unused + */ +attribute_deprecated +int av_picture_pad(AVPicture *dst, const AVPicture *src, int height, int width, enum AVPixelFormat pix_fmt, + int padtop, int padbottom, int padleft, int padright, int *color); + +/** + * @} + */ +#endif + +/** + * @defgroup lavc_misc Utility functions + * @ingroup libavc + * + * Miscellaneous utility functions related to both encoding and decoding + * (or neither). + * @{ + */ + +/** + * @defgroup lavc_misc_pixfmt Pixel formats + * + * Functions for working with pixel formats. + * @{ + */ + +/** + * Utility function to access log2_chroma_w log2_chroma_h from + * the pixel format AVPixFmtDescriptor. + * + * This function asserts that pix_fmt is valid. See av_pix_fmt_get_chroma_sub_sample + * for one that returns a failure code and continues in case of invalid + * pix_fmts. + * + * @param[in] pix_fmt the pixel format + * @param[out] h_shift store log2_chroma_w + * @param[out] v_shift store log2_chroma_h + * + * @see av_pix_fmt_get_chroma_sub_sample + */ + +void avcodec_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, int *h_shift, int *v_shift); + +/** + * Return a value representing the fourCC code associated to the + * pixel format pix_fmt, or 0 if no associated fourCC code can be + * found. + */ +unsigned int avcodec_pix_fmt_to_codec_tag(enum AVPixelFormat pix_fmt); + +/** + * @deprecated see av_get_pix_fmt_loss() + */ +int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, enum AVPixelFormat src_pix_fmt, + int has_alpha); + +/** + * Find the best pixel format to convert to given a certain source pixel + * format. When converting from one pixel format to another, information loss + * may occur. For example, when converting from RGB24 to GRAY, the color + * information will be lost. Similarly, other losses occur when converting from + * some formats to other formats. avcodec_find_best_pix_fmt_of_2() searches which of + * the given pixel formats should be used to suffer the least amount of loss. + * The pixel formats from which it chooses one, are determined by the + * pix_fmt_list parameter. + * + * + * @param[in] pix_fmt_list AV_PIX_FMT_NONE terminated array of pixel formats to choose from + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @param[out] loss_ptr Combination of flags informing you what kind of losses will occur. + * @return The best pixel format to convert to or -1 if none was found. + */ +enum AVPixelFormat avcodec_find_best_pix_fmt_of_list(const enum AVPixelFormat *pix_fmt_list, + enum AVPixelFormat src_pix_fmt, + int has_alpha, int *loss_ptr); + +/** + * @deprecated see av_find_best_pix_fmt_of_2() + */ +enum AVPixelFormat avcodec_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr); + +attribute_deprecated +enum AVPixelFormat avcodec_find_best_pix_fmt2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr); + +enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum AVPixelFormat * fmt); + +/** + * @} + */ + +#if FF_API_SET_DIMENSIONS +/** + * @deprecated this function is not supposed to be used from outside of lavc + */ +attribute_deprecated +void avcodec_set_dimensions(AVCodecContext *s, int width, int height); +#endif + +#if FF_API_TAG_STRING +/** + * Put a string representing the codec tag codec_tag in buf. + * + * @param buf buffer to place codec tag in + * @param buf_size size in bytes of buf + * @param codec_tag codec tag to assign + * @return the length of the string that would have been generated if + * enough space had been available, excluding the trailing null + * + * @deprecated see av_fourcc_make_string() and av_fourcc2str(). + */ +attribute_deprecated +size_t av_get_codec_tag_string(char *buf, size_t buf_size, unsigned int codec_tag); +#endif + +void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode); + +/** + * Return a name for the specified profile, if available. + * + * @param codec the codec that is searched for the given profile + * @param profile the profile value for which a name is requested + * @return A name for the profile if found, NULL otherwise. + */ +const char *av_get_profile_name(const AVCodec *codec, int profile); + +/** + * Return a name for the specified profile, if available. + * + * @param codec_id the ID of the codec to which the requested profile belongs + * @param profile the profile value for which a name is requested + * @return A name for the profile if found, NULL otherwise. + * + * @note unlike av_get_profile_name(), which searches a list of profiles + * supported by a specific decoder or encoder implementation, this + * function searches the list of profiles from the AVCodecDescriptor + */ +const char *avcodec_profile_name(enum AVCodecID codec_id, int profile); + +int avcodec_default_execute(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2),void *arg, int *ret, int count, int size); +int avcodec_default_execute2(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2, int, int),void *arg, int *ret, int count); +//FIXME func typedef + +/** + * Fill AVFrame audio data and linesize pointers. + * + * The buffer buf must be a preallocated buffer with a size big enough + * to contain the specified samples amount. The filled AVFrame data + * pointers will point to this buffer. + * + * AVFrame extended_data channel pointers are allocated if necessary for + * planar audio. + * + * @param frame the AVFrame + * frame->nb_samples must be set prior to calling the + * function. This function fills in frame->data, + * frame->extended_data, frame->linesize[0]. + * @param nb_channels channel count + * @param sample_fmt sample format + * @param buf buffer to use for frame data + * @param buf_size size of buffer + * @param align plane size sample alignment (0 = default) + * @return >=0 on success, negative error code on failure + * @todo return the size in bytes required to store the samples in + * case of success, at the next libavutil bump + */ +int avcodec_fill_audio_frame(AVFrame *frame, int nb_channels, + enum AVSampleFormat sample_fmt, const uint8_t *buf, + int buf_size, int align); + +/** + * Reset the internal decoder state / flush internal buffers. Should be called + * e.g. when seeking or when switching to a different stream. + * + * @note when refcounted frames are not used (i.e. avctx->refcounted_frames is 0), + * this invalidates the frames previously returned from the decoder. When + * refcounted frames are used, the decoder just releases any references it might + * keep internally, but the caller's reference remains valid. + */ +void avcodec_flush_buffers(AVCodecContext *avctx); + +/** + * Return codec bits per sample. + * + * @param[in] codec_id the codec + * @return Number of bits per sample or zero if unknown for the given codec. + */ +int av_get_bits_per_sample(enum AVCodecID codec_id); + +/** + * Return the PCM codec associated with a sample format. + * @param be endianness, 0 for little, 1 for big, + * -1 (or anything else) for native + * @return AV_CODEC_ID_PCM_* or AV_CODEC_ID_NONE + */ +enum AVCodecID av_get_pcm_codec(enum AVSampleFormat fmt, int be); + +/** + * Return codec bits per sample. + * Only return non-zero if the bits per sample is exactly correct, not an + * approximation. + * + * @param[in] codec_id the codec + * @return Number of bits per sample or zero if unknown for the given codec. + */ +int av_get_exact_bits_per_sample(enum AVCodecID codec_id); + +/** + * Return audio frame duration. + * + * @param avctx codec context + * @param frame_bytes size of the frame, or 0 if unknown + * @return frame duration, in samples, if known. 0 if not able to + * determine. + */ +int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes); + +/** + * This function is the same as av_get_audio_frame_duration(), except it works + * with AVCodecParameters instead of an AVCodecContext. + */ +int av_get_audio_frame_duration2(AVCodecParameters *par, int frame_bytes); + +#if FF_API_OLD_BSF +typedef struct AVBitStreamFilterContext { + void *priv_data; + const struct AVBitStreamFilter *filter; + AVCodecParserContext *parser; + struct AVBitStreamFilterContext *next; + /** + * Internal default arguments, used if NULL is passed to av_bitstream_filter_filter(). + * Not for access by library users. + */ + char *args; +} AVBitStreamFilterContext; +#endif + +typedef struct AVBSFInternal AVBSFInternal; + +/** + * The bitstream filter state. + * + * This struct must be allocated with av_bsf_alloc() and freed with + * av_bsf_free(). + * + * The fields in the struct will only be changed (by the caller or by the + * filter) as described in their documentation, and are to be considered + * immutable otherwise. + */ +typedef struct AVBSFContext { + /** + * A class for logging and AVOptions + */ + const AVClass *av_class; + + /** + * The bitstream filter this context is an instance of. + */ + const struct AVBitStreamFilter *filter; + + /** + * Opaque libavcodec internal data. Must not be touched by the caller in any + * way. + */ + AVBSFInternal *internal; + + /** + * Opaque filter-specific private data. If filter->priv_class is non-NULL, + * this is an AVOptions-enabled struct. + */ + void *priv_data; + + /** + * Parameters of the input stream. This field is allocated in + * av_bsf_alloc(), it needs to be filled by the caller before + * av_bsf_init(). + */ + AVCodecParameters *par_in; + + /** + * Parameters of the output stream. This field is allocated in + * av_bsf_alloc(), it is set by the filter in av_bsf_init(). + */ + AVCodecParameters *par_out; + + /** + * The timebase used for the timestamps of the input packets. Set by the + * caller before av_bsf_init(). + */ + AVRational time_base_in; + + /** + * The timebase used for the timestamps of the output packets. Set by the + * filter in av_bsf_init(). + */ + AVRational time_base_out; +} AVBSFContext; + +typedef struct AVBitStreamFilter { + const char *name; + + /** + * A list of codec ids supported by the filter, terminated by + * AV_CODEC_ID_NONE. + * May be NULL, in that case the bitstream filter works with any codec id. + */ + const enum AVCodecID *codec_ids; + + /** + * A class for the private data, used to declare bitstream filter private + * AVOptions. This field is NULL for bitstream filters that do not declare + * any options. + * + * If this field is non-NULL, the first member of the filter private data + * must be a pointer to AVClass, which will be set by libavcodec generic + * code to this class. + */ + const AVClass *priv_class; + + /***************************************************************** + * No fields below this line are part of the public API. They + * may not be used outside of libavcodec and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + + int priv_data_size; + int (*init)(AVBSFContext *ctx); + int (*filter)(AVBSFContext *ctx, AVPacket *pkt); + void (*close)(AVBSFContext *ctx); +} AVBitStreamFilter; + +#if FF_API_OLD_BSF +/** + * Register a bitstream filter. + * + * The filter will be accessible to the application code through + * av_bitstream_filter_next() or can be directly initialized with + * av_bitstream_filter_init(). + * + * @see avcodec_register_all() + */ +attribute_deprecated +void av_register_bitstream_filter(AVBitStreamFilter *bsf); + +/** + * Create and initialize a bitstream filter context given a bitstream + * filter name. + * + * The returned context must be freed with av_bitstream_filter_close(). + * + * @param name the name of the bitstream filter + * @return a bitstream filter context if a matching filter was found + * and successfully initialized, NULL otherwise + */ +attribute_deprecated +AVBitStreamFilterContext *av_bitstream_filter_init(const char *name); + +/** + * Filter bitstream. + * + * This function filters the buffer buf with size buf_size, and places the + * filtered buffer in the buffer pointed to by poutbuf. + * + * The output buffer must be freed by the caller. + * + * @param bsfc bitstream filter context created by av_bitstream_filter_init() + * @param avctx AVCodecContext accessed by the filter, may be NULL. + * If specified, this must point to the encoder context of the + * output stream the packet is sent to. + * @param args arguments which specify the filter configuration, may be NULL + * @param poutbuf pointer which is updated to point to the filtered buffer + * @param poutbuf_size pointer which is updated to the filtered buffer size in bytes + * @param buf buffer containing the data to filter + * @param buf_size size in bytes of buf + * @param keyframe set to non-zero if the buffer to filter corresponds to a key-frame packet data + * @return >= 0 in case of success, or a negative error code in case of failure + * + * If the return value is positive, an output buffer is allocated and + * is available in *poutbuf, and is distinct from the input buffer. + * + * If the return value is 0, the output buffer is not allocated and + * should be considered identical to the input buffer, or in case + * *poutbuf was set it points to the input buffer (not necessarily to + * its starting address). A special case is if *poutbuf was set to NULL and + * *poutbuf_size was set to 0, which indicates the packet should be dropped. + */ +attribute_deprecated +int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc, + AVCodecContext *avctx, const char *args, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, int keyframe); + +/** + * Release bitstream filter context. + * + * @param bsf the bitstream filter context created with + * av_bitstream_filter_init(), can be NULL + */ +attribute_deprecated +void av_bitstream_filter_close(AVBitStreamFilterContext *bsf); + +/** + * If f is NULL, return the first registered bitstream filter, + * if f is non-NULL, return the next registered bitstream filter + * after f, or NULL if f is the last one. + * + * This function can be used to iterate over all registered bitstream + * filters. + */ +attribute_deprecated +AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f); +#endif + +/** + * @return a bitstream filter with the specified name or NULL if no such + * bitstream filter exists. + */ +const AVBitStreamFilter *av_bsf_get_by_name(const char *name); + +/** + * Iterate over all registered bitstream filters. + * + * @param opaque a pointer where libavcodec will store the iteration state. Must + * point to NULL to start the iteration. + * + * @return the next registered bitstream filter or NULL when the iteration is + * finished + */ +const AVBitStreamFilter *av_bsf_next(void **opaque); + +/** + * Allocate a context for a given bitstream filter. The caller must fill in the + * context parameters as described in the documentation and then call + * av_bsf_init() before sending any data to the filter. + * + * @param filter the filter for which to allocate an instance. + * @param ctx a pointer into which the pointer to the newly-allocated context + * will be written. It must be freed with av_bsf_free() after the + * filtering is done. + * + * @return 0 on success, a negative AVERROR code on failure + */ +int av_bsf_alloc(const AVBitStreamFilter *filter, AVBSFContext **ctx); + +/** + * Prepare the filter for use, after all the parameters and options have been + * set. + */ +int av_bsf_init(AVBSFContext *ctx); + +/** + * Submit a packet for filtering. + * + * After sending each packet, the filter must be completely drained by calling + * av_bsf_receive_packet() repeatedly until it returns AVERROR(EAGAIN) or + * AVERROR_EOF. + * + * @param pkt the packet to filter. pkt must contain some payload (i.e data or + * side data must be present in pkt). The bitstream filter will take ownership of + * the packet and reset the contents of pkt. pkt is not touched if an error occurs. + * This parameter may be NULL, which signals the end of the stream (i.e. no more + * packets will be sent). That will cause the filter to output any packets it + * may have buffered internally. + * + * @return 0 on success, a negative AVERROR on error. + */ +int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt); + +/** + * Retrieve a filtered packet. + * + * @param[out] pkt this struct will be filled with the contents of the filtered + * packet. It is owned by the caller and must be freed using + * av_packet_unref() when it is no longer needed. + * This parameter should be "clean" (i.e. freshly allocated + * with av_packet_alloc() or unreffed with av_packet_unref()) + * when this function is called. If this function returns + * successfully, the contents of pkt will be completely + * overwritten by the returned data. On failure, pkt is not + * touched. + * + * @return 0 on success. AVERROR(EAGAIN) if more packets need to be sent to the + * filter (using av_bsf_send_packet()) to get more output. AVERROR_EOF if there + * will be no further output from the filter. Another negative AVERROR value if + * an error occurs. + * + * @note one input packet may result in several output packets, so after sending + * a packet with av_bsf_send_packet(), this function needs to be called + * repeatedly until it stops returning 0. It is also possible for a filter to + * output fewer packets than were sent to it, so this function may return + * AVERROR(EAGAIN) immediately after a successful av_bsf_send_packet() call. + */ +int av_bsf_receive_packet(AVBSFContext *ctx, AVPacket *pkt); + +/** + * Free a bitstream filter context and everything associated with it; write NULL + * into the supplied pointer. + */ +void av_bsf_free(AVBSFContext **ctx); + +/** + * Get the AVClass for AVBSFContext. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *av_bsf_get_class(void); + +/** + * Structure for chain/list of bitstream filters. + * Empty list can be allocated by av_bsf_list_alloc(). + */ +typedef struct AVBSFList AVBSFList; + +/** + * Allocate empty list of bitstream filters. + * The list must be later freed by av_bsf_list_free() + * or finalized by av_bsf_list_finalize(). + * + * @return Pointer to @ref AVBSFList on success, NULL in case of failure + */ +AVBSFList *av_bsf_list_alloc(void); + +/** + * Free list of bitstream filters. + * + * @param lst Pointer to pointer returned by av_bsf_list_alloc() + */ +void av_bsf_list_free(AVBSFList **lst); + +/** + * Append bitstream filter to the list of bitstream filters. + * + * @param lst List to append to + * @param bsf Filter context to be appended + * + * @return >=0 on success, negative AVERROR in case of failure + */ +int av_bsf_list_append(AVBSFList *lst, AVBSFContext *bsf); + +/** + * Construct new bitstream filter context given it's name and options + * and append it to the list of bitstream filters. + * + * @param lst List to append to + * @param bsf_name Name of the bitstream filter + * @param options Options for the bitstream filter, can be set to NULL + * + * @return >=0 on success, negative AVERROR in case of failure + */ +int av_bsf_list_append2(AVBSFList *lst, const char * bsf_name, AVDictionary **options); +/** + * Finalize list of bitstream filters. + * + * This function will transform @ref AVBSFList to single @ref AVBSFContext, + * so the whole chain of bitstream filters can be treated as single filter + * freshly allocated by av_bsf_alloc(). + * If the call is successful, @ref AVBSFList structure is freed and lst + * will be set to NULL. In case of failure, caller is responsible for + * freeing the structure by av_bsf_list_free() + * + * @param lst Filter list structure to be transformed + * @param[out] bsf Pointer to be set to newly created @ref AVBSFContext structure + * representing the chain of bitstream filters + * + * @return >=0 on success, negative AVERROR in case of failure + */ +int av_bsf_list_finalize(AVBSFList **lst, AVBSFContext **bsf); + +/** + * Parse string describing list of bitstream filters and create single + * @ref AVBSFContext describing the whole chain of bitstream filters. + * Resulting @ref AVBSFContext can be treated as any other @ref AVBSFContext freshly + * allocated by av_bsf_alloc(). + * + * @param str String describing chain of bitstream filters in format + * `bsf1[=opt1=val1:opt2=val2][,bsf2]` + * @param[out] bsf Pointer to be set to newly created @ref AVBSFContext structure + * representing the chain of bitstream filters + * + * @return >=0 on success, negative AVERROR in case of failure + */ +int av_bsf_list_parse_str(const char *str, AVBSFContext **bsf); + +/** + * Get null/pass-through bitstream filter. + * + * @param[out] bsf Pointer to be set to new instance of pass-through bitstream filter + * + * @return + */ +int av_bsf_get_null_filter(AVBSFContext **bsf); + +/* memory */ + +/** + * Same behaviour av_fast_malloc but the buffer has additional + * AV_INPUT_BUFFER_PADDING_SIZE at the end which will always be 0. + * + * In addition the whole buffer will initially and after resizes + * be 0-initialized so that no uninitialized data will ever appear. + */ +void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size); + +/** + * Same behaviour av_fast_padded_malloc except that buffer will always + * be 0-initialized after call. + */ +void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size); + +/** + * Encode extradata length to a buffer. Used by xiph codecs. + * + * @param s buffer to write to; must be at least (v/255+1) bytes long + * @param v size of extradata in bytes + * @return number of bytes written to the buffer. + */ +unsigned int av_xiphlacing(unsigned char *s, unsigned int v); + +#if FF_API_MISSING_SAMPLE +/** + * Log a generic warning message about a missing feature. This function is + * intended to be used internally by FFmpeg (libavcodec, libavformat, etc.) + * only, and would normally not be used by applications. + * @param[in] avc a pointer to an arbitrary struct of which the first field is + * a pointer to an AVClass struct + * @param[in] feature string containing the name of the missing feature + * @param[in] want_sample indicates if samples are wanted which exhibit this feature. + * If want_sample is non-zero, additional verbiage will be added to the log + * message which tells the user how to report samples to the development + * mailing list. + * @deprecated Use avpriv_report_missing_feature() instead. + */ +attribute_deprecated +void av_log_missing_feature(void *avc, const char *feature, int want_sample); + +/** + * Log a generic warning message asking for a sample. This function is + * intended to be used internally by FFmpeg (libavcodec, libavformat, etc.) + * only, and would normally not be used by applications. + * @param[in] avc a pointer to an arbitrary struct of which the first field is + * a pointer to an AVClass struct + * @param[in] msg string containing an optional message, or NULL if no message + * @deprecated Use avpriv_request_sample() instead. + */ +attribute_deprecated +void av_log_ask_for_sample(void *avc, const char *msg, ...) av_printf_format(2, 3); +#endif /* FF_API_MISSING_SAMPLE */ + +/** + * Register the hardware accelerator hwaccel. + */ +void av_register_hwaccel(AVHWAccel *hwaccel); + +/** + * If hwaccel is NULL, returns the first registered hardware accelerator, + * if hwaccel is non-NULL, returns the next registered hardware accelerator + * after hwaccel, or NULL if hwaccel is the last one. + */ +AVHWAccel *av_hwaccel_next(const AVHWAccel *hwaccel); + + +/** + * Lock operation used by lockmgr + */ +enum AVLockOp { + AV_LOCK_CREATE, ///< Create a mutex + AV_LOCK_OBTAIN, ///< Lock the mutex + AV_LOCK_RELEASE, ///< Unlock the mutex + AV_LOCK_DESTROY, ///< Free mutex resources +}; + +/** + * Register a user provided lock manager supporting the operations + * specified by AVLockOp. The "mutex" argument to the function points + * to a (void *) where the lockmgr should store/get a pointer to a user + * allocated mutex. It is NULL upon AV_LOCK_CREATE and equal to the + * value left by the last call for all other ops. If the lock manager is + * unable to perform the op then it should leave the mutex in the same + * state as when it was called and return a non-zero value. However, + * when called with AV_LOCK_DESTROY the mutex will always be assumed to + * have been successfully destroyed. If av_lockmgr_register succeeds + * it will return a non-negative value, if it fails it will return a + * negative value and destroy all mutex and unregister all callbacks. + * av_lockmgr_register is not thread-safe, it must be called from a + * single thread before any calls which make use of locking are used. + * + * @param cb User defined callback. av_lockmgr_register invokes calls + * to this callback and the previously registered callback. + * The callback will be used to create more than one mutex + * each of which must be backed by its own underlying locking + * mechanism (i.e. do not use a single static object to + * implement your lock manager). If cb is set to NULL the + * lockmgr will be unregistered. + */ +int av_lockmgr_register(int (*cb)(void **mutex, enum AVLockOp op)); + +/** + * Get the type of the given codec. + */ +enum AVMediaType avcodec_get_type(enum AVCodecID codec_id); + +/** + * Get the name of a codec. + * @return a static string identifying the codec; never NULL + */ +const char *avcodec_get_name(enum AVCodecID id); + +/** + * @return a positive value if s is open (i.e. avcodec_open2() was called on it + * with no corresponding avcodec_close()), 0 otherwise. + */ +int avcodec_is_open(AVCodecContext *s); + +/** + * @return a non-zero number if codec is an encoder, zero otherwise + */ +int av_codec_is_encoder(const AVCodec *codec); + +/** + * @return a non-zero number if codec is a decoder, zero otherwise + */ +int av_codec_is_decoder(const AVCodec *codec); + +/** + * @return descriptor for given codec ID or NULL if no descriptor exists. + */ +const AVCodecDescriptor *avcodec_descriptor_get(enum AVCodecID id); + +/** + * Iterate over all codec descriptors known to libavcodec. + * + * @param prev previous descriptor. NULL to get the first descriptor. + * + * @return next descriptor or NULL after the last descriptor + */ +const AVCodecDescriptor *avcodec_descriptor_next(const AVCodecDescriptor *prev); + +/** + * @return codec descriptor with the given name or NULL if no such descriptor + * exists. + */ +const AVCodecDescriptor *avcodec_descriptor_get_by_name(const char *name); + +/** + * Allocate a CPB properties structure and initialize its fields to default + * values. + * + * @param size if non-NULL, the size of the allocated struct will be written + * here. This is useful for embedding it in side data. + * + * @return the newly allocated struct or NULL on failure + */ +AVCPBProperties *av_cpb_properties_alloc(size_t *size); + +/** + * @} + */ + +#endif /* AVCODEC_AVCODEC_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/avdct.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/avdct.h new file mode 100644 index 0000000..272422e --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/avdct.h @@ -0,0 +1,84 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AVDCT_H +#define AVCODEC_AVDCT_H + +#include "libavutil/opt.h" + +/** + * AVDCT context. + * @note function pointers can be NULL if the specific features have been + * disabled at build time. + */ +typedef struct AVDCT { + const AVClass *av_class; + + void (*idct)(int16_t *block /* align 16 */); + + /** + * IDCT input permutation. + * Several optimized IDCTs need a permutated input (relative to the + * normal order of the reference IDCT). + * This permutation must be performed before the idct_put/add. + * Note, normally this can be merged with the zigzag/alternate scan
+ * An example to avoid confusion: + * - (->decode coeffs -> zigzag reorder -> dequant -> reference IDCT -> ...) + * - (x -> reference DCT -> reference IDCT -> x) + * - (x -> reference DCT -> simple_mmx_perm = idct_permutation + * -> simple_idct_mmx -> x) + * - (-> decode coeffs -> zigzag reorder -> simple_mmx_perm -> dequant + * -> simple_idct_mmx -> ...) + */ + uint8_t idct_permutation[64]; + + void (*fdct)(int16_t *block /* align 16 */); + + + /** + * DCT algorithm. + * must use AVOptions to set this field. + */ + int dct_algo; + + /** + * IDCT algorithm. + * must use AVOptions to set this field. + */ + int idct_algo; + + void (*get_pixels)(int16_t *block /* align 16 */, + const uint8_t *pixels /* align 8 */, + ptrdiff_t line_size); + + int bits_per_sample; +} AVDCT; + +/** + * Allocates a AVDCT context. + * This needs to be initialized with avcodec_dct_init() after optionally + * configuring it with AVOptions. + * + * To free it use av_free() + */ +AVDCT *avcodec_dct_alloc(void); +int avcodec_dct_init(AVDCT *); + +const AVClass *avcodec_dct_get_class(void); + +#endif /* AVCODEC_AVDCT_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/avfft.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/avfft.h new file mode 100644 index 0000000..0c0f9b8 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/avfft.h @@ -0,0 +1,118 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AVFFT_H +#define AVCODEC_AVFFT_H + +/** + * @file + * @ingroup lavc_fft + * FFT functions + */ + +/** + * @defgroup lavc_fft FFT functions + * @ingroup lavc_misc + * + * @{ + */ + +typedef float FFTSample; + +typedef struct FFTComplex { + FFTSample re, im; +} FFTComplex; + +typedef struct FFTContext FFTContext; + +/** + * Set up a complex FFT. + * @param nbits log2 of the length of the input array + * @param inverse if 0 perform the forward transform, if 1 perform the inverse + */ +FFTContext *av_fft_init(int nbits, int inverse); + +/** + * Do the permutation needed BEFORE calling ff_fft_calc(). + */ +void av_fft_permute(FFTContext *s, FFTComplex *z); + +/** + * Do a complex FFT with the parameters defined in av_fft_init(). The + * input data must be permuted before. No 1.0/sqrt(n) normalization is done. + */ +void av_fft_calc(FFTContext *s, FFTComplex *z); + +void av_fft_end(FFTContext *s); + +FFTContext *av_mdct_init(int nbits, int inverse, double scale); +void av_imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); +void av_imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input); +void av_mdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); +void av_mdct_end(FFTContext *s); + +/* Real Discrete Fourier Transform */ + +enum RDFTransformType { + DFT_R2C, + IDFT_C2R, + IDFT_R2C, + DFT_C2R, +}; + +typedef struct RDFTContext RDFTContext; + +/** + * Set up a real FFT. + * @param nbits log2 of the length of the input array + * @param trans the type of transform + */ +RDFTContext *av_rdft_init(int nbits, enum RDFTransformType trans); +void av_rdft_calc(RDFTContext *s, FFTSample *data); +void av_rdft_end(RDFTContext *s); + +/* Discrete Cosine Transform */ + +typedef struct DCTContext DCTContext; + +enum DCTTransformType { + DCT_II = 0, + DCT_III, + DCT_I, + DST_I, +}; + +/** + * Set up DCT. + * + * @param nbits size of the input array: + * (1 << nbits) for DCT-II, DCT-III and DST-I + * (1 << nbits) + 1 for DCT-I + * @param type the type of transform + * + * @note the first element of the input of DST-I is ignored + */ +DCTContext *av_dct_init(int nbits, enum DCTTransformType type); +void av_dct_calc(DCTContext *s, FFTSample *data); +void av_dct_end (DCTContext *s); + +/** + * @} + */ + +#endif /* AVCODEC_AVFFT_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/d3d11va.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/d3d11va.h new file mode 100644 index 0000000..6816b6c --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/d3d11va.h @@ -0,0 +1,112 @@ +/* + * Direct3D11 HW acceleration + * + * copyright (c) 2009 Laurent Aimar + * copyright (c) 2015 Steve Lhomme + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_D3D11VA_H +#define AVCODEC_D3D11VA_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_d3d11va + * Public libavcodec D3D11VA header. + */ + +#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0602 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0602 +#endif + +#include +#include + +/** + * @defgroup lavc_codec_hwaccel_d3d11va Direct3D11 + * @ingroup lavc_codec_hwaccel + * + * @{ + */ + +#define FF_DXVA2_WORKAROUND_SCALING_LIST_ZIGZAG 1 ///< Work around for Direct3D11 and old UVD/UVD+ ATI video cards +#define FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO 2 ///< Work around for Direct3D11 and old Intel GPUs with ClearVideo interface + +/** + * This structure is used to provides the necessary configurations and data + * to the Direct3D11 FFmpeg HWAccel implementation. + * + * The application must make it available as AVCodecContext.hwaccel_context. + * + * Use av_d3d11va_alloc_context() exclusively to allocate an AVD3D11VAContext. + */ +typedef struct AVD3D11VAContext { + /** + * D3D11 decoder object + */ + ID3D11VideoDecoder *decoder; + + /** + * D3D11 VideoContext + */ + ID3D11VideoContext *video_context; + + /** + * D3D11 configuration used to create the decoder + */ + D3D11_VIDEO_DECODER_CONFIG *cfg; + + /** + * The number of surface in the surface array + */ + unsigned surface_count; + + /** + * The array of Direct3D surfaces used to create the decoder + */ + ID3D11VideoDecoderOutputView **surface; + + /** + * A bit field configuring the workarounds needed for using the decoder + */ + uint64_t workaround; + + /** + * Private to the FFmpeg AVHWAccel implementation + */ + unsigned report_id; + + /** + * Mutex to access video_context + */ + HANDLE context_mutex; +} AVD3D11VAContext; + +/** + * Allocate an AVD3D11VAContext. + * + * @return Newly-allocated AVD3D11VAContext or NULL on failure. + */ +AVD3D11VAContext *av_d3d11va_alloc_context(void); + +/** + * @} + */ + +#endif /* AVCODEC_D3D11VA_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/dirac.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/dirac.h new file mode 100644 index 0000000..e6d9d34 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/dirac.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2007 Marco Gerards + * Copyright (C) 2009 David Conrad + * Copyright (C) 2011 Jordi Ortiz + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DIRAC_H +#define AVCODEC_DIRAC_H + +/** + * @file + * Interface to Dirac Decoder/Encoder + * @author Marco Gerards + * @author David Conrad + * @author Jordi Ortiz + */ + +#include "avcodec.h" + +/** + * The spec limits the number of wavelet decompositions to 4 for both + * level 1 (VC-2) and 128 (long-gop default). + * 5 decompositions is the maximum before >16-bit buffers are needed. + * Schroedinger allows this for DD 9,7 and 13,7 wavelets only, limiting + * the others to 4 decompositions (or 3 for the fidelity filter). + * + * We use this instead of MAX_DECOMPOSITIONS to save some memory. + */ +#define MAX_DWT_LEVELS 5 + +/** + * Parse code values: + * + * Dirac Specification -> + * 9.6.1 Table 9.1 + * + * VC-2 Specification -> + * 10.4.1 Table 10.1 + */ + +enum DiracParseCodes { + DIRAC_PCODE_SEQ_HEADER = 0x00, + DIRAC_PCODE_END_SEQ = 0x10, + DIRAC_PCODE_AUX = 0x20, + DIRAC_PCODE_PAD = 0x30, + DIRAC_PCODE_PICTURE_CODED = 0x08, + DIRAC_PCODE_PICTURE_RAW = 0x48, + DIRAC_PCODE_PICTURE_LOW_DEL = 0xC8, + DIRAC_PCODE_PICTURE_HQ = 0xE8, + DIRAC_PCODE_INTER_NOREF_CO1 = 0x0A, + DIRAC_PCODE_INTER_NOREF_CO2 = 0x09, + DIRAC_PCODE_INTER_REF_CO1 = 0x0D, + DIRAC_PCODE_INTER_REF_CO2 = 0x0E, + DIRAC_PCODE_INTRA_REF_CO = 0x0C, + DIRAC_PCODE_INTRA_REF_RAW = 0x4C, + DIRAC_PCODE_INTRA_REF_PICT = 0xCC, + DIRAC_PCODE_MAGIC = 0x42424344, +}; + +typedef struct DiracVersionInfo { + int major; + int minor; +} DiracVersionInfo; + +typedef struct AVDiracSeqHeader { + unsigned width; + unsigned height; + uint8_t chroma_format; ///< 0: 444 1: 422 2: 420 + + uint8_t interlaced; + uint8_t top_field_first; + + uint8_t frame_rate_index; ///< index into dirac_frame_rate[] + uint8_t aspect_ratio_index; ///< index into dirac_aspect_ratio[] + + uint16_t clean_width; + uint16_t clean_height; + uint16_t clean_left_offset; + uint16_t clean_right_offset; + + uint8_t pixel_range_index; ///< index into dirac_pixel_range_presets[] + uint8_t color_spec_index; ///< index into dirac_color_spec_presets[] + + int profile; + int level; + + AVRational framerate; + AVRational sample_aspect_ratio; + + enum AVPixelFormat pix_fmt; + enum AVColorRange color_range; + enum AVColorPrimaries color_primaries; + enum AVColorTransferCharacteristic color_trc; + enum AVColorSpace colorspace; + + DiracVersionInfo version; + int bit_depth; +} AVDiracSeqHeader; + +/** + * Parse a Dirac sequence header. + * + * @param dsh this function will allocate and fill an AVDiracSeqHeader struct + * and write it into this pointer. The caller must free it with + * av_free(). + * @param buf the data buffer + * @param buf_size the size of the data buffer in bytes + * @param log_ctx if non-NULL, this function will log errors here + * @return 0 on success, a negative AVERROR code on failure + */ +int av_dirac_parse_sequence_header(AVDiracSeqHeader **dsh, + const uint8_t *buf, size_t buf_size, + void *log_ctx); + +#endif /* AVCODEC_DIRAC_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/dv_profile.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/dv_profile.h new file mode 100644 index 0000000..9380a66 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/dv_profile.h @@ -0,0 +1,83 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DV_PROFILE_H +#define AVCODEC_DV_PROFILE_H + +#include + +#include "libavutil/pixfmt.h" +#include "libavutil/rational.h" +#include "avcodec.h" + +/* minimum number of bytes to read from a DV stream in order to + * determine the profile */ +#define DV_PROFILE_BYTES (6 * 80) /* 6 DIF blocks */ + + +/* + * AVDVProfile is used to express the differences between various + * DV flavors. For now it's primarily used for differentiating + * 525/60 and 625/50, but the plans are to use it for various + * DV specs as well (e.g. SMPTE314M vs. IEC 61834). + */ +typedef struct AVDVProfile { + int dsf; /* value of the dsf in the DV header */ + int video_stype; /* stype for VAUX source pack */ + int frame_size; /* total size of one frame in bytes */ + int difseg_size; /* number of DIF segments per DIF channel */ + int n_difchan; /* number of DIF channels per frame */ + AVRational time_base; /* 1/framerate */ + int ltc_divisor; /* FPS from the LTS standpoint */ + int height; /* picture height in pixels */ + int width; /* picture width in pixels */ + AVRational sar[2]; /* sample aspect ratios for 4:3 and 16:9 */ + enum AVPixelFormat pix_fmt; /* picture pixel format */ + int bpm; /* blocks per macroblock */ + const uint8_t *block_sizes; /* AC block sizes, in bits */ + int audio_stride; /* size of audio_shuffle table */ + int audio_min_samples[3]; /* min amount of audio samples */ + /* for 48kHz, 44.1kHz and 32kHz */ + int audio_samples_dist[5]; /* how many samples are supposed to be */ + /* in each frame in a 5 frames window */ + const uint8_t (*audio_shuffle)[9]; /* PCM shuffling table */ +} AVDVProfile; + +/** + * Get a DV profile for the provided compressed frame. + * + * @param sys the profile used for the previous frame, may be NULL + * @param frame the compressed data buffer + * @param buf_size size of the buffer in bytes + * @return the DV profile for the supplied data or NULL on failure + */ +const AVDVProfile *av_dv_frame_profile(const AVDVProfile *sys, + const uint8_t *frame, unsigned buf_size); + +/** + * Get a DV profile for the provided stream parameters. + */ +const AVDVProfile *av_dv_codec_profile(int width, int height, enum AVPixelFormat pix_fmt); + +/** + * Get a DV profile for the provided stream parameters. + * The frame rate is used as a best-effort parameter. + */ +const AVDVProfile *av_dv_codec_profile2(int width, int height, enum AVPixelFormat pix_fmt, AVRational frame_rate); + +#endif /* AVCODEC_DV_PROFILE_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/dxva2.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/dxva2.h new file mode 100644 index 0000000..22c9399 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/dxva2.h @@ -0,0 +1,93 @@ +/* + * DXVA2 HW acceleration + * + * copyright (c) 2009 Laurent Aimar + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DXVA2_H +#define AVCODEC_DXVA2_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_dxva2 + * Public libavcodec DXVA2 header. + */ + +#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0602 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0602 +#endif + +#include +#include +#include + +/** + * @defgroup lavc_codec_hwaccel_dxva2 DXVA2 + * @ingroup lavc_codec_hwaccel + * + * @{ + */ + +#define FF_DXVA2_WORKAROUND_SCALING_LIST_ZIGZAG 1 ///< Work around for DXVA2 and old UVD/UVD+ ATI video cards +#define FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO 2 ///< Work around for DXVA2 and old Intel GPUs with ClearVideo interface + +/** + * This structure is used to provides the necessary configurations and data + * to the DXVA2 FFmpeg HWAccel implementation. + * + * The application must make it available as AVCodecContext.hwaccel_context. + */ +struct dxva_context { + /** + * DXVA2 decoder object + */ + IDirectXVideoDecoder *decoder; + + /** + * DXVA2 configuration used to create the decoder + */ + const DXVA2_ConfigPictureDecode *cfg; + + /** + * The number of surface in the surface array + */ + unsigned surface_count; + + /** + * The array of Direct3D surfaces used to create the decoder + */ + LPDIRECT3DSURFACE9 *surface; + + /** + * A bit field configuring the workarounds needed for using the decoder + */ + uint64_t workaround; + + /** + * Private to the FFmpeg AVHWAccel implementation + */ + unsigned report_id; +}; + +/** + * @} + */ + +#endif /* AVCODEC_DXVA2_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/jni.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/jni.h new file mode 100644 index 0000000..dd99e92 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/jni.h @@ -0,0 +1,46 @@ +/* + * JNI public API functions + * + * Copyright (c) 2015-2016 Matthieu Bouron + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_JNI_H +#define AVCODEC_JNI_H + +/* + * Manually set a Java virtual machine which will be used to retrieve the JNI + * environment. Once a Java VM is set it cannot be changed afterwards, meaning + * you can call multiple times av_jni_set_java_vm with the same Java VM pointer + * however it will error out if you try to set a different Java VM. + * + * @param vm Java virtual machine + * @param log_ctx context used for logging, can be NULL + * @return 0 on success, < 0 otherwise + */ +int av_jni_set_java_vm(void *vm, void *log_ctx); + +/* + * Get the Java virtual machine which has been set with av_jni_set_java_vm. + * + * @param vm Java virtual machine + * @return a pointer to the Java virtual machine + */ +void *av_jni_get_java_vm(void *log_ctx); + +#endif /* AVCODEC_JNI_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/mediacodec.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/mediacodec.h new file mode 100644 index 0000000..5606d24 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/mediacodec.h @@ -0,0 +1,88 @@ +/* + * Android MediaCodec public API + * + * Copyright (c) 2016 Matthieu Bouron + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_MEDIACODEC_H +#define AVCODEC_MEDIACODEC_H + +#include "libavcodec/avcodec.h" + +/** + * This structure holds a reference to a android/view/Surface object that will + * be used as output by the decoder. + * + */ +typedef struct AVMediaCodecContext { + + /** + * android/view/Surface object reference. + */ + void *surface; + +} AVMediaCodecContext; + +/** + * Allocate and initialize a MediaCodec context. + * + * When decoding with MediaCodec is finished, the caller must free the + * MediaCodec context with av_mediacodec_default_free. + * + * @return a pointer to a newly allocated AVMediaCodecContext on success, NULL otherwise + */ +AVMediaCodecContext *av_mediacodec_alloc_context(void); + +/** + * Convenience function that sets up the MediaCodec context. + * + * @param avctx codec context + * @param ctx MediaCodec context to initialize + * @param surface reference to an android/view/Surface + * @return 0 on success, < 0 otherwise + */ +int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx, void *surface); + +/** + * This function must be called to free the MediaCodec context initialized with + * av_mediacodec_default_init(). + * + * @param avctx codec context + */ +void av_mediacodec_default_free(AVCodecContext *avctx); + +/** + * Opaque structure representing a MediaCodec buffer to render. + */ +typedef struct MediaCodecBuffer AVMediaCodecBuffer; + +/** + * Release a MediaCodec buffer and render it to the surface that is associated + * with the decoder. This function should only be called once on a given + * buffer, once released the underlying buffer returns to the codec, thus + * subsequent calls to this function will have no effect. + * + * @param buffer the buffer to render + * @param render 1 to release and render the buffer to the surface or 0 to + * discard the buffer + * @return 0 on success, < 0 otherwise + */ +int av_mediacodec_release_buffer(AVMediaCodecBuffer *buffer, int render); + +#endif /* AVCODEC_MEDIACODEC_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/qsv.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/qsv.h new file mode 100644 index 0000000..b77158e --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/qsv.h @@ -0,0 +1,107 @@ +/* + * Intel MediaSDK QSV public API + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_QSV_H +#define AVCODEC_QSV_H + +#include + +#include "libavutil/buffer.h" + +/** + * This struct is used for communicating QSV parameters between libavcodec and + * the caller. It is managed by the caller and must be assigned to + * AVCodecContext.hwaccel_context. + * - decoding: hwaccel_context must be set on return from the get_format() + * callback + * - encoding: hwaccel_context must be set before avcodec_open2() + */ +typedef struct AVQSVContext { + /** + * If non-NULL, the session to use for encoding or decoding. + * Otherwise, libavcodec will try to create an internal session. + */ + mfxSession session; + + /** + * The IO pattern to use. + */ + int iopattern; + + /** + * Extra buffers to pass to encoder or decoder initialization. + */ + mfxExtBuffer **ext_buffers; + int nb_ext_buffers; + + /** + * Encoding only. If this field is set to non-zero by the caller, libavcodec + * will create an mfxExtOpaqueSurfaceAlloc extended buffer and pass it to + * the encoder initialization. This only makes sense if iopattern is also + * set to MFX_IOPATTERN_IN_OPAQUE_MEMORY. + * + * The number of allocated opaque surfaces will be the sum of the number + * required by the encoder and the user-provided value nb_opaque_surfaces. + * The array of the opaque surfaces will be exported to the caller through + * the opaque_surfaces field. + */ + int opaque_alloc; + + /** + * Encoding only, and only if opaque_alloc is set to non-zero. Before + * calling avcodec_open2(), the caller should set this field to the number + * of extra opaque surfaces to allocate beyond what is required by the + * encoder. + * + * On return from avcodec_open2(), this field will be set by libavcodec to + * the total number of allocated opaque surfaces. + */ + int nb_opaque_surfaces; + + /** + * Encoding only, and only if opaque_alloc is set to non-zero. On return + * from avcodec_open2(), this field will be used by libavcodec to export the + * array of the allocated opaque surfaces to the caller, so they can be + * passed to other parts of the pipeline. + * + * The buffer reference exported here is owned and managed by libavcodec, + * the callers should make their own reference with av_buffer_ref() and free + * it with av_buffer_unref() when it is no longer needed. + * + * The buffer data is an nb_opaque_surfaces-sized array of mfxFrameSurface1. + */ + AVBufferRef *opaque_surfaces; + + /** + * Encoding only, and only if opaque_alloc is set to non-zero. On return + * from avcodec_open2(), this field will be set to the surface type used in + * the opaque allocation request. + */ + int opaque_alloc_type; +} AVQSVContext; + +/** + * Allocate a new context. + * + * It must be freed by the caller with av_free(). + */ +AVQSVContext *av_qsv_alloc_context(void); + +#endif /* AVCODEC_QSV_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/vaapi.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/vaapi.h new file mode 100644 index 0000000..bb28455 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/vaapi.h @@ -0,0 +1,195 @@ +/* + * Video Acceleration API (shared data between FFmpeg and the video player) + * HW decode acceleration for MPEG-2, MPEG-4, H.264 and VC-1 + * + * Copyright (C) 2008-2009 Splitted-Desktop Systems + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VAAPI_H +#define AVCODEC_VAAPI_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_vaapi + * Public libavcodec VA API header. + */ + +#include +#include "libavutil/attributes.h" +#include "version.h" + +#if FF_API_STRUCT_VAAPI_CONTEXT + +/** + * @defgroup lavc_codec_hwaccel_vaapi VA API Decoding + * @ingroup lavc_codec_hwaccel + * @{ + */ + +/** + * This structure is used to share data between the FFmpeg library and + * the client video application. + * This shall be zero-allocated and available as + * AVCodecContext.hwaccel_context. All user members can be set once + * during initialization or through each AVCodecContext.get_buffer() + * function call. In any case, they must be valid prior to calling + * decoding functions. + * + * Deprecated: use AVCodecContext.hw_frames_ctx instead. + */ +struct attribute_deprecated vaapi_context { + /** + * Window system dependent data + * + * - encoding: unused + * - decoding: Set by user + */ + void *display; + + /** + * Configuration ID + * + * - encoding: unused + * - decoding: Set by user + */ + uint32_t config_id; + + /** + * Context ID (video decode pipeline) + * + * - encoding: unused + * - decoding: Set by user + */ + uint32_t context_id; + +#if FF_API_VAAPI_CONTEXT + /** + * VAPictureParameterBuffer ID + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + uint32_t pic_param_buf_id; + + /** + * VAIQMatrixBuffer ID + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + uint32_t iq_matrix_buf_id; + + /** + * VABitPlaneBuffer ID (for VC-1 decoding) + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + uint32_t bitplane_buf_id; + + /** + * Slice parameter/data buffer IDs + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + uint32_t *slice_buf_ids; + + /** + * Number of effective slice buffer IDs to send to the HW + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + unsigned int n_slice_buf_ids; + + /** + * Size of pre-allocated slice_buf_ids + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + unsigned int slice_buf_ids_alloc; + + /** + * Pointer to VASliceParameterBuffers + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + void *slice_params; + + /** + * Size of a VASliceParameterBuffer element + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + unsigned int slice_param_size; + + /** + * Size of pre-allocated slice_params + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + unsigned int slice_params_alloc; + + /** + * Number of slices currently filled in + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + unsigned int slice_count; + + /** + * Pointer to slice data buffer base + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + const uint8_t *slice_data; + + /** + * Current size of slice data + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + uint32_t slice_data_size; +#endif +}; + +/* @} */ + +#endif /* FF_API_STRUCT_VAAPI_CONTEXT */ + +#endif /* AVCODEC_VAAPI_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/vda.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/vda.h new file mode 100644 index 0000000..bde14e3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/vda.h @@ -0,0 +1,230 @@ +/* + * VDA HW acceleration + * + * copyright (c) 2011 Sebastien Zwickert + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VDA_H +#define AVCODEC_VDA_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_vda + * Public libavcodec VDA header. + */ + +#include "libavcodec/avcodec.h" + +#include + +// emmintrin.h is unable to compile with -std=c99 -Werror=missing-prototypes +// http://openradar.appspot.com/8026390 +#undef __GNUC_STDC_INLINE__ + +#define Picture QuickdrawPicture +#include +#undef Picture + +#include "libavcodec/version.h" + +// extra flags not defined in VDADecoder.h +enum { + kVDADecodeInfo_Asynchronous = 1UL << 0, + kVDADecodeInfo_FrameDropped = 1UL << 1 +}; + +/** + * @defgroup lavc_codec_hwaccel_vda VDA + * @ingroup lavc_codec_hwaccel + * + * @{ + */ + +/** + * This structure is used to provide the necessary configurations and data + * to the VDA FFmpeg HWAccel implementation. + * + * The application must make it available as AVCodecContext.hwaccel_context. + */ +struct vda_context { + /** + * VDA decoder object. + * + * - encoding: unused + * - decoding: Set/Unset by libavcodec. + */ + VDADecoder decoder; + + /** + * The Core Video pixel buffer that contains the current image data. + * + * encoding: unused + * decoding: Set by libavcodec. Unset by user. + */ + CVPixelBufferRef cv_buffer; + + /** + * Use the hardware decoder in synchronous mode. + * + * encoding: unused + * decoding: Set by user. + */ + int use_sync_decoding; + + /** + * The frame width. + * + * - encoding: unused + * - decoding: Set/Unset by user. + */ + int width; + + /** + * The frame height. + * + * - encoding: unused + * - decoding: Set/Unset by user. + */ + int height; + + /** + * The frame format. + * + * - encoding: unused + * - decoding: Set/Unset by user. + */ + int format; + + /** + * The pixel format for output image buffers. + * + * - encoding: unused + * - decoding: Set/Unset by user. + */ + OSType cv_pix_fmt_type; + + /** + * unused + */ + uint8_t *priv_bitstream; + + /** + * unused + */ + int priv_bitstream_size; + + /** + * unused + */ + int priv_allocated_size; + + /** + * Use av_buffer to manage buffer. + * When the flag is set, the CVPixelBuffers returned by the decoder will + * be released automatically, so you have to retain them if necessary. + * Not setting this flag may cause memory leak. + * + * encoding: unused + * decoding: Set by user. + */ + int use_ref_buffer; +}; + +/** Create the video decoder. */ +int ff_vda_create_decoder(struct vda_context *vda_ctx, + uint8_t *extradata, + int extradata_size); + +/** Destroy the video decoder. */ +int ff_vda_destroy_decoder(struct vda_context *vda_ctx); + +/** + * This struct holds all the information that needs to be passed + * between the caller and libavcodec for initializing VDA decoding. + * Its size is not a part of the public ABI, it must be allocated with + * av_vda_alloc_context() and freed with av_free(). + */ +typedef struct AVVDAContext { + /** + * VDA decoder object. Created and freed by the caller. + */ + VDADecoder decoder; + + /** + * The output callback that must be passed to VDADecoderCreate. + * Set by av_vda_alloc_context(). + */ + VDADecoderOutputCallback output_callback; + + /** + * CVPixelBuffer Format Type that VDA will use for decoded frames; set by + * the caller. + */ + OSType cv_pix_fmt_type; +} AVVDAContext; + +/** + * Allocate and initialize a VDA context. + * + * This function should be called from the get_format() callback when the caller + * selects the AV_PIX_FMT_VDA format. The caller must then create the decoder + * object (using the output callback provided by libavcodec) that will be used + * for VDA-accelerated decoding. + * + * When decoding with VDA is finished, the caller must destroy the decoder + * object and free the VDA context using av_free(). + * + * @return the newly allocated context or NULL on failure + */ +AVVDAContext *av_vda_alloc_context(void); + +/** + * This is a convenience function that creates and sets up the VDA context using + * an internal implementation. + * + * @param avctx the corresponding codec context + * + * @return >= 0 on success, a negative AVERROR code on failure + */ +int av_vda_default_init(AVCodecContext *avctx); + +/** + * This is a convenience function that creates and sets up the VDA context using + * an internal implementation. + * + * @param avctx the corresponding codec context + * @param vdactx the VDA context to use + * + * @return >= 0 on success, a negative AVERROR code on failure + */ +int av_vda_default_init2(AVCodecContext *avctx, AVVDAContext *vdactx); + +/** + * This function must be called to free the VDA context initialized with + * av_vda_default_init(). + * + * @param avctx the corresponding codec context + */ +void av_vda_default_free(AVCodecContext *avctx); + +/** + * @} + */ + +#endif /* AVCODEC_VDA_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/vdpau.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/vdpau.h new file mode 100644 index 0000000..e85e4d9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/vdpau.h @@ -0,0 +1,253 @@ +/* + * The Video Decode and Presentation API for UNIX (VDPAU) is used for + * hardware-accelerated decoding of MPEG-1/2, H.264 and VC-1. + * + * Copyright (C) 2008 NVIDIA + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VDPAU_H +#define AVCODEC_VDPAU_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_vdpau + * Public libavcodec VDPAU header. + */ + + +/** + * @defgroup lavc_codec_hwaccel_vdpau VDPAU Decoder and Renderer + * @ingroup lavc_codec_hwaccel + * + * VDPAU hardware acceleration has two modules + * - VDPAU decoding + * - VDPAU presentation + * + * The VDPAU decoding module parses all headers using FFmpeg + * parsing mechanisms and uses VDPAU for the actual decoding. + * + * As per the current implementation, the actual decoding + * and rendering (API calls) are done as part of the VDPAU + * presentation (vo_vdpau.c) module. + * + * @{ + */ + +#include +#include +#include "libavutil/avconfig.h" +#include "libavutil/attributes.h" + +#include "avcodec.h" +#include "version.h" + +#if FF_API_BUFS_VDPAU +union AVVDPAUPictureInfo { + VdpPictureInfoH264 h264; + VdpPictureInfoMPEG1Or2 mpeg; + VdpPictureInfoVC1 vc1; + VdpPictureInfoMPEG4Part2 mpeg4; +}; +#endif + +struct AVCodecContext; +struct AVFrame; + +typedef int (*AVVDPAU_Render2)(struct AVCodecContext *, struct AVFrame *, + const VdpPictureInfo *, uint32_t, + const VdpBitstreamBuffer *); + +/** + * This structure is used to share data between the libavcodec library and + * the client video application. + * The user shall allocate the structure via the av_alloc_vdpau_hwaccel + * function and make it available as + * AVCodecContext.hwaccel_context. Members can be set by the user once + * during initialization or through each AVCodecContext.get_buffer() + * function call. In any case, they must be valid prior to calling + * decoding functions. + * + * The size of this structure is not a part of the public ABI and must not + * be used outside of libavcodec. Use av_vdpau_alloc_context() to allocate an + * AVVDPAUContext. + */ +typedef struct AVVDPAUContext { + /** + * VDPAU decoder handle + * + * Set by user. + */ + VdpDecoder decoder; + + /** + * VDPAU decoder render callback + * + * Set by the user. + */ + VdpDecoderRender *render; + +#if FF_API_BUFS_VDPAU + /** + * VDPAU picture information + * + * Set by libavcodec. + */ + attribute_deprecated + union AVVDPAUPictureInfo info; + + /** + * Allocated size of the bitstream_buffers table. + * + * Set by libavcodec. + */ + attribute_deprecated + int bitstream_buffers_allocated; + + /** + * Useful bitstream buffers in the bitstream buffers table. + * + * Set by libavcodec. + */ + attribute_deprecated + int bitstream_buffers_used; + + /** + * Table of bitstream buffers. + * The user is responsible for freeing this buffer using av_freep(). + * + * Set by libavcodec. + */ + attribute_deprecated + VdpBitstreamBuffer *bitstream_buffers; +#endif + AVVDPAU_Render2 render2; +} AVVDPAUContext; + +/** + * @brief allocation function for AVVDPAUContext + * + * Allows extending the struct without breaking API/ABI + */ +AVVDPAUContext *av_alloc_vdpaucontext(void); + +AVVDPAU_Render2 av_vdpau_hwaccel_get_render2(const AVVDPAUContext *); +void av_vdpau_hwaccel_set_render2(AVVDPAUContext *, AVVDPAU_Render2); + +/** + * Associate a VDPAU device with a codec context for hardware acceleration. + * This function is meant to be called from the get_format() codec callback, + * or earlier. It can also be called after avcodec_flush_buffers() to change + * the underlying VDPAU device mid-stream (e.g. to recover from non-transparent + * display preemption). + * + * @note get_format() must return AV_PIX_FMT_VDPAU if this function completes + * successfully. + * + * @param avctx decoding context whose get_format() callback is invoked + * @param device VDPAU device handle to use for hardware acceleration + * @param get_proc_address VDPAU device driver + * @param flags zero of more OR'd AV_HWACCEL_FLAG_* flags + * + * @return 0 on success, an AVERROR code on failure. + */ +int av_vdpau_bind_context(AVCodecContext *avctx, VdpDevice device, + VdpGetProcAddress *get_proc_address, unsigned flags); + +/** + * Gets the parameters to create an adequate VDPAU video surface for the codec + * context using VDPAU hardware decoding acceleration. + * + * @note Behavior is undefined if the context was not successfully bound to a + * VDPAU device using av_vdpau_bind_context(). + * + * @param avctx the codec context being used for decoding the stream + * @param type storage space for the VDPAU video surface chroma type + * (or NULL to ignore) + * @param width storage space for the VDPAU video surface pixel width + * (or NULL to ignore) + * @param height storage space for the VDPAU video surface pixel height + * (or NULL to ignore) + * + * @return 0 on success, a negative AVERROR code on failure. + */ +int av_vdpau_get_surface_parameters(AVCodecContext *avctx, VdpChromaType *type, + uint32_t *width, uint32_t *height); + +/** + * Allocate an AVVDPAUContext. + * + * @return Newly-allocated AVVDPAUContext or NULL on failure. + */ +AVVDPAUContext *av_vdpau_alloc_context(void); + +#if FF_API_VDPAU_PROFILE +/** + * Get a decoder profile that should be used for initializing a VDPAU decoder. + * Should be called from the AVCodecContext.get_format() callback. + * + * @deprecated Use av_vdpau_bind_context() instead. + * + * @param avctx the codec context being used for decoding the stream + * @param profile a pointer into which the result will be written on success. + * The contents of profile are undefined if this function returns + * an error. + * + * @return 0 on success (non-negative), a negative AVERROR on failure. + */ +attribute_deprecated +int av_vdpau_get_profile(AVCodecContext *avctx, VdpDecoderProfile *profile); +#endif + +#if FF_API_CAP_VDPAU +/** @brief The videoSurface is used for rendering. */ +#define FF_VDPAU_STATE_USED_FOR_RENDER 1 + +/** + * @brief The videoSurface is needed for reference/prediction. + * The codec manipulates this. + */ +#define FF_VDPAU_STATE_USED_FOR_REFERENCE 2 + +/** + * @brief This structure is used as a callback between the FFmpeg + * decoder (vd_) and presentation (vo_) module. + * This is used for defining a video frame containing surface, + * picture parameter, bitstream information etc which are passed + * between the FFmpeg decoder and its clients. + */ +struct vdpau_render_state { + VdpVideoSurface surface; ///< Used as rendered surface, never changed. + + int state; ///< Holds FF_VDPAU_STATE_* values. + + /** picture parameter information for all supported codecs */ + union AVVDPAUPictureInfo info; + + /** Describe size/location of the compressed video data. + Set to 0 when freeing bitstream_buffers. */ + int bitstream_buffers_allocated; + int bitstream_buffers_used; + /** The user is responsible for freeing this buffer using av_freep(). */ + VdpBitstreamBuffer *bitstream_buffers; +}; +#endif + +/* @}*/ + +#endif /* AVCODEC_VDPAU_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/version.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/version.h new file mode 100644 index 0000000..51df9e0 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/version.h @@ -0,0 +1,243 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VERSION_H +#define AVCODEC_VERSION_H + +/** + * @file + * @ingroup libavc + * Libavcodec version macros. + */ + +#include "libavutil/version.h" + +#define LIBAVCODEC_VERSION_MAJOR 57 +#define LIBAVCODEC_VERSION_MINOR 89 +#define LIBAVCODEC_VERSION_MICRO 100 + +#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ + LIBAVCODEC_VERSION_MINOR, \ + LIBAVCODEC_VERSION_MICRO) +#define LIBAVCODEC_VERSION AV_VERSION(LIBAVCODEC_VERSION_MAJOR, \ + LIBAVCODEC_VERSION_MINOR, \ + LIBAVCODEC_VERSION_MICRO) +#define LIBAVCODEC_BUILD LIBAVCODEC_VERSION_INT + +#define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION) + +/** + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + * + * @note, when bumping the major version it is recommended to manually + * disable each FF_API_* in its own commit instead of disabling them all + * at once through the bump. This improves the git bisect-ability of the change. + */ + +#ifndef FF_API_VIMA_DECODER +#define FF_API_VIMA_DECODER (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_AUDIO_CONVERT +#define FF_API_AUDIO_CONVERT (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_AVCODEC_RESAMPLE +#define FF_API_AVCODEC_RESAMPLE FF_API_AUDIO_CONVERT +#endif +#ifndef FF_API_GETCHROMA +#define FF_API_GETCHROMA (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_MISSING_SAMPLE +#define FF_API_MISSING_SAMPLE (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_LOWRES +#define FF_API_LOWRES (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_CAP_VDPAU +#define FF_API_CAP_VDPAU (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_BUFS_VDPAU +#define FF_API_BUFS_VDPAU (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_VOXWARE +#define FF_API_VOXWARE (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_SET_DIMENSIONS +#define FF_API_SET_DIMENSIONS (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_DEBUG_MV +#define FF_API_DEBUG_MV (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_AC_VLC +#define FF_API_AC_VLC (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_OLD_MSMPEG4 +#define FF_API_OLD_MSMPEG4 (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_ASPECT_EXTENDED +#define FF_API_ASPECT_EXTENDED (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_ARCH_ALPHA +#define FF_API_ARCH_ALPHA (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_XVMC +#define FF_API_XVMC (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_ERROR_RATE +#define FF_API_ERROR_RATE (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_QSCALE_TYPE +#define FF_API_QSCALE_TYPE (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_MB_TYPE +#define FF_API_MB_TYPE (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_MAX_BFRAMES +#define FF_API_MAX_BFRAMES (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_NEG_LINESIZES +#define FF_API_NEG_LINESIZES (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_EMU_EDGE +#define FF_API_EMU_EDGE (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_ARCH_SH4 +#define FF_API_ARCH_SH4 (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_ARCH_SPARC +#define FF_API_ARCH_SPARC (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_UNUSED_MEMBERS +#define FF_API_UNUSED_MEMBERS (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_IDCT_XVIDMMX +#define FF_API_IDCT_XVIDMMX (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_INPUT_PRESERVED +#define FF_API_INPUT_PRESERVED (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_NORMALIZE_AQP +#define FF_API_NORMALIZE_AQP (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_GMC +#define FF_API_GMC (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_MV0 +#define FF_API_MV0 (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_CODEC_NAME +#define FF_API_CODEC_NAME (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_AFD +#define FF_API_AFD (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_VISMV +/* XXX: don't forget to drop the -vismv documentation */ +#define FF_API_VISMV (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_AUDIOENC_DELAY +#define FF_API_AUDIOENC_DELAY (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_VAAPI_CONTEXT +#define FF_API_VAAPI_CONTEXT (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_MERGE_SD +#define FF_API_MERGE_SD (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_AVCTX_TIMEBASE +#define FF_API_AVCTX_TIMEBASE (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_MPV_OPT +#define FF_API_MPV_OPT (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_STREAM_CODEC_TAG +#define FF_API_STREAM_CODEC_TAG (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_QUANT_BIAS +#define FF_API_QUANT_BIAS (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_RC_STRATEGY +#define FF_API_RC_STRATEGY (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_CODED_FRAME +#define FF_API_CODED_FRAME (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_MOTION_EST +#define FF_API_MOTION_EST (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_WITHOUT_PREFIX +#define FF_API_WITHOUT_PREFIX (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_SIDEDATA_ONLY_PKT +#define FF_API_SIDEDATA_ONLY_PKT (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_VDPAU_PROFILE +#define FF_API_VDPAU_PROFILE (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_CONVERGENCE_DURATION +#define FF_API_CONVERGENCE_DURATION (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_AVPICTURE +#define FF_API_AVPICTURE (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_AVPACKET_OLD_API +#define FF_API_AVPACKET_OLD_API (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_RTP_CALLBACK +#define FF_API_RTP_CALLBACK (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_VBV_DELAY +#define FF_API_VBV_DELAY (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_CODER_TYPE +#define FF_API_CODER_TYPE (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_STAT_BITS +#define FF_API_STAT_BITS (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_PRIVATE_OPT +#define FF_API_PRIVATE_OPT (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_ASS_TIMING +#define FF_API_ASS_TIMING (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_OLD_BSF +#define FF_API_OLD_BSF (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_COPY_CONTEXT +#define FF_API_COPY_CONTEXT (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_GET_CONTEXT_DEFAULTS +#define FF_API_GET_CONTEXT_DEFAULTS (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_NVENC_OLD_NAME +#define FF_API_NVENC_OLD_NAME (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_STRUCT_VAAPI_CONTEXT +#define FF_API_STRUCT_VAAPI_CONTEXT (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_MERGE_SD_API +#define FF_API_MERGE_SD_API (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_TAG_STRING +#define FF_API_TAG_STRING (LIBAVCODEC_VERSION_MAJOR < 59) +#endif + + +#endif /* AVCODEC_VERSION_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/videotoolbox.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/videotoolbox.h new file mode 100644 index 0000000..af2db0d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/videotoolbox.h @@ -0,0 +1,127 @@ +/* + * Videotoolbox hardware acceleration + * + * copyright (c) 2012 Sebastien Zwickert + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VIDEOTOOLBOX_H +#define AVCODEC_VIDEOTOOLBOX_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_videotoolbox + * Public libavcodec Videotoolbox header. + */ + +#include + +#define Picture QuickdrawPicture +#include +#undef Picture + +#include "libavcodec/avcodec.h" + +/** + * This struct holds all the information that needs to be passed + * between the caller and libavcodec for initializing Videotoolbox decoding. + * Its size is not a part of the public ABI, it must be allocated with + * av_videotoolbox_alloc_context() and freed with av_free(). + */ +typedef struct AVVideotoolboxContext { + /** + * Videotoolbox decompression session object. + * Created and freed the caller. + */ + VTDecompressionSessionRef session; + + /** + * The output callback that must be passed to the session. + * Set by av_videottoolbox_default_init() + */ + VTDecompressionOutputCallback output_callback; + + /** + * CVPixelBuffer Format Type that Videotoolbox will use for decoded frames. + * set by the caller. If this is set to 0, then no specific format is + * requested from the decoder, and its native format is output. + */ + OSType cv_pix_fmt_type; + + /** + * CoreMedia Format Description that Videotoolbox will use to create the decompression session. + * Set by the caller. + */ + CMVideoFormatDescriptionRef cm_fmt_desc; + + /** + * CoreMedia codec type that Videotoolbox will use to create the decompression session. + * Set by the caller. + */ + int cm_codec_type; +} AVVideotoolboxContext; + +/** + * Allocate and initialize a Videotoolbox context. + * + * This function should be called from the get_format() callback when the caller + * selects the AV_PIX_FMT_VIDETOOLBOX format. The caller must then create + * the decoder object (using the output callback provided by libavcodec) that + * will be used for Videotoolbox-accelerated decoding. + * + * When decoding with Videotoolbox is finished, the caller must destroy the decoder + * object and free the Videotoolbox context using av_free(). + * + * @return the newly allocated context or NULL on failure + */ +AVVideotoolboxContext *av_videotoolbox_alloc_context(void); + +/** + * This is a convenience function that creates and sets up the Videotoolbox context using + * an internal implementation. + * + * @param avctx the corresponding codec context + * + * @return >= 0 on success, a negative AVERROR code on failure + */ +int av_videotoolbox_default_init(AVCodecContext *avctx); + +/** + * This is a convenience function that creates and sets up the Videotoolbox context using + * an internal implementation. + * + * @param avctx the corresponding codec context + * @param vtctx the Videotoolbox context to use + * + * @return >= 0 on success, a negative AVERROR code on failure + */ +int av_videotoolbox_default_init2(AVCodecContext *avctx, AVVideotoolboxContext *vtctx); + +/** + * This function must be called to free the Videotoolbox context initialized with + * av_videotoolbox_default_init(). + * + * @param avctx the corresponding codec context + */ +void av_videotoolbox_default_free(AVCodecContext *avctx); + +/** + * @} + */ + +#endif /* AVCODEC_VIDEOTOOLBOX_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/vorbis_parser.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/vorbis_parser.h new file mode 100644 index 0000000..9205027 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/vorbis_parser.h @@ -0,0 +1,77 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * A public API for Vorbis parsing + * + * Determines the duration for each packet. + */ + +#ifndef AVCODEC_VORBIS_PARSER_H +#define AVCODEC_VORBIS_PARSER_H + +#include + +typedef struct AVVorbisParseContext AVVorbisParseContext; + +/** + * Allocate and initialize the Vorbis parser using headers in the extradata. + * + * @param avctx codec context + * @param s Vorbis parser context + */ +AVVorbisParseContext *av_vorbis_parse_init(const uint8_t *extradata, + int extradata_size); + +/** + * Free the parser and everything associated with it. + */ +void av_vorbis_parse_free(AVVorbisParseContext **s); + +#define VORBIS_FLAG_HEADER 0x00000001 +#define VORBIS_FLAG_COMMENT 0x00000002 +#define VORBIS_FLAG_SETUP 0x00000004 + +/** + * Get the duration for a Vorbis packet. + * + * If @p flags is @c NULL, + * special frames are considered invalid. + * + * @param s Vorbis parser context + * @param buf buffer containing a Vorbis frame + * @param buf_size size of the buffer + * @param flags flags for special frames + */ +int av_vorbis_parse_frame_flags(AVVorbisParseContext *s, const uint8_t *buf, + int buf_size, int *flags); + +/** + * Get the duration for a Vorbis packet. + * + * @param s Vorbis parser context + * @param buf buffer containing a Vorbis frame + * @param buf_size size of the buffer + */ +int av_vorbis_parse_frame(AVVorbisParseContext *s, const uint8_t *buf, + int buf_size); + +void av_vorbis_parse_reset(AVVorbisParseContext *s); + +#endif /* AVCODEC_VORBIS_PARSER_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/xvmc.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/xvmc.h new file mode 100644 index 0000000..465ee78 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavcodec/xvmc.h @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2003 Ivan Kalvachev + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_XVMC_H +#define AVCODEC_XVMC_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_xvmc + * Public libavcodec XvMC header. + */ + +#include + +#include "libavutil/attributes.h" +#include "version.h" +#include "avcodec.h" + +/** + * @defgroup lavc_codec_hwaccel_xvmc XvMC + * @ingroup lavc_codec_hwaccel + * + * @{ + */ + +#define AV_XVMC_ID 0x1DC711C0 /**< special value to ensure that regular pixel routines haven't corrupted the struct + the number is 1337 speak for the letters IDCT MCo (motion compensation) */ + +struct attribute_deprecated xvmc_pix_fmt { + /** The field contains the special constant value AV_XVMC_ID. + It is used as a test that the application correctly uses the API, + and that there is no corruption caused by pixel routines. + - application - set during initialization + - libavcodec - unchanged + */ + int xvmc_id; + + /** Pointer to the block array allocated by XvMCCreateBlocks(). + The array has to be freed by XvMCDestroyBlocks(). + Each group of 64 values represents one data block of differential + pixel information (in MoCo mode) or coefficients for IDCT. + - application - set the pointer during initialization + - libavcodec - fills coefficients/pixel data into the array + */ + short* data_blocks; + + /** Pointer to the macroblock description array allocated by + XvMCCreateMacroBlocks() and freed by XvMCDestroyMacroBlocks(). + - application - set the pointer during initialization + - libavcodec - fills description data into the array + */ + XvMCMacroBlock* mv_blocks; + + /** Number of macroblock descriptions that can be stored in the mv_blocks + array. + - application - set during initialization + - libavcodec - unchanged + */ + int allocated_mv_blocks; + + /** Number of blocks that can be stored at once in the data_blocks array. + - application - set during initialization + - libavcodec - unchanged + */ + int allocated_data_blocks; + + /** Indicate that the hardware would interpret data_blocks as IDCT + coefficients and perform IDCT on them. + - application - set during initialization + - libavcodec - unchanged + */ + int idct; + + /** In MoCo mode it indicates that intra macroblocks are assumed to be in + unsigned format; same as the XVMC_INTRA_UNSIGNED flag. + - application - set during initialization + - libavcodec - unchanged + */ + int unsigned_intra; + + /** Pointer to the surface allocated by XvMCCreateSurface(). + It has to be freed by XvMCDestroySurface() on application exit. + It identifies the frame and its state on the video hardware. + - application - set during initialization + - libavcodec - unchanged + */ + XvMCSurface* p_surface; + +/** Set by the decoder before calling ff_draw_horiz_band(), + needed by the XvMCRenderSurface function. */ +//@{ + /** Pointer to the surface used as past reference + - application - unchanged + - libavcodec - set + */ + XvMCSurface* p_past_surface; + + /** Pointer to the surface used as future reference + - application - unchanged + - libavcodec - set + */ + XvMCSurface* p_future_surface; + + /** top/bottom field or frame + - application - unchanged + - libavcodec - set + */ + unsigned int picture_structure; + + /** XVMC_SECOND_FIELD - 1st or 2nd field in the sequence + - application - unchanged + - libavcodec - set + */ + unsigned int flags; +//}@ + + /** Number of macroblock descriptions in the mv_blocks array + that have already been passed to the hardware. + - application - zeroes it on get_buffer(). + A successful ff_draw_horiz_band() may increment it + with filled_mb_block_num or zero both. + - libavcodec - unchanged + */ + int start_mv_blocks_num; + + /** Number of new macroblock descriptions in the mv_blocks array (after + start_mv_blocks_num) that are filled by libavcodec and have to be + passed to the hardware. + - application - zeroes it on get_buffer() or after successful + ff_draw_horiz_band(). + - libavcodec - increment with one of each stored MB + */ + int filled_mv_blocks_num; + + /** Number of the next free data block; one data block consists of + 64 short values in the data_blocks array. + All blocks before this one have already been claimed by placing their + position into the corresponding block description structure field, + that are part of the mv_blocks array. + - application - zeroes it on get_buffer(). + A successful ff_draw_horiz_band() may zero it together + with start_mb_blocks_num. + - libavcodec - each decoded macroblock increases it by the number + of coded blocks it contains. + */ + int next_free_data_block_num; +}; + +/** + * @} + */ + +#endif /* AVCODEC_XVMC_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavdevice/avdevice.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavdevice/avdevice.h new file mode 100644 index 0000000..ee94624 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavdevice/avdevice.h @@ -0,0 +1,514 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVDEVICE_AVDEVICE_H +#define AVDEVICE_AVDEVICE_H + +#include "version.h" + +/** + * @file + * @ingroup lavd + * Main libavdevice API header + */ + +/** + * @defgroup lavd libavdevice + * Special devices muxing/demuxing library. + * + * Libavdevice is a complementary library to @ref libavf "libavformat". It + * provides various "special" platform-specific muxers and demuxers, e.g. for + * grabbing devices, audio capture and playback etc. As a consequence, the + * (de)muxers in libavdevice are of the AVFMT_NOFILE type (they use their own + * I/O functions). The filename passed to avformat_open_input() often does not + * refer to an actually existing file, but has some special device-specific + * meaning - e.g. for xcbgrab it is the display name. + * + * To use libavdevice, simply call avdevice_register_all() to register all + * compiled muxers and demuxers. They all use standard libavformat API. + * + * @{ + */ + +#include "libavutil/log.h" +#include "libavutil/opt.h" +#include "libavutil/dict.h" +#include "libavformat/avformat.h" + +/** + * Return the LIBAVDEVICE_VERSION_INT constant. + */ +unsigned avdevice_version(void); + +/** + * Return the libavdevice build-time configuration. + */ +const char *avdevice_configuration(void); + +/** + * Return the libavdevice license. + */ +const char *avdevice_license(void); + +/** + * Initialize libavdevice and register all the input and output devices. + */ +void avdevice_register_all(void); + +/** + * Audio input devices iterator. + * + * If d is NULL, returns the first registered input audio/video device, + * if d is non-NULL, returns the next registered input audio/video device after d + * or NULL if d is the last one. + */ +AVInputFormat *av_input_audio_device_next(AVInputFormat *d); + +/** + * Video input devices iterator. + * + * If d is NULL, returns the first registered input audio/video device, + * if d is non-NULL, returns the next registered input audio/video device after d + * or NULL if d is the last one. + */ +AVInputFormat *av_input_video_device_next(AVInputFormat *d); + +/** + * Audio output devices iterator. + * + * If d is NULL, returns the first registered output audio/video device, + * if d is non-NULL, returns the next registered output audio/video device after d + * or NULL if d is the last one. + */ +AVOutputFormat *av_output_audio_device_next(AVOutputFormat *d); + +/** + * Video output devices iterator. + * + * If d is NULL, returns the first registered output audio/video device, + * if d is non-NULL, returns the next registered output audio/video device after d + * or NULL if d is the last one. + */ +AVOutputFormat *av_output_video_device_next(AVOutputFormat *d); + +typedef struct AVDeviceRect { + int x; /**< x coordinate of top left corner */ + int y; /**< y coordinate of top left corner */ + int width; /**< width */ + int height; /**< height */ +} AVDeviceRect; + +/** + * Message types used by avdevice_app_to_dev_control_message(). + */ +enum AVAppToDevMessageType { + /** + * Dummy message. + */ + AV_APP_TO_DEV_NONE = MKBETAG('N','O','N','E'), + + /** + * Window size change message. + * + * Message is sent to the device every time the application changes the size + * of the window device renders to. + * Message should also be sent right after window is created. + * + * data: AVDeviceRect: new window size. + */ + AV_APP_TO_DEV_WINDOW_SIZE = MKBETAG('G','E','O','M'), + + /** + * Repaint request message. + * + * Message is sent to the device when window has to be repainted. + * + * data: AVDeviceRect: area required to be repainted. + * NULL: whole area is required to be repainted. + */ + AV_APP_TO_DEV_WINDOW_REPAINT = MKBETAG('R','E','P','A'), + + /** + * Request pause/play. + * + * Application requests pause/unpause playback. + * Mostly usable with devices that have internal buffer. + * By default devices are not paused. + * + * data: NULL + */ + AV_APP_TO_DEV_PAUSE = MKBETAG('P', 'A', 'U', ' '), + AV_APP_TO_DEV_PLAY = MKBETAG('P', 'L', 'A', 'Y'), + AV_APP_TO_DEV_TOGGLE_PAUSE = MKBETAG('P', 'A', 'U', 'T'), + + /** + * Volume control message. + * + * Set volume level. It may be device-dependent if volume + * is changed per stream or system wide. Per stream volume + * change is expected when possible. + * + * data: double: new volume with range of 0.0 - 1.0. + */ + AV_APP_TO_DEV_SET_VOLUME = MKBETAG('S', 'V', 'O', 'L'), + + /** + * Mute control messages. + * + * Change mute state. It may be device-dependent if mute status + * is changed per stream or system wide. Per stream mute status + * change is expected when possible. + * + * data: NULL. + */ + AV_APP_TO_DEV_MUTE = MKBETAG(' ', 'M', 'U', 'T'), + AV_APP_TO_DEV_UNMUTE = MKBETAG('U', 'M', 'U', 'T'), + AV_APP_TO_DEV_TOGGLE_MUTE = MKBETAG('T', 'M', 'U', 'T'), + + /** + * Get volume/mute messages. + * + * Force the device to send AV_DEV_TO_APP_VOLUME_LEVEL_CHANGED or + * AV_DEV_TO_APP_MUTE_STATE_CHANGED command respectively. + * + * data: NULL. + */ + AV_APP_TO_DEV_GET_VOLUME = MKBETAG('G', 'V', 'O', 'L'), + AV_APP_TO_DEV_GET_MUTE = MKBETAG('G', 'M', 'U', 'T'), +}; + +/** + * Message types used by avdevice_dev_to_app_control_message(). + */ +enum AVDevToAppMessageType { + /** + * Dummy message. + */ + AV_DEV_TO_APP_NONE = MKBETAG('N','O','N','E'), + + /** + * Create window buffer message. + * + * Device requests to create a window buffer. Exact meaning is device- + * and application-dependent. Message is sent before rendering first + * frame and all one-shot initializations should be done here. + * Application is allowed to ignore preferred window buffer size. + * + * @note: Application is obligated to inform about window buffer size + * with AV_APP_TO_DEV_WINDOW_SIZE message. + * + * data: AVDeviceRect: preferred size of the window buffer. + * NULL: no preferred size of the window buffer. + */ + AV_DEV_TO_APP_CREATE_WINDOW_BUFFER = MKBETAG('B','C','R','E'), + + /** + * Prepare window buffer message. + * + * Device requests to prepare a window buffer for rendering. + * Exact meaning is device- and application-dependent. + * Message is sent before rendering of each frame. + * + * data: NULL. + */ + AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER = MKBETAG('B','P','R','E'), + + /** + * Display window buffer message. + * + * Device requests to display a window buffer. + * Message is sent when new frame is ready to be displayed. + * Usually buffers need to be swapped in handler of this message. + * + * data: NULL. + */ + AV_DEV_TO_APP_DISPLAY_WINDOW_BUFFER = MKBETAG('B','D','I','S'), + + /** + * Destroy window buffer message. + * + * Device requests to destroy a window buffer. + * Message is sent when device is about to be destroyed and window + * buffer is not required anymore. + * + * data: NULL. + */ + AV_DEV_TO_APP_DESTROY_WINDOW_BUFFER = MKBETAG('B','D','E','S'), + + /** + * Buffer fullness status messages. + * + * Device signals buffer overflow/underflow. + * + * data: NULL. + */ + AV_DEV_TO_APP_BUFFER_OVERFLOW = MKBETAG('B','O','F','L'), + AV_DEV_TO_APP_BUFFER_UNDERFLOW = MKBETAG('B','U','F','L'), + + /** + * Buffer readable/writable. + * + * Device informs that buffer is readable/writable. + * When possible, device informs how many bytes can be read/write. + * + * @warning Device may not inform when number of bytes than can be read/write changes. + * + * data: int64_t: amount of bytes available to read/write. + * NULL: amount of bytes available to read/write is not known. + */ + AV_DEV_TO_APP_BUFFER_READABLE = MKBETAG('B','R','D',' '), + AV_DEV_TO_APP_BUFFER_WRITABLE = MKBETAG('B','W','R',' '), + + /** + * Mute state change message. + * + * Device informs that mute state has changed. + * + * data: int: 0 for not muted state, non-zero for muted state. + */ + AV_DEV_TO_APP_MUTE_STATE_CHANGED = MKBETAG('C','M','U','T'), + + /** + * Volume level change message. + * + * Device informs that volume level has changed. + * + * data: double: new volume with range of 0.0 - 1.0. + */ + AV_DEV_TO_APP_VOLUME_LEVEL_CHANGED = MKBETAG('C','V','O','L'), +}; + +/** + * Send control message from application to device. + * + * @param s device context. + * @param type message type. + * @param data message data. Exact type depends on message type. + * @param data_size size of message data. + * @return >= 0 on success, negative on error. + * AVERROR(ENOSYS) when device doesn't implement handler of the message. + */ +int avdevice_app_to_dev_control_message(struct AVFormatContext *s, + enum AVAppToDevMessageType type, + void *data, size_t data_size); + +/** + * Send control message from device to application. + * + * @param s device context. + * @param type message type. + * @param data message data. Can be NULL. + * @param data_size size of message data. + * @return >= 0 on success, negative on error. + * AVERROR(ENOSYS) when application doesn't implement handler of the message. + */ +int avdevice_dev_to_app_control_message(struct AVFormatContext *s, + enum AVDevToAppMessageType type, + void *data, size_t data_size); + +/** + * Following API allows user to probe device capabilities (supported codecs, + * pixel formats, sample formats, resolutions, channel counts, etc). + * It is build on top op AVOption API. + * Queried capabilities make it possible to set up converters of video or audio + * parameters that fit to the device. + * + * List of capabilities that can be queried: + * - Capabilities valid for both audio and video devices: + * - codec: supported audio/video codecs. + * type: AV_OPT_TYPE_INT (AVCodecID value) + * - Capabilities valid for audio devices: + * - sample_format: supported sample formats. + * type: AV_OPT_TYPE_INT (AVSampleFormat value) + * - sample_rate: supported sample rates. + * type: AV_OPT_TYPE_INT + * - channels: supported number of channels. + * type: AV_OPT_TYPE_INT + * - channel_layout: supported channel layouts. + * type: AV_OPT_TYPE_INT64 + * - Capabilities valid for video devices: + * - pixel_format: supported pixel formats. + * type: AV_OPT_TYPE_INT (AVPixelFormat value) + * - window_size: supported window sizes (describes size of the window size presented to the user). + * type: AV_OPT_TYPE_IMAGE_SIZE + * - frame_size: supported frame sizes (describes size of provided video frames). + * type: AV_OPT_TYPE_IMAGE_SIZE + * - fps: supported fps values + * type: AV_OPT_TYPE_RATIONAL + * + * Value of the capability may be set by user using av_opt_set() function + * and AVDeviceCapabilitiesQuery object. Following queries will + * limit results to the values matching already set capabilities. + * For example, setting a codec may impact number of formats or fps values + * returned during next query. Setting invalid value may limit results to zero. + * + * Example of the usage basing on opengl output device: + * + * @code + * AVFormatContext *oc = NULL; + * AVDeviceCapabilitiesQuery *caps = NULL; + * AVOptionRanges *ranges; + * int ret; + * + * if ((ret = avformat_alloc_output_context2(&oc, NULL, "opengl", NULL)) < 0) + * goto fail; + * if (avdevice_capabilities_create(&caps, oc, NULL) < 0) + * goto fail; + * + * //query codecs + * if (av_opt_query_ranges(&ranges, caps, "codec", AV_OPT_MULTI_COMPONENT_RANGE)) < 0) + * goto fail; + * //pick codec here and set it + * av_opt_set(caps, "codec", AV_CODEC_ID_RAWVIDEO, 0); + * + * //query format + * if (av_opt_query_ranges(&ranges, caps, "pixel_format", AV_OPT_MULTI_COMPONENT_RANGE)) < 0) + * goto fail; + * //pick format here and set it + * av_opt_set(caps, "pixel_format", AV_PIX_FMT_YUV420P, 0); + * + * //query and set more capabilities + * + * fail: + * //clean up code + * avdevice_capabilities_free(&query, oc); + * avformat_free_context(oc); + * @endcode + */ + +/** + * Structure describes device capabilities. + * + * It is used by devices in conjunction with av_device_capabilities AVOption table + * to implement capabilities probing API based on AVOption API. Should not be used directly. + */ +typedef struct AVDeviceCapabilitiesQuery { + const AVClass *av_class; + AVFormatContext *device_context; + enum AVCodecID codec; + enum AVSampleFormat sample_format; + enum AVPixelFormat pixel_format; + int sample_rate; + int channels; + int64_t channel_layout; + int window_width; + int window_height; + int frame_width; + int frame_height; + AVRational fps; +} AVDeviceCapabilitiesQuery; + +/** + * AVOption table used by devices to implement device capabilities API. Should not be used by a user. + */ +extern const AVOption av_device_capabilities[]; + +/** + * Initialize capabilities probing API based on AVOption API. + * + * avdevice_capabilities_free() must be called when query capabilities API is + * not used anymore. + * + * @param[out] caps Device capabilities data. Pointer to a NULL pointer must be passed. + * @param s Context of the device. + * @param device_options An AVDictionary filled with device-private options. + * On return this parameter will be destroyed and replaced with a dict + * containing options that were not found. May be NULL. + * The same options must be passed later to avformat_write_header() for output + * devices or avformat_open_input() for input devices, or at any other place + * that affects device-private options. + * + * @return >= 0 on success, negative otherwise. + */ +int avdevice_capabilities_create(AVDeviceCapabilitiesQuery **caps, AVFormatContext *s, + AVDictionary **device_options); + +/** + * Free resources created by avdevice_capabilities_create() + * + * @param caps Device capabilities data to be freed. + * @param s Context of the device. + */ +void avdevice_capabilities_free(AVDeviceCapabilitiesQuery **caps, AVFormatContext *s); + +/** + * Structure describes basic parameters of the device. + */ +typedef struct AVDeviceInfo { + char *device_name; /**< device name, format depends on device */ + char *device_description; /**< human friendly name */ +} AVDeviceInfo; + +/** + * List of devices. + */ +typedef struct AVDeviceInfoList { + AVDeviceInfo **devices; /**< list of autodetected devices */ + int nb_devices; /**< number of autodetected devices */ + int default_device; /**< index of default device or -1 if no default */ +} AVDeviceInfoList; + +/** + * List devices. + * + * Returns available device names and their parameters. + * + * @note: Some devices may accept system-dependent device names that cannot be + * autodetected. The list returned by this function cannot be assumed to + * be always completed. + * + * @param s device context. + * @param[out] device_list list of autodetected devices. + * @return count of autodetected devices, negative on error. + */ +int avdevice_list_devices(struct AVFormatContext *s, AVDeviceInfoList **device_list); + +/** + * Convenient function to free result of avdevice_list_devices(). + * + * @param devices device list to be freed. + */ +void avdevice_free_list_devices(AVDeviceInfoList **device_list); + +/** + * List devices. + * + * Returns available device names and their parameters. + * These are convinient wrappers for avdevice_list_devices(). + * Device context is allocated and deallocated internally. + * + * @param device device format. May be NULL if device name is set. + * @param device_name device name. May be NULL if device format is set. + * @param device_options An AVDictionary filled with device-private options. May be NULL. + * The same options must be passed later to avformat_write_header() for output + * devices or avformat_open_input() for input devices, or at any other place + * that affects device-private options. + * @param[out] device_list list of autodetected devices + * @return count of autodetected devices, negative on error. + * @note device argument takes precedence over device_name when both are set. + */ +int avdevice_list_input_sources(struct AVInputFormat *device, const char *device_name, + AVDictionary *device_options, AVDeviceInfoList **device_list); +int avdevice_list_output_sinks(struct AVOutputFormat *device, const char *device_name, + AVDictionary *device_options, AVDeviceInfoList **device_list); + +/** + * @} + */ + +#endif /* AVDEVICE_AVDEVICE_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavdevice/version.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavdevice/version.h new file mode 100644 index 0000000..986ca98 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavdevice/version.h @@ -0,0 +1,50 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVDEVICE_VERSION_H +#define AVDEVICE_VERSION_H + +/** + * @file + * @ingroup lavd + * Libavdevice version macros + */ + +#include "libavutil/version.h" + +#define LIBAVDEVICE_VERSION_MAJOR 57 +#define LIBAVDEVICE_VERSION_MINOR 6 +#define LIBAVDEVICE_VERSION_MICRO 100 + +#define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \ + LIBAVDEVICE_VERSION_MINOR, \ + LIBAVDEVICE_VERSION_MICRO) +#define LIBAVDEVICE_VERSION AV_VERSION(LIBAVDEVICE_VERSION_MAJOR, \ + LIBAVDEVICE_VERSION_MINOR, \ + LIBAVDEVICE_VERSION_MICRO) +#define LIBAVDEVICE_BUILD LIBAVDEVICE_VERSION_INT + +#define LIBAVDEVICE_IDENT "Lavd" AV_STRINGIFY(LIBAVDEVICE_VERSION) + +/** + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + */ + +#endif /* AVDEVICE_VERSION_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavfilter/avfilter.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavfilter/avfilter.h new file mode 100644 index 0000000..60662c1 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavfilter/avfilter.h @@ -0,0 +1,1182 @@ +/* + * filter layer + * Copyright (c) 2007 Bobby Bingham + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFILTER_AVFILTER_H +#define AVFILTER_AVFILTER_H + +/** + * @file + * @ingroup lavfi + * Main libavfilter public API header + */ + +/** + * @defgroup lavfi libavfilter + * Graph-based frame editing library. + * + * @{ + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/avutil.h" +#include "libavutil/buffer.h" +#include "libavutil/dict.h" +#include "libavutil/frame.h" +#include "libavutil/log.h" +#include "libavutil/samplefmt.h" +#include "libavutil/pixfmt.h" +#include "libavutil/rational.h" + +#include "libavfilter/version.h" + +/** + * Return the LIBAVFILTER_VERSION_INT constant. + */ +unsigned avfilter_version(void); + +/** + * Return the libavfilter build-time configuration. + */ +const char *avfilter_configuration(void); + +/** + * Return the libavfilter license. + */ +const char *avfilter_license(void); + +typedef struct AVFilterContext AVFilterContext; +typedef struct AVFilterLink AVFilterLink; +typedef struct AVFilterPad AVFilterPad; +typedef struct AVFilterFormats AVFilterFormats; + +/** + * Get the number of elements in a NULL-terminated array of AVFilterPads (e.g. + * AVFilter.inputs/outputs). + */ +int avfilter_pad_count(const AVFilterPad *pads); + +/** + * Get the name of an AVFilterPad. + * + * @param pads an array of AVFilterPads + * @param pad_idx index of the pad in the array it; is the caller's + * responsibility to ensure the index is valid + * + * @return name of the pad_idx'th pad in pads + */ +const char *avfilter_pad_get_name(const AVFilterPad *pads, int pad_idx); + +/** + * Get the type of an AVFilterPad. + * + * @param pads an array of AVFilterPads + * @param pad_idx index of the pad in the array; it is the caller's + * responsibility to ensure the index is valid + * + * @return type of the pad_idx'th pad in pads + */ +enum AVMediaType avfilter_pad_get_type(const AVFilterPad *pads, int pad_idx); + +/** + * The number of the filter inputs is not determined just by AVFilter.inputs. + * The filter might add additional inputs during initialization depending on the + * options supplied to it. + */ +#define AVFILTER_FLAG_DYNAMIC_INPUTS (1 << 0) +/** + * The number of the filter outputs is not determined just by AVFilter.outputs. + * The filter might add additional outputs during initialization depending on + * the options supplied to it. + */ +#define AVFILTER_FLAG_DYNAMIC_OUTPUTS (1 << 1) +/** + * The filter supports multithreading by splitting frames into multiple parts + * and processing them concurrently. + */ +#define AVFILTER_FLAG_SLICE_THREADS (1 << 2) +/** + * Some filters support a generic "enable" expression option that can be used + * to enable or disable a filter in the timeline. Filters supporting this + * option have this flag set. When the enable expression is false, the default + * no-op filter_frame() function is called in place of the filter_frame() + * callback defined on each input pad, thus the frame is passed unchanged to + * the next filters. + */ +#define AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC (1 << 16) +/** + * Same as AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, except that the filter will + * have its filter_frame() callback(s) called as usual even when the enable + * expression is false. The filter will disable filtering within the + * filter_frame() callback(s) itself, for example executing code depending on + * the AVFilterContext->is_disabled value. + */ +#define AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL (1 << 17) +/** + * Handy mask to test whether the filter supports or no the timeline feature + * (internally or generically). + */ +#define AVFILTER_FLAG_SUPPORT_TIMELINE (AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL) + +/** + * Filter definition. This defines the pads a filter contains, and all the + * callback functions used to interact with the filter. + */ +typedef struct AVFilter { + /** + * Filter name. Must be non-NULL and unique among filters. + */ + const char *name; + + /** + * A description of the filter. May be NULL. + * + * You should use the NULL_IF_CONFIG_SMALL() macro to define it. + */ + const char *description; + + /** + * List of inputs, terminated by a zeroed element. + * + * NULL if there are no (static) inputs. Instances of filters with + * AVFILTER_FLAG_DYNAMIC_INPUTS set may have more inputs than present in + * this list. + */ + const AVFilterPad *inputs; + /** + * List of outputs, terminated by a zeroed element. + * + * NULL if there are no (static) outputs. Instances of filters with + * AVFILTER_FLAG_DYNAMIC_OUTPUTS set may have more outputs than present in + * this list. + */ + const AVFilterPad *outputs; + + /** + * A class for the private data, used to declare filter private AVOptions. + * This field is NULL for filters that do not declare any options. + * + * If this field is non-NULL, the first member of the filter private data + * must be a pointer to AVClass, which will be set by libavfilter generic + * code to this class. + */ + const AVClass *priv_class; + + /** + * A combination of AVFILTER_FLAG_* + */ + int flags; + + /***************************************************************** + * All fields below this line are not part of the public API. They + * may not be used outside of libavfilter and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + + /** + * Filter initialization function. + * + * This callback will be called only once during the filter lifetime, after + * all the options have been set, but before links between filters are + * established and format negotiation is done. + * + * Basic filter initialization should be done here. Filters with dynamic + * inputs and/or outputs should create those inputs/outputs here based on + * provided options. No more changes to this filter's inputs/outputs can be + * done after this callback. + * + * This callback must not assume that the filter links exist or frame + * parameters are known. + * + * @ref AVFilter.uninit "uninit" is guaranteed to be called even if + * initialization fails, so this callback does not have to clean up on + * failure. + * + * @return 0 on success, a negative AVERROR on failure + */ + int (*init)(AVFilterContext *ctx); + + /** + * Should be set instead of @ref AVFilter.init "init" by the filters that + * want to pass a dictionary of AVOptions to nested contexts that are + * allocated during init. + * + * On return, the options dict should be freed and replaced with one that + * contains all the options which could not be processed by this filter (or + * with NULL if all the options were processed). + * + * Otherwise the semantics is the same as for @ref AVFilter.init "init". + */ + int (*init_dict)(AVFilterContext *ctx, AVDictionary **options); + + /** + * Filter uninitialization function. + * + * Called only once right before the filter is freed. Should deallocate any + * memory held by the filter, release any buffer references, etc. It does + * not need to deallocate the AVFilterContext.priv memory itself. + * + * This callback may be called even if @ref AVFilter.init "init" was not + * called or failed, so it must be prepared to handle such a situation. + */ + void (*uninit)(AVFilterContext *ctx); + + /** + * Query formats supported by the filter on its inputs and outputs. + * + * This callback is called after the filter is initialized (so the inputs + * and outputs are fixed), shortly before the format negotiation. This + * callback may be called more than once. + * + * This callback must set AVFilterLink.out_formats on every input link and + * AVFilterLink.in_formats on every output link to a list of pixel/sample + * formats that the filter supports on that link. For audio links, this + * filter must also set @ref AVFilterLink.in_samplerates "in_samplerates" / + * @ref AVFilterLink.out_samplerates "out_samplerates" and + * @ref AVFilterLink.in_channel_layouts "in_channel_layouts" / + * @ref AVFilterLink.out_channel_layouts "out_channel_layouts" analogously. + * + * This callback may be NULL for filters with one input, in which case + * libavfilter assumes that it supports all input formats and preserves + * them on output. + * + * @return zero on success, a negative value corresponding to an + * AVERROR code otherwise + */ + int (*query_formats)(AVFilterContext *); + + int priv_size; ///< size of private data to allocate for the filter + + int flags_internal; ///< Additional flags for avfilter internal use only. + + /** + * Used by the filter registration system. Must not be touched by any other + * code. + */ + struct AVFilter *next; + + /** + * Make the filter instance process a command. + * + * @param cmd the command to process, for handling simplicity all commands must be alphanumeric only + * @param arg the argument for the command + * @param res a buffer with size res_size where the filter(s) can return a response. This must not change when the command is not supported. + * @param flags if AVFILTER_CMD_FLAG_FAST is set and the command would be + * time consuming then a filter should treat it like an unsupported command + * + * @returns >=0 on success otherwise an error code. + * AVERROR(ENOSYS) on unsupported commands + */ + int (*process_command)(AVFilterContext *, const char *cmd, const char *arg, char *res, int res_len, int flags); + + /** + * Filter initialization function, alternative to the init() + * callback. Args contains the user-supplied parameters, opaque is + * used for providing binary data. + */ + int (*init_opaque)(AVFilterContext *ctx, void *opaque); + + /** + * Filter activation function. + * + * Called when any processing is needed from the filter, instead of any + * filter_frame and request_frame on pads. + * + * The function must examine inlinks and outlinks and perform a single + * step of processing. If there is nothing to do, the function must do + * nothing and not return an error. If more steps are or may be + * possible, it must use ff_filter_set_ready() to schedule another + * activation. + */ + int (*activate)(AVFilterContext *ctx); +} AVFilter; + +/** + * Process multiple parts of the frame concurrently. + */ +#define AVFILTER_THREAD_SLICE (1 << 0) + +typedef struct AVFilterInternal AVFilterInternal; + +/** An instance of a filter */ +struct AVFilterContext { + const AVClass *av_class; ///< needed for av_log() and filters common options + + const AVFilter *filter; ///< the AVFilter of which this is an instance + + char *name; ///< name of this filter instance + + AVFilterPad *input_pads; ///< array of input pads + AVFilterLink **inputs; ///< array of pointers to input links + unsigned nb_inputs; ///< number of input pads + + AVFilterPad *output_pads; ///< array of output pads + AVFilterLink **outputs; ///< array of pointers to output links + unsigned nb_outputs; ///< number of output pads + + void *priv; ///< private data for use by the filter + + struct AVFilterGraph *graph; ///< filtergraph this filter belongs to + + /** + * Type of multithreading being allowed/used. A combination of + * AVFILTER_THREAD_* flags. + * + * May be set by the caller before initializing the filter to forbid some + * or all kinds of multithreading for this filter. The default is allowing + * everything. + * + * When the filter is initialized, this field is combined using bit AND with + * AVFilterGraph.thread_type to get the final mask used for determining + * allowed threading types. I.e. a threading type needs to be set in both + * to be allowed. + * + * After the filter is initialized, libavfilter sets this field to the + * threading type that is actually used (0 for no multithreading). + */ + int thread_type; + + /** + * An opaque struct for libavfilter internal use. + */ + AVFilterInternal *internal; + + struct AVFilterCommand *command_queue; + + char *enable_str; ///< enable expression string + void *enable; ///< parsed expression (AVExpr*) + double *var_values; ///< variable values for the enable expression + int is_disabled; ///< the enabled state from the last expression evaluation + + /** + * For filters which will create hardware frames, sets the device the + * filter should create them in. All other filters will ignore this field: + * in particular, a filter which consumes or processes hardware frames will + * instead use the hw_frames_ctx field in AVFilterLink to carry the + * hardware context information. + */ + AVBufferRef *hw_device_ctx; + + /** + * Max number of threads allowed in this filter instance. + * If <= 0, its value is ignored. + * Overrides global number of threads set per filter graph. + */ + int nb_threads; + + /** + * Ready status of the filter. + * A non-0 value means that the filter needs activating; + * a higher value suggests a more urgent activation. + */ + unsigned ready; +}; + +/** + * A link between two filters. This contains pointers to the source and + * destination filters between which this link exists, and the indexes of + * the pads involved. In addition, this link also contains the parameters + * which have been negotiated and agreed upon between the filter, such as + * image dimensions, format, etc. + * + * Applications must not normally access the link structure directly. + * Use the buffersrc and buffersink API instead. + * In the future, access to the header may be reserved for filters + * implementation. + */ +struct AVFilterLink { + AVFilterContext *src; ///< source filter + AVFilterPad *srcpad; ///< output pad on the source filter + + AVFilterContext *dst; ///< dest filter + AVFilterPad *dstpad; ///< input pad on the dest filter + + enum AVMediaType type; ///< filter media type + + /* These parameters apply only to video */ + int w; ///< agreed upon image width + int h; ///< agreed upon image height + AVRational sample_aspect_ratio; ///< agreed upon sample aspect ratio + /* These parameters apply only to audio */ + uint64_t channel_layout; ///< channel layout of current buffer (see libavutil/channel_layout.h) + int sample_rate; ///< samples per second + + int format; ///< agreed upon media format + + /** + * Define the time base used by the PTS of the frames/samples + * which will pass through this link. + * During the configuration stage, each filter is supposed to + * change only the output timebase, while the timebase of the + * input link is assumed to be an unchangeable property. + */ + AVRational time_base; + + /***************************************************************** + * All fields below this line are not part of the public API. They + * may not be used outside of libavfilter and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + /** + * Lists of formats and channel layouts supported by the input and output + * filters respectively. These lists are used for negotiating the format + * to actually be used, which will be loaded into the format and + * channel_layout members, above, when chosen. + * + */ + AVFilterFormats *in_formats; + AVFilterFormats *out_formats; + + /** + * Lists of channel layouts and sample rates used for automatic + * negotiation. + */ + AVFilterFormats *in_samplerates; + AVFilterFormats *out_samplerates; + struct AVFilterChannelLayouts *in_channel_layouts; + struct AVFilterChannelLayouts *out_channel_layouts; + + /** + * Audio only, the destination filter sets this to a non-zero value to + * request that buffers with the given number of samples should be sent to + * it. AVFilterPad.needs_fifo must also be set on the corresponding input + * pad. + * Last buffer before EOF will be padded with silence. + */ + int request_samples; + + /** stage of the initialization of the link properties (dimensions, etc) */ + enum { + AVLINK_UNINIT = 0, ///< not started + AVLINK_STARTINIT, ///< started, but incomplete + AVLINK_INIT ///< complete + } init_state; + + /** + * Graph the filter belongs to. + */ + struct AVFilterGraph *graph; + + /** + * Current timestamp of the link, as defined by the most recent + * frame(s), in link time_base units. + */ + int64_t current_pts; + + /** + * Current timestamp of the link, as defined by the most recent + * frame(s), in AV_TIME_BASE units. + */ + int64_t current_pts_us; + + /** + * Index in the age array. + */ + int age_index; + + /** + * Frame rate of the stream on the link, or 1/0 if unknown or variable; + * if left to 0/0, will be automatically copied from the first input + * of the source filter if it exists. + * + * Sources should set it to the best estimation of the real frame rate. + * If the source frame rate is unknown or variable, set this to 1/0. + * Filters should update it if necessary depending on their function. + * Sinks can use it to set a default output frame rate. + * It is similar to the r_frame_rate field in AVStream. + */ + AVRational frame_rate; + + /** + * Buffer partially filled with samples to achieve a fixed/minimum size. + */ + AVFrame *partial_buf; + + /** + * Size of the partial buffer to allocate. + * Must be between min_samples and max_samples. + */ + int partial_buf_size; + + /** + * Minimum number of samples to filter at once. If filter_frame() is + * called with fewer samples, it will accumulate them in partial_buf. + * This field and the related ones must not be changed after filtering + * has started. + * If 0, all related fields are ignored. + */ + int min_samples; + + /** + * Maximum number of samples to filter at once. If filter_frame() is + * called with more samples, it will split them. + */ + int max_samples; + + /** + * Number of channels. + */ + int channels; + + /** + * Link processing flags. + */ + unsigned flags; + + /** + * Number of past frames sent through the link. + */ + int64_t frame_count_in, frame_count_out; + + /** + * A pointer to a FFFramePool struct. + */ + void *frame_pool; + + /** + * True if a frame is currently wanted on the output of this filter. + * Set when ff_request_frame() is called by the output, + * cleared when a frame is filtered. + */ + int frame_wanted_out; + + /** + * For hwaccel pixel formats, this should be a reference to the + * AVHWFramesContext describing the frames. + */ + AVBufferRef *hw_frames_ctx; + +#ifndef FF_INTERNAL_FIELDS + + /** + * Internal structure members. + * The fields below this limit are internal for libavfilter's use + * and must in no way be accessed by applications. + */ + char reserved[0xF000]; + +#else /* FF_INTERNAL_FIELDS */ + + /** + * Queue of frames waiting to be filtered. + */ + FFFrameQueue fifo; + + /** + * If set, the source filter can not generate a frame as is. + * The goal is to avoid repeatedly calling the request_frame() method on + * the same link. + */ + int frame_blocked_in; + + /** + * Link input status. + * If not zero, all attempts of filter_frame will fail with the + * corresponding code. + */ + int status_in; + + /** + * Timestamp of the input status change. + */ + int64_t status_in_pts; + + /** + * Link output status. + * If not zero, all attempts of request_frame will fail with the + * corresponding code. + */ + int status_out; + +#endif /* FF_INTERNAL_FIELDS */ + +}; + +/** + * Link two filters together. + * + * @param src the source filter + * @param srcpad index of the output pad on the source filter + * @param dst the destination filter + * @param dstpad index of the input pad on the destination filter + * @return zero on success + */ +int avfilter_link(AVFilterContext *src, unsigned srcpad, + AVFilterContext *dst, unsigned dstpad); + +/** + * Free the link in *link, and set its pointer to NULL. + */ +void avfilter_link_free(AVFilterLink **link); + +/** + * Get the number of channels of a link. + */ +int avfilter_link_get_channels(AVFilterLink *link); + +/** + * Set the closed field of a link. + * @deprecated applications are not supposed to mess with links, they should + * close the sinks. + */ +attribute_deprecated +void avfilter_link_set_closed(AVFilterLink *link, int closed); + +/** + * Negotiate the media format, dimensions, etc of all inputs to a filter. + * + * @param filter the filter to negotiate the properties for its inputs + * @return zero on successful negotiation + */ +int avfilter_config_links(AVFilterContext *filter); + +#define AVFILTER_CMD_FLAG_ONE 1 ///< Stop once a filter understood the command (for target=all for example), fast filters are favored automatically +#define AVFILTER_CMD_FLAG_FAST 2 ///< Only execute command when its fast (like a video out that supports contrast adjustment in hw) + +/** + * Make the filter instance process a command. + * It is recommended to use avfilter_graph_send_command(). + */ +int avfilter_process_command(AVFilterContext *filter, const char *cmd, const char *arg, char *res, int res_len, int flags); + +/** Initialize the filter system. Register all builtin filters. */ +void avfilter_register_all(void); + +#if FF_API_OLD_FILTER_REGISTER +/** Uninitialize the filter system. Unregister all filters. */ +attribute_deprecated +void avfilter_uninit(void); +#endif + +/** + * Register a filter. This is only needed if you plan to use + * avfilter_get_by_name later to lookup the AVFilter structure by name. A + * filter can still by instantiated with avfilter_graph_alloc_filter even if it + * is not registered. + * + * @param filter the filter to register + * @return 0 if the registration was successful, a negative value + * otherwise + */ +int avfilter_register(AVFilter *filter); + +/** + * Get a filter definition matching the given name. + * + * @param name the filter name to find + * @return the filter definition, if any matching one is registered. + * NULL if none found. + */ +#if !FF_API_NOCONST_GET_NAME +const +#endif +AVFilter *avfilter_get_by_name(const char *name); + +/** + * Iterate over all registered filters. + * @return If prev is non-NULL, next registered filter after prev or NULL if + * prev is the last filter. If prev is NULL, return the first registered filter. + */ +const AVFilter *avfilter_next(const AVFilter *prev); + +#if FF_API_OLD_FILTER_REGISTER +/** + * If filter is NULL, returns a pointer to the first registered filter pointer, + * if filter is non-NULL, returns the next pointer after filter. + * If the returned pointer points to NULL, the last registered filter + * was already reached. + * @deprecated use avfilter_next() + */ +attribute_deprecated +AVFilter **av_filter_next(AVFilter **filter); +#endif + +#if FF_API_AVFILTER_OPEN +/** + * Create a filter instance. + * + * @param filter_ctx put here a pointer to the created filter context + * on success, NULL on failure + * @param filter the filter to create an instance of + * @param inst_name Name to give to the new instance. Can be NULL for none. + * @return >= 0 in case of success, a negative error code otherwise + * @deprecated use avfilter_graph_alloc_filter() instead + */ +attribute_deprecated +int avfilter_open(AVFilterContext **filter_ctx, AVFilter *filter, const char *inst_name); +#endif + + +#if FF_API_AVFILTER_INIT_FILTER +/** + * Initialize a filter. + * + * @param filter the filter to initialize + * @param args A string of parameters to use when initializing the filter. + * The format and meaning of this string varies by filter. + * @param opaque Any extra non-string data needed by the filter. The meaning + * of this parameter varies by filter. + * @return zero on success + */ +attribute_deprecated +int avfilter_init_filter(AVFilterContext *filter, const char *args, void *opaque); +#endif + +/** + * Initialize a filter with the supplied parameters. + * + * @param ctx uninitialized filter context to initialize + * @param args Options to initialize the filter with. This must be a + * ':'-separated list of options in the 'key=value' form. + * May be NULL if the options have been set directly using the + * AVOptions API or there are no options that need to be set. + * @return 0 on success, a negative AVERROR on failure + */ +int avfilter_init_str(AVFilterContext *ctx, const char *args); + +/** + * Initialize a filter with the supplied dictionary of options. + * + * @param ctx uninitialized filter context to initialize + * @param options An AVDictionary filled with options for this filter. On + * return this parameter will be destroyed and replaced with + * a dict containing options that were not found. This dictionary + * must be freed by the caller. + * May be NULL, then this function is equivalent to + * avfilter_init_str() with the second parameter set to NULL. + * @return 0 on success, a negative AVERROR on failure + * + * @note This function and avfilter_init_str() do essentially the same thing, + * the difference is in manner in which the options are passed. It is up to the + * calling code to choose whichever is more preferable. The two functions also + * behave differently when some of the provided options are not declared as + * supported by the filter. In such a case, avfilter_init_str() will fail, but + * this function will leave those extra options in the options AVDictionary and + * continue as usual. + */ +int avfilter_init_dict(AVFilterContext *ctx, AVDictionary **options); + +/** + * Free a filter context. This will also remove the filter from its + * filtergraph's list of filters. + * + * @param filter the filter to free + */ +void avfilter_free(AVFilterContext *filter); + +/** + * Insert a filter in the middle of an existing link. + * + * @param link the link into which the filter should be inserted + * @param filt the filter to be inserted + * @param filt_srcpad_idx the input pad on the filter to connect + * @param filt_dstpad_idx the output pad on the filter to connect + * @return zero on success + */ +int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt, + unsigned filt_srcpad_idx, unsigned filt_dstpad_idx); + +/** + * @return AVClass for AVFilterContext. + * + * @see av_opt_find(). + */ +const AVClass *avfilter_get_class(void); + +typedef struct AVFilterGraphInternal AVFilterGraphInternal; + +/** + * A function pointer passed to the @ref AVFilterGraph.execute callback to be + * executed multiple times, possibly in parallel. + * + * @param ctx the filter context the job belongs to + * @param arg an opaque parameter passed through from @ref + * AVFilterGraph.execute + * @param jobnr the index of the job being executed + * @param nb_jobs the total number of jobs + * + * @return 0 on success, a negative AVERROR on error + */ +typedef int (avfilter_action_func)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); + +/** + * A function executing multiple jobs, possibly in parallel. + * + * @param ctx the filter context to which the jobs belong + * @param func the function to be called multiple times + * @param arg the argument to be passed to func + * @param ret a nb_jobs-sized array to be filled with return values from each + * invocation of func + * @param nb_jobs the number of jobs to execute + * + * @return 0 on success, a negative AVERROR on error + */ +typedef int (avfilter_execute_func)(AVFilterContext *ctx, avfilter_action_func *func, + void *arg, int *ret, int nb_jobs); + +typedef struct AVFilterGraph { + const AVClass *av_class; + AVFilterContext **filters; + unsigned nb_filters; + + char *scale_sws_opts; ///< sws options to use for the auto-inserted scale filters +#if FF_API_LAVR_OPTS + attribute_deprecated char *resample_lavr_opts; ///< libavresample options to use for the auto-inserted resample filters +#endif + + /** + * Type of multithreading allowed for filters in this graph. A combination + * of AVFILTER_THREAD_* flags. + * + * May be set by the caller at any point, the setting will apply to all + * filters initialized after that. The default is allowing everything. + * + * When a filter in this graph is initialized, this field is combined using + * bit AND with AVFilterContext.thread_type to get the final mask used for + * determining allowed threading types. I.e. a threading type needs to be + * set in both to be allowed. + */ + int thread_type; + + /** + * Maximum number of threads used by filters in this graph. May be set by + * the caller before adding any filters to the filtergraph. Zero (the + * default) means that the number of threads is determined automatically. + */ + int nb_threads; + + /** + * Opaque object for libavfilter internal use. + */ + AVFilterGraphInternal *internal; + + /** + * Opaque user data. May be set by the caller to an arbitrary value, e.g. to + * be used from callbacks like @ref AVFilterGraph.execute. + * Libavfilter will not touch this field in any way. + */ + void *opaque; + + /** + * This callback may be set by the caller immediately after allocating the + * graph and before adding any filters to it, to provide a custom + * multithreading implementation. + * + * If set, filters with slice threading capability will call this callback + * to execute multiple jobs in parallel. + * + * If this field is left unset, libavfilter will use its internal + * implementation, which may or may not be multithreaded depending on the + * platform and build options. + */ + avfilter_execute_func *execute; + + char *aresample_swr_opts; ///< swr options to use for the auto-inserted aresample filters, Access ONLY through AVOptions + + /** + * Private fields + * + * The following fields are for internal use only. + * Their type, offset, number and semantic can change without notice. + */ + + AVFilterLink **sink_links; + int sink_links_count; + + unsigned disable_auto_convert; +} AVFilterGraph; + +/** + * Allocate a filter graph. + * + * @return the allocated filter graph on success or NULL. + */ +AVFilterGraph *avfilter_graph_alloc(void); + +/** + * Create a new filter instance in a filter graph. + * + * @param graph graph in which the new filter will be used + * @param filter the filter to create an instance of + * @param name Name to give to the new instance (will be copied to + * AVFilterContext.name). This may be used by the caller to identify + * different filters, libavfilter itself assigns no semantics to + * this parameter. May be NULL. + * + * @return the context of the newly created filter instance (note that it is + * also retrievable directly through AVFilterGraph.filters or with + * avfilter_graph_get_filter()) on success or NULL on failure. + */ +AVFilterContext *avfilter_graph_alloc_filter(AVFilterGraph *graph, + const AVFilter *filter, + const char *name); + +/** + * Get a filter instance identified by instance name from graph. + * + * @param graph filter graph to search through. + * @param name filter instance name (should be unique in the graph). + * @return the pointer to the found filter instance or NULL if it + * cannot be found. + */ +AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, const char *name); + +#if FF_API_AVFILTER_OPEN +/** + * Add an existing filter instance to a filter graph. + * + * @param graphctx the filter graph + * @param filter the filter to be added + * + * @deprecated use avfilter_graph_alloc_filter() to allocate a filter in a + * filter graph + */ +attribute_deprecated +int avfilter_graph_add_filter(AVFilterGraph *graphctx, AVFilterContext *filter); +#endif + +/** + * Create and add a filter instance into an existing graph. + * The filter instance is created from the filter filt and inited + * with the parameters args and opaque. + * + * In case of success put in *filt_ctx the pointer to the created + * filter instance, otherwise set *filt_ctx to NULL. + * + * @param name the instance name to give to the created filter instance + * @param graph_ctx the filter graph + * @return a negative AVERROR error code in case of failure, a non + * negative value otherwise + */ +int avfilter_graph_create_filter(AVFilterContext **filt_ctx, const AVFilter *filt, + const char *name, const char *args, void *opaque, + AVFilterGraph *graph_ctx); + +/** + * Enable or disable automatic format conversion inside the graph. + * + * Note that format conversion can still happen inside explicitly inserted + * scale and aresample filters. + * + * @param flags any of the AVFILTER_AUTO_CONVERT_* constants + */ +void avfilter_graph_set_auto_convert(AVFilterGraph *graph, unsigned flags); + +enum { + AVFILTER_AUTO_CONVERT_ALL = 0, /**< all automatic conversions enabled */ + AVFILTER_AUTO_CONVERT_NONE = -1, /**< all automatic conversions disabled */ +}; + +/** + * Check validity and configure all the links and formats in the graph. + * + * @param graphctx the filter graph + * @param log_ctx context used for logging + * @return >= 0 in case of success, a negative AVERROR code otherwise + */ +int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx); + +/** + * Free a graph, destroy its links, and set *graph to NULL. + * If *graph is NULL, do nothing. + */ +void avfilter_graph_free(AVFilterGraph **graph); + +/** + * A linked-list of the inputs/outputs of the filter chain. + * + * This is mainly useful for avfilter_graph_parse() / avfilter_graph_parse2(), + * where it is used to communicate open (unlinked) inputs and outputs from and + * to the caller. + * This struct specifies, per each not connected pad contained in the graph, the + * filter context and the pad index required for establishing a link. + */ +typedef struct AVFilterInOut { + /** unique name for this input/output in the list */ + char *name; + + /** filter context associated to this input/output */ + AVFilterContext *filter_ctx; + + /** index of the filt_ctx pad to use for linking */ + int pad_idx; + + /** next input/input in the list, NULL if this is the last */ + struct AVFilterInOut *next; +} AVFilterInOut; + +/** + * Allocate a single AVFilterInOut entry. + * Must be freed with avfilter_inout_free(). + * @return allocated AVFilterInOut on success, NULL on failure. + */ +AVFilterInOut *avfilter_inout_alloc(void); + +/** + * Free the supplied list of AVFilterInOut and set *inout to NULL. + * If *inout is NULL, do nothing. + */ +void avfilter_inout_free(AVFilterInOut **inout); + +/** + * Add a graph described by a string to a graph. + * + * @note The caller must provide the lists of inputs and outputs, + * which therefore must be known before calling the function. + * + * @note The inputs parameter describes inputs of the already existing + * part of the graph; i.e. from the point of view of the newly created + * part, they are outputs. Similarly the outputs parameter describes + * outputs of the already existing filters, which are provided as + * inputs to the parsed filters. + * + * @param graph the filter graph where to link the parsed graph context + * @param filters string to be parsed + * @param inputs linked list to the inputs of the graph + * @param outputs linked list to the outputs of the graph + * @return zero on success, a negative AVERROR code on error + */ +int avfilter_graph_parse(AVFilterGraph *graph, const char *filters, + AVFilterInOut *inputs, AVFilterInOut *outputs, + void *log_ctx); + +/** + * Add a graph described by a string to a graph. + * + * In the graph filters description, if the input label of the first + * filter is not specified, "in" is assumed; if the output label of + * the last filter is not specified, "out" is assumed. + * + * @param graph the filter graph where to link the parsed graph context + * @param filters string to be parsed + * @param inputs pointer to a linked list to the inputs of the graph, may be NULL. + * If non-NULL, *inputs is updated to contain the list of open inputs + * after the parsing, should be freed with avfilter_inout_free(). + * @param outputs pointer to a linked list to the outputs of the graph, may be NULL. + * If non-NULL, *outputs is updated to contain the list of open outputs + * after the parsing, should be freed with avfilter_inout_free(). + * @return non negative on success, a negative AVERROR code on error + */ +int avfilter_graph_parse_ptr(AVFilterGraph *graph, const char *filters, + AVFilterInOut **inputs, AVFilterInOut **outputs, + void *log_ctx); + +/** + * Add a graph described by a string to a graph. + * + * @param[in] graph the filter graph where to link the parsed graph context + * @param[in] filters string to be parsed + * @param[out] inputs a linked list of all free (unlinked) inputs of the + * parsed graph will be returned here. It is to be freed + * by the caller using avfilter_inout_free(). + * @param[out] outputs a linked list of all free (unlinked) outputs of the + * parsed graph will be returned here. It is to be freed by the + * caller using avfilter_inout_free(). + * @return zero on success, a negative AVERROR code on error + * + * @note This function returns the inputs and outputs that are left + * unlinked after parsing the graph and the caller then deals with + * them. + * @note This function makes no reference whatsoever to already + * existing parts of the graph and the inputs parameter will on return + * contain inputs of the newly parsed part of the graph. Analogously + * the outputs parameter will contain outputs of the newly created + * filters. + */ +int avfilter_graph_parse2(AVFilterGraph *graph, const char *filters, + AVFilterInOut **inputs, + AVFilterInOut **outputs); + +/** + * Send a command to one or more filter instances. + * + * @param graph the filter graph + * @param target the filter(s) to which the command should be sent + * "all" sends to all filters + * otherwise it can be a filter or filter instance name + * which will send the command to all matching filters. + * @param cmd the command to send, for handling simplicity all commands must be alphanumeric only + * @param arg the argument for the command + * @param res a buffer with size res_size where the filter(s) can return a response. + * + * @returns >=0 on success otherwise an error code. + * AVERROR(ENOSYS) on unsupported commands + */ +int avfilter_graph_send_command(AVFilterGraph *graph, const char *target, const char *cmd, const char *arg, char *res, int res_len, int flags); + +/** + * Queue a command for one or more filter instances. + * + * @param graph the filter graph + * @param target the filter(s) to which the command should be sent + * "all" sends to all filters + * otherwise it can be a filter or filter instance name + * which will send the command to all matching filters. + * @param cmd the command to sent, for handling simplicity all commands must be alphanumeric only + * @param arg the argument for the command + * @param ts time at which the command should be sent to the filter + * + * @note As this executes commands after this function returns, no return code + * from the filter is provided, also AVFILTER_CMD_FLAG_ONE is not supported. + */ +int avfilter_graph_queue_command(AVFilterGraph *graph, const char *target, const char *cmd, const char *arg, int flags, double ts); + + +/** + * Dump a graph into a human-readable string representation. + * + * @param graph the graph to dump + * @param options formatting options; currently ignored + * @return a string, or NULL in case of memory allocation failure; + * the string must be freed using av_free + */ +char *avfilter_graph_dump(AVFilterGraph *graph, const char *options); + +/** + * Request a frame on the oldest sink link. + * + * If the request returns AVERROR_EOF, try the next. + * + * Note that this function is not meant to be the sole scheduling mechanism + * of a filtergraph, only a convenience function to help drain a filtergraph + * in a balanced way under normal circumstances. + * + * Also note that AVERROR_EOF does not mean that frames did not arrive on + * some of the sinks during the process. + * When there are multiple sink links, in case the requested link + * returns an EOF, this may cause a filter to flush pending frames + * which are sent to another sink link, although unrequested. + * + * @return the return value of ff_request_frame(), + * or AVERROR_EOF if all links returned AVERROR_EOF + */ +int avfilter_graph_request_oldest(AVFilterGraph *graph); + +/** + * @} + */ + +#endif /* AVFILTER_AVFILTER_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavfilter/avfiltergraph.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavfilter/avfiltergraph.h new file mode 100644 index 0000000..b31d581 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavfilter/avfiltergraph.h @@ -0,0 +1,28 @@ +/* + * Filter graphs + * copyright (c) 2007 Bobby Bingham + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFILTER_AVFILTERGRAPH_H +#define AVFILTER_AVFILTERGRAPH_H + +#include "avfilter.h" +#include "libavutil/log.h" + +#endif /* AVFILTER_AVFILTERGRAPH_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavfilter/buffersink.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavfilter/buffersink.h new file mode 100644 index 0000000..f51fa7c --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavfilter/buffersink.h @@ -0,0 +1,165 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFILTER_BUFFERSINK_H +#define AVFILTER_BUFFERSINK_H + +/** + * @file + * @ingroup lavfi_buffersink + * memory buffer sink API for audio and video + */ + +#include "avfilter.h" + +/** + * @defgroup lavfi_buffersink Buffer sink API + * @ingroup lavfi + * @{ + */ + +/** + * Get a frame with filtered data from sink and put it in frame. + * + * @param ctx pointer to a buffersink or abuffersink filter context. + * @param frame pointer to an allocated frame that will be filled with data. + * The data must be freed using av_frame_unref() / av_frame_free() + * @param flags a combination of AV_BUFFERSINK_FLAG_* flags + * + * @return >= 0 in for success, a negative AVERROR code for failure. + */ +int av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags); + +/** + * Tell av_buffersink_get_buffer_ref() to read video/samples buffer + * reference, but not remove it from the buffer. This is useful if you + * need only to read a video/samples buffer, without to fetch it. + */ +#define AV_BUFFERSINK_FLAG_PEEK 1 + +/** + * Tell av_buffersink_get_buffer_ref() not to request a frame from its input. + * If a frame is already buffered, it is read (and removed from the buffer), + * but if no frame is present, return AVERROR(EAGAIN). + */ +#define AV_BUFFERSINK_FLAG_NO_REQUEST 2 + +/** + * Struct to use for initializing a buffersink context. + */ +typedef struct { + const enum AVPixelFormat *pixel_fmts; ///< list of allowed pixel formats, terminated by AV_PIX_FMT_NONE +} AVBufferSinkParams; + +/** + * Create an AVBufferSinkParams structure. + * + * Must be freed with av_free(). + */ +AVBufferSinkParams *av_buffersink_params_alloc(void); + +/** + * Struct to use for initializing an abuffersink context. + */ +typedef struct { + const enum AVSampleFormat *sample_fmts; ///< list of allowed sample formats, terminated by AV_SAMPLE_FMT_NONE + const int64_t *channel_layouts; ///< list of allowed channel layouts, terminated by -1 + const int *channel_counts; ///< list of allowed channel counts, terminated by -1 + int all_channel_counts; ///< if not 0, accept any channel count or layout + int *sample_rates; ///< list of allowed sample rates, terminated by -1 +} AVABufferSinkParams; + +/** + * Create an AVABufferSinkParams structure. + * + * Must be freed with av_free(). + */ +AVABufferSinkParams *av_abuffersink_params_alloc(void); + +/** + * Set the frame size for an audio buffer sink. + * + * All calls to av_buffersink_get_buffer_ref will return a buffer with + * exactly the specified number of samples, or AVERROR(EAGAIN) if there is + * not enough. The last buffer at EOF will be padded with 0. + */ +void av_buffersink_set_frame_size(AVFilterContext *ctx, unsigned frame_size); + +/** + * @defgroup lavfi_buffersink_accessors Buffer sink accessors + * Get the properties of the stream + * @{ + */ + +enum AVMediaType av_buffersink_get_type (const AVFilterContext *ctx); +AVRational av_buffersink_get_time_base (const AVFilterContext *ctx); +int av_buffersink_get_format (const AVFilterContext *ctx); + +AVRational av_buffersink_get_frame_rate (const AVFilterContext *ctx); +int av_buffersink_get_w (const AVFilterContext *ctx); +int av_buffersink_get_h (const AVFilterContext *ctx); +AVRational av_buffersink_get_sample_aspect_ratio (const AVFilterContext *ctx); + +int av_buffersink_get_channels (const AVFilterContext *ctx); +uint64_t av_buffersink_get_channel_layout (const AVFilterContext *ctx); +int av_buffersink_get_sample_rate (const AVFilterContext *ctx); + +AVBufferRef * av_buffersink_get_hw_frames_ctx (const AVFilterContext *ctx); + +/** @} */ + +/** + * Get a frame with filtered data from sink and put it in frame. + * + * @param ctx pointer to a context of a buffersink or abuffersink AVFilter. + * @param frame pointer to an allocated frame that will be filled with data. + * The data must be freed using av_frame_unref() / av_frame_free() + * + * @return + * - >= 0 if a frame was successfully returned. + * - AVERROR(EAGAIN) if no frames are available at this point; more + * input frames must be added to the filtergraph to get more output. + * - AVERROR_EOF if there will be no more output frames on this sink. + * - A different negative AVERROR code in other failure cases. + */ +int av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame); + +/** + * Same as av_buffersink_get_frame(), but with the ability to specify the number + * of samples read. This function is less efficient than + * av_buffersink_get_frame(), because it copies the data around. + * + * @param ctx pointer to a context of the abuffersink AVFilter. + * @param frame pointer to an allocated frame that will be filled with data. + * The data must be freed using av_frame_unref() / av_frame_free() + * frame will contain exactly nb_samples audio samples, except at + * the end of stream, when it can contain less than nb_samples. + * + * @return The return codes have the same meaning as for + * av_buffersink_get_samples(). + * + * @warning do not mix this function with av_buffersink_get_frame(). Use only one or + * the other with a single sink, not both. + */ +int av_buffersink_get_samples(AVFilterContext *ctx, AVFrame *frame, int nb_samples); + +/** + * @} + */ + +#endif /* AVFILTER_BUFFERSINK_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavfilter/buffersrc.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavfilter/buffersrc.h new file mode 100644 index 0000000..e42c781 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavfilter/buffersrc.h @@ -0,0 +1,201 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFILTER_BUFFERSRC_H +#define AVFILTER_BUFFERSRC_H + +/** + * @file + * @ingroup lavfi_buffersrc + * Memory buffer source API. + */ + +#include "avfilter.h" + +/** + * @defgroup lavfi_buffersrc Buffer source API + * @ingroup lavfi + * @{ + */ + +enum { + + /** + * Do not check for format changes. + */ + AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT = 1, + + /** + * Immediately push the frame to the output. + */ + AV_BUFFERSRC_FLAG_PUSH = 4, + + /** + * Keep a reference to the frame. + * If the frame if reference-counted, create a new reference; otherwise + * copy the frame data. + */ + AV_BUFFERSRC_FLAG_KEEP_REF = 8, + +}; + +/** + * Get the number of failed requests. + * + * A failed request is when the request_frame method is called while no + * frame is present in the buffer. + * The number is reset when a frame is added. + */ +unsigned av_buffersrc_get_nb_failed_requests(AVFilterContext *buffer_src); + +/** + * This structure contains the parameters describing the frames that will be + * passed to this filter. + * + * It should be allocated with av_buffersrc_parameters_alloc() and freed with + * av_free(). All the allocated fields in it remain owned by the caller. + */ +typedef struct AVBufferSrcParameters { + /** + * video: the pixel format, value corresponds to enum AVPixelFormat + * audio: the sample format, value corresponds to enum AVSampleFormat + */ + int format; + /** + * The timebase to be used for the timestamps on the input frames. + */ + AVRational time_base; + + /** + * Video only, the display dimensions of the input frames. + */ + int width, height; + + /** + * Video only, the sample (pixel) aspect ratio. + */ + AVRational sample_aspect_ratio; + + /** + * Video only, the frame rate of the input video. This field must only be + * set to a non-zero value if input stream has a known constant framerate + * and should be left at its initial value if the framerate is variable or + * unknown. + */ + AVRational frame_rate; + + /** + * Video with a hwaccel pixel format only. This should be a reference to an + * AVHWFramesContext instance describing the input frames. + */ + AVBufferRef *hw_frames_ctx; + + /** + * Audio only, the audio sampling rate in samples per secon. + */ + int sample_rate; + + /** + * Audio only, the audio channel layout + */ + uint64_t channel_layout; +} AVBufferSrcParameters; + +/** + * Allocate a new AVBufferSrcParameters instance. It should be freed by the + * caller with av_free(). + */ +AVBufferSrcParameters *av_buffersrc_parameters_alloc(void); + +/** + * Initialize the buffersrc or abuffersrc filter with the provided parameters. + * This function may be called multiple times, the later calls override the + * previous ones. Some of the parameters may also be set through AVOptions, then + * whatever method is used last takes precedence. + * + * @param ctx an instance of the buffersrc or abuffersrc filter + * @param param the stream parameters. The frames later passed to this filter + * must conform to those parameters. All the allocated fields in + * param remain owned by the caller, libavfilter will make internal + * copies or references when necessary. + * @return 0 on success, a negative AVERROR code on failure. + */ +int av_buffersrc_parameters_set(AVFilterContext *ctx, AVBufferSrcParameters *param); + +/** + * Add a frame to the buffer source. + * + * @param ctx an instance of the buffersrc filter + * @param frame frame to be added. If the frame is reference counted, this + * function will make a new reference to it. Otherwise the frame data will be + * copied. + * + * @return 0 on success, a negative AVERROR on error + * + * This function is equivalent to av_buffersrc_add_frame_flags() with the + * AV_BUFFERSRC_FLAG_KEEP_REF flag. + */ +av_warn_unused_result +int av_buffersrc_write_frame(AVFilterContext *ctx, const AVFrame *frame); + +/** + * Add a frame to the buffer source. + * + * @param ctx an instance of the buffersrc filter + * @param frame frame to be added. If the frame is reference counted, this + * function will take ownership of the reference(s) and reset the frame. + * Otherwise the frame data will be copied. If this function returns an error, + * the input frame is not touched. + * + * @return 0 on success, a negative AVERROR on error. + * + * @note the difference between this function and av_buffersrc_write_frame() is + * that av_buffersrc_write_frame() creates a new reference to the input frame, + * while this function takes ownership of the reference passed to it. + * + * This function is equivalent to av_buffersrc_add_frame_flags() without the + * AV_BUFFERSRC_FLAG_KEEP_REF flag. + */ +av_warn_unused_result +int av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame); + +/** + * Add a frame to the buffer source. + * + * By default, if the frame is reference-counted, this function will take + * ownership of the reference(s) and reset the frame. This can be controlled + * using the flags. + * + * If this function returns an error, the input frame is not touched. + * + * @param buffer_src pointer to a buffer source context + * @param frame a frame, or NULL to mark EOF + * @param flags a combination of AV_BUFFERSRC_FLAG_* + * @return >= 0 in case of success, a negative AVERROR code + * in case of failure + */ +av_warn_unused_result +int av_buffersrc_add_frame_flags(AVFilterContext *buffer_src, + AVFrame *frame, int flags); + + +/** + * @} + */ + +#endif /* AVFILTER_BUFFERSRC_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavfilter/version.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavfilter/version.h new file mode 100644 index 0000000..4cbd185 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavfilter/version.h @@ -0,0 +1,74 @@ +/* + * Version macros. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFILTER_VERSION_H +#define AVFILTER_VERSION_H + +/** + * @file + * @ingroup lavfi + * Libavfilter version macros + */ + +#include "libavutil/version.h" + +#define LIBAVFILTER_VERSION_MAJOR 6 +#define LIBAVFILTER_VERSION_MINOR 82 +#define LIBAVFILTER_VERSION_MICRO 100 + +#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ + LIBAVFILTER_VERSION_MINOR, \ + LIBAVFILTER_VERSION_MICRO) +#define LIBAVFILTER_VERSION AV_VERSION(LIBAVFILTER_VERSION_MAJOR, \ + LIBAVFILTER_VERSION_MINOR, \ + LIBAVFILTER_VERSION_MICRO) +#define LIBAVFILTER_BUILD LIBAVFILTER_VERSION_INT + +#define LIBAVFILTER_IDENT "Lavfi" AV_STRINGIFY(LIBAVFILTER_VERSION) + +/** + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + */ + +#ifndef FF_API_OLD_FILTER_OPTS +#define FF_API_OLD_FILTER_OPTS (LIBAVFILTER_VERSION_MAJOR < 7) +#endif +#ifndef FF_API_OLD_FILTER_OPTS_ERROR +#define FF_API_OLD_FILTER_OPTS_ERROR (LIBAVFILTER_VERSION_MAJOR < 7) +#endif +#ifndef FF_API_AVFILTER_OPEN +#define FF_API_AVFILTER_OPEN (LIBAVFILTER_VERSION_MAJOR < 7) +#endif +#ifndef FF_API_AVFILTER_INIT_FILTER +#define FF_API_AVFILTER_INIT_FILTER (LIBAVFILTER_VERSION_MAJOR < 7) +#endif +#ifndef FF_API_OLD_FILTER_REGISTER +#define FF_API_OLD_FILTER_REGISTER (LIBAVFILTER_VERSION_MAJOR < 7) +#endif +#ifndef FF_API_NOCONST_GET_NAME +#define FF_API_NOCONST_GET_NAME (LIBAVFILTER_VERSION_MAJOR < 7) +#endif +#ifndef FF_API_LAVR_OPTS +#define FF_API_LAVR_OPTS (LIBAVFILTER_VERSION_MAJOR < 7) +#endif + +#endif /* AVFILTER_VERSION_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavformat/avformat.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavformat/avformat.h new file mode 100644 index 0000000..4ab217d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavformat/avformat.h @@ -0,0 +1,3008 @@ +/* + * copyright (c) 2001 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFORMAT_AVFORMAT_H +#define AVFORMAT_AVFORMAT_H + +/** + * @file + * @ingroup libavf + * Main libavformat public API header + */ + +/** + * @defgroup libavf libavformat + * I/O and Muxing/Demuxing Library + * + * Libavformat (lavf) is a library for dealing with various media container + * formats. Its main two purposes are demuxing - i.e. splitting a media file + * into component streams, and the reverse process of muxing - writing supplied + * data in a specified container format. It also has an @ref lavf_io + * "I/O module" which supports a number of protocols for accessing the data (e.g. + * file, tcp, http and others). Before using lavf, you need to call + * av_register_all() to register all compiled muxers, demuxers and protocols. + * Unless you are absolutely sure you won't use libavformat's network + * capabilities, you should also call avformat_network_init(). + * + * A supported input format is described by an AVInputFormat struct, conversely + * an output format is described by AVOutputFormat. You can iterate over all + * registered input/output formats using the av_iformat_next() / + * av_oformat_next() functions. The protocols layer is not part of the public + * API, so you can only get the names of supported protocols with the + * avio_enum_protocols() function. + * + * Main lavf structure used for both muxing and demuxing is AVFormatContext, + * which exports all information about the file being read or written. As with + * most Libavformat structures, its size is not part of public ABI, so it cannot be + * allocated on stack or directly with av_malloc(). To create an + * AVFormatContext, use avformat_alloc_context() (some functions, like + * avformat_open_input() might do that for you). + * + * Most importantly an AVFormatContext contains: + * @li the @ref AVFormatContext.iformat "input" or @ref AVFormatContext.oformat + * "output" format. It is either autodetected or set by user for input; + * always set by user for output. + * @li an @ref AVFormatContext.streams "array" of AVStreams, which describe all + * elementary streams stored in the file. AVStreams are typically referred to + * using their index in this array. + * @li an @ref AVFormatContext.pb "I/O context". It is either opened by lavf or + * set by user for input, always set by user for output (unless you are dealing + * with an AVFMT_NOFILE format). + * + * @section lavf_options Passing options to (de)muxers + * It is possible to configure lavf muxers and demuxers using the @ref avoptions + * mechanism. Generic (format-independent) libavformat options are provided by + * AVFormatContext, they can be examined from a user program by calling + * av_opt_next() / av_opt_find() on an allocated AVFormatContext (or its AVClass + * from avformat_get_class()). Private (format-specific) options are provided by + * AVFormatContext.priv_data if and only if AVInputFormat.priv_class / + * AVOutputFormat.priv_class of the corresponding format struct is non-NULL. + * Further options may be provided by the @ref AVFormatContext.pb "I/O context", + * if its AVClass is non-NULL, and the protocols layer. See the discussion on + * nesting in @ref avoptions documentation to learn how to access those. + * + * @section urls + * URL strings in libavformat are made of a scheme/protocol, a ':', and a + * scheme specific string. URLs without a scheme and ':' used for local files + * are supported but deprecated. "file:" should be used for local files. + * + * It is important that the scheme string is not taken from untrusted + * sources without checks. + * + * Note that some schemes/protocols are quite powerful, allowing access to + * both local and remote files, parts of them, concatenations of them, local + * audio and video devices and so on. + * + * @{ + * + * @defgroup lavf_decoding Demuxing + * @{ + * Demuxers read a media file and split it into chunks of data (@em packets). A + * @ref AVPacket "packet" contains one or more encoded frames which belongs to a + * single elementary stream. In the lavf API this process is represented by the + * avformat_open_input() function for opening a file, av_read_frame() for + * reading a single packet and finally avformat_close_input(), which does the + * cleanup. + * + * @section lavf_decoding_open Opening a media file + * The minimum information required to open a file is its URL, which + * is passed to avformat_open_input(), as in the following code: + * @code + * const char *url = "file:in.mp3"; + * AVFormatContext *s = NULL; + * int ret = avformat_open_input(&s, url, NULL, NULL); + * if (ret < 0) + * abort(); + * @endcode + * The above code attempts to allocate an AVFormatContext, open the + * specified file (autodetecting the format) and read the header, exporting the + * information stored there into s. Some formats do not have a header or do not + * store enough information there, so it is recommended that you call the + * avformat_find_stream_info() function which tries to read and decode a few + * frames to find missing information. + * + * In some cases you might want to preallocate an AVFormatContext yourself with + * avformat_alloc_context() and do some tweaking on it before passing it to + * avformat_open_input(). One such case is when you want to use custom functions + * for reading input data instead of lavf internal I/O layer. + * To do that, create your own AVIOContext with avio_alloc_context(), passing + * your reading callbacks to it. Then set the @em pb field of your + * AVFormatContext to newly created AVIOContext. + * + * Since the format of the opened file is in general not known until after + * avformat_open_input() has returned, it is not possible to set demuxer private + * options on a preallocated context. Instead, the options should be passed to + * avformat_open_input() wrapped in an AVDictionary: + * @code + * AVDictionary *options = NULL; + * av_dict_set(&options, "video_size", "640x480", 0); + * av_dict_set(&options, "pixel_format", "rgb24", 0); + * + * if (avformat_open_input(&s, url, NULL, &options) < 0) + * abort(); + * av_dict_free(&options); + * @endcode + * This code passes the private options 'video_size' and 'pixel_format' to the + * demuxer. They would be necessary for e.g. the rawvideo demuxer, since it + * cannot know how to interpret raw video data otherwise. If the format turns + * out to be something different than raw video, those options will not be + * recognized by the demuxer and therefore will not be applied. Such unrecognized + * options are then returned in the options dictionary (recognized options are + * consumed). The calling program can handle such unrecognized options as it + * wishes, e.g. + * @code + * AVDictionaryEntry *e; + * if (e = av_dict_get(options, "", NULL, AV_DICT_IGNORE_SUFFIX)) { + * fprintf(stderr, "Option %s not recognized by the demuxer.\n", e->key); + * abort(); + * } + * @endcode + * + * After you have finished reading the file, you must close it with + * avformat_close_input(). It will free everything associated with the file. + * + * @section lavf_decoding_read Reading from an opened file + * Reading data from an opened AVFormatContext is done by repeatedly calling + * av_read_frame() on it. Each call, if successful, will return an AVPacket + * containing encoded data for one AVStream, identified by + * AVPacket.stream_index. This packet may be passed straight into the libavcodec + * decoding functions avcodec_send_packet() or avcodec_decode_subtitle2() if the + * caller wishes to decode the data. + * + * AVPacket.pts, AVPacket.dts and AVPacket.duration timing information will be + * set if known. They may also be unset (i.e. AV_NOPTS_VALUE for + * pts/dts, 0 for duration) if the stream does not provide them. The timing + * information will be in AVStream.time_base units, i.e. it has to be + * multiplied by the timebase to convert them to seconds. + * + * If AVPacket.buf is set on the returned packet, then the packet is + * allocated dynamically and the user may keep it indefinitely. + * Otherwise, if AVPacket.buf is NULL, the packet data is backed by a + * static storage somewhere inside the demuxer and the packet is only valid + * until the next av_read_frame() call or closing the file. If the caller + * requires a longer lifetime, av_dup_packet() will make an av_malloc()ed copy + * of it. + * In both cases, the packet must be freed with av_packet_unref() when it is no + * longer needed. + * + * @section lavf_decoding_seek Seeking + * @} + * + * @defgroup lavf_encoding Muxing + * @{ + * Muxers take encoded data in the form of @ref AVPacket "AVPackets" and write + * it into files or other output bytestreams in the specified container format. + * + * The main API functions for muxing are avformat_write_header() for writing the + * file header, av_write_frame() / av_interleaved_write_frame() for writing the + * packets and av_write_trailer() for finalizing the file. + * + * At the beginning of the muxing process, the caller must first call + * avformat_alloc_context() to create a muxing context. The caller then sets up + * the muxer by filling the various fields in this context: + * + * - The @ref AVFormatContext.oformat "oformat" field must be set to select the + * muxer that will be used. + * - Unless the format is of the AVFMT_NOFILE type, the @ref AVFormatContext.pb + * "pb" field must be set to an opened IO context, either returned from + * avio_open2() or a custom one. + * - Unless the format is of the AVFMT_NOSTREAMS type, at least one stream must + * be created with the avformat_new_stream() function. The caller should fill + * the @ref AVStream.codecpar "stream codec parameters" information, such as the + * codec @ref AVCodecParameters.codec_type "type", @ref AVCodecParameters.codec_id + * "id" and other parameters (e.g. width / height, the pixel or sample format, + * etc.) as known. The @ref AVStream.time_base "stream timebase" should + * be set to the timebase that the caller desires to use for this stream (note + * that the timebase actually used by the muxer can be different, as will be + * described later). + * - It is advised to manually initialize only the relevant fields in + * AVCodecParameters, rather than using @ref avcodec_parameters_copy() during + * remuxing: there is no guarantee that the codec context values remain valid + * for both input and output format contexts. + * - The caller may fill in additional information, such as @ref + * AVFormatContext.metadata "global" or @ref AVStream.metadata "per-stream" + * metadata, @ref AVFormatContext.chapters "chapters", @ref + * AVFormatContext.programs "programs", etc. as described in the + * AVFormatContext documentation. Whether such information will actually be + * stored in the output depends on what the container format and the muxer + * support. + * + * When the muxing context is fully set up, the caller must call + * avformat_write_header() to initialize the muxer internals and write the file + * header. Whether anything actually is written to the IO context at this step + * depends on the muxer, but this function must always be called. Any muxer + * private options must be passed in the options parameter to this function. + * + * The data is then sent to the muxer by repeatedly calling av_write_frame() or + * av_interleaved_write_frame() (consult those functions' documentation for + * discussion on the difference between them; only one of them may be used with + * a single muxing context, they should not be mixed). Do note that the timing + * information on the packets sent to the muxer must be in the corresponding + * AVStream's timebase. That timebase is set by the muxer (in the + * avformat_write_header() step) and may be different from the timebase + * requested by the caller. + * + * Once all the data has been written, the caller must call av_write_trailer() + * to flush any buffered packets and finalize the output file, then close the IO + * context (if any) and finally free the muxing context with + * avformat_free_context(). + * @} + * + * @defgroup lavf_io I/O Read/Write + * @{ + * @section lavf_io_dirlist Directory listing + * The directory listing API makes it possible to list files on remote servers. + * + * Some of possible use cases: + * - an "open file" dialog to choose files from a remote location, + * - a recursive media finder providing a player with an ability to play all + * files from a given directory. + * + * @subsection lavf_io_dirlist_open Opening a directory + * At first, a directory needs to be opened by calling avio_open_dir() + * supplied with a URL and, optionally, ::AVDictionary containing + * protocol-specific parameters. The function returns zero or positive + * integer and allocates AVIODirContext on success. + * + * @code + * AVIODirContext *ctx = NULL; + * if (avio_open_dir(&ctx, "smb://example.com/some_dir", NULL) < 0) { + * fprintf(stderr, "Cannot open directory.\n"); + * abort(); + * } + * @endcode + * + * This code tries to open a sample directory using smb protocol without + * any additional parameters. + * + * @subsection lavf_io_dirlist_read Reading entries + * Each directory's entry (i.e. file, another directory, anything else + * within ::AVIODirEntryType) is represented by AVIODirEntry. + * Reading consecutive entries from an opened AVIODirContext is done by + * repeatedly calling avio_read_dir() on it. Each call returns zero or + * positive integer if successful. Reading can be stopped right after the + * NULL entry has been read -- it means there are no entries left to be + * read. The following code reads all entries from a directory associated + * with ctx and prints their names to standard output. + * @code + * AVIODirEntry *entry = NULL; + * for (;;) { + * if (avio_read_dir(ctx, &entry) < 0) { + * fprintf(stderr, "Cannot list directory.\n"); + * abort(); + * } + * if (!entry) + * break; + * printf("%s\n", entry->name); + * avio_free_directory_entry(&entry); + * } + * @endcode + * @} + * + * @defgroup lavf_codec Demuxers + * @{ + * @defgroup lavf_codec_native Native Demuxers + * @{ + * @} + * @defgroup lavf_codec_wrappers External library wrappers + * @{ + * @} + * @} + * @defgroup lavf_protos I/O Protocols + * @{ + * @} + * @defgroup lavf_internal Internal + * @{ + * @} + * @} + */ + +#include +#include /* FILE */ +#include "libavcodec/avcodec.h" +#include "libavutil/dict.h" +#include "libavutil/log.h" + +#include "avio.h" +#include "libavformat/version.h" + +struct AVFormatContext; + +struct AVDeviceInfoList; +struct AVDeviceCapabilitiesQuery; + +/** + * @defgroup metadata_api Public Metadata API + * @{ + * @ingroup libavf + * The metadata API allows libavformat to export metadata tags to a client + * application when demuxing. Conversely it allows a client application to + * set metadata when muxing. + * + * Metadata is exported or set as pairs of key/value strings in the 'metadata' + * fields of the AVFormatContext, AVStream, AVChapter and AVProgram structs + * using the @ref lavu_dict "AVDictionary" API. Like all strings in FFmpeg, + * metadata is assumed to be UTF-8 encoded Unicode. Note that metadata + * exported by demuxers isn't checked to be valid UTF-8 in most cases. + * + * Important concepts to keep in mind: + * - Keys are unique; there can never be 2 tags with the same key. This is + * also meant semantically, i.e., a demuxer should not knowingly produce + * several keys that are literally different but semantically identical. + * E.g., key=Author5, key=Author6. In this example, all authors must be + * placed in the same tag. + * - Metadata is flat, not hierarchical; there are no subtags. If you + * want to store, e.g., the email address of the child of producer Alice + * and actor Bob, that could have key=alice_and_bobs_childs_email_address. + * - Several modifiers can be applied to the tag name. This is done by + * appending a dash character ('-') and the modifier name in the order + * they appear in the list below -- e.g. foo-eng-sort, not foo-sort-eng. + * - language -- a tag whose value is localized for a particular language + * is appended with the ISO 639-2/B 3-letter language code. + * For example: Author-ger=Michael, Author-eng=Mike + * The original/default language is in the unqualified "Author" tag. + * A demuxer should set a default if it sets any translated tag. + * - sorting -- a modified version of a tag that should be used for + * sorting will have '-sort' appended. E.g. artist="The Beatles", + * artist-sort="Beatles, The". + * - Some protocols and demuxers support metadata updates. After a successful + * call to av_read_packet(), AVFormatContext.event_flags or AVStream.event_flags + * will be updated to indicate if metadata changed. In order to detect metadata + * changes on a stream, you need to loop through all streams in the AVFormatContext + * and check their individual event_flags. + * + * - Demuxers attempt to export metadata in a generic format, however tags + * with no generic equivalents are left as they are stored in the container. + * Follows a list of generic tag names: + * + @verbatim + album -- name of the set this work belongs to + album_artist -- main creator of the set/album, if different from artist. + e.g. "Various Artists" for compilation albums. + artist -- main creator of the work + comment -- any additional description of the file. + composer -- who composed the work, if different from artist. + copyright -- name of copyright holder. + creation_time-- date when the file was created, preferably in ISO 8601. + date -- date when the work was created, preferably in ISO 8601. + disc -- number of a subset, e.g. disc in a multi-disc collection. + encoder -- name/settings of the software/hardware that produced the file. + encoded_by -- person/group who created the file. + filename -- original name of the file. + genre -- . + language -- main language in which the work is performed, preferably + in ISO 639-2 format. Multiple languages can be specified by + separating them with commas. + performer -- artist who performed the work, if different from artist. + E.g for "Also sprach Zarathustra", artist would be "Richard + Strauss" and performer "London Philharmonic Orchestra". + publisher -- name of the label/publisher. + service_name -- name of the service in broadcasting (channel name). + service_provider -- name of the service provider in broadcasting. + title -- name of the work. + track -- number of this work in the set, can be in form current/total. + variant_bitrate -- the total bitrate of the bitrate variant that the current stream is part of + @endverbatim + * + * Look in the examples section for an application example how to use the Metadata API. + * + * @} + */ + +/* packet functions */ + + +/** + * Allocate and read the payload of a packet and initialize its + * fields with default values. + * + * @param s associated IO context + * @param pkt packet + * @param size desired payload size + * @return >0 (read size) if OK, AVERROR_xxx otherwise + */ +int av_get_packet(AVIOContext *s, AVPacket *pkt, int size); + + +/** + * Read data and append it to the current content of the AVPacket. + * If pkt->size is 0 this is identical to av_get_packet. + * Note that this uses av_grow_packet and thus involves a realloc + * which is inefficient. Thus this function should only be used + * when there is no reasonable way to know (an upper bound of) + * the final size. + * + * @param s associated IO context + * @param pkt packet + * @param size amount of data to read + * @return >0 (read size) if OK, AVERROR_xxx otherwise, previous data + * will not be lost even if an error occurs. + */ +int av_append_packet(AVIOContext *s, AVPacket *pkt, int size); + +#if FF_API_LAVF_FRAC +/*************************************************/ +/* fractional numbers for exact pts handling */ + +/** + * The exact value of the fractional number is: 'val + num / den'. + * num is assumed to be 0 <= num < den. + */ +typedef struct AVFrac { + int64_t val, num, den; +} AVFrac; +#endif + +/*************************************************/ +/* input/output formats */ + +struct AVCodecTag; + +/** + * This structure contains the data a format has to probe a file. + */ +typedef struct AVProbeData { + const char *filename; + unsigned char *buf; /**< Buffer must have AVPROBE_PADDING_SIZE of extra allocated bytes filled with zero. */ + int buf_size; /**< Size of buf except extra allocated bytes */ + const char *mime_type; /**< mime_type, when known. */ +} AVProbeData; + +#define AVPROBE_SCORE_RETRY (AVPROBE_SCORE_MAX/4) +#define AVPROBE_SCORE_STREAM_RETRY (AVPROBE_SCORE_MAX/4-1) + +#define AVPROBE_SCORE_EXTENSION 50 ///< score for file extension +#define AVPROBE_SCORE_MIME 75 ///< score for file mime type +#define AVPROBE_SCORE_MAX 100 ///< maximum score + +#define AVPROBE_PADDING_SIZE 32 ///< extra allocated bytes at the end of the probe buffer + +/// Demuxer will use avio_open, no opened file should be provided by the caller. +#define AVFMT_NOFILE 0x0001 +#define AVFMT_NEEDNUMBER 0x0002 /**< Needs '%d' in filename. */ +#define AVFMT_SHOW_IDS 0x0008 /**< Show format stream IDs numbers. */ +#if FF_API_LAVF_FMT_RAWPICTURE +#define AVFMT_RAWPICTURE 0x0020 /**< Format wants AVPicture structure for + raw picture data. @deprecated Not used anymore */ +#endif +#define AVFMT_GLOBALHEADER 0x0040 /**< Format wants global header. */ +#define AVFMT_NOTIMESTAMPS 0x0080 /**< Format does not need / have any timestamps. */ +#define AVFMT_GENERIC_INDEX 0x0100 /**< Use generic index building code. */ +#define AVFMT_TS_DISCONT 0x0200 /**< Format allows timestamp discontinuities. Note, muxers always require valid (monotone) timestamps */ +#define AVFMT_VARIABLE_FPS 0x0400 /**< Format allows variable fps. */ +#define AVFMT_NODIMENSIONS 0x0800 /**< Format does not need width/height */ +#define AVFMT_NOSTREAMS 0x1000 /**< Format does not require any streams */ +#define AVFMT_NOBINSEARCH 0x2000 /**< Format does not allow to fall back on binary search via read_timestamp */ +#define AVFMT_NOGENSEARCH 0x4000 /**< Format does not allow to fall back on generic search */ +#define AVFMT_NO_BYTE_SEEK 0x8000 /**< Format does not allow seeking by bytes */ +#define AVFMT_ALLOW_FLUSH 0x10000 /**< Format allows flushing. If not set, the muxer will not receive a NULL packet in the write_packet function. */ +#define AVFMT_TS_NONSTRICT 0x20000 /**< Format does not require strictly + increasing timestamps, but they must + still be monotonic */ +#define AVFMT_TS_NEGATIVE 0x40000 /**< Format allows muxing negative + timestamps. If not set the timestamp + will be shifted in av_write_frame and + av_interleaved_write_frame so they + start from 0. + The user or muxer can override this through + AVFormatContext.avoid_negative_ts + */ + +#define AVFMT_SEEK_TO_PTS 0x4000000 /**< Seeking is based on PTS */ + +/** + * @addtogroup lavf_encoding + * @{ + */ +typedef struct AVOutputFormat { + const char *name; + /** + * Descriptive name for the format, meant to be more human-readable + * than name. You should use the NULL_IF_CONFIG_SMALL() macro + * to define it. + */ + const char *long_name; + const char *mime_type; + const char *extensions; /**< comma-separated filename extensions */ + /* output support */ + enum AVCodecID audio_codec; /**< default audio codec */ + enum AVCodecID video_codec; /**< default video codec */ + enum AVCodecID subtitle_codec; /**< default subtitle codec */ + /** + * can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, + * AVFMT_GLOBALHEADER, AVFMT_NOTIMESTAMPS, AVFMT_VARIABLE_FPS, + * AVFMT_NODIMENSIONS, AVFMT_NOSTREAMS, AVFMT_ALLOW_FLUSH, + * AVFMT_TS_NONSTRICT, AVFMT_TS_NEGATIVE + */ + int flags; + + /** + * List of supported codec_id-codec_tag pairs, ordered by "better + * choice first". The arrays are all terminated by AV_CODEC_ID_NONE. + */ + const struct AVCodecTag * const *codec_tag; + + + const AVClass *priv_class; ///< AVClass for the private context + + /***************************************************************** + * No fields below this line are part of the public API. They + * may not be used outside of libavformat and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + struct AVOutputFormat *next; + /** + * size of private data so that it can be allocated in the wrapper + */ + int priv_data_size; + + int (*write_header)(struct AVFormatContext *); + /** + * Write a packet. If AVFMT_ALLOW_FLUSH is set in flags, + * pkt can be NULL in order to flush data buffered in the muxer. + * When flushing, return 0 if there still is more data to flush, + * or 1 if everything was flushed and there is no more buffered + * data. + */ + int (*write_packet)(struct AVFormatContext *, AVPacket *pkt); + int (*write_trailer)(struct AVFormatContext *); + /** + * Currently only used to set pixel format if not YUV420P. + */ + int (*interleave_packet)(struct AVFormatContext *, AVPacket *out, + AVPacket *in, int flush); + /** + * Test if the given codec can be stored in this container. + * + * @return 1 if the codec is supported, 0 if it is not. + * A negative number if unknown. + * MKTAG('A', 'P', 'I', 'C') if the codec is only supported as AV_DISPOSITION_ATTACHED_PIC + */ + int (*query_codec)(enum AVCodecID id, int std_compliance); + + void (*get_output_timestamp)(struct AVFormatContext *s, int stream, + int64_t *dts, int64_t *wall); + /** + * Allows sending messages from application to device. + */ + int (*control_message)(struct AVFormatContext *s, int type, + void *data, size_t data_size); + + /** + * Write an uncoded AVFrame. + * + * See av_write_uncoded_frame() for details. + * + * The library will free *frame afterwards, but the muxer can prevent it + * by setting the pointer to NULL. + */ + int (*write_uncoded_frame)(struct AVFormatContext *, int stream_index, + AVFrame **frame, unsigned flags); + /** + * Returns device list with it properties. + * @see avdevice_list_devices() for more details. + */ + int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list); + /** + * Initialize device capabilities submodule. + * @see avdevice_capabilities_create() for more details. + */ + int (*create_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); + /** + * Free device capabilities submodule. + * @see avdevice_capabilities_free() for more details. + */ + int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); + enum AVCodecID data_codec; /**< default data codec */ + /** + * Initialize format. May allocate data here, and set any AVFormatContext or + * AVStream parameters that need to be set before packets are sent. + * This method must not write output. + * + * Return 0 if streams were fully configured, 1 if not, negative AVERROR on failure + * + * Any allocations made here must be freed in deinit(). + */ + int (*init)(struct AVFormatContext *); + /** + * Deinitialize format. If present, this is called whenever the muxer is being + * destroyed, regardless of whether or not the header has been written. + * + * If a trailer is being written, this is called after write_trailer(). + * + * This is called if init() fails as well. + */ + void (*deinit)(struct AVFormatContext *); + /** + * Set up any necessary bitstream filtering and extract any extra data needed + * for the global header. + * Return 0 if more packets from this stream must be checked; 1 if not. + */ + int (*check_bitstream)(struct AVFormatContext *, const AVPacket *pkt); +} AVOutputFormat; +/** + * @} + */ + +/** + * @addtogroup lavf_decoding + * @{ + */ +typedef struct AVInputFormat { + /** + * A comma separated list of short names for the format. New names + * may be appended with a minor bump. + */ + const char *name; + + /** + * Descriptive name for the format, meant to be more human-readable + * than name. You should use the NULL_IF_CONFIG_SMALL() macro + * to define it. + */ + const char *long_name; + + /** + * Can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_SHOW_IDS, + * AVFMT_GENERIC_INDEX, AVFMT_TS_DISCONT, AVFMT_NOBINSEARCH, + * AVFMT_NOGENSEARCH, AVFMT_NO_BYTE_SEEK, AVFMT_SEEK_TO_PTS. + */ + int flags; + + /** + * If extensions are defined, then no probe is done. You should + * usually not use extension format guessing because it is not + * reliable enough + */ + const char *extensions; + + const struct AVCodecTag * const *codec_tag; + + const AVClass *priv_class; ///< AVClass for the private context + + /** + * Comma-separated list of mime types. + * It is used check for matching mime types while probing. + * @see av_probe_input_format2 + */ + const char *mime_type; + + /***************************************************************** + * No fields below this line are part of the public API. They + * may not be used outside of libavformat and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + struct AVInputFormat *next; + + /** + * Raw demuxers store their codec ID here. + */ + int raw_codec_id; + + /** + * Size of private data so that it can be allocated in the wrapper. + */ + int priv_data_size; + + /** + * Tell if a given file has a chance of being parsed as this format. + * The buffer provided is guaranteed to be AVPROBE_PADDING_SIZE bytes + * big so you do not have to check for that unless you need more. + */ + int (*read_probe)(AVProbeData *); + + /** + * Read the format header and initialize the AVFormatContext + * structure. Return 0 if OK. 'avformat_new_stream' should be + * called to create new streams. + */ + int (*read_header)(struct AVFormatContext *); + + /** + * Read one packet and put it in 'pkt'. pts and flags are also + * set. 'avformat_new_stream' can be called only if the flag + * AVFMTCTX_NOHEADER is used and only in the calling thread (not in a + * background thread). + * @return 0 on success, < 0 on error. + * When returning an error, pkt must not have been allocated + * or must be freed before returning + */ + int (*read_packet)(struct AVFormatContext *, AVPacket *pkt); + + /** + * Close the stream. The AVFormatContext and AVStreams are not + * freed by this function + */ + int (*read_close)(struct AVFormatContext *); + + /** + * Seek to a given timestamp relative to the frames in + * stream component stream_index. + * @param stream_index Must not be -1. + * @param flags Selects which direction should be preferred if no exact + * match is available. + * @return >= 0 on success (but not necessarily the new offset) + */ + int (*read_seek)(struct AVFormatContext *, + int stream_index, int64_t timestamp, int flags); + + /** + * Get the next timestamp in stream[stream_index].time_base units. + * @return the timestamp or AV_NOPTS_VALUE if an error occurred + */ + int64_t (*read_timestamp)(struct AVFormatContext *s, int stream_index, + int64_t *pos, int64_t pos_limit); + + /** + * Start/resume playing - only meaningful if using a network-based format + * (RTSP). + */ + int (*read_play)(struct AVFormatContext *); + + /** + * Pause playing - only meaningful if using a network-based format + * (RTSP). + */ + int (*read_pause)(struct AVFormatContext *); + + /** + * Seek to timestamp ts. + * Seeking will be done so that the point from which all active streams + * can be presented successfully will be closest to ts and within min/max_ts. + * Active streams are all streams that have AVStream.discard < AVDISCARD_ALL. + */ + int (*read_seek2)(struct AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags); + + /** + * Returns device list with it properties. + * @see avdevice_list_devices() for more details. + */ + int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list); + + /** + * Initialize device capabilities submodule. + * @see avdevice_capabilities_create() for more details. + */ + int (*create_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); + + /** + * Free device capabilities submodule. + * @see avdevice_capabilities_free() for more details. + */ + int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); +} AVInputFormat; +/** + * @} + */ + +enum AVStreamParseType { + AVSTREAM_PARSE_NONE, + AVSTREAM_PARSE_FULL, /**< full parsing and repack */ + AVSTREAM_PARSE_HEADERS, /**< Only parse headers, do not repack. */ + AVSTREAM_PARSE_TIMESTAMPS, /**< full parsing and interpolation of timestamps for frames not starting on a packet boundary */ + AVSTREAM_PARSE_FULL_ONCE, /**< full parsing and repack of the first frame only, only implemented for H.264 currently */ + AVSTREAM_PARSE_FULL_RAW=MKTAG(0,'R','A','W'), /**< full parsing and repack with timestamp and position generation by parser for raw + this assumes that each packet in the file contains no demuxer level headers and + just codec level data, otherwise position generation would fail */ +}; + +typedef struct AVIndexEntry { + int64_t pos; + int64_t timestamp; /**< + * Timestamp in AVStream.time_base units, preferably the time from which on correctly decoded frames are available + * when seeking to this entry. That means preferable PTS on keyframe based formats. + * But demuxers can choose to store a different timestamp, if it is more convenient for the implementation or nothing better + * is known + */ +#define AVINDEX_KEYFRAME 0x0001 +#define AVINDEX_DISCARD_FRAME 0x0002 /** + * Flag is used to indicate which frame should be discarded after decoding. + */ + int flags:2; + int size:30; //Yeah, trying to keep the size of this small to reduce memory requirements (it is 24 vs. 32 bytes due to possible 8-byte alignment). + int min_distance; /**< Minimum distance between this and the previous keyframe, used to avoid unneeded searching. */ +} AVIndexEntry; + +#define AV_DISPOSITION_DEFAULT 0x0001 +#define AV_DISPOSITION_DUB 0x0002 +#define AV_DISPOSITION_ORIGINAL 0x0004 +#define AV_DISPOSITION_COMMENT 0x0008 +#define AV_DISPOSITION_LYRICS 0x0010 +#define AV_DISPOSITION_KARAOKE 0x0020 + +/** + * Track should be used during playback by default. + * Useful for subtitle track that should be displayed + * even when user did not explicitly ask for subtitles. + */ +#define AV_DISPOSITION_FORCED 0x0040 +#define AV_DISPOSITION_HEARING_IMPAIRED 0x0080 /**< stream for hearing impaired audiences */ +#define AV_DISPOSITION_VISUAL_IMPAIRED 0x0100 /**< stream for visual impaired audiences */ +#define AV_DISPOSITION_CLEAN_EFFECTS 0x0200 /**< stream without voice */ +/** + * The stream is stored in the file as an attached picture/"cover art" (e.g. + * APIC frame in ID3v2). The first (usually only) packet associated with it + * will be returned among the first few packets read from the file unless + * seeking takes place. It can also be accessed at any time in + * AVStream.attached_pic. + */ +#define AV_DISPOSITION_ATTACHED_PIC 0x0400 +/** + * The stream is sparse, and contains thumbnail images, often corresponding + * to chapter markers. Only ever used with AV_DISPOSITION_ATTACHED_PIC. + */ +#define AV_DISPOSITION_TIMED_THUMBNAILS 0x0800 + +typedef struct AVStreamInternal AVStreamInternal; + +/** + * To specify text track kind (different from subtitles default). + */ +#define AV_DISPOSITION_CAPTIONS 0x10000 +#define AV_DISPOSITION_DESCRIPTIONS 0x20000 +#define AV_DISPOSITION_METADATA 0x40000 + +/** + * Options for behavior on timestamp wrap detection. + */ +#define AV_PTS_WRAP_IGNORE 0 ///< ignore the wrap +#define AV_PTS_WRAP_ADD_OFFSET 1 ///< add the format specific offset on wrap detection +#define AV_PTS_WRAP_SUB_OFFSET -1 ///< subtract the format specific offset on wrap detection + +/** + * Stream structure. + * New fields can be added to the end with minor version bumps. + * Removal, reordering and changes to existing fields require a major + * version bump. + * sizeof(AVStream) must not be used outside libav*. + */ +typedef struct AVStream { + int index; /**< stream index in AVFormatContext */ + /** + * Format-specific stream ID. + * decoding: set by libavformat + * encoding: set by the user, replaced by libavformat if left unset + */ + int id; +#if FF_API_LAVF_AVCTX + /** + * @deprecated use the codecpar struct instead + */ + attribute_deprecated + AVCodecContext *codec; +#endif + void *priv_data; + +#if FF_API_LAVF_FRAC + /** + * @deprecated this field is unused + */ + attribute_deprecated + struct AVFrac pts; +#endif + + /** + * This is the fundamental unit of time (in seconds) in terms + * of which frame timestamps are represented. + * + * decoding: set by libavformat + * encoding: May be set by the caller before avformat_write_header() to + * provide a hint to the muxer about the desired timebase. In + * avformat_write_header(), the muxer will overwrite this field + * with the timebase that will actually be used for the timestamps + * written into the file (which may or may not be related to the + * user-provided one, depending on the format). + */ + AVRational time_base; + + /** + * Decoding: pts of the first frame of the stream in presentation order, in stream time base. + * Only set this if you are absolutely 100% sure that the value you set + * it to really is the pts of the first frame. + * This may be undefined (AV_NOPTS_VALUE). + * @note The ASF header does NOT contain a correct start_time the ASF + * demuxer must NOT set this. + */ + int64_t start_time; + + /** + * Decoding: duration of the stream, in stream time base. + * If a source file does not specify a duration, but does specify + * a bitrate, this value will be estimated from bitrate and file size. + * + * Encoding: May be set by the caller before avformat_write_header() to + * provide a hint to the muxer about the estimated duration. + */ + int64_t duration; + + int64_t nb_frames; ///< number of frames in this stream if known or 0 + + int disposition; /**< AV_DISPOSITION_* bit field */ + + enum AVDiscard discard; ///< Selects which packets can be discarded at will and do not need to be demuxed. + + /** + * sample aspect ratio (0 if unknown) + * - encoding: Set by user. + * - decoding: Set by libavformat. + */ + AVRational sample_aspect_ratio; + + AVDictionary *metadata; + + /** + * Average framerate + * + * - demuxing: May be set by libavformat when creating the stream or in + * avformat_find_stream_info(). + * - muxing: May be set by the caller before avformat_write_header(). + */ + AVRational avg_frame_rate; + + /** + * For streams with AV_DISPOSITION_ATTACHED_PIC disposition, this packet + * will contain the attached picture. + * + * decoding: set by libavformat, must not be modified by the caller. + * encoding: unused + */ + AVPacket attached_pic; + + /** + * An array of side data that applies to the whole stream (i.e. the + * container does not allow it to change between packets). + * + * There may be no overlap between the side data in this array and side data + * in the packets. I.e. a given side data is either exported by the muxer + * (demuxing) / set by the caller (muxing) in this array, then it never + * appears in the packets, or the side data is exported / sent through + * the packets (always in the first packet where the value becomes known or + * changes), then it does not appear in this array. + * + * - demuxing: Set by libavformat when the stream is created. + * - muxing: May be set by the caller before avformat_write_header(). + * + * Freed by libavformat in avformat_free_context(). + * + * @see av_format_inject_global_side_data() + */ + AVPacketSideData *side_data; + /** + * The number of elements in the AVStream.side_data array. + */ + int nb_side_data; + + /** + * Flags for the user to detect events happening on the stream. Flags must + * be cleared by the user once the event has been handled. + * A combination of AVSTREAM_EVENT_FLAG_*. + */ + int event_flags; +#define AVSTREAM_EVENT_FLAG_METADATA_UPDATED 0x0001 ///< The call resulted in updated metadata. + + /***************************************************************** + * All fields below this line are not part of the public API. They + * may not be used outside of libavformat and can be changed and + * removed at will. + * Internal note: be aware that physically removing these fields + * will break ABI. Replace removed fields with dummy fields, and + * add new fields to AVStreamInternal. + ***************************************************************** + */ + + /** + * Stream information used internally by avformat_find_stream_info() + */ +#define MAX_STD_TIMEBASES (30*12+30+3+6) + struct { + int64_t last_dts; + int64_t duration_gcd; + int duration_count; + int64_t rfps_duration_sum; + double (*duration_error)[2][MAX_STD_TIMEBASES]; + int64_t codec_info_duration; + int64_t codec_info_duration_fields; + + /** + * 0 -> decoder has not been searched for yet. + * >0 -> decoder found + * <0 -> decoder with codec_id == -found_decoder has not been found + */ + int found_decoder; + + int64_t last_duration; + + /** + * Those are used for average framerate estimation. + */ + int64_t fps_first_dts; + int fps_first_dts_idx; + int64_t fps_last_dts; + int fps_last_dts_idx; + + } *info; + + int pts_wrap_bits; /**< number of bits in pts (used for wrapping control) */ + + // Timestamp generation support: + /** + * Timestamp corresponding to the last dts sync point. + * + * Initialized when AVCodecParserContext.dts_sync_point >= 0 and + * a DTS is received from the underlying container. Otherwise set to + * AV_NOPTS_VALUE by default. + */ + int64_t first_dts; + int64_t cur_dts; + int64_t last_IP_pts; + int last_IP_duration; + + /** + * Number of packets to buffer for codec probing + */ + int probe_packets; + + /** + * Number of frames that have been demuxed during avformat_find_stream_info() + */ + int codec_info_nb_frames; + + /* av_read_frame() support */ + enum AVStreamParseType need_parsing; + struct AVCodecParserContext *parser; + + /** + * last packet in packet_buffer for this stream when muxing. + */ + struct AVPacketList *last_in_packet_buffer; + AVProbeData probe_data; +#define MAX_REORDER_DELAY 16 + int64_t pts_buffer[MAX_REORDER_DELAY+1]; + + AVIndexEntry *index_entries; /**< Only used if the format does not + support seeking natively. */ + int nb_index_entries; + unsigned int index_entries_allocated_size; + + /** + * Real base framerate of the stream. + * This is the lowest framerate with which all timestamps can be + * represented accurately (it is the least common multiple of all + * framerates in the stream). Note, this value is just a guess! + * For example, if the time base is 1/90000 and all frames have either + * approximately 3600 or 1800 timer ticks, then r_frame_rate will be 50/1. + * + * Code outside avformat should access this field using: + * av_stream_get/set_r_frame_rate(stream) + */ + AVRational r_frame_rate; + + /** + * Stream Identifier + * This is the MPEG-TS stream identifier +1 + * 0 means unknown + */ + int stream_identifier; + + int64_t interleaver_chunk_size; + int64_t interleaver_chunk_duration; + + /** + * stream probing state + * -1 -> probing finished + * 0 -> no probing requested + * rest -> perform probing with request_probe being the minimum score to accept. + * NOT PART OF PUBLIC API + */ + int request_probe; + /** + * Indicates that everything up to the next keyframe + * should be discarded. + */ + int skip_to_keyframe; + + /** + * Number of samples to skip at the start of the frame decoded from the next packet. + */ + int skip_samples; + + /** + * If not 0, the number of samples that should be skipped from the start of + * the stream (the samples are removed from packets with pts==0, which also + * assumes negative timestamps do not happen). + * Intended for use with formats such as mp3 with ad-hoc gapless audio + * support. + */ + int64_t start_skip_samples; + + /** + * If not 0, the first audio sample that should be discarded from the stream. + * This is broken by design (needs global sample count), but can't be + * avoided for broken by design formats such as mp3 with ad-hoc gapless + * audio support. + */ + int64_t first_discard_sample; + + /** + * The sample after last sample that is intended to be discarded after + * first_discard_sample. Works on frame boundaries only. Used to prevent + * early EOF if the gapless info is broken (considered concatenated mp3s). + */ + int64_t last_discard_sample; + + /** + * Number of internally decoded frames, used internally in libavformat, do not access + * its lifetime differs from info which is why it is not in that structure. + */ + int nb_decoded_frames; + + /** + * Timestamp offset added to timestamps before muxing + * NOT PART OF PUBLIC API + */ + int64_t mux_ts_offset; + + /** + * Internal data to check for wrapping of the time stamp + */ + int64_t pts_wrap_reference; + + /** + * Options for behavior, when a wrap is detected. + * + * Defined by AV_PTS_WRAP_ values. + * + * If correction is enabled, there are two possibilities: + * If the first time stamp is near the wrap point, the wrap offset + * will be subtracted, which will create negative time stamps. + * Otherwise the offset will be added. + */ + int pts_wrap_behavior; + + /** + * Internal data to prevent doing update_initial_durations() twice + */ + int update_initial_durations_done; + + /** + * Internal data to generate dts from pts + */ + int64_t pts_reorder_error[MAX_REORDER_DELAY+1]; + uint8_t pts_reorder_error_count[MAX_REORDER_DELAY+1]; + + /** + * Internal data to analyze DTS and detect faulty mpeg streams + */ + int64_t last_dts_for_order_check; + uint8_t dts_ordered; + uint8_t dts_misordered; + + /** + * Internal data to inject global side data + */ + int inject_global_side_data; + + /***************************************************************** + * All fields above this line are not part of the public API. + * Fields below are part of the public API and ABI again. + ***************************************************************** + */ + + /** + * String containing paris of key and values describing recommended encoder configuration. + * Paris are separated by ','. + * Keys are separated from values by '='. + */ + char *recommended_encoder_configuration; + + /** + * display aspect ratio (0 if unknown) + * - encoding: unused + * - decoding: Set by libavformat to calculate sample_aspect_ratio internally + */ + AVRational display_aspect_ratio; + + struct FFFrac *priv_pts; + + /** + * An opaque field for libavformat internal usage. + * Must not be accessed in any way by callers. + */ + AVStreamInternal *internal; + + /* + * Codec parameters associated with this stream. Allocated and freed by + * libavformat in avformat_new_stream() and avformat_free_context() + * respectively. + * + * - demuxing: filled by libavformat on stream creation or in + * avformat_find_stream_info() + * - muxing: filled by the caller before avformat_write_header() + */ + AVCodecParameters *codecpar; +} AVStream; + +AVRational av_stream_get_r_frame_rate(const AVStream *s); +void av_stream_set_r_frame_rate(AVStream *s, AVRational r); +struct AVCodecParserContext *av_stream_get_parser(const AVStream *s); +char* av_stream_get_recommended_encoder_configuration(const AVStream *s); +void av_stream_set_recommended_encoder_configuration(AVStream *s, char *configuration); + +/** + * Returns the pts of the last muxed packet + its duration + * + * the retuned value is undefined when used with a demuxer. + */ +int64_t av_stream_get_end_pts(const AVStream *st); + +#define AV_PROGRAM_RUNNING 1 + +/** + * New fields can be added to the end with minor version bumps. + * Removal, reordering and changes to existing fields require a major + * version bump. + * sizeof(AVProgram) must not be used outside libav*. + */ +typedef struct AVProgram { + int id; + int flags; + enum AVDiscard discard; ///< selects which program to discard and which to feed to the caller + unsigned int *stream_index; + unsigned int nb_stream_indexes; + AVDictionary *metadata; + + int program_num; + int pmt_pid; + int pcr_pid; + + /***************************************************************** + * All fields below this line are not part of the public API. They + * may not be used outside of libavformat and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + int64_t start_time; + int64_t end_time; + + int64_t pts_wrap_reference; ///< reference dts for wrap detection + int pts_wrap_behavior; ///< behavior on wrap detection +} AVProgram; + +#define AVFMTCTX_NOHEADER 0x0001 /**< signal that no header is present + (streams are added dynamically) */ + +typedef struct AVChapter { + int id; ///< unique ID to identify the chapter + AVRational time_base; ///< time base in which the start/end timestamps are specified + int64_t start, end; ///< chapter start/end time in time_base units + AVDictionary *metadata; +} AVChapter; + + +/** + * Callback used by devices to communicate with application. + */ +typedef int (*av_format_control_message)(struct AVFormatContext *s, int type, + void *data, size_t data_size); + +typedef int (*AVOpenCallback)(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, + const AVIOInterruptCB *int_cb, AVDictionary **options); + +/** + * The duration of a video can be estimated through various ways, and this enum can be used + * to know how the duration was estimated. + */ +enum AVDurationEstimationMethod { + AVFMT_DURATION_FROM_PTS, ///< Duration accurately estimated from PTSes + AVFMT_DURATION_FROM_STREAM, ///< Duration estimated from a stream with a known duration + AVFMT_DURATION_FROM_BITRATE ///< Duration estimated from bitrate (less accurate) +}; + +typedef struct AVFormatInternal AVFormatInternal; + +/** + * Format I/O context. + * New fields can be added to the end with minor version bumps. + * Removal, reordering and changes to existing fields require a major + * version bump. + * sizeof(AVFormatContext) must not be used outside libav*, use + * avformat_alloc_context() to create an AVFormatContext. + * + * Fields can be accessed through AVOptions (av_opt*), + * the name string used matches the associated command line parameter name and + * can be found in libavformat/options_table.h. + * The AVOption/command line parameter names differ in some cases from the C + * structure field names for historic reasons or brevity. + */ +typedef struct AVFormatContext { + /** + * A class for logging and @ref avoptions. Set by avformat_alloc_context(). + * Exports (de)muxer private options if they exist. + */ + const AVClass *av_class; + + /** + * The input container format. + * + * Demuxing only, set by avformat_open_input(). + */ + struct AVInputFormat *iformat; + + /** + * The output container format. + * + * Muxing only, must be set by the caller before avformat_write_header(). + */ + struct AVOutputFormat *oformat; + + /** + * Format private data. This is an AVOptions-enabled struct + * if and only if iformat/oformat.priv_class is not NULL. + * + * - muxing: set by avformat_write_header() + * - demuxing: set by avformat_open_input() + */ + void *priv_data; + + /** + * I/O context. + * + * - demuxing: either set by the user before avformat_open_input() (then + * the user must close it manually) or set by avformat_open_input(). + * - muxing: set by the user before avformat_write_header(). The caller must + * take care of closing / freeing the IO context. + * + * Do NOT set this field if AVFMT_NOFILE flag is set in + * iformat/oformat.flags. In such a case, the (de)muxer will handle + * I/O in some other way and this field will be NULL. + */ + AVIOContext *pb; + + /* stream info */ + /** + * Flags signalling stream properties. A combination of AVFMTCTX_*. + * Set by libavformat. + */ + int ctx_flags; + + /** + * Number of elements in AVFormatContext.streams. + * + * Set by avformat_new_stream(), must not be modified by any other code. + */ + unsigned int nb_streams; + /** + * A list of all streams in the file. New streams are created with + * avformat_new_stream(). + * + * - demuxing: streams are created by libavformat in avformat_open_input(). + * If AVFMTCTX_NOHEADER is set in ctx_flags, then new streams may also + * appear in av_read_frame(). + * - muxing: streams are created by the user before avformat_write_header(). + * + * Freed by libavformat in avformat_free_context(). + */ + AVStream **streams; + + /** + * input or output filename + * + * - demuxing: set by avformat_open_input() + * - muxing: may be set by the caller before avformat_write_header() + */ + char filename[1024]; + + /** + * Position of the first frame of the component, in + * AV_TIME_BASE fractional seconds. NEVER set this value directly: + * It is deduced from the AVStream values. + * + * Demuxing only, set by libavformat. + */ + int64_t start_time; + + /** + * Duration of the stream, in AV_TIME_BASE fractional + * seconds. Only set this value if you know none of the individual stream + * durations and also do not set any of them. This is deduced from the + * AVStream values if not set. + * + * Demuxing only, set by libavformat. + */ + int64_t duration; + + /** + * Total stream bitrate in bit/s, 0 if not + * available. Never set it directly if the file_size and the + * duration are known as FFmpeg can compute it automatically. + */ + int64_t bit_rate; + + unsigned int packet_size; + int max_delay; + + /** + * Flags modifying the (de)muxer behaviour. A combination of AVFMT_FLAG_*. + * Set by the user before avformat_open_input() / avformat_write_header(). + */ + int flags; +#define AVFMT_FLAG_GENPTS 0x0001 ///< Generate missing pts even if it requires parsing future frames. +#define AVFMT_FLAG_IGNIDX 0x0002 ///< Ignore index. +#define AVFMT_FLAG_NONBLOCK 0x0004 ///< Do not block when reading packets from input. +#define AVFMT_FLAG_IGNDTS 0x0008 ///< Ignore DTS on frames that contain both DTS & PTS +#define AVFMT_FLAG_NOFILLIN 0x0010 ///< Do not infer any values from other values, just return what is stored in the container +#define AVFMT_FLAG_NOPARSE 0x0020 ///< Do not use AVParsers, you also must set AVFMT_FLAG_NOFILLIN as the fillin code works on frames and no parsing -> no frames. Also seeking to frames can not work if parsing to find frame boundaries has been disabled +#define AVFMT_FLAG_NOBUFFER 0x0040 ///< Do not buffer frames when possible +#define AVFMT_FLAG_CUSTOM_IO 0x0080 ///< The caller has supplied a custom AVIOContext, don't avio_close() it. +#define AVFMT_FLAG_DISCARD_CORRUPT 0x0100 ///< Discard frames marked corrupted +#define AVFMT_FLAG_FLUSH_PACKETS 0x0200 ///< Flush the AVIOContext every packet. +/** + * When muxing, try to avoid writing any random/volatile data to the output. + * This includes any random IDs, real-time timestamps/dates, muxer version, etc. + * + * This flag is mainly intended for testing. + */ +#define AVFMT_FLAG_BITEXACT 0x0400 +#define AVFMT_FLAG_MP4A_LATM 0x8000 ///< Enable RTP MP4A-LATM payload +#define AVFMT_FLAG_SORT_DTS 0x10000 ///< try to interleave outputted packets by dts (using this flag can slow demuxing down) +#define AVFMT_FLAG_PRIV_OPT 0x20000 ///< Enable use of private options by delaying codec open (this could be made default once all code is converted) +#if FF_API_LAVF_KEEPSIDE_FLAG +#define AVFMT_FLAG_KEEP_SIDE_DATA 0x40000 ///< Don't merge side data but keep it separate. Deprecated, will be the default. +#endif +#define AVFMT_FLAG_FAST_SEEK 0x80000 ///< Enable fast, but inaccurate seeks for some formats +#define AVFMT_FLAG_SHORTEST 0x100000 ///< Stop muxing when the shortest stream stops. +#define AVFMT_FLAG_AUTO_BSF 0x200000 ///< Wait for packet data before writing a header, and add bitstream filters as requested by the muxer + + /** + * Maximum size of the data read from input for determining + * the input container format. + * Demuxing only, set by the caller before avformat_open_input(). + */ + int64_t probesize; + + /** + * Maximum duration (in AV_TIME_BASE units) of the data read + * from input in avformat_find_stream_info(). + * Demuxing only, set by the caller before avformat_find_stream_info(). + * Can be set to 0 to let avformat choose using a heuristic. + */ + int64_t max_analyze_duration; + + const uint8_t *key; + int keylen; + + unsigned int nb_programs; + AVProgram **programs; + + /** + * Forced video codec_id. + * Demuxing: Set by user. + */ + enum AVCodecID video_codec_id; + + /** + * Forced audio codec_id. + * Demuxing: Set by user. + */ + enum AVCodecID audio_codec_id; + + /** + * Forced subtitle codec_id. + * Demuxing: Set by user. + */ + enum AVCodecID subtitle_codec_id; + + /** + * Maximum amount of memory in bytes to use for the index of each stream. + * If the index exceeds this size, entries will be discarded as + * needed to maintain a smaller size. This can lead to slower or less + * accurate seeking (depends on demuxer). + * Demuxers for which a full in-memory index is mandatory will ignore + * this. + * - muxing: unused + * - demuxing: set by user + */ + unsigned int max_index_size; + + /** + * Maximum amount of memory in bytes to use for buffering frames + * obtained from realtime capture devices. + */ + unsigned int max_picture_buffer; + + /** + * Number of chapters in AVChapter array. + * When muxing, chapters are normally written in the file header, + * so nb_chapters should normally be initialized before write_header + * is called. Some muxers (e.g. mov and mkv) can also write chapters + * in the trailer. To write chapters in the trailer, nb_chapters + * must be zero when write_header is called and non-zero when + * write_trailer is called. + * - muxing: set by user + * - demuxing: set by libavformat + */ + unsigned int nb_chapters; + AVChapter **chapters; + + /** + * Metadata that applies to the whole file. + * + * - demuxing: set by libavformat in avformat_open_input() + * - muxing: may be set by the caller before avformat_write_header() + * + * Freed by libavformat in avformat_free_context(). + */ + AVDictionary *metadata; + + /** + * Start time of the stream in real world time, in microseconds + * since the Unix epoch (00:00 1st January 1970). That is, pts=0 in the + * stream was captured at this real world time. + * - muxing: Set by the caller before avformat_write_header(). If set to + * either 0 or AV_NOPTS_VALUE, then the current wall-time will + * be used. + * - demuxing: Set by libavformat. AV_NOPTS_VALUE if unknown. Note that + * the value may become known after some number of frames + * have been received. + */ + int64_t start_time_realtime; + + /** + * The number of frames used for determining the framerate in + * avformat_find_stream_info(). + * Demuxing only, set by the caller before avformat_find_stream_info(). + */ + int fps_probe_size; + + /** + * Error recognition; higher values will detect more errors but may + * misdetect some more or less valid parts as errors. + * Demuxing only, set by the caller before avformat_open_input(). + */ + int error_recognition; + + /** + * Custom interrupt callbacks for the I/O layer. + * + * demuxing: set by the user before avformat_open_input(). + * muxing: set by the user before avformat_write_header() + * (mainly useful for AVFMT_NOFILE formats). The callback + * should also be passed to avio_open2() if it's used to + * open the file. + */ + AVIOInterruptCB interrupt_callback; + + /** + * Flags to enable debugging. + */ + int debug; +#define FF_FDEBUG_TS 0x0001 + + /** + * Maximum buffering duration for interleaving. + * + * To ensure all the streams are interleaved correctly, + * av_interleaved_write_frame() will wait until it has at least one packet + * for each stream before actually writing any packets to the output file. + * When some streams are "sparse" (i.e. there are large gaps between + * successive packets), this can result in excessive buffering. + * + * This field specifies the maximum difference between the timestamps of the + * first and the last packet in the muxing queue, above which libavformat + * will output a packet regardless of whether it has queued a packet for all + * the streams. + * + * Muxing only, set by the caller before avformat_write_header(). + */ + int64_t max_interleave_delta; + + /** + * Allow non-standard and experimental extension + * @see AVCodecContext.strict_std_compliance + */ + int strict_std_compliance; + + /** + * Flags for the user to detect events happening on the file. Flags must + * be cleared by the user once the event has been handled. + * A combination of AVFMT_EVENT_FLAG_*. + */ + int event_flags; +#define AVFMT_EVENT_FLAG_METADATA_UPDATED 0x0001 ///< The call resulted in updated metadata. + + /** + * Maximum number of packets to read while waiting for the first timestamp. + * Decoding only. + */ + int max_ts_probe; + + /** + * Avoid negative timestamps during muxing. + * Any value of the AVFMT_AVOID_NEG_TS_* constants. + * Note, this only works when using av_interleaved_write_frame. (interleave_packet_per_dts is in use) + * - muxing: Set by user + * - demuxing: unused + */ + int avoid_negative_ts; +#define AVFMT_AVOID_NEG_TS_AUTO -1 ///< Enabled when required by target format +#define AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE 1 ///< Shift timestamps so they are non negative +#define AVFMT_AVOID_NEG_TS_MAKE_ZERO 2 ///< Shift timestamps so that they start at 0 + + /** + * Transport stream id. + * This will be moved into demuxer private options. Thus no API/ABI compatibility + */ + int ts_id; + + /** + * Audio preload in microseconds. + * Note, not all formats support this and unpredictable things may happen if it is used when not supported. + * - encoding: Set by user + * - decoding: unused + */ + int audio_preload; + + /** + * Max chunk time in microseconds. + * Note, not all formats support this and unpredictable things may happen if it is used when not supported. + * - encoding: Set by user + * - decoding: unused + */ + int max_chunk_duration; + + /** + * Max chunk size in bytes + * Note, not all formats support this and unpredictable things may happen if it is used when not supported. + * - encoding: Set by user + * - decoding: unused + */ + int max_chunk_size; + + /** + * forces the use of wallclock timestamps as pts/dts of packets + * This has undefined results in the presence of B frames. + * - encoding: unused + * - decoding: Set by user + */ + int use_wallclock_as_timestamps; + + /** + * avio flags, used to force AVIO_FLAG_DIRECT. + * - encoding: unused + * - decoding: Set by user + */ + int avio_flags; + + /** + * The duration field can be estimated through various ways, and this field can be used + * to know how the duration was estimated. + * - encoding: unused + * - decoding: Read by user + */ + enum AVDurationEstimationMethod duration_estimation_method; + + /** + * Skip initial bytes when opening stream + * - encoding: unused + * - decoding: Set by user + */ + int64_t skip_initial_bytes; + + /** + * Correct single timestamp overflows + * - encoding: unused + * - decoding: Set by user + */ + unsigned int correct_ts_overflow; + + /** + * Force seeking to any (also non key) frames. + * - encoding: unused + * - decoding: Set by user + */ + int seek2any; + + /** + * Flush the I/O context after each packet. + * - encoding: Set by user + * - decoding: unused + */ + int flush_packets; + + /** + * format probing score. + * The maximal score is AVPROBE_SCORE_MAX, its set when the demuxer probes + * the format. + * - encoding: unused + * - decoding: set by avformat, read by user + */ + int probe_score; + + /** + * number of bytes to read maximally to identify format. + * - encoding: unused + * - decoding: set by user + */ + int format_probesize; + + /** + * ',' separated list of allowed decoders. + * If NULL then all are allowed + * - encoding: unused + * - decoding: set by user + */ + char *codec_whitelist; + + /** + * ',' separated list of allowed demuxers. + * If NULL then all are allowed + * - encoding: unused + * - decoding: set by user + */ + char *format_whitelist; + + /** + * An opaque field for libavformat internal usage. + * Must not be accessed in any way by callers. + */ + AVFormatInternal *internal; + + /** + * IO repositioned flag. + * This is set by avformat when the underlaying IO context read pointer + * is repositioned, for example when doing byte based seeking. + * Demuxers can use the flag to detect such changes. + */ + int io_repositioned; + + /** + * Forced video codec. + * This allows forcing a specific decoder, even when there are multiple with + * the same codec_id. + * Demuxing: Set by user + */ + AVCodec *video_codec; + + /** + * Forced audio codec. + * This allows forcing a specific decoder, even when there are multiple with + * the same codec_id. + * Demuxing: Set by user + */ + AVCodec *audio_codec; + + /** + * Forced subtitle codec. + * This allows forcing a specific decoder, even when there are multiple with + * the same codec_id. + * Demuxing: Set by user + */ + AVCodec *subtitle_codec; + + /** + * Forced data codec. + * This allows forcing a specific decoder, even when there are multiple with + * the same codec_id. + * Demuxing: Set by user + */ + AVCodec *data_codec; + + /** + * Number of bytes to be written as padding in a metadata header. + * Demuxing: Unused. + * Muxing: Set by user via av_format_set_metadata_header_padding. + */ + int metadata_header_padding; + + /** + * User data. + * This is a place for some private data of the user. + */ + void *opaque; + + /** + * Callback used by devices to communicate with application. + */ + av_format_control_message control_message_cb; + + /** + * Output timestamp offset, in microseconds. + * Muxing: set by user + */ + int64_t output_ts_offset; + + /** + * dump format separator. + * can be ", " or "\n " or anything else + * - muxing: Set by user. + * - demuxing: Set by user. + */ + uint8_t *dump_separator; + + /** + * Forced Data codec_id. + * Demuxing: Set by user. + */ + enum AVCodecID data_codec_id; + +#if FF_API_OLD_OPEN_CALLBACKS + /** + * Called to open further IO contexts when needed for demuxing. + * + * This can be set by the user application to perform security checks on + * the URLs before opening them. + * The function should behave like avio_open2(), AVFormatContext is provided + * as contextual information and to reach AVFormatContext.opaque. + * + * If NULL then some simple checks are used together with avio_open2(). + * + * Must not be accessed directly from outside avformat. + * @See av_format_set_open_cb() + * + * Demuxing: Set by user. + * + * @deprecated Use io_open and io_close. + */ + attribute_deprecated + int (*open_cb)(struct AVFormatContext *s, AVIOContext **p, const char *url, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options); +#endif + + /** + * ',' separated list of allowed protocols. + * - encoding: unused + * - decoding: set by user + */ + char *protocol_whitelist; + + /* + * A callback for opening new IO streams. + * + * Whenever a muxer or a demuxer needs to open an IO stream (typically from + * avformat_open_input() for demuxers, but for certain formats can happen at + * other times as well), it will call this callback to obtain an IO context. + * + * @param s the format context + * @param pb on success, the newly opened IO context should be returned here + * @param url the url to open + * @param flags a combination of AVIO_FLAG_* + * @param options a dictionary of additional options, with the same + * semantics as in avio_open2() + * @return 0 on success, a negative AVERROR code on failure + * + * @note Certain muxers and demuxers do nesting, i.e. they open one or more + * additional internal format contexts. Thus the AVFormatContext pointer + * passed to this callback may be different from the one facing the caller. + * It will, however, have the same 'opaque' field. + */ + int (*io_open)(struct AVFormatContext *s, AVIOContext **pb, const char *url, + int flags, AVDictionary **options); + + /** + * A callback for closing the streams opened with AVFormatContext.io_open(). + */ + void (*io_close)(struct AVFormatContext *s, AVIOContext *pb); + + /** + * ',' separated list of disallowed protocols. + * - encoding: unused + * - decoding: set by user + */ + char *protocol_blacklist; + + /** + * The maximum number of streams. + * - encoding: unused + * - decoding: set by user + */ + int max_streams; +} AVFormatContext; + +/** + * Accessors for some AVFormatContext fields. These used to be provided for ABI + * compatibility, and do not need to be used anymore. + */ +int av_format_get_probe_score(const AVFormatContext *s); +AVCodec * av_format_get_video_codec(const AVFormatContext *s); +void av_format_set_video_codec(AVFormatContext *s, AVCodec *c); +AVCodec * av_format_get_audio_codec(const AVFormatContext *s); +void av_format_set_audio_codec(AVFormatContext *s, AVCodec *c); +AVCodec * av_format_get_subtitle_codec(const AVFormatContext *s); +void av_format_set_subtitle_codec(AVFormatContext *s, AVCodec *c); +AVCodec * av_format_get_data_codec(const AVFormatContext *s); +void av_format_set_data_codec(AVFormatContext *s, AVCodec *c); +int av_format_get_metadata_header_padding(const AVFormatContext *s); +void av_format_set_metadata_header_padding(AVFormatContext *s, int c); +void * av_format_get_opaque(const AVFormatContext *s); +void av_format_set_opaque(AVFormatContext *s, void *opaque); +av_format_control_message av_format_get_control_message_cb(const AVFormatContext *s); +void av_format_set_control_message_cb(AVFormatContext *s, av_format_control_message callback); +#if FF_API_OLD_OPEN_CALLBACKS +attribute_deprecated AVOpenCallback av_format_get_open_cb(const AVFormatContext *s); +attribute_deprecated void av_format_set_open_cb(AVFormatContext *s, AVOpenCallback callback); +#endif + +/** + * This function will cause global side data to be injected in the next packet + * of each stream as well as after any subsequent seek. + */ +void av_format_inject_global_side_data(AVFormatContext *s); + +/** + * Returns the method used to set ctx->duration. + * + * @return AVFMT_DURATION_FROM_PTS, AVFMT_DURATION_FROM_STREAM, or AVFMT_DURATION_FROM_BITRATE. + */ +enum AVDurationEstimationMethod av_fmt_ctx_get_duration_estimation_method(const AVFormatContext* ctx); + +typedef struct AVPacketList { + AVPacket pkt; + struct AVPacketList *next; +} AVPacketList; + + +/** + * @defgroup lavf_core Core functions + * @ingroup libavf + * + * Functions for querying libavformat capabilities, allocating core structures, + * etc. + * @{ + */ + +/** + * Return the LIBAVFORMAT_VERSION_INT constant. + */ +unsigned avformat_version(void); + +/** + * Return the libavformat build-time configuration. + */ +const char *avformat_configuration(void); + +/** + * Return the libavformat license. + */ +const char *avformat_license(void); + +/** + * Initialize libavformat and register all the muxers, demuxers and + * protocols. If you do not call this function, then you can select + * exactly which formats you want to support. + * + * @see av_register_input_format() + * @see av_register_output_format() + */ +void av_register_all(void); + +void av_register_input_format(AVInputFormat *format); +void av_register_output_format(AVOutputFormat *format); + +/** + * Do global initialization of network components. This is optional, + * but recommended, since it avoids the overhead of implicitly + * doing the setup for each session. + * + * Calling this function will become mandatory if using network + * protocols at some major version bump. + */ +int avformat_network_init(void); + +/** + * Undo the initialization done by avformat_network_init. + */ +int avformat_network_deinit(void); + +/** + * If f is NULL, returns the first registered input format, + * if f is non-NULL, returns the next registered input format after f + * or NULL if f is the last one. + */ +AVInputFormat *av_iformat_next(const AVInputFormat *f); + +/** + * If f is NULL, returns the first registered output format, + * if f is non-NULL, returns the next registered output format after f + * or NULL if f is the last one. + */ +AVOutputFormat *av_oformat_next(const AVOutputFormat *f); + +/** + * Allocate an AVFormatContext. + * avformat_free_context() can be used to free the context and everything + * allocated by the framework within it. + */ +AVFormatContext *avformat_alloc_context(void); + +/** + * Free an AVFormatContext and all its streams. + * @param s context to free + */ +void avformat_free_context(AVFormatContext *s); + +/** + * Get the AVClass for AVFormatContext. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *avformat_get_class(void); + +/** + * Add a new stream to a media file. + * + * When demuxing, it is called by the demuxer in read_header(). If the + * flag AVFMTCTX_NOHEADER is set in s.ctx_flags, then it may also + * be called in read_packet(). + * + * When muxing, should be called by the user before avformat_write_header(). + * + * User is required to call avcodec_close() and avformat_free_context() to + * clean up the allocation by avformat_new_stream(). + * + * @param s media file handle + * @param c If non-NULL, the AVCodecContext corresponding to the new stream + * will be initialized to use this codec. This is needed for e.g. codec-specific + * defaults to be set, so codec should be provided if it is known. + * + * @return newly created stream or NULL on error. + */ +AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c); + +/** + * Wrap an existing array as stream side data. + * + * @param st stream + * @param type side information type + * @param data the side data array. It must be allocated with the av_malloc() + * family of functions. The ownership of the data is transferred to + * st. + * @param size side information size + * @return zero on success, a negative AVERROR code on failure. On failure, + * the stream is unchanged and the data remains owned by the caller. + */ +int av_stream_add_side_data(AVStream *st, enum AVPacketSideDataType type, + uint8_t *data, size_t size); + +/** + * Allocate new information from stream. + * + * @param stream stream + * @param type desired side information type + * @param size side information size + * @return pointer to fresh allocated data or NULL otherwise + */ +uint8_t *av_stream_new_side_data(AVStream *stream, + enum AVPacketSideDataType type, int size); +/** + * Get side information from stream. + * + * @param stream stream + * @param type desired side information type + * @param size pointer for side information size to store (optional) + * @return pointer to data if present or NULL otherwise + */ +#if FF_API_NOCONST_GET_SIDE_DATA +uint8_t *av_stream_get_side_data(AVStream *stream, + enum AVPacketSideDataType type, int *size); +#else +uint8_t *av_stream_get_side_data(const AVStream *stream, + enum AVPacketSideDataType type, int *size); +#endif + +AVProgram *av_new_program(AVFormatContext *s, int id); + +/** + * @} + */ + + +/** + * Allocate an AVFormatContext for an output format. + * avformat_free_context() can be used to free the context and + * everything allocated by the framework within it. + * + * @param *ctx is set to the created format context, or to NULL in + * case of failure + * @param oformat format to use for allocating the context, if NULL + * format_name and filename are used instead + * @param format_name the name of output format to use for allocating the + * context, if NULL filename is used instead + * @param filename the name of the filename to use for allocating the + * context, may be NULL + * @return >= 0 in case of success, a negative AVERROR code in case of + * failure + */ +int avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat, + const char *format_name, const char *filename); + +/** + * @addtogroup lavf_decoding + * @{ + */ + +/** + * Find AVInputFormat based on the short name of the input format. + */ +AVInputFormat *av_find_input_format(const char *short_name); + +/** + * Guess the file format. + * + * @param pd data to be probed + * @param is_opened Whether the file is already opened; determines whether + * demuxers with or without AVFMT_NOFILE are probed. + */ +AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened); + +/** + * Guess the file format. + * + * @param pd data to be probed + * @param is_opened Whether the file is already opened; determines whether + * demuxers with or without AVFMT_NOFILE are probed. + * @param score_max A probe score larger that this is required to accept a + * detection, the variable is set to the actual detection + * score afterwards. + * If the score is <= AVPROBE_SCORE_MAX / 4 it is recommended + * to retry with a larger probe buffer. + */ +AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max); + +/** + * Guess the file format. + * + * @param is_opened Whether the file is already opened; determines whether + * demuxers with or without AVFMT_NOFILE are probed. + * @param score_ret The score of the best detection. + */ +AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score_ret); + +/** + * Probe a bytestream to determine the input format. Each time a probe returns + * with a score that is too low, the probe buffer size is increased and another + * attempt is made. When the maximum probe size is reached, the input format + * with the highest score is returned. + * + * @param pb the bytestream to probe + * @param fmt the input format is put here + * @param url the url of the stream + * @param logctx the log context + * @param offset the offset within the bytestream to probe from + * @param max_probe_size the maximum probe buffer size (zero for default) + * @return the score in case of success, a negative value corresponding to an + * the maximal score is AVPROBE_SCORE_MAX + * AVERROR code otherwise + */ +int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt, + const char *url, void *logctx, + unsigned int offset, unsigned int max_probe_size); + +/** + * Like av_probe_input_buffer2() but returns 0 on success + */ +int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, + const char *url, void *logctx, + unsigned int offset, unsigned int max_probe_size); + +/** + * Open an input stream and read the header. The codecs are not opened. + * The stream must be closed with avformat_close_input(). + * + * @param ps Pointer to user-supplied AVFormatContext (allocated by avformat_alloc_context). + * May be a pointer to NULL, in which case an AVFormatContext is allocated by this + * function and written into ps. + * Note that a user-supplied AVFormatContext will be freed on failure. + * @param url URL of the stream to open. + * @param fmt If non-NULL, this parameter forces a specific input format. + * Otherwise the format is autodetected. + * @param options A dictionary filled with AVFormatContext and demuxer-private options. + * On return this parameter will be destroyed and replaced with a dict containing + * options that were not found. May be NULL. + * + * @return 0 on success, a negative AVERROR on failure. + * + * @note If you want to use custom IO, preallocate the format context and set its pb field. + */ +int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options); + +attribute_deprecated +int av_demuxer_open(AVFormatContext *ic); + +/** + * Read packets of a media file to get stream information. This + * is useful for file formats with no headers such as MPEG. This + * function also computes the real framerate in case of MPEG-2 repeat + * frame mode. + * The logical file position is not changed by this function; + * examined packets may be buffered for later processing. + * + * @param ic media file handle + * @param options If non-NULL, an ic.nb_streams long array of pointers to + * dictionaries, where i-th member contains options for + * codec corresponding to i-th stream. + * On return each dictionary will be filled with options that were not found. + * @return >=0 if OK, AVERROR_xxx on error + * + * @note this function isn't guaranteed to open all the codecs, so + * options being non-empty at return is a perfectly normal behavior. + * + * @todo Let the user decide somehow what information is needed so that + * we do not waste time getting stuff the user does not need. + */ +int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options); + +/** + * Find the programs which belong to a given stream. + * + * @param ic media file handle + * @param last the last found program, the search will start after this + * program, or from the beginning if it is NULL + * @param s stream index + * @return the next program which belongs to s, NULL if no program is found or + * the last program is not among the programs of ic. + */ +AVProgram *av_find_program_from_stream(AVFormatContext *ic, AVProgram *last, int s); + +void av_program_add_stream_index(AVFormatContext *ac, int progid, unsigned int idx); + +/** + * Find the "best" stream in the file. + * The best stream is determined according to various heuristics as the most + * likely to be what the user expects. + * If the decoder parameter is non-NULL, av_find_best_stream will find the + * default decoder for the stream's codec; streams for which no decoder can + * be found are ignored. + * + * @param ic media file handle + * @param type stream type: video, audio, subtitles, etc. + * @param wanted_stream_nb user-requested stream number, + * or -1 for automatic selection + * @param related_stream try to find a stream related (eg. in the same + * program) to this one, or -1 if none + * @param decoder_ret if non-NULL, returns the decoder for the + * selected stream + * @param flags flags; none are currently defined + * @return the non-negative stream number in case of success, + * AVERROR_STREAM_NOT_FOUND if no stream with the requested type + * could be found, + * AVERROR_DECODER_NOT_FOUND if streams were found but no decoder + * @note If av_find_best_stream returns successfully and decoder_ret is not + * NULL, then *decoder_ret is guaranteed to be set to a valid AVCodec. + */ +int av_find_best_stream(AVFormatContext *ic, + enum AVMediaType type, + int wanted_stream_nb, + int related_stream, + AVCodec **decoder_ret, + int flags); + +/** + * Return the next frame of a stream. + * This function returns what is stored in the file, and does not validate + * that what is there are valid frames for the decoder. It will split what is + * stored in the file into frames and return one for each call. It will not + * omit invalid data between valid frames so as to give the decoder the maximum + * information possible for decoding. + * + * If pkt->buf is NULL, then the packet is valid until the next + * av_read_frame() or until avformat_close_input(). Otherwise the packet + * is valid indefinitely. In both cases the packet must be freed with + * av_packet_unref when it is no longer needed. For video, the packet contains + * exactly one frame. For audio, it contains an integer number of frames if each + * frame has a known fixed size (e.g. PCM or ADPCM data). If the audio frames + * have a variable size (e.g. MPEG audio), then it contains one frame. + * + * pkt->pts, pkt->dts and pkt->duration are always set to correct + * values in AVStream.time_base units (and guessed if the format cannot + * provide them). pkt->pts can be AV_NOPTS_VALUE if the video format + * has B-frames, so it is better to rely on pkt->dts if you do not + * decompress the payload. + * + * @return 0 if OK, < 0 on error or end of file + */ +int av_read_frame(AVFormatContext *s, AVPacket *pkt); + +/** + * Seek to the keyframe at timestamp. + * 'timestamp' in 'stream_index'. + * + * @param s media file handle + * @param stream_index If stream_index is (-1), a default + * stream is selected, and timestamp is automatically converted + * from AV_TIME_BASE units to the stream specific time_base. + * @param timestamp Timestamp in AVStream.time_base units + * or, if no stream is specified, in AV_TIME_BASE units. + * @param flags flags which select direction and seeking mode + * @return >= 0 on success + */ +int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, + int flags); + +/** + * Seek to timestamp ts. + * Seeking will be done so that the point from which all active streams + * can be presented successfully will be closest to ts and within min/max_ts. + * Active streams are all streams that have AVStream.discard < AVDISCARD_ALL. + * + * If flags contain AVSEEK_FLAG_BYTE, then all timestamps are in bytes and + * are the file position (this may not be supported by all demuxers). + * If flags contain AVSEEK_FLAG_FRAME, then all timestamps are in frames + * in the stream with stream_index (this may not be supported by all demuxers). + * Otherwise all timestamps are in units of the stream selected by stream_index + * or if stream_index is -1, in AV_TIME_BASE units. + * If flags contain AVSEEK_FLAG_ANY, then non-keyframes are treated as + * keyframes (this may not be supported by all demuxers). + * If flags contain AVSEEK_FLAG_BACKWARD, it is ignored. + * + * @param s media file handle + * @param stream_index index of the stream which is used as time base reference + * @param min_ts smallest acceptable timestamp + * @param ts target timestamp + * @param max_ts largest acceptable timestamp + * @param flags flags + * @return >=0 on success, error code otherwise + * + * @note This is part of the new seek API which is still under construction. + * Thus do not use this yet. It may change at any time, do not expect + * ABI compatibility yet! + */ +int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags); + +/** + * Discard all internally buffered data. This can be useful when dealing with + * discontinuities in the byte stream. Generally works only with formats that + * can resync. This includes headerless formats like MPEG-TS/TS but should also + * work with NUT, Ogg and in a limited way AVI for example. + * + * The set of streams, the detected duration, stream parameters and codecs do + * not change when calling this function. If you want a complete reset, it's + * better to open a new AVFormatContext. + * + * This does not flush the AVIOContext (s->pb). If necessary, call + * avio_flush(s->pb) before calling this function. + * + * @param s media file handle + * @return >=0 on success, error code otherwise + */ +int avformat_flush(AVFormatContext *s); + +/** + * Start playing a network-based stream (e.g. RTSP stream) at the + * current position. + */ +int av_read_play(AVFormatContext *s); + +/** + * Pause a network-based stream (e.g. RTSP stream). + * + * Use av_read_play() to resume it. + */ +int av_read_pause(AVFormatContext *s); + +/** + * Close an opened input AVFormatContext. Free it and all its contents + * and set *s to NULL. + */ +void avformat_close_input(AVFormatContext **s); +/** + * @} + */ + +#define AVSEEK_FLAG_BACKWARD 1 ///< seek backward +#define AVSEEK_FLAG_BYTE 2 ///< seeking based on position in bytes +#define AVSEEK_FLAG_ANY 4 ///< seek to any frame, even non-keyframes +#define AVSEEK_FLAG_FRAME 8 ///< seeking based on frame number + +/** + * @addtogroup lavf_encoding + * @{ + */ + +#define AVSTREAM_INIT_IN_WRITE_HEADER 0 ///< stream parameters initialized in avformat_write_header +#define AVSTREAM_INIT_IN_INIT_OUTPUT 1 ///< stream parameters initialized in avformat_init_output + +/** + * Allocate the stream private data and write the stream header to + * an output media file. + * + * @param s Media file handle, must be allocated with avformat_alloc_context(). + * Its oformat field must be set to the desired output format; + * Its pb field must be set to an already opened AVIOContext. + * @param options An AVDictionary filled with AVFormatContext and muxer-private options. + * On return this parameter will be destroyed and replaced with a dict containing + * options that were not found. May be NULL. + * + * @return AVSTREAM_INIT_IN_WRITE_HEADER on success if the codec had not already been fully initialized in avformat_init, + * AVSTREAM_INIT_IN_INIT_OUTPUT on success if the codec had already been fully initialized in avformat_init, + * negative AVERROR on failure. + * + * @see av_opt_find, av_dict_set, avio_open, av_oformat_next, avformat_init_output. + */ +av_warn_unused_result +int avformat_write_header(AVFormatContext *s, AVDictionary **options); + +/** + * Allocate the stream private data and initialize the codec, but do not write the header. + * May optionally be used before avformat_write_header to initialize stream parameters + * before actually writing the header. + * If using this function, do not pass the same options to avformat_write_header. + * + * @param s Media file handle, must be allocated with avformat_alloc_context(). + * Its oformat field must be set to the desired output format; + * Its pb field must be set to an already opened AVIOContext. + * @param options An AVDictionary filled with AVFormatContext and muxer-private options. + * On return this parameter will be destroyed and replaced with a dict containing + * options that were not found. May be NULL. + * + * @return AVSTREAM_INIT_IN_WRITE_HEADER on success if the codec requires avformat_write_header to fully initialize, + * AVSTREAM_INIT_IN_INIT_OUTPUT on success if the codec has been fully initialized, + * negative AVERROR on failure. + * + * @see av_opt_find, av_dict_set, avio_open, av_oformat_next, avformat_write_header. + */ +av_warn_unused_result +int avformat_init_output(AVFormatContext *s, AVDictionary **options); + +/** + * Write a packet to an output media file. + * + * This function passes the packet directly to the muxer, without any buffering + * or reordering. The caller is responsible for correctly interleaving the + * packets if the format requires it. Callers that want libavformat to handle + * the interleaving should call av_interleaved_write_frame() instead of this + * function. + * + * @param s media file handle + * @param pkt The packet containing the data to be written. Note that unlike + * av_interleaved_write_frame(), this function does not take + * ownership of the packet passed to it (though some muxers may make + * an internal reference to the input packet). + *
+ * This parameter can be NULL (at any time, not just at the end), in + * order to immediately flush data buffered within the muxer, for + * muxers that buffer up data internally before writing it to the + * output. + *
+ * Packet's @ref AVPacket.stream_index "stream_index" field must be + * set to the index of the corresponding stream in @ref + * AVFormatContext.streams "s->streams". + *
+ * The timestamps (@ref AVPacket.pts "pts", @ref AVPacket.dts "dts") + * must be set to correct values in the stream's timebase (unless the + * output format is flagged with the AVFMT_NOTIMESTAMPS flag, then + * they can be set to AV_NOPTS_VALUE). + * The dts for subsequent packets passed to this function must be strictly + * increasing when compared in their respective timebases (unless the + * output format is flagged with the AVFMT_TS_NONSTRICT, then they + * merely have to be nondecreasing). @ref AVPacket.duration + * "duration") should also be set if known. + * @return < 0 on error, = 0 if OK, 1 if flushed and there is no more data to flush + * + * @see av_interleaved_write_frame() + */ +int av_write_frame(AVFormatContext *s, AVPacket *pkt); + +/** + * Write a packet to an output media file ensuring correct interleaving. + * + * This function will buffer the packets internally as needed to make sure the + * packets in the output file are properly interleaved in the order of + * increasing dts. Callers doing their own interleaving should call + * av_write_frame() instead of this function. + * + * Using this function instead of av_write_frame() can give muxers advance + * knowledge of future packets, improving e.g. the behaviour of the mp4 + * muxer for VFR content in fragmenting mode. + * + * @param s media file handle + * @param pkt The packet containing the data to be written. + *
+ * If the packet is reference-counted, this function will take + * ownership of this reference and unreference it later when it sees + * fit. + * The caller must not access the data through this reference after + * this function returns. If the packet is not reference-counted, + * libavformat will make a copy. + *
+ * This parameter can be NULL (at any time, not just at the end), to + * flush the interleaving queues. + *
+ * Packet's @ref AVPacket.stream_index "stream_index" field must be + * set to the index of the corresponding stream in @ref + * AVFormatContext.streams "s->streams". + *
+ * The timestamps (@ref AVPacket.pts "pts", @ref AVPacket.dts "dts") + * must be set to correct values in the stream's timebase (unless the + * output format is flagged with the AVFMT_NOTIMESTAMPS flag, then + * they can be set to AV_NOPTS_VALUE). + * The dts for subsequent packets in one stream must be strictly + * increasing (unless the output format is flagged with the + * AVFMT_TS_NONSTRICT, then they merely have to be nondecreasing). + * @ref AVPacket.duration "duration") should also be set if known. + * + * @return 0 on success, a negative AVERROR on error. Libavformat will always + * take care of freeing the packet, even if this function fails. + * + * @see av_write_frame(), AVFormatContext.max_interleave_delta + */ +int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt); + +/** + * Write an uncoded frame to an output media file. + * + * The frame must be correctly interleaved according to the container + * specification; if not, then av_interleaved_write_frame() must be used. + * + * See av_interleaved_write_frame() for details. + */ +int av_write_uncoded_frame(AVFormatContext *s, int stream_index, + AVFrame *frame); + +/** + * Write an uncoded frame to an output media file. + * + * If the muxer supports it, this function makes it possible to write an AVFrame + * structure directly, without encoding it into a packet. + * It is mostly useful for devices and similar special muxers that use raw + * video or PCM data and will not serialize it into a byte stream. + * + * To test whether it is possible to use it with a given muxer and stream, + * use av_write_uncoded_frame_query(). + * + * The caller gives up ownership of the frame and must not access it + * afterwards. + * + * @return >=0 for success, a negative code on error + */ +int av_interleaved_write_uncoded_frame(AVFormatContext *s, int stream_index, + AVFrame *frame); + +/** + * Test whether a muxer supports uncoded frame. + * + * @return >=0 if an uncoded frame can be written to that muxer and stream, + * <0 if not + */ +int av_write_uncoded_frame_query(AVFormatContext *s, int stream_index); + +/** + * Write the stream trailer to an output media file and free the + * file private data. + * + * May only be called after a successful call to avformat_write_header. + * + * @param s media file handle + * @return 0 if OK, AVERROR_xxx on error + */ +int av_write_trailer(AVFormatContext *s); + +/** + * Return the output format in the list of registered output formats + * which best matches the provided parameters, or return NULL if + * there is no match. + * + * @param short_name if non-NULL checks if short_name matches with the + * names of the registered formats + * @param filename if non-NULL checks if filename terminates with the + * extensions of the registered formats + * @param mime_type if non-NULL checks if mime_type matches with the + * MIME type of the registered formats + */ +AVOutputFormat *av_guess_format(const char *short_name, + const char *filename, + const char *mime_type); + +/** + * Guess the codec ID based upon muxer and filename. + */ +enum AVCodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name, + const char *filename, const char *mime_type, + enum AVMediaType type); + +/** + * Get timing information for the data currently output. + * The exact meaning of "currently output" depends on the format. + * It is mostly relevant for devices that have an internal buffer and/or + * work in real time. + * @param s media file handle + * @param stream stream in the media file + * @param[out] dts DTS of the last packet output for the stream, in stream + * time_base units + * @param[out] wall absolute time when that packet whas output, + * in microsecond + * @return 0 if OK, AVERROR(ENOSYS) if the format does not support it + * Note: some formats or devices may not allow to measure dts and wall + * atomically. + */ +int av_get_output_timestamp(struct AVFormatContext *s, int stream, + int64_t *dts, int64_t *wall); + + +/** + * @} + */ + + +/** + * @defgroup lavf_misc Utility functions + * @ingroup libavf + * @{ + * + * Miscellaneous utility functions related to both muxing and demuxing + * (or neither). + */ + +/** + * Send a nice hexadecimal dump of a buffer to the specified file stream. + * + * @param f The file stream pointer where the dump should be sent to. + * @param buf buffer + * @param size buffer size + * + * @see av_hex_dump_log, av_pkt_dump2, av_pkt_dump_log2 + */ +void av_hex_dump(FILE *f, const uint8_t *buf, int size); + +/** + * Send a nice hexadecimal dump of a buffer to the log. + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message, lower values signifying + * higher importance. + * @param buf buffer + * @param size buffer size + * + * @see av_hex_dump, av_pkt_dump2, av_pkt_dump_log2 + */ +void av_hex_dump_log(void *avcl, int level, const uint8_t *buf, int size); + +/** + * Send a nice dump of a packet to the specified file stream. + * + * @param f The file stream pointer where the dump should be sent to. + * @param pkt packet to dump + * @param dump_payload True if the payload must be displayed, too. + * @param st AVStream that the packet belongs to + */ +void av_pkt_dump2(FILE *f, const AVPacket *pkt, int dump_payload, const AVStream *st); + + +/** + * Send a nice dump of a packet to the log. + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message, lower values signifying + * higher importance. + * @param pkt packet to dump + * @param dump_payload True if the payload must be displayed, too. + * @param st AVStream that the packet belongs to + */ +void av_pkt_dump_log2(void *avcl, int level, const AVPacket *pkt, int dump_payload, + const AVStream *st); + +/** + * Get the AVCodecID for the given codec tag tag. + * If no codec id is found returns AV_CODEC_ID_NONE. + * + * @param tags list of supported codec_id-codec_tag pairs, as stored + * in AVInputFormat.codec_tag and AVOutputFormat.codec_tag + * @param tag codec tag to match to a codec ID + */ +enum AVCodecID av_codec_get_id(const struct AVCodecTag * const *tags, unsigned int tag); + +/** + * Get the codec tag for the given codec id id. + * If no codec tag is found returns 0. + * + * @param tags list of supported codec_id-codec_tag pairs, as stored + * in AVInputFormat.codec_tag and AVOutputFormat.codec_tag + * @param id codec ID to match to a codec tag + */ +unsigned int av_codec_get_tag(const struct AVCodecTag * const *tags, enum AVCodecID id); + +/** + * Get the codec tag for the given codec id. + * + * @param tags list of supported codec_id - codec_tag pairs, as stored + * in AVInputFormat.codec_tag and AVOutputFormat.codec_tag + * @param id codec id that should be searched for in the list + * @param tag A pointer to the found tag + * @return 0 if id was not found in tags, > 0 if it was found + */ +int av_codec_get_tag2(const struct AVCodecTag * const *tags, enum AVCodecID id, + unsigned int *tag); + +int av_find_default_stream_index(AVFormatContext *s); + +/** + * Get the index for a specific timestamp. + * + * @param st stream that the timestamp belongs to + * @param timestamp timestamp to retrieve the index for + * @param flags if AVSEEK_FLAG_BACKWARD then the returned index will correspond + * to the timestamp which is <= the requested one, if backward + * is 0, then it will be >= + * if AVSEEK_FLAG_ANY seek to any frame, only keyframes otherwise + * @return < 0 if no such timestamp could be found + */ +int av_index_search_timestamp(AVStream *st, int64_t timestamp, int flags); + +/** + * Add an index entry into a sorted list. Update the entry if the list + * already contains it. + * + * @param timestamp timestamp in the time base of the given stream + */ +int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp, + int size, int distance, int flags); + + +/** + * Split a URL string into components. + * + * The pointers to buffers for storing individual components may be null, + * in order to ignore that component. Buffers for components not found are + * set to empty strings. If the port is not found, it is set to a negative + * value. + * + * @param proto the buffer for the protocol + * @param proto_size the size of the proto buffer + * @param authorization the buffer for the authorization + * @param authorization_size the size of the authorization buffer + * @param hostname the buffer for the host name + * @param hostname_size the size of the hostname buffer + * @param port_ptr a pointer to store the port number in + * @param path the buffer for the path + * @param path_size the size of the path buffer + * @param url the URL to split + */ +void av_url_split(char *proto, int proto_size, + char *authorization, int authorization_size, + char *hostname, int hostname_size, + int *port_ptr, + char *path, int path_size, + const char *url); + + +/** + * Print detailed information about the input or output format, such as + * duration, bitrate, streams, container, programs, metadata, side data, + * codec and time base. + * + * @param ic the context to analyze + * @param index index of the stream to dump information about + * @param url the URL to print, such as source or destination file + * @param is_output Select whether the specified context is an input(0) or output(1) + */ +void av_dump_format(AVFormatContext *ic, + int index, + const char *url, + int is_output); + + +#define AV_FRAME_FILENAME_FLAGS_MULTIPLE 1 ///< Allow multiple %d + +/** + * Return in 'buf' the path with '%d' replaced by a number. + * + * Also handles the '%0nd' format where 'n' is the total number + * of digits and '%%'. + * + * @param buf destination buffer + * @param buf_size destination buffer size + * @param path numbered sequence string + * @param number frame number + * @param flags AV_FRAME_FILENAME_FLAGS_* + * @return 0 if OK, -1 on format error + */ +int av_get_frame_filename2(char *buf, int buf_size, + const char *path, int number, int flags); + +int av_get_frame_filename(char *buf, int buf_size, + const char *path, int number); + +/** + * Check whether filename actually is a numbered sequence generator. + * + * @param filename possible numbered sequence string + * @return 1 if a valid numbered sequence string, 0 otherwise + */ +int av_filename_number_test(const char *filename); + +/** + * Generate an SDP for an RTP session. + * + * Note, this overwrites the id values of AVStreams in the muxer contexts + * for getting unique dynamic payload types. + * + * @param ac array of AVFormatContexts describing the RTP streams. If the + * array is composed by only one context, such context can contain + * multiple AVStreams (one AVStream per RTP stream). Otherwise, + * all the contexts in the array (an AVCodecContext per RTP stream) + * must contain only one AVStream. + * @param n_files number of AVCodecContexts contained in ac + * @param buf buffer where the SDP will be stored (must be allocated by + * the caller) + * @param size the size of the buffer + * @return 0 if OK, AVERROR_xxx on error + */ +int av_sdp_create(AVFormatContext *ac[], int n_files, char *buf, int size); + +/** + * Return a positive value if the given filename has one of the given + * extensions, 0 otherwise. + * + * @param filename file name to check against the given extensions + * @param extensions a comma-separated list of filename extensions + */ +int av_match_ext(const char *filename, const char *extensions); + +/** + * Test if the given container can store a codec. + * + * @param ofmt container to check for compatibility + * @param codec_id codec to potentially store in container + * @param std_compliance standards compliance level, one of FF_COMPLIANCE_* + * + * @return 1 if codec with ID codec_id can be stored in ofmt, 0 if it cannot. + * A negative number if this information is not available. + */ +int avformat_query_codec(const AVOutputFormat *ofmt, enum AVCodecID codec_id, + int std_compliance); + +/** + * @defgroup riff_fourcc RIFF FourCCs + * @{ + * Get the tables mapping RIFF FourCCs to libavcodec AVCodecIDs. The tables are + * meant to be passed to av_codec_get_id()/av_codec_get_tag() as in the + * following code: + * @code + * uint32_t tag = MKTAG('H', '2', '6', '4'); + * const struct AVCodecTag *table[] = { avformat_get_riff_video_tags(), 0 }; + * enum AVCodecID id = av_codec_get_id(table, tag); + * @endcode + */ +/** + * @return the table mapping RIFF FourCCs for video to libavcodec AVCodecID. + */ +const struct AVCodecTag *avformat_get_riff_video_tags(void); +/** + * @return the table mapping RIFF FourCCs for audio to AVCodecID. + */ +const struct AVCodecTag *avformat_get_riff_audio_tags(void); +/** + * @return the table mapping MOV FourCCs for video to libavcodec AVCodecID. + */ +const struct AVCodecTag *avformat_get_mov_video_tags(void); +/** + * @return the table mapping MOV FourCCs for audio to AVCodecID. + */ +const struct AVCodecTag *avformat_get_mov_audio_tags(void); + +/** + * @} + */ + +/** + * Guess the sample aspect ratio of a frame, based on both the stream and the + * frame aspect ratio. + * + * Since the frame aspect ratio is set by the codec but the stream aspect ratio + * is set by the demuxer, these two may not be equal. This function tries to + * return the value that you should use if you would like to display the frame. + * + * Basic logic is to use the stream aspect ratio if it is set to something sane + * otherwise use the frame aspect ratio. This way a container setting, which is + * usually easy to modify can override the coded value in the frames. + * + * @param format the format context which the stream is part of + * @param stream the stream which the frame is part of + * @param frame the frame with the aspect ratio to be determined + * @return the guessed (valid) sample_aspect_ratio, 0/1 if no idea + */ +AVRational av_guess_sample_aspect_ratio(AVFormatContext *format, AVStream *stream, AVFrame *frame); + +/** + * Guess the frame rate, based on both the container and codec information. + * + * @param ctx the format context which the stream is part of + * @param stream the stream which the frame is part of + * @param frame the frame for which the frame rate should be determined, may be NULL + * @return the guessed (valid) frame rate, 0/1 if no idea + */ +AVRational av_guess_frame_rate(AVFormatContext *ctx, AVStream *stream, AVFrame *frame); + +/** + * Check if the stream st contained in s is matched by the stream specifier + * spec. + * + * See the "stream specifiers" chapter in the documentation for the syntax + * of spec. + * + * @return >0 if st is matched by spec; + * 0 if st is not matched by spec; + * AVERROR code if spec is invalid + * + * @note A stream specifier can match several streams in the format. + */ +int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, + const char *spec); + +int avformat_queue_attached_pictures(AVFormatContext *s); + +/** + * Apply a list of bitstream filters to a packet. + * + * @param codec AVCodecContext, usually from an AVStream + * @param pkt the packet to apply filters to. If, on success, the returned + * packet has size == 0 and side_data_elems == 0, it indicates that + * the packet should be dropped + * @param bsfc a NULL-terminated list of filters to apply + * @return >=0 on success; + * AVERROR code on failure + */ +#if FF_API_OLD_BSF +attribute_deprecated +int av_apply_bitstream_filters(AVCodecContext *codec, AVPacket *pkt, + AVBitStreamFilterContext *bsfc); +#endif + +enum AVTimebaseSource { + AVFMT_TBCF_AUTO = -1, + AVFMT_TBCF_DECODER, + AVFMT_TBCF_DEMUXER, +#if FF_API_R_FRAME_RATE + AVFMT_TBCF_R_FRAMERATE, +#endif +}; + +/** + * Transfer internal timing information from one stream to another. + * + * This function is useful when doing stream copy. + * + * @param ofmt target output format for ost + * @param ost output stream which needs timings copy and adjustments + * @param ist reference input stream to copy timings from + * @param copy_tb define from where the stream codec timebase needs to be imported + */ +int avformat_transfer_internal_stream_timing_info(const AVOutputFormat *ofmt, + AVStream *ost, const AVStream *ist, + enum AVTimebaseSource copy_tb); + +/** + * Get the internal codec timebase from a stream. + * + * @param st input stream to extract the timebase from + */ +AVRational av_stream_get_codec_timebase(const AVStream *st); + +/** + * @} + */ + +#endif /* AVFORMAT_AVFORMAT_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavformat/avio.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavformat/avio.h new file mode 100644 index 0000000..6f4ed84 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavformat/avio.h @@ -0,0 +1,827 @@ +/* + * copyright (c) 2001 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef AVFORMAT_AVIO_H +#define AVFORMAT_AVIO_H + +/** + * @file + * @ingroup lavf_io + * Buffered I/O operations + */ + +#include + +#include "libavutil/common.h" +#include "libavutil/dict.h" +#include "libavutil/log.h" + +#include "libavformat/version.h" + +/** + * Seeking works like for a local file. + */ +#define AVIO_SEEKABLE_NORMAL (1 << 0) + +/** + * Seeking by timestamp with avio_seek_time() is possible. + */ +#define AVIO_SEEKABLE_TIME (1 << 1) + +/** + * Callback for checking whether to abort blocking functions. + * AVERROR_EXIT is returned in this case by the interrupted + * function. During blocking operations, callback is called with + * opaque as parameter. If the callback returns 1, the + * blocking operation will be aborted. + * + * No members can be added to this struct without a major bump, if + * new elements have been added after this struct in AVFormatContext + * or AVIOContext. + */ +typedef struct AVIOInterruptCB { + int (*callback)(void*); + void *opaque; +} AVIOInterruptCB; + +/** + * Directory entry types. + */ +enum AVIODirEntryType { + AVIO_ENTRY_UNKNOWN, + AVIO_ENTRY_BLOCK_DEVICE, + AVIO_ENTRY_CHARACTER_DEVICE, + AVIO_ENTRY_DIRECTORY, + AVIO_ENTRY_NAMED_PIPE, + AVIO_ENTRY_SYMBOLIC_LINK, + AVIO_ENTRY_SOCKET, + AVIO_ENTRY_FILE, + AVIO_ENTRY_SERVER, + AVIO_ENTRY_SHARE, + AVIO_ENTRY_WORKGROUP, +}; + +/** + * Describes single entry of the directory. + * + * Only name and type fields are guaranteed be set. + * Rest of fields are protocol or/and platform dependent and might be unknown. + */ +typedef struct AVIODirEntry { + char *name; /**< Filename */ + int type; /**< Type of the entry */ + int utf8; /**< Set to 1 when name is encoded with UTF-8, 0 otherwise. + Name can be encoded with UTF-8 even though 0 is set. */ + int64_t size; /**< File size in bytes, -1 if unknown. */ + int64_t modification_timestamp; /**< Time of last modification in microseconds since unix + epoch, -1 if unknown. */ + int64_t access_timestamp; /**< Time of last access in microseconds since unix epoch, + -1 if unknown. */ + int64_t status_change_timestamp; /**< Time of last status change in microseconds since unix + epoch, -1 if unknown. */ + int64_t user_id; /**< User ID of owner, -1 if unknown. */ + int64_t group_id; /**< Group ID of owner, -1 if unknown. */ + int64_t filemode; /**< Unix file mode, -1 if unknown. */ +} AVIODirEntry; + +typedef struct AVIODirContext { + struct URLContext *url_context; +} AVIODirContext; + +/** + * Different data types that can be returned via the AVIO + * write_data_type callback. + */ +enum AVIODataMarkerType { + /** + * Header data; this needs to be present for the stream to be decodeable. + */ + AVIO_DATA_MARKER_HEADER, + /** + * A point in the output bytestream where a decoder can start decoding + * (i.e. a keyframe). A demuxer/decoder given the data flagged with + * AVIO_DATA_MARKER_HEADER, followed by any AVIO_DATA_MARKER_SYNC_POINT, + * should give decodeable results. + */ + AVIO_DATA_MARKER_SYNC_POINT, + /** + * A point in the output bytestream where a demuxer can start parsing + * (for non self synchronizing bytestream formats). That is, any + * non-keyframe packet start point. + */ + AVIO_DATA_MARKER_BOUNDARY_POINT, + /** + * This is any, unlabelled data. It can either be a muxer not marking + * any positions at all, it can be an actual boundary/sync point + * that the muxer chooses not to mark, or a later part of a packet/fragment + * that is cut into multiple write callbacks due to limited IO buffer size. + */ + AVIO_DATA_MARKER_UNKNOWN, + /** + * Trailer data, which doesn't contain actual content, but only for + * finalizing the output file. + */ + AVIO_DATA_MARKER_TRAILER +}; + +/** + * Bytestream IO Context. + * New fields can be added to the end with minor version bumps. + * Removal, reordering and changes to existing fields require a major + * version bump. + * sizeof(AVIOContext) must not be used outside libav*. + * + * @note None of the function pointers in AVIOContext should be called + * directly, they should only be set by the client application + * when implementing custom I/O. Normally these are set to the + * function pointers specified in avio_alloc_context() + */ +typedef struct AVIOContext { + /** + * A class for private options. + * + * If this AVIOContext is created by avio_open2(), av_class is set and + * passes the options down to protocols. + * + * If this AVIOContext is manually allocated, then av_class may be set by + * the caller. + * + * warning -- this field can be NULL, be sure to not pass this AVIOContext + * to any av_opt_* functions in that case. + */ + const AVClass *av_class; + + /* + * The following shows the relationship between buffer, buf_ptr, buf_end, buf_size, + * and pos, when reading and when writing (since AVIOContext is used for both): + * + ********************************************************************************** + * READING + ********************************************************************************** + * + * | buffer_size | + * |---------------------------------------| + * | | + * + * buffer buf_ptr buf_end + * +---------------+-----------------------+ + * |/ / / / / / / /|/ / / / / / /| | + * read buffer: |/ / consumed / | to be read /| | + * |/ / / / / / / /|/ / / / / / /| | + * +---------------+-----------------------+ + * + * pos + * +-------------------------------------------+-----------------+ + * input file: | | | + * +-------------------------------------------+-----------------+ + * + * + ********************************************************************************** + * WRITING + ********************************************************************************** + * + * | buffer_size | + * |-------------------------------| + * | | + * + * buffer buf_ptr buf_end + * +-------------------+-----------+ + * |/ / / / / / / / / /| | + * write buffer: | / to be flushed / | | + * |/ / / / / / / / / /| | + * +-------------------+-----------+ + * + * pos + * +--------------------------+-----------------------------------+ + * output file: | | | + * +--------------------------+-----------------------------------+ + * + */ + unsigned char *buffer; /**< Start of the buffer. */ + int buffer_size; /**< Maximum buffer size */ + unsigned char *buf_ptr; /**< Current position in the buffer */ + unsigned char *buf_end; /**< End of the data, may be less than + buffer+buffer_size if the read function returned + less data than requested, e.g. for streams where + no more data has been received yet. */ + void *opaque; /**< A private pointer, passed to the read/write/seek/... + functions. */ + int (*read_packet)(void *opaque, uint8_t *buf, int buf_size); + int (*write_packet)(void *opaque, uint8_t *buf, int buf_size); + int64_t (*seek)(void *opaque, int64_t offset, int whence); + int64_t pos; /**< position in the file of the current buffer */ + int must_flush; /**< true if the next seek should flush */ + int eof_reached; /**< true if eof reached */ + int write_flag; /**< true if open for writing */ + int max_packet_size; + unsigned long checksum; + unsigned char *checksum_ptr; + unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size); + int error; /**< contains the error code or 0 if no error happened */ + /** + * Pause or resume playback for network streaming protocols - e.g. MMS. + */ + int (*read_pause)(void *opaque, int pause); + /** + * Seek to a given timestamp in stream with the specified stream_index. + * Needed for some network streaming protocols which don't support seeking + * to byte position. + */ + int64_t (*read_seek)(void *opaque, int stream_index, + int64_t timestamp, int flags); + /** + * A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable. + */ + int seekable; + + /** + * max filesize, used to limit allocations + * This field is internal to libavformat and access from outside is not allowed. + */ + int64_t maxsize; + + /** + * avio_read and avio_write should if possible be satisfied directly + * instead of going through a buffer, and avio_seek will always + * call the underlying seek function directly. + */ + int direct; + + /** + * Bytes read statistic + * This field is internal to libavformat and access from outside is not allowed. + */ + int64_t bytes_read; + + /** + * seek statistic + * This field is internal to libavformat and access from outside is not allowed. + */ + int seek_count; + + /** + * writeout statistic + * This field is internal to libavformat and access from outside is not allowed. + */ + int writeout_count; + + /** + * Original buffer size + * used internally after probing and ensure seekback to reset the buffer size + * This field is internal to libavformat and access from outside is not allowed. + */ + int orig_buffer_size; + + /** + * Threshold to favor readahead over seek. + * This is current internal only, do not use from outside. + */ + int short_seek_threshold; + + /** + * ',' separated list of allowed protocols. + */ + const char *protocol_whitelist; + + /** + * ',' separated list of disallowed protocols. + */ + const char *protocol_blacklist; + + /** + * A callback that is used instead of write_packet. + */ + int (*write_data_type)(void *opaque, uint8_t *buf, int buf_size, + enum AVIODataMarkerType type, int64_t time); + /** + * If set, don't call write_data_type separately for AVIO_DATA_MARKER_BOUNDARY_POINT, + * but ignore them and treat them as AVIO_DATA_MARKER_UNKNOWN (to avoid needlessly + * small chunks of data returned from the callback). + */ + int ignore_boundary_point; + + /** + * Internal, not meant to be used from outside of AVIOContext. + */ + enum AVIODataMarkerType current_type; + int64_t last_time; + + /** + * A callback that is used instead of short_seek_threshold. + * This is current internal only, do not use from outside. + */ + int (*short_seek_get)(void *opaque); +} AVIOContext; + +/** + * Return the name of the protocol that will handle the passed URL. + * + * NULL is returned if no protocol could be found for the given URL. + * + * @return Name of the protocol or NULL. + */ +const char *avio_find_protocol_name(const char *url); + +/** + * Return AVIO_FLAG_* access flags corresponding to the access permissions + * of the resource in url, or a negative value corresponding to an + * AVERROR code in case of failure. The returned access flags are + * masked by the value in flags. + * + * @note This function is intrinsically unsafe, in the sense that the + * checked resource may change its existence or permission status from + * one call to another. Thus you should not trust the returned value, + * unless you are sure that no other processes are accessing the + * checked resource. + */ +int avio_check(const char *url, int flags); + +/** + * Move or rename a resource. + * + * @note url_src and url_dst should share the same protocol and authority. + * + * @param url_src url to resource to be moved + * @param url_dst new url to resource if the operation succeeded + * @return >=0 on success or negative on error. + */ +int avpriv_io_move(const char *url_src, const char *url_dst); + +/** + * Delete a resource. + * + * @param url resource to be deleted. + * @return >=0 on success or negative on error. + */ +int avpriv_io_delete(const char *url); + +/** + * Open directory for reading. + * + * @param s directory read context. Pointer to a NULL pointer must be passed. + * @param url directory to be listed. + * @param options A dictionary filled with protocol-private options. On return + * this parameter will be destroyed and replaced with a dictionary + * containing options that were not found. May be NULL. + * @return >=0 on success or negative on error. + */ +int avio_open_dir(AVIODirContext **s, const char *url, AVDictionary **options); + +/** + * Get next directory entry. + * + * Returned entry must be freed with avio_free_directory_entry(). In particular + * it may outlive AVIODirContext. + * + * @param s directory read context. + * @param[out] next next entry or NULL when no more entries. + * @return >=0 on success or negative on error. End of list is not considered an + * error. + */ +int avio_read_dir(AVIODirContext *s, AVIODirEntry **next); + +/** + * Close directory. + * + * @note Entries created using avio_read_dir() are not deleted and must be + * freeded with avio_free_directory_entry(). + * + * @param s directory read context. + * @return >=0 on success or negative on error. + */ +int avio_close_dir(AVIODirContext **s); + +/** + * Free entry allocated by avio_read_dir(). + * + * @param entry entry to be freed. + */ +void avio_free_directory_entry(AVIODirEntry **entry); + +/** + * Allocate and initialize an AVIOContext for buffered I/O. It must be later + * freed with av_free(). + * + * @param buffer Memory block for input/output operations via AVIOContext. + * The buffer must be allocated with av_malloc() and friends. + * It may be freed and replaced with a new buffer by libavformat. + * AVIOContext.buffer holds the buffer currently in use, + * which must be later freed with av_free(). + * @param buffer_size The buffer size is very important for performance. + * For protocols with fixed blocksize it should be set to this blocksize. + * For others a typical size is a cache page, e.g. 4kb. + * @param write_flag Set to 1 if the buffer should be writable, 0 otherwise. + * @param opaque An opaque pointer to user-specific data. + * @param read_packet A function for refilling the buffer, may be NULL. + * @param write_packet A function for writing the buffer contents, may be NULL. + * The function may not change the input buffers content. + * @param seek A function for seeking to specified byte position, may be NULL. + * + * @return Allocated AVIOContext or NULL on failure. + */ +AVIOContext *avio_alloc_context( + unsigned char *buffer, + int buffer_size, + int write_flag, + void *opaque, + int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), + int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), + int64_t (*seek)(void *opaque, int64_t offset, int whence)); + +void avio_w8(AVIOContext *s, int b); +void avio_write(AVIOContext *s, const unsigned char *buf, int size); +void avio_wl64(AVIOContext *s, uint64_t val); +void avio_wb64(AVIOContext *s, uint64_t val); +void avio_wl32(AVIOContext *s, unsigned int val); +void avio_wb32(AVIOContext *s, unsigned int val); +void avio_wl24(AVIOContext *s, unsigned int val); +void avio_wb24(AVIOContext *s, unsigned int val); +void avio_wl16(AVIOContext *s, unsigned int val); +void avio_wb16(AVIOContext *s, unsigned int val); + +/** + * Write a NULL-terminated string. + * @return number of bytes written. + */ +int avio_put_str(AVIOContext *s, const char *str); + +/** + * Convert an UTF-8 string to UTF-16LE and write it. + * @param s the AVIOContext + * @param str NULL-terminated UTF-8 string + * + * @return number of bytes written. + */ +int avio_put_str16le(AVIOContext *s, const char *str); + +/** + * Convert an UTF-8 string to UTF-16BE and write it. + * @param s the AVIOContext + * @param str NULL-terminated UTF-8 string + * + * @return number of bytes written. + */ +int avio_put_str16be(AVIOContext *s, const char *str); + +/** + * Mark the written bytestream as a specific type. + * + * Zero-length ranges are omitted from the output. + * + * @param time the stream time the current bytestream pos corresponds to + * (in AV_TIME_BASE units), or AV_NOPTS_VALUE if unknown or not + * applicable + * @param type the kind of data written starting at the current pos + */ +void avio_write_marker(AVIOContext *s, int64_t time, enum AVIODataMarkerType type); + +/** + * ORing this as the "whence" parameter to a seek function causes it to + * return the filesize without seeking anywhere. Supporting this is optional. + * If it is not supported then the seek function will return <0. + */ +#define AVSEEK_SIZE 0x10000 + +/** + * Passing this flag as the "whence" parameter to a seek function causes it to + * seek by any means (like reopening and linear reading) or other normally unreasonable + * means that can be extremely slow. + * This may be ignored by the seek code. + */ +#define AVSEEK_FORCE 0x20000 + +/** + * fseek() equivalent for AVIOContext. + * @return new position or AVERROR. + */ +int64_t avio_seek(AVIOContext *s, int64_t offset, int whence); + +/** + * Skip given number of bytes forward + * @return new position or AVERROR. + */ +int64_t avio_skip(AVIOContext *s, int64_t offset); + +/** + * ftell() equivalent for AVIOContext. + * @return position or AVERROR. + */ +static av_always_inline int64_t avio_tell(AVIOContext *s) +{ + return avio_seek(s, 0, SEEK_CUR); +} + +/** + * Get the filesize. + * @return filesize or AVERROR + */ +int64_t avio_size(AVIOContext *s); + +/** + * feof() equivalent for AVIOContext. + * @return non zero if and only if end of file + */ +int avio_feof(AVIOContext *s); +#if FF_API_URL_FEOF +/** + * @deprecated use avio_feof() + */ +attribute_deprecated +int url_feof(AVIOContext *s); +#endif + +/** @warning Writes up to 4 KiB per call */ +int avio_printf(AVIOContext *s, const char *fmt, ...) av_printf_format(2, 3); + +/** + * Force flushing of buffered data. + * + * For write streams, force the buffered data to be immediately written to the output, + * without to wait to fill the internal buffer. + * + * For read streams, discard all currently buffered data, and advance the + * reported file position to that of the underlying stream. This does not + * read new data, and does not perform any seeks. + */ +void avio_flush(AVIOContext *s); + +/** + * Read size bytes from AVIOContext into buf. + * @return number of bytes read or AVERROR + */ +int avio_read(AVIOContext *s, unsigned char *buf, int size); + +/** + * @name Functions for reading from AVIOContext + * @{ + * + * @note return 0 if EOF, so you cannot use it if EOF handling is + * necessary + */ +int avio_r8 (AVIOContext *s); +unsigned int avio_rl16(AVIOContext *s); +unsigned int avio_rl24(AVIOContext *s); +unsigned int avio_rl32(AVIOContext *s); +uint64_t avio_rl64(AVIOContext *s); +unsigned int avio_rb16(AVIOContext *s); +unsigned int avio_rb24(AVIOContext *s); +unsigned int avio_rb32(AVIOContext *s); +uint64_t avio_rb64(AVIOContext *s); +/** + * @} + */ + +/** + * Read a string from pb into buf. The reading will terminate when either + * a NULL character was encountered, maxlen bytes have been read, or nothing + * more can be read from pb. The result is guaranteed to be NULL-terminated, it + * will be truncated if buf is too small. + * Note that the string is not interpreted or validated in any way, it + * might get truncated in the middle of a sequence for multi-byte encodings. + * + * @return number of bytes read (is always <= maxlen). + * If reading ends on EOF or error, the return value will be one more than + * bytes actually read. + */ +int avio_get_str(AVIOContext *pb, int maxlen, char *buf, int buflen); + +/** + * Read a UTF-16 string from pb and convert it to UTF-8. + * The reading will terminate when either a null or invalid character was + * encountered or maxlen bytes have been read. + * @return number of bytes read (is always <= maxlen) + */ +int avio_get_str16le(AVIOContext *pb, int maxlen, char *buf, int buflen); +int avio_get_str16be(AVIOContext *pb, int maxlen, char *buf, int buflen); + + +/** + * @name URL open modes + * The flags argument to avio_open must be one of the following + * constants, optionally ORed with other flags. + * @{ + */ +#define AVIO_FLAG_READ 1 /**< read-only */ +#define AVIO_FLAG_WRITE 2 /**< write-only */ +#define AVIO_FLAG_READ_WRITE (AVIO_FLAG_READ|AVIO_FLAG_WRITE) /**< read-write pseudo flag */ +/** + * @} + */ + +/** + * Use non-blocking mode. + * If this flag is set, operations on the context will return + * AVERROR(EAGAIN) if they can not be performed immediately. + * If this flag is not set, operations on the context will never return + * AVERROR(EAGAIN). + * Note that this flag does not affect the opening/connecting of the + * context. Connecting a protocol will always block if necessary (e.g. on + * network protocols) but never hang (e.g. on busy devices). + * Warning: non-blocking protocols is work-in-progress; this flag may be + * silently ignored. + */ +#define AVIO_FLAG_NONBLOCK 8 + +/** + * Use direct mode. + * avio_read and avio_write should if possible be satisfied directly + * instead of going through a buffer, and avio_seek will always + * call the underlying seek function directly. + */ +#define AVIO_FLAG_DIRECT 0x8000 + +/** + * Create and initialize a AVIOContext for accessing the + * resource indicated by url. + * @note When the resource indicated by url has been opened in + * read+write mode, the AVIOContext can be used only for writing. + * + * @param s Used to return the pointer to the created AVIOContext. + * In case of failure the pointed to value is set to NULL. + * @param url resource to access + * @param flags flags which control how the resource indicated by url + * is to be opened + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code in case of failure + */ +int avio_open(AVIOContext **s, const char *url, int flags); + +/** + * Create and initialize a AVIOContext for accessing the + * resource indicated by url. + * @note When the resource indicated by url has been opened in + * read+write mode, the AVIOContext can be used only for writing. + * + * @param s Used to return the pointer to the created AVIOContext. + * In case of failure the pointed to value is set to NULL. + * @param url resource to access + * @param flags flags which control how the resource indicated by url + * is to be opened + * @param int_cb an interrupt callback to be used at the protocols level + * @param options A dictionary filled with protocol-private options. On return + * this parameter will be destroyed and replaced with a dict containing options + * that were not found. May be NULL. + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code in case of failure + */ +int avio_open2(AVIOContext **s, const char *url, int flags, + const AVIOInterruptCB *int_cb, AVDictionary **options); + +/** + * Close the resource accessed by the AVIOContext s and free it. + * This function can only be used if s was opened by avio_open(). + * + * The internal buffer is automatically flushed before closing the + * resource. + * + * @return 0 on success, an AVERROR < 0 on error. + * @see avio_closep + */ +int avio_close(AVIOContext *s); + +/** + * Close the resource accessed by the AVIOContext *s, free it + * and set the pointer pointing to it to NULL. + * This function can only be used if s was opened by avio_open(). + * + * The internal buffer is automatically flushed before closing the + * resource. + * + * @return 0 on success, an AVERROR < 0 on error. + * @see avio_close + */ +int avio_closep(AVIOContext **s); + + +/** + * Open a write only memory stream. + * + * @param s new IO context + * @return zero if no error. + */ +int avio_open_dyn_buf(AVIOContext **s); + +/** + * Return the written size and a pointer to the buffer. + * The AVIOContext stream is left intact. + * The buffer must NOT be freed. + * No padding is added to the buffer. + * + * @param s IO context + * @param pbuffer pointer to a byte buffer + * @return the length of the byte buffer + */ +int avio_get_dyn_buf(AVIOContext *s, uint8_t **pbuffer); + +/** + * Return the written size and a pointer to the buffer. The buffer + * must be freed with av_free(). + * Padding of AV_INPUT_BUFFER_PADDING_SIZE is added to the buffer. + * + * @param s IO context + * @param pbuffer pointer to a byte buffer + * @return the length of the byte buffer + */ +int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer); + +/** + * Iterate through names of available protocols. + * + * @param opaque A private pointer representing current protocol. + * It must be a pointer to NULL on first iteration and will + * be updated by successive calls to avio_enum_protocols. + * @param output If set to 1, iterate over output protocols, + * otherwise over input protocols. + * + * @return A static string containing the name of current protocol or NULL + */ +const char *avio_enum_protocols(void **opaque, int output); + +/** + * Pause and resume playing - only meaningful if using a network streaming + * protocol (e.g. MMS). + * + * @param h IO context from which to call the read_pause function pointer + * @param pause 1 for pause, 0 for resume + */ +int avio_pause(AVIOContext *h, int pause); + +/** + * Seek to a given timestamp relative to some component stream. + * Only meaningful if using a network streaming protocol (e.g. MMS.). + * + * @param h IO context from which to call the seek function pointers + * @param stream_index The stream index that the timestamp is relative to. + * If stream_index is (-1) the timestamp should be in AV_TIME_BASE + * units from the beginning of the presentation. + * If a stream_index >= 0 is used and the protocol does not support + * seeking based on component streams, the call will fail. + * @param timestamp timestamp in AVStream.time_base units + * or if there is no stream specified then in AV_TIME_BASE units. + * @param flags Optional combination of AVSEEK_FLAG_BACKWARD, AVSEEK_FLAG_BYTE + * and AVSEEK_FLAG_ANY. The protocol may silently ignore + * AVSEEK_FLAG_BACKWARD and AVSEEK_FLAG_ANY, but AVSEEK_FLAG_BYTE will + * fail if used and not supported. + * @return >= 0 on success + * @see AVInputFormat::read_seek + */ +int64_t avio_seek_time(AVIOContext *h, int stream_index, + int64_t timestamp, int flags); + +/* Avoid a warning. The header can not be included because it breaks c++. */ +struct AVBPrint; + +/** + * Read contents of h into print buffer, up to max_size bytes, or up to EOF. + * + * @return 0 for success (max_size bytes read or EOF reached), negative error + * code otherwise + */ +int avio_read_to_bprint(AVIOContext *h, struct AVBPrint *pb, size_t max_size); + +/** + * Accept and allocate a client context on a server context. + * @param s the server context + * @param c the client context, must be unallocated + * @return >= 0 on success or a negative value corresponding + * to an AVERROR on failure + */ +int avio_accept(AVIOContext *s, AVIOContext **c); + +/** + * Perform one step of the protocol handshake to accept a new client. + * This function must be called on a client returned by avio_accept() before + * using it as a read/write context. + * It is separate from avio_accept() because it may block. + * A step of the handshake is defined by places where the application may + * decide to change the proceedings. + * For example, on a protocol with a request header and a reply header, each + * one can constitute a step because the application may use the parameters + * from the request to change parameters in the reply; or each individual + * chunk of the request can constitute a step. + * If the handshake is already finished, avio_handshake() does nothing and + * returns 0 immediately. + * + * @param c the client context to perform the handshake on + * @return 0 on a complete and successful handshake + * > 0 if the handshake progressed, but is not complete + * < 0 for an AVERROR code + */ +int avio_handshake(AVIOContext *c); +#endif /* AVFORMAT_AVIO_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavformat/version.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavformat/version.h new file mode 100644 index 0000000..fc054ee --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavformat/version.h @@ -0,0 +1,105 @@ +/* + * Version macros. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFORMAT_VERSION_H +#define AVFORMAT_VERSION_H + +/** + * @file + * @ingroup libavf + * Libavformat version macros + */ + +#include "libavutil/version.h" + +// Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium) +// Also please add any ticket numbers that you believe might be affected here +#define LIBAVFORMAT_VERSION_MAJOR 57 +#define LIBAVFORMAT_VERSION_MINOR 71 +#define LIBAVFORMAT_VERSION_MICRO 100 + +#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ + LIBAVFORMAT_VERSION_MINOR, \ + LIBAVFORMAT_VERSION_MICRO) +#define LIBAVFORMAT_VERSION AV_VERSION(LIBAVFORMAT_VERSION_MAJOR, \ + LIBAVFORMAT_VERSION_MINOR, \ + LIBAVFORMAT_VERSION_MICRO) +#define LIBAVFORMAT_BUILD LIBAVFORMAT_VERSION_INT + +#define LIBAVFORMAT_IDENT "Lavf" AV_STRINGIFY(LIBAVFORMAT_VERSION) + +/** + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + * + * @note, when bumping the major version it is recommended to manually + * disable each FF_API_* in its own commit instead of disabling them all + * at once through the bump. This improves the git bisect-ability of the change. + * + */ +#ifndef FF_API_LAVF_BITEXACT +#define FF_API_LAVF_BITEXACT (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_LAVF_FRAC +#define FF_API_LAVF_FRAC (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_LAVF_CODEC_TB +#define FF_API_LAVF_CODEC_TB (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_URL_FEOF +#define FF_API_URL_FEOF (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_LAVF_FMT_RAWPICTURE +#define FF_API_LAVF_FMT_RAWPICTURE (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_COMPUTE_PKT_FIELDS2 +#define FF_API_COMPUTE_PKT_FIELDS2 (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_OLD_OPEN_CALLBACKS +#define FF_API_OLD_OPEN_CALLBACKS (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_LAVF_AVCTX +#define FF_API_LAVF_AVCTX (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_NOCONST_GET_SIDE_DATA +#define FF_API_NOCONST_GET_SIDE_DATA (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_HTTP_USER_AGENT +#define FF_API_HTTP_USER_AGENT (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_HLS_WRAP +#define FF_API_HLS_WRAP (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_LAVF_MERGE_SD +#define FF_API_LAVF_MERGE_SD (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_LAVF_KEEPSIDE_FLAG +#define FF_API_LAVF_KEEPSIDE_FLAG (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_OLD_ROTATE_API +#define FF_API_OLD_ROTATE_API (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif + + +#ifndef FF_API_R_FRAME_RATE +#define FF_API_R_FRAME_RATE 1 +#endif +#endif /* AVFORMAT_VERSION_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/adler32.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/adler32.h new file mode 100644 index 0000000..a1f035b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/adler32.h @@ -0,0 +1,60 @@ +/* + * copyright (c) 2006 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_adler32 + * Public header for Adler-32 hash function implementation. + */ + +#ifndef AVUTIL_ADLER32_H +#define AVUTIL_ADLER32_H + +#include +#include "attributes.h" + +/** + * @defgroup lavu_adler32 Adler-32 + * @ingroup lavu_hash + * Adler-32 hash function implementation. + * + * @{ + */ + +/** + * Calculate the Adler32 checksum of a buffer. + * + * Passing the return value to a subsequent av_adler32_update() call + * allows the checksum of multiple buffers to be calculated as though + * they were concatenated. + * + * @param adler initial checksum value + * @param buf pointer to input buffer + * @param len size of input buffer + * @return updated checksum + */ +unsigned long av_adler32_update(unsigned long adler, const uint8_t *buf, + unsigned int len) av_pure; + +/** + * @} + */ + +#endif /* AVUTIL_ADLER32_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/aes.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/aes.h new file mode 100644 index 0000000..09efbda --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/aes.h @@ -0,0 +1,65 @@ +/* + * copyright (c) 2007 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AES_H +#define AVUTIL_AES_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_aes AES + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_aes_size; + +struct AVAES; + +/** + * Allocate an AVAES context. + */ +struct AVAES *av_aes_alloc(void); + +/** + * Initialize an AVAES context. + * @param key_bits 128, 192 or 256 + * @param decrypt 0 for encryption, 1 for decryption + */ +int av_aes_init(struct AVAES *a, const uint8_t *key, int key_bits, int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * @param count number of 16 byte blocks + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_aes_crypt(struct AVAES *a, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_AES_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/aes_ctr.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/aes_ctr.h new file mode 100644 index 0000000..f596fa6 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/aes_ctr.h @@ -0,0 +1,83 @@ +/* + * AES-CTR cipher + * Copyright (c) 2015 Eran Kornblau + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AES_CTR_H +#define AVUTIL_AES_CTR_H + +#include + +#include "attributes.h" +#include "version.h" + +#define AES_CTR_KEY_SIZE (16) +#define AES_CTR_IV_SIZE (8) + +struct AVAESCTR; + +/** + * Allocate an AVAESCTR context. + */ +struct AVAESCTR *av_aes_ctr_alloc(void); + +/** + * Initialize an AVAESCTR context. + * @param key encryption key, must have a length of AES_CTR_KEY_SIZE + */ +int av_aes_ctr_init(struct AVAESCTR *a, const uint8_t *key); + +/** + * Release an AVAESCTR context. + */ +void av_aes_ctr_free(struct AVAESCTR *a); + +/** + * Process a buffer using a previously initialized context. + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param size the size of src and dst + */ +void av_aes_ctr_crypt(struct AVAESCTR *a, uint8_t *dst, const uint8_t *src, int size); + +/** + * Get the current iv + */ +const uint8_t* av_aes_ctr_get_iv(struct AVAESCTR *a); + +/** + * Generate a random iv + */ +void av_aes_ctr_set_random_iv(struct AVAESCTR *a); + +/** + * Forcefully change the iv + */ +void av_aes_ctr_set_iv(struct AVAESCTR *a, const uint8_t* iv); + +/** + * Increment the top 64 bit of the iv (performed after each frame) + */ +void av_aes_ctr_increment_iv(struct AVAESCTR *a); + +/** + * @} + */ + +#endif /* AVUTIL_AES_CTR_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/attributes.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/attributes.h new file mode 100644 index 0000000..54d1901 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/attributes.h @@ -0,0 +1,167 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Macro definitions for various function/variable attributes + */ + +#ifndef AVUTIL_ATTRIBUTES_H +#define AVUTIL_ATTRIBUTES_H + +#ifdef __GNUC__ +# define AV_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y)) +# define AV_GCC_VERSION_AT_MOST(x,y) (__GNUC__ < (x) || __GNUC__ == (x) && __GNUC_MINOR__ <= (y)) +#else +# define AV_GCC_VERSION_AT_LEAST(x,y) 0 +# define AV_GCC_VERSION_AT_MOST(x,y) 0 +#endif + +#ifndef av_always_inline +#if AV_GCC_VERSION_AT_LEAST(3,1) +# define av_always_inline __attribute__((always_inline)) inline +#elif defined(_MSC_VER) +# define av_always_inline __forceinline +#else +# define av_always_inline inline +#endif +#endif + +#ifndef av_extern_inline +#if defined(__ICL) && __ICL >= 1210 || defined(__GNUC_STDC_INLINE__) +# define av_extern_inline extern inline +#else +# define av_extern_inline inline +#endif +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,4) +# define av_warn_unused_result __attribute__((warn_unused_result)) +#else +# define av_warn_unused_result +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,1) +# define av_noinline __attribute__((noinline)) +#elif defined(_MSC_VER) +# define av_noinline __declspec(noinline) +#else +# define av_noinline +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,1) +# define av_pure __attribute__((pure)) +#else +# define av_pure +#endif + +#if AV_GCC_VERSION_AT_LEAST(2,6) +# define av_const __attribute__((const)) +#else +# define av_const +#endif + +#if AV_GCC_VERSION_AT_LEAST(4,3) +# define av_cold __attribute__((cold)) +#else +# define av_cold +#endif + +#if AV_GCC_VERSION_AT_LEAST(4,1) && !defined(__llvm__) +# define av_flatten __attribute__((flatten)) +#else +# define av_flatten +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,1) +# define attribute_deprecated __attribute__((deprecated)) +#elif defined(_MSC_VER) +# define attribute_deprecated __declspec(deprecated) +#else +# define attribute_deprecated +#endif + +/** + * Disable warnings about deprecated features + * This is useful for sections of code kept for backward compatibility and + * scheduled for removal. + */ +#ifndef AV_NOWARN_DEPRECATED +#if AV_GCC_VERSION_AT_LEAST(4,6) +# define AV_NOWARN_DEPRECATED(code) \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \ + code \ + _Pragma("GCC diagnostic pop") +#elif defined(_MSC_VER) +# define AV_NOWARN_DEPRECATED(code) \ + __pragma(warning(push)) \ + __pragma(warning(disable : 4996)) \ + code; \ + __pragma(warning(pop)) +#else +# define AV_NOWARN_DEPRECATED(code) code +#endif +#endif + +#if defined(__GNUC__) || defined(__clang__) +# define av_unused __attribute__((unused)) +#else +# define av_unused +#endif + +/** + * Mark a variable as used and prevent the compiler from optimizing it + * away. This is useful for variables accessed only from inline + * assembler without the compiler being aware. + */ +#if AV_GCC_VERSION_AT_LEAST(3,1) || defined(__clang__) +# define av_used __attribute__((used)) +#else +# define av_used +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,3) +# define av_alias __attribute__((may_alias)) +#else +# define av_alias +#endif + +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) +# define av_uninit(x) x=x +#else +# define av_uninit(x) x +#endif + +#ifdef __GNUC__ +# define av_builtin_constant_p __builtin_constant_p +# define av_printf_format(fmtpos, attrpos) __attribute__((__format__(__printf__, fmtpos, attrpos))) +#else +# define av_builtin_constant_p(x) 0 +# define av_printf_format(fmtpos, attrpos) +#endif + +#if AV_GCC_VERSION_AT_LEAST(2,5) +# define av_noreturn __attribute__((noreturn)) +#else +# define av_noreturn +#endif + +#endif /* AVUTIL_ATTRIBUTES_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/audio_fifo.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/audio_fifo.h new file mode 100644 index 0000000..d8a9194 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/audio_fifo.h @@ -0,0 +1,187 @@ +/* + * Audio FIFO + * Copyright (c) 2012 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Audio FIFO Buffer + */ + +#ifndef AVUTIL_AUDIO_FIFO_H +#define AVUTIL_AUDIO_FIFO_H + +#include "avutil.h" +#include "fifo.h" +#include "samplefmt.h" + +/** + * @addtogroup lavu_audio + * @{ + * + * @defgroup lavu_audiofifo Audio FIFO Buffer + * @{ + */ + +/** + * Context for an Audio FIFO Buffer. + * + * - Operates at the sample level rather than the byte level. + * - Supports multiple channels with either planar or packed sample format. + * - Automatic reallocation when writing to a full buffer. + */ +typedef struct AVAudioFifo AVAudioFifo; + +/** + * Free an AVAudioFifo. + * + * @param af AVAudioFifo to free + */ +void av_audio_fifo_free(AVAudioFifo *af); + +/** + * Allocate an AVAudioFifo. + * + * @param sample_fmt sample format + * @param channels number of channels + * @param nb_samples initial allocation size, in samples + * @return newly allocated AVAudioFifo, or NULL on error + */ +AVAudioFifo *av_audio_fifo_alloc(enum AVSampleFormat sample_fmt, int channels, + int nb_samples); + +/** + * Reallocate an AVAudioFifo. + * + * @param af AVAudioFifo to reallocate + * @param nb_samples new allocation size, in samples + * @return 0 if OK, or negative AVERROR code on failure + */ +av_warn_unused_result +int av_audio_fifo_realloc(AVAudioFifo *af, int nb_samples); + +/** + * Write data to an AVAudioFifo. + * + * The AVAudioFifo will be reallocated automatically if the available space + * is less than nb_samples. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to write to + * @param data audio data plane pointers + * @param nb_samples number of samples to write + * @return number of samples actually written, or negative AVERROR + * code on failure. If successful, the number of samples + * actually written will always be nb_samples. + */ +int av_audio_fifo_write(AVAudioFifo *af, void **data, int nb_samples); + +/** + * Peek data from an AVAudioFifo. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to read from + * @param data audio data plane pointers + * @param nb_samples number of samples to peek + * @return number of samples actually peek, or negative AVERROR code + * on failure. The number of samples actually peek will not + * be greater than nb_samples, and will only be less than + * nb_samples if av_audio_fifo_size is less than nb_samples. + */ +int av_audio_fifo_peek(AVAudioFifo *af, void **data, int nb_samples); + +/** + * Peek data from an AVAudioFifo. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to read from + * @param data audio data plane pointers + * @param nb_samples number of samples to peek + * @param offset offset from current read position + * @return number of samples actually peek, or negative AVERROR code + * on failure. The number of samples actually peek will not + * be greater than nb_samples, and will only be less than + * nb_samples if av_audio_fifo_size is less than nb_samples. + */ +int av_audio_fifo_peek_at(AVAudioFifo *af, void **data, int nb_samples, int offset); + +/** + * Read data from an AVAudioFifo. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to read from + * @param data audio data plane pointers + * @param nb_samples number of samples to read + * @return number of samples actually read, or negative AVERROR code + * on failure. The number of samples actually read will not + * be greater than nb_samples, and will only be less than + * nb_samples if av_audio_fifo_size is less than nb_samples. + */ +int av_audio_fifo_read(AVAudioFifo *af, void **data, int nb_samples); + +/** + * Drain data from an AVAudioFifo. + * + * Removes the data without reading it. + * + * @param af AVAudioFifo to drain + * @param nb_samples number of samples to drain + * @return 0 if OK, or negative AVERROR code on failure + */ +int av_audio_fifo_drain(AVAudioFifo *af, int nb_samples); + +/** + * Reset the AVAudioFifo buffer. + * + * This empties all data in the buffer. + * + * @param af AVAudioFifo to reset + */ +void av_audio_fifo_reset(AVAudioFifo *af); + +/** + * Get the current number of samples in the AVAudioFifo available for reading. + * + * @param af the AVAudioFifo to query + * @return number of samples available for reading + */ +int av_audio_fifo_size(AVAudioFifo *af); + +/** + * Get the current number of samples in the AVAudioFifo available for writing. + * + * @param af the AVAudioFifo to query + * @return number of samples available for writing + */ +int av_audio_fifo_space(AVAudioFifo *af); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_AUDIO_FIFO_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/avassert.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/avassert.h new file mode 100644 index 0000000..46f3fea --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/avassert.h @@ -0,0 +1,75 @@ +/* + * copyright (c) 2010 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * simple assert() macros that are a bit more flexible than ISO C assert(). + * @author Michael Niedermayer + */ + +#ifndef AVUTIL_AVASSERT_H +#define AVUTIL_AVASSERT_H + +#include +#include "avutil.h" +#include "log.h" + +/** + * assert() equivalent, that is always enabled. + */ +#define av_assert0(cond) do { \ + if (!(cond)) { \ + av_log(NULL, AV_LOG_PANIC, "Assertion %s failed at %s:%d\n", \ + AV_STRINGIFY(cond), __FILE__, __LINE__); \ + abort(); \ + } \ +} while (0) + + +/** + * assert() equivalent, that does not lie in speed critical code. + * These asserts() thus can be enabled without fearing speed loss. + */ +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 0 +#define av_assert1(cond) av_assert0(cond) +#else +#define av_assert1(cond) ((void)0) +#endif + + +/** + * assert() equivalent, that does lie in speed critical code. + */ +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 1 +#define av_assert2(cond) av_assert0(cond) +#define av_assert2_fpu() av_assert0_fpu() +#else +#define av_assert2(cond) ((void)0) +#define av_assert2_fpu() ((void)0) +#endif + +/** + * Assert that floating point opperations can be executed. + * + * This will av_assert0() that the cpu is not in MMX state on X86 + */ +void av_assert0_fpu(void); + +#endif /* AVUTIL_AVASSERT_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/avconfig.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/avconfig.h new file mode 100644 index 0000000..f10aa61 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/avconfig.h @@ -0,0 +1,6 @@ +/* Generated by ffconf */ +#ifndef AVUTIL_AVCONFIG_H +#define AVUTIL_AVCONFIG_H +#define AV_HAVE_BIGENDIAN 0 +#define AV_HAVE_FAST_UNALIGNED 1 +#endif /* AVUTIL_AVCONFIG_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/avstring.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/avstring.h new file mode 100644 index 0000000..dd28769 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/avstring.h @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2007 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AVSTRING_H +#define AVUTIL_AVSTRING_H + +#include +#include +#include "attributes.h" + +/** + * @addtogroup lavu_string + * @{ + */ + +/** + * Return non-zero if pfx is a prefix of str. If it is, *ptr is set to + * the address of the first character in str after the prefix. + * + * @param str input string + * @param pfx prefix to test + * @param ptr updated if the prefix is matched inside str + * @return non-zero if the prefix matches, zero otherwise + */ +int av_strstart(const char *str, const char *pfx, const char **ptr); + +/** + * Return non-zero if pfx is a prefix of str independent of case. If + * it is, *ptr is set to the address of the first character in str + * after the prefix. + * + * @param str input string + * @param pfx prefix to test + * @param ptr updated if the prefix is matched inside str + * @return non-zero if the prefix matches, zero otherwise + */ +int av_stristart(const char *str, const char *pfx, const char **ptr); + +/** + * Locate the first case-independent occurrence in the string haystack + * of the string needle. A zero-length string needle is considered to + * match at the start of haystack. + * + * This function is a case-insensitive version of the standard strstr(). + * + * @param haystack string to search in + * @param needle string to search for + * @return pointer to the located match within haystack + * or a null pointer if no match + */ +char *av_stristr(const char *haystack, const char *needle); + +/** + * Locate the first occurrence of the string needle in the string haystack + * where not more than hay_length characters are searched. A zero-length + * string needle is considered to match at the start of haystack. + * + * This function is a length-limited version of the standard strstr(). + * + * @param haystack string to search in + * @param needle string to search for + * @param hay_length length of string to search in + * @return pointer to the located match within haystack + * or a null pointer if no match + */ +char *av_strnstr(const char *haystack, const char *needle, size_t hay_length); + +/** + * Copy the string src to dst, but no more than size - 1 bytes, and + * null-terminate dst. + * + * This function is the same as BSD strlcpy(). + * + * @param dst destination buffer + * @param src source string + * @param size size of destination buffer + * @return the length of src + * + * @warning since the return value is the length of src, src absolutely + * _must_ be a properly 0-terminated string, otherwise this will read beyond + * the end of the buffer and possibly crash. + */ +size_t av_strlcpy(char *dst, const char *src, size_t size); + +/** + * Append the string src to the string dst, but to a total length of + * no more than size - 1 bytes, and null-terminate dst. + * + * This function is similar to BSD strlcat(), but differs when + * size <= strlen(dst). + * + * @param dst destination buffer + * @param src source string + * @param size size of destination buffer + * @return the total length of src and dst + * + * @warning since the return value use the length of src and dst, these + * absolutely _must_ be a properly 0-terminated strings, otherwise this + * will read beyond the end of the buffer and possibly crash. + */ +size_t av_strlcat(char *dst, const char *src, size_t size); + +/** + * Append output to a string, according to a format. Never write out of + * the destination buffer, and always put a terminating 0 within + * the buffer. + * @param dst destination buffer (string to which the output is + * appended) + * @param size total size of the destination buffer + * @param fmt printf-compatible format string, specifying how the + * following parameters are used + * @return the length of the string that would have been generated + * if enough space had been available + */ +size_t av_strlcatf(char *dst, size_t size, const char *fmt, ...) av_printf_format(3, 4); + +/** + * Get the count of continuous non zero chars starting from the beginning. + * + * @param len maximum number of characters to check in the string, that + * is the maximum value which is returned by the function + */ +static inline size_t av_strnlen(const char *s, size_t len) +{ + size_t i; + for (i = 0; i < len && s[i]; i++) + ; + return i; +} + +/** + * Print arguments following specified format into a large enough auto + * allocated buffer. It is similar to GNU asprintf(). + * @param fmt printf-compatible format string, specifying how the + * following parameters are used. + * @return the allocated string + * @note You have to free the string yourself with av_free(). + */ +char *av_asprintf(const char *fmt, ...) av_printf_format(1, 2); + +/** + * Convert a number to an av_malloced string. + */ +char *av_d2str(double d); + +/** + * Unescape the given string until a non escaped terminating char, + * and return the token corresponding to the unescaped string. + * + * The normal \ and ' escaping is supported. Leading and trailing + * whitespaces are removed, unless they are escaped with '\' or are + * enclosed between ''. + * + * @param buf the buffer to parse, buf will be updated to point to the + * terminating char + * @param term a 0-terminated list of terminating chars + * @return the malloced unescaped string, which must be av_freed by + * the user, NULL in case of allocation failure + */ +char *av_get_token(const char **buf, const char *term); + +/** + * Split the string into several tokens which can be accessed by + * successive calls to av_strtok(). + * + * A token is defined as a sequence of characters not belonging to the + * set specified in delim. + * + * On the first call to av_strtok(), s should point to the string to + * parse, and the value of saveptr is ignored. In subsequent calls, s + * should be NULL, and saveptr should be unchanged since the previous + * call. + * + * This function is similar to strtok_r() defined in POSIX.1. + * + * @param s the string to parse, may be NULL + * @param delim 0-terminated list of token delimiters, must be non-NULL + * @param saveptr user-provided pointer which points to stored + * information necessary for av_strtok() to continue scanning the same + * string. saveptr is updated to point to the next character after the + * first delimiter found, or to NULL if the string was terminated + * @return the found token, or NULL when no token is found + */ +char *av_strtok(char *s, const char *delim, char **saveptr); + +/** + * Locale-independent conversion of ASCII isdigit. + */ +static inline av_const int av_isdigit(int c) +{ + return c >= '0' && c <= '9'; +} + +/** + * Locale-independent conversion of ASCII isgraph. + */ +static inline av_const int av_isgraph(int c) +{ + return c > 32 && c < 127; +} + +/** + * Locale-independent conversion of ASCII isspace. + */ +static inline av_const int av_isspace(int c) +{ + return c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || + c == '\v'; +} + +/** + * Locale-independent conversion of ASCII characters to uppercase. + */ +static inline av_const int av_toupper(int c) +{ + if (c >= 'a' && c <= 'z') + c ^= 0x20; + return c; +} + +/** + * Locale-independent conversion of ASCII characters to lowercase. + */ +static inline av_const int av_tolower(int c) +{ + if (c >= 'A' && c <= 'Z') + c ^= 0x20; + return c; +} + +/** + * Locale-independent conversion of ASCII isxdigit. + */ +static inline av_const int av_isxdigit(int c) +{ + c = av_tolower(c); + return av_isdigit(c) || (c >= 'a' && c <= 'f'); +} + +/** + * Locale-independent case-insensitive compare. + * @note This means only ASCII-range characters are case-insensitive + */ +int av_strcasecmp(const char *a, const char *b); + +/** + * Locale-independent case-insensitive compare. + * @note This means only ASCII-range characters are case-insensitive + */ +int av_strncasecmp(const char *a, const char *b, size_t n); + + +/** + * Thread safe basename. + * @param path the path, on DOS both \ and / are considered separators. + * @return pointer to the basename substring. + */ +const char *av_basename(const char *path); + +/** + * Thread safe dirname. + * @param path the path, on DOS both \ and / are considered separators. + * @return the path with the separator replaced by the string terminator or ".". + * @note the function may change the input string. + */ +const char *av_dirname(char *path); + +/** + * Match instances of a name in a comma-separated list of names. + * List entries are checked from the start to the end of the names list, + * the first match ends further processing. If an entry prefixed with '-' + * matches, then 0 is returned. The "ALL" list entry is considered to + * match all names. + * + * @param name Name to look for. + * @param names List of names. + * @return 1 on match, 0 otherwise. + */ +int av_match_name(const char *name, const char *names); + +/** + * Append path component to the existing path. + * Path separator '/' is placed between when needed. + * Resulting string have to be freed with av_free(). + * @param path base path + * @param component component to be appended + * @return new path or NULL on error. + */ +char *av_append_path_component(const char *path, const char *component); + +enum AVEscapeMode { + AV_ESCAPE_MODE_AUTO, ///< Use auto-selected escaping mode. + AV_ESCAPE_MODE_BACKSLASH, ///< Use backslash escaping. + AV_ESCAPE_MODE_QUOTE, ///< Use single-quote escaping. +}; + +/** + * Consider spaces special and escape them even in the middle of the + * string. + * + * This is equivalent to adding the whitespace characters to the special + * characters lists, except it is guaranteed to use the exact same list + * of whitespace characters as the rest of libavutil. + */ +#define AV_ESCAPE_FLAG_WHITESPACE (1 << 0) + +/** + * Escape only specified special characters. + * Without this flag, escape also any characters that may be considered + * special by av_get_token(), such as the single quote. + */ +#define AV_ESCAPE_FLAG_STRICT (1 << 1) + +/** + * Escape string in src, and put the escaped string in an allocated + * string in *dst, which must be freed with av_free(). + * + * @param dst pointer where an allocated string is put + * @param src string to escape, must be non-NULL + * @param special_chars string containing the special characters which + * need to be escaped, can be NULL + * @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros. + * Any unknown value for mode will be considered equivalent to + * AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without + * notice. + * @param flags flags which control how to escape, see AV_ESCAPE_FLAG_ macros + * @return the length of the allocated string, or a negative error code in case of error + * @see av_bprint_escape() + */ +av_warn_unused_result +int av_escape(char **dst, const char *src, const char *special_chars, + enum AVEscapeMode mode, int flags); + +#define AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES 1 ///< accept codepoints over 0x10FFFF +#define AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS 2 ///< accept non-characters - 0xFFFE and 0xFFFF +#define AV_UTF8_FLAG_ACCEPT_SURROGATES 4 ///< accept UTF-16 surrogates codes +#define AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES 8 ///< exclude control codes not accepted by XML + +#define AV_UTF8_FLAG_ACCEPT_ALL \ + AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES|AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS|AV_UTF8_FLAG_ACCEPT_SURROGATES + +/** + * Read and decode a single UTF-8 code point (character) from the + * buffer in *buf, and update *buf to point to the next byte to + * decode. + * + * In case of an invalid byte sequence, the pointer will be updated to + * the next byte after the invalid sequence and the function will + * return an error code. + * + * Depending on the specified flags, the function will also fail in + * case the decoded code point does not belong to a valid range. + * + * @note For speed-relevant code a carefully implemented use of + * GET_UTF8() may be preferred. + * + * @param codep pointer used to return the parsed code in case of success. + * The value in *codep is set even in case the range check fails. + * @param bufp pointer to the address the first byte of the sequence + * to decode, updated by the function to point to the + * byte next after the decoded sequence + * @param buf_end pointer to the end of the buffer, points to the next + * byte past the last in the buffer. This is used to + * avoid buffer overreads (in case of an unfinished + * UTF-8 sequence towards the end of the buffer). + * @param flags a collection of AV_UTF8_FLAG_* flags + * @return >= 0 in case a sequence was successfully read, a negative + * value in case of invalid sequence + */ +av_warn_unused_result +int av_utf8_decode(int32_t *codep, const uint8_t **bufp, const uint8_t *buf_end, + unsigned int flags); + +/** + * Check if a name is in a list. + * @returns 0 if not found, or the 1 based index where it has been found in the + * list. + */ +int av_match_list(const char *name, const char *list, char separator); + +/** + * @} + */ + +#endif /* AVUTIL_AVSTRING_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/avutil.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/avutil.h new file mode 100644 index 0000000..4d63315 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/avutil.h @@ -0,0 +1,365 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AVUTIL_H +#define AVUTIL_AVUTIL_H + +/** + * @file + * @ingroup lavu + * Convenience header that includes @ref lavu "libavutil"'s core. + */ + +/** + * @mainpage + * + * @section ffmpeg_intro Introduction + * + * This document describes the usage of the different libraries + * provided by FFmpeg. + * + * @li @ref libavc "libavcodec" encoding/decoding library + * @li @ref lavfi "libavfilter" graph-based frame editing library + * @li @ref libavf "libavformat" I/O and muxing/demuxing library + * @li @ref lavd "libavdevice" special devices muxing/demuxing library + * @li @ref lavu "libavutil" common utility library + * @li @ref lswr "libswresample" audio resampling, format conversion and mixing + * @li @ref lpp "libpostproc" post processing library + * @li @ref libsws "libswscale" color conversion and scaling library + * + * @section ffmpeg_versioning Versioning and compatibility + * + * Each of the FFmpeg libraries contains a version.h header, which defines a + * major, minor and micro version number with the + * LIBRARYNAME_VERSION_{MAJOR,MINOR,MICRO} macros. The major version + * number is incremented with backward incompatible changes - e.g. removing + * parts of the public API, reordering public struct members, etc. The minor + * version number is incremented for backward compatible API changes or major + * new features - e.g. adding a new public function or a new decoder. The micro + * version number is incremented for smaller changes that a calling program + * might still want to check for - e.g. changing behavior in a previously + * unspecified situation. + * + * FFmpeg guarantees backward API and ABI compatibility for each library as long + * as its major version number is unchanged. This means that no public symbols + * will be removed or renamed. Types and names of the public struct members and + * values of public macros and enums will remain the same (unless they were + * explicitly declared as not part of the public API). Documented behavior will + * not change. + * + * In other words, any correct program that works with a given FFmpeg snapshot + * should work just as well without any changes with any later snapshot with the + * same major versions. This applies to both rebuilding the program against new + * FFmpeg versions or to replacing the dynamic FFmpeg libraries that a program + * links against. + * + * However, new public symbols may be added and new members may be appended to + * public structs whose size is not part of public ABI (most public structs in + * FFmpeg). New macros and enum values may be added. Behavior in undocumented + * situations may change slightly (and be documented). All those are accompanied + * by an entry in doc/APIchanges and incrementing either the minor or micro + * version number. + */ + +/** + * @defgroup lavu libavutil + * Common code shared across all FFmpeg libraries. + * + * @note + * libavutil is designed to be modular. In most cases, in order to use the + * functions provided by one component of libavutil you must explicitly include + * the specific header containing that feature. If you are only using + * media-related components, you could simply include libavutil/avutil.h, which + * brings in most of the "core" components. + * + * @{ + * + * @defgroup lavu_crypto Crypto and Hashing + * + * @{ + * @} + * + * @defgroup lavu_math Mathematics + * @{ + * + * @} + * + * @defgroup lavu_string String Manipulation + * + * @{ + * + * @} + * + * @defgroup lavu_mem Memory Management + * + * @{ + * + * @} + * + * @defgroup lavu_data Data Structures + * @{ + * + * @} + * + * @defgroup lavu_video Video related + * + * @{ + * + * @} + * + * @defgroup lavu_audio Audio related + * + * @{ + * + * @} + * + * @defgroup lavu_error Error Codes + * + * @{ + * + * @} + * + * @defgroup lavu_log Logging Facility + * + * @{ + * + * @} + * + * @defgroup lavu_misc Other + * + * @{ + * + * @defgroup preproc_misc Preprocessor String Macros + * + * @{ + * + * @} + * + * @defgroup version_utils Library Version Macros + * + * @{ + * + * @} + */ + + +/** + * @addtogroup lavu_ver + * @{ + */ + +/** + * Return the LIBAVUTIL_VERSION_INT constant. + */ +unsigned avutil_version(void); + +/** + * Return an informative version string. This usually is the actual release + * version number or a git commit description. This string has no fixed format + * and can change any time. It should never be parsed by code. + */ +const char *av_version_info(void); + +/** + * Return the libavutil build-time configuration. + */ +const char *avutil_configuration(void); + +/** + * Return the libavutil license. + */ +const char *avutil_license(void); + +/** + * @} + */ + +/** + * @addtogroup lavu_media Media Type + * @brief Media Type + */ + +enum AVMediaType { + AVMEDIA_TYPE_UNKNOWN = -1, ///< Usually treated as AVMEDIA_TYPE_DATA + AVMEDIA_TYPE_VIDEO, + AVMEDIA_TYPE_AUDIO, + AVMEDIA_TYPE_DATA, ///< Opaque data information usually continuous + AVMEDIA_TYPE_SUBTITLE, + AVMEDIA_TYPE_ATTACHMENT, ///< Opaque data information usually sparse + AVMEDIA_TYPE_NB +}; + +/** + * Return a string describing the media_type enum, NULL if media_type + * is unknown. + */ +const char *av_get_media_type_string(enum AVMediaType media_type); + +/** + * @defgroup lavu_const Constants + * @{ + * + * @defgroup lavu_enc Encoding specific + * + * @note those definition should move to avcodec + * @{ + */ + +#define FF_LAMBDA_SHIFT 7 +#define FF_LAMBDA_SCALE (1< + +/** + * @defgroup lavu_base64 Base64 + * @ingroup lavu_crypto + * @{ + */ + +/** + * Decode a base64-encoded string. + * + * @param out buffer for decoded data + * @param in null-terminated input string + * @param out_size size in bytes of the out buffer, must be at + * least 3/4 of the length of in, that is AV_BASE64_DECODE_SIZE(strlen(in)) + * @return number of bytes written, or a negative value in case of + * invalid input + */ +int av_base64_decode(uint8_t *out, const char *in, int out_size); + +/** + * Calculate the output size in bytes needed to decode a base64 string + * with length x to a data buffer. + */ +#define AV_BASE64_DECODE_SIZE(x) ((x) * 3LL / 4) + +/** + * Encode data to base64 and null-terminate. + * + * @param out buffer for encoded data + * @param out_size size in bytes of the out buffer (including the + * null terminator), must be at least AV_BASE64_SIZE(in_size) + * @param in input buffer containing the data to encode + * @param in_size size in bytes of the in buffer + * @return out or NULL in case of error + */ +char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size); + +/** + * Calculate the output size needed to base64-encode x bytes to a + * null-terminated string. + */ +#define AV_BASE64_SIZE(x) (((x)+2) / 3 * 4 + 1) + + /** + * @} + */ + +#endif /* AVUTIL_BASE64_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/blowfish.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/blowfish.h new file mode 100644 index 0000000..9e289a4 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/blowfish.h @@ -0,0 +1,82 @@ +/* + * Blowfish algorithm + * Copyright (c) 2012 Samuel Pitoiset + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_BLOWFISH_H +#define AVUTIL_BLOWFISH_H + +#include + +/** + * @defgroup lavu_blowfish Blowfish + * @ingroup lavu_crypto + * @{ + */ + +#define AV_BF_ROUNDS 16 + +typedef struct AVBlowfish { + uint32_t p[AV_BF_ROUNDS + 2]; + uint32_t s[4][256]; +} AVBlowfish; + +/** + * Allocate an AVBlowfish context. + */ +AVBlowfish *av_blowfish_alloc(void); + +/** + * Initialize an AVBlowfish context. + * + * @param ctx an AVBlowfish context + * @param key a key + * @param key_len length of the key + */ +void av_blowfish_init(struct AVBlowfish *ctx, const uint8_t *key, int key_len); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVBlowfish context + * @param xl left four bytes halves of input to be encrypted + * @param xr right four bytes halves of input to be encrypted + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_blowfish_crypt_ecb(struct AVBlowfish *ctx, uint32_t *xl, uint32_t *xr, + int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVBlowfish context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_blowfish_crypt(struct AVBlowfish *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_BLOWFISH_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/bprint.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/bprint.h new file mode 100644 index 0000000..c09b1ac --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/bprint.h @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2012 Nicolas George + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_BPRINT_H +#define AVUTIL_BPRINT_H + +#include + +#include "attributes.h" +#include "avstring.h" + +/** + * Define a structure with extra padding to a fixed size + * This helps ensuring binary compatibility with future versions. + */ + +#define FF_PAD_STRUCTURE(name, size, ...) \ +struct ff_pad_helper_##name { __VA_ARGS__ }; \ +typedef struct name { \ + __VA_ARGS__ \ + char reserved_padding[size - sizeof(struct ff_pad_helper_##name)]; \ +} name; + +/** + * Buffer to print data progressively + * + * The string buffer grows as necessary and is always 0-terminated. + * The content of the string is never accessed, and thus is + * encoding-agnostic and can even hold binary data. + * + * Small buffers are kept in the structure itself, and thus require no + * memory allocation at all (unless the contents of the buffer is needed + * after the structure goes out of scope). This is almost as lightweight as + * declaring a local "char buf[512]". + * + * The length of the string can go beyond the allocated size: the buffer is + * then truncated, but the functions still keep account of the actual total + * length. + * + * In other words, buf->len can be greater than buf->size and records the + * total length of what would have been to the buffer if there had been + * enough memory. + * + * Append operations do not need to be tested for failure: if a memory + * allocation fails, data stop being appended to the buffer, but the length + * is still updated. This situation can be tested with + * av_bprint_is_complete(). + * + * The size_max field determines several possible behaviours: + * + * size_max = -1 (= UINT_MAX) or any large value will let the buffer be + * reallocated as necessary, with an amortized linear cost. + * + * size_max = 0 prevents writing anything to the buffer: only the total + * length is computed. The write operations can then possibly be repeated in + * a buffer with exactly the necessary size + * (using size_init = size_max = len + 1). + * + * size_max = 1 is automatically replaced by the exact size available in the + * structure itself, thus ensuring no dynamic memory allocation. The + * internal buffer is large enough to hold a reasonable paragraph of text, + * such as the current paragraph. + */ + +FF_PAD_STRUCTURE(AVBPrint, 1024, + char *str; /**< string so far */ + unsigned len; /**< length so far */ + unsigned size; /**< allocated memory */ + unsigned size_max; /**< maximum allocated memory */ + char reserved_internal_buffer[1]; +) + +/** + * Convenience macros for special values for av_bprint_init() size_max + * parameter. + */ +#define AV_BPRINT_SIZE_UNLIMITED ((unsigned)-1) +#define AV_BPRINT_SIZE_AUTOMATIC 1 +#define AV_BPRINT_SIZE_COUNT_ONLY 0 + +/** + * Init a print buffer. + * + * @param buf buffer to init + * @param size_init initial size (including the final 0) + * @param size_max maximum size; + * 0 means do not write anything, just count the length; + * 1 is replaced by the maximum value for automatic storage; + * any large value means that the internal buffer will be + * reallocated as needed up to that limit; -1 is converted to + * UINT_MAX, the largest limit possible. + * Check also AV_BPRINT_SIZE_* macros. + */ +void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max); + +/** + * Init a print buffer using a pre-existing buffer. + * + * The buffer will not be reallocated. + * + * @param buf buffer structure to init + * @param buffer byte buffer to use for the string data + * @param size size of buffer + */ +void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size); + +/** + * Append a formatted string to a print buffer. + */ +void av_bprintf(AVBPrint *buf, const char *fmt, ...) av_printf_format(2, 3); + +/** + * Append a formatted string to a print buffer. + */ +void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg); + +/** + * Append char c n times to a print buffer. + */ +void av_bprint_chars(AVBPrint *buf, char c, unsigned n); + +/** + * Append data to a print buffer. + * + * param buf bprint buffer to use + * param data pointer to data + * param size size of data + */ +void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size); + +struct tm; +/** + * Append a formatted date and time to a print buffer. + * + * param buf bprint buffer to use + * param fmt date and time format string, see strftime() + * param tm broken-down time structure to translate + * + * @note due to poor design of the standard strftime function, it may + * produce poor results if the format string expands to a very long text and + * the bprint buffer is near the limit stated by the size_max option. + */ +void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm); + +/** + * Allocate bytes in the buffer for external use. + * + * @param[in] buf buffer structure + * @param[in] size required size + * @param[out] mem pointer to the memory area + * @param[out] actual_size size of the memory area after allocation; + * can be larger or smaller than size + */ +void av_bprint_get_buffer(AVBPrint *buf, unsigned size, + unsigned char **mem, unsigned *actual_size); + +/** + * Reset the string to "" but keep internal allocated data. + */ +void av_bprint_clear(AVBPrint *buf); + +/** + * Test if the print buffer is complete (not truncated). + * + * It may have been truncated due to a memory allocation failure + * or the size_max limit (compare size and size_max if necessary). + */ +static inline int av_bprint_is_complete(const AVBPrint *buf) +{ + return buf->len < buf->size; +} + +/** + * Finalize a print buffer. + * + * The print buffer can no longer be used afterwards, + * but the len and size fields are still valid. + * + * @arg[out] ret_str if not NULL, used to return a permanent copy of the + * buffer contents, or NULL if memory allocation fails; + * if NULL, the buffer is discarded and freed + * @return 0 for success or error code (probably AVERROR(ENOMEM)) + */ +int av_bprint_finalize(AVBPrint *buf, char **ret_str); + +/** + * Escape the content in src and append it to dstbuf. + * + * @param dstbuf already inited destination bprint buffer + * @param src string containing the text to escape + * @param special_chars string containing the special characters which + * need to be escaped, can be NULL + * @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros. + * Any unknown value for mode will be considered equivalent to + * AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without + * notice. + * @param flags flags which control how to escape, see AV_ESCAPE_FLAG_* macros + */ +void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars, + enum AVEscapeMode mode, int flags); + +#endif /* AVUTIL_BPRINT_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/bswap.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/bswap.h new file mode 100644 index 0000000..91cb795 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/bswap.h @@ -0,0 +1,109 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * byte swapping routines + */ + +#ifndef AVUTIL_BSWAP_H +#define AVUTIL_BSWAP_H + +#include +#include "libavutil/avconfig.h" +#include "attributes.h" + +#ifdef HAVE_AV_CONFIG_H + +#include "config.h" + +#if ARCH_AARCH64 +# include "aarch64/bswap.h" +#elif ARCH_ARM +# include "arm/bswap.h" +#elif ARCH_AVR32 +# include "avr32/bswap.h" +#elif ARCH_SH4 +# include "sh4/bswap.h" +#elif ARCH_X86 +# include "x86/bswap.h" +#endif + +#endif /* HAVE_AV_CONFIG_H */ + +#define AV_BSWAP16C(x) (((x) << 8 & 0xff00) | ((x) >> 8 & 0x00ff)) +#define AV_BSWAP32C(x) (AV_BSWAP16C(x) << 16 | AV_BSWAP16C((x) >> 16)) +#define AV_BSWAP64C(x) (AV_BSWAP32C(x) << 32 | AV_BSWAP32C((x) >> 32)) + +#define AV_BSWAPC(s, x) AV_BSWAP##s##C(x) + +#ifndef av_bswap16 +static av_always_inline av_const uint16_t av_bswap16(uint16_t x) +{ + x= (x>>8) | (x<<8); + return x; +} +#endif + +#ifndef av_bswap32 +static av_always_inline av_const uint32_t av_bswap32(uint32_t x) +{ + return AV_BSWAP32C(x); +} +#endif + +#ifndef av_bswap64 +static inline uint64_t av_const av_bswap64(uint64_t x) +{ + return (uint64_t)av_bswap32(x) << 32 | av_bswap32(x >> 32); +} +#endif + +// be2ne ... big-endian to native-endian +// le2ne ... little-endian to native-endian + +#if AV_HAVE_BIGENDIAN +#define av_be2ne16(x) (x) +#define av_be2ne32(x) (x) +#define av_be2ne64(x) (x) +#define av_le2ne16(x) av_bswap16(x) +#define av_le2ne32(x) av_bswap32(x) +#define av_le2ne64(x) av_bswap64(x) +#define AV_BE2NEC(s, x) (x) +#define AV_LE2NEC(s, x) AV_BSWAPC(s, x) +#else +#define av_be2ne16(x) av_bswap16(x) +#define av_be2ne32(x) av_bswap32(x) +#define av_be2ne64(x) av_bswap64(x) +#define av_le2ne16(x) (x) +#define av_le2ne32(x) (x) +#define av_le2ne64(x) (x) +#define AV_BE2NEC(s, x) AV_BSWAPC(s, x) +#define AV_LE2NEC(s, x) (x) +#endif + +#define AV_BE2NE16C(x) AV_BE2NEC(16, x) +#define AV_BE2NE32C(x) AV_BE2NEC(32, x) +#define AV_BE2NE64C(x) AV_BE2NEC(64, x) +#define AV_LE2NE16C(x) AV_LE2NEC(16, x) +#define AV_LE2NE32C(x) AV_LE2NEC(32, x) +#define AV_LE2NE64C(x) AV_LE2NEC(64, x) + +#endif /* AVUTIL_BSWAP_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/buffer.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/buffer.h new file mode 100644 index 0000000..73b6bd0 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/buffer.h @@ -0,0 +1,291 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_buffer + * refcounted data buffer API + */ + +#ifndef AVUTIL_BUFFER_H +#define AVUTIL_BUFFER_H + +#include + +/** + * @defgroup lavu_buffer AVBuffer + * @ingroup lavu_data + * + * @{ + * AVBuffer is an API for reference-counted data buffers. + * + * There are two core objects in this API -- AVBuffer and AVBufferRef. AVBuffer + * represents the data buffer itself; it is opaque and not meant to be accessed + * by the caller directly, but only through AVBufferRef. However, the caller may + * e.g. compare two AVBuffer pointers to check whether two different references + * are describing the same data buffer. AVBufferRef represents a single + * reference to an AVBuffer and it is the object that may be manipulated by the + * caller directly. + * + * There are two functions provided for creating a new AVBuffer with a single + * reference -- av_buffer_alloc() to just allocate a new buffer, and + * av_buffer_create() to wrap an existing array in an AVBuffer. From an existing + * reference, additional references may be created with av_buffer_ref(). + * Use av_buffer_unref() to free a reference (this will automatically free the + * data once all the references are freed). + * + * The convention throughout this API and the rest of FFmpeg is such that the + * buffer is considered writable if there exists only one reference to it (and + * it has not been marked as read-only). The av_buffer_is_writable() function is + * provided to check whether this is true and av_buffer_make_writable() will + * automatically create a new writable buffer when necessary. + * Of course nothing prevents the calling code from violating this convention, + * however that is safe only when all the existing references are under its + * control. + * + * @note Referencing and unreferencing the buffers is thread-safe and thus + * may be done from multiple threads simultaneously without any need for + * additional locking. + * + * @note Two different references to the same buffer can point to different + * parts of the buffer (i.e. their AVBufferRef.data will not be equal). + */ + +/** + * A reference counted buffer type. It is opaque and is meant to be used through + * references (AVBufferRef). + */ +typedef struct AVBuffer AVBuffer; + +/** + * A reference to a data buffer. + * + * The size of this struct is not a part of the public ABI and it is not meant + * to be allocated directly. + */ +typedef struct AVBufferRef { + AVBuffer *buffer; + + /** + * The data buffer. It is considered writable if and only if + * this is the only reference to the buffer, in which case + * av_buffer_is_writable() returns 1. + */ + uint8_t *data; + /** + * Size of data in bytes. + */ + int size; +} AVBufferRef; + +/** + * Allocate an AVBuffer of the given size using av_malloc(). + * + * @return an AVBufferRef of given size or NULL when out of memory + */ +AVBufferRef *av_buffer_alloc(int size); + +/** + * Same as av_buffer_alloc(), except the returned buffer will be initialized + * to zero. + */ +AVBufferRef *av_buffer_allocz(int size); + +/** + * Always treat the buffer as read-only, even when it has only one + * reference. + */ +#define AV_BUFFER_FLAG_READONLY (1 << 0) + +/** + * Create an AVBuffer from an existing array. + * + * If this function is successful, data is owned by the AVBuffer. The caller may + * only access data through the returned AVBufferRef and references derived from + * it. + * If this function fails, data is left untouched. + * @param data data array + * @param size size of data in bytes + * @param free a callback for freeing this buffer's data + * @param opaque parameter to be got for processing or passed to free + * @param flags a combination of AV_BUFFER_FLAG_* + * + * @return an AVBufferRef referring to data on success, NULL on failure. + */ +AVBufferRef *av_buffer_create(uint8_t *data, int size, + void (*free)(void *opaque, uint8_t *data), + void *opaque, int flags); + +/** + * Default free callback, which calls av_free() on the buffer data. + * This function is meant to be passed to av_buffer_create(), not called + * directly. + */ +void av_buffer_default_free(void *opaque, uint8_t *data); + +/** + * Create a new reference to an AVBuffer. + * + * @return a new AVBufferRef referring to the same AVBuffer as buf or NULL on + * failure. + */ +AVBufferRef *av_buffer_ref(AVBufferRef *buf); + +/** + * Free a given reference and automatically free the buffer if there are no more + * references to it. + * + * @param buf the reference to be freed. The pointer is set to NULL on return. + */ +void av_buffer_unref(AVBufferRef **buf); + +/** + * @return 1 if the caller may write to the data referred to by buf (which is + * true if and only if buf is the only reference to the underlying AVBuffer). + * Return 0 otherwise. + * A positive answer is valid until av_buffer_ref() is called on buf. + */ +int av_buffer_is_writable(const AVBufferRef *buf); + +/** + * @return the opaque parameter set by av_buffer_create. + */ +void *av_buffer_get_opaque(const AVBufferRef *buf); + +int av_buffer_get_ref_count(const AVBufferRef *buf); + +/** + * Create a writable reference from a given buffer reference, avoiding data copy + * if possible. + * + * @param buf buffer reference to make writable. On success, buf is either left + * untouched, or it is unreferenced and a new writable AVBufferRef is + * written in its place. On failure, buf is left untouched. + * @return 0 on success, a negative AVERROR on failure. + */ +int av_buffer_make_writable(AVBufferRef **buf); + +/** + * Reallocate a given buffer. + * + * @param buf a buffer reference to reallocate. On success, buf will be + * unreferenced and a new reference with the required size will be + * written in its place. On failure buf will be left untouched. *buf + * may be NULL, then a new buffer is allocated. + * @param size required new buffer size. + * @return 0 on success, a negative AVERROR on failure. + * + * @note the buffer is actually reallocated with av_realloc() only if it was + * initially allocated through av_buffer_realloc(NULL) and there is only one + * reference to it (i.e. the one passed to this function). In all other cases + * a new buffer is allocated and the data is copied. + */ +int av_buffer_realloc(AVBufferRef **buf, int size); + +/** + * @} + */ + +/** + * @defgroup lavu_bufferpool AVBufferPool + * @ingroup lavu_data + * + * @{ + * AVBufferPool is an API for a lock-free thread-safe pool of AVBuffers. + * + * Frequently allocating and freeing large buffers may be slow. AVBufferPool is + * meant to solve this in cases when the caller needs a set of buffers of the + * same size (the most obvious use case being buffers for raw video or audio + * frames). + * + * At the beginning, the user must call av_buffer_pool_init() to create the + * buffer pool. Then whenever a buffer is needed, call av_buffer_pool_get() to + * get a reference to a new buffer, similar to av_buffer_alloc(). This new + * reference works in all aspects the same way as the one created by + * av_buffer_alloc(). However, when the last reference to this buffer is + * unreferenced, it is returned to the pool instead of being freed and will be + * reused for subsequent av_buffer_pool_get() calls. + * + * When the caller is done with the pool and no longer needs to allocate any new + * buffers, av_buffer_pool_uninit() must be called to mark the pool as freeable. + * Once all the buffers are released, it will automatically be freed. + * + * Allocating and releasing buffers with this API is thread-safe as long as + * either the default alloc callback is used, or the user-supplied one is + * thread-safe. + */ + +/** + * The buffer pool. This structure is opaque and not meant to be accessed + * directly. It is allocated with av_buffer_pool_init() and freed with + * av_buffer_pool_uninit(). + */ +typedef struct AVBufferPool AVBufferPool; + +/** + * Allocate and initialize a buffer pool. + * + * @param size size of each buffer in this pool + * @param alloc a function that will be used to allocate new buffers when the + * pool is empty. May be NULL, then the default allocator will be used + * (av_buffer_alloc()). + * @return newly created buffer pool on success, NULL on error. + */ +AVBufferPool *av_buffer_pool_init(int size, AVBufferRef* (*alloc)(int size)); + +/** + * Allocate and initialize a buffer pool with a more complex allocator. + * + * @param size size of each buffer in this pool + * @param opaque arbitrary user data used by the allocator + * @param alloc a function that will be used to allocate new buffers when the + * pool is empty. + * @param pool_free a function that will be called immediately before the pool + * is freed. I.e. after av_buffer_pool_uninit() is called + * by the caller and all the frames are returned to the pool + * and freed. It is intended to uninitialize the user opaque + * data. + * @return newly created buffer pool on success, NULL on error. + */ +AVBufferPool *av_buffer_pool_init2(int size, void *opaque, + AVBufferRef* (*alloc)(void *opaque, int size), + void (*pool_free)(void *opaque)); + +/** + * Mark the pool as being available for freeing. It will actually be freed only + * once all the allocated buffers associated with the pool are released. Thus it + * is safe to call this function while some of the allocated buffers are still + * in use. + * + * @param pool pointer to the pool to be freed. It will be set to NULL. + */ +void av_buffer_pool_uninit(AVBufferPool **pool); + +/** + * Allocate a new AVBuffer, reusing an old buffer from the pool when available. + * This function may be called simultaneously from multiple threads. + * + * @return a reference to the new buffer on success, NULL on error. + */ +AVBufferRef *av_buffer_pool_get(AVBufferPool *pool); + +/** + * @} + */ + +#endif /* AVUTIL_BUFFER_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/camellia.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/camellia.h new file mode 100644 index 0000000..e674c9b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/camellia.h @@ -0,0 +1,70 @@ +/* + * An implementation of the CAMELLIA algorithm as mentioned in RFC3713 + * Copyright (c) 2014 Supraja Meedinti + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CAMELLIA_H +#define AVUTIL_CAMELLIA_H + +#include + + +/** + * @file + * @brief Public header for libavutil CAMELLIA algorithm + * @defgroup lavu_camellia CAMELLIA + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_camellia_size; + +struct AVCAMELLIA; + +/** + * Allocate an AVCAMELLIA context + * To free the struct: av_free(ptr) + */ +struct AVCAMELLIA *av_camellia_alloc(void); + +/** + * Initialize an AVCAMELLIA context. + * + * @param ctx an AVCAMELLIA context + * @param key a key of 16, 24, 32 bytes used for encryption/decryption + * @param key_bits number of keybits: possible are 128, 192, 256 + */ +int av_camellia_init(struct AVCAMELLIA *ctx, const uint8_t *key, int key_bits); + +/** + * Encrypt or decrypt a buffer using a previously initialized context + * + * @param ctx an AVCAMELLIA context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 16 byte blocks + * @paran iv initialization vector for CBC mode, NULL for ECB mode + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_camellia_crypt(struct AVCAMELLIA *ctx, uint8_t *dst, const uint8_t *src, int count, uint8_t* iv, int decrypt); + +/** + * @} + */ +#endif /* AVUTIL_CAMELLIA_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/cast5.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/cast5.h new file mode 100644 index 0000000..ad5b347 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/cast5.h @@ -0,0 +1,80 @@ +/* + * An implementation of the CAST128 algorithm as mentioned in RFC2144 + * Copyright (c) 2014 Supraja Meedinti + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CAST5_H +#define AVUTIL_CAST5_H + +#include + + +/** + * @file + * @brief Public header for libavutil CAST5 algorithm + * @defgroup lavu_cast5 CAST5 + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_cast5_size; + +struct AVCAST5; + +/** + * Allocate an AVCAST5 context + * To free the struct: av_free(ptr) + */ +struct AVCAST5 *av_cast5_alloc(void); +/** + * Initialize an AVCAST5 context. + * + * @param ctx an AVCAST5 context + * @param key a key of 5,6,...16 bytes used for encryption/decryption + * @param key_bits number of keybits: possible are 40,48,...,128 + * @return 0 on success, less than 0 on failure + */ +int av_cast5_init(struct AVCAST5 *ctx, const uint8_t *key, int key_bits); + +/** + * Encrypt or decrypt a buffer using a previously initialized context, ECB mode only + * + * @param ctx an AVCAST5 context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_cast5_crypt(struct AVCAST5 *ctx, uint8_t *dst, const uint8_t *src, int count, int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context + * + * @param ctx an AVCAST5 context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, NULL for ECB mode + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_cast5_crypt2(struct AVCAST5 *ctx, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); +/** + * @} + */ +#endif /* AVUTIL_CAST5_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/channel_layout.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/channel_layout.h new file mode 100644 index 0000000..50bb8f0 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/channel_layout.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2006 Michael Niedermayer + * Copyright (c) 2008 Peter Ross + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CHANNEL_LAYOUT_H +#define AVUTIL_CHANNEL_LAYOUT_H + +#include + +/** + * @file + * audio channel layout utility functions + */ + +/** + * @addtogroup lavu_audio + * @{ + */ + +/** + * @defgroup channel_masks Audio channel masks + * + * A channel layout is a 64-bits integer with a bit set for every channel. + * The number of bits set must be equal to the number of channels. + * The value 0 means that the channel layout is not known. + * @note this data structure is not powerful enough to handle channels + * combinations that have the same channel multiple times, such as + * dual-mono. + * + * @{ + */ +#define AV_CH_FRONT_LEFT 0x00000001 +#define AV_CH_FRONT_RIGHT 0x00000002 +#define AV_CH_FRONT_CENTER 0x00000004 +#define AV_CH_LOW_FREQUENCY 0x00000008 +#define AV_CH_BACK_LEFT 0x00000010 +#define AV_CH_BACK_RIGHT 0x00000020 +#define AV_CH_FRONT_LEFT_OF_CENTER 0x00000040 +#define AV_CH_FRONT_RIGHT_OF_CENTER 0x00000080 +#define AV_CH_BACK_CENTER 0x00000100 +#define AV_CH_SIDE_LEFT 0x00000200 +#define AV_CH_SIDE_RIGHT 0x00000400 +#define AV_CH_TOP_CENTER 0x00000800 +#define AV_CH_TOP_FRONT_LEFT 0x00001000 +#define AV_CH_TOP_FRONT_CENTER 0x00002000 +#define AV_CH_TOP_FRONT_RIGHT 0x00004000 +#define AV_CH_TOP_BACK_LEFT 0x00008000 +#define AV_CH_TOP_BACK_CENTER 0x00010000 +#define AV_CH_TOP_BACK_RIGHT 0x00020000 +#define AV_CH_STEREO_LEFT 0x20000000 ///< Stereo downmix. +#define AV_CH_STEREO_RIGHT 0x40000000 ///< See AV_CH_STEREO_LEFT. +#define AV_CH_WIDE_LEFT 0x0000000080000000ULL +#define AV_CH_WIDE_RIGHT 0x0000000100000000ULL +#define AV_CH_SURROUND_DIRECT_LEFT 0x0000000200000000ULL +#define AV_CH_SURROUND_DIRECT_RIGHT 0x0000000400000000ULL +#define AV_CH_LOW_FREQUENCY_2 0x0000000800000000ULL + +/** Channel mask value used for AVCodecContext.request_channel_layout + to indicate that the user requests the channel order of the decoder output + to be the native codec channel order. */ +#define AV_CH_LAYOUT_NATIVE 0x8000000000000000ULL + +/** + * @} + * @defgroup channel_mask_c Audio channel layouts + * @{ + * */ +#define AV_CH_LAYOUT_MONO (AV_CH_FRONT_CENTER) +#define AV_CH_LAYOUT_STEREO (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT) +#define AV_CH_LAYOUT_2POINT1 (AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_2_1 (AV_CH_LAYOUT_STEREO|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_SURROUND (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER) +#define AV_CH_LAYOUT_3POINT1 (AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_4POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_4POINT1 (AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_2_2 (AV_CH_LAYOUT_STEREO|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT) +#define AV_CH_LAYOUT_QUAD (AV_CH_LAYOUT_STEREO|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_5POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT) +#define AV_CH_LAYOUT_5POINT1 (AV_CH_LAYOUT_5POINT0|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_5POINT0_BACK (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_5POINT1_BACK (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_6POINT0 (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT0_FRONT (AV_CH_LAYOUT_2_2|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_HEXAGONAL (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT1_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT1_FRONT (AV_CH_LAYOUT_6POINT0_FRONT|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_7POINT0 (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_7POINT0_FRONT (AV_CH_LAYOUT_5POINT0|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_7POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_7POINT1_WIDE (AV_CH_LAYOUT_5POINT1|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_7POINT1_WIDE_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_OCTAGONAL (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_CENTER|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_HEXADECAGONAL (AV_CH_LAYOUT_OCTAGONAL|AV_CH_WIDE_LEFT|AV_CH_WIDE_RIGHT|AV_CH_TOP_BACK_LEFT|AV_CH_TOP_BACK_RIGHT|AV_CH_TOP_BACK_CENTER|AV_CH_TOP_FRONT_CENTER|AV_CH_TOP_FRONT_LEFT|AV_CH_TOP_FRONT_RIGHT) +#define AV_CH_LAYOUT_STEREO_DOWNMIX (AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT) + +enum AVMatrixEncoding { + AV_MATRIX_ENCODING_NONE, + AV_MATRIX_ENCODING_DOLBY, + AV_MATRIX_ENCODING_DPLII, + AV_MATRIX_ENCODING_DPLIIX, + AV_MATRIX_ENCODING_DPLIIZ, + AV_MATRIX_ENCODING_DOLBYEX, + AV_MATRIX_ENCODING_DOLBYHEADPHONE, + AV_MATRIX_ENCODING_NB +}; + +/** + * Return a channel layout id that matches name, or 0 if no match is found. + * + * name can be one or several of the following notations, + * separated by '+' or '|': + * - the name of an usual channel layout (mono, stereo, 4.0, quad, 5.0, + * 5.0(side), 5.1, 5.1(side), 7.1, 7.1(wide), downmix); + * - the name of a single channel (FL, FR, FC, LFE, BL, BR, FLC, FRC, BC, + * SL, SR, TC, TFL, TFC, TFR, TBL, TBC, TBR, DL, DR); + * - a number of channels, in decimal, followed by 'c', yielding + * the default channel layout for that number of channels (@see + * av_get_default_channel_layout); + * - a channel layout mask, in hexadecimal starting with "0x" (see the + * AV_CH_* macros). + * + * Example: "stereo+FC" = "2c+FC" = "2c+1c" = "0x7" + */ +uint64_t av_get_channel_layout(const char *name); + +/** + * Return a channel layout and the number of channels based on the specified name. + * + * This function is similar to (@see av_get_channel_layout), but can also parse + * unknown channel layout specifications. + * + * @param[in] name channel layout specification string + * @param[out] channel_layout parsed channel layout (0 if unknown) + * @param[out] nb_channels number of channels + * + * @return 0 on success, AVERROR(EINVAL) if the parsing fails. + */ +int av_get_extended_channel_layout(const char *name, uint64_t* channel_layout, int* nb_channels); + +/** + * Return a description of a channel layout. + * If nb_channels is <= 0, it is guessed from the channel_layout. + * + * @param buf put here the string containing the channel layout + * @param buf_size size in bytes of the buffer + */ +void av_get_channel_layout_string(char *buf, int buf_size, int nb_channels, uint64_t channel_layout); + +struct AVBPrint; +/** + * Append a description of a channel layout to a bprint buffer. + */ +void av_bprint_channel_layout(struct AVBPrint *bp, int nb_channels, uint64_t channel_layout); + +/** + * Return the number of channels in the channel layout. + */ +int av_get_channel_layout_nb_channels(uint64_t channel_layout); + +/** + * Return default channel layout for a given number of channels. + */ +int64_t av_get_default_channel_layout(int nb_channels); + +/** + * Get the index of a channel in channel_layout. + * + * @param channel a channel layout describing exactly one channel which must be + * present in channel_layout. + * + * @return index of channel in channel_layout on success, a negative AVERROR + * on error. + */ +int av_get_channel_layout_channel_index(uint64_t channel_layout, + uint64_t channel); + +/** + * Get the channel with the given index in channel_layout. + */ +uint64_t av_channel_layout_extract_channel(uint64_t channel_layout, int index); + +/** + * Get the name of a given channel. + * + * @return channel name on success, NULL on error. + */ +const char *av_get_channel_name(uint64_t channel); + +/** + * Get the description of a given channel. + * + * @param channel a channel layout with a single channel + * @return channel description on success, NULL on error + */ +const char *av_get_channel_description(uint64_t channel); + +/** + * Get the value and name of a standard channel layout. + * + * @param[in] index index in an internal list, starting at 0 + * @param[out] layout channel layout mask + * @param[out] name name of the layout + * @return 0 if the layout exists, + * <0 if index is beyond the limits + */ +int av_get_standard_channel_layout(unsigned index, uint64_t *layout, + const char **name); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_CHANNEL_LAYOUT_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/common.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/common.h new file mode 100644 index 0000000..58ead80 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/common.h @@ -0,0 +1,530 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * common internal and external API header + */ + +#ifndef AVUTIL_COMMON_H +#define AVUTIL_COMMON_H + +#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) && !defined(UINT64_C) +#error missing -D__STDC_CONSTANT_MACROS / #define __STDC_CONSTANT_MACROS +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "attributes.h" +#include "macros.h" +#include "version.h" +#include "libavutil/avconfig.h" + +#if AV_HAVE_BIGENDIAN +# define AV_NE(be, le) (be) +#else +# define AV_NE(be, le) (le) +#endif + +//rounded division & shift +#define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b)) +/* assume b>0 */ +#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) +/* Fast a/(1<=0 and b>=0 */ +#define AV_CEIL_RSHIFT(a,b) (!av_builtin_constant_p(b) ? -((-(a)) >> (b)) \ + : ((a) + (1<<(b)) - 1) >> (b)) +/* Backwards compat. */ +#define FF_CEIL_RSHIFT AV_CEIL_RSHIFT + +#define FFUDIV(a,b) (((a)>0 ?(a):(a)-(b)+1) / (b)) +#define FFUMOD(a,b) ((a)-(b)*FFUDIV(a,b)) + +/** + * Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they + * are not representable as absolute values of their type. This is the same + * as with *abs() + * @see FFNABS() + */ +#define FFABS(a) ((a) >= 0 ? (a) : (-(a))) +#define FFSIGN(a) ((a) > 0 ? 1 : -1) + +/** + * Negative Absolute value. + * this works for all integers of all types. + * As with many macros, this evaluates its argument twice, it thus must not have + * a sideeffect, that is FFNABS(x++) has undefined behavior. + */ +#define FFNABS(a) ((a) <= 0 ? (a) : (-(a))) + +/** + * Comparator. + * For two numerical expressions x and y, gives 1 if x > y, -1 if x < y, and 0 + * if x == y. This is useful for instance in a qsort comparator callback. + * Furthermore, compilers are able to optimize this to branchless code, and + * there is no risk of overflow with signed types. + * As with many macros, this evaluates its argument multiple times, it thus + * must not have a side-effect. + */ +#define FFDIFFSIGN(x,y) (((x)>(y)) - ((x)<(y))) + +#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) +#define FFMAX3(a,b,c) FFMAX(FFMAX(a,b),c) +#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) +#define FFMIN3(a,b,c) FFMIN(FFMIN(a,b),c) + +#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0) +#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0])) + +/* misc math functions */ + +#ifdef HAVE_AV_CONFIG_H +# include "config.h" +# include "intmath.h" +#endif + +/* Pull in unguarded fallback defines at the end of this file. */ +#include "common.h" + +#ifndef av_log2 +av_const int av_log2(unsigned v); +#endif + +#ifndef av_log2_16bit +av_const int av_log2_16bit(unsigned v); +#endif + +/** + * Clip a signed integer value into the amin-amax range. + * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range + * @return clipped value + */ +static av_always_inline av_const int av_clip_c(int a, int amin, int amax) +{ +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +/** + * Clip a signed 64bit integer value into the amin-amax range. + * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range + * @return clipped value + */ +static av_always_inline av_const int64_t av_clip64_c(int64_t a, int64_t amin, int64_t amax) +{ +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +/** + * Clip a signed integer value into the 0-255 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const uint8_t av_clip_uint8_c(int a) +{ + if (a&(~0xFF)) return (~a)>>31; + else return a; +} + +/** + * Clip a signed integer value into the -128,127 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const int8_t av_clip_int8_c(int a) +{ + if ((a+0x80U) & ~0xFF) return (a>>31) ^ 0x7F; + else return a; +} + +/** + * Clip a signed integer value into the 0-65535 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const uint16_t av_clip_uint16_c(int a) +{ + if (a&(~0xFFFF)) return (~a)>>31; + else return a; +} + +/** + * Clip a signed integer value into the -32768,32767 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const int16_t av_clip_int16_c(int a) +{ + if ((a+0x8000U) & ~0xFFFF) return (a>>31) ^ 0x7FFF; + else return a; +} + +/** + * Clip a signed 64-bit integer value into the -2147483648,2147483647 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const int32_t av_clipl_int32_c(int64_t a) +{ + if ((a+0x80000000u) & ~UINT64_C(0xFFFFFFFF)) return (int32_t)((a>>63) ^ 0x7FFFFFFF); + else return (int32_t)a; +} + +/** + * Clip a signed integer into the -(2^p),(2^p-1) range. + * @param a value to clip + * @param p bit position to clip at + * @return clipped value + */ +static av_always_inline av_const int av_clip_intp2_c(int a, int p) +{ + if (((unsigned)a + (1 << p)) & ~((2 << p) - 1)) + return (a >> 31) ^ ((1 << p) - 1); + else + return a; +} + +/** + * Clip a signed integer to an unsigned power of two range. + * @param a value to clip + * @param p bit position to clip at + * @return clipped value + */ +static av_always_inline av_const unsigned av_clip_uintp2_c(int a, int p) +{ + if (a & ~((1<> 31 & ((1<= 2 + if (amin > amax) abort(); +#endif + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +/** + * Clip a double value into the amin-amax range. + * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range + * @return clipped value + */ +static av_always_inline av_const double av_clipd_c(double a, double amin, double amax) +{ +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +/** Compute ceil(log2(x)). + * @param x value used to compute ceil(log2(x)) + * @return computed ceiling of log2(x) + */ +static av_always_inline av_const int av_ceil_log2_c(int x) +{ + return av_log2((x - 1) << 1); +} + +/** + * Count number of bits set to one in x + * @param x value to count bits of + * @return the number of bits set to one in x + */ +static av_always_inline av_const int av_popcount_c(uint32_t x) +{ + x -= (x >> 1) & 0x55555555; + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x + (x >> 4)) & 0x0F0F0F0F; + x += x >> 8; + return (x + (x >> 16)) & 0x3F; +} + +/** + * Count number of bits set to one in x + * @param x value to count bits of + * @return the number of bits set to one in x + */ +static av_always_inline av_const int av_popcount64_c(uint64_t x) +{ + return av_popcount((uint32_t)x) + av_popcount((uint32_t)(x >> 32)); +} + +static av_always_inline av_const int av_parity_c(uint32_t v) +{ + return av_popcount(v) & 1; +} + +#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24)) +#define MKBETAG(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((unsigned)(a) << 24)) + +/** + * Convert a UTF-8 character (up to 4 bytes) to its 32-bit UCS-4 encoded form. + * + * @param val Output value, must be an lvalue of type uint32_t. + * @param GET_BYTE Expression reading one byte from the input. + * Evaluated up to 7 times (4 for the currently + * assigned Unicode range). With a memory buffer + * input, this could be *ptr++. + * @param ERROR Expression to be evaluated on invalid input, + * typically a goto statement. + * + * @warning ERROR should not contain a loop control statement which + * could interact with the internal while loop, and should force an + * exit from the macro code (e.g. through a goto or a return) in order + * to prevent undefined results. + */ +#define GET_UTF8(val, GET_BYTE, ERROR)\ + val= (GET_BYTE);\ + {\ + uint32_t top = (val & 128) >> 1;\ + if ((val & 0xc0) == 0x80 || val >= 0xFE)\ + ERROR\ + while (val & top) {\ + int tmp= (GET_BYTE) - 128;\ + if(tmp>>6)\ + ERROR\ + val= (val<<6) + tmp;\ + top <<= 5;\ + }\ + val &= (top << 1) - 1;\ + } + +/** + * Convert a UTF-16 character (2 or 4 bytes) to its 32-bit UCS-4 encoded form. + * + * @param val Output value, must be an lvalue of type uint32_t. + * @param GET_16BIT Expression returning two bytes of UTF-16 data converted + * to native byte order. Evaluated one or two times. + * @param ERROR Expression to be evaluated on invalid input, + * typically a goto statement. + */ +#define GET_UTF16(val, GET_16BIT, ERROR)\ + val = GET_16BIT;\ + {\ + unsigned int hi = val - 0xD800;\ + if (hi < 0x800) {\ + val = GET_16BIT - 0xDC00;\ + if (val > 0x3FFU || hi > 0x3FFU)\ + ERROR\ + val += (hi<<10) + 0x10000;\ + }\ + }\ + +/** + * @def PUT_UTF8(val, tmp, PUT_BYTE) + * Convert a 32-bit Unicode character to its UTF-8 encoded form (up to 4 bytes long). + * @param val is an input-only argument and should be of type uint32_t. It holds + * a UCS-4 encoded Unicode character that is to be converted to UTF-8. If + * val is given as a function it is executed only once. + * @param tmp is a temporary variable and should be of type uint8_t. It + * represents an intermediate value during conversion that is to be + * output by PUT_BYTE. + * @param PUT_BYTE writes the converted UTF-8 bytes to any proper destination. + * It could be a function or a statement, and uses tmp as the input byte. + * For example, PUT_BYTE could be "*output++ = tmp;" PUT_BYTE will be + * executed up to 4 times for values in the valid UTF-8 range and up to + * 7 times in the general case, depending on the length of the converted + * Unicode character. + */ +#define PUT_UTF8(val, tmp, PUT_BYTE)\ + {\ + int bytes, shift;\ + uint32_t in = val;\ + if (in < 0x80) {\ + tmp = in;\ + PUT_BYTE\ + } else {\ + bytes = (av_log2(in) + 4) / 5;\ + shift = (bytes - 1) * 6;\ + tmp = (256 - (256 >> bytes)) | (in >> shift);\ + PUT_BYTE\ + while (shift >= 6) {\ + shift -= 6;\ + tmp = 0x80 | ((in >> shift) & 0x3f);\ + PUT_BYTE\ + }\ + }\ + } + +/** + * @def PUT_UTF16(val, tmp, PUT_16BIT) + * Convert a 32-bit Unicode character to its UTF-16 encoded form (2 or 4 bytes). + * @param val is an input-only argument and should be of type uint32_t. It holds + * a UCS-4 encoded Unicode character that is to be converted to UTF-16. If + * val is given as a function it is executed only once. + * @param tmp is a temporary variable and should be of type uint16_t. It + * represents an intermediate value during conversion that is to be + * output by PUT_16BIT. + * @param PUT_16BIT writes the converted UTF-16 data to any proper destination + * in desired endianness. It could be a function or a statement, and uses tmp + * as the input byte. For example, PUT_BYTE could be "*output++ = tmp;" + * PUT_BYTE will be executed 1 or 2 times depending on input character. + */ +#define PUT_UTF16(val, tmp, PUT_16BIT)\ + {\ + uint32_t in = val;\ + if (in < 0x10000) {\ + tmp = in;\ + PUT_16BIT\ + } else {\ + tmp = 0xD800 | ((in - 0x10000) >> 10);\ + PUT_16BIT\ + tmp = 0xDC00 | ((in - 0x10000) & 0x3FF);\ + PUT_16BIT\ + }\ + }\ + + + +#include "mem.h" + +#ifdef HAVE_AV_CONFIG_H +# include "internal.h" +#endif /* HAVE_AV_CONFIG_H */ + +#endif /* AVUTIL_COMMON_H */ + +/* + * The following definitions are outside the multiple inclusion guard + * to ensure they are immediately available in intmath.h. + */ + +#ifndef av_ceil_log2 +# define av_ceil_log2 av_ceil_log2_c +#endif +#ifndef av_clip +# define av_clip av_clip_c +#endif +#ifndef av_clip64 +# define av_clip64 av_clip64_c +#endif +#ifndef av_clip_uint8 +# define av_clip_uint8 av_clip_uint8_c +#endif +#ifndef av_clip_int8 +# define av_clip_int8 av_clip_int8_c +#endif +#ifndef av_clip_uint16 +# define av_clip_uint16 av_clip_uint16_c +#endif +#ifndef av_clip_int16 +# define av_clip_int16 av_clip_int16_c +#endif +#ifndef av_clipl_int32 +# define av_clipl_int32 av_clipl_int32_c +#endif +#ifndef av_clip_intp2 +# define av_clip_intp2 av_clip_intp2_c +#endif +#ifndef av_clip_uintp2 +# define av_clip_uintp2 av_clip_uintp2_c +#endif +#ifndef av_mod_uintp2 +# define av_mod_uintp2 av_mod_uintp2_c +#endif +#ifndef av_sat_add32 +# define av_sat_add32 av_sat_add32_c +#endif +#ifndef av_sat_dadd32 +# define av_sat_dadd32 av_sat_dadd32_c +#endif +#ifndef av_clipf +# define av_clipf av_clipf_c +#endif +#ifndef av_clipd +# define av_clipd av_clipd_c +#endif +#ifndef av_popcount +# define av_popcount av_popcount_c +#endif +#ifndef av_popcount64 +# define av_popcount64 av_popcount64_c +#endif +#ifndef av_parity +# define av_parity av_parity_c +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/cpu.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/cpu.h new file mode 100644 index 0000000..de05593 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/cpu.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CPU_H +#define AVUTIL_CPU_H + +#include "attributes.h" + +#define AV_CPU_FLAG_FORCE 0x80000000 /* force usage of selected flags (OR) */ + + /* lower 16 bits - CPU features */ +#define AV_CPU_FLAG_MMX 0x0001 ///< standard MMX +#define AV_CPU_FLAG_MMXEXT 0x0002 ///< SSE integer functions or AMD MMX ext +#define AV_CPU_FLAG_MMX2 0x0002 ///< SSE integer functions or AMD MMX ext +#define AV_CPU_FLAG_3DNOW 0x0004 ///< AMD 3DNOW +#define AV_CPU_FLAG_SSE 0x0008 ///< SSE functions +#define AV_CPU_FLAG_SSE2 0x0010 ///< PIV SSE2 functions +#define AV_CPU_FLAG_SSE2SLOW 0x40000000 ///< SSE2 supported, but usually not faster + ///< than regular MMX/SSE (e.g. Core1) +#define AV_CPU_FLAG_3DNOWEXT 0x0020 ///< AMD 3DNowExt +#define AV_CPU_FLAG_SSE3 0x0040 ///< Prescott SSE3 functions +#define AV_CPU_FLAG_SSE3SLOW 0x20000000 ///< SSE3 supported, but usually not faster + ///< than regular MMX/SSE (e.g. Core1) +#define AV_CPU_FLAG_SSSE3 0x0080 ///< Conroe SSSE3 functions +#define AV_CPU_FLAG_SSSE3SLOW 0x4000000 ///< SSSE3 supported, but usually not faster +#define AV_CPU_FLAG_ATOM 0x10000000 ///< Atom processor, some SSSE3 instructions are slower +#define AV_CPU_FLAG_SSE4 0x0100 ///< Penryn SSE4.1 functions +#define AV_CPU_FLAG_SSE42 0x0200 ///< Nehalem SSE4.2 functions +#define AV_CPU_FLAG_AESNI 0x80000 ///< Advanced Encryption Standard functions +#define AV_CPU_FLAG_AVX 0x4000 ///< AVX functions: requires OS support even if YMM registers aren't used +#define AV_CPU_FLAG_AVXSLOW 0x8000000 ///< AVX supported, but slow when using YMM registers (e.g. Bulldozer) +#define AV_CPU_FLAG_XOP 0x0400 ///< Bulldozer XOP functions +#define AV_CPU_FLAG_FMA4 0x0800 ///< Bulldozer FMA4 functions +#define AV_CPU_FLAG_CMOV 0x1000 ///< supports cmov instruction +#define AV_CPU_FLAG_AVX2 0x8000 ///< AVX2 functions: requires OS support even if YMM registers aren't used +#define AV_CPU_FLAG_FMA3 0x10000 ///< Haswell FMA3 functions +#define AV_CPU_FLAG_BMI1 0x20000 ///< Bit Manipulation Instruction Set 1 +#define AV_CPU_FLAG_BMI2 0x40000 ///< Bit Manipulation Instruction Set 2 + +#define AV_CPU_FLAG_ALTIVEC 0x0001 ///< standard +#define AV_CPU_FLAG_VSX 0x0002 ///< ISA 2.06 +#define AV_CPU_FLAG_POWER8 0x0004 ///< ISA 2.07 + +#define AV_CPU_FLAG_ARMV5TE (1 << 0) +#define AV_CPU_FLAG_ARMV6 (1 << 1) +#define AV_CPU_FLAG_ARMV6T2 (1 << 2) +#define AV_CPU_FLAG_VFP (1 << 3) +#define AV_CPU_FLAG_VFPV3 (1 << 4) +#define AV_CPU_FLAG_NEON (1 << 5) +#define AV_CPU_FLAG_ARMV8 (1 << 6) +#define AV_CPU_FLAG_VFP_VM (1 << 7) ///< VFPv2 vector mode, deprecated in ARMv7-A and unavailable in various CPUs implementations +#define AV_CPU_FLAG_SETEND (1 <<16) + +/** + * Return the flags which specify extensions supported by the CPU. + * The returned value is affected by av_force_cpu_flags() if that was used + * before. So av_get_cpu_flags() can easily be used in an application to + * detect the enabled cpu flags. + */ +int av_get_cpu_flags(void); + +/** + * Disables cpu detection and forces the specified flags. + * -1 is a special case that disables forcing of specific flags. + */ +void av_force_cpu_flags(int flags); + +/** + * Set a mask on flags returned by av_get_cpu_flags(). + * This function is mainly useful for testing. + * Please use av_force_cpu_flags() and av_get_cpu_flags() instead which are more flexible + */ +attribute_deprecated void av_set_cpu_flags_mask(int mask); + +/** + * Parse CPU flags from a string. + * + * The returned flags contain the specified flags as well as related unspecified flags. + * + * This function exists only for compatibility with libav. + * Please use av_parse_cpu_caps() when possible. + * @return a combination of AV_CPU_* flags, negative on error. + */ +attribute_deprecated +int av_parse_cpu_flags(const char *s); + +/** + * Parse CPU caps from a string and update the given AV_CPU_* flags based on that. + * + * @return negative on error. + */ +int av_parse_cpu_caps(unsigned *flags, const char *s); + +/** + * @return the number of logical CPU cores present. + */ +int av_cpu_count(void); + +#endif /* AVUTIL_CPU_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/crc.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/crc.h new file mode 100644 index 0000000..2a1b0d7 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/crc.h @@ -0,0 +1,103 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_crc32 + * Public header for CRC hash function implementation. + */ + +#ifndef AVUTIL_CRC_H +#define AVUTIL_CRC_H + +#include +#include +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_crc32 CRC + * @ingroup lavu_hash + * CRC (Cyclic Redundancy Check) hash function implementation. + * + * This module supports numerous CRC polynomials, in addition to the most + * widely used CRC-32-IEEE. See @ref AVCRCId for a list of available + * polynomials. + * + * @{ + */ + +typedef uint32_t AVCRC; + +typedef enum { + AV_CRC_8_ATM, + AV_CRC_16_ANSI, + AV_CRC_16_CCITT, + AV_CRC_32_IEEE, + AV_CRC_32_IEEE_LE, /*< reversed bitorder version of AV_CRC_32_IEEE */ + AV_CRC_16_ANSI_LE, /*< reversed bitorder version of AV_CRC_16_ANSI */ +#if FF_API_CRC_BIG_TABLE + AV_CRC_24_IEEE = 12, +#else + AV_CRC_24_IEEE, +#endif /* FF_API_CRC_BIG_TABLE */ + AV_CRC_MAX, /*< Not part of public API! Do not use outside libavutil. */ +}AVCRCId; + +/** + * Initialize a CRC table. + * @param ctx must be an array of size sizeof(AVCRC)*257 or sizeof(AVCRC)*1024 + * @param le If 1, the lowest bit represents the coefficient for the highest + * exponent of the corresponding polynomial (both for poly and + * actual CRC). + * If 0, you must swap the CRC parameter and the result of av_crc + * if you need the standard representation (can be simplified in + * most cases to e.g. bswap16): + * av_bswap32(crc << (32-bits)) + * @param bits number of bits for the CRC + * @param poly generator polynomial without the x**bits coefficient, in the + * representation as specified by le + * @param ctx_size size of ctx in bytes + * @return <0 on failure + */ +int av_crc_init(AVCRC *ctx, int le, int bits, uint32_t poly, int ctx_size); + +/** + * Get an initialized standard CRC table. + * @param crc_id ID of a standard CRC + * @return a pointer to the CRC table or NULL on failure + */ +const AVCRC *av_crc_get_table(AVCRCId crc_id); + +/** + * Calculate the CRC of a block. + * @param crc CRC of previous blocks if any or initial value for CRC + * @return CRC updated with the data from the given block + * + * @see av_crc_init() "le" parameter + */ +uint32_t av_crc(const AVCRC *ctx, uint32_t crc, + const uint8_t *buffer, size_t length) av_pure; + +/** + * @} + */ + +#endif /* AVUTIL_CRC_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/des.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/des.h new file mode 100644 index 0000000..4cf11f5 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/des.h @@ -0,0 +1,77 @@ +/* + * DES encryption/decryption + * Copyright (c) 2007 Reimar Doeffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DES_H +#define AVUTIL_DES_H + +#include + +/** + * @defgroup lavu_des DES + * @ingroup lavu_crypto + * @{ + */ + +typedef struct AVDES { + uint64_t round_keys[3][16]; + int triple_des; +} AVDES; + +/** + * Allocate an AVDES context. + */ +AVDES *av_des_alloc(void); + +/** + * @brief Initializes an AVDES context. + * + * @param key_bits must be 64 or 192 + * @param decrypt 0 for encryption/CBC-MAC, 1 for decryption + * @return zero on success, negative value otherwise + */ +int av_des_init(struct AVDES *d, const uint8_t *key, int key_bits, int decrypt); + +/** + * @brief Encrypts / decrypts using the DES algorithm. + * + * @param count number of 8 byte blocks + * @param dst destination array, can be equal to src, must be 8-byte aligned + * @param src source array, can be equal to dst, must be 8-byte aligned, may be NULL + * @param iv initialization vector for CBC mode, if NULL then ECB will be used, + * must be 8-byte aligned + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_des_crypt(struct AVDES *d, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); + +/** + * @brief Calculates CBC-MAC using the DES algorithm. + * + * @param count number of 8 byte blocks + * @param dst destination array, can be equal to src, must be 8-byte aligned + * @param src source array, can be equal to dst, must be 8-byte aligned, may be NULL + */ +void av_des_mac(struct AVDES *d, uint8_t *dst, const uint8_t *src, int count); + +/** + * @} + */ + +#endif /* AVUTIL_DES_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/dict.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/dict.h new file mode 100644 index 0000000..118f1f0 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/dict.h @@ -0,0 +1,200 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Public dictionary API. + * @deprecated + * AVDictionary is provided for compatibility with libav. It is both in + * implementation as well as API inefficient. It does not scale and is + * extremely slow with large dictionaries. + * It is recommended that new code uses our tree container from tree.c/h + * where applicable, which uses AVL trees to achieve O(log n) performance. + */ + +#ifndef AVUTIL_DICT_H +#define AVUTIL_DICT_H + +#include + +#include "version.h" + +/** + * @addtogroup lavu_dict AVDictionary + * @ingroup lavu_data + * + * @brief Simple key:value store + * + * @{ + * Dictionaries are used for storing key:value pairs. To create + * an AVDictionary, simply pass an address of a NULL pointer to + * av_dict_set(). NULL can be used as an empty dictionary wherever + * a pointer to an AVDictionary is required. + * Use av_dict_get() to retrieve an entry or iterate over all + * entries and finally av_dict_free() to free the dictionary + * and all its contents. + * + @code + AVDictionary *d = NULL; // "create" an empty dictionary + AVDictionaryEntry *t = NULL; + + av_dict_set(&d, "foo", "bar", 0); // add an entry + + char *k = av_strdup("key"); // if your strings are already allocated, + char *v = av_strdup("value"); // you can avoid copying them like this + av_dict_set(&d, k, v, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL); + + while (t = av_dict_get(d, "", t, AV_DICT_IGNORE_SUFFIX)) { + <....> // iterate over all entries in d + } + av_dict_free(&d); + @endcode + */ + +#define AV_DICT_MATCH_CASE 1 /**< Only get an entry with exact-case key match. Only relevant in av_dict_get(). */ +#define AV_DICT_IGNORE_SUFFIX 2 /**< Return first entry in a dictionary whose first part corresponds to the search key, + ignoring the suffix of the found key string. Only relevant in av_dict_get(). */ +#define AV_DICT_DONT_STRDUP_KEY 4 /**< Take ownership of a key that's been + allocated with av_malloc() or another memory allocation function. */ +#define AV_DICT_DONT_STRDUP_VAL 8 /**< Take ownership of a value that's been + allocated with av_malloc() or another memory allocation function. */ +#define AV_DICT_DONT_OVERWRITE 16 ///< Don't overwrite existing entries. +#define AV_DICT_APPEND 32 /**< If the entry already exists, append to it. Note that no + delimiter is added, the strings are simply concatenated. */ +#define AV_DICT_MULTIKEY 64 /**< Allow to store several equal keys in the dictionary */ + +typedef struct AVDictionaryEntry { + char *key; + char *value; +} AVDictionaryEntry; + +typedef struct AVDictionary AVDictionary; + +/** + * Get a dictionary entry with matching key. + * + * The returned entry key or value must not be changed, or it will + * cause undefined behavior. + * + * To iterate through all the dictionary entries, you can set the matching key + * to the null string "" and set the AV_DICT_IGNORE_SUFFIX flag. + * + * @param prev Set to the previous matching element to find the next. + * If set to NULL the first matching element is returned. + * @param key matching key + * @param flags a collection of AV_DICT_* flags controlling how the entry is retrieved + * @return found entry or NULL in case no matching entry was found in the dictionary + */ +AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key, + const AVDictionaryEntry *prev, int flags); + +/** + * Get number of entries in dictionary. + * + * @param m dictionary + * @return number of entries in dictionary + */ +int av_dict_count(const AVDictionary *m); + +/** + * Set the given entry in *pm, overwriting an existing entry. + * + * Note: If AV_DICT_DONT_STRDUP_KEY or AV_DICT_DONT_STRDUP_VAL is set, + * these arguments will be freed on error. + * + * Warning: Adding a new entry to a dictionary invalidates all existing entries + * previously returned with av_dict_get. + * + * @param pm pointer to a pointer to a dictionary struct. If *pm is NULL + * a dictionary struct is allocated and put in *pm. + * @param key entry key to add to *pm (will either be av_strduped or added as a new key depending on flags) + * @param value entry value to add to *pm (will be av_strduped or added as a new key depending on flags). + * Passing a NULL value will cause an existing entry to be deleted. + * @return >= 0 on success otherwise an error code <0 + */ +int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags); + +/** + * Convenience wrapper for av_dict_set that converts the value to a string + * and stores it. + * + * Note: If AV_DICT_DONT_STRDUP_KEY is set, key will be freed on error. + */ +int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags); + +/** + * Parse the key/value pairs list and add the parsed entries to a dictionary. + * + * In case of failure, all the successfully set entries are stored in + * *pm. You may need to manually free the created dictionary. + * + * @param key_val_sep a 0-terminated list of characters used to separate + * key from value + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other + * @param flags flags to use when adding to dictionary. + * AV_DICT_DONT_STRDUP_KEY and AV_DICT_DONT_STRDUP_VAL + * are ignored since the key/value tokens will always + * be duplicated. + * @return 0 on success, negative AVERROR code on failure + */ +int av_dict_parse_string(AVDictionary **pm, const char *str, + const char *key_val_sep, const char *pairs_sep, + int flags); + +/** + * Copy entries from one AVDictionary struct into another. + * @param dst pointer to a pointer to a AVDictionary struct. If *dst is NULL, + * this function will allocate a struct for you and put it in *dst + * @param src pointer to source AVDictionary struct + * @param flags flags to use when setting entries in *dst + * @note metadata is read using the AV_DICT_IGNORE_SUFFIX flag + * @return 0 on success, negative AVERROR code on failure. If dst was allocated + * by this function, callers should free the associated memory. + */ +int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags); + +/** + * Free all the memory allocated for an AVDictionary struct + * and all keys and values. + */ +void av_dict_free(AVDictionary **m); + +/** + * Get dictionary entries as a string. + * + * Create a string containing dictionary's entries. + * Such string may be passed back to av_dict_parse_string(). + * @note String is escaped with backslashes ('\'). + * + * @param[in] m dictionary + * @param[out] buffer Pointer to buffer that will be allocated with string containg entries. + * Buffer must be freed by the caller when is no longer needed. + * @param[in] key_val_sep character used to separate key from value + * @param[in] pairs_sep character used to separate two pairs from each other + * @return >= 0 on success, negative on error + * @warning Separators cannot be neither '\\' nor '\0'. They also cannot be the same. + */ +int av_dict_get_string(const AVDictionary *m, char **buffer, + const char key_val_sep, const char pairs_sep); + +/** + * @} + */ + +#endif /* AVUTIL_DICT_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/display.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/display.h new file mode 100644 index 0000000..39c15ee --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/display.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2014 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DISPLAY_H +#define AVUTIL_DISPLAY_H + +#include +#include "common.h" + +/** + * The display transformation matrix specifies an affine transformation that + * should be applied to video frames for correct presentation. It is compatible + * with the matrices stored in the ISO/IEC 14496-12 container format. + * + * The data is a 3x3 matrix represented as a 9-element array: + * + * | a b u | + * (a, b, u, c, d, v, x, y, w) -> | c d v | + * | x y w | + * + * All numbers are stored in native endianness, as 16.16 fixed-point values, + * except for u, v and w, which are stored as 2.30 fixed-point values. + * + * The transformation maps a point (p, q) in the source (pre-transformation) + * frame to the point (p', q') in the destination (post-transformation) frame as + * follows: + * | a b u | + * (p, q, 1) . | c d v | = z * (p', q', 1) + * | x y w | + * + * The transformation can also be more explicitly written in components as + * follows: + * p' = (a * p + c * q + x) / z; + * q' = (b * p + d * q + y) / z; + * z = u * p + v * q + w + */ + +/** + * Extract the rotation component of the transformation matrix. + * + * @param matrix the transformation matrix + * @return the angle (in degrees) by which the transformation rotates the frame + * counterclockwise. The angle will be in range [-180.0, 180.0], + * or NaN if the matrix is singular. + * + * @note floating point numbers are inherently inexact, so callers are + * recommended to round the return value to nearest integer before use. + */ +double av_display_rotation_get(const int32_t matrix[9]); + +/** + * Initialize a transformation matrix describing a pure counterclockwise + * rotation by the specified angle (in degrees). + * + * @param matrix an allocated transformation matrix (will be fully overwritten + * by this function) + * @param angle rotation angle in degrees. + */ +void av_display_rotation_set(int32_t matrix[9], double angle); + +/** + * Flip the input matrix horizontally and/or vertically. + * + * @param matrix an allocated transformation matrix + * @param hflip whether the matrix should be flipped horizontally + * @param vflip whether the matrix should be flipped vertically + */ +void av_display_matrix_flip(int32_t matrix[9], int hflip, int vflip); + +#endif /* AVUTIL_DISPLAY_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/downmix_info.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/downmix_info.h new file mode 100644 index 0000000..221cf5b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/downmix_info.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2014 Tim Walker + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DOWNMIX_INFO_H +#define AVUTIL_DOWNMIX_INFO_H + +#include "frame.h" + +/** + * @file + * audio downmix medatata + */ + +/** + * @addtogroup lavu_audio + * @{ + */ + +/** + * @defgroup downmix_info Audio downmix metadata + * @{ + */ + +/** + * Possible downmix types. + */ +enum AVDownmixType { + AV_DOWNMIX_TYPE_UNKNOWN, /**< Not indicated. */ + AV_DOWNMIX_TYPE_LORO, /**< Lo/Ro 2-channel downmix (Stereo). */ + AV_DOWNMIX_TYPE_LTRT, /**< Lt/Rt 2-channel downmix, Dolby Surround compatible. */ + AV_DOWNMIX_TYPE_DPLII, /**< Lt/Rt 2-channel downmix, Dolby Pro Logic II compatible. */ + AV_DOWNMIX_TYPE_NB /**< Number of downmix types. Not part of ABI. */ +}; + +/** + * This structure describes optional metadata relevant to a downmix procedure. + * + * All fields are set by the decoder to the value indicated in the audio + * bitstream (if present), or to a "sane" default otherwise. + */ +typedef struct AVDownmixInfo { + /** + * Type of downmix preferred by the mastering engineer. + */ + enum AVDownmixType preferred_downmix_type; + + /** + * Absolute scale factor representing the nominal level of the center + * channel during a regular downmix. + */ + double center_mix_level; + + /** + * Absolute scale factor representing the nominal level of the center + * channel during an Lt/Rt compatible downmix. + */ + double center_mix_level_ltrt; + + /** + * Absolute scale factor representing the nominal level of the surround + * channels during a regular downmix. + */ + double surround_mix_level; + + /** + * Absolute scale factor representing the nominal level of the surround + * channels during an Lt/Rt compatible downmix. + */ + double surround_mix_level_ltrt; + + /** + * Absolute scale factor representing the level at which the LFE data is + * mixed into L/R channels during downmixing. + */ + double lfe_mix_level; +} AVDownmixInfo; + +/** + * Get a frame's AV_FRAME_DATA_DOWNMIX_INFO side data for editing. + * + * If the side data is absent, it is created and added to the frame. + * + * @param frame the frame for which the side data is to be obtained or created + * + * @return the AVDownmixInfo structure to be edited by the caller, or NULL if + * the structure cannot be allocated. + */ +AVDownmixInfo *av_downmix_info_update_side_data(AVFrame *frame); + +/** + * @} + */ + +/** + * @} + */ + +#endif /* AVUTIL_DOWNMIX_INFO_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/error.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/error.h new file mode 100644 index 0000000..71df4da --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/error.h @@ -0,0 +1,126 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * error code definitions + */ + +#ifndef AVUTIL_ERROR_H +#define AVUTIL_ERROR_H + +#include +#include + +/** + * @addtogroup lavu_error + * + * @{ + */ + + +/* error handling */ +#if EDOM > 0 +#define AVERROR(e) (-(e)) ///< Returns a negative error code from a POSIX error code, to return from library functions. +#define AVUNERROR(e) (-(e)) ///< Returns a POSIX error code from a library function error return value. +#else +/* Some platforms have E* and errno already negated. */ +#define AVERROR(e) (e) +#define AVUNERROR(e) (e) +#endif + +#define FFERRTAG(a, b, c, d) (-(int)MKTAG(a, b, c, d)) + +#define AVERROR_BSF_NOT_FOUND FFERRTAG(0xF8,'B','S','F') ///< Bitstream filter not found +#define AVERROR_BUG FFERRTAG( 'B','U','G','!') ///< Internal bug, also see AVERROR_BUG2 +#define AVERROR_BUFFER_TOO_SMALL FFERRTAG( 'B','U','F','S') ///< Buffer too small +#define AVERROR_DECODER_NOT_FOUND FFERRTAG(0xF8,'D','E','C') ///< Decoder not found +#define AVERROR_DEMUXER_NOT_FOUND FFERRTAG(0xF8,'D','E','M') ///< Demuxer not found +#define AVERROR_ENCODER_NOT_FOUND FFERRTAG(0xF8,'E','N','C') ///< Encoder not found +#define AVERROR_EOF FFERRTAG( 'E','O','F',' ') ///< End of file +#define AVERROR_EXIT FFERRTAG( 'E','X','I','T') ///< Immediate exit was requested; the called function should not be restarted +#define AVERROR_EXTERNAL FFERRTAG( 'E','X','T',' ') ///< Generic error in an external library +#define AVERROR_FILTER_NOT_FOUND FFERRTAG(0xF8,'F','I','L') ///< Filter not found +#define AVERROR_INVALIDDATA FFERRTAG( 'I','N','D','A') ///< Invalid data found when processing input +#define AVERROR_MUXER_NOT_FOUND FFERRTAG(0xF8,'M','U','X') ///< Muxer not found +#define AVERROR_OPTION_NOT_FOUND FFERRTAG(0xF8,'O','P','T') ///< Option not found +#define AVERROR_PATCHWELCOME FFERRTAG( 'P','A','W','E') ///< Not yet implemented in FFmpeg, patches welcome +#define AVERROR_PROTOCOL_NOT_FOUND FFERRTAG(0xF8,'P','R','O') ///< Protocol not found + +#define AVERROR_STREAM_NOT_FOUND FFERRTAG(0xF8,'S','T','R') ///< Stream not found +/** + * This is semantically identical to AVERROR_BUG + * it has been introduced in Libav after our AVERROR_BUG and with a modified value. + */ +#define AVERROR_BUG2 FFERRTAG( 'B','U','G',' ') +#define AVERROR_UNKNOWN FFERRTAG( 'U','N','K','N') ///< Unknown error, typically from an external library +#define AVERROR_EXPERIMENTAL (-0x2bb2afa8) ///< Requested feature is flagged experimental. Set strict_std_compliance if you really want to use it. +#define AVERROR_INPUT_CHANGED (-0x636e6701) ///< Input changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_OUTPUT_CHANGED) +#define AVERROR_OUTPUT_CHANGED (-0x636e6702) ///< Output changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_INPUT_CHANGED) +/* HTTP & RTSP errors */ +#define AVERROR_HTTP_BAD_REQUEST FFERRTAG(0xF8,'4','0','0') +#define AVERROR_HTTP_UNAUTHORIZED FFERRTAG(0xF8,'4','0','1') +#define AVERROR_HTTP_FORBIDDEN FFERRTAG(0xF8,'4','0','3') +#define AVERROR_HTTP_NOT_FOUND FFERRTAG(0xF8,'4','0','4') +#define AVERROR_HTTP_OTHER_4XX FFERRTAG(0xF8,'4','X','X') +#define AVERROR_HTTP_SERVER_ERROR FFERRTAG(0xF8,'5','X','X') + +#define AV_ERROR_MAX_STRING_SIZE 64 + +/** + * Put a description of the AVERROR code errnum in errbuf. + * In case of failure the global variable errno is set to indicate the + * error. Even in case of failure av_strerror() will print a generic + * error message indicating the errnum provided to errbuf. + * + * @param errnum error code to describe + * @param errbuf buffer to which description is written + * @param errbuf_size the size in bytes of errbuf + * @return 0 on success, a negative value if a description for errnum + * cannot be found + */ +int av_strerror(int errnum, char *errbuf, size_t errbuf_size); + +/** + * Fill the provided buffer with a string containing an error string + * corresponding to the AVERROR code errnum. + * + * @param errbuf a buffer + * @param errbuf_size size in bytes of errbuf + * @param errnum error code to describe + * @return the buffer in input, filled with the error description + * @see av_strerror() + */ +static inline char *av_make_error_string(char *errbuf, size_t errbuf_size, int errnum) +{ + av_strerror(errnum, errbuf, errbuf_size); + return errbuf; +} + +/** + * Convenience macro, the return value should be used only directly in + * function arguments but never stand-alone. + */ +#define av_err2str(errnum) \ + av_make_error_string((char[AV_ERROR_MAX_STRING_SIZE]){0}, AV_ERROR_MAX_STRING_SIZE, errnum) + +/** + * @} + */ + +#endif /* AVUTIL_ERROR_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/eval.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/eval.h new file mode 100644 index 0000000..dacd22b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/eval.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2002 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * simple arithmetic expression evaluator + */ + +#ifndef AVUTIL_EVAL_H +#define AVUTIL_EVAL_H + +#include "avutil.h" + +typedef struct AVExpr AVExpr; + +/** + * Parse and evaluate an expression. + * Note, this is significantly slower than av_expr_eval(). + * + * @param res a pointer to a double where is put the result value of + * the expression, or NAN in case of error + * @param s expression as a zero terminated string, for example "1+2^3+5*5+sin(2/3)" + * @param const_names NULL terminated array of zero terminated strings of constant identifiers, for example {"PI", "E", 0} + * @param const_values a zero terminated array of values for the identifiers from const_names + * @param func1_names NULL terminated array of zero terminated strings of funcs1 identifiers + * @param funcs1 NULL terminated array of function pointers for functions which take 1 argument + * @param func2_names NULL terminated array of zero terminated strings of funcs2 identifiers + * @param funcs2 NULL terminated array of function pointers for functions which take 2 arguments + * @param opaque a pointer which will be passed to all functions from funcs1 and funcs2 + * @param log_ctx parent logging context + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_expr_parse_and_eval(double *res, const char *s, + const char * const *const_names, const double *const_values, + const char * const *func1_names, double (* const *funcs1)(void *, double), + const char * const *func2_names, double (* const *funcs2)(void *, double, double), + void *opaque, int log_offset, void *log_ctx); + +/** + * Parse an expression. + * + * @param expr a pointer where is put an AVExpr containing the parsed + * value in case of successful parsing, or NULL otherwise. + * The pointed to AVExpr must be freed with av_expr_free() by the user + * when it is not needed anymore. + * @param s expression as a zero terminated string, for example "1+2^3+5*5+sin(2/3)" + * @param const_names NULL terminated array of zero terminated strings of constant identifiers, for example {"PI", "E", 0} + * @param func1_names NULL terminated array of zero terminated strings of funcs1 identifiers + * @param funcs1 NULL terminated array of function pointers for functions which take 1 argument + * @param func2_names NULL terminated array of zero terminated strings of funcs2 identifiers + * @param funcs2 NULL terminated array of function pointers for functions which take 2 arguments + * @param log_ctx parent logging context + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_expr_parse(AVExpr **expr, const char *s, + const char * const *const_names, + const char * const *func1_names, double (* const *funcs1)(void *, double), + const char * const *func2_names, double (* const *funcs2)(void *, double, double), + int log_offset, void *log_ctx); + +/** + * Evaluate a previously parsed expression. + * + * @param const_values a zero terminated array of values for the identifiers from av_expr_parse() const_names + * @param opaque a pointer which will be passed to all functions from funcs1 and funcs2 + * @return the value of the expression + */ +double av_expr_eval(AVExpr *e, const double *const_values, void *opaque); + +/** + * Free a parsed expression previously created with av_expr_parse(). + */ +void av_expr_free(AVExpr *e); + +/** + * Parse the string in numstr and return its value as a double. If + * the string is empty, contains only whitespaces, or does not contain + * an initial substring that has the expected syntax for a + * floating-point number, no conversion is performed. In this case, + * returns a value of zero and the value returned in tail is the value + * of numstr. + * + * @param numstr a string representing a number, may contain one of + * the International System number postfixes, for example 'K', 'M', + * 'G'. If 'i' is appended after the postfix, powers of 2 are used + * instead of powers of 10. The 'B' postfix multiplies the value by + * 8, and can be appended after another postfix or used alone. This + * allows using for example 'KB', 'MiB', 'G' and 'B' as postfix. + * @param tail if non-NULL puts here the pointer to the char next + * after the last parsed character + */ +double av_strtod(const char *numstr, char **tail); + +#endif /* AVUTIL_EVAL_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/ffversion.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/ffversion.h new file mode 100644 index 0000000..16c192a --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/ffversion.h @@ -0,0 +1,5 @@ +/* Automatically generated by version.sh, do not manually edit! */ +#ifndef AVUTIL_FFVERSION_H +#define AVUTIL_FFVERSION_H +#define FFMPEG_VERSION "3.3.9" +#endif /* AVUTIL_FFVERSION_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/fifo.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/fifo.h new file mode 100644 index 0000000..dc7bc6f --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/fifo.h @@ -0,0 +1,179 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * a very simple circular buffer FIFO implementation + */ + +#ifndef AVUTIL_FIFO_H +#define AVUTIL_FIFO_H + +#include +#include "avutil.h" +#include "attributes.h" + +typedef struct AVFifoBuffer { + uint8_t *buffer; + uint8_t *rptr, *wptr, *end; + uint32_t rndx, wndx; +} AVFifoBuffer; + +/** + * Initialize an AVFifoBuffer. + * @param size of FIFO + * @return AVFifoBuffer or NULL in case of memory allocation failure + */ +AVFifoBuffer *av_fifo_alloc(unsigned int size); + +/** + * Initialize an AVFifoBuffer. + * @param nmemb number of elements + * @param size size of the single element + * @return AVFifoBuffer or NULL in case of memory allocation failure + */ +AVFifoBuffer *av_fifo_alloc_array(size_t nmemb, size_t size); + +/** + * Free an AVFifoBuffer. + * @param f AVFifoBuffer to free + */ +void av_fifo_free(AVFifoBuffer *f); + +/** + * Free an AVFifoBuffer and reset pointer to NULL. + * @param f AVFifoBuffer to free + */ +void av_fifo_freep(AVFifoBuffer **f); + +/** + * Reset the AVFifoBuffer to the state right after av_fifo_alloc, in particular it is emptied. + * @param f AVFifoBuffer to reset + */ +void av_fifo_reset(AVFifoBuffer *f); + +/** + * Return the amount of data in bytes in the AVFifoBuffer, that is the + * amount of data you can read from it. + * @param f AVFifoBuffer to read from + * @return size + */ +int av_fifo_size(const AVFifoBuffer *f); + +/** + * Return the amount of space in bytes in the AVFifoBuffer, that is the + * amount of data you can write into it. + * @param f AVFifoBuffer to write into + * @return size + */ +int av_fifo_space(const AVFifoBuffer *f); + +/** + * Feed data at specific position from an AVFifoBuffer to a user-supplied callback. + * Similar as av_fifo_gereric_read but without discarding data. + * @param f AVFifoBuffer to read from + * @param offset offset from current read position + * @param buf_size number of bytes to read + * @param func generic read function + * @param dest data destination + */ +int av_fifo_generic_peek_at(AVFifoBuffer *f, void *dest, int offset, int buf_size, void (*func)(void*, void*, int)); + +/** + * Feed data from an AVFifoBuffer to a user-supplied callback. + * Similar as av_fifo_gereric_read but without discarding data. + * @param f AVFifoBuffer to read from + * @param buf_size number of bytes to read + * @param func generic read function + * @param dest data destination + */ +int av_fifo_generic_peek(AVFifoBuffer *f, void *dest, int buf_size, void (*func)(void*, void*, int)); + +/** + * Feed data from an AVFifoBuffer to a user-supplied callback. + * @param f AVFifoBuffer to read from + * @param buf_size number of bytes to read + * @param func generic read function + * @param dest data destination + */ +int av_fifo_generic_read(AVFifoBuffer *f, void *dest, int buf_size, void (*func)(void*, void*, int)); + +/** + * Feed data from a user-supplied callback to an AVFifoBuffer. + * @param f AVFifoBuffer to write to + * @param src data source; non-const since it may be used as a + * modifiable context by the function defined in func + * @param size number of bytes to write + * @param func generic write function; the first parameter is src, + * the second is dest_buf, the third is dest_buf_size. + * func must return the number of bytes written to dest_buf, or <= 0 to + * indicate no more data available to write. + * If func is NULL, src is interpreted as a simple byte array for source data. + * @return the number of bytes written to the FIFO + */ +int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size, int (*func)(void*, void*, int)); + +/** + * Resize an AVFifoBuffer. + * In case of reallocation failure, the old FIFO is kept unchanged. + * + * @param f AVFifoBuffer to resize + * @param size new AVFifoBuffer size in bytes + * @return <0 for failure, >=0 otherwise + */ +int av_fifo_realloc2(AVFifoBuffer *f, unsigned int size); + +/** + * Enlarge an AVFifoBuffer. + * In case of reallocation failure, the old FIFO is kept unchanged. + * The new fifo size may be larger than the requested size. + * + * @param f AVFifoBuffer to resize + * @param additional_space the amount of space in bytes to allocate in addition to av_fifo_size() + * @return <0 for failure, >=0 otherwise + */ +int av_fifo_grow(AVFifoBuffer *f, unsigned int additional_space); + +/** + * Read and discard the specified amount of data from an AVFifoBuffer. + * @param f AVFifoBuffer to read from + * @param size amount of data to read in bytes + */ +void av_fifo_drain(AVFifoBuffer *f, int size); + +/** + * Return a pointer to the data stored in a FIFO buffer at a certain offset. + * The FIFO buffer is not modified. + * + * @param f AVFifoBuffer to peek at, f must be non-NULL + * @param offs an offset in bytes, its absolute value must be less + * than the used buffer size or the returned pointer will + * point outside to the buffer data. + * The used buffer size can be checked with av_fifo_size(). + */ +static inline uint8_t *av_fifo_peek2(const AVFifoBuffer *f, int offs) +{ + uint8_t *ptr = f->rptr + offs; + if (ptr >= f->end) + ptr = f->buffer + (ptr - f->end); + else if (ptr < f->buffer) + ptr = f->end - (f->buffer - ptr); + return ptr; +} + +#endif /* AVUTIL_FIFO_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/file.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/file.h new file mode 100644 index 0000000..8666c7b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/file.h @@ -0,0 +1,69 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_FILE_H +#define AVUTIL_FILE_H + +#include + +#include "avutil.h" + +/** + * @file + * Misc file utilities. + */ + +/** + * Read the file with name filename, and put its content in a newly + * allocated buffer or map it with mmap() when available. + * In case of success set *bufptr to the read or mmapped buffer, and + * *size to the size in bytes of the buffer in *bufptr. + * The returned buffer must be released with av_file_unmap(). + * + * @param log_offset loglevel offset used for logging + * @param log_ctx context used for logging + * @return a non negative number in case of success, a negative value + * corresponding to an AVERROR error code in case of failure + */ +av_warn_unused_result +int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, + int log_offset, void *log_ctx); + +/** + * Unmap or free the buffer bufptr created by av_file_map(). + * + * @param size size in bytes of bufptr, must be the same as returned + * by av_file_map() + */ +void av_file_unmap(uint8_t *bufptr, size_t size); + +/** + * Wrapper to work around the lack of mkstemp() on mingw. + * Also, tries to create file in /tmp first, if possible. + * *prefix can be a character constant; *filename will be allocated internally. + * @return file descriptor of opened file (or negative value corresponding to an + * AVERROR code on error) + * and opened file name in **filename. + * @note On very old libcs it is necessary to set a secure umask before + * calling this, av_tempfile() can't call umask itself as it is used in + * libraries and could interfere with the calling application. + * @deprecated as fd numbers cannot be passed saftely between libs on some platforms + */ +int av_tempfile(const char *prefix, char **filename, int log_offset, void *log_ctx); + +#endif /* AVUTIL_FILE_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/frame.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/frame.h new file mode 100644 index 0000000..7cb78a1 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/frame.h @@ -0,0 +1,746 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_frame + * reference-counted frame API + */ + +#ifndef AVUTIL_FRAME_H +#define AVUTIL_FRAME_H + +#include + +#include "avutil.h" +#include "buffer.h" +#include "dict.h" +#include "rational.h" +#include "samplefmt.h" +#include "pixfmt.h" +#include "version.h" + + +/** + * @defgroup lavu_frame AVFrame + * @ingroup lavu_data + * + * @{ + * AVFrame is an abstraction for reference-counted raw multimedia data. + */ + +enum AVFrameSideDataType { + /** + * The data is the AVPanScan struct defined in libavcodec. + */ + AV_FRAME_DATA_PANSCAN, + /** + * ATSC A53 Part 4 Closed Captions. + * A53 CC bitstream is stored as uint8_t in AVFrameSideData.data. + * The number of bytes of CC data is AVFrameSideData.size. + */ + AV_FRAME_DATA_A53_CC, + /** + * Stereoscopic 3d metadata. + * The data is the AVStereo3D struct defined in libavutil/stereo3d.h. + */ + AV_FRAME_DATA_STEREO3D, + /** + * The data is the AVMatrixEncoding enum defined in libavutil/channel_layout.h. + */ + AV_FRAME_DATA_MATRIXENCODING, + /** + * Metadata relevant to a downmix procedure. + * The data is the AVDownmixInfo struct defined in libavutil/downmix_info.h. + */ + AV_FRAME_DATA_DOWNMIX_INFO, + /** + * ReplayGain information in the form of the AVReplayGain struct. + */ + AV_FRAME_DATA_REPLAYGAIN, + /** + * This side data contains a 3x3 transformation matrix describing an affine + * transformation that needs to be applied to the frame for correct + * presentation. + * + * See libavutil/display.h for a detailed description of the data. + */ + AV_FRAME_DATA_DISPLAYMATRIX, + /** + * Active Format Description data consisting of a single byte as specified + * in ETSI TS 101 154 using AVActiveFormatDescription enum. + */ + AV_FRAME_DATA_AFD, + /** + * Motion vectors exported by some codecs (on demand through the export_mvs + * flag set in the libavcodec AVCodecContext flags2 option). + * The data is the AVMotionVector struct defined in + * libavutil/motion_vector.h. + */ + AV_FRAME_DATA_MOTION_VECTORS, + /** + * Recommmends skipping the specified number of samples. This is exported + * only if the "skip_manual" AVOption is set in libavcodec. + * This has the same format as AV_PKT_DATA_SKIP_SAMPLES. + * @code + * u32le number of samples to skip from start of this packet + * u32le number of samples to skip from end of this packet + * u8 reason for start skip + * u8 reason for end skip (0=padding silence, 1=convergence) + * @endcode + */ + AV_FRAME_DATA_SKIP_SAMPLES, + /** + * This side data must be associated with an audio frame and corresponds to + * enum AVAudioServiceType defined in avcodec.h. + */ + AV_FRAME_DATA_AUDIO_SERVICE_TYPE, + /** + * Mastering display metadata associated with a video frame. The payload is + * an AVMasteringDisplayMetadata type and contains information about the + * mastering display color volume. + */ + AV_FRAME_DATA_MASTERING_DISPLAY_METADATA, + /** + * The GOP timecode in 25 bit timecode format. Data format is 64-bit integer. + * This is set on the first frame of a GOP that has a temporal reference of 0. + */ + AV_FRAME_DATA_GOP_TIMECODE, + + /** + * The data represents the AVSphericalMapping structure defined in + * libavutil/spherical.h. + */ + AV_FRAME_DATA_SPHERICAL, +}; + +enum AVActiveFormatDescription { + AV_AFD_SAME = 8, + AV_AFD_4_3 = 9, + AV_AFD_16_9 = 10, + AV_AFD_14_9 = 11, + AV_AFD_4_3_SP_14_9 = 13, + AV_AFD_16_9_SP_14_9 = 14, + AV_AFD_SP_4_3 = 15, +}; + + +/** + * Structure to hold side data for an AVFrame. + * + * sizeof(AVFrameSideData) is not a part of the public ABI, so new fields may be added + * to the end with a minor bump. + */ +typedef struct AVFrameSideData { + enum AVFrameSideDataType type; + uint8_t *data; + int size; + AVDictionary *metadata; + AVBufferRef *buf; +} AVFrameSideData; + +/** + * This structure describes decoded (raw) audio or video data. + * + * AVFrame must be allocated using av_frame_alloc(). Note that this only + * allocates the AVFrame itself, the buffers for the data must be managed + * through other means (see below). + * AVFrame must be freed with av_frame_free(). + * + * AVFrame is typically allocated once and then reused multiple times to hold + * different data (e.g. a single AVFrame to hold frames received from a + * decoder). In such a case, av_frame_unref() will free any references held by + * the frame and reset it to its original clean state before it + * is reused again. + * + * The data described by an AVFrame is usually reference counted through the + * AVBuffer API. The underlying buffer references are stored in AVFrame.buf / + * AVFrame.extended_buf. An AVFrame is considered to be reference counted if at + * least one reference is set, i.e. if AVFrame.buf[0] != NULL. In such a case, + * every single data plane must be contained in one of the buffers in + * AVFrame.buf or AVFrame.extended_buf. + * There may be a single buffer for all the data, or one separate buffer for + * each plane, or anything in between. + * + * sizeof(AVFrame) is not a part of the public ABI, so new fields may be added + * to the end with a minor bump. + * + * Fields can be accessed through AVOptions, the name string used, matches the + * C structure field name for fields accessible through AVOptions. The AVClass + * for AVFrame can be obtained from avcodec_get_frame_class() + */ +typedef struct AVFrame { +#define AV_NUM_DATA_POINTERS 8 + /** + * pointer to the picture/channel planes. + * This might be different from the first allocated byte + * + * Some decoders access areas outside 0,0 - width,height, please + * see avcodec_align_dimensions2(). Some filters and swscale can read + * up to 16 bytes beyond the planes, if these filters are to be used, + * then 16 extra bytes must be allocated. + * + * NOTE: Except for hwaccel formats, pointers not needed by the format + * MUST be set to NULL. + */ + uint8_t *data[AV_NUM_DATA_POINTERS]; + + /** + * For video, size in bytes of each picture line. + * For audio, size in bytes of each plane. + * + * For audio, only linesize[0] may be set. For planar audio, each channel + * plane must be the same size. + * + * For video the linesizes should be multiples of the CPUs alignment + * preference, this is 16 or 32 for modern desktop CPUs. + * Some code requires such alignment other code can be slower without + * correct alignment, for yet other it makes no difference. + * + * @note The linesize may be larger than the size of usable data -- there + * may be extra padding present for performance reasons. + */ + int linesize[AV_NUM_DATA_POINTERS]; + + /** + * pointers to the data planes/channels. + * + * For video, this should simply point to data[]. + * + * For planar audio, each channel has a separate data pointer, and + * linesize[0] contains the size of each channel buffer. + * For packed audio, there is just one data pointer, and linesize[0] + * contains the total size of the buffer for all channels. + * + * Note: Both data and extended_data should always be set in a valid frame, + * but for planar audio with more channels that can fit in data, + * extended_data must be used in order to access all channels. + */ + uint8_t **extended_data; + + /** + * width and height of the video frame + */ + int width, height; + + /** + * number of audio samples (per channel) described by this frame + */ + int nb_samples; + + /** + * format of the frame, -1 if unknown or unset + * Values correspond to enum AVPixelFormat for video frames, + * enum AVSampleFormat for audio) + */ + int format; + + /** + * 1 -> keyframe, 0-> not + */ + int key_frame; + + /** + * Picture type of the frame. + */ + enum AVPictureType pict_type; + + /** + * Sample aspect ratio for the video frame, 0/1 if unknown/unspecified. + */ + AVRational sample_aspect_ratio; + + /** + * Presentation timestamp in time_base units (time when frame should be shown to user). + */ + int64_t pts; + +#if FF_API_PKT_PTS + /** + * PTS copied from the AVPacket that was decoded to produce this frame. + * @deprecated use the pts field instead + */ + attribute_deprecated + int64_t pkt_pts; +#endif + + /** + * DTS copied from the AVPacket that triggered returning this frame. (if frame threading isn't used) + * This is also the Presentation time of this AVFrame calculated from + * only AVPacket.dts values without pts values. + */ + int64_t pkt_dts; + + /** + * picture number in bitstream order + */ + int coded_picture_number; + /** + * picture number in display order + */ + int display_picture_number; + + /** + * quality (between 1 (good) and FF_LAMBDA_MAX (bad)) + */ + int quality; + + /** + * for some private data of the user + */ + void *opaque; + +#if FF_API_ERROR_FRAME + /** + * @deprecated unused + */ + attribute_deprecated + uint64_t error[AV_NUM_DATA_POINTERS]; +#endif + + /** + * When decoding, this signals how much the picture must be delayed. + * extra_delay = repeat_pict / (2*fps) + */ + int repeat_pict; + + /** + * The content of the picture is interlaced. + */ + int interlaced_frame; + + /** + * If the content is interlaced, is top field displayed first. + */ + int top_field_first; + + /** + * Tell user application that palette has changed from previous frame. + */ + int palette_has_changed; + + /** + * reordered opaque 64 bits (generally an integer or a double precision float + * PTS but can be anything). + * The user sets AVCodecContext.reordered_opaque to represent the input at + * that time, + * the decoder reorders values as needed and sets AVFrame.reordered_opaque + * to exactly one of the values provided by the user through AVCodecContext.reordered_opaque + * @deprecated in favor of pkt_pts + */ + int64_t reordered_opaque; + + /** + * Sample rate of the audio data. + */ + int sample_rate; + + /** + * Channel layout of the audio data. + */ + uint64_t channel_layout; + + /** + * AVBuffer references backing the data for this frame. If all elements of + * this array are NULL, then this frame is not reference counted. This array + * must be filled contiguously -- if buf[i] is non-NULL then buf[j] must + * also be non-NULL for all j < i. + * + * There may be at most one AVBuffer per data plane, so for video this array + * always contains all the references. For planar audio with more than + * AV_NUM_DATA_POINTERS channels, there may be more buffers than can fit in + * this array. Then the extra AVBufferRef pointers are stored in the + * extended_buf array. + */ + AVBufferRef *buf[AV_NUM_DATA_POINTERS]; + + /** + * For planar audio which requires more than AV_NUM_DATA_POINTERS + * AVBufferRef pointers, this array will hold all the references which + * cannot fit into AVFrame.buf. + * + * Note that this is different from AVFrame.extended_data, which always + * contains all the pointers. This array only contains the extra pointers, + * which cannot fit into AVFrame.buf. + * + * This array is always allocated using av_malloc() by whoever constructs + * the frame. It is freed in av_frame_unref(). + */ + AVBufferRef **extended_buf; + /** + * Number of elements in extended_buf. + */ + int nb_extended_buf; + + AVFrameSideData **side_data; + int nb_side_data; + +/** + * @defgroup lavu_frame_flags AV_FRAME_FLAGS + * @ingroup lavu_frame + * Flags describing additional frame properties. + * + * @{ + */ + +/** + * The frame data may be corrupted, e.g. due to decoding errors. + */ +#define AV_FRAME_FLAG_CORRUPT (1 << 0) +/** + * A flag to mark the frames which need to be decoded, but shouldn't be output. + */ +#define AV_FRAME_FLAG_DISCARD (1 << 2) +/** + * @} + */ + + /** + * Frame flags, a combination of @ref lavu_frame_flags + */ + int flags; + + /** + * MPEG vs JPEG YUV range. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorRange color_range; + + enum AVColorPrimaries color_primaries; + + enum AVColorTransferCharacteristic color_trc; + + /** + * YUV colorspace type. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorSpace colorspace; + + enum AVChromaLocation chroma_location; + + /** + * frame timestamp estimated using various heuristics, in stream time base + * - encoding: unused + * - decoding: set by libavcodec, read by user. + */ + int64_t best_effort_timestamp; + + /** + * reordered pos from the last AVPacket that has been input into the decoder + * - encoding: unused + * - decoding: Read by user. + */ + int64_t pkt_pos; + + /** + * duration of the corresponding packet, expressed in + * AVStream->time_base units, 0 if unknown. + * - encoding: unused + * - decoding: Read by user. + */ + int64_t pkt_duration; + + /** + * metadata. + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + AVDictionary *metadata; + + /** + * decode error flags of the frame, set to a combination of + * FF_DECODE_ERROR_xxx flags if the decoder produced a frame, but there + * were errors during the decoding. + * - encoding: unused + * - decoding: set by libavcodec, read by user. + */ + int decode_error_flags; +#define FF_DECODE_ERROR_INVALID_BITSTREAM 1 +#define FF_DECODE_ERROR_MISSING_REFERENCE 2 + + /** + * number of audio channels, only used for audio. + * - encoding: unused + * - decoding: Read by user. + */ + int channels; + + /** + * size of the corresponding packet containing the compressed + * frame. + * It is set to a negative value if unknown. + * - encoding: unused + * - decoding: set by libavcodec, read by user. + */ + int pkt_size; + +#if FF_API_FRAME_QP + /** + * QP table + */ + attribute_deprecated + int8_t *qscale_table; + /** + * QP store stride + */ + attribute_deprecated + int qstride; + + attribute_deprecated + int qscale_type; + + AVBufferRef *qp_table_buf; +#endif + /** + * For hwaccel-format frames, this should be a reference to the + * AVHWFramesContext describing the frame. + */ + AVBufferRef *hw_frames_ctx; + + /** + * AVBufferRef for free use by the API user. FFmpeg will never check the + * contents of the buffer ref. FFmpeg calls av_buffer_unref() on it when + * the frame is unreferenced. av_frame_copy_props() calls create a new + * reference with av_buffer_ref() for the target frame's opaque_ref field. + * + * This is unrelated to the opaque field, although it serves a similar + * purpose. + */ + AVBufferRef *opaque_ref; +} AVFrame; + +/** + * Accessors for some AVFrame fields. These used to be provided for ABI + * compatibility, and do not need to be used anymore. + */ +int64_t av_frame_get_best_effort_timestamp(const AVFrame *frame); +void av_frame_set_best_effort_timestamp(AVFrame *frame, int64_t val); +int64_t av_frame_get_pkt_duration (const AVFrame *frame); +void av_frame_set_pkt_duration (AVFrame *frame, int64_t val); +int64_t av_frame_get_pkt_pos (const AVFrame *frame); +void av_frame_set_pkt_pos (AVFrame *frame, int64_t val); +int64_t av_frame_get_channel_layout (const AVFrame *frame); +void av_frame_set_channel_layout (AVFrame *frame, int64_t val); +int av_frame_get_channels (const AVFrame *frame); +void av_frame_set_channels (AVFrame *frame, int val); +int av_frame_get_sample_rate (const AVFrame *frame); +void av_frame_set_sample_rate (AVFrame *frame, int val); +AVDictionary *av_frame_get_metadata (const AVFrame *frame); +void av_frame_set_metadata (AVFrame *frame, AVDictionary *val); +int av_frame_get_decode_error_flags (const AVFrame *frame); +void av_frame_set_decode_error_flags (AVFrame *frame, int val); +int av_frame_get_pkt_size(const AVFrame *frame); +void av_frame_set_pkt_size(AVFrame *frame, int val); +AVDictionary **avpriv_frame_get_metadatap(AVFrame *frame); +#if FF_API_FRAME_QP +int8_t *av_frame_get_qp_table(AVFrame *f, int *stride, int *type); +int av_frame_set_qp_table(AVFrame *f, AVBufferRef *buf, int stride, int type); +#endif +enum AVColorSpace av_frame_get_colorspace(const AVFrame *frame); +void av_frame_set_colorspace(AVFrame *frame, enum AVColorSpace val); +enum AVColorRange av_frame_get_color_range(const AVFrame *frame); +void av_frame_set_color_range(AVFrame *frame, enum AVColorRange val); + +/** + * Get the name of a colorspace. + * @return a static string identifying the colorspace; can be NULL. + */ +const char *av_get_colorspace_name(enum AVColorSpace val); + +/** + * Allocate an AVFrame and set its fields to default values. The resulting + * struct must be freed using av_frame_free(). + * + * @return An AVFrame filled with default values or NULL on failure. + * + * @note this only allocates the AVFrame itself, not the data buffers. Those + * must be allocated through other means, e.g. with av_frame_get_buffer() or + * manually. + */ +AVFrame *av_frame_alloc(void); + +/** + * Free the frame and any dynamically allocated objects in it, + * e.g. extended_data. If the frame is reference counted, it will be + * unreferenced first. + * + * @param frame frame to be freed. The pointer will be set to NULL. + */ +void av_frame_free(AVFrame **frame); + +/** + * Set up a new reference to the data described by the source frame. + * + * Copy frame properties from src to dst and create a new reference for each + * AVBufferRef from src. + * + * If src is not reference counted, new buffers are allocated and the data is + * copied. + * + * @warning: dst MUST have been either unreferenced with av_frame_unref(dst), + * or newly allocated with av_frame_alloc() before calling this + * function, or undefined behavior will occur. + * + * @return 0 on success, a negative AVERROR on error + */ +int av_frame_ref(AVFrame *dst, const AVFrame *src); + +/** + * Create a new frame that references the same data as src. + * + * This is a shortcut for av_frame_alloc()+av_frame_ref(). + * + * @return newly created AVFrame on success, NULL on error. + */ +AVFrame *av_frame_clone(const AVFrame *src); + +/** + * Unreference all the buffers referenced by frame and reset the frame fields. + */ +void av_frame_unref(AVFrame *frame); + +/** + * Move everything contained in src to dst and reset src. + * + * @warning: dst is not unreferenced, but directly overwritten without reading + * or deallocating its contents. Call av_frame_unref(dst) manually + * before calling this function to ensure that no memory is leaked. + */ +void av_frame_move_ref(AVFrame *dst, AVFrame *src); + +/** + * Allocate new buffer(s) for audio or video data. + * + * The following fields must be set on frame before calling this function: + * - format (pixel format for video, sample format for audio) + * - width and height for video + * - nb_samples and channel_layout for audio + * + * This function will fill AVFrame.data and AVFrame.buf arrays and, if + * necessary, allocate and fill AVFrame.extended_data and AVFrame.extended_buf. + * For planar formats, one buffer will be allocated for each plane. + * + * @warning: if frame already has been allocated, calling this function will + * leak memory. In addition, undefined behavior can occur in certain + * cases. + * + * @param frame frame in which to store the new buffers. + * @param align required buffer size alignment + * + * @return 0 on success, a negative AVERROR on error. + */ +int av_frame_get_buffer(AVFrame *frame, int align); + +/** + * Check if the frame data is writable. + * + * @return A positive value if the frame data is writable (which is true if and + * only if each of the underlying buffers has only one reference, namely the one + * stored in this frame). Return 0 otherwise. + * + * If 1 is returned the answer is valid until av_buffer_ref() is called on any + * of the underlying AVBufferRefs (e.g. through av_frame_ref() or directly). + * + * @see av_frame_make_writable(), av_buffer_is_writable() + */ +int av_frame_is_writable(AVFrame *frame); + +/** + * Ensure that the frame data is writable, avoiding data copy if possible. + * + * Do nothing if the frame is writable, allocate new buffers and copy the data + * if it is not. + * + * @return 0 on success, a negative AVERROR on error. + * + * @see av_frame_is_writable(), av_buffer_is_writable(), + * av_buffer_make_writable() + */ +int av_frame_make_writable(AVFrame *frame); + +/** + * Copy the frame data from src to dst. + * + * This function does not allocate anything, dst must be already initialized and + * allocated with the same parameters as src. + * + * This function only copies the frame data (i.e. the contents of the data / + * extended data arrays), not any other properties. + * + * @return >= 0 on success, a negative AVERROR on error. + */ +int av_frame_copy(AVFrame *dst, const AVFrame *src); + +/** + * Copy only "metadata" fields from src to dst. + * + * Metadata for the purpose of this function are those fields that do not affect + * the data layout in the buffers. E.g. pts, sample rate (for audio) or sample + * aspect ratio (for video), but not width/height or channel layout. + * Side data is also copied. + */ +int av_frame_copy_props(AVFrame *dst, const AVFrame *src); + +/** + * Get the buffer reference a given data plane is stored in. + * + * @param plane index of the data plane of interest in frame->extended_data. + * + * @return the buffer reference that contains the plane or NULL if the input + * frame is not valid. + */ +AVBufferRef *av_frame_get_plane_buffer(AVFrame *frame, int plane); + +/** + * Add a new side data to a frame. + * + * @param frame a frame to which the side data should be added + * @param type type of the added side data + * @param size size of the side data + * + * @return newly added side data on success, NULL on error + */ +AVFrameSideData *av_frame_new_side_data(AVFrame *frame, + enum AVFrameSideDataType type, + int size); + +/** + * @return a pointer to the side data of a given type on success, NULL if there + * is no side data with such type in this frame. + */ +AVFrameSideData *av_frame_get_side_data(const AVFrame *frame, + enum AVFrameSideDataType type); + +/** + * If side data of the supplied type exists in the frame, free it and remove it + * from the frame. + */ +void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type); + +/** + * @return a string identifying the side data type + */ +const char *av_frame_side_data_name(enum AVFrameSideDataType type); + +/** + * @} + */ + +#endif /* AVUTIL_FRAME_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hash.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hash.h new file mode 100644 index 0000000..a20b893 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hash.h @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2013 Reimar Döffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_hash_generic + * Generic hashing API + */ + +#ifndef AVUTIL_HASH_H +#define AVUTIL_HASH_H + +#include + +/** + * @defgroup lavu_hash Hash Functions + * @ingroup lavu_crypto + * Hash functions useful in multimedia. + * + * Hash functions are widely used in multimedia, from error checking and + * concealment to internal regression testing. libavutil has efficient + * implementations of a variety of hash functions that may be useful for + * FFmpeg and other multimedia applications. + * + * @{ + * + * @defgroup lavu_hash_generic Generic Hashing API + * An abstraction layer for all hash functions supported by libavutil. + * + * If your application needs to support a wide range of different hash + * functions, then the Generic Hashing API is for you. It provides a generic, + * reusable API for @ref lavu_hash "all hash functions" implemented in libavutil. + * If you just need to use one particular hash function, use the @ref lavu_hash + * "individual hash" directly. + * + * @section Sample Code + * + * A basic template for using the Generic Hashing API follows: + * + * @code + * struct AVHashContext *ctx = NULL; + * const char *hash_name = NULL; + * uint8_t *output_buf = NULL; + * + * // Select from a string returned by av_hash_names() + * hash_name = ...; + * + * // Allocate a hash context + * ret = av_hash_alloc(&ctx, hash_name); + * if (ret < 0) + * return ret; + * + * // Initialize the hash context + * av_hash_init(ctx); + * + * // Update the hash context with data + * while (data_left) { + * av_hash_update(ctx, data, size); + * } + * + * // Now we have no more data, so it is time to finalize the hash and get the + * // output. But we need to first allocate an output buffer. Note that you can + * // use any memory allocation function, including malloc(), not just + * // av_malloc(). + * output_buf = av_malloc(av_hash_get_size(ctx)); + * if (!output_buf) + * return AVERROR(ENOMEM); + * + * // Finalize the hash context. + * // You can use any of the av_hash_final*() functions provided, for other + * // output formats. If you do so, be sure to adjust the memory allocation + * // above. See the function documentation below for the exact amount of extra + * // memory needed. + * av_hash_final(ctx, output_buffer); + * + * // Free the context + * av_hash_freep(&ctx); + * @endcode + * + * @section Hash Function-Specific Information + * If the CRC32 hash is selected, the #AV_CRC_32_IEEE polynomial will be + * used. + * + * If the Murmur3 hash is selected, the default seed will be used. See @ref + * lavu_murmur3_seedinfo "Murmur3" for more information. + * + * @{ + */ + +/** + * @example ffhash.c + * This example is a simple command line application that takes one or more + * arguments. It demonstrates a typical use of the hashing API with allocation, + * initialization, updating, and finalizing. + */ + +struct AVHashContext; + +/** + * Allocate a hash context for the algorithm specified by name. + * + * @return >= 0 for success, a negative error code for failure + * + * @note The context is not initialized after a call to this function; you must + * call av_hash_init() to do so. + */ +int av_hash_alloc(struct AVHashContext **ctx, const char *name); + +/** + * Get the names of available hash algorithms. + * + * This function can be used to enumerate the algorithms. + * + * @param[in] i Index of the hash algorithm, starting from 0 + * @return Pointer to a static string or `NULL` if `i` is out of range + */ +const char *av_hash_names(int i); + +/** + * Get the name of the algorithm corresponding to the given hash context. + */ +const char *av_hash_get_name(const struct AVHashContext *ctx); + +/** + * Maximum value that av_hash_get_size() will currently return. + * + * You can use this if you absolutely want or need to use static allocation for + * the output buffer and are fine with not supporting hashes newly added to + * libavutil without recompilation. + * + * @warning + * Adding new hashes with larger sizes, and increasing the macro while doing + * so, will not be considered an ABI change. To prevent your code from + * overflowing a buffer, either dynamically allocate the output buffer with + * av_hash_get_size(), or limit your use of the Hashing API to hashes that are + * already in FFmpeg during the time of compilation. + */ +#define AV_HASH_MAX_SIZE 64 + +/** + * Get the size of the resulting hash value in bytes. + * + * The maximum value this function will currently return is available as macro + * #AV_HASH_MAX_SIZE. + * + * @param[in] ctx Hash context + * @return Size of the hash value in bytes + */ +int av_hash_get_size(const struct AVHashContext *ctx); + +/** + * Initialize or reset a hash context. + * + * @param[in,out] ctx Hash context + */ +void av_hash_init(struct AVHashContext *ctx); + +/** + * Update a hash context with additional data. + * + * @param[in,out] ctx Hash context + * @param[in] src Data to be added to the hash context + * @param[in] len Size of the additional data + */ +void av_hash_update(struct AVHashContext *ctx, const uint8_t *src, int len); + +/** + * Finalize a hash context and compute the actual hash value. + * + * The minimum size of `dst` buffer is given by av_hash_get_size() or + * #AV_HASH_MAX_SIZE. The use of the latter macro is discouraged. + * + * It is not safe to update or finalize a hash context again, if it has already + * been finalized. + * + * @param[in,out] ctx Hash context + * @param[out] dst Where the final hash value will be stored + * + * @see av_hash_final_bin() provides an alternative API + */ +void av_hash_final(struct AVHashContext *ctx, uint8_t *dst); + +/** + * Finalize a hash context and store the actual hash value in a buffer. + * + * It is not safe to update or finalize a hash context again, if it has already + * been finalized. + * + * If `size` is smaller than the hash size (given by av_hash_get_size()), the + * hash is truncated; if size is larger, the buffer is padded with 0. + * + * @param[in,out] ctx Hash context + * @param[out] dst Where the final hash value will be stored + * @param[in] size Number of bytes to write to `dst` + */ +void av_hash_final_bin(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Finalize a hash context and store the hexadecimal representation of the + * actual hash value as a string. + * + * It is not safe to update or finalize a hash context again, if it has already + * been finalized. + * + * The string is always 0-terminated. + * + * If `size` is smaller than `2 * hash_size + 1`, where `hash_size` is the + * value returned by av_hash_get_size(), the string will be truncated. + * + * @param[in,out] ctx Hash context + * @param[out] dst Where the string will be stored + * @param[in] size Maximum number of bytes to write to `dst` + */ +void av_hash_final_hex(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Finalize a hash context and store the Base64 representation of the + * actual hash value as a string. + * + * It is not safe to update or finalize a hash context again, if it has already + * been finalized. + * + * The string is always 0-terminated. + * + * If `size` is smaller than AV_BASE64_SIZE(hash_size), where `hash_size` is + * the value returned by av_hash_get_size(), the string will be truncated. + * + * @param[in,out] ctx Hash context + * @param[out] dst Where the final hash value will be stored + * @param[in] size Maximum number of bytes to write to `dst` + */ +void av_hash_final_b64(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Free hash context and set hash context pointer to `NULL`. + * + * @param[in,out] ctx Pointer to hash context + */ +void av_hash_freep(struct AVHashContext **ctx); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_HASH_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hmac.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hmac.h new file mode 100644 index 0000000..576a0a4 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hmac.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2012 Martin Storsjo + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HMAC_H +#define AVUTIL_HMAC_H + +#include + +#include "version.h" +/** + * @defgroup lavu_hmac HMAC + * @ingroup lavu_crypto + * @{ + */ + +enum AVHMACType { + AV_HMAC_MD5, + AV_HMAC_SHA1, + AV_HMAC_SHA224, + AV_HMAC_SHA256, + AV_HMAC_SHA384 = 12, + AV_HMAC_SHA512, +}; + +typedef struct AVHMAC AVHMAC; + +/** + * Allocate an AVHMAC context. + * @param type The hash function used for the HMAC. + */ +AVHMAC *av_hmac_alloc(enum AVHMACType type); + +/** + * Free an AVHMAC context. + * @param ctx The context to free, may be NULL + */ +void av_hmac_free(AVHMAC *ctx); + +/** + * Initialize an AVHMAC context with an authentication key. + * @param ctx The HMAC context + * @param key The authentication key + * @param keylen The length of the key, in bytes + */ +void av_hmac_init(AVHMAC *ctx, const uint8_t *key, unsigned int keylen); + +/** + * Hash data with the HMAC. + * @param ctx The HMAC context + * @param data The data to hash + * @param len The length of the data, in bytes + */ +void av_hmac_update(AVHMAC *ctx, const uint8_t *data, unsigned int len); + +/** + * Finish hashing and output the HMAC digest. + * @param ctx The HMAC context + * @param out The output buffer to write the digest into + * @param outlen The length of the out buffer, in bytes + * @return The number of bytes written to out, or a negative error code. + */ +int av_hmac_final(AVHMAC *ctx, uint8_t *out, unsigned int outlen); + +/** + * Hash an array of data with a key. + * @param ctx The HMAC context + * @param data The data to hash + * @param len The length of the data, in bytes + * @param key The authentication key + * @param keylen The length of the key, in bytes + * @param out The output buffer to write the digest into + * @param outlen The length of the out buffer, in bytes + * @return The number of bytes written to out, or a negative error code. + */ +int av_hmac_calc(AVHMAC *ctx, const uint8_t *data, unsigned int len, + const uint8_t *key, unsigned int keylen, + uint8_t *out, unsigned int outlen); + +/** + * @} + */ + +#endif /* AVUTIL_HMAC_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext.h new file mode 100644 index 0000000..e35fb25 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext.h @@ -0,0 +1,523 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HWCONTEXT_H +#define AVUTIL_HWCONTEXT_H + +#include "buffer.h" +#include "frame.h" +#include "log.h" +#include "pixfmt.h" + +enum AVHWDeviceType { + AV_HWDEVICE_TYPE_VDPAU, + AV_HWDEVICE_TYPE_CUDA, + AV_HWDEVICE_TYPE_VAAPI, + AV_HWDEVICE_TYPE_DXVA2, + AV_HWDEVICE_TYPE_QSV, +}; + +typedef struct AVHWDeviceInternal AVHWDeviceInternal; + +/** + * This struct aggregates all the (hardware/vendor-specific) "high-level" state, + * i.e. state that is not tied to a concrete processing configuration. + * E.g., in an API that supports hardware-accelerated encoding and decoding, + * this struct will (if possible) wrap the state that is common to both encoding + * and decoding and from which specific instances of encoders or decoders can be + * derived. + * + * This struct is reference-counted with the AVBuffer mechanism. The + * av_hwdevice_ctx_alloc() constructor yields a reference, whose data field + * points to the actual AVHWDeviceContext. Further objects derived from + * AVHWDeviceContext (such as AVHWFramesContext, describing a frame pool with + * specific properties) will hold an internal reference to it. After all the + * references are released, the AVHWDeviceContext itself will be freed, + * optionally invoking a user-specified callback for uninitializing the hardware + * state. + */ +typedef struct AVHWDeviceContext { + /** + * A class for logging. Set by av_hwdevice_ctx_alloc(). + */ + const AVClass *av_class; + + /** + * Private data used internally by libavutil. Must not be accessed in any + * way by the caller. + */ + AVHWDeviceInternal *internal; + + /** + * This field identifies the underlying API used for hardware access. + * + * This field is set when this struct is allocated and never changed + * afterwards. + */ + enum AVHWDeviceType type; + + /** + * The format-specific data, allocated and freed by libavutil along with + * this context. + * + * Should be cast by the user to the format-specific context defined in the + * corresponding header (hwcontext_*.h) and filled as described in the + * documentation before calling av_hwdevice_ctx_init(). + * + * After calling av_hwdevice_ctx_init() this struct should not be modified + * by the caller. + */ + void *hwctx; + + /** + * This field may be set by the caller before calling av_hwdevice_ctx_init(). + * + * If non-NULL, this callback will be called when the last reference to + * this context is unreferenced, immediately before it is freed. + * + * @note when other objects (e.g an AVHWFramesContext) are derived from this + * struct, this callback will be invoked after all such child objects + * are fully uninitialized and their respective destructors invoked. + */ + void (*free)(struct AVHWDeviceContext *ctx); + + /** + * Arbitrary user data, to be used e.g. by the free() callback. + */ + void *user_opaque; +} AVHWDeviceContext; + +typedef struct AVHWFramesInternal AVHWFramesInternal; + +/** + * This struct describes a set or pool of "hardware" frames (i.e. those with + * data not located in normal system memory). All the frames in the pool are + * assumed to be allocated in the same way and interchangeable. + * + * This struct is reference-counted with the AVBuffer mechanism and tied to a + * given AVHWDeviceContext instance. The av_hwframe_ctx_alloc() constructor + * yields a reference, whose data field points to the actual AVHWFramesContext + * struct. + */ +typedef struct AVHWFramesContext { + /** + * A class for logging. + */ + const AVClass *av_class; + + /** + * Private data used internally by libavutil. Must not be accessed in any + * way by the caller. + */ + AVHWFramesInternal *internal; + + /** + * A reference to the parent AVHWDeviceContext. This reference is owned and + * managed by the enclosing AVHWFramesContext, but the caller may derive + * additional references from it. + */ + AVBufferRef *device_ref; + + /** + * The parent AVHWDeviceContext. This is simply a pointer to + * device_ref->data provided for convenience. + * + * Set by libavutil in av_hwframe_ctx_init(). + */ + AVHWDeviceContext *device_ctx; + + /** + * The format-specific data, allocated and freed automatically along with + * this context. + * + * Should be cast by the user to the format-specific context defined in the + * corresponding header (hwframe_*.h) and filled as described in the + * documentation before calling av_hwframe_ctx_init(). + * + * After any frames using this context are created, the contents of this + * struct should not be modified by the caller. + */ + void *hwctx; + + /** + * This field may be set by the caller before calling av_hwframe_ctx_init(). + * + * If non-NULL, this callback will be called when the last reference to + * this context is unreferenced, immediately before it is freed. + */ + void (*free)(struct AVHWFramesContext *ctx); + + /** + * Arbitrary user data, to be used e.g. by the free() callback. + */ + void *user_opaque; + + /** + * A pool from which the frames are allocated by av_hwframe_get_buffer(). + * This field may be set by the caller before calling av_hwframe_ctx_init(). + * The buffers returned by calling av_buffer_pool_get() on this pool must + * have the properties described in the documentation in the corresponding hw + * type's header (hwcontext_*.h). The pool will be freed strictly before + * this struct's free() callback is invoked. + * + * This field may be NULL, then libavutil will attempt to allocate a pool + * internally. Note that certain device types enforce pools allocated at + * fixed size (frame count), which cannot be extended dynamically. In such a + * case, initial_pool_size must be set appropriately. + */ + AVBufferPool *pool; + + /** + * Initial size of the frame pool. If a device type does not support + * dynamically resizing the pool, then this is also the maximum pool size. + * + * May be set by the caller before calling av_hwframe_ctx_init(). Must be + * set if pool is NULL and the device type does not support dynamic pools. + */ + int initial_pool_size; + + /** + * The pixel format identifying the underlying HW surface type. + * + * Must be a hwaccel format, i.e. the corresponding descriptor must have the + * AV_PIX_FMT_FLAG_HWACCEL flag set. + * + * Must be set by the user before calling av_hwframe_ctx_init(). + */ + enum AVPixelFormat format; + + /** + * The pixel format identifying the actual data layout of the hardware + * frames. + * + * Must be set by the caller before calling av_hwframe_ctx_init(). + * + * @note when the underlying API does not provide the exact data layout, but + * only the colorspace/bit depth, this field should be set to the fully + * planar version of that format (e.g. for 8-bit 420 YUV it should be + * AV_PIX_FMT_YUV420P, not AV_PIX_FMT_NV12 or anything else). + */ + enum AVPixelFormat sw_format; + + /** + * The allocated dimensions of the frames in this pool. + * + * Must be set by the user before calling av_hwframe_ctx_init(). + */ + int width, height; +} AVHWFramesContext; + +/** + * Allocate an AVHWDeviceContext for a given hardware type. + * + * @param type the type of the hardware device to allocate. + * @return a reference to the newly created AVHWDeviceContext on success or NULL + * on failure. + */ +AVBufferRef *av_hwdevice_ctx_alloc(enum AVHWDeviceType type); + +/** + * Finalize the device context before use. This function must be called after + * the context is filled with all the required information and before it is + * used in any way. + * + * @param ref a reference to the AVHWDeviceContext + * @return 0 on success, a negative AVERROR code on failure + */ +int av_hwdevice_ctx_init(AVBufferRef *ref); + +/** + * Open a device of the specified type and create an AVHWDeviceContext for it. + * + * This is a convenience function intended to cover the simple cases. Callers + * who need to fine-tune device creation/management should open the device + * manually and then wrap it in an AVHWDeviceContext using + * av_hwdevice_ctx_alloc()/av_hwdevice_ctx_init(). + * + * The returned context is already initialized and ready for use, the caller + * should not call av_hwdevice_ctx_init() on it. The user_opaque/free fields of + * the created AVHWDeviceContext are set by this function and should not be + * touched by the caller. + * + * @param device_ctx On success, a reference to the newly-created device context + * will be written here. The reference is owned by the caller + * and must be released with av_buffer_unref() when no longer + * needed. On failure, NULL will be written to this pointer. + * @param type The type of the device to create. + * @param device A type-specific string identifying the device to open. + * @param opts A dictionary of additional (type-specific) options to use in + * opening the device. The dictionary remains owned by the caller. + * @param flags currently unused + * + * @return 0 on success, a negative AVERROR code on failure. + */ +int av_hwdevice_ctx_create(AVBufferRef **device_ctx, enum AVHWDeviceType type, + const char *device, AVDictionary *opts, int flags); + +/** + * Allocate an AVHWFramesContext tied to a given device context. + * + * @param device_ctx a reference to a AVHWDeviceContext. This function will make + * a new reference for internal use, the one passed to the + * function remains owned by the caller. + * @return a reference to the newly created AVHWFramesContext on success or NULL + * on failure. + */ +AVBufferRef *av_hwframe_ctx_alloc(AVBufferRef *device_ctx); + +/** + * Finalize the context before use. This function must be called after the + * context is filled with all the required information and before it is attached + * to any frames. + * + * @param ref a reference to the AVHWFramesContext + * @return 0 on success, a negative AVERROR code on failure + */ +int av_hwframe_ctx_init(AVBufferRef *ref); + +/** + * Allocate a new frame attached to the given AVHWFramesContext. + * + * @param hwframe_ctx a reference to an AVHWFramesContext + * @param frame an empty (freshly allocated or unreffed) frame to be filled with + * newly allocated buffers. + * @param flags currently unused, should be set to zero + * @return 0 on success, a negative AVERROR code on failure + */ +int av_hwframe_get_buffer(AVBufferRef *hwframe_ctx, AVFrame *frame, int flags); + +/** + * Copy data to or from a hw surface. At least one of dst/src must have an + * AVHWFramesContext attached. + * + * If src has an AVHWFramesContext attached, then the format of dst (if set) + * must use one of the formats returned by av_hwframe_transfer_get_formats(src, + * AV_HWFRAME_TRANSFER_DIRECTION_FROM). + * If dst has an AVHWFramesContext attached, then the format of src must use one + * of the formats returned by av_hwframe_transfer_get_formats(dst, + * AV_HWFRAME_TRANSFER_DIRECTION_TO) + * + * dst may be "clean" (i.e. with data/buf pointers unset), in which case the + * data buffers will be allocated by this function using av_frame_get_buffer(). + * If dst->format is set, then this format will be used, otherwise (when + * dst->format is AV_PIX_FMT_NONE) the first acceptable format will be chosen. + * + * The two frames must have matching allocated dimensions (i.e. equal to + * AVHWFramesContext.width/height), since not all device types support + * transferring a sub-rectangle of the whole surface. The display dimensions + * (i.e. AVFrame.width/height) may be smaller than the allocated dimensions, but + * also have to be equal for both frames. When the display dimensions are + * smaller than the allocated dimensions, the content of the padding in the + * destination frame is unspecified. + * + * @param dst the destination frame. dst is not touched on failure. + * @param src the source frame. + * @param flags currently unused, should be set to zero + * @return 0 on success, a negative AVERROR error code on failure. + */ +int av_hwframe_transfer_data(AVFrame *dst, const AVFrame *src, int flags); + +enum AVHWFrameTransferDirection { + /** + * Transfer the data from the queried hw frame. + */ + AV_HWFRAME_TRANSFER_DIRECTION_FROM, + + /** + * Transfer the data to the queried hw frame. + */ + AV_HWFRAME_TRANSFER_DIRECTION_TO, +}; + +/** + * Get a list of possible source or target formats usable in + * av_hwframe_transfer_data(). + * + * @param hwframe_ctx the frame context to obtain the information for + * @param dir the direction of the transfer + * @param formats the pointer to the output format list will be written here. + * The list is terminated with AV_PIX_FMT_NONE and must be freed + * by the caller when no longer needed using av_free(). + * If this function returns successfully, the format list will + * have at least one item (not counting the terminator). + * On failure, the contents of this pointer are unspecified. + * @param flags currently unused, should be set to zero + * @return 0 on success, a negative AVERROR code on failure. + */ +int av_hwframe_transfer_get_formats(AVBufferRef *hwframe_ctx, + enum AVHWFrameTransferDirection dir, + enum AVPixelFormat **formats, int flags); + + +/** + * This struct describes the constraints on hardware frames attached to + * a given device with a hardware-specific configuration. This is returned + * by av_hwdevice_get_hwframe_constraints() and must be freed by + * av_hwframe_constraints_free() after use. + */ +typedef struct AVHWFramesConstraints { + /** + * A list of possible values for format in the hw_frames_ctx, + * terminated by AV_PIX_FMT_NONE. This member will always be filled. + */ + enum AVPixelFormat *valid_hw_formats; + + /** + * A list of possible values for sw_format in the hw_frames_ctx, + * terminated by AV_PIX_FMT_NONE. Can be NULL if this information is + * not known. + */ + enum AVPixelFormat *valid_sw_formats; + + /** + * The minimum size of frames in this hw_frames_ctx. + * (Zero if not known.) + */ + int min_width; + int min_height; + + /** + * The maximum size of frames in this hw_frames_ctx. + * (INT_MAX if not known / no limit.) + */ + int max_width; + int max_height; +} AVHWFramesConstraints; + +/** + * Allocate a HW-specific configuration structure for a given HW device. + * After use, the user must free all members as required by the specific + * hardware structure being used, then free the structure itself with + * av_free(). + * + * @param device_ctx a reference to the associated AVHWDeviceContext. + * @return The newly created HW-specific configuration structure on + * success or NULL on failure. + */ +void *av_hwdevice_hwconfig_alloc(AVBufferRef *device_ctx); + +/** + * Get the constraints on HW frames given a device and the HW-specific + * configuration to be used with that device. If no HW-specific + * configuration is provided, returns the maximum possible capabilities + * of the device. + * + * @param device_ctx a reference to the associated AVHWDeviceContext. + * @param hwconfig a filled HW-specific configuration structure, or NULL + * to return the maximum possible capabilities of the device. + * @return AVHWFramesConstraints structure describing the constraints + * on the device, or NULL if not available. + */ +AVHWFramesConstraints *av_hwdevice_get_hwframe_constraints(AVBufferRef *ref, + const void *hwconfig); + +/** + * Free an AVHWFrameConstraints structure. + * + * @param constraints The (filled or unfilled) AVHWFrameConstraints structure. + */ +void av_hwframe_constraints_free(AVHWFramesConstraints **constraints); + + +/** + * Flags to apply to frame mappings. + */ +enum { + /** + * The mapping must be readable. + */ + AV_HWFRAME_MAP_READ = 1 << 0, + /** + * The mapping must be writeable. + */ + AV_HWFRAME_MAP_WRITE = 1 << 1, + /** + * The mapped frame will be overwritten completely in subsequent + * operations, so the current frame data need not be loaded. Any values + * which are not overwritten are unspecified. + */ + AV_HWFRAME_MAP_OVERWRITE = 1 << 2, + /** + * The mapping must be direct. That is, there must not be any copying in + * the map or unmap steps. Note that performance of direct mappings may + * be much lower than normal memory. + */ + AV_HWFRAME_MAP_DIRECT = 1 << 3, +}; + +/** + * Map a hardware frame. + * + * This has a number of different possible effects, depending on the format + * and origin of the src and dst frames. On input, src should be a usable + * frame with valid buffers and dst should be blank (typically as just created + * by av_frame_alloc()). src should have an associated hwframe context, and + * dst may optionally have a format and associated hwframe context. + * + * If src was created by mapping a frame from the hwframe context of dst, + * then this function undoes the mapping - dst is replaced by a reference to + * the frame that src was originally mapped from. + * + * If both src and dst have an associated hwframe context, then this function + * attempts to map the src frame from its hardware context to that of dst and + * then fill dst with appropriate data to be usable there. This will only be + * possible if the hwframe contexts and associated devices are compatible - + * given compatible devices, av_hwframe_ctx_create_derived() can be used to + * create a hwframe context for dst in which mapping should be possible. + * + * If src has a hwframe context but dst does not, then the src frame is + * mapped to normal memory and should thereafter be usable as a normal frame. + * If the format is set on dst, then the mapping will attempt to create dst + * with that format and fail if it is not possible. If format is unset (is + * AV_PIX_FMT_NONE) then dst will be mapped with whatever the most appropriate + * format to use is (probably the sw_format of the src hwframe context). + * + * A return value of AVERROR(ENOSYS) indicates that the mapping is not + * possible with the given arguments and hwframe setup, while other return + * values indicate that it failed somehow. + * + * @param dst Destination frame, to contain the mapping. + * @param src Source frame, to be mapped. + * @param flags Some combination of AV_HWFRAME_MAP_* flags. + * @return Zero on success, negative AVERROR code on failure. + */ +int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags); + + +/** + * Create and initialise an AVHWFramesContext as a mapping of another existing + * AVHWFramesContext on a different device. + * + * av_hwframe_ctx_init() should not be called after this. + * + * @param derived_frame_ctx On success, a reference to the newly created + * AVHWFramesContext. + * @param derived_device_ctx A reference to the device to create the new + * AVHWFramesContext on. + * @param source_frame_ctx A reference to an existing AVHWFramesContext + * which will be mapped to the derived context. + * @param flags Currently unused; should be set to zero. + * @return Zero on success, negative AVERROR code on failure. + */ +int av_hwframe_ctx_create_derived(AVBufferRef **derived_frame_ctx, + enum AVPixelFormat format, + AVBufferRef *derived_device_ctx, + AVBufferRef *source_frame_ctx, + int flags); + +#endif /* AVUTIL_HWCONTEXT_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext_cuda.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext_cuda.h new file mode 100644 index 0000000..12dae84 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext_cuda.h @@ -0,0 +1,51 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef AVUTIL_HWCONTEXT_CUDA_H +#define AVUTIL_HWCONTEXT_CUDA_H + +#ifndef CUDA_VERSION +#include +#endif + +#include "pixfmt.h" + +/** + * @file + * An API-specific header for AV_HWDEVICE_TYPE_CUDA. + * + * This API supports dynamic frame pools. AVHWFramesContext.pool must return + * AVBufferRefs whose data pointer is a CUdeviceptr. + */ + +typedef struct AVCUDADeviceContextInternal AVCUDADeviceContextInternal; + +/** + * This struct is allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVCUDADeviceContext { + CUcontext cuda_ctx; + AVCUDADeviceContextInternal *internal; +} AVCUDADeviceContext; + +/** + * AVHWFramesContext.hwctx is currently not used + */ + +#endif /* AVUTIL_HWCONTEXT_CUDA_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext_dxva2.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext_dxva2.h new file mode 100644 index 0000000..6c36cb4 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext_dxva2.h @@ -0,0 +1,72 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef AVUTIL_HWCONTEXT_DXVA2_H +#define AVUTIL_HWCONTEXT_DXVA2_H + +/** + * @file + * An API-specific header for AV_HWDEVICE_TYPE_DXVA2. + * + * Only fixed-size pools are supported. + * + * For user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs + * with the data pointer set to a pointer to IDirect3DSurface9. + */ + +#include +#include + +/** + * This struct is allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVDXVA2DeviceContext { + IDirect3DDeviceManager9 *devmgr; +} AVDXVA2DeviceContext; + +/** + * This struct is allocated as AVHWFramesContext.hwctx + */ +typedef struct AVDXVA2FramesContext { + /** + * The surface type (e.g. DXVA2_VideoProcessorRenderTarget or + * DXVA2_VideoDecoderRenderTarget). Must be set by the caller. + */ + DWORD surface_type; + + /** + * The surface pool. When an external pool is not provided by the caller, + * this will be managed (allocated and filled on init, freed on uninit) by + * libavutil. + */ + IDirect3DSurface9 **surfaces; + int nb_surfaces; + + /** + * Certain drivers require the decoder to be destroyed before the surfaces. + * To allow internally managed pools to work properly in such cases, this + * field is provided. + * + * If it is non-NULL, libavutil will call IDirectXVideoDecoder_Release() on + * it just before the internal surface pool is freed. + */ + IDirectXVideoDecoder *decoder_to_release; +} AVDXVA2FramesContext; + +#endif /* AVUTIL_HWCONTEXT_DXVA2_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext_qsv.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext_qsv.h new file mode 100644 index 0000000..b98d611 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext_qsv.h @@ -0,0 +1,53 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HWCONTEXT_QSV_H +#define AVUTIL_HWCONTEXT_QSV_H + +#include + +/** + * @file + * An API-specific header for AV_HWDEVICE_TYPE_QSV. + * + * This API does not support dynamic frame pools. AVHWFramesContext.pool must + * contain AVBufferRefs whose data pointer points to an mfxFrameSurface1 struct. + */ + +/** + * This struct is allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVQSVDeviceContext { + mfxSession session; +} AVQSVDeviceContext; + +/** + * This struct is allocated as AVHWFramesContext.hwctx + */ +typedef struct AVQSVFramesContext { + mfxFrameSurface1 *surfaces; + int nb_surfaces; + + /** + * A combination of MFX_MEMTYPE_* describing the frame pool. + */ + int frame_type; +} AVQSVFramesContext; + +#endif /* AVUTIL_HWCONTEXT_QSV_H */ + diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext_vaapi.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext_vaapi.h new file mode 100644 index 0000000..da1d4fe --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext_vaapi.h @@ -0,0 +1,110 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HWCONTEXT_VAAPI_H +#define AVUTIL_HWCONTEXT_VAAPI_H + +#include + +/** + * @file + * API-specific header for AV_HWDEVICE_TYPE_VAAPI. + * + * Dynamic frame pools are supported, but note that any pool used as a render + * target is required to be of fixed size in order to be be usable as an + * argument to vaCreateContext(). + * + * For user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs + * with the data pointer set to a VASurfaceID. + */ + +enum { + /** + * The quirks field has been set by the user and should not be detected + * automatically by av_hwdevice_ctx_init(). + */ + AV_VAAPI_DRIVER_QUIRK_USER_SET = (1 << 0), + /** + * The driver does not destroy parameter buffers when they are used by + * vaRenderPicture(). Additional code will be required to destroy them + * separately afterwards. + */ + AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS = (1 << 1), + + /** + * The driver does not support the VASurfaceAttribMemoryType attribute, + * so the surface allocation code will not try to use it. + */ + AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE = (1 << 2), +}; + +/** + * VAAPI connection details. + * + * Allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVVAAPIDeviceContext { + /** + * The VADisplay handle, to be filled by the user. + */ + VADisplay display; + /** + * Driver quirks to apply - this is filled by av_hwdevice_ctx_init(), + * with reference to a table of known drivers, unless the + * AV_VAAPI_DRIVER_QUIRK_USER_SET bit is already present. The user + * may need to refer to this field when performing any later + * operations using VAAPI with the same VADisplay. + */ + unsigned int driver_quirks; +} AVVAAPIDeviceContext; + +/** + * VAAPI-specific data associated with a frame pool. + * + * Allocated as AVHWFramesContext.hwctx. + */ +typedef struct AVVAAPIFramesContext { + /** + * Set by the user to apply surface attributes to all surfaces in + * the frame pool. If null, default settings are used. + */ + VASurfaceAttrib *attributes; + int nb_attributes; + /** + * The surfaces IDs of all surfaces in the pool after creation. + * Only valid if AVHWFramesContext.initial_pool_size was positive. + * These are intended to be used as the render_targets arguments to + * vaCreateContext(). + */ + VASurfaceID *surface_ids; + int nb_surfaces; +} AVVAAPIFramesContext; + +/** + * VAAPI hardware pipeline configuration details. + * + * Allocated with av_hwdevice_hwconfig_alloc(). + */ +typedef struct AVVAAPIHWConfig { + /** + * ID of a VAAPI pipeline configuration. + */ + VAConfigID config_id; +} AVVAAPIHWConfig; + +#endif /* AVUTIL_HWCONTEXT_VAAPI_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext_vdpau.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext_vdpau.h new file mode 100644 index 0000000..1b7ea1e --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/hwcontext_vdpau.h @@ -0,0 +1,44 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HWCONTEXT_VDPAU_H +#define AVUTIL_HWCONTEXT_VDPAU_H + +#include + +/** + * @file + * An API-specific header for AV_HWDEVICE_TYPE_VDPAU. + * + * This API supports dynamic frame pools. AVHWFramesContext.pool must return + * AVBufferRefs whose data pointer is a VdpVideoSurface. + */ + +/** + * This struct is allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVVDPAUDeviceContext { + VdpDevice device; + VdpGetProcAddress *get_proc_address; +} AVVDPAUDeviceContext; + +/** + * AVHWFramesContext.hwctx is currently not used + */ + +#endif /* AVUTIL_HWCONTEXT_VDPAU_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/imgutils.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/imgutils.h new file mode 100644 index 0000000..a4a5efc --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/imgutils.h @@ -0,0 +1,246 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_IMGUTILS_H +#define AVUTIL_IMGUTILS_H + +/** + * @file + * misc image utilities + * + * @addtogroup lavu_picture + * @{ + */ + +#include "avutil.h" +#include "pixdesc.h" +#include "rational.h" + +/** + * Compute the max pixel step for each plane of an image with a + * format described by pixdesc. + * + * The pixel step is the distance in bytes between the first byte of + * the group of bytes which describe a pixel component and the first + * byte of the successive group in the same plane for the same + * component. + * + * @param max_pixsteps an array which is filled with the max pixel step + * for each plane. Since a plane may contain different pixel + * components, the computed max_pixsteps[plane] is relative to the + * component in the plane with the max pixel step. + * @param max_pixstep_comps an array which is filled with the component + * for each plane which has the max pixel step. May be NULL. + */ +void av_image_fill_max_pixsteps(int max_pixsteps[4], int max_pixstep_comps[4], + const AVPixFmtDescriptor *pixdesc); + +/** + * Compute the size of an image line with format pix_fmt and width + * width for the plane plane. + * + * @return the computed size in bytes + */ +int av_image_get_linesize(enum AVPixelFormat pix_fmt, int width, int plane); + +/** + * Fill plane linesizes for an image with pixel format pix_fmt and + * width width. + * + * @param linesizes array to be filled with the linesize for each plane + * @return >= 0 in case of success, a negative error code otherwise + */ +int av_image_fill_linesizes(int linesizes[4], enum AVPixelFormat pix_fmt, int width); + +/** + * Fill plane data pointers for an image with pixel format pix_fmt and + * height height. + * + * @param data pointers array to be filled with the pointer for each image plane + * @param ptr the pointer to a buffer which will contain the image + * @param linesizes the array containing the linesize for each + * plane, should be filled by av_image_fill_linesizes() + * @return the size in bytes required for the image buffer, a negative + * error code in case of failure + */ +int av_image_fill_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt, int height, + uint8_t *ptr, const int linesizes[4]); + +/** + * Allocate an image with size w and h and pixel format pix_fmt, and + * fill pointers and linesizes accordingly. + * The allocated image buffer has to be freed by using + * av_freep(&pointers[0]). + * + * @param align the value to use for buffer size alignment + * @return the size in bytes required for the image buffer, a negative + * error code in case of failure + */ +int av_image_alloc(uint8_t *pointers[4], int linesizes[4], + int w, int h, enum AVPixelFormat pix_fmt, int align); + +/** + * Copy image plane from src to dst. + * That is, copy "height" number of lines of "bytewidth" bytes each. + * The first byte of each successive line is separated by *_linesize + * bytes. + * + * bytewidth must be contained by both absolute values of dst_linesize + * and src_linesize, otherwise the function behavior is undefined. + * + * @param dst_linesize linesize for the image plane in dst + * @param src_linesize linesize for the image plane in src + */ +void av_image_copy_plane(uint8_t *dst, int dst_linesize, + const uint8_t *src, int src_linesize, + int bytewidth, int height); + +/** + * Copy image in src_data to dst_data. + * + * @param dst_linesizes linesizes for the image in dst_data + * @param src_linesizes linesizes for the image in src_data + */ +void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], + const uint8_t *src_data[4], const int src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height); + +/** + * Copy image data located in uncacheable (e.g. GPU mapped) memory. Where + * available, this function will use special functionality for reading from such + * memory, which may result in greatly improved performance compared to plain + * av_image_copy(). + * + * The data pointers and the linesizes must be aligned to the maximum required + * by the CPU architecture. + * + * @note The linesize parameters have the type ptrdiff_t here, while they are + * int for av_image_copy(). + * @note On x86, the linesizes currently need to be aligned to the cacheline + * size (i.e. 64) to get improved performance. + */ +void av_image_copy_uc_from(uint8_t *dst_data[4], const ptrdiff_t dst_linesizes[4], + const uint8_t *src_data[4], const ptrdiff_t src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height); + +/** + * Setup the data pointers and linesizes based on the specified image + * parameters and the provided array. + * + * The fields of the given image are filled in by using the src + * address which points to the image data buffer. Depending on the + * specified pixel format, one or multiple image data pointers and + * line sizes will be set. If a planar format is specified, several + * pointers will be set pointing to the different picture planes and + * the line sizes of the different planes will be stored in the + * lines_sizes array. Call with src == NULL to get the required + * size for the src buffer. + * + * To allocate the buffer and fill in the dst_data and dst_linesize in + * one call, use av_image_alloc(). + * + * @param dst_data data pointers to be filled in + * @param dst_linesizes linesizes for the image in dst_data to be filled in + * @param src buffer which will contain or contains the actual image data, can be NULL + * @param pix_fmt the pixel format of the image + * @param width the width of the image in pixels + * @param height the height of the image in pixels + * @param align the value used in src for linesize alignment + * @return the size in bytes required for src, a negative error code + * in case of failure + */ +int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4], + const uint8_t *src, + enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Return the size in bytes of the amount of data required to store an + * image with the given parameters. + * + * @param[in] align the assumed linesize alignment + */ +int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Copy image data from an image into a buffer. + * + * av_image_get_buffer_size() can be used to compute the required size + * for the buffer to fill. + * + * @param dst a buffer into which picture data will be copied + * @param dst_size the size in bytes of dst + * @param src_data pointers containing the source image data + * @param src_linesizes linesizes for the image in src_data + * @param pix_fmt the pixel format of the source image + * @param width the width of the source image in pixels + * @param height the height of the source image in pixels + * @param align the assumed linesize alignment for dst + * @return the number of bytes written to dst, or a negative value + * (error code) on error + */ +int av_image_copy_to_buffer(uint8_t *dst, int dst_size, + const uint8_t * const src_data[4], const int src_linesize[4], + enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Check if the given dimension of an image is valid, meaning that all + * bytes of the image can be addressed with a signed int. + * + * @param w the width of the picture + * @param h the height of the picture + * @param log_offset the offset to sum to the log level for logging with log_ctx + * @param log_ctx the parent logging context, it may be NULL + * @return >= 0 if valid, a negative error code otherwise + */ +int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx); + +/** + * Check if the given dimension of an image is valid, meaning that all + * bytes of a plane of an image with the specified pix_fmt can be addressed + * with a signed int. + * + * @param w the width of the picture + * @param h the height of the picture + * @param max_pixels the maximum number of pixels the user wants to accept + * @param pix_fmt the pixel format, can be AV_PIX_FMT_NONE if unknown. + * @param log_offset the offset to sum to the log level for logging with log_ctx + * @param log_ctx the parent logging context, it may be NULL + * @return >= 0 if valid, a negative error code otherwise + */ +int av_image_check_size2(unsigned int w, unsigned int h, int64_t max_pixels, enum AVPixelFormat pix_fmt, int log_offset, void *log_ctx); + +/** + * Check if the given sample aspect ratio of an image is valid. + * + * It is considered invalid if the denominator is 0 or if applying the ratio + * to the image size would make the smaller dimension less than 1. If the + * sar numerator is 0, it is considered unknown and will return as valid. + * + * @param w width of the image + * @param h height of the image + * @param sar sample aspect ratio of the image + * @return 0 if valid, a negative AVERROR code otherwise + */ +int av_image_check_sar(unsigned int w, unsigned int h, AVRational sar); + +/** + * @} + */ + + +#endif /* AVUTIL_IMGUTILS_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/intfloat.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/intfloat.h new file mode 100644 index 0000000..fe3d7ec --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/intfloat.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_INTFLOAT_H +#define AVUTIL_INTFLOAT_H + +#include +#include "attributes.h" + +union av_intfloat32 { + uint32_t i; + float f; +}; + +union av_intfloat64 { + uint64_t i; + double f; +}; + +/** + * Reinterpret a 32-bit integer as a float. + */ +static av_always_inline float av_int2float(uint32_t i) +{ + union av_intfloat32 v; + v.i = i; + return v.f; +} + +/** + * Reinterpret a float as a 32-bit integer. + */ +static av_always_inline uint32_t av_float2int(float f) +{ + union av_intfloat32 v; + v.f = f; + return v.i; +} + +/** + * Reinterpret a 64-bit integer as a double. + */ +static av_always_inline double av_int2double(uint64_t i) +{ + union av_intfloat64 v; + v.i = i; + return v.f; +} + +/** + * Reinterpret a double as a 64-bit integer. + */ +static av_always_inline uint64_t av_double2int(double f) +{ + union av_intfloat64 v; + v.f = f; + return v.i; +} + +#endif /* AVUTIL_INTFLOAT_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/intreadwrite.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/intreadwrite.h new file mode 100644 index 0000000..d54d4b9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/intreadwrite.h @@ -0,0 +1,634 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_INTREADWRITE_H +#define AVUTIL_INTREADWRITE_H + +#include +#include "libavutil/avconfig.h" +#include "attributes.h" +#include "bswap.h" + +typedef union { + uint64_t u64; + uint32_t u32[2]; + uint16_t u16[4]; + uint8_t u8 [8]; + double f64; + float f32[2]; +} av_alias av_alias64; + +typedef union { + uint32_t u32; + uint16_t u16[2]; + uint8_t u8 [4]; + float f32; +} av_alias av_alias32; + +typedef union { + uint16_t u16; + uint8_t u8 [2]; +} av_alias av_alias16; + +/* + * Arch-specific headers can provide any combination of + * AV_[RW][BLN](16|24|32|48|64) and AV_(COPY|SWAP|ZERO)(64|128) macros. + * Preprocessor symbols must be defined, even if these are implemented + * as inline functions. + * + * R/W means read/write, B/L/N means big/little/native endianness. + * The following macros require aligned access, compared to their + * unaligned variants: AV_(COPY|SWAP|ZERO)(64|128), AV_[RW]N[8-64]A. + * Incorrect usage may range from abysmal performance to crash + * depending on the platform. + * + * The unaligned variants are AV_[RW][BLN][8-64] and AV_COPY*U. + */ + +#ifdef HAVE_AV_CONFIG_H + +#include "config.h" + +#if ARCH_ARM +# include "arm/intreadwrite.h" +#elif ARCH_AVR32 +# include "avr32/intreadwrite.h" +#elif ARCH_MIPS +# include "mips/intreadwrite.h" +#elif ARCH_PPC +# include "ppc/intreadwrite.h" +#elif ARCH_TOMI +# include "tomi/intreadwrite.h" +#elif ARCH_X86 +# include "x86/intreadwrite.h" +#endif + +#endif /* HAVE_AV_CONFIG_H */ + +/* + * Map AV_RNXX <-> AV_R[BL]XX for all variants provided by per-arch headers. + */ + +#if AV_HAVE_BIGENDIAN + +# if defined(AV_RN16) && !defined(AV_RB16) +# define AV_RB16(p) AV_RN16(p) +# elif !defined(AV_RN16) && defined(AV_RB16) +# define AV_RN16(p) AV_RB16(p) +# endif + +# if defined(AV_WN16) && !defined(AV_WB16) +# define AV_WB16(p, v) AV_WN16(p, v) +# elif !defined(AV_WN16) && defined(AV_WB16) +# define AV_WN16(p, v) AV_WB16(p, v) +# endif + +# if defined(AV_RN24) && !defined(AV_RB24) +# define AV_RB24(p) AV_RN24(p) +# elif !defined(AV_RN24) && defined(AV_RB24) +# define AV_RN24(p) AV_RB24(p) +# endif + +# if defined(AV_WN24) && !defined(AV_WB24) +# define AV_WB24(p, v) AV_WN24(p, v) +# elif !defined(AV_WN24) && defined(AV_WB24) +# define AV_WN24(p, v) AV_WB24(p, v) +# endif + +# if defined(AV_RN32) && !defined(AV_RB32) +# define AV_RB32(p) AV_RN32(p) +# elif !defined(AV_RN32) && defined(AV_RB32) +# define AV_RN32(p) AV_RB32(p) +# endif + +# if defined(AV_WN32) && !defined(AV_WB32) +# define AV_WB32(p, v) AV_WN32(p, v) +# elif !defined(AV_WN32) && defined(AV_WB32) +# define AV_WN32(p, v) AV_WB32(p, v) +# endif + +# if defined(AV_RN48) && !defined(AV_RB48) +# define AV_RB48(p) AV_RN48(p) +# elif !defined(AV_RN48) && defined(AV_RB48) +# define AV_RN48(p) AV_RB48(p) +# endif + +# if defined(AV_WN48) && !defined(AV_WB48) +# define AV_WB48(p, v) AV_WN48(p, v) +# elif !defined(AV_WN48) && defined(AV_WB48) +# define AV_WN48(p, v) AV_WB48(p, v) +# endif + +# if defined(AV_RN64) && !defined(AV_RB64) +# define AV_RB64(p) AV_RN64(p) +# elif !defined(AV_RN64) && defined(AV_RB64) +# define AV_RN64(p) AV_RB64(p) +# endif + +# if defined(AV_WN64) && !defined(AV_WB64) +# define AV_WB64(p, v) AV_WN64(p, v) +# elif !defined(AV_WN64) && defined(AV_WB64) +# define AV_WN64(p, v) AV_WB64(p, v) +# endif + +#else /* AV_HAVE_BIGENDIAN */ + +# if defined(AV_RN16) && !defined(AV_RL16) +# define AV_RL16(p) AV_RN16(p) +# elif !defined(AV_RN16) && defined(AV_RL16) +# define AV_RN16(p) AV_RL16(p) +# endif + +# if defined(AV_WN16) && !defined(AV_WL16) +# define AV_WL16(p, v) AV_WN16(p, v) +# elif !defined(AV_WN16) && defined(AV_WL16) +# define AV_WN16(p, v) AV_WL16(p, v) +# endif + +# if defined(AV_RN24) && !defined(AV_RL24) +# define AV_RL24(p) AV_RN24(p) +# elif !defined(AV_RN24) && defined(AV_RL24) +# define AV_RN24(p) AV_RL24(p) +# endif + +# if defined(AV_WN24) && !defined(AV_WL24) +# define AV_WL24(p, v) AV_WN24(p, v) +# elif !defined(AV_WN24) && defined(AV_WL24) +# define AV_WN24(p, v) AV_WL24(p, v) +# endif + +# if defined(AV_RN32) && !defined(AV_RL32) +# define AV_RL32(p) AV_RN32(p) +# elif !defined(AV_RN32) && defined(AV_RL32) +# define AV_RN32(p) AV_RL32(p) +# endif + +# if defined(AV_WN32) && !defined(AV_WL32) +# define AV_WL32(p, v) AV_WN32(p, v) +# elif !defined(AV_WN32) && defined(AV_WL32) +# define AV_WN32(p, v) AV_WL32(p, v) +# endif + +# if defined(AV_RN48) && !defined(AV_RL48) +# define AV_RL48(p) AV_RN48(p) +# elif !defined(AV_RN48) && defined(AV_RL48) +# define AV_RN48(p) AV_RL48(p) +# endif + +# if defined(AV_WN48) && !defined(AV_WL48) +# define AV_WL48(p, v) AV_WN48(p, v) +# elif !defined(AV_WN48) && defined(AV_WL48) +# define AV_WN48(p, v) AV_WL48(p, v) +# endif + +# if defined(AV_RN64) && !defined(AV_RL64) +# define AV_RL64(p) AV_RN64(p) +# elif !defined(AV_RN64) && defined(AV_RL64) +# define AV_RN64(p) AV_RL64(p) +# endif + +# if defined(AV_WN64) && !defined(AV_WL64) +# define AV_WL64(p, v) AV_WN64(p, v) +# elif !defined(AV_WN64) && defined(AV_WL64) +# define AV_WN64(p, v) AV_WL64(p, v) +# endif + +#endif /* !AV_HAVE_BIGENDIAN */ + +/* + * Define AV_[RW]N helper macros to simplify definitions not provided + * by per-arch headers. + */ + +#if defined(__GNUC__) && !defined(__TI_COMPILER_VERSION__) + +union unaligned_64 { uint64_t l; } __attribute__((packed)) av_alias; +union unaligned_32 { uint32_t l; } __attribute__((packed)) av_alias; +union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; + +# define AV_RN(s, p) (((const union unaligned_##s *) (p))->l) +# define AV_WN(s, p, v) ((((union unaligned_##s *) (p))->l) = (v)) + +#elif defined(__DECC) + +# define AV_RN(s, p) (*((const __unaligned uint##s##_t*)(p))) +# define AV_WN(s, p, v) (*((__unaligned uint##s##_t*)(p)) = (v)) + +#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_X64)) && AV_HAVE_FAST_UNALIGNED + +# define AV_RN(s, p) (*((const __unaligned uint##s##_t*)(p))) +# define AV_WN(s, p, v) (*((__unaligned uint##s##_t*)(p)) = (v)) + +#elif AV_HAVE_FAST_UNALIGNED + +# define AV_RN(s, p) (((const av_alias##s*)(p))->u##s) +# define AV_WN(s, p, v) (((av_alias##s*)(p))->u##s = (v)) + +#else + +#ifndef AV_RB16 +# define AV_RB16(x) \ + ((((const uint8_t*)(x))[0] << 8) | \ + ((const uint8_t*)(x))[1]) +#endif +#ifndef AV_WB16 +# define AV_WB16(p, val) do { \ + uint16_t d = (val); \ + ((uint8_t*)(p))[1] = (d); \ + ((uint8_t*)(p))[0] = (d)>>8; \ + } while(0) +#endif + +#ifndef AV_RL16 +# define AV_RL16(x) \ + ((((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL16 +# define AV_WL16(p, val) do { \ + uint16_t d = (val); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + } while(0) +#endif + +#ifndef AV_RB32 +# define AV_RB32(x) \ + (((uint32_t)((const uint8_t*)(x))[0] << 24) | \ + (((const uint8_t*)(x))[1] << 16) | \ + (((const uint8_t*)(x))[2] << 8) | \ + ((const uint8_t*)(x))[3]) +#endif +#ifndef AV_WB32 +# define AV_WB32(p, val) do { \ + uint32_t d = (val); \ + ((uint8_t*)(p))[3] = (d); \ + ((uint8_t*)(p))[2] = (d)>>8; \ + ((uint8_t*)(p))[1] = (d)>>16; \ + ((uint8_t*)(p))[0] = (d)>>24; \ + } while(0) +#endif + +#ifndef AV_RL32 +# define AV_RL32(x) \ + (((uint32_t)((const uint8_t*)(x))[3] << 24) | \ + (((const uint8_t*)(x))[2] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL32 +# define AV_WL32(p, val) do { \ + uint32_t d = (val); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + } while(0) +#endif + +#ifndef AV_RB64 +# define AV_RB64(x) \ + (((uint64_t)((const uint8_t*)(x))[0] << 56) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 48) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[5] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[6] << 8) | \ + (uint64_t)((const uint8_t*)(x))[7]) +#endif +#ifndef AV_WB64 +# define AV_WB64(p, val) do { \ + uint64_t d = (val); \ + ((uint8_t*)(p))[7] = (d); \ + ((uint8_t*)(p))[6] = (d)>>8; \ + ((uint8_t*)(p))[5] = (d)>>16; \ + ((uint8_t*)(p))[4] = (d)>>24; \ + ((uint8_t*)(p))[3] = (d)>>32; \ + ((uint8_t*)(p))[2] = (d)>>40; \ + ((uint8_t*)(p))[1] = (d)>>48; \ + ((uint8_t*)(p))[0] = (d)>>56; \ + } while(0) +#endif + +#ifndef AV_RL64 +# define AV_RL64(x) \ + (((uint64_t)((const uint8_t*)(x))[7] << 56) | \ + ((uint64_t)((const uint8_t*)(x))[6] << 48) | \ + ((uint64_t)((const uint8_t*)(x))[5] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 8) | \ + (uint64_t)((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL64 +# define AV_WL64(p, val) do { \ + uint64_t d = (val); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + ((uint8_t*)(p))[4] = (d)>>32; \ + ((uint8_t*)(p))[5] = (d)>>40; \ + ((uint8_t*)(p))[6] = (d)>>48; \ + ((uint8_t*)(p))[7] = (d)>>56; \ + } while(0) +#endif + +#if AV_HAVE_BIGENDIAN +# define AV_RN(s, p) AV_RB##s(p) +# define AV_WN(s, p, v) AV_WB##s(p, v) +#else +# define AV_RN(s, p) AV_RL##s(p) +# define AV_WN(s, p, v) AV_WL##s(p, v) +#endif + +#endif /* HAVE_FAST_UNALIGNED */ + +#ifndef AV_RN16 +# define AV_RN16(p) AV_RN(16, p) +#endif + +#ifndef AV_RN32 +# define AV_RN32(p) AV_RN(32, p) +#endif + +#ifndef AV_RN64 +# define AV_RN64(p) AV_RN(64, p) +#endif + +#ifndef AV_WN16 +# define AV_WN16(p, v) AV_WN(16, p, v) +#endif + +#ifndef AV_WN32 +# define AV_WN32(p, v) AV_WN(32, p, v) +#endif + +#ifndef AV_WN64 +# define AV_WN64(p, v) AV_WN(64, p, v) +#endif + +#if AV_HAVE_BIGENDIAN +# define AV_RB(s, p) AV_RN##s(p) +# define AV_WB(s, p, v) AV_WN##s(p, v) +# define AV_RL(s, p) av_bswap##s(AV_RN##s(p)) +# define AV_WL(s, p, v) AV_WN##s(p, av_bswap##s(v)) +#else +# define AV_RB(s, p) av_bswap##s(AV_RN##s(p)) +# define AV_WB(s, p, v) AV_WN##s(p, av_bswap##s(v)) +# define AV_RL(s, p) AV_RN##s(p) +# define AV_WL(s, p, v) AV_WN##s(p, v) +#endif + +#define AV_RB8(x) (((const uint8_t*)(x))[0]) +#define AV_WB8(p, d) do { ((uint8_t*)(p))[0] = (d); } while(0) + +#define AV_RL8(x) AV_RB8(x) +#define AV_WL8(p, d) AV_WB8(p, d) + +#ifndef AV_RB16 +# define AV_RB16(p) AV_RB(16, p) +#endif +#ifndef AV_WB16 +# define AV_WB16(p, v) AV_WB(16, p, v) +#endif + +#ifndef AV_RL16 +# define AV_RL16(p) AV_RL(16, p) +#endif +#ifndef AV_WL16 +# define AV_WL16(p, v) AV_WL(16, p, v) +#endif + +#ifndef AV_RB32 +# define AV_RB32(p) AV_RB(32, p) +#endif +#ifndef AV_WB32 +# define AV_WB32(p, v) AV_WB(32, p, v) +#endif + +#ifndef AV_RL32 +# define AV_RL32(p) AV_RL(32, p) +#endif +#ifndef AV_WL32 +# define AV_WL32(p, v) AV_WL(32, p, v) +#endif + +#ifndef AV_RB64 +# define AV_RB64(p) AV_RB(64, p) +#endif +#ifndef AV_WB64 +# define AV_WB64(p, v) AV_WB(64, p, v) +#endif + +#ifndef AV_RL64 +# define AV_RL64(p) AV_RL(64, p) +#endif +#ifndef AV_WL64 +# define AV_WL64(p, v) AV_WL(64, p, v) +#endif + +#ifndef AV_RB24 +# define AV_RB24(x) \ + ((((const uint8_t*)(x))[0] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[2]) +#endif +#ifndef AV_WB24 +# define AV_WB24(p, d) do { \ + ((uint8_t*)(p))[2] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[0] = (d)>>16; \ + } while(0) +#endif + +#ifndef AV_RL24 +# define AV_RL24(x) \ + ((((const uint8_t*)(x))[2] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL24 +# define AV_WL24(p, d) do { \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + } while(0) +#endif + +#ifndef AV_RB48 +# define AV_RB48(x) \ + (((uint64_t)((const uint8_t*)(x))[0] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 8) | \ + (uint64_t)((const uint8_t*)(x))[5]) +#endif +#ifndef AV_WB48 +# define AV_WB48(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[5] = (d); \ + ((uint8_t*)(p))[4] = (d)>>8; \ + ((uint8_t*)(p))[3] = (d)>>16; \ + ((uint8_t*)(p))[2] = (d)>>24; \ + ((uint8_t*)(p))[1] = (d)>>32; \ + ((uint8_t*)(p))[0] = (d)>>40; \ + } while(0) +#endif + +#ifndef AV_RL48 +# define AV_RL48(x) \ + (((uint64_t)((const uint8_t*)(x))[5] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 8) | \ + (uint64_t)((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL48 +# define AV_WL48(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + ((uint8_t*)(p))[4] = (d)>>32; \ + ((uint8_t*)(p))[5] = (d)>>40; \ + } while(0) +#endif + +/* + * The AV_[RW]NA macros access naturally aligned data + * in a type-safe way. + */ + +#define AV_RNA(s, p) (((const av_alias##s*)(p))->u##s) +#define AV_WNA(s, p, v) (((av_alias##s*)(p))->u##s = (v)) + +#ifndef AV_RN16A +# define AV_RN16A(p) AV_RNA(16, p) +#endif + +#ifndef AV_RN32A +# define AV_RN32A(p) AV_RNA(32, p) +#endif + +#ifndef AV_RN64A +# define AV_RN64A(p) AV_RNA(64, p) +#endif + +#ifndef AV_WN16A +# define AV_WN16A(p, v) AV_WNA(16, p, v) +#endif + +#ifndef AV_WN32A +# define AV_WN32A(p, v) AV_WNA(32, p, v) +#endif + +#ifndef AV_WN64A +# define AV_WN64A(p, v) AV_WNA(64, p, v) +#endif + +/* + * The AV_COPYxxU macros are suitable for copying data to/from unaligned + * memory locations. + */ + +#define AV_COPYU(n, d, s) AV_WN##n(d, AV_RN##n(s)); + +#ifndef AV_COPY16U +# define AV_COPY16U(d, s) AV_COPYU(16, d, s) +#endif + +#ifndef AV_COPY32U +# define AV_COPY32U(d, s) AV_COPYU(32, d, s) +#endif + +#ifndef AV_COPY64U +# define AV_COPY64U(d, s) AV_COPYU(64, d, s) +#endif + +#ifndef AV_COPY128U +# define AV_COPY128U(d, s) \ + do { \ + AV_COPY64U(d, s); \ + AV_COPY64U((char *)(d) + 8, (const char *)(s) + 8); \ + } while(0) +#endif + +/* Parameters for AV_COPY*, AV_SWAP*, AV_ZERO* must be + * naturally aligned. They may be implemented using MMX, + * so emms_c() must be called before using any float code + * afterwards. + */ + +#define AV_COPY(n, d, s) \ + (((av_alias##n*)(d))->u##n = ((const av_alias##n*)(s))->u##n) + +#ifndef AV_COPY16 +# define AV_COPY16(d, s) AV_COPY(16, d, s) +#endif + +#ifndef AV_COPY32 +# define AV_COPY32(d, s) AV_COPY(32, d, s) +#endif + +#ifndef AV_COPY64 +# define AV_COPY64(d, s) AV_COPY(64, d, s) +#endif + +#ifndef AV_COPY128 +# define AV_COPY128(d, s) \ + do { \ + AV_COPY64(d, s); \ + AV_COPY64((char*)(d)+8, (char*)(s)+8); \ + } while(0) +#endif + +#define AV_SWAP(n, a, b) FFSWAP(av_alias##n, *(av_alias##n*)(a), *(av_alias##n*)(b)) + +#ifndef AV_SWAP64 +# define AV_SWAP64(a, b) AV_SWAP(64, a, b) +#endif + +#define AV_ZERO(n, d) (((av_alias##n*)(d))->u##n = 0) + +#ifndef AV_ZERO16 +# define AV_ZERO16(d) AV_ZERO(16, d) +#endif + +#ifndef AV_ZERO32 +# define AV_ZERO32(d) AV_ZERO(32, d) +#endif + +#ifndef AV_ZERO64 +# define AV_ZERO64(d) AV_ZERO(64, d) +#endif + +#ifndef AV_ZERO128 +# define AV_ZERO128(d) \ + do { \ + AV_ZERO64(d); \ + AV_ZERO64((char*)(d)+8); \ + } while(0) +#endif + +#endif /* AVUTIL_INTREADWRITE_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/lfg.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/lfg.h new file mode 100644 index 0000000..03f779a --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/lfg.h @@ -0,0 +1,71 @@ +/* + * Lagged Fibonacci PRNG + * Copyright (c) 2008 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LFG_H +#define AVUTIL_LFG_H + +#include + +typedef struct AVLFG { + unsigned int state[64]; + int index; +} AVLFG; + +void av_lfg_init(AVLFG *c, unsigned int seed); + +/** + * Seed the state of the ALFG using binary data. + * + * Return value: 0 on success, negative value (AVERROR) on failure. + */ +int av_lfg_init_from_data(AVLFG *c, const uint8_t *data, unsigned int length); + +/** + * Get the next random unsigned 32-bit number using an ALFG. + * + * Please also consider a simple LCG like state= state*1664525+1013904223, + * it may be good enough and faster for your specific use case. + */ +static inline unsigned int av_lfg_get(AVLFG *c){ + c->state[c->index & 63] = c->state[(c->index-24) & 63] + c->state[(c->index-55) & 63]; + return c->state[c->index++ & 63]; +} + +/** + * Get the next random unsigned 32-bit number using a MLFG. + * + * Please also consider av_lfg_get() above, it is faster. + */ +static inline unsigned int av_mlfg_get(AVLFG *c){ + unsigned int a= c->state[(c->index-55) & 63]; + unsigned int b= c->state[(c->index-24) & 63]; + return c->state[c->index++ & 63] = 2*a*b+a+b; +} + +/** + * Get the next two numbers generated by a Box-Muller Gaussian + * generator using the random numbers issued by lfg. + * + * @param out array where the two generated numbers are placed + */ +void av_bmg_get(AVLFG *lfg, double out[2]); + +#endif /* AVUTIL_LFG_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/log.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/log.h new file mode 100644 index 0000000..f0a5738 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/log.h @@ -0,0 +1,376 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LOG_H +#define AVUTIL_LOG_H + +#include +#include "avutil.h" +#include "attributes.h" +#include "version.h" + +typedef enum { + AV_CLASS_CATEGORY_NA = 0, + AV_CLASS_CATEGORY_INPUT, + AV_CLASS_CATEGORY_OUTPUT, + AV_CLASS_CATEGORY_MUXER, + AV_CLASS_CATEGORY_DEMUXER, + AV_CLASS_CATEGORY_ENCODER, + AV_CLASS_CATEGORY_DECODER, + AV_CLASS_CATEGORY_FILTER, + AV_CLASS_CATEGORY_BITSTREAM_FILTER, + AV_CLASS_CATEGORY_SWSCALER, + AV_CLASS_CATEGORY_SWRESAMPLER, + AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT = 40, + AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT, + AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT, + AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT, + AV_CLASS_CATEGORY_DEVICE_OUTPUT, + AV_CLASS_CATEGORY_DEVICE_INPUT, + AV_CLASS_CATEGORY_NB ///< not part of ABI/API +}AVClassCategory; + +#define AV_IS_INPUT_DEVICE(category) \ + (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_INPUT)) + +#define AV_IS_OUTPUT_DEVICE(category) \ + (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_OUTPUT)) + +struct AVOptionRanges; + +/** + * Describe the class of an AVClass context structure. That is an + * arbitrary struct of which the first field is a pointer to an + * AVClass struct (e.g. AVCodecContext, AVFormatContext etc.). + */ +typedef struct AVClass { + /** + * The name of the class; usually it is the same name as the + * context structure type to which the AVClass is associated. + */ + const char* class_name; + + /** + * A pointer to a function which returns the name of a context + * instance ctx associated with the class. + */ + const char* (*item_name)(void* ctx); + + /** + * a pointer to the first option specified in the class if any or NULL + * + * @see av_set_default_options() + */ + const struct AVOption *option; + + /** + * LIBAVUTIL_VERSION with which this structure was created. + * This is used to allow fields to be added without requiring major + * version bumps everywhere. + */ + + int version; + + /** + * Offset in the structure where log_level_offset is stored. + * 0 means there is no such variable + */ + int log_level_offset_offset; + + /** + * Offset in the structure where a pointer to the parent context for + * logging is stored. For example a decoder could pass its AVCodecContext + * to eval as such a parent context, which an av_log() implementation + * could then leverage to display the parent context. + * The offset can be NULL. + */ + int parent_log_context_offset; + + /** + * Return next AVOptions-enabled child or NULL + */ + void* (*child_next)(void *obj, void *prev); + + /** + * Return an AVClass corresponding to the next potential + * AVOptions-enabled child. + * + * The difference between child_next and this is that + * child_next iterates over _already existing_ objects, while + * child_class_next iterates over _all possible_ children. + */ + const struct AVClass* (*child_class_next)(const struct AVClass *prev); + + /** + * Category used for visualization (like color) + * This is only set if the category is equal for all objects using this class. + * available since version (51 << 16 | 56 << 8 | 100) + */ + AVClassCategory category; + + /** + * Callback to return the category. + * available since version (51 << 16 | 59 << 8 | 100) + */ + AVClassCategory (*get_category)(void* ctx); + + /** + * Callback to return the supported/allowed ranges. + * available since version (52.12) + */ + int (*query_ranges)(struct AVOptionRanges **, void *obj, const char *key, int flags); +} AVClass; + +/** + * @addtogroup lavu_log + * + * @{ + * + * @defgroup lavu_log_constants Logging Constants + * + * @{ + */ + +/** + * Print no output. + */ +#define AV_LOG_QUIET -8 + +/** + * Something went really wrong and we will crash now. + */ +#define AV_LOG_PANIC 0 + +/** + * Something went wrong and recovery is not possible. + * For example, no header was found for a format which depends + * on headers or an illegal combination of parameters is used. + */ +#define AV_LOG_FATAL 8 + +/** + * Something went wrong and cannot losslessly be recovered. + * However, not all future data is affected. + */ +#define AV_LOG_ERROR 16 + +/** + * Something somehow does not look correct. This may or may not + * lead to problems. An example would be the use of '-vstrict -2'. + */ +#define AV_LOG_WARNING 24 + +/** + * Standard information. + */ +#define AV_LOG_INFO 32 + +/** + * Detailed information. + */ +#define AV_LOG_VERBOSE 40 + +/** + * Stuff which is only useful for libav* developers. + */ +#define AV_LOG_DEBUG 48 + +/** + * Extremely verbose debugging, useful for libav* development. + */ +#define AV_LOG_TRACE 56 + +#define AV_LOG_MAX_OFFSET (AV_LOG_TRACE - AV_LOG_QUIET) + +/** + * @} + */ + +/** + * Sets additional colors for extended debugging sessions. + * @code + av_log(ctx, AV_LOG_DEBUG|AV_LOG_C(134), "Message in purple\n"); + @endcode + * Requires 256color terminal support. Uses outside debugging is not + * recommended. + */ +#define AV_LOG_C(x) ((x) << 8) + +/** + * Send the specified message to the log if the level is less than or equal + * to the current av_log_level. By default, all logging messages are sent to + * stderr. This behavior can be altered by setting a different logging callback + * function. + * @see av_log_set_callback + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct or NULL if general log. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + */ +void av_log(void *avcl, int level, const char *fmt, ...) av_printf_format(3, 4); + + +/** + * Send the specified message to the log if the level is less than or equal + * to the current av_log_level. By default, all logging messages are sent to + * stderr. This behavior can be altered by setting a different logging callback + * function. + * @see av_log_set_callback + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + * @param vl The arguments referenced by the format string. + */ +void av_vlog(void *avcl, int level, const char *fmt, va_list vl); + +/** + * Get the current log level + * + * @see lavu_log_constants + * + * @return Current log level + */ +int av_log_get_level(void); + +/** + * Set the log level + * + * @see lavu_log_constants + * + * @param level Logging level + */ +void av_log_set_level(int level); + +/** + * Set the logging callback + * + * @note The callback must be thread safe, even if the application does not use + * threads itself as some codecs are multithreaded. + * + * @see av_log_default_callback + * + * @param callback A logging function with a compatible signature. + */ +void av_log_set_callback(void (*callback)(void*, int, const char*, va_list)); + +/** + * Default logging callback + * + * It prints the message to stderr, optionally colorizing it. + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + * @param vl The arguments referenced by the format string. + */ +void av_log_default_callback(void *avcl, int level, const char *fmt, + va_list vl); + +/** + * Return the context name + * + * @param ctx The AVClass context + * + * @return The AVClass class_name + */ +const char* av_default_item_name(void* ctx); +AVClassCategory av_default_get_category(void *ptr); + +/** + * Format a line of log the same way as the default callback. + * @param line buffer to receive the formatted line + * @param line_size size of the buffer + * @param print_prefix used to store whether the prefix must be printed; + * must point to a persistent integer initially set to 1 + */ +void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl, + char *line, int line_size, int *print_prefix); + +/** + * Format a line of log the same way as the default callback. + * @param line buffer to receive the formatted line; + * may be NULL if line_size is 0 + * @param line_size size of the buffer; at most line_size-1 characters will + * be written to the buffer, plus one null terminator + * @param print_prefix used to store whether the prefix must be printed; + * must point to a persistent integer initially set to 1 + * @return Returns a negative value if an error occurred, otherwise returns + * the number of characters that would have been written for a + * sufficiently large buffer, not including the terminating null + * character. If the return value is not less than line_size, it means + * that the log message was truncated to fit the buffer. + */ +int av_log_format_line2(void *ptr, int level, const char *fmt, va_list vl, + char *line, int line_size, int *print_prefix); + +#if FF_API_DLOG +/** + * av_dlog macros + * @deprecated unused + * Useful to print debug messages that shouldn't get compiled in normally. + */ + +#ifdef DEBUG +# define av_dlog(pctx, ...) av_log(pctx, AV_LOG_DEBUG, __VA_ARGS__) +#else +# define av_dlog(pctx, ...) do { if (0) av_log(pctx, AV_LOG_DEBUG, __VA_ARGS__); } while (0) +#endif +#endif /* FF_API_DLOG */ + +/** + * Skip repeated messages, this requires the user app to use av_log() instead of + * (f)printf as the 2 would otherwise interfere and lead to + * "Last message repeated x times" messages below (f)printf messages with some + * bad luck. + * Also to receive the last, "last repeated" line if any, the user app must + * call av_log(NULL, AV_LOG_QUIET, "%s", ""); at the end + */ +#define AV_LOG_SKIP_REPEATED 1 + +/** + * Include the log severity in messages originating from codecs. + * + * Results in messages such as: + * [rawvideo @ 0xDEADBEEF] [error] encode did not produce valid pts + */ +#define AV_LOG_PRINT_LEVEL 2 + +void av_log_set_flags(int arg); +int av_log_get_flags(void); + +/** + * @} + */ + +#endif /* AVUTIL_LOG_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/lzo.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/lzo.h new file mode 100644 index 0000000..c034039 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/lzo.h @@ -0,0 +1,66 @@ +/* + * LZO 1x decompression + * copyright (c) 2006 Reimar Doeffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LZO_H +#define AVUTIL_LZO_H + +/** + * @defgroup lavu_lzo LZO + * @ingroup lavu_crypto + * + * @{ + */ + +#include + +/** @name Error flags returned by av_lzo1x_decode + * @{ */ +/// end of the input buffer reached before decoding finished +#define AV_LZO_INPUT_DEPLETED 1 +/// decoded data did not fit into output buffer +#define AV_LZO_OUTPUT_FULL 2 +/// a reference to previously decoded data was wrong +#define AV_LZO_INVALID_BACKPTR 4 +/// a non-specific error in the compressed bitstream +#define AV_LZO_ERROR 8 +/** @} */ + +#define AV_LZO_INPUT_PADDING 8 +#define AV_LZO_OUTPUT_PADDING 12 + +/** + * @brief Decodes LZO 1x compressed data. + * @param out output buffer + * @param outlen size of output buffer, number of bytes left are returned here + * @param in input buffer + * @param inlen size of input buffer, number of bytes left are returned here + * @return 0 on success, otherwise a combination of the error flags above + * + * Make sure all buffers are appropriately padded, in must provide + * AV_LZO_INPUT_PADDING, out must provide AV_LZO_OUTPUT_PADDING additional bytes. + */ +int av_lzo1x_decode(void *out, int *outlen, const void *in, int *inlen); + +/** + * @} + */ + +#endif /* AVUTIL_LZO_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/macros.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/macros.h new file mode 100644 index 0000000..2007ee5 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/macros.h @@ -0,0 +1,50 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu + * Utility Preprocessor macros + */ + +#ifndef AVUTIL_MACROS_H +#define AVUTIL_MACROS_H + +/** + * @addtogroup preproc_misc Preprocessor String Macros + * + * String manipulation macros + * + * @{ + */ + +#define AV_STRINGIFY(s) AV_TOSTRING(s) +#define AV_TOSTRING(s) #s + +#define AV_GLUE(a, b) a ## b +#define AV_JOIN(a, b) AV_GLUE(a, b) + +/** + * @} + */ + +#define AV_PRAGMA(s) _Pragma(#s) + +#define FFALIGN(x, a) (((x)+(a)-1)&~((a)-1)) + +#endif /* AVUTIL_MACROS_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/mastering_display_metadata.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/mastering_display_metadata.h new file mode 100644 index 0000000..936533f --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/mastering_display_metadata.h @@ -0,0 +1,89 @@ +/** + * Copyright (c) 2016 Neil Birkbeck + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MASTERING_DISPLAY_METADATA_H +#define AVUTIL_MASTERING_DISPLAY_METADATA_H + +#include "frame.h" +#include "rational.h" + + +/** + * Mastering display metadata capable of representing the color volume of + * the display used to master the content (SMPTE 2086:2014). + * + * To be used as payload of a AVFrameSideData or AVPacketSideData with the + * appropriate type. + * + * @note The struct should be allocated with av_mastering_display_metadata_alloc() + * and its size is not a part of the public ABI. + */ +typedef struct AVMasteringDisplayMetadata { + /** + * CIE 1931 xy chromaticity coords of color primaries (r, g, b order). + */ + AVRational display_primaries[3][2]; + + /** + * CIE 1931 xy chromaticity coords of white point. + */ + AVRational white_point[2]; + + /** + * Min luminance of mastering display (cd/m^2). + */ + AVRational min_luminance; + + /** + * Max luminance of mastering display (cd/m^2). + */ + AVRational max_luminance; + + /** + * Flag indicating whether the display primaries (and white point) are set. + */ + int has_primaries; + + /** + * Flag indicating whether the luminance (min_ and max_) have been set. + */ + int has_luminance; + +} AVMasteringDisplayMetadata; + +/** + * Allocate an AVMasteringDisplayMetadata structure and set its fields to + * default values. The resulting struct can be freed using av_freep(). + * + * @return An AVMasteringDisplayMetadata filled with default values or NULL + * on failure. + */ +AVMasteringDisplayMetadata *av_mastering_display_metadata_alloc(void); + +/** + * Allocate a complete AVMasteringDisplayMetadata and add it to the frame. + * + * @param frame The frame which side data is added to. + * + * @return The AVMasteringDisplayMetadata structure to be filled by caller. + */ +AVMasteringDisplayMetadata *av_mastering_display_metadata_create_side_data(AVFrame *frame); + +#endif /* AVUTIL_MASTERING_DISPLAY_METADATA_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/mathematics.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/mathematics.h new file mode 100644 index 0000000..5490180 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/mathematics.h @@ -0,0 +1,242 @@ +/* + * copyright (c) 2005-2012 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @addtogroup lavu_math + * Mathematical utilities for working with timestamp and time base. + */ + +#ifndef AVUTIL_MATHEMATICS_H +#define AVUTIL_MATHEMATICS_H + +#include +#include +#include "attributes.h" +#include "rational.h" +#include "intfloat.h" + +#ifndef M_E +#define M_E 2.7182818284590452354 /* e */ +#endif +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 /* log_e 2 */ +#endif +#ifndef M_LN10 +#define M_LN10 2.30258509299404568402 /* log_e 10 */ +#endif +#ifndef M_LOG2_10 +#define M_LOG2_10 3.32192809488736234787 /* log_2 10 */ +#endif +#ifndef M_PHI +#define M_PHI 1.61803398874989484820 /* phi / golden ratio */ +#endif +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* pi */ +#endif +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923 /* pi/2 */ +#endif +#ifndef M_SQRT1_2 +#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ +#endif +#ifndef M_SQRT2 +#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ +#endif +#ifndef NAN +#define NAN av_int2float(0x7fc00000) +#endif +#ifndef INFINITY +#define INFINITY av_int2float(0x7f800000) +#endif + +/** + * @addtogroup lavu_math + * + * @{ + */ + +/** + * Rounding methods. + */ +enum AVRounding { + AV_ROUND_ZERO = 0, ///< Round toward zero. + AV_ROUND_INF = 1, ///< Round away from zero. + AV_ROUND_DOWN = 2, ///< Round toward -infinity. + AV_ROUND_UP = 3, ///< Round toward +infinity. + AV_ROUND_NEAR_INF = 5, ///< Round to nearest and halfway cases away from zero. + /** + * Flag telling rescaling functions to pass `INT64_MIN`/`MAX` through + * unchanged, avoiding special cases for #AV_NOPTS_VALUE. + * + * Unlike other values of the enumeration AVRounding, this value is a + * bitmask that must be used in conjunction with another value of the + * enumeration through a bitwise OR, in order to set behavior for normal + * cases. + * + * @code{.c} + * av_rescale_rnd(3, 1, 2, AV_ROUND_UP | AV_ROUND_PASS_MINMAX); + * // Rescaling 3: + * // Calculating 3 * 1 / 2 + * // 3 / 2 is rounded up to 2 + * // => 2 + * + * av_rescale_rnd(AV_NOPTS_VALUE, 1, 2, AV_ROUND_UP | AV_ROUND_PASS_MINMAX); + * // Rescaling AV_NOPTS_VALUE: + * // AV_NOPTS_VALUE == INT64_MIN + * // AV_NOPTS_VALUE is passed through + * // => AV_NOPTS_VALUE + * @endcode + */ + AV_ROUND_PASS_MINMAX = 8192, +}; + +/** + * Compute the greatest common divisor of two integer operands. + * + * @param a,b Operands + * @return GCD of a and b up to sign; if a >= 0 and b >= 0, return value is >= 0; + * if a == 0 and b == 0, returns 0. + */ +int64_t av_const av_gcd(int64_t a, int64_t b); + +/** + * Rescale a 64-bit integer with rounding to nearest. + * + * The operation is mathematically equivalent to `a * b / c`, but writing that + * directly can overflow. + * + * This function is equivalent to av_rescale_rnd() with #AV_ROUND_NEAR_INF. + * + * @see av_rescale_rnd(), av_rescale_q(), av_rescale_q_rnd() + */ +int64_t av_rescale(int64_t a, int64_t b, int64_t c) av_const; + +/** + * Rescale a 64-bit integer with specified rounding. + * + * The operation is mathematically equivalent to `a * b / c`, but writing that + * directly can overflow, and does not support different rounding methods. + * + * @see av_rescale(), av_rescale_q(), av_rescale_q_rnd() + */ +int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd) av_const; + +/** + * Rescale a 64-bit integer by 2 rational numbers. + * + * The operation is mathematically equivalent to `a * bq / cq`. + * + * This function is equivalent to av_rescale_q_rnd() with #AV_ROUND_NEAR_INF. + * + * @see av_rescale(), av_rescale_rnd(), av_rescale_q_rnd() + */ +int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const; + +/** + * Rescale a 64-bit integer by 2 rational numbers with specified rounding. + * + * The operation is mathematically equivalent to `a * bq / cq`. + * + * @see av_rescale(), av_rescale_rnd(), av_rescale_q() + */ +int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq, + enum AVRounding rnd) av_const; + +/** + * Compare two timestamps each in its own time base. + * + * @return One of the following values: + * - -1 if `ts_a` is before `ts_b` + * - 1 if `ts_a` is after `ts_b` + * - 0 if they represent the same position + * + * @warning + * The result of the function is undefined if one of the timestamps is outside + * the `int64_t` range when represented in the other's timebase. + */ +int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b); + +/** + * Compare the remainders of two integer operands divided by a common divisor. + * + * In other words, compare the least significant `log2(mod)` bits of integers + * `a` and `b`. + * + * @code{.c} + * av_compare_mod(0x11, 0x02, 0x10) < 0 // since 0x11 % 0x10 (0x1) < 0x02 % 0x10 (0x2) + * av_compare_mod(0x11, 0x02, 0x20) > 0 // since 0x11 % 0x20 (0x11) > 0x02 % 0x20 (0x02) + * @endcode + * + * @param a,b Operands + * @param mod Divisor; must be a power of 2 + * @return + * - a negative value if `a % mod < b % mod` + * - a positive value if `a % mod > b % mod` + * - zero if `a % mod == b % mod` + */ +int64_t av_compare_mod(uint64_t a, uint64_t b, uint64_t mod); + +/** + * Rescale a timestamp while preserving known durations. + * + * This function is designed to be called per audio packet to scale the input + * timestamp to a different time base. Compared to a simple av_rescale_q() + * call, this function is robust against possible inconsistent frame durations. + * + * The `last` parameter is a state variable that must be preserved for all + * subsequent calls for the same stream. For the first call, `*last` should be + * initialized to #AV_NOPTS_VALUE. + * + * @param[in] in_tb Input time base + * @param[in] in_ts Input timestamp + * @param[in] fs_tb Duration time base; typically this is finer-grained + * (greater) than `in_tb` and `out_tb` + * @param[in] duration Duration till the next call to this function (i.e. + * duration of the current packet/frame) + * @param[in,out] last Pointer to a timestamp expressed in terms of + * `fs_tb`, acting as a state variable + * @param[in] out_tb Output timebase + * @return Timestamp expressed in terms of `out_tb` + * + * @note In the context of this function, "duration" is in term of samples, not + * seconds. + */ +int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb); + +/** + * Add a value to a timestamp. + * + * This function guarantees that when the same value is repeatly added that + * no accumulation of rounding errors occurs. + * + * @param[in] ts Input timestamp + * @param[in] ts_tb Input timestamp time base + * @param[in] inc Value to be added + * @param[in] inc_tb Time base of `inc` + */ +int64_t av_add_stable(AVRational ts_tb, int64_t ts, AVRational inc_tb, int64_t inc); + + +/** + * @} + */ + +#endif /* AVUTIL_MATHEMATICS_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/md5.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/md5.h new file mode 100644 index 0000000..9571c1f --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/md5.h @@ -0,0 +1,89 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_md5 + * Public header for MD5 hash function implementation. + */ + +#ifndef AVUTIL_MD5_H +#define AVUTIL_MD5_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_md5 MD5 + * @ingroup lavu_hash + * MD5 hash function implementation. + * + * @{ + */ + +extern const int av_md5_size; + +struct AVMD5; + +/** + * Allocate an AVMD5 context. + */ +struct AVMD5 *av_md5_alloc(void); + +/** + * Initialize MD5 hashing. + * + * @param ctx pointer to the function context (of size av_md5_size) + */ +void av_md5_init(struct AVMD5 *ctx); + +/** + * Update hash value. + * + * @param ctx hash function context + * @param src input data to update hash with + * @param len input data length + */ +void av_md5_update(struct AVMD5 *ctx, const uint8_t *src, int len); + +/** + * Finish hashing and output digest value. + * + * @param ctx hash function context + * @param dst buffer where output digest value is stored + */ +void av_md5_final(struct AVMD5 *ctx, uint8_t *dst); + +/** + * Hash an array of data. + * + * @param dst The output buffer to write the digest into + * @param src The data to hash + * @param len The length of the data, in bytes + */ +void av_md5_sum(uint8_t *dst, const uint8_t *src, const int len); + +/** + * @} + */ + +#endif /* AVUTIL_MD5_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/mem.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/mem.h new file mode 100644 index 0000000..527cd03 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/mem.h @@ -0,0 +1,699 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_mem + * Memory handling functions + */ + +#ifndef AVUTIL_MEM_H +#define AVUTIL_MEM_H + +#include +#include + +#include "attributes.h" +#include "error.h" +#include "avutil.h" + +/** + * @addtogroup lavu_mem + * Utilities for manipulating memory. + * + * FFmpeg has several applications of memory that are not required of a typical + * program. For example, the computing-heavy components like video decoding and + * encoding can be sped up significantly through the use of aligned memory. + * + * However, for each of FFmpeg's applications of memory, there might not be a + * recognized or standardized API for that specific use. Memory alignment, for + * instance, varies wildly depending on operating systems, architectures, and + * compilers. Hence, this component of @ref libavutil is created to make + * dealing with memory consistently possible on all platforms. + * + * @{ + * + * @defgroup lavu_mem_macros Alignment Macros + * Helper macros for declaring aligned variables. + * @{ + */ + +/** + * @def DECLARE_ALIGNED(n,t,v) + * Declare a variable that is aligned in memory. + * + * @code{.c} + * DECLARE_ALIGNED(16, uint16_t, aligned_int) = 42; + * DECLARE_ALIGNED(32, uint8_t, aligned_array)[128]; + * + * // The default-alignment equivalent would be + * uint16_t aligned_int = 42; + * uint8_t aligned_array[128]; + * @endcode + * + * @param n Minimum alignment in bytes + * @param t Type of the variable (or array element) + * @param v Name of the variable + */ + +/** + * @def DECLARE_ASM_CONST(n,t,v) + * Declare a static constant aligned variable appropriate for use in inline + * assembly code. + * + * @code{.c} + * DECLARE_ASM_CONST(16, uint64_t, pw_08) = UINT64_C(0x0008000800080008); + * @endcode + * + * @param n Minimum alignment in bytes + * @param t Type of the variable (or array element) + * @param v Name of the variable + */ + +#if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 1110 || defined(__SUNPRO_C) + #define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v + #define DECLARE_ASM_CONST(n,t,v) const t __attribute__ ((aligned (n))) v +#elif defined(__TI_COMPILER_VERSION__) + #define DECLARE_ALIGNED(n,t,v) \ + AV_PRAGMA(DATA_ALIGN(v,n)) \ + t __attribute__((aligned(n))) v + #define DECLARE_ASM_CONST(n,t,v) \ + AV_PRAGMA(DATA_ALIGN(v,n)) \ + static const t __attribute__((aligned(n))) v +#elif defined(__DJGPP__) + #define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (FFMIN(n, 16)))) v + #define DECLARE_ASM_CONST(n,t,v) static const t av_used __attribute__ ((aligned (FFMIN(n, 16)))) v +#elif defined(__GNUC__) || defined(__clang__) + #define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v + #define DECLARE_ASM_CONST(n,t,v) static const t av_used __attribute__ ((aligned (n))) v +#elif defined(_MSC_VER) + #define DECLARE_ALIGNED(n,t,v) __declspec(align(n)) t v + #define DECLARE_ASM_CONST(n,t,v) __declspec(align(n)) static const t v +#else + #define DECLARE_ALIGNED(n,t,v) t v + #define DECLARE_ASM_CONST(n,t,v) static const t v +#endif + +/** + * @} + */ + +/** + * @defgroup lavu_mem_attrs Function Attributes + * Function attributes applicable to memory handling functions. + * + * These function attributes can help compilers emit more useful warnings, or + * generate better code. + * @{ + */ + +/** + * @def av_malloc_attrib + * Function attribute denoting a malloc-like function. + * + * @see Function attribute `malloc` in GCC's documentation + */ + +#if AV_GCC_VERSION_AT_LEAST(3,1) + #define av_malloc_attrib __attribute__((__malloc__)) +#else + #define av_malloc_attrib +#endif + +/** + * @def av_alloc_size(...) + * Function attribute used on a function that allocates memory, whose size is + * given by the specified parameter(s). + * + * @code{.c} + * void *av_malloc(size_t size) av_alloc_size(1); + * void *av_calloc(size_t nmemb, size_t size) av_alloc_size(1, 2); + * @endcode + * + * @param ... One or two parameter indexes, separated by a comma + * + * @see Function attribute `alloc_size` in GCC's documentation + */ + +#if AV_GCC_VERSION_AT_LEAST(4,3) + #define av_alloc_size(...) __attribute__((alloc_size(__VA_ARGS__))) +#else + #define av_alloc_size(...) +#endif + +/** + * @} + */ + +/** + * @defgroup lavu_mem_funcs Heap Management + * Functions responsible for allocating, freeing, and copying memory. + * + * All memory allocation functions have a built-in upper limit of `INT_MAX` + * bytes. This may be changed with av_max_alloc(), although exercise extreme + * caution when doing so. + * + * @{ + */ + +/** + * Allocate a memory block with alignment suitable for all memory accesses + * (including vectors if available on the CPU). + * + * @param size Size in bytes for the memory block to be allocated + * @return Pointer to the allocated block, or `NULL` if the block cannot + * be allocated + * @see av_mallocz() + */ +void *av_malloc(size_t size) av_malloc_attrib av_alloc_size(1); + +/** + * Allocate a memory block with alignment suitable for all memory accesses + * (including vectors if available on the CPU) and zero all the bytes of the + * block. + * + * @param size Size in bytes for the memory block to be allocated + * @return Pointer to the allocated block, or `NULL` if it cannot be allocated + * @see av_malloc() + */ +void *av_mallocz(size_t size) av_malloc_attrib av_alloc_size(1); + +/** + * Allocate a memory block for an array with av_malloc(). + * + * The allocated memory will have size `size * nmemb` bytes. + * + * @param nmemb Number of element + * @param size Size of a single element + * @return Pointer to the allocated block, or `NULL` if the block cannot + * be allocated + * @see av_malloc() + */ +av_alloc_size(1, 2) static inline void *av_malloc_array(size_t nmemb, size_t size) +{ + if (!size || nmemb >= INT_MAX / size) + return NULL; + return av_malloc(nmemb * size); +} + +/** + * Allocate a memory block for an array with av_mallocz(). + * + * The allocated memory will have size `size * nmemb` bytes. + * + * @param nmemb Number of elements + * @param size Size of the single element + * @return Pointer to the allocated block, or `NULL` if the block cannot + * be allocated + * + * @see av_mallocz() + * @see av_malloc_array() + */ +av_alloc_size(1, 2) static inline void *av_mallocz_array(size_t nmemb, size_t size) +{ + if (!size || nmemb >= INT_MAX / size) + return NULL; + return av_mallocz(nmemb * size); +} + +/** + * Non-inlined equivalent of av_mallocz_array(). + * + * Created for symmetry with the calloc() C function. + */ +void *av_calloc(size_t nmemb, size_t size) av_malloc_attrib; + +/** + * Allocate, reallocate, or free a block of memory. + * + * If `ptr` is `NULL` and `size` > 0, allocate a new block. If `size` is + * zero, free the memory block pointed to by `ptr`. Otherwise, expand or + * shrink that block of memory according to `size`. + * + * @param ptr Pointer to a memory block already allocated with + * av_realloc() or `NULL` + * @param size Size in bytes of the memory block to be allocated or + * reallocated + * + * @return Pointer to a newly-reallocated block or `NULL` if the block + * cannot be reallocated or the function is used to free the memory block + * + * @warning Unlike av_malloc(), the returned pointer is not guaranteed to be + * correctly aligned. + * @see av_fast_realloc() + * @see av_reallocp() + */ +void *av_realloc(void *ptr, size_t size) av_alloc_size(2); + +/** + * Allocate, reallocate, or free a block of memory through a pointer to a + * pointer. + * + * If `*ptr` is `NULL` and `size` > 0, allocate a new block. If `size` is + * zero, free the memory block pointed to by `*ptr`. Otherwise, expand or + * shrink that block of memory according to `size`. + * + * @param[in,out] ptr Pointer to a pointer to a memory block already allocated + * with av_realloc(), or a pointer to `NULL`. The pointer + * is updated on success, or freed on failure. + * @param[in] size Size in bytes for the memory block to be allocated or + * reallocated + * + * @return Zero on success, an AVERROR error code on failure + * + * @warning Unlike av_malloc(), the allocated memory is not guaranteed to be + * correctly aligned. + */ +av_warn_unused_result +int av_reallocp(void *ptr, size_t size); + +/** + * Allocate, reallocate, or free a block of memory. + * + * This function does the same thing as av_realloc(), except: + * - It takes two size arguments and allocates `nelem * elsize` bytes, + * after checking the result of the multiplication for integer overflow. + * - It frees the input block in case of failure, thus avoiding the memory + * leak with the classic + * @code{.c} + * buf = realloc(buf); + * if (!buf) + * return -1; + * @endcode + * pattern. + */ +void *av_realloc_f(void *ptr, size_t nelem, size_t elsize); + +/** + * Allocate, reallocate, or free an array. + * + * If `ptr` is `NULL` and `nmemb` > 0, allocate a new block. If + * `nmemb` is zero, free the memory block pointed to by `ptr`. + * + * @param ptr Pointer to a memory block already allocated with + * av_realloc() or `NULL` + * @param nmemb Number of elements in the array + * @param size Size of the single element of the array + * + * @return Pointer to a newly-reallocated block or NULL if the block + * cannot be reallocated or the function is used to free the memory block + * + * @warning Unlike av_malloc(), the allocated memory is not guaranteed to be + * correctly aligned. + * @see av_reallocp_array() + */ +av_alloc_size(2, 3) void *av_realloc_array(void *ptr, size_t nmemb, size_t size); + +/** + * Allocate, reallocate, or free an array through a pointer to a pointer. + * + * If `*ptr` is `NULL` and `nmemb` > 0, allocate a new block. If `nmemb` is + * zero, free the memory block pointed to by `*ptr`. + * + * @param[in,out] ptr Pointer to a pointer to a memory block already + * allocated with av_realloc(), or a pointer to `NULL`. + * The pointer is updated on success, or freed on failure. + * @param[in] nmemb Number of elements + * @param[in] size Size of the single element + * + * @return Zero on success, an AVERROR error code on failure + * + * @warning Unlike av_malloc(), the allocated memory is not guaranteed to be + * correctly aligned. + */ +av_alloc_size(2, 3) int av_reallocp_array(void *ptr, size_t nmemb, size_t size); + +/** + * Reallocate the given buffer if it is not large enough, otherwise do nothing. + * + * If the given buffer is `NULL`, then a new uninitialized buffer is allocated. + * + * If the given buffer is not large enough, and reallocation fails, `NULL` is + * returned and `*size` is set to 0, but the original buffer is not changed or + * freed. + * + * A typical use pattern follows: + * + * @code{.c} + * uint8_t *buf = ...; + * uint8_t *new_buf = av_fast_realloc(buf, ¤t_size, size_needed); + * if (!new_buf) { + * // Allocation failed; clean up original buffer + * av_freep(&buf); + * return AVERROR(ENOMEM); + * } + * @endcode + * + * @param[in,out] ptr Already allocated buffer, or `NULL` + * @param[in,out] size Pointer to current size of buffer `ptr`. `*size` is + * changed to `min_size` in case of success or 0 in + * case of failure + * @param[in] min_size New size of buffer `ptr` + * @return `ptr` if the buffer is large enough, a pointer to newly reallocated + * buffer if the buffer was not large enough, or `NULL` in case of + * error + * @see av_realloc() + * @see av_fast_malloc() + */ +void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size); + +/** + * Allocate a buffer, reusing the given one if large enough. + * + * Contrary to av_fast_realloc(), the current buffer contents might not be + * preserved and on error the old buffer is freed, thus no special handling to + * avoid memleaks is necessary. + * + * `*ptr` is allowed to be `NULL`, in which case allocation always happens if + * `size_needed` is greater than 0. + * + * @code{.c} + * uint8_t *buf = ...; + * av_fast_malloc(&buf, ¤t_size, size_needed); + * if (!buf) { + * // Allocation failed; buf already freed + * return AVERROR(ENOMEM); + * } + * @endcode + * + * @param[in,out] ptr Pointer to pointer to an already allocated buffer. + * `*ptr` will be overwritten with pointer to new + * buffer on success or `NULL` on failure + * @param[in,out] size Pointer to current size of buffer `*ptr`. `*size` is + * changed to `min_size` in case of success or 0 in + * case of failure + * @param[in] min_size New size of buffer `*ptr` + * @see av_realloc() + * @see av_fast_mallocz() + */ +void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size); + +/** + * Allocate and clear a buffer, reusing the given one if large enough. + * + * Like av_fast_malloc(), but all newly allocated space is initially cleared. + * Reused buffer is not cleared. + * + * `*ptr` is allowed to be `NULL`, in which case allocation always happens if + * `size_needed` is greater than 0. + * + * @param[in,out] ptr Pointer to pointer to an already allocated buffer. + * `*ptr` will be overwritten with pointer to new + * buffer on success or `NULL` on failure + * @param[in,out] size Pointer to current size of buffer `*ptr`. `*size` is + * changed to `min_size` in case of success or 0 in + * case of failure + * @param[in] min_size New size of buffer `*ptr` + * @see av_fast_malloc() + */ +void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size); + +/** + * Free a memory block which has been allocated with a function of av_malloc() + * or av_realloc() family. + * + * @param ptr Pointer to the memory block which should be freed. + * + * @note `ptr = NULL` is explicitly allowed. + * @note It is recommended that you use av_freep() instead, to prevent leaving + * behind dangling pointers. + * @see av_freep() + */ +void av_free(void *ptr); + +/** + * Free a memory block which has been allocated with a function of av_malloc() + * or av_realloc() family, and set the pointer pointing to it to `NULL`. + * + * @code{.c} + * uint8_t *buf = av_malloc(16); + * av_free(buf); + * // buf now contains a dangling pointer to freed memory, and accidental + * // dereference of buf will result in a use-after-free, which may be a + * // security risk. + * + * uint8_t *buf = av_malloc(16); + * av_freep(&buf); + * // buf is now NULL, and accidental dereference will only result in a + * // NULL-pointer dereference. + * @endcode + * + * @param ptr Pointer to the pointer to the memory block which should be freed + * @note `*ptr = NULL` is safe and leads to no action. + * @see av_free() + */ +void av_freep(void *ptr); + +/** + * Duplicate a string. + * + * @param s String to be duplicated + * @return Pointer to a newly-allocated string containing a + * copy of `s` or `NULL` if the string cannot be allocated + * @see av_strndup() + */ +char *av_strdup(const char *s) av_malloc_attrib; + +/** + * Duplicate a substring of a string. + * + * @param s String to be duplicated + * @param len Maximum length of the resulting string (not counting the + * terminating byte) + * @return Pointer to a newly-allocated string containing a + * substring of `s` or `NULL` if the string cannot be allocated + */ +char *av_strndup(const char *s, size_t len) av_malloc_attrib; + +/** + * Duplicate a buffer with av_malloc(). + * + * @param p Buffer to be duplicated + * @param size Size in bytes of the buffer copied + * @return Pointer to a newly allocated buffer containing a + * copy of `p` or `NULL` if the buffer cannot be allocated + */ +void *av_memdup(const void *p, size_t size); + +/** + * Overlapping memcpy() implementation. + * + * @param dst Destination buffer + * @param back Number of bytes back to start copying (i.e. the initial size of + * the overlapping window); must be > 0 + * @param cnt Number of bytes to copy; must be >= 0 + * + * @note `cnt > back` is valid, this will copy the bytes we just copied, + * thus creating a repeating pattern with a period length of `back`. + */ +void av_memcpy_backptr(uint8_t *dst, int back, int cnt); + +/** + * @} + */ + +/** + * @defgroup lavu_mem_dynarray Dynamic Array + * + * Utilities to make an array grow when needed. + * + * Sometimes, the programmer would want to have an array that can grow when + * needed. The libavutil dynamic array utilities fill that need. + * + * libavutil supports two systems of appending elements onto a dynamically + * allocated array, the first one storing the pointer to the value in the + * array, and the second storing the value directly. In both systems, the + * caller is responsible for maintaining a variable containing the length of + * the array, as well as freeing of the array after use. + * + * The first system stores pointers to values in a block of dynamically + * allocated memory. Since only pointers are stored, the function does not need + * to know the size of the type. Both av_dynarray_add() and + * av_dynarray_add_nofree() implement this system. + * + * @code + * type **array = NULL; //< an array of pointers to values + * int nb = 0; //< a variable to keep track of the length of the array + * + * type to_be_added = ...; + * type to_be_added2 = ...; + * + * av_dynarray_add(&array, &nb, &to_be_added); + * if (nb == 0) + * return AVERROR(ENOMEM); + * + * av_dynarray_add(&array, &nb, &to_be_added2); + * if (nb == 0) + * return AVERROR(ENOMEM); + * + * // Now: + * // nb == 2 + * // &to_be_added == array[0] + * // &to_be_added2 == array[1] + * + * av_freep(&array); + * @endcode + * + * The second system stores the value directly in a block of memory. As a + * result, the function has to know the size of the type. av_dynarray2_add() + * implements this mechanism. + * + * @code + * type *array = NULL; //< an array of values + * int nb = 0; //< a variable to keep track of the length of the array + * + * type to_be_added = ...; + * type to_be_added2 = ...; + * + * type *addr = av_dynarray2_add((void **)&array, &nb, sizeof(*array), NULL); + * if (!addr) + * return AVERROR(ENOMEM); + * memcpy(addr, &to_be_added, sizeof(to_be_added)); + * + * // Shortcut of the above. + * type *addr = av_dynarray2_add((void **)&array, &nb, sizeof(*array), + * (const void *)&to_be_added2); + * if (!addr) + * return AVERROR(ENOMEM); + * + * // Now: + * // nb == 2 + * // to_be_added == array[0] + * // to_be_added2 == array[1] + * + * av_freep(&array); + * @endcode + * + * @{ + */ + +/** + * Add the pointer to an element to a dynamic array. + * + * The array to grow is supposed to be an array of pointers to + * structures, and the element to add must be a pointer to an already + * allocated structure. + * + * The array is reallocated when its size reaches powers of 2. + * Therefore, the amortized cost of adding an element is constant. + * + * In case of success, the pointer to the array is updated in order to + * point to the new grown array, and the number pointed to by `nb_ptr` + * is incremented. + * In case of failure, the array is freed, `*tab_ptr` is set to `NULL` and + * `*nb_ptr` is set to 0. + * + * @param[in,out] tab_ptr Pointer to the array to grow + * @param[in,out] nb_ptr Pointer to the number of elements in the array + * @param[in] elem Element to add + * @see av_dynarray_add_nofree(), av_dynarray2_add() + */ +void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem); + +/** + * Add an element to a dynamic array. + * + * Function has the same functionality as av_dynarray_add(), + * but it doesn't free memory on fails. It returns error code + * instead and leave current buffer untouched. + * + * @return >=0 on success, negative otherwise + * @see av_dynarray_add(), av_dynarray2_add() + */ +av_warn_unused_result +int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem); + +/** + * Add an element of size `elem_size` to a dynamic array. + * + * The array is reallocated when its number of elements reaches powers of 2. + * Therefore, the amortized cost of adding an element is constant. + * + * In case of success, the pointer to the array is updated in order to + * point to the new grown array, and the number pointed to by `nb_ptr` + * is incremented. + * In case of failure, the array is freed, `*tab_ptr` is set to `NULL` and + * `*nb_ptr` is set to 0. + * + * @param[in,out] tab_ptr Pointer to the array to grow + * @param[in,out] nb_ptr Pointer to the number of elements in the array + * @param[in] elem_size Size in bytes of an element in the array + * @param[in] elem_data Pointer to the data of the element to add. If + * `NULL`, the space of the newly added element is + * allocated but left uninitialized. + * + * @return Pointer to the data of the element to copy in the newly allocated + * space + * @see av_dynarray_add(), av_dynarray_add_nofree() + */ +void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, + const uint8_t *elem_data); + +/** + * @} + */ + +/** + * @defgroup lavu_mem_misc Miscellaneous Functions + * + * Other functions related to memory allocation. + * + * @{ + */ + +/** + * Multiply two `size_t` values checking for overflow. + * + * @param[in] a,b Operands of multiplication + * @param[out] r Pointer to the result of the operation + * @return 0 on success, AVERROR(EINVAL) on overflow + */ +static inline int av_size_mult(size_t a, size_t b, size_t *r) +{ + size_t t = a * b; + /* Hack inspired from glibc: don't try the division if nelem and elsize + * are both less than sqrt(SIZE_MAX). */ + if ((a | b) >= ((size_t)1 << (sizeof(size_t) * 4)) && a && t / a != b) + return AVERROR(EINVAL); + *r = t; + return 0; +} + +/** + * Set the maximum size that may be allocated in one block. + * + * The value specified with this function is effective for all libavutil's @ref + * lavu_mem_funcs "heap management functions." + * + * By default, the max value is defined as `INT_MAX`. + * + * @param max Value to be set as the new maximum size + * + * @warning Exercise extreme caution when using this function. Don't touch + * this if you do not understand the full consequence of doing so. + */ +void av_max_alloc(size_t max); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_MEM_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/motion_vector.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/motion_vector.h new file mode 100644 index 0000000..ec29556 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/motion_vector.h @@ -0,0 +1,57 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MOTION_VECTOR_H +#define AVUTIL_MOTION_VECTOR_H + +#include + +typedef struct AVMotionVector { + /** + * Where the current macroblock comes from; negative value when it comes + * from the past, positive value when it comes from the future. + * XXX: set exact relative ref frame reference instead of a +/- 1 "direction". + */ + int32_t source; + /** + * Width and height of the block. + */ + uint8_t w, h; + /** + * Absolute source position. Can be outside the frame area. + */ + int16_t src_x, src_y; + /** + * Absolute destination position. Can be outside the frame area. + */ + int16_t dst_x, dst_y; + /** + * Extra flag information. + * Currently unused. + */ + uint64_t flags; + /** + * Motion vector + * src_x = dst_x + motion_x / motion_scale + * src_y = dst_y + motion_y / motion_scale + */ + int32_t motion_x, motion_y; + uint16_t motion_scale; +} AVMotionVector; + +#endif /* AVUTIL_MOTION_VECTOR_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/murmur3.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/murmur3.h new file mode 100644 index 0000000..6a1694c --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/murmur3.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2013 Reimar Döffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_murmur3 + * Public header for MurmurHash3 hash function implementation. + */ + +#ifndef AVUTIL_MURMUR3_H +#define AVUTIL_MURMUR3_H + +#include + +/** + * @defgroup lavu_murmur3 Murmur3 + * @ingroup lavu_hash + * MurmurHash3 hash function implementation. + * + * MurmurHash3 is a non-cryptographic hash function, of which three + * incompatible versions were created by its inventor Austin Appleby: + * + * - 32-bit output + * - 128-bit output for 32-bit platforms + * - 128-bit output for 64-bit platforms + * + * FFmpeg only implements the last variant: 128-bit output designed for 64-bit + * platforms. Even though the hash function was designed for 64-bit platforms, + * the function in reality works on 32-bit systems too, only with reduced + * performance. + * + * @anchor lavu_murmur3_seedinfo + * By design, MurmurHash3 requires a seed to operate. In response to this, + * libavutil provides two functions for hash initiation, one that requires a + * seed (av_murmur3_init_seeded()) and one that uses a fixed arbitrary integer + * as the seed, and therefore does not (av_murmur3_init()). + * + * To make hashes comparable, you should provide the same seed for all calls to + * this hash function -- if you are supplying one yourself, that is. + * + * @{ + */ + +/** + * Allocate an AVMurMur3 hash context. + * + * @return Uninitialized hash context or `NULL` in case of error + */ +struct AVMurMur3 *av_murmur3_alloc(void); + +/** + * Initialize or reinitialize an AVMurMur3 hash context with a seed. + * + * @param[out] c Hash context + * @param[in] seed Random seed + * + * @see av_murmur3_init() + * @see @ref lavu_murmur3_seedinfo "Detailed description" on a discussion of + * seeds for MurmurHash3. + */ +void av_murmur3_init_seeded(struct AVMurMur3 *c, uint64_t seed); + +/** + * Initialize or reinitialize an AVMurMur3 hash context. + * + * Equivalent to av_murmur3_init_seeded() with a built-in seed. + * + * @param[out] c Hash context + * + * @see av_murmur3_init_seeded() + * @see @ref lavu_murmur3_seedinfo "Detailed description" on a discussion of + * seeds for MurmurHash3. + */ +void av_murmur3_init(struct AVMurMur3 *c); + +/** + * Update hash context with new data. + * + * @param[out] c Hash context + * @param[in] src Input data to update hash with + * @param[in] len Number of bytes to read from `src` + */ +void av_murmur3_update(struct AVMurMur3 *c, const uint8_t *src, int len); + +/** + * Finish hashing and output digest value. + * + * @param[in,out] c Hash context + * @param[out] dst Buffer where output digest value is stored + */ +void av_murmur3_final(struct AVMurMur3 *c, uint8_t dst[16]); + +/** + * @} + */ + +#endif /* AVUTIL_MURMUR3_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/opt.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/opt.h new file mode 100644 index 0000000..0d89379 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/opt.h @@ -0,0 +1,866 @@ +/* + * AVOptions + * copyright (c) 2005 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_OPT_H +#define AVUTIL_OPT_H + +/** + * @file + * AVOptions + */ + +#include "rational.h" +#include "avutil.h" +#include "dict.h" +#include "log.h" +#include "pixfmt.h" +#include "samplefmt.h" +#include "version.h" + +/** + * @defgroup avoptions AVOptions + * @ingroup lavu_data + * @{ + * AVOptions provide a generic system to declare options on arbitrary structs + * ("objects"). An option can have a help text, a type and a range of possible + * values. Options may then be enumerated, read and written to. + * + * @section avoptions_implement Implementing AVOptions + * This section describes how to add AVOptions capabilities to a struct. + * + * All AVOptions-related information is stored in an AVClass. Therefore + * the first member of the struct should be a pointer to an AVClass describing it. + * The option field of the AVClass must be set to a NULL-terminated static array + * of AVOptions. Each AVOption must have a non-empty name, a type, a default + * value and for number-type AVOptions also a range of allowed values. It must + * also declare an offset in bytes from the start of the struct, where the field + * associated with this AVOption is located. Other fields in the AVOption struct + * should also be set when applicable, but are not required. + * + * The following example illustrates an AVOptions-enabled struct: + * @code + * typedef struct test_struct { + * const AVClass *class; + * int int_opt; + * char *str_opt; + * uint8_t *bin_opt; + * int bin_len; + * } test_struct; + * + * static const AVOption test_options[] = { + * { "test_int", "This is a test option of int type.", offsetof(test_struct, int_opt), + * AV_OPT_TYPE_INT, { .i64 = -1 }, INT_MIN, INT_MAX }, + * { "test_str", "This is a test option of string type.", offsetof(test_struct, str_opt), + * AV_OPT_TYPE_STRING }, + * { "test_bin", "This is a test option of binary type.", offsetof(test_struct, bin_opt), + * AV_OPT_TYPE_BINARY }, + * { NULL }, + * }; + * + * static const AVClass test_class = { + * .class_name = "test class", + * .item_name = av_default_item_name, + * .option = test_options, + * .version = LIBAVUTIL_VERSION_INT, + * }; + * @endcode + * + * Next, when allocating your struct, you must ensure that the AVClass pointer + * is set to the correct value. Then, av_opt_set_defaults() can be called to + * initialize defaults. After that the struct is ready to be used with the + * AVOptions API. + * + * When cleaning up, you may use the av_opt_free() function to automatically + * free all the allocated string and binary options. + * + * Continuing with the above example: + * + * @code + * test_struct *alloc_test_struct(void) + * { + * test_struct *ret = av_mallocz(sizeof(*ret)); + * ret->class = &test_class; + * av_opt_set_defaults(ret); + * return ret; + * } + * void free_test_struct(test_struct **foo) + * { + * av_opt_free(*foo); + * av_freep(foo); + * } + * @endcode + * + * @subsection avoptions_implement_nesting Nesting + * It may happen that an AVOptions-enabled struct contains another + * AVOptions-enabled struct as a member (e.g. AVCodecContext in + * libavcodec exports generic options, while its priv_data field exports + * codec-specific options). In such a case, it is possible to set up the + * parent struct to export a child's options. To do that, simply + * implement AVClass.child_next() and AVClass.child_class_next() in the + * parent struct's AVClass. + * Assuming that the test_struct from above now also contains a + * child_struct field: + * + * @code + * typedef struct child_struct { + * AVClass *class; + * int flags_opt; + * } child_struct; + * static const AVOption child_opts[] = { + * { "test_flags", "This is a test option of flags type.", + * offsetof(child_struct, flags_opt), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT_MIN, INT_MAX }, + * { NULL }, + * }; + * static const AVClass child_class = { + * .class_name = "child class", + * .item_name = av_default_item_name, + * .option = child_opts, + * .version = LIBAVUTIL_VERSION_INT, + * }; + * + * void *child_next(void *obj, void *prev) + * { + * test_struct *t = obj; + * if (!prev && t->child_struct) + * return t->child_struct; + * return NULL + * } + * const AVClass child_class_next(const AVClass *prev) + * { + * return prev ? NULL : &child_class; + * } + * @endcode + * Putting child_next() and child_class_next() as defined above into + * test_class will now make child_struct's options accessible through + * test_struct (again, proper setup as described above needs to be done on + * child_struct right after it is created). + * + * From the above example it might not be clear why both child_next() + * and child_class_next() are needed. The distinction is that child_next() + * iterates over actually existing objects, while child_class_next() + * iterates over all possible child classes. E.g. if an AVCodecContext + * was initialized to use a codec which has private options, then its + * child_next() will return AVCodecContext.priv_data and finish + * iterating. OTOH child_class_next() on AVCodecContext.av_class will + * iterate over all available codecs with private options. + * + * @subsection avoptions_implement_named_constants Named constants + * It is possible to create named constants for options. Simply set the unit + * field of the option the constants should apply to a string and + * create the constants themselves as options of type AV_OPT_TYPE_CONST + * with their unit field set to the same string. + * Their default_val field should contain the value of the named + * constant. + * For example, to add some named constants for the test_flags option + * above, put the following into the child_opts array: + * @code + * { "test_flags", "This is a test option of flags type.", + * offsetof(child_struct, flags_opt), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT_MIN, INT_MAX, "test_unit" }, + * { "flag1", "This is a flag with value 16", 0, AV_OPT_TYPE_CONST, { .i64 = 16 }, 0, 0, "test_unit" }, + * @endcode + * + * @section avoptions_use Using AVOptions + * This section deals with accessing options in an AVOptions-enabled struct. + * Such structs in FFmpeg are e.g. AVCodecContext in libavcodec or + * AVFormatContext in libavformat. + * + * @subsection avoptions_use_examine Examining AVOptions + * The basic functions for examining options are av_opt_next(), which iterates + * over all options defined for one object, and av_opt_find(), which searches + * for an option with the given name. + * + * The situation is more complicated with nesting. An AVOptions-enabled struct + * may have AVOptions-enabled children. Passing the AV_OPT_SEARCH_CHILDREN flag + * to av_opt_find() will make the function search children recursively. + * + * For enumerating there are basically two cases. The first is when you want to + * get all options that may potentially exist on the struct and its children + * (e.g. when constructing documentation). In that case you should call + * av_opt_child_class_next() recursively on the parent struct's AVClass. The + * second case is when you have an already initialized struct with all its + * children and you want to get all options that can be actually written or read + * from it. In that case you should call av_opt_child_next() recursively (and + * av_opt_next() on each result). + * + * @subsection avoptions_use_get_set Reading and writing AVOptions + * When setting options, you often have a string read directly from the + * user. In such a case, simply passing it to av_opt_set() is enough. For + * non-string type options, av_opt_set() will parse the string according to the + * option type. + * + * Similarly av_opt_get() will read any option type and convert it to a string + * which will be returned. Do not forget that the string is allocated, so you + * have to free it with av_free(). + * + * In some cases it may be more convenient to put all options into an + * AVDictionary and call av_opt_set_dict() on it. A specific case of this + * are the format/codec open functions in lavf/lavc which take a dictionary + * filled with option as a parameter. This makes it possible to set some options + * that cannot be set otherwise, since e.g. the input file format is not known + * before the file is actually opened. + */ + +enum AVOptionType{ + AV_OPT_TYPE_FLAGS, + AV_OPT_TYPE_INT, + AV_OPT_TYPE_INT64, + AV_OPT_TYPE_DOUBLE, + AV_OPT_TYPE_FLOAT, + AV_OPT_TYPE_STRING, + AV_OPT_TYPE_RATIONAL, + AV_OPT_TYPE_BINARY, ///< offset must point to a pointer immediately followed by an int for the length + AV_OPT_TYPE_DICT, + AV_OPT_TYPE_UINT64, + AV_OPT_TYPE_CONST = 128, + AV_OPT_TYPE_IMAGE_SIZE = MKBETAG('S','I','Z','E'), ///< offset must point to two consecutive integers + AV_OPT_TYPE_PIXEL_FMT = MKBETAG('P','F','M','T'), + AV_OPT_TYPE_SAMPLE_FMT = MKBETAG('S','F','M','T'), + AV_OPT_TYPE_VIDEO_RATE = MKBETAG('V','R','A','T'), ///< offset must point to AVRational + AV_OPT_TYPE_DURATION = MKBETAG('D','U','R',' '), + AV_OPT_TYPE_COLOR = MKBETAG('C','O','L','R'), + AV_OPT_TYPE_CHANNEL_LAYOUT = MKBETAG('C','H','L','A'), + AV_OPT_TYPE_BOOL = MKBETAG('B','O','O','L'), +}; + +/** + * AVOption + */ +typedef struct AVOption { + const char *name; + + /** + * short English help text + * @todo What about other languages? + */ + const char *help; + + /** + * The offset relative to the context structure where the option + * value is stored. It should be 0 for named constants. + */ + int offset; + enum AVOptionType type; + + /** + * the default value for scalar options + */ + union { + int64_t i64; + double dbl; + const char *str; + /* TODO those are unused now */ + AVRational q; + } default_val; + double min; ///< minimum valid value for the option + double max; ///< maximum valid value for the option + + int flags; +#define AV_OPT_FLAG_ENCODING_PARAM 1 ///< a generic parameter which can be set by the user for muxing or encoding +#define AV_OPT_FLAG_DECODING_PARAM 2 ///< a generic parameter which can be set by the user for demuxing or decoding +#if FF_API_OPT_TYPE_METADATA +#define AV_OPT_FLAG_METADATA 4 ///< some data extracted or inserted into the file like title, comment, ... +#endif +#define AV_OPT_FLAG_AUDIO_PARAM 8 +#define AV_OPT_FLAG_VIDEO_PARAM 16 +#define AV_OPT_FLAG_SUBTITLE_PARAM 32 +/** + * The option is intended for exporting values to the caller. + */ +#define AV_OPT_FLAG_EXPORT 64 +/** + * The option may not be set through the AVOptions API, only read. + * This flag only makes sense when AV_OPT_FLAG_EXPORT is also set. + */ +#define AV_OPT_FLAG_READONLY 128 +#define AV_OPT_FLAG_FILTERING_PARAM (1<<16) ///< a generic parameter which can be set by the user for filtering +//FIXME think about enc-audio, ... style flags + + /** + * The logical unit to which the option belongs. Non-constant + * options and corresponding named constants share the same + * unit. May be NULL. + */ + const char *unit; +} AVOption; + +/** + * A single allowed range of values, or a single allowed value. + */ +typedef struct AVOptionRange { + const char *str; + /** + * Value range. + * For string ranges this represents the min/max length. + * For dimensions this represents the min/max pixel count or width/height in multi-component case. + */ + double value_min, value_max; + /** + * Value's component range. + * For string this represents the unicode range for chars, 0-127 limits to ASCII. + */ + double component_min, component_max; + /** + * Range flag. + * If set to 1 the struct encodes a range, if set to 0 a single value. + */ + int is_range; +} AVOptionRange; + +/** + * List of AVOptionRange structs. + */ +typedef struct AVOptionRanges { + /** + * Array of option ranges. + * + * Most of option types use just one component. + * Following describes multi-component option types: + * + * AV_OPT_TYPE_IMAGE_SIZE: + * component index 0: range of pixel count (width * height). + * component index 1: range of width. + * component index 2: range of height. + * + * @note To obtain multi-component version of this structure, user must + * provide AV_OPT_MULTI_COMPONENT_RANGE to av_opt_query_ranges or + * av_opt_query_ranges_default function. + * + * Multi-component range can be read as in following example: + * + * @code + * int range_index, component_index; + * AVOptionRanges *ranges; + * AVOptionRange *range[3]; //may require more than 3 in the future. + * av_opt_query_ranges(&ranges, obj, key, AV_OPT_MULTI_COMPONENT_RANGE); + * for (range_index = 0; range_index < ranges->nb_ranges; range_index++) { + * for (component_index = 0; component_index < ranges->nb_components; component_index++) + * range[component_index] = ranges->range[ranges->nb_ranges * component_index + range_index]; + * //do something with range here. + * } + * av_opt_freep_ranges(&ranges); + * @endcode + */ + AVOptionRange **range; + /** + * Number of ranges per component. + */ + int nb_ranges; + /** + * Number of componentes. + */ + int nb_components; +} AVOptionRanges; + +/** + * Show the obj options. + * + * @param req_flags requested flags for the options to show. Show only the + * options for which it is opt->flags & req_flags. + * @param rej_flags rejected flags for the options to show. Show only the + * options for which it is !(opt->flags & req_flags). + * @param av_log_obj log context to use for showing the options + */ +int av_opt_show2(void *obj, void *av_log_obj, int req_flags, int rej_flags); + +/** + * Set the values of all AVOption fields to their default values. + * + * @param s an AVOption-enabled struct (its first member must be a pointer to AVClass) + */ +void av_opt_set_defaults(void *s); + +/** + * Set the values of all AVOption fields to their default values. Only these + * AVOption fields for which (opt->flags & mask) == flags will have their + * default applied to s. + * + * @param s an AVOption-enabled struct (its first member must be a pointer to AVClass) + * @param mask combination of AV_OPT_FLAG_* + * @param flags combination of AV_OPT_FLAG_* + */ +void av_opt_set_defaults2(void *s, int mask, int flags); + +/** + * Parse the key/value pairs list in opts. For each key/value pair + * found, stores the value in the field in ctx that is named like the + * key. ctx must be an AVClass context, storing is done using + * AVOptions. + * + * @param opts options string to parse, may be NULL + * @param key_val_sep a 0-terminated list of characters used to + * separate key from value + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other + * @return the number of successfully set key/value pairs, or a negative + * value corresponding to an AVERROR code in case of error: + * AVERROR(EINVAL) if opts cannot be parsed, + * the error code issued by av_opt_set() if a key/value pair + * cannot be set + */ +int av_set_options_string(void *ctx, const char *opts, + const char *key_val_sep, const char *pairs_sep); + +/** + * Parse the key-value pairs list in opts. For each key=value pair found, + * set the value of the corresponding option in ctx. + * + * @param ctx the AVClass object to set options on + * @param opts the options string, key-value pairs separated by a + * delimiter + * @param shorthand a NULL-terminated array of options names for shorthand + * notation: if the first field in opts has no key part, + * the key is taken from the first element of shorthand; + * then again for the second, etc., until either opts is + * finished, shorthand is finished or a named option is + * found; after that, all options must be named + * @param key_val_sep a 0-terminated list of characters used to separate + * key from value, for example '=' + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other, for example ':' or ',' + * @return the number of successfully set key=value pairs, or a negative + * value corresponding to an AVERROR code in case of error: + * AVERROR(EINVAL) if opts cannot be parsed, + * the error code issued by av_set_string3() if a key/value pair + * cannot be set + * + * Options names must use only the following characters: a-z A-Z 0-9 - . / _ + * Separators must use characters distinct from option names and from each + * other. + */ +int av_opt_set_from_string(void *ctx, const char *opts, + const char *const *shorthand, + const char *key_val_sep, const char *pairs_sep); +/** + * Free all allocated objects in obj. + */ +void av_opt_free(void *obj); + +/** + * Check whether a particular flag is set in a flags field. + * + * @param field_name the name of the flag field option + * @param flag_name the name of the flag to check + * @return non-zero if the flag is set, zero if the flag isn't set, + * isn't of the right type, or the flags field doesn't exist. + */ +int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name); + +/** + * Set all the options from a given dictionary on an object. + * + * @param obj a struct whose first element is a pointer to AVClass + * @param options options to process. This dictionary will be freed and replaced + * by a new one containing all options not found in obj. + * Of course this new dictionary needs to be freed by caller + * with av_dict_free(). + * + * @return 0 on success, a negative AVERROR if some option was found in obj, + * but could not be set. + * + * @see av_dict_copy() + */ +int av_opt_set_dict(void *obj, struct AVDictionary **options); + + +/** + * Set all the options from a given dictionary on an object. + * + * @param obj a struct whose first element is a pointer to AVClass + * @param options options to process. This dictionary will be freed and replaced + * by a new one containing all options not found in obj. + * Of course this new dictionary needs to be freed by caller + * with av_dict_free(). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * + * @return 0 on success, a negative AVERROR if some option was found in obj, + * but could not be set. + * + * @see av_dict_copy() + */ +int av_opt_set_dict2(void *obj, struct AVDictionary **options, int search_flags); + +/** + * Extract a key-value pair from the beginning of a string. + * + * @param ropts pointer to the options string, will be updated to + * point to the rest of the string (one of the pairs_sep + * or the final NUL) + * @param key_val_sep a 0-terminated list of characters used to separate + * key from value, for example '=' + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other, for example ':' or ',' + * @param flags flags; see the AV_OPT_FLAG_* values below + * @param rkey parsed key; must be freed using av_free() + * @param rval parsed value; must be freed using av_free() + * + * @return >=0 for success, or a negative value corresponding to an + * AVERROR code in case of error; in particular: + * AVERROR(EINVAL) if no key is present + * + */ +int av_opt_get_key_value(const char **ropts, + const char *key_val_sep, const char *pairs_sep, + unsigned flags, + char **rkey, char **rval); + +enum { + + /** + * Accept to parse a value without a key; the key will then be returned + * as NULL. + */ + AV_OPT_FLAG_IMPLICIT_KEY = 1, +}; + +/** + * @defgroup opt_eval_funcs Evaluating option strings + * @{ + * This group of functions can be used to evaluate option strings + * and get numbers out of them. They do the same thing as av_opt_set(), + * except the result is written into the caller-supplied pointer. + * + * @param obj a struct whose first element is a pointer to AVClass. + * @param o an option for which the string is to be evaluated. + * @param val string to be evaluated. + * @param *_out value of the string will be written here. + * + * @return 0 on success, a negative number on failure. + */ +int av_opt_eval_flags (void *obj, const AVOption *o, const char *val, int *flags_out); +int av_opt_eval_int (void *obj, const AVOption *o, const char *val, int *int_out); +int av_opt_eval_int64 (void *obj, const AVOption *o, const char *val, int64_t *int64_out); +int av_opt_eval_float (void *obj, const AVOption *o, const char *val, float *float_out); +int av_opt_eval_double(void *obj, const AVOption *o, const char *val, double *double_out); +int av_opt_eval_q (void *obj, const AVOption *o, const char *val, AVRational *q_out); +/** + * @} + */ + +#define AV_OPT_SEARCH_CHILDREN (1 << 0) /**< Search in possible children of the + given object first. */ +/** + * The obj passed to av_opt_find() is fake -- only a double pointer to AVClass + * instead of a required pointer to a struct containing AVClass. This is + * useful for searching for options without needing to allocate the corresponding + * object. + */ +#define AV_OPT_SEARCH_FAKE_OBJ (1 << 1) + +/** + * In av_opt_get, return NULL if the option has a pointer type and is set to NULL, + * rather than returning an empty string. + */ +#define AV_OPT_ALLOW_NULL (1 << 2) + +/** + * Allows av_opt_query_ranges and av_opt_query_ranges_default to return more than + * one component for certain option types. + * @see AVOptionRanges for details. + */ +#define AV_OPT_MULTI_COMPONENT_RANGE (1 << 12) + +/** + * Look for an option in an object. Consider only options which + * have all the specified flags set. + * + * @param[in] obj A pointer to a struct whose first element is a + * pointer to an AVClass. + * Alternatively a double pointer to an AVClass, if + * AV_OPT_SEARCH_FAKE_OBJ search flag is set. + * @param[in] name The name of the option to look for. + * @param[in] unit When searching for named constants, name of the unit + * it belongs to. + * @param opt_flags Find only options with all the specified flags set (AV_OPT_FLAG). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * + * @return A pointer to the option found, or NULL if no option + * was found. + * + * @note Options found with AV_OPT_SEARCH_CHILDREN flag may not be settable + * directly with av_opt_set(). Use special calls which take an options + * AVDictionary (e.g. avformat_open_input()) to set options found with this + * flag. + */ +const AVOption *av_opt_find(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags); + +/** + * Look for an option in an object. Consider only options which + * have all the specified flags set. + * + * @param[in] obj A pointer to a struct whose first element is a + * pointer to an AVClass. + * Alternatively a double pointer to an AVClass, if + * AV_OPT_SEARCH_FAKE_OBJ search flag is set. + * @param[in] name The name of the option to look for. + * @param[in] unit When searching for named constants, name of the unit + * it belongs to. + * @param opt_flags Find only options with all the specified flags set (AV_OPT_FLAG). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * @param[out] target_obj if non-NULL, an object to which the option belongs will be + * written here. It may be different from obj if AV_OPT_SEARCH_CHILDREN is present + * in search_flags. This parameter is ignored if search_flags contain + * AV_OPT_SEARCH_FAKE_OBJ. + * + * @return A pointer to the option found, or NULL if no option + * was found. + */ +const AVOption *av_opt_find2(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags, void **target_obj); + +/** + * Iterate over all AVOptions belonging to obj. + * + * @param obj an AVOptions-enabled struct or a double pointer to an + * AVClass describing it. + * @param prev result of the previous call to av_opt_next() on this object + * or NULL + * @return next AVOption or NULL + */ +const AVOption *av_opt_next(const void *obj, const AVOption *prev); + +/** + * Iterate over AVOptions-enabled children of obj. + * + * @param prev result of a previous call to this function or NULL + * @return next AVOptions-enabled child or NULL + */ +void *av_opt_child_next(void *obj, void *prev); + +/** + * Iterate over potential AVOptions-enabled children of parent. + * + * @param prev result of a previous call to this function or NULL + * @return AVClass corresponding to next potential child or NULL + */ +const AVClass *av_opt_child_class_next(const AVClass *parent, const AVClass *prev); + +/** + * @defgroup opt_set_funcs Option setting functions + * @{ + * Those functions set the field of obj with the given name to value. + * + * @param[in] obj A struct whose first element is a pointer to an AVClass. + * @param[in] name the name of the field to set + * @param[in] val The value to set. In case of av_opt_set() if the field is not + * of a string type, then the given string is parsed. + * SI postfixes and some named scalars are supported. + * If the field is of a numeric type, it has to be a numeric or named + * scalar. Behavior with more than one scalar and +- infix operators + * is undefined. + * If the field is of a flags type, it has to be a sequence of numeric + * scalars or named flags separated by '+' or '-'. Prefixing a flag + * with '+' causes it to be set without affecting the other flags; + * similarly, '-' unsets a flag. + * @param search_flags flags passed to av_opt_find2. I.e. if AV_OPT_SEARCH_CHILDREN + * is passed here, then the option may be set on a child of obj. + * + * @return 0 if the value has been set, or an AVERROR code in case of + * error: + * AVERROR_OPTION_NOT_FOUND if no matching option exists + * AVERROR(ERANGE) if the value is out of range + * AVERROR(EINVAL) if the value is not valid + */ +int av_opt_set (void *obj, const char *name, const char *val, int search_flags); +int av_opt_set_int (void *obj, const char *name, int64_t val, int search_flags); +int av_opt_set_double (void *obj, const char *name, double val, int search_flags); +int av_opt_set_q (void *obj, const char *name, AVRational val, int search_flags); +int av_opt_set_bin (void *obj, const char *name, const uint8_t *val, int size, int search_flags); +int av_opt_set_image_size(void *obj, const char *name, int w, int h, int search_flags); +int av_opt_set_pixel_fmt (void *obj, const char *name, enum AVPixelFormat fmt, int search_flags); +int av_opt_set_sample_fmt(void *obj, const char *name, enum AVSampleFormat fmt, int search_flags); +int av_opt_set_video_rate(void *obj, const char *name, AVRational val, int search_flags); +int av_opt_set_channel_layout(void *obj, const char *name, int64_t ch_layout, int search_flags); +/** + * @note Any old dictionary present is discarded and replaced with a copy of the new one. The + * caller still owns val is and responsible for freeing it. + */ +int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val, int search_flags); + +/** + * Set a binary option to an integer list. + * + * @param obj AVClass object to set options on + * @param name name of the binary option + * @param val pointer to an integer list (must have the correct type with + * regard to the contents of the list) + * @param term list terminator (usually 0 or -1) + * @param flags search flags + */ +#define av_opt_set_int_list(obj, name, val, term, flags) \ + (av_int_list_length(val, term) > INT_MAX / sizeof(*(val)) ? \ + AVERROR(EINVAL) : \ + av_opt_set_bin(obj, name, (const uint8_t *)(val), \ + av_int_list_length(val, term) * sizeof(*(val)), flags)) + +/** + * @} + */ + +/** + * @defgroup opt_get_funcs Option getting functions + * @{ + * Those functions get a value of the option with the given name from an object. + * + * @param[in] obj a struct whose first element is a pointer to an AVClass. + * @param[in] name name of the option to get. + * @param[in] search_flags flags passed to av_opt_find2. I.e. if AV_OPT_SEARCH_CHILDREN + * is passed here, then the option may be found in a child of obj. + * @param[out] out_val value of the option will be written here + * @return >=0 on success, a negative error code otherwise + */ +/** + * @note the returned string will be av_malloc()ed and must be av_free()ed by the caller + * + * @note if AV_OPT_ALLOW_NULL is set in search_flags in av_opt_get, and the option has + * AV_OPT_TYPE_STRING or AV_OPT_TYPE_BINARY and is set to NULL, *out_val will be set + * to NULL instead of an allocated empty string. + */ +int av_opt_get (void *obj, const char *name, int search_flags, uint8_t **out_val); +int av_opt_get_int (void *obj, const char *name, int search_flags, int64_t *out_val); +int av_opt_get_double (void *obj, const char *name, int search_flags, double *out_val); +int av_opt_get_q (void *obj, const char *name, int search_flags, AVRational *out_val); +int av_opt_get_image_size(void *obj, const char *name, int search_flags, int *w_out, int *h_out); +int av_opt_get_pixel_fmt (void *obj, const char *name, int search_flags, enum AVPixelFormat *out_fmt); +int av_opt_get_sample_fmt(void *obj, const char *name, int search_flags, enum AVSampleFormat *out_fmt); +int av_opt_get_video_rate(void *obj, const char *name, int search_flags, AVRational *out_val); +int av_opt_get_channel_layout(void *obj, const char *name, int search_flags, int64_t *ch_layout); +/** + * @param[out] out_val The returned dictionary is a copy of the actual value and must + * be freed with av_dict_free() by the caller + */ +int av_opt_get_dict_val(void *obj, const char *name, int search_flags, AVDictionary **out_val); +/** + * @} + */ +/** + * Gets a pointer to the requested field in a struct. + * This function allows accessing a struct even when its fields are moved or + * renamed since the application making the access has been compiled, + * + * @returns a pointer to the field, it can be cast to the correct type and read + * or written to. + */ +void *av_opt_ptr(const AVClass *avclass, void *obj, const char *name); + +/** + * Free an AVOptionRanges struct and set it to NULL. + */ +void av_opt_freep_ranges(AVOptionRanges **ranges); + +/** + * Get a list of allowed ranges for the given option. + * + * The returned list may depend on other fields in obj like for example profile. + * + * @param flags is a bitmask of flags, undefined flags should not be set and should be ignored + * AV_OPT_SEARCH_FAKE_OBJ indicates that the obj is a double pointer to a AVClass instead of a full instance + * AV_OPT_MULTI_COMPONENT_RANGE indicates that function may return more than one component, @see AVOptionRanges + * + * The result must be freed with av_opt_freep_ranges. + * + * @return number of compontents returned on success, a negative errro code otherwise + */ +int av_opt_query_ranges(AVOptionRanges **, void *obj, const char *key, int flags); + +/** + * Copy options from src object into dest object. + * + * Options that require memory allocation (e.g. string or binary) are malloc'ed in dest object. + * Original memory allocated for such options is freed unless both src and dest options points to the same memory. + * + * @param dest Object to copy from + * @param src Object to copy into + * @return 0 on success, negative on error + */ +int av_opt_copy(void *dest, const void *src); + +/** + * Get a default list of allowed ranges for the given option. + * + * This list is constructed without using the AVClass.query_ranges() callback + * and can be used as fallback from within the callback. + * + * @param flags is a bitmask of flags, undefined flags should not be set and should be ignored + * AV_OPT_SEARCH_FAKE_OBJ indicates that the obj is a double pointer to a AVClass instead of a full instance + * AV_OPT_MULTI_COMPONENT_RANGE indicates that function may return more than one component, @see AVOptionRanges + * + * The result must be freed with av_opt_free_ranges. + * + * @return number of compontents returned on success, a negative errro code otherwise + */ +int av_opt_query_ranges_default(AVOptionRanges **, void *obj, const char *key, int flags); + +/** + * Check if given option is set to its default value. + * + * Options o must belong to the obj. This function must not be called to check child's options state. + * @see av_opt_is_set_to_default_by_name(). + * + * @param obj AVClass object to check option on + * @param o option to be checked + * @return >0 when option is set to its default, + * 0 when option is not set its default, + * <0 on error + */ +int av_opt_is_set_to_default(void *obj, const AVOption *o); + +/** + * Check if given option is set to its default value. + * + * @param obj AVClass object to check option on + * @param name option name + * @param search_flags combination of AV_OPT_SEARCH_* + * @return >0 when option is set to its default, + * 0 when option is not set its default, + * <0 on error + */ +int av_opt_is_set_to_default_by_name(void *obj, const char *name, int search_flags); + + +#define AV_OPT_SERIALIZE_SKIP_DEFAULTS 0x00000001 ///< Serialize options that are not set to default values only. +#define AV_OPT_SERIALIZE_OPT_FLAGS_EXACT 0x00000002 ///< Serialize options that exactly match opt_flags only. + +/** + * Serialize object's options. + * + * Create a string containing object's serialized options. + * Such string may be passed back to av_opt_set_from_string() in order to restore option values. + * A key/value or pairs separator occurring in the serialized value or + * name string are escaped through the av_escape() function. + * + * @param[in] obj AVClass object to serialize + * @param[in] opt_flags serialize options with all the specified flags set (AV_OPT_FLAG) + * @param[in] flags combination of AV_OPT_SERIALIZE_* flags + * @param[out] buffer Pointer to buffer that will be allocated with string containg serialized options. + * Buffer must be freed by the caller when is no longer needed. + * @param[in] key_val_sep character used to separate key from value + * @param[in] pairs_sep character used to separate two pairs from each other + * @return >= 0 on success, negative on error + * @warning Separators cannot be neither '\\' nor '\0'. They also cannot be the same. + */ +int av_opt_serialize(void *obj, int opt_flags, int flags, char **buffer, + const char key_val_sep, const char pairs_sep); +/** + * @} + */ + +#endif /* AVUTIL_OPT_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/parseutils.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/parseutils.h new file mode 100644 index 0000000..e66d24b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/parseutils.h @@ -0,0 +1,193 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PARSEUTILS_H +#define AVUTIL_PARSEUTILS_H + +#include + +#include "rational.h" + +/** + * @file + * misc parsing utilities + */ + +/** + * Parse str and store the parsed ratio in q. + * + * Note that a ratio with infinite (1/0) or negative value is + * considered valid, so you should check on the returned value if you + * want to exclude those values. + * + * The undefined value can be expressed using the "0:0" string. + * + * @param[in,out] q pointer to the AVRational which will contain the ratio + * @param[in] str the string to parse: it has to be a string in the format + * num:den, a float number or an expression + * @param[in] max the maximum allowed numerator and denominator + * @param[in] log_offset log level offset which is applied to the log + * level of log_ctx + * @param[in] log_ctx parent logging context + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_ratio(AVRational *q, const char *str, int max, + int log_offset, void *log_ctx); + +#define av_parse_ratio_quiet(rate, str, max) \ + av_parse_ratio(rate, str, max, AV_LOG_MAX_OFFSET, NULL) + +/** + * Parse str and put in width_ptr and height_ptr the detected values. + * + * @param[in,out] width_ptr pointer to the variable which will contain the detected + * width value + * @param[in,out] height_ptr pointer to the variable which will contain the detected + * height value + * @param[in] str the string to parse: it has to be a string in the format + * width x height or a valid video size abbreviation. + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str); + +/** + * Parse str and store the detected values in *rate. + * + * @param[in,out] rate pointer to the AVRational which will contain the detected + * frame rate + * @param[in] str the string to parse: it has to be a string in the format + * rate_num / rate_den, a float number or a valid video rate abbreviation + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_video_rate(AVRational *rate, const char *str); + +/** + * Put the RGBA values that correspond to color_string in rgba_color. + * + * @param color_string a string specifying a color. It can be the name of + * a color (case insensitive match) or a [0x|#]RRGGBB[AA] sequence, + * possibly followed by "@" and a string representing the alpha + * component. + * The alpha component may be a string composed by "0x" followed by an + * hexadecimal number or a decimal number between 0.0 and 1.0, which + * represents the opacity value (0x00/0.0 means completely transparent, + * 0xff/1.0 completely opaque). + * If the alpha component is not specified then 0xff is assumed. + * The string "random" will result in a random color. + * @param slen length of the initial part of color_string containing the + * color. It can be set to -1 if color_string is a null terminated string + * containing nothing else than the color. + * @return >= 0 in case of success, a negative value in case of + * failure (for example if color_string cannot be parsed). + */ +int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen, + void *log_ctx); + +/** + * Get the name of a color from the internal table of hard-coded named + * colors. + * + * This function is meant to enumerate the color names recognized by + * av_parse_color(). + * + * @param color_idx index of the requested color, starting from 0 + * @param rgbp if not NULL, will point to a 3-elements array with the color value in RGB + * @return the color name string or NULL if color_idx is not in the array + */ +const char *av_get_known_color_name(int color_idx, const uint8_t **rgb); + +/** + * Parse timestr and return in *time a corresponding number of + * microseconds. + * + * @param timeval puts here the number of microseconds corresponding + * to the string in timestr. If the string represents a duration, it + * is the number of microseconds contained in the time interval. If + * the string is a date, is the number of microseconds since 1st of + * January, 1970 up to the time of the parsed date. If timestr cannot + * be successfully parsed, set *time to INT64_MIN. + + * @param timestr a string representing a date or a duration. + * - If a date the syntax is: + * @code + * [{YYYY-MM-DD|YYYYMMDD}[T|t| ]]{{HH:MM:SS[.m...]]]}|{HHMMSS[.m...]]]}}[Z] + * now + * @endcode + * If the value is "now" it takes the current time. + * Time is local time unless Z is appended, in which case it is + * interpreted as UTC. + * If the year-month-day part is not specified it takes the current + * year-month-day. + * - If a duration the syntax is: + * @code + * [-][HH:]MM:SS[.m...] + * [-]S+[.m...] + * @endcode + * @param duration flag which tells how to interpret timestr, if not + * zero timestr is interpreted as a duration, otherwise as a date + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_parse_time(int64_t *timeval, const char *timestr, int duration); + +/** + * Attempt to find a specific tag in a URL. + * + * syntax: '?tag1=val1&tag2=val2...'. Little URL decoding is done. + * Return 1 if found. + */ +int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info); + +/** + * Simplified version of strptime + * + * Parse the input string p according to the format string fmt and + * store its results in the structure dt. + * This implementation supports only a subset of the formats supported + * by the standard strptime(). + * + * The supported input field descriptors are listed below. + * - %H: the hour as a decimal number, using a 24-hour clock, in the + * range '00' through '23' + * - %J: hours as a decimal number, in the range '0' through INT_MAX + * - %M: the minute as a decimal number, using a 24-hour clock, in the + * range '00' through '59' + * - %S: the second as a decimal number, using a 24-hour clock, in the + * range '00' through '59' + * - %Y: the year as a decimal number, using the Gregorian calendar + * - %m: the month as a decimal number, in the range '1' through '12' + * - %d: the day of the month as a decimal number, in the range '1' + * through '31' + * - %T: alias for '%H:%M:%S' + * - %%: a literal '%' + * + * @return a pointer to the first character not processed in this function + * call. In case the input string contains more characters than + * required by the format string the return value points right after + * the last consumed input character. In case the whole input string + * is consumed the return value points to the null byte at the end of + * the string. On failure NULL is returned. + */ +char *av_small_strptime(const char *p, const char *fmt, struct tm *dt); + +/** + * Convert the decomposed UTC time in tm to a time_t value. + */ +time_t av_timegm(struct tm *tm); + +#endif /* AVUTIL_PARSEUTILS_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/pixdesc.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/pixdesc.h new file mode 100644 index 0000000..c3a6f27 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/pixdesc.h @@ -0,0 +1,399 @@ +/* + * pixel format descriptor + * Copyright (c) 2009 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PIXDESC_H +#define AVUTIL_PIXDESC_H + +#include + +#include "attributes.h" +#include "pixfmt.h" +#include "version.h" + +typedef struct AVComponentDescriptor { + /** + * Which of the 4 planes contains the component. + */ + int plane; + + /** + * Number of elements between 2 horizontally consecutive pixels. + * Elements are bits for bitstream formats, bytes otherwise. + */ + int step; + + /** + * Number of elements before the component of the first pixel. + * Elements are bits for bitstream formats, bytes otherwise. + */ + int offset; + + /** + * Number of least significant bits that must be shifted away + * to get the value. + */ + int shift; + + /** + * Number of bits in the component. + */ + int depth; + +#if FF_API_PLUS1_MINUS1 + /** deprecated, use step instead */ + attribute_deprecated int step_minus1; + + /** deprecated, use depth instead */ + attribute_deprecated int depth_minus1; + + /** deprecated, use offset instead */ + attribute_deprecated int offset_plus1; +#endif +} AVComponentDescriptor; + +/** + * Descriptor that unambiguously describes how the bits of a pixel are + * stored in the up to 4 data planes of an image. It also stores the + * subsampling factors and number of components. + * + * @note This is separate of the colorspace (RGB, YCbCr, YPbPr, JPEG-style YUV + * and all the YUV variants) AVPixFmtDescriptor just stores how values + * are stored not what these values represent. + */ +typedef struct AVPixFmtDescriptor { + const char *name; + uint8_t nb_components; ///< The number of components each pixel has, (1-4) + + /** + * Amount to shift the luma width right to find the chroma width. + * For YV12 this is 1 for example. + * chroma_width = AV_CEIL_RSHIFT(luma_width, log2_chroma_w) + * The note above is needed to ensure rounding up. + * This value only refers to the chroma components. + */ + uint8_t log2_chroma_w; + + /** + * Amount to shift the luma height right to find the chroma height. + * For YV12 this is 1 for example. + * chroma_height= AV_CEIL_RSHIFT(luma_height, log2_chroma_h) + * The note above is needed to ensure rounding up. + * This value only refers to the chroma components. + */ + uint8_t log2_chroma_h; + + /** + * Combination of AV_PIX_FMT_FLAG_... flags. + */ + uint64_t flags; + + /** + * Parameters that describe how pixels are packed. + * If the format has 1 or 2 components, then luma is 0. + * If the format has 3 or 4 components: + * if the RGB flag is set then 0 is red, 1 is green and 2 is blue; + * otherwise 0 is luma, 1 is chroma-U and 2 is chroma-V. + * + * If present, the Alpha channel is always the last component. + */ + AVComponentDescriptor comp[4]; + + /** + * Alternative comma-separated names. + */ + const char *alias; +} AVPixFmtDescriptor; + +/** + * Pixel format is big-endian. + */ +#define AV_PIX_FMT_FLAG_BE (1 << 0) +/** + * Pixel format has a palette in data[1], values are indexes in this palette. + */ +#define AV_PIX_FMT_FLAG_PAL (1 << 1) +/** + * All values of a component are bit-wise packed end to end. + */ +#define AV_PIX_FMT_FLAG_BITSTREAM (1 << 2) +/** + * Pixel format is an HW accelerated format. + */ +#define AV_PIX_FMT_FLAG_HWACCEL (1 << 3) +/** + * At least one pixel component is not in the first data plane. + */ +#define AV_PIX_FMT_FLAG_PLANAR (1 << 4) +/** + * The pixel format contains RGB-like data (as opposed to YUV/grayscale). + */ +#define AV_PIX_FMT_FLAG_RGB (1 << 5) + +/** + * The pixel format is "pseudo-paletted". This means that it contains a + * fixed palette in the 2nd plane but the palette is fixed/constant for each + * PIX_FMT. This allows interpreting the data as if it was PAL8, which can + * in some cases be simpler. Or the data can be interpreted purely based on + * the pixel format without using the palette. + * An example of a pseudo-paletted format is AV_PIX_FMT_GRAY8 + */ +#define AV_PIX_FMT_FLAG_PSEUDOPAL (1 << 6) + +/** + * The pixel format has an alpha channel. This is set on all formats that + * support alpha in some way. The exception is AV_PIX_FMT_PAL8, which can + * carry alpha as part of the palette. Details are explained in the + * AVPixelFormat enum, and are also encoded in the corresponding + * AVPixFmtDescriptor. + * + * The alpha is always straight, never pre-multiplied. + * + * If a codec or a filter does not support alpha, it should set all alpha to + * opaque, or use the equivalent pixel formats without alpha component, e.g. + * AV_PIX_FMT_RGB0 (or AV_PIX_FMT_RGB24 etc.) instead of AV_PIX_FMT_RGBA. + */ +#define AV_PIX_FMT_FLAG_ALPHA (1 << 7) + +/** + * The pixel format is following a Bayer pattern + */ +#define AV_PIX_FMT_FLAG_BAYER (1 << 8) + +/** + * Return the number of bits per pixel used by the pixel format + * described by pixdesc. Note that this is not the same as the number + * of bits per sample. + * + * The returned number of bits refers to the number of bits actually + * used for storing the pixel information, that is padding bits are + * not counted. + */ +int av_get_bits_per_pixel(const AVPixFmtDescriptor *pixdesc); + +/** + * Return the number of bits per pixel for the pixel format + * described by pixdesc, including any padding or unused bits. + */ +int av_get_padded_bits_per_pixel(const AVPixFmtDescriptor *pixdesc); + +/** + * @return a pixel format descriptor for provided pixel format or NULL if + * this pixel format is unknown. + */ +const AVPixFmtDescriptor *av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt); + +/** + * Iterate over all pixel format descriptors known to libavutil. + * + * @param prev previous descriptor. NULL to get the first descriptor. + * + * @return next descriptor or NULL after the last descriptor + */ +const AVPixFmtDescriptor *av_pix_fmt_desc_next(const AVPixFmtDescriptor *prev); + +/** + * @return an AVPixelFormat id described by desc, or AV_PIX_FMT_NONE if desc + * is not a valid pointer to a pixel format descriptor. + */ +enum AVPixelFormat av_pix_fmt_desc_get_id(const AVPixFmtDescriptor *desc); + +/** + * Utility function to access log2_chroma_w log2_chroma_h from + * the pixel format AVPixFmtDescriptor. + * + * See av_get_chroma_sub_sample() for a function that asserts a + * valid pixel format instead of returning an error code. + * Its recommended that you use avcodec_get_chroma_sub_sample unless + * you do check the return code! + * + * @param[in] pix_fmt the pixel format + * @param[out] h_shift store log2_chroma_w (horizontal/width shift) + * @param[out] v_shift store log2_chroma_h (vertical/height shift) + * + * @return 0 on success, AVERROR(ENOSYS) on invalid or unknown pixel format + */ +int av_pix_fmt_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, + int *h_shift, int *v_shift); + +/** + * @return number of planes in pix_fmt, a negative AVERROR if pix_fmt is not a + * valid pixel format. + */ +int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt); + +/** + * @return the name for provided color range or NULL if unknown. + */ +const char *av_color_range_name(enum AVColorRange range); + +/** + * @return the name for provided color primaries or NULL if unknown. + */ +const char *av_color_primaries_name(enum AVColorPrimaries primaries); + +/** + * @return the name for provided color transfer or NULL if unknown. + */ +const char *av_color_transfer_name(enum AVColorTransferCharacteristic transfer); + +/** + * @return the name for provided color space or NULL if unknown. + */ +const char *av_color_space_name(enum AVColorSpace space); + +/** + * @return the name for provided chroma location or NULL if unknown. + */ +const char *av_chroma_location_name(enum AVChromaLocation location); + +/** + * Return the pixel format corresponding to name. + * + * If there is no pixel format with name name, then looks for a + * pixel format with the name corresponding to the native endian + * format of name. + * For example in a little-endian system, first looks for "gray16", + * then for "gray16le". + * + * Finally if no pixel format has been found, returns AV_PIX_FMT_NONE. + */ +enum AVPixelFormat av_get_pix_fmt(const char *name); + +/** + * Return the short name for a pixel format, NULL in case pix_fmt is + * unknown. + * + * @see av_get_pix_fmt(), av_get_pix_fmt_string() + */ +const char *av_get_pix_fmt_name(enum AVPixelFormat pix_fmt); + +/** + * Print in buf the string corresponding to the pixel format with + * number pix_fmt, or a header if pix_fmt is negative. + * + * @param buf the buffer where to write the string + * @param buf_size the size of buf + * @param pix_fmt the number of the pixel format to print the + * corresponding info string, or a negative value to print the + * corresponding header. + */ +char *av_get_pix_fmt_string(char *buf, int buf_size, + enum AVPixelFormat pix_fmt); + +/** + * Read a line from an image, and write the values of the + * pixel format component c to dst. + * + * @param data the array containing the pointers to the planes of the image + * @param linesize the array containing the linesizes of the image + * @param desc the pixel format descriptor for the image + * @param x the horizontal coordinate of the first pixel to read + * @param y the vertical coordinate of the first pixel to read + * @param w the width of the line to read, that is the number of + * values to write to dst + * @param read_pal_component if not zero and the format is a paletted + * format writes the values corresponding to the palette + * component c in data[1] to dst, rather than the palette indexes in + * data[0]. The behavior is undefined if the format is not paletted. + */ +void av_read_image_line(uint16_t *dst, const uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, int read_pal_component); + +/** + * Write the values from src to the pixel format component c of an + * image line. + * + * @param src array containing the values to write + * @param data the array containing the pointers to the planes of the + * image to write into. It is supposed to be zeroed. + * @param linesize the array containing the linesizes of the image + * @param desc the pixel format descriptor for the image + * @param x the horizontal coordinate of the first pixel to write + * @param y the vertical coordinate of the first pixel to write + * @param w the width of the line to write, that is the number of + * values to write to the image line + */ +void av_write_image_line(const uint16_t *src, uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w); + +/** + * Utility function to swap the endianness of a pixel format. + * + * @param[in] pix_fmt the pixel format + * + * @return pixel format with swapped endianness if it exists, + * otherwise AV_PIX_FMT_NONE + */ +enum AVPixelFormat av_pix_fmt_swap_endianness(enum AVPixelFormat pix_fmt); + +#define FF_LOSS_RESOLUTION 0x0001 /**< loss due to resolution change */ +#define FF_LOSS_DEPTH 0x0002 /**< loss due to color depth change */ +#define FF_LOSS_COLORSPACE 0x0004 /**< loss due to color space conversion */ +#define FF_LOSS_ALPHA 0x0008 /**< loss of alpha bits */ +#define FF_LOSS_COLORQUANT 0x0010 /**< loss due to color quantization */ +#define FF_LOSS_CHROMA 0x0020 /**< loss of chroma (e.g. RGB to gray conversion) */ + +/** + * Compute what kind of losses will occur when converting from one specific + * pixel format to another. + * When converting from one pixel format to another, information loss may occur. + * For example, when converting from RGB24 to GRAY, the color information will + * be lost. Similarly, other losses occur when converting from some formats to + * other formats. These losses can involve loss of chroma, but also loss of + * resolution, loss of color depth, loss due to the color space conversion, loss + * of the alpha bits or loss due to color quantization. + * av_get_fix_fmt_loss() informs you about the various types of losses + * which will occur when converting from one pixel format to another. + * + * @param[in] dst_pix_fmt destination pixel format + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @return Combination of flags informing you what kind of losses will occur + * (maximum loss for an invalid dst_pix_fmt). + */ +int av_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, + enum AVPixelFormat src_pix_fmt, + int has_alpha); + +/** + * Compute what kind of losses will occur when converting from one specific + * pixel format to another. + * When converting from one pixel format to another, information loss may occur. + * For example, when converting from RGB24 to GRAY, the color information will + * be lost. Similarly, other losses occur when converting from some formats to + * other formats. These losses can involve loss of chroma, but also loss of + * resolution, loss of color depth, loss due to the color space conversion, loss + * of the alpha bits or loss due to color quantization. + * av_get_fix_fmt_loss() informs you about the various types of losses + * which will occur when converting from one pixel format to another. + * + * @param[in] dst_pix_fmt destination pixel format + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @return Combination of flags informing you what kind of losses will occur + * (maximum loss for an invalid dst_pix_fmt). + */ +enum AVPixelFormat av_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr); + +#endif /* AVUTIL_PIXDESC_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/pixelutils.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/pixelutils.h new file mode 100644 index 0000000..a8dbc15 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/pixelutils.h @@ -0,0 +1,52 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PIXELUTILS_H +#define AVUTIL_PIXELUTILS_H + +#include +#include +#include "common.h" + +/** + * Sum of abs(src1[x] - src2[x]) + */ +typedef int (*av_pixelutils_sad_fn)(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); + +/** + * Get a potentially optimized pointer to a Sum-of-absolute-differences + * function (see the av_pixelutils_sad_fn prototype). + * + * @param w_bits 1< + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PIXFMT_H +#define AVUTIL_PIXFMT_H + +/** + * @file + * pixel format definitions + */ + +#include "libavutil/avconfig.h" +#include "version.h" + +#define AVPALETTE_SIZE 1024 +#define AVPALETTE_COUNT 256 + +/** + * Pixel format. + * + * @note + * AV_PIX_FMT_RGB32 is handled in an endian-specific manner. An RGBA + * color is put together as: + * (A << 24) | (R << 16) | (G << 8) | B + * This is stored as BGRA on little-endian CPU architectures and ARGB on + * big-endian CPUs. + * + * @note + * If the resolution is not a multiple of the chroma subsampling factor + * then the chroma plane resolution must be rounded up. + * + * @par + * When the pixel format is palettized RGB32 (AV_PIX_FMT_PAL8), the palettized + * image data is stored in AVFrame.data[0]. The palette is transported in + * AVFrame.data[1], is 1024 bytes long (256 4-byte entries) and is + * formatted the same as in AV_PIX_FMT_RGB32 described above (i.e., it is + * also endian-specific). Note also that the individual RGB32 palette + * components stored in AVFrame.data[1] should be in the range 0..255. + * This is important as many custom PAL8 video codecs that were designed + * to run on the IBM VGA graphics adapter use 6-bit palette components. + * + * @par + * For all the 8 bits per pixel formats, an RGB32 palette is in data[1] like + * for pal8. This palette is filled in automatically by the function + * allocating the picture. + */ +enum AVPixelFormat { + AV_PIX_FMT_NONE = -1, + AV_PIX_FMT_YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) + AV_PIX_FMT_YUYV422, ///< packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr + AV_PIX_FMT_RGB24, ///< packed RGB 8:8:8, 24bpp, RGBRGB... + AV_PIX_FMT_BGR24, ///< packed RGB 8:8:8, 24bpp, BGRBGR... + AV_PIX_FMT_YUV422P, ///< planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) + AV_PIX_FMT_YUV444P, ///< planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples) + AV_PIX_FMT_YUV410P, ///< planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples) + AV_PIX_FMT_YUV411P, ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) + AV_PIX_FMT_GRAY8, ///< Y , 8bpp + AV_PIX_FMT_MONOWHITE, ///< Y , 1bpp, 0 is white, 1 is black, in each byte pixels are ordered from the msb to the lsb + AV_PIX_FMT_MONOBLACK, ///< Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb + AV_PIX_FMT_PAL8, ///< 8 bits with AV_PIX_FMT_RGB32 palette + AV_PIX_FMT_YUVJ420P, ///< planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV420P and setting color_range + AV_PIX_FMT_YUVJ422P, ///< planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV422P and setting color_range + AV_PIX_FMT_YUVJ444P, ///< planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting color_range +#if FF_API_XVMC + AV_PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing + AV_PIX_FMT_XVMC_MPEG2_IDCT, + AV_PIX_FMT_XVMC = AV_PIX_FMT_XVMC_MPEG2_IDCT, +#endif /* FF_API_XVMC */ + AV_PIX_FMT_UYVY422, ///< packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1 + AV_PIX_FMT_UYYVYY411, ///< packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3 + AV_PIX_FMT_BGR8, ///< packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb) + AV_PIX_FMT_BGR4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1B 2G 1R(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits + AV_PIX_FMT_BGR4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1B 2G 1R(lsb) + AV_PIX_FMT_RGB8, ///< packed RGB 3:3:2, 8bpp, (msb)2R 3G 3B(lsb) + AV_PIX_FMT_RGB4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1R 2G 1B(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits + AV_PIX_FMT_RGB4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1R 2G 1B(lsb) + AV_PIX_FMT_NV12, ///< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V) + AV_PIX_FMT_NV21, ///< as above, but U and V bytes are swapped + + AV_PIX_FMT_ARGB, ///< packed ARGB 8:8:8:8, 32bpp, ARGBARGB... + AV_PIX_FMT_RGBA, ///< packed RGBA 8:8:8:8, 32bpp, RGBARGBA... + AV_PIX_FMT_ABGR, ///< packed ABGR 8:8:8:8, 32bpp, ABGRABGR... + AV_PIX_FMT_BGRA, ///< packed BGRA 8:8:8:8, 32bpp, BGRABGRA... + + AV_PIX_FMT_GRAY16BE, ///< Y , 16bpp, big-endian + AV_PIX_FMT_GRAY16LE, ///< Y , 16bpp, little-endian + AV_PIX_FMT_YUV440P, ///< planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples) + AV_PIX_FMT_YUVJ440P, ///< planar YUV 4:4:0 full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV440P and setting color_range + AV_PIX_FMT_YUVA420P, ///< planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples) +#if FF_API_VDPAU + AV_PIX_FMT_VDPAU_H264,///< H.264 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + AV_PIX_FMT_VDPAU_MPEG1,///< MPEG-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + AV_PIX_FMT_VDPAU_MPEG2,///< MPEG-2 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + AV_PIX_FMT_VDPAU_WMV3,///< WMV3 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + AV_PIX_FMT_VDPAU_VC1, ///< VC-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers +#endif + AV_PIX_FMT_RGB48BE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as big-endian + AV_PIX_FMT_RGB48LE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as little-endian + + AV_PIX_FMT_RGB565BE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), big-endian + AV_PIX_FMT_RGB565LE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian + AV_PIX_FMT_RGB555BE, ///< packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), big-endian , X=unused/undefined + AV_PIX_FMT_RGB555LE, ///< packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), little-endian, X=unused/undefined + + AV_PIX_FMT_BGR565BE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), big-endian + AV_PIX_FMT_BGR565LE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), little-endian + AV_PIX_FMT_BGR555BE, ///< packed BGR 5:5:5, 16bpp, (msb)1X 5B 5G 5R(lsb), big-endian , X=unused/undefined + AV_PIX_FMT_BGR555LE, ///< packed BGR 5:5:5, 16bpp, (msb)1X 5B 5G 5R(lsb), little-endian, X=unused/undefined + +#if FF_API_VAAPI + /** @name Deprecated pixel formats */ + /**@{*/ + AV_PIX_FMT_VAAPI_MOCO, ///< HW acceleration through VA API at motion compensation entry-point, Picture.data[3] contains a vaapi_render_state struct which contains macroblocks as well as various fields extracted from headers + AV_PIX_FMT_VAAPI_IDCT, ///< HW acceleration through VA API at IDCT entry-point, Picture.data[3] contains a vaapi_render_state struct which contains fields extracted from headers + AV_PIX_FMT_VAAPI_VLD, ///< HW decoding through VA API, Picture.data[3] contains a VASurfaceID + /**@}*/ + AV_PIX_FMT_VAAPI = AV_PIX_FMT_VAAPI_VLD, +#else + /** + * Hardware acceleration through VA-API, data[3] contains a + * VASurfaceID. + */ + AV_PIX_FMT_VAAPI, +#endif + + AV_PIX_FMT_YUV420P16LE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV420P16BE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV422P16LE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV422P16BE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV444P16LE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV444P16BE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian +#if FF_API_VDPAU + AV_PIX_FMT_VDPAU_MPEG4, ///< MPEG-4 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers +#endif + AV_PIX_FMT_DXVA2_VLD, ///< HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer + + AV_PIX_FMT_RGB444LE, ///< packed RGB 4:4:4, 16bpp, (msb)4X 4R 4G 4B(lsb), little-endian, X=unused/undefined + AV_PIX_FMT_RGB444BE, ///< packed RGB 4:4:4, 16bpp, (msb)4X 4R 4G 4B(lsb), big-endian, X=unused/undefined + AV_PIX_FMT_BGR444LE, ///< packed BGR 4:4:4, 16bpp, (msb)4X 4B 4G 4R(lsb), little-endian, X=unused/undefined + AV_PIX_FMT_BGR444BE, ///< packed BGR 4:4:4, 16bpp, (msb)4X 4B 4G 4R(lsb), big-endian, X=unused/undefined + AV_PIX_FMT_YA8, ///< 8 bits gray, 8 bits alpha + + AV_PIX_FMT_Y400A = AV_PIX_FMT_YA8, ///< alias for AV_PIX_FMT_YA8 + AV_PIX_FMT_GRAY8A= AV_PIX_FMT_YA8, ///< alias for AV_PIX_FMT_YA8 + + AV_PIX_FMT_BGR48BE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as big-endian + AV_PIX_FMT_BGR48LE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as little-endian + + /** + * The following 12 formats have the disadvantage of needing 1 format for each bit depth. + * Notice that each 9/10 bits sample is stored in 16 bits with extra padding. + * If you want to support multiple bit depths, then using AV_PIX_FMT_YUV420P16* with the bpp stored separately is better. + */ + AV_PIX_FMT_YUV420P9BE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P9LE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV420P10BE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P10LE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV422P10BE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P10LE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV444P9BE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P9LE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV444P10BE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P10LE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV422P9BE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P9LE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_VDA_VLD, ///< hardware decoding through VDA + AV_PIX_FMT_GBRP, ///< planar GBR 4:4:4 24bpp + AV_PIX_FMT_GBR24P = AV_PIX_FMT_GBRP, // alias for #AV_PIX_FMT_GBRP + AV_PIX_FMT_GBRP9BE, ///< planar GBR 4:4:4 27bpp, big-endian + AV_PIX_FMT_GBRP9LE, ///< planar GBR 4:4:4 27bpp, little-endian + AV_PIX_FMT_GBRP10BE, ///< planar GBR 4:4:4 30bpp, big-endian + AV_PIX_FMT_GBRP10LE, ///< planar GBR 4:4:4 30bpp, little-endian + AV_PIX_FMT_GBRP16BE, ///< planar GBR 4:4:4 48bpp, big-endian + AV_PIX_FMT_GBRP16LE, ///< planar GBR 4:4:4 48bpp, little-endian + AV_PIX_FMT_YUVA422P, ///< planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples) + AV_PIX_FMT_YUVA444P, ///< planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples) + AV_PIX_FMT_YUVA420P9BE, ///< planar YUV 4:2:0 22.5bpp, (1 Cr & Cb sample per 2x2 Y & A samples), big-endian + AV_PIX_FMT_YUVA420P9LE, ///< planar YUV 4:2:0 22.5bpp, (1 Cr & Cb sample per 2x2 Y & A samples), little-endian + AV_PIX_FMT_YUVA422P9BE, ///< planar YUV 4:2:2 27bpp, (1 Cr & Cb sample per 2x1 Y & A samples), big-endian + AV_PIX_FMT_YUVA422P9LE, ///< planar YUV 4:2:2 27bpp, (1 Cr & Cb sample per 2x1 Y & A samples), little-endian + AV_PIX_FMT_YUVA444P9BE, ///< planar YUV 4:4:4 36bpp, (1 Cr & Cb sample per 1x1 Y & A samples), big-endian + AV_PIX_FMT_YUVA444P9LE, ///< planar YUV 4:4:4 36bpp, (1 Cr & Cb sample per 1x1 Y & A samples), little-endian + AV_PIX_FMT_YUVA420P10BE, ///< planar YUV 4:2:0 25bpp, (1 Cr & Cb sample per 2x2 Y & A samples, big-endian) + AV_PIX_FMT_YUVA420P10LE, ///< planar YUV 4:2:0 25bpp, (1 Cr & Cb sample per 2x2 Y & A samples, little-endian) + AV_PIX_FMT_YUVA422P10BE, ///< planar YUV 4:2:2 30bpp, (1 Cr & Cb sample per 2x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA422P10LE, ///< planar YUV 4:2:2 30bpp, (1 Cr & Cb sample per 2x1 Y & A samples, little-endian) + AV_PIX_FMT_YUVA444P10BE, ///< planar YUV 4:4:4 40bpp, (1 Cr & Cb sample per 1x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA444P10LE, ///< planar YUV 4:4:4 40bpp, (1 Cr & Cb sample per 1x1 Y & A samples, little-endian) + AV_PIX_FMT_YUVA420P16BE, ///< planar YUV 4:2:0 40bpp, (1 Cr & Cb sample per 2x2 Y & A samples, big-endian) + AV_PIX_FMT_YUVA420P16LE, ///< planar YUV 4:2:0 40bpp, (1 Cr & Cb sample per 2x2 Y & A samples, little-endian) + AV_PIX_FMT_YUVA422P16BE, ///< planar YUV 4:2:2 48bpp, (1 Cr & Cb sample per 2x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA422P16LE, ///< planar YUV 4:2:2 48bpp, (1 Cr & Cb sample per 2x1 Y & A samples, little-endian) + AV_PIX_FMT_YUVA444P16BE, ///< planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA444P16LE, ///< planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, little-endian) + + AV_PIX_FMT_VDPAU, ///< HW acceleration through VDPAU, Picture.data[3] contains a VdpVideoSurface + + AV_PIX_FMT_XYZ12LE, ///< packed XYZ 4:4:4, 36 bpp, (msb) 12X, 12Y, 12Z (lsb), the 2-byte value for each X/Y/Z is stored as little-endian, the 4 lower bits are set to 0 + AV_PIX_FMT_XYZ12BE, ///< packed XYZ 4:4:4, 36 bpp, (msb) 12X, 12Y, 12Z (lsb), the 2-byte value for each X/Y/Z is stored as big-endian, the 4 lower bits are set to 0 + AV_PIX_FMT_NV16, ///< interleaved chroma YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) + AV_PIX_FMT_NV20LE, ///< interleaved chroma YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_NV20BE, ///< interleaved chroma YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + + AV_PIX_FMT_RGBA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + AV_PIX_FMT_RGBA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian + AV_PIX_FMT_BGRA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + AV_PIX_FMT_BGRA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian + + AV_PIX_FMT_YVYU422, ///< packed YUV 4:2:2, 16bpp, Y0 Cr Y1 Cb + + AV_PIX_FMT_VDA, ///< HW acceleration through VDA, data[3] contains a CVPixelBufferRef + + AV_PIX_FMT_YA16BE, ///< 16 bits gray, 16 bits alpha (big-endian) + AV_PIX_FMT_YA16LE, ///< 16 bits gray, 16 bits alpha (little-endian) + + AV_PIX_FMT_GBRAP, ///< planar GBRA 4:4:4:4 32bpp + AV_PIX_FMT_GBRAP16BE, ///< planar GBRA 4:4:4:4 64bpp, big-endian + AV_PIX_FMT_GBRAP16LE, ///< planar GBRA 4:4:4:4 64bpp, little-endian + /** + * HW acceleration through QSV, data[3] contains a pointer to the + * mfxFrameSurface1 structure. + */ + AV_PIX_FMT_QSV, + /** + * HW acceleration though MMAL, data[3] contains a pointer to the + * MMAL_BUFFER_HEADER_T structure. + */ + AV_PIX_FMT_MMAL, + + AV_PIX_FMT_D3D11VA_VLD, ///< HW decoding through Direct3D11, Picture.data[3] contains a ID3D11VideoDecoderOutputView pointer + + /** + * HW acceleration through CUDA. data[i] contain CUdeviceptr pointers + * exactly as for system memory frames. + */ + AV_PIX_FMT_CUDA, + + AV_PIX_FMT_0RGB=0x123+4,///< packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined + AV_PIX_FMT_RGB0, ///< packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined + AV_PIX_FMT_0BGR, ///< packed BGR 8:8:8, 32bpp, XBGRXBGR... X=unused/undefined + AV_PIX_FMT_BGR0, ///< packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined + + AV_PIX_FMT_YUV420P12BE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P12LE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV420P14BE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P14LE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV422P12BE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P12LE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV422P14BE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P14LE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV444P12BE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P12LE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV444P14BE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P14LE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_GBRP12BE, ///< planar GBR 4:4:4 36bpp, big-endian + AV_PIX_FMT_GBRP12LE, ///< planar GBR 4:4:4 36bpp, little-endian + AV_PIX_FMT_GBRP14BE, ///< planar GBR 4:4:4 42bpp, big-endian + AV_PIX_FMT_GBRP14LE, ///< planar GBR 4:4:4 42bpp, little-endian + AV_PIX_FMT_YUVJ411P, ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV411P and setting color_range + + AV_PIX_FMT_BAYER_BGGR8, ///< bayer, BGBG..(odd line), GRGR..(even line), 8-bit samples */ + AV_PIX_FMT_BAYER_RGGB8, ///< bayer, RGRG..(odd line), GBGB..(even line), 8-bit samples */ + AV_PIX_FMT_BAYER_GBRG8, ///< bayer, GBGB..(odd line), RGRG..(even line), 8-bit samples */ + AV_PIX_FMT_BAYER_GRBG8, ///< bayer, GRGR..(odd line), BGBG..(even line), 8-bit samples */ + AV_PIX_FMT_BAYER_BGGR16LE, ///< bayer, BGBG..(odd line), GRGR..(even line), 16-bit samples, little-endian */ + AV_PIX_FMT_BAYER_BGGR16BE, ///< bayer, BGBG..(odd line), GRGR..(even line), 16-bit samples, big-endian */ + AV_PIX_FMT_BAYER_RGGB16LE, ///< bayer, RGRG..(odd line), GBGB..(even line), 16-bit samples, little-endian */ + AV_PIX_FMT_BAYER_RGGB16BE, ///< bayer, RGRG..(odd line), GBGB..(even line), 16-bit samples, big-endian */ + AV_PIX_FMT_BAYER_GBRG16LE, ///< bayer, GBGB..(odd line), RGRG..(even line), 16-bit samples, little-endian */ + AV_PIX_FMT_BAYER_GBRG16BE, ///< bayer, GBGB..(odd line), RGRG..(even line), 16-bit samples, big-endian */ + AV_PIX_FMT_BAYER_GRBG16LE, ///< bayer, GRGR..(odd line), BGBG..(even line), 16-bit samples, little-endian */ + AV_PIX_FMT_BAYER_GRBG16BE, ///< bayer, GRGR..(odd line), BGBG..(even line), 16-bit samples, big-endian */ +#if !FF_API_XVMC + AV_PIX_FMT_XVMC,///< XVideo Motion Acceleration via common packet passing +#endif /* !FF_API_XVMC */ + AV_PIX_FMT_YUV440P10LE, ///< planar YUV 4:4:0,20bpp, (1 Cr & Cb sample per 1x2 Y samples), little-endian + AV_PIX_FMT_YUV440P10BE, ///< planar YUV 4:4:0,20bpp, (1 Cr & Cb sample per 1x2 Y samples), big-endian + AV_PIX_FMT_YUV440P12LE, ///< planar YUV 4:4:0,24bpp, (1 Cr & Cb sample per 1x2 Y samples), little-endian + AV_PIX_FMT_YUV440P12BE, ///< planar YUV 4:4:0,24bpp, (1 Cr & Cb sample per 1x2 Y samples), big-endian + AV_PIX_FMT_AYUV64LE, ///< packed AYUV 4:4:4,64bpp (1 Cr & Cb sample per 1x1 Y & A samples), little-endian + AV_PIX_FMT_AYUV64BE, ///< packed AYUV 4:4:4,64bpp (1 Cr & Cb sample per 1x1 Y & A samples), big-endian + + AV_PIX_FMT_VIDEOTOOLBOX, ///< hardware decoding through Videotoolbox + + AV_PIX_FMT_P010LE, ///< like NV12, with 10bpp per component, data in the high bits, zeros in the low bits, little-endian + AV_PIX_FMT_P010BE, ///< like NV12, with 10bpp per component, data in the high bits, zeros in the low bits, big-endian + + AV_PIX_FMT_GBRAP12BE, ///< planar GBR 4:4:4:4 48bpp, big-endian + AV_PIX_FMT_GBRAP12LE, ///< planar GBR 4:4:4:4 48bpp, little-endian + + AV_PIX_FMT_GBRAP10BE, ///< planar GBR 4:4:4:4 40bpp, big-endian + AV_PIX_FMT_GBRAP10LE, ///< planar GBR 4:4:4:4 40bpp, little-endian + + AV_PIX_FMT_MEDIACODEC, ///< hardware decoding through MediaCodec + + AV_PIX_FMT_GRAY12BE, ///< Y , 12bpp, big-endian + AV_PIX_FMT_GRAY12LE, ///< Y , 12bpp, little-endian + AV_PIX_FMT_GRAY10BE, ///< Y , 10bpp, big-endian + AV_PIX_FMT_GRAY10LE, ///< Y , 10bpp, little-endian + + AV_PIX_FMT_P016LE, ///< like NV12, with 16bpp per component, little-endian + AV_PIX_FMT_P016BE, ///< like NV12, with 16bpp per component, big-endian + + AV_PIX_FMT_NB ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions +}; + +#if AV_HAVE_BIGENDIAN +# define AV_PIX_FMT_NE(be, le) AV_PIX_FMT_##be +#else +# define AV_PIX_FMT_NE(be, le) AV_PIX_FMT_##le +#endif + +#define AV_PIX_FMT_RGB32 AV_PIX_FMT_NE(ARGB, BGRA) +#define AV_PIX_FMT_RGB32_1 AV_PIX_FMT_NE(RGBA, ABGR) +#define AV_PIX_FMT_BGR32 AV_PIX_FMT_NE(ABGR, RGBA) +#define AV_PIX_FMT_BGR32_1 AV_PIX_FMT_NE(BGRA, ARGB) +#define AV_PIX_FMT_0RGB32 AV_PIX_FMT_NE(0RGB, BGR0) +#define AV_PIX_FMT_0BGR32 AV_PIX_FMT_NE(0BGR, RGB0) + +#define AV_PIX_FMT_GRAY10 AV_PIX_FMT_NE(GRAY10BE, GRAY10LE) +#define AV_PIX_FMT_GRAY12 AV_PIX_FMT_NE(GRAY12BE, GRAY12LE) +#define AV_PIX_FMT_GRAY16 AV_PIX_FMT_NE(GRAY16BE, GRAY16LE) +#define AV_PIX_FMT_YA16 AV_PIX_FMT_NE(YA16BE, YA16LE) +#define AV_PIX_FMT_RGB48 AV_PIX_FMT_NE(RGB48BE, RGB48LE) +#define AV_PIX_FMT_RGB565 AV_PIX_FMT_NE(RGB565BE, RGB565LE) +#define AV_PIX_FMT_RGB555 AV_PIX_FMT_NE(RGB555BE, RGB555LE) +#define AV_PIX_FMT_RGB444 AV_PIX_FMT_NE(RGB444BE, RGB444LE) +#define AV_PIX_FMT_RGBA64 AV_PIX_FMT_NE(RGBA64BE, RGBA64LE) +#define AV_PIX_FMT_BGR48 AV_PIX_FMT_NE(BGR48BE, BGR48LE) +#define AV_PIX_FMT_BGR565 AV_PIX_FMT_NE(BGR565BE, BGR565LE) +#define AV_PIX_FMT_BGR555 AV_PIX_FMT_NE(BGR555BE, BGR555LE) +#define AV_PIX_FMT_BGR444 AV_PIX_FMT_NE(BGR444BE, BGR444LE) +#define AV_PIX_FMT_BGRA64 AV_PIX_FMT_NE(BGRA64BE, BGRA64LE) + +#define AV_PIX_FMT_YUV420P9 AV_PIX_FMT_NE(YUV420P9BE , YUV420P9LE) +#define AV_PIX_FMT_YUV422P9 AV_PIX_FMT_NE(YUV422P9BE , YUV422P9LE) +#define AV_PIX_FMT_YUV444P9 AV_PIX_FMT_NE(YUV444P9BE , YUV444P9LE) +#define AV_PIX_FMT_YUV420P10 AV_PIX_FMT_NE(YUV420P10BE, YUV420P10LE) +#define AV_PIX_FMT_YUV422P10 AV_PIX_FMT_NE(YUV422P10BE, YUV422P10LE) +#define AV_PIX_FMT_YUV440P10 AV_PIX_FMT_NE(YUV440P10BE, YUV440P10LE) +#define AV_PIX_FMT_YUV444P10 AV_PIX_FMT_NE(YUV444P10BE, YUV444P10LE) +#define AV_PIX_FMT_YUV420P12 AV_PIX_FMT_NE(YUV420P12BE, YUV420P12LE) +#define AV_PIX_FMT_YUV422P12 AV_PIX_FMT_NE(YUV422P12BE, YUV422P12LE) +#define AV_PIX_FMT_YUV440P12 AV_PIX_FMT_NE(YUV440P12BE, YUV440P12LE) +#define AV_PIX_FMT_YUV444P12 AV_PIX_FMT_NE(YUV444P12BE, YUV444P12LE) +#define AV_PIX_FMT_YUV420P14 AV_PIX_FMT_NE(YUV420P14BE, YUV420P14LE) +#define AV_PIX_FMT_YUV422P14 AV_PIX_FMT_NE(YUV422P14BE, YUV422P14LE) +#define AV_PIX_FMT_YUV444P14 AV_PIX_FMT_NE(YUV444P14BE, YUV444P14LE) +#define AV_PIX_FMT_YUV420P16 AV_PIX_FMT_NE(YUV420P16BE, YUV420P16LE) +#define AV_PIX_FMT_YUV422P16 AV_PIX_FMT_NE(YUV422P16BE, YUV422P16LE) +#define AV_PIX_FMT_YUV444P16 AV_PIX_FMT_NE(YUV444P16BE, YUV444P16LE) + +#define AV_PIX_FMT_GBRP9 AV_PIX_FMT_NE(GBRP9BE , GBRP9LE) +#define AV_PIX_FMT_GBRP10 AV_PIX_FMT_NE(GBRP10BE, GBRP10LE) +#define AV_PIX_FMT_GBRP12 AV_PIX_FMT_NE(GBRP12BE, GBRP12LE) +#define AV_PIX_FMT_GBRP14 AV_PIX_FMT_NE(GBRP14BE, GBRP14LE) +#define AV_PIX_FMT_GBRP16 AV_PIX_FMT_NE(GBRP16BE, GBRP16LE) +#define AV_PIX_FMT_GBRAP10 AV_PIX_FMT_NE(GBRAP10BE, GBRAP10LE) +#define AV_PIX_FMT_GBRAP12 AV_PIX_FMT_NE(GBRAP12BE, GBRAP12LE) +#define AV_PIX_FMT_GBRAP16 AV_PIX_FMT_NE(GBRAP16BE, GBRAP16LE) + +#define AV_PIX_FMT_BAYER_BGGR16 AV_PIX_FMT_NE(BAYER_BGGR16BE, BAYER_BGGR16LE) +#define AV_PIX_FMT_BAYER_RGGB16 AV_PIX_FMT_NE(BAYER_RGGB16BE, BAYER_RGGB16LE) +#define AV_PIX_FMT_BAYER_GBRG16 AV_PIX_FMT_NE(BAYER_GBRG16BE, BAYER_GBRG16LE) +#define AV_PIX_FMT_BAYER_GRBG16 AV_PIX_FMT_NE(BAYER_GRBG16BE, BAYER_GRBG16LE) + + +#define AV_PIX_FMT_YUVA420P9 AV_PIX_FMT_NE(YUVA420P9BE , YUVA420P9LE) +#define AV_PIX_FMT_YUVA422P9 AV_PIX_FMT_NE(YUVA422P9BE , YUVA422P9LE) +#define AV_PIX_FMT_YUVA444P9 AV_PIX_FMT_NE(YUVA444P9BE , YUVA444P9LE) +#define AV_PIX_FMT_YUVA420P10 AV_PIX_FMT_NE(YUVA420P10BE, YUVA420P10LE) +#define AV_PIX_FMT_YUVA422P10 AV_PIX_FMT_NE(YUVA422P10BE, YUVA422P10LE) +#define AV_PIX_FMT_YUVA444P10 AV_PIX_FMT_NE(YUVA444P10BE, YUVA444P10LE) +#define AV_PIX_FMT_YUVA420P16 AV_PIX_FMT_NE(YUVA420P16BE, YUVA420P16LE) +#define AV_PIX_FMT_YUVA422P16 AV_PIX_FMT_NE(YUVA422P16BE, YUVA422P16LE) +#define AV_PIX_FMT_YUVA444P16 AV_PIX_FMT_NE(YUVA444P16BE, YUVA444P16LE) + +#define AV_PIX_FMT_XYZ12 AV_PIX_FMT_NE(XYZ12BE, XYZ12LE) +#define AV_PIX_FMT_NV20 AV_PIX_FMT_NE(NV20BE, NV20LE) +#define AV_PIX_FMT_AYUV64 AV_PIX_FMT_NE(AYUV64BE, AYUV64LE) +#define AV_PIX_FMT_P010 AV_PIX_FMT_NE(P010BE, P010LE) +#define AV_PIX_FMT_P016 AV_PIX_FMT_NE(P016BE, P016LE) + +/** + * Chromaticity coordinates of the source primaries. + */ +enum AVColorPrimaries { + AVCOL_PRI_RESERVED0 = 0, + AVCOL_PRI_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 / SMPTE RP177 Annex B + AVCOL_PRI_UNSPECIFIED = 2, + AVCOL_PRI_RESERVED = 3, + AVCOL_PRI_BT470M = 4, ///< also FCC Title 47 Code of Federal Regulations 73.682 (a)(20) + + AVCOL_PRI_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM + AVCOL_PRI_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC + AVCOL_PRI_SMPTE240M = 7, ///< functionally identical to above + AVCOL_PRI_FILM = 8, ///< colour filters using Illuminant C + AVCOL_PRI_BT2020 = 9, ///< ITU-R BT2020 + AVCOL_PRI_SMPTE428 = 10, ///< SMPTE ST 428-1 (CIE 1931 XYZ) + AVCOL_PRI_SMPTEST428_1 = AVCOL_PRI_SMPTE428, + AVCOL_PRI_SMPTE431 = 11, ///< SMPTE ST 431-2 (2011) / DCI P3 + AVCOL_PRI_SMPTE432 = 12, ///< SMPTE ST 432-1 (2010) / P3 D65 / Display P3 + AVCOL_PRI_JEDEC_P22 = 22, ///< JEDEC P22 phosphors + AVCOL_PRI_NB ///< Not part of ABI +}; + +/** + * Color Transfer Characteristic. + */ +enum AVColorTransferCharacteristic { + AVCOL_TRC_RESERVED0 = 0, + AVCOL_TRC_BT709 = 1, ///< also ITU-R BT1361 + AVCOL_TRC_UNSPECIFIED = 2, + AVCOL_TRC_RESERVED = 3, + AVCOL_TRC_GAMMA22 = 4, ///< also ITU-R BT470M / ITU-R BT1700 625 PAL & SECAM + AVCOL_TRC_GAMMA28 = 5, ///< also ITU-R BT470BG + AVCOL_TRC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 or 625 / ITU-R BT1358 525 or 625 / ITU-R BT1700 NTSC + AVCOL_TRC_SMPTE240M = 7, + AVCOL_TRC_LINEAR = 8, ///< "Linear transfer characteristics" + AVCOL_TRC_LOG = 9, ///< "Logarithmic transfer characteristic (100:1 range)" + AVCOL_TRC_LOG_SQRT = 10, ///< "Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range)" + AVCOL_TRC_IEC61966_2_4 = 11, ///< IEC 61966-2-4 + AVCOL_TRC_BT1361_ECG = 12, ///< ITU-R BT1361 Extended Colour Gamut + AVCOL_TRC_IEC61966_2_1 = 13, ///< IEC 61966-2-1 (sRGB or sYCC) + AVCOL_TRC_BT2020_10 = 14, ///< ITU-R BT2020 for 10-bit system + AVCOL_TRC_BT2020_12 = 15, ///< ITU-R BT2020 for 12-bit system + AVCOL_TRC_SMPTE2084 = 16, ///< SMPTE ST 2084 for 10-, 12-, 14- and 16-bit systems + AVCOL_TRC_SMPTEST2084 = AVCOL_TRC_SMPTE2084, + AVCOL_TRC_SMPTE428 = 17, ///< SMPTE ST 428-1 + AVCOL_TRC_SMPTEST428_1 = AVCOL_TRC_SMPTE428, + AVCOL_TRC_ARIB_STD_B67 = 18, ///< ARIB STD-B67, known as "Hybrid log-gamma" + AVCOL_TRC_NB ///< Not part of ABI +}; + +/** + * YUV colorspace type. + */ +enum AVColorSpace { + AVCOL_SPC_RGB = 0, ///< order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB) + AVCOL_SPC_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 xvYCC709 / SMPTE RP177 Annex B + AVCOL_SPC_UNSPECIFIED = 2, + AVCOL_SPC_RESERVED = 3, + AVCOL_SPC_FCC = 4, ///< FCC Title 47 Code of Federal Regulations 73.682 (a)(20) + AVCOL_SPC_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM / IEC 61966-2-4 xvYCC601 + AVCOL_SPC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC + AVCOL_SPC_SMPTE240M = 7, ///< functionally identical to above + AVCOL_SPC_YCGCO = 8, ///< Used by Dirac / VC-2 and H.264 FRext, see ITU-T SG16 + AVCOL_SPC_YCOCG = AVCOL_SPC_YCGCO, + AVCOL_SPC_BT2020_NCL = 9, ///< ITU-R BT2020 non-constant luminance system + AVCOL_SPC_BT2020_CL = 10, ///< ITU-R BT2020 constant luminance system + AVCOL_SPC_SMPTE2085 = 11, ///< SMPTE 2085, Y'D'zD'x + AVCOL_SPC_NB ///< Not part of ABI +}; +#define AVCOL_SPC_YCGCO AVCOL_SPC_YCOCG + + +/** + * MPEG vs JPEG YUV range. + */ +enum AVColorRange { + AVCOL_RANGE_UNSPECIFIED = 0, + AVCOL_RANGE_MPEG = 1, ///< the normal 219*2^(n-8) "MPEG" YUV ranges + AVCOL_RANGE_JPEG = 2, ///< the normal 2^n-1 "JPEG" YUV ranges + AVCOL_RANGE_NB ///< Not part of ABI +}; + +/** + * Location of chroma samples. + * + * Illustration showing the location of the first (top left) chroma sample of the + * image, the left shows only luma, the right + * shows the location of the chroma sample, the 2 could be imagined to overlay + * each other but are drawn separately due to limitations of ASCII + * + * 1st 2nd 1st 2nd horizontal luma sample positions + * v v v v + * ______ ______ + *1st luma line > |X X ... |3 4 X ... X are luma samples, + * | |1 2 1-6 are possible chroma positions + *2nd luma line > |X X ... |5 6 X ... 0 is undefined/unknown position + */ +enum AVChromaLocation { + AVCHROMA_LOC_UNSPECIFIED = 0, + AVCHROMA_LOC_LEFT = 1, ///< MPEG-2/4 4:2:0, H.264 default for 4:2:0 + AVCHROMA_LOC_CENTER = 2, ///< MPEG-1 4:2:0, JPEG 4:2:0, H.263 4:2:0 + AVCHROMA_LOC_TOPLEFT = 3, ///< ITU-R 601, SMPTE 274M 296M S314M(DV 4:1:1), mpeg2 4:2:2 + AVCHROMA_LOC_TOP = 4, + AVCHROMA_LOC_BOTTOMLEFT = 5, + AVCHROMA_LOC_BOTTOM = 6, + AVCHROMA_LOC_NB ///< Not part of ABI +}; + +#endif /* AVUTIL_PIXFMT_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/random_seed.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/random_seed.h new file mode 100644 index 0000000..0462a04 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/random_seed.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2009 Baptiste Coudurier + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_RANDOM_SEED_H +#define AVUTIL_RANDOM_SEED_H + +#include +/** + * @addtogroup lavu_crypto + * @{ + */ + +/** + * Get a seed to use in conjunction with random functions. + * This function tries to provide a good seed at a best effort bases. + * Its possible to call this function multiple times if more bits are needed. + * It can be quite slow, which is why it should only be used as seed for a faster + * PRNG. The quality of the seed depends on the platform. + */ +uint32_t av_get_random_seed(void); + +/** + * @} + */ + +#endif /* AVUTIL_RANDOM_SEED_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/rational.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/rational.h new file mode 100644 index 0000000..5c6b67b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/rational.h @@ -0,0 +1,214 @@ +/* + * rational numbers + * Copyright (c) 2003 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_math_rational + * Utilties for rational number calculation. + * @author Michael Niedermayer + */ + +#ifndef AVUTIL_RATIONAL_H +#define AVUTIL_RATIONAL_H + +#include +#include +#include "attributes.h" + +/** + * @defgroup lavu_math_rational AVRational + * @ingroup lavu_math + * Rational number calculation. + * + * While rational numbers can be expressed as floating-point numbers, the + * conversion process is a lossy one, so are floating-point operations. On the + * other hand, the nature of FFmpeg demands highly accurate calculation of + * timestamps. This set of rational number utilities serves as a generic + * interface for manipulating rational numbers as pairs of numerators and + * denominators. + * + * Many of the functions that operate on AVRational's have the suffix `_q`, in + * reference to the mathematical symbol "ℚ" (Q) which denotes the set of all + * rational numbers. + * + * @{ + */ + +/** + * Rational number (pair of numerator and denominator). + */ +typedef struct AVRational{ + int num; ///< Numerator + int den; ///< Denominator +} AVRational; + +/** + * Create an AVRational. + * + * Useful for compilers that do not support compound literals. + * + * @note The return value is not reduced. + * @see av_reduce() + */ +static inline AVRational av_make_q(int num, int den) +{ + AVRational r = { num, den }; + return r; +} + +/** + * Compare two rationals. + * + * @param a First rational + * @param b Second rational + * + * @return One of the following values: + * - 0 if `a == b` + * - 1 if `a > b` + * - -1 if `a < b` + * - `INT_MIN` if one of the values is of the form `0 / 0` + */ +static inline int av_cmp_q(AVRational a, AVRational b){ + const int64_t tmp= a.num * (int64_t)b.den - b.num * (int64_t)a.den; + + if(tmp) return (int)((tmp ^ a.den ^ b.den)>>63)|1; + else if(b.den && a.den) return 0; + else if(a.num && b.num) return (a.num>>31) - (b.num>>31); + else return INT_MIN; +} + +/** + * Convert an AVRational to a `double`. + * @param a AVRational to convert + * @return `a` in floating-point form + * @see av_d2q() + */ +static inline double av_q2d(AVRational a){ + return a.num / (double) a.den; +} + +/** + * Reduce a fraction. + * + * This is useful for framerate calculations. + * + * @param[out] dst_num Destination numerator + * @param[out] dst_den Destination denominator + * @param[in] num Source numerator + * @param[in] den Source denominator + * @param[in] max Maximum allowed values for `dst_num` & `dst_den` + * @return 1 if the operation is exact, 0 otherwise + */ +int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max); + +/** + * Multiply two rationals. + * @param b First rational + * @param c Second rational + * @return b*c + */ +AVRational av_mul_q(AVRational b, AVRational c) av_const; + +/** + * Divide one rational by another. + * @param b First rational + * @param c Second rational + * @return b/c + */ +AVRational av_div_q(AVRational b, AVRational c) av_const; + +/** + * Add two rationals. + * @param b First rational + * @param c Second rational + * @return b+c + */ +AVRational av_add_q(AVRational b, AVRational c) av_const; + +/** + * Subtract one rational from another. + * @param b First rational + * @param c Second rational + * @return b-c + */ +AVRational av_sub_q(AVRational b, AVRational c) av_const; + +/** + * Invert a rational. + * @param q value + * @return 1 / q + */ +static av_always_inline AVRational av_inv_q(AVRational q) +{ + AVRational r = { q.den, q.num }; + return r; +} + +/** + * Convert a double precision floating point number to a rational. + * + * In case of infinity, the returned value is expressed as `{1, 0}` or + * `{-1, 0}` depending on the sign. + * + * @param d `double` to convert + * @param max Maximum allowed numerator and denominator + * @return `d` in AVRational form + * @see av_q2d() + */ +AVRational av_d2q(double d, int max) av_const; + +/** + * Find which of the two rationals is closer to another rational. + * + * @param q Rational to be compared against + * @param q1,q2 Rationals to be tested + * @return One of the following values: + * - 1 if `q1` is nearer to `q` than `q2` + * - -1 if `q2` is nearer to `q` than `q1` + * - 0 if they have the same distance + */ +int av_nearer_q(AVRational q, AVRational q1, AVRational q2); + +/** + * Find the value in a list of rationals nearest a given reference rational. + * + * @param q Reference rational + * @param q_list Array of rationals terminated by `{0, 0}` + * @return Index of the nearest value found in the array + */ +int av_find_nearest_q_idx(AVRational q, const AVRational* q_list); + +/** + * Convert an AVRational to a IEEE 32-bit `float` expressed in fixed-point + * format. + * + * @param q Rational to be converted + * @return Equivalent floating-point value, expressed as an unsigned 32-bit + * integer. + * @note The returned value is platform-indepedant. + */ +uint32_t av_q2intfloat(AVRational q); + +/** + * @} + */ + +#endif /* AVUTIL_RATIONAL_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/rc4.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/rc4.h new file mode 100644 index 0000000..029cd2a --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/rc4.h @@ -0,0 +1,66 @@ +/* + * RC4 encryption/decryption/pseudo-random number generator + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_RC4_H +#define AVUTIL_RC4_H + +#include + +/** + * @defgroup lavu_rc4 RC4 + * @ingroup lavu_crypto + * @{ + */ + +typedef struct AVRC4 { + uint8_t state[256]; + int x, y; +} AVRC4; + +/** + * Allocate an AVRC4 context. + */ +AVRC4 *av_rc4_alloc(void); + +/** + * @brief Initializes an AVRC4 context. + * + * @param key_bits must be a multiple of 8 + * @param decrypt 0 for encryption, 1 for decryption, currently has no effect + * @return zero on success, negative value otherwise + */ +int av_rc4_init(struct AVRC4 *d, const uint8_t *key, int key_bits, int decrypt); + +/** + * @brief Encrypts / decrypts using the RC4 algorithm. + * + * @param count number of bytes + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst, may be NULL + * @param iv not (yet) used for RC4, should be NULL + * @param decrypt 0 for encryption, 1 for decryption, not (yet) used + */ +void av_rc4_crypt(struct AVRC4 *d, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_RC4_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/replaygain.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/replaygain.h new file mode 100644 index 0000000..b49bf1a --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/replaygain.h @@ -0,0 +1,50 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_REPLAYGAIN_H +#define AVUTIL_REPLAYGAIN_H + +#include + +/** + * ReplayGain information (see + * http://wiki.hydrogenaudio.org/index.php?title=ReplayGain_1.0_specification). + * The size of this struct is a part of the public ABI. + */ +typedef struct AVReplayGain { + /** + * Track replay gain in microbels (divide by 100000 to get the value in dB). + * Should be set to INT32_MIN when unknown. + */ + int32_t track_gain; + /** + * Peak track amplitude, with 100000 representing full scale (but values + * may overflow). 0 when unknown. + */ + uint32_t track_peak; + /** + * Same as track_gain, but for the whole album. + */ + int32_t album_gain; + /** + * Same as track_peak, but for the whole album, + */ + uint32_t album_peak; +} AVReplayGain; + +#endif /* AVUTIL_REPLAYGAIN_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/ripemd.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/ripemd.h new file mode 100644 index 0000000..6d6bb32 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/ripemd.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2007 Michael Niedermayer + * Copyright (C) 2013 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_ripemd + * Public header for RIPEMD hash function implementation. + */ + +#ifndef AVUTIL_RIPEMD_H +#define AVUTIL_RIPEMD_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_ripemd RIPEMD + * @ingroup lavu_hash + * RIPEMD hash function implementation. + * + * @{ + */ + +extern const int av_ripemd_size; + +struct AVRIPEMD; + +/** + * Allocate an AVRIPEMD context. + */ +struct AVRIPEMD *av_ripemd_alloc(void); + +/** + * Initialize RIPEMD hashing. + * + * @param context pointer to the function context (of size av_ripemd_size) + * @param bits number of bits in digest (128, 160, 256 or 320 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_ripemd_init(struct AVRIPEMD* context, int bits); + +/** + * Update hash value. + * + * @param context hash function context + * @param data input data to update hash with + * @param len input data length + */ +void av_ripemd_update(struct AVRIPEMD* context, const uint8_t* data, unsigned int len); + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_ripemd_final(struct AVRIPEMD* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_RIPEMD_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/samplefmt.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/samplefmt.h new file mode 100644 index 0000000..8cd43ae --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/samplefmt.h @@ -0,0 +1,272 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SAMPLEFMT_H +#define AVUTIL_SAMPLEFMT_H + +#include + +#include "avutil.h" +#include "attributes.h" + +/** + * @addtogroup lavu_audio + * @{ + * + * @defgroup lavu_sampfmts Audio sample formats + * + * Audio sample format enumeration and related convenience functions. + * @{ + */ + +/** + * Audio sample formats + * + * - The data described by the sample format is always in native-endian order. + * Sample values can be expressed by native C types, hence the lack of a signed + * 24-bit sample format even though it is a common raw audio data format. + * + * - The floating-point formats are based on full volume being in the range + * [-1.0, 1.0]. Any values outside this range are beyond full volume level. + * + * - The data layout as used in av_samples_fill_arrays() and elsewhere in FFmpeg + * (such as AVFrame in libavcodec) is as follows: + * + * @par + * For planar sample formats, each audio channel is in a separate data plane, + * and linesize is the buffer size, in bytes, for a single plane. All data + * planes must be the same size. For packed sample formats, only the first data + * plane is used, and samples for each channel are interleaved. In this case, + * linesize is the buffer size, in bytes, for the 1 plane. + * + */ +enum AVSampleFormat { + AV_SAMPLE_FMT_NONE = -1, + AV_SAMPLE_FMT_U8, ///< unsigned 8 bits + AV_SAMPLE_FMT_S16, ///< signed 16 bits + AV_SAMPLE_FMT_S32, ///< signed 32 bits + AV_SAMPLE_FMT_FLT, ///< float + AV_SAMPLE_FMT_DBL, ///< double + + AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar + AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar + AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar + AV_SAMPLE_FMT_FLTP, ///< float, planar + AV_SAMPLE_FMT_DBLP, ///< double, planar + AV_SAMPLE_FMT_S64, ///< signed 64 bits + AV_SAMPLE_FMT_S64P, ///< signed 64 bits, planar + + AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically +}; + +/** + * Return the name of sample_fmt, or NULL if sample_fmt is not + * recognized. + */ +const char *av_get_sample_fmt_name(enum AVSampleFormat sample_fmt); + +/** + * Return a sample format corresponding to name, or AV_SAMPLE_FMT_NONE + * on error. + */ +enum AVSampleFormat av_get_sample_fmt(const char *name); + +/** + * Return the planar<->packed alternative form of the given sample format, or + * AV_SAMPLE_FMT_NONE on error. If the passed sample_fmt is already in the + * requested planar/packed format, the format returned is the same as the + * input. + */ +enum AVSampleFormat av_get_alt_sample_fmt(enum AVSampleFormat sample_fmt, int planar); + +/** + * Get the packed alternative form of the given sample format. + * + * If the passed sample_fmt is already in packed format, the format returned is + * the same as the input. + * + * @return the packed alternative form of the given sample format or + AV_SAMPLE_FMT_NONE on error. + */ +enum AVSampleFormat av_get_packed_sample_fmt(enum AVSampleFormat sample_fmt); + +/** + * Get the planar alternative form of the given sample format. + * + * If the passed sample_fmt is already in planar format, the format returned is + * the same as the input. + * + * @return the planar alternative form of the given sample format or + AV_SAMPLE_FMT_NONE on error. + */ +enum AVSampleFormat av_get_planar_sample_fmt(enum AVSampleFormat sample_fmt); + +/** + * Generate a string corresponding to the sample format with + * sample_fmt, or a header if sample_fmt is negative. + * + * @param buf the buffer where to write the string + * @param buf_size the size of buf + * @param sample_fmt the number of the sample format to print the + * corresponding info string, or a negative value to print the + * corresponding header. + * @return the pointer to the filled buffer or NULL if sample_fmt is + * unknown or in case of other errors + */ +char *av_get_sample_fmt_string(char *buf, int buf_size, enum AVSampleFormat sample_fmt); + +/** + * Return number of bytes per sample. + * + * @param sample_fmt the sample format + * @return number of bytes per sample or zero if unknown for the given + * sample format + */ +int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt); + +/** + * Check if the sample format is planar. + * + * @param sample_fmt the sample format to inspect + * @return 1 if the sample format is planar, 0 if it is interleaved + */ +int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt); + +/** + * Get the required buffer size for the given audio parameters. + * + * @param[out] linesize calculated linesize, may be NULL + * @param nb_channels the number of channels + * @param nb_samples the number of samples in a single channel + * @param sample_fmt the sample format + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return required buffer size, or negative error code on failure + */ +int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align); + +/** + * @} + * + * @defgroup lavu_sampmanip Samples manipulation + * + * Functions that manipulate audio samples + * @{ + */ + +/** + * Fill plane data pointers and linesize for samples with sample + * format sample_fmt. + * + * The audio_data array is filled with the pointers to the samples data planes: + * for planar, set the start point of each channel's data within the buffer, + * for packed, set the start point of the entire buffer only. + * + * The value pointed to by linesize is set to the aligned size of each + * channel's data buffer for planar layout, or to the aligned size of the + * buffer for all channels for packed layout. + * + * The buffer in buf must be big enough to contain all the samples + * (use av_samples_get_buffer_size() to compute its minimum size), + * otherwise the audio_data pointers will point to invalid data. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param[out] audio_data array to be filled with the pointer for each channel + * @param[out] linesize calculated linesize, may be NULL + * @param buf the pointer to a buffer containing the samples + * @param nb_channels the number of channels + * @param nb_samples the number of samples in a single channel + * @param sample_fmt the sample format + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return >=0 on success or a negative error code on failure + * @todo return minimum size in bytes required for the buffer in case + * of success at the next bump + */ +int av_samples_fill_arrays(uint8_t **audio_data, int *linesize, + const uint8_t *buf, + int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align); + +/** + * Allocate a samples buffer for nb_samples samples, and fill data pointers and + * linesize accordingly. + * The allocated samples buffer can be freed by using av_freep(&audio_data[0]) + * Allocated data will be initialized to silence. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param[out] audio_data array to be filled with the pointer for each channel + * @param[out] linesize aligned size for audio buffer(s), may be NULL + * @param nb_channels number of audio channels + * @param nb_samples number of samples per channel + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return >=0 on success or a negative error code on failure + * @todo return the size of the allocated buffer in case of success at the next bump + * @see av_samples_fill_arrays() + * @see av_samples_alloc_array_and_samples() + */ +int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align); + +/** + * Allocate a data pointers array, samples buffer for nb_samples + * samples, and fill data pointers and linesize accordingly. + * + * This is the same as av_samples_alloc(), but also allocates the data + * pointers array. + * + * @see av_samples_alloc() + */ +int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align); + +/** + * Copy samples from src to dst. + * + * @param dst destination array of pointers to data planes + * @param src source array of pointers to data planes + * @param dst_offset offset in samples at which the data will be written to dst + * @param src_offset offset in samples at which the data will be read from src + * @param nb_samples number of samples to be copied + * @param nb_channels number of audio channels + * @param sample_fmt audio sample format + */ +int av_samples_copy(uint8_t **dst, uint8_t * const *src, int dst_offset, + int src_offset, int nb_samples, int nb_channels, + enum AVSampleFormat sample_fmt); + +/** + * Fill an audio buffer with silence. + * + * @param audio_data array of pointers to data planes + * @param offset offset in samples at which to start filling + * @param nb_samples number of samples to fill + * @param nb_channels number of audio channels + * @param sample_fmt audio sample format + */ +int av_samples_set_silence(uint8_t **audio_data, int offset, int nb_samples, + int nb_channels, enum AVSampleFormat sample_fmt); + +/** + * @} + * @} + */ +#endif /* AVUTIL_SAMPLEFMT_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/sha.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/sha.h new file mode 100644 index 0000000..c7558a8 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/sha.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2007 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_sha + * Public header for SHA-1 & SHA-256 hash function implementations. + */ + +#ifndef AVUTIL_SHA_H +#define AVUTIL_SHA_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_sha SHA + * @ingroup lavu_hash + * SHA-1 and SHA-256 (Secure Hash Algorithm) hash function implementations. + * + * This module supports the following SHA hash functions: + * + * - SHA-1: 160 bits + * - SHA-224: 224 bits, as a variant of SHA-2 + * - SHA-256: 256 bits, as a variant of SHA-2 + * + * @see For SHA-384, SHA-512, and variants thereof, see @ref lavu_sha512. + * + * @{ + */ + +extern const int av_sha_size; + +struct AVSHA; + +/** + * Allocate an AVSHA context. + */ +struct AVSHA *av_sha_alloc(void); + +/** + * Initialize SHA-1 or SHA-2 hashing. + * + * @param context pointer to the function context (of size av_sha_size) + * @param bits number of bits in digest (SHA-1 - 160 bits, SHA-2 224 or 256 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_sha_init(struct AVSHA* context, int bits); + +/** + * Update hash value. + * + * @param context hash function context + * @param data input data to update hash with + * @param len input data length + */ +void av_sha_update(struct AVSHA* context, const uint8_t* data, unsigned int len); + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_sha_final(struct AVSHA* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_SHA_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/sha512.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/sha512.h new file mode 100644 index 0000000..5bac184 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/sha512.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2007 Michael Niedermayer + * Copyright (C) 2013 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_sha512 + * Public header for SHA-512 implementation. + */ + +#ifndef AVUTIL_SHA512_H +#define AVUTIL_SHA512_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_sha512 SHA-512 + * @ingroup lavu_hash + * SHA-512 (Secure Hash Algorithm) hash function implementations. + * + * This module supports the following SHA-2 hash functions: + * + * - SHA-512/224: 224 bits + * - SHA-512/256: 256 bits + * - SHA-384: 384 bits + * - SHA-512: 512 bits + * + * @see For SHA-1, SHA-256, and variants thereof, see @ref lavu_sha. + * + * @{ + */ + +extern const int av_sha512_size; + +struct AVSHA512; + +/** + * Allocate an AVSHA512 context. + */ +struct AVSHA512 *av_sha512_alloc(void); + +/** + * Initialize SHA-2 512 hashing. + * + * @param context pointer to the function context (of size av_sha512_size) + * @param bits number of bits in digest (224, 256, 384 or 512 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_sha512_init(struct AVSHA512* context, int bits); + +/** + * Update hash value. + * + * @param context hash function context + * @param data input data to update hash with + * @param len input data length + */ +void av_sha512_update(struct AVSHA512* context, const uint8_t* data, unsigned int len); + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_sha512_final(struct AVSHA512* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_SHA512_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/spherical.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/spherical.h new file mode 100644 index 0000000..cef759c --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/spherical.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2016 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Spherical video + */ + +#ifndef AVUTIL_SPHERICAL_H +#define AVUTIL_SPHERICAL_H + +#include +#include + +/** + * @addtogroup lavu_video + * @{ + * + * @defgroup lavu_video_spherical Spherical video mapping + * @{ + */ + +/** + * @addtogroup lavu_video_spherical + * A spherical video file contains surfaces that need to be mapped onto a + * sphere. Depending on how the frame was converted, a different distortion + * transformation or surface recomposition function needs to be applied before + * the video should be mapped and displayed. + */ + +/** + * Projection of the video surface(s) on a sphere. + */ +enum AVSphericalProjection { + /** + * Video represents a sphere mapped on a flat surface using + * equirectangular projection. + */ + AV_SPHERICAL_EQUIRECTANGULAR, + + /** + * Video frame is split into 6 faces of a cube, and arranged on a + * 3x2 layout. Faces are oriented upwards for the front, left, right, + * and back faces. The up face is oriented so the top of the face is + * forwards and the down face is oriented so the top of the face is + * to the back. + */ + AV_SPHERICAL_CUBEMAP, + + /** + * Video represents a portion of a sphere mapped on a flat surface + * using equirectangular projection. The @ref bounding fields indicate + * the position of the current video in a larger surface. + */ + AV_SPHERICAL_EQUIRECTANGULAR_TILE, +}; + +/** + * This structure describes how to handle spherical videos, outlining + * information about projection, initial layout, and any other view modifier. + * + * @note The struct must be allocated with av_spherical_alloc() and + * its size is not a part of the public ABI. + */ +typedef struct AVSphericalMapping { + /** + * Projection type. + */ + enum AVSphericalProjection projection; + + /** + * @name Initial orientation + * @{ + * There fields describe additional rotations applied to the sphere after + * the video frame is mapped onto it. The sphere is rotated around the + * viewer, who remains stationary. The order of transformation is always + * yaw, followed by pitch, and finally by roll. + * + * The coordinate system matches the one defined in OpenGL, where the + * forward vector (z) is coming out of screen, and it is equivalent to + * a rotation matrix of R = r_y(yaw) * r_x(pitch) * r_z(roll). + * + * A positive yaw rotates the portion of the sphere in front of the viewer + * toward their right. A positive pitch rotates the portion of the sphere + * in front of the viewer upwards. A positive roll tilts the portion of + * the sphere in front of the viewer to the viewer's right. + * + * These values are exported as 16.16 fixed point. + * + * See this equirectangular projection as example: + * + * @code{.unparsed} + * Yaw + * -180 0 180 + * 90 +-------------+-------------+ 180 + * | | | up + * P | | | y| forward + * i | ^ | | /z + * t 0 +-------------X-------------+ 0 Roll | / + * c | | | | / + * h | | | 0|/_____right + * | | | x + * -90 +-------------+-------------+ -180 + * + * X - the default camera center + * ^ - the default up vector + * @endcode + */ + int32_t yaw; ///< Rotation around the up vector [-180, 180]. + int32_t pitch; ///< Rotation around the right vector [-90, 90]. + int32_t roll; ///< Rotation around the forward vector [-180, 180]. + /** + * @} + */ + + /** + * @name Bounding rectangle + * @anchor bounding + * @{ + * These fields indicate the location of the current tile, and where + * it should be mapped relative to the original surface. They are + * exported as 0.32 fixed point, and can be converted to classic + * pixel values with av_spherical_bounds(). + * + * @code{.unparsed} + * +----------------+----------+ + * | |bound_top | + * | +--------+ | + * | bound_left |tile | | + * +<---------->| |<--->+bound_right + * | +--------+ | + * | | | + * | bound_bottom| | + * +----------------+----------+ + * @endcode + * + * If needed, the original video surface dimensions can be derived + * by adding the current stream or frame size to the related bounds, + * like in the following example: + * + * @code{c} + * original_width = tile->width + bound_left + bound_right; + * original_height = tile->height + bound_top + bound_bottom; + * @endcode + * + * @note These values are valid only for the tiled equirectangular + * projection type (@ref AV_SPHERICAL_EQUIRECTANGULAR_TILE), + * and should be ignored in all other cases. + */ + uint32_t bound_left; ///< Distance from the left edge + uint32_t bound_top; ///< Distance from the top edge + uint32_t bound_right; ///< Distance from the right edge + uint32_t bound_bottom; ///< Distance from the bottom edge + /** + * @} + */ + + /** + * Number of pixels to pad from the edge of each cube face. + * + * @note This value is valid for only for the cubemap projection type + * (@ref AV_SPHERICAL_CUBEMAP), and should be ignored in all other + * cases. + */ + uint32_t padding; +} AVSphericalMapping; + +/** + * Allocate a AVSphericalVideo structure and initialize its fields to default + * values. + * + * @return the newly allocated struct or NULL on failure + */ +AVSphericalMapping *av_spherical_alloc(size_t *size); + +/** + * Convert the @ref bounding fields from an AVSphericalVideo + * from 0.32 fixed point to pixels. + * + * @param map The AVSphericalVideo map to read bound values from. + * @param width Width of the current frame or stream. + * @param height Height of the current frame or stream. + * @param left Pixels from the left edge. + * @param top Pixels from the top edge. + * @param right Pixels from the right edge. + * @param bottom Pixels from the bottom edge. + */ +void av_spherical_tile_bounds(const AVSphericalMapping *map, + size_t width, size_t height, + size_t *left, size_t *top, + size_t *right, size_t *bottom); + +/** + * Provide a human-readable name of a given AVSphericalProjection. + * + * @param projection The input AVSphericalProjection. + * + * @return The name of the AVSphericalProjection, or "unknown". + */ +const char *av_spherical_projection_name(enum AVSphericalProjection projection); + +/** + * Get the AVSphericalProjection form a human-readable name. + * + * @param name The input string. + * + * @return The AVSphericalProjection value, or -1 if not found. + */ +int av_spherical_from_name(const char *name); +/** + * @} + * @} + */ + +#endif /* AVUTIL_SPHERICAL_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/stereo3d.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/stereo3d.h new file mode 100644 index 0000000..19c5416 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/stereo3d.h @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2013 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_STEREO3D_H +#define AVUTIL_STEREO3D_H + +#include + +#include "frame.h" + +/** + * List of possible 3D Types + */ +enum AVStereo3DType { + /** + * Video is not stereoscopic (and metadata has to be there). + */ + AV_STEREO3D_2D, + + /** + * Views are next to each other. + * + * LLLLRRRR + * LLLLRRRR + * LLLLRRRR + * ... + */ + AV_STEREO3D_SIDEBYSIDE, + + /** + * Views are on top of each other. + * + * LLLLLLLL + * LLLLLLLL + * RRRRRRRR + * RRRRRRRR + */ + AV_STEREO3D_TOPBOTTOM, + + /** + * Views are alternated temporally. + * + * frame0 frame1 frame2 ... + * LLLLLLLL RRRRRRRR LLLLLLLL + * LLLLLLLL RRRRRRRR LLLLLLLL + * LLLLLLLL RRRRRRRR LLLLLLLL + * ... ... ... + */ + AV_STEREO3D_FRAMESEQUENCE, + + /** + * Views are packed in a checkerboard-like structure per pixel. + * + * LRLRLRLR + * RLRLRLRL + * LRLRLRLR + * ... + */ + AV_STEREO3D_CHECKERBOARD, + + /** + * Views are next to each other, but when upscaling + * apply a checkerboard pattern. + * + * LLLLRRRR L L L L R R R R + * LLLLRRRR => L L L L R R R R + * LLLLRRRR L L L L R R R R + * LLLLRRRR L L L L R R R R + */ + AV_STEREO3D_SIDEBYSIDE_QUINCUNX, + + /** + * Views are packed per line, as if interlaced. + * + * LLLLLLLL + * RRRRRRRR + * LLLLLLLL + * ... + */ + AV_STEREO3D_LINES, + + /** + * Views are packed per column. + * + * LRLRLRLR + * LRLRLRLR + * LRLRLRLR + * ... + */ + AV_STEREO3D_COLUMNS, +}; + + +/** + * Inverted views, Right/Bottom represents the left view. + */ +#define AV_STEREO3D_FLAG_INVERT (1 << 0) + +/** + * Stereo 3D type: this structure describes how two videos are packed + * within a single video surface, with additional information as needed. + * + * @note The struct must be allocated with av_stereo3d_alloc() and + * its size is not a part of the public ABI. + */ +typedef struct AVStereo3D { + /** + * How views are packed within the video. + */ + enum AVStereo3DType type; + + /** + * Additional information about the frame packing. + */ + int flags; +} AVStereo3D; + +/** + * Allocate an AVStereo3D structure and set its fields to default values. + * The resulting struct can be freed using av_freep(). + * + * @return An AVStereo3D filled with default values or NULL on failure. + */ +AVStereo3D *av_stereo3d_alloc(void); + +/** + * Allocate a complete AVFrameSideData and add it to the frame. + * + * @param frame The frame which side data is added to. + * + * @return The AVStereo3D structure to be filled by caller. + */ +AVStereo3D *av_stereo3d_create_side_data(AVFrame *frame); + +/** + * Provide a human-readable name of a given stereo3d type. + * + * @param type The input stereo3d type value. + * + * @return The name of the stereo3d value, or "unknown". + */ +const char *av_stereo3d_type_name(unsigned int type); + +/** + * Get the AVStereo3DType form a human-readable name. + * + * @param type The input string. + * + * @return The AVStereo3DType value, or -1 if not found. + */ +int av_stereo3d_from_name(const char *name); + +#endif /* AVUTIL_STEREO3D_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/tea.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/tea.h new file mode 100644 index 0000000..dd929bd --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/tea.h @@ -0,0 +1,71 @@ +/* + * A 32-bit implementation of the TEA algorithm + * Copyright (c) 2015 Vesselin Bontchev + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TEA_H +#define AVUTIL_TEA_H + +#include + +/** + * @file + * @brief Public header for libavutil TEA algorithm + * @defgroup lavu_tea TEA + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_tea_size; + +struct AVTEA; + +/** + * Allocate an AVTEA context + * To free the struct: av_free(ptr) + */ +struct AVTEA *av_tea_alloc(void); + +/** + * Initialize an AVTEA context. + * + * @param ctx an AVTEA context + * @param key a key of 16 bytes used for encryption/decryption + * @param rounds the number of rounds in TEA (64 is the "standard") + */ +void av_tea_init(struct AVTEA *ctx, const uint8_t key[16], int rounds); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVTEA context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_tea_crypt(struct AVTEA *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_TEA_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/threadmessage.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/threadmessage.h new file mode 100644 index 0000000..8480a0a --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/threadmessage.h @@ -0,0 +1,107 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_THREADMESSAGE_H +#define AVUTIL_THREADMESSAGE_H + +typedef struct AVThreadMessageQueue AVThreadMessageQueue; + +typedef enum AVThreadMessageFlags { + + /** + * Perform non-blocking operation. + * If this flag is set, send and recv operations are non-blocking and + * return AVERROR(EAGAIN) immediately if they can not proceed. + */ + AV_THREAD_MESSAGE_NONBLOCK = 1, + +} AVThreadMessageFlags; + +/** + * Allocate a new message queue. + * + * @param mq pointer to the message queue + * @param nelem maximum number of elements in the queue + * @param elsize size of each element in the queue + * @return >=0 for success; <0 for error, in particular AVERROR(ENOSYS) if + * lavu was built without thread support + */ +int av_thread_message_queue_alloc(AVThreadMessageQueue **mq, + unsigned nelem, + unsigned elsize); + +/** + * Free a message queue. + * + * The message queue must no longer be in use by another thread. + */ +void av_thread_message_queue_free(AVThreadMessageQueue **mq); + +/** + * Send a message on the queue. + */ +int av_thread_message_queue_send(AVThreadMessageQueue *mq, + void *msg, + unsigned flags); + +/** + * Receive a message from the queue. + */ +int av_thread_message_queue_recv(AVThreadMessageQueue *mq, + void *msg, + unsigned flags); + +/** + * Set the sending error code. + * + * If the error code is set to non-zero, av_thread_message_queue_send() will + * return it immediately. Conventional values, such as AVERROR_EOF or + * AVERROR(EAGAIN), can be used to cause the sending thread to stop or + * suspend its operation. + */ +void av_thread_message_queue_set_err_send(AVThreadMessageQueue *mq, + int err); + +/** + * Set the receiving error code. + * + * If the error code is set to non-zero, av_thread_message_queue_recv() will + * return it immediately when there are no longer available messages. + * Conventional values, such as AVERROR_EOF or AVERROR(EAGAIN), can be used + * to cause the receiving thread to stop or suspend its operation. + */ +void av_thread_message_queue_set_err_recv(AVThreadMessageQueue *mq, + int err); + +/** + * Set the optional free message callback function which will be called if an + * operation is removing messages from the queue. + */ +void av_thread_message_queue_set_free_func(AVThreadMessageQueue *mq, + void (*free_func)(void *msg)); + +/** + * Flush the message queue + * + * This function is mostly equivalent to reading and free-ing every message + * except that it will be done in a single operation (no lock/unlock between + * reads). + */ +void av_thread_message_flush(AVThreadMessageQueue *mq); + +#endif /* AVUTIL_THREADMESSAGE_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/time.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/time.h new file mode 100644 index 0000000..dc169b0 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/time.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2000-2003 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TIME_H +#define AVUTIL_TIME_H + +#include + +/** + * Get the current time in microseconds. + */ +int64_t av_gettime(void); + +/** + * Get the current time in microseconds since some unspecified starting point. + * On platforms that support it, the time comes from a monotonic clock + * This property makes this time source ideal for measuring relative time. + * The returned values may not be monotonic on platforms where a monotonic + * clock is not available. + */ +int64_t av_gettime_relative(void); + +/** + * Indicates with a boolean result if the av_gettime_relative() time source + * is monotonic. + */ +int av_gettime_relative_is_monotonic(void); + +/** + * Sleep for a period of time. Although the duration is expressed in + * microseconds, the actual delay may be rounded to the precision of the + * system timer. + * + * @param usec Number of microseconds to sleep. + * @return zero on success or (negative) error code. + */ +int av_usleep(unsigned usec); + +#endif /* AVUTIL_TIME_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/timecode.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/timecode.h new file mode 100644 index 0000000..56e3975 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/timecode.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2006 Smartjog S.A.S, Baptiste Coudurier + * Copyright (c) 2011-2012 Smartjog S.A.S, Clément Bœsch + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Timecode helpers header + */ + +#ifndef AVUTIL_TIMECODE_H +#define AVUTIL_TIMECODE_H + +#include +#include "rational.h" + +#define AV_TIMECODE_STR_SIZE 16 + +enum AVTimecodeFlag { + AV_TIMECODE_FLAG_DROPFRAME = 1<<0, ///< timecode is drop frame + AV_TIMECODE_FLAG_24HOURSMAX = 1<<1, ///< timecode wraps after 24 hours + AV_TIMECODE_FLAG_ALLOWNEGATIVE = 1<<2, ///< negative time values are allowed +}; + +typedef struct { + int start; ///< timecode frame start (first base frame number) + uint32_t flags; ///< flags such as drop frame, +24 hours support, ... + AVRational rate; ///< frame rate in rational form + unsigned fps; ///< frame per second; must be consistent with the rate field +} AVTimecode; + +/** + * Adjust frame number for NTSC drop frame time code. + * + * @param framenum frame number to adjust + * @param fps frame per second, 30 or 60 + * @return adjusted frame number + * @warning adjustment is only valid in NTSC 29.97 and 59.94 + */ +int av_timecode_adjust_ntsc_framenum2(int framenum, int fps); + +/** + * Convert frame number to SMPTE 12M binary representation. + * + * @param tc timecode data correctly initialized + * @param framenum frame number + * @return the SMPTE binary representation + * + * @note Frame number adjustment is automatically done in case of drop timecode, + * you do NOT have to call av_timecode_adjust_ntsc_framenum2(). + * @note The frame number is relative to tc->start. + * @note Color frame (CF), binary group flags (BGF) and biphase mark polarity + * correction (PC) bits are set to zero. + */ +uint32_t av_timecode_get_smpte_from_framenum(const AVTimecode *tc, int framenum); + +/** + * Load timecode string in buf. + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param tc timecode data correctly initialized + * @param framenum frame number + * @return the buf parameter + * + * @note Timecode representation can be a negative timecode and have more than + * 24 hours, but will only be honored if the flags are correctly set. + * @note The frame number is relative to tc->start. + */ +char *av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum); + +/** + * Get the timecode string from the SMPTE timecode format. + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param tcsmpte the 32-bit SMPTE timecode + * @param prevent_df prevent the use of a drop flag when it is known the DF bit + * is arbitrary + * @return the buf parameter + */ +char *av_timecode_make_smpte_tc_string(char *buf, uint32_t tcsmpte, int prevent_df); + +/** + * Get the timecode string from the 25-bit timecode format (MPEG GOP format). + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param tc25bit the 25-bits timecode + * @return the buf parameter + */ +char *av_timecode_make_mpeg_tc_string(char *buf, uint32_t tc25bit); + +/** + * Init a timecode struct with the passed parameters. + * + * @param log_ctx a pointer to an arbitrary struct of which the first field + * is a pointer to an AVClass struct (used for av_log) + * @param tc pointer to an allocated AVTimecode + * @param rate frame rate in rational form + * @param flags miscellaneous flags such as drop frame, +24 hours, ... + * (see AVTimecodeFlag) + * @param frame_start the first frame number + * @return 0 on success, AVERROR otherwise + */ +int av_timecode_init(AVTimecode *tc, AVRational rate, int flags, int frame_start, void *log_ctx); + +/** + * Parse timecode representation (hh:mm:ss[:;.]ff). + * + * @param log_ctx a pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct (used for av_log). + * @param tc pointer to an allocated AVTimecode + * @param rate frame rate in rational form + * @param str timecode string which will determine the frame start + * @return 0 on success, AVERROR otherwise + */ +int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx); + +/** + * Check if the timecode feature is available for the given frame rate + * + * @return 0 if supported, <0 otherwise + */ +int av_timecode_check_frame_rate(AVRational rate); + +#endif /* AVUTIL_TIMECODE_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/timestamp.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/timestamp.h new file mode 100644 index 0000000..e082f01 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/timestamp.h @@ -0,0 +1,78 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * timestamp utils, mostly useful for debugging/logging purposes + */ + +#ifndef AVUTIL_TIMESTAMP_H +#define AVUTIL_TIMESTAMP_H + +#include "common.h" + +#if defined(__cplusplus) && !defined(__STDC_FORMAT_MACROS) && !defined(PRId64) +#error missing -D__STDC_FORMAT_MACROS / #define __STDC_FORMAT_MACROS +#endif + +#define AV_TS_MAX_STRING_SIZE 32 + +/** + * Fill the provided buffer with a string containing a timestamp + * representation. + * + * @param buf a buffer with size in bytes of at least AV_TS_MAX_STRING_SIZE + * @param ts the timestamp to represent + * @return the buffer in input + */ +static inline char *av_ts_make_string(char *buf, int64_t ts) +{ + if (ts == AV_NOPTS_VALUE) snprintf(buf, AV_TS_MAX_STRING_SIZE, "NOPTS"); + else snprintf(buf, AV_TS_MAX_STRING_SIZE, "%" PRId64, ts); + return buf; +} + +/** + * Convenience macro, the return value should be used only directly in + * function arguments but never stand-alone. + */ +#define av_ts2str(ts) av_ts_make_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts) + +/** + * Fill the provided buffer with a string containing a timestamp time + * representation. + * + * @param buf a buffer with size in bytes of at least AV_TS_MAX_STRING_SIZE + * @param ts the timestamp to represent + * @param tb the timebase of the timestamp + * @return the buffer in input + */ +static inline char *av_ts_make_time_string(char *buf, int64_t ts, AVRational *tb) +{ + if (ts == AV_NOPTS_VALUE) snprintf(buf, AV_TS_MAX_STRING_SIZE, "NOPTS"); + else snprintf(buf, AV_TS_MAX_STRING_SIZE, "%.6g", av_q2d(*tb) * ts); + return buf; +} + +/** + * Convenience macro, the return value should be used only directly in + * function arguments but never stand-alone. + */ +#define av_ts2timestr(ts, tb) av_ts_make_time_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts, tb) + +#endif /* AVUTIL_TIMESTAMP_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/tree.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/tree.h new file mode 100644 index 0000000..d5e0aeb --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/tree.h @@ -0,0 +1,138 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * A tree container. + * @author Michael Niedermayer + */ + +#ifndef AVUTIL_TREE_H +#define AVUTIL_TREE_H + +#include "attributes.h" +#include "version.h" + +/** + * @addtogroup lavu_tree AVTree + * @ingroup lavu_data + * + * Low-complexity tree container + * + * Insertion, removal, finding equal, largest which is smaller than and + * smallest which is larger than, all have O(log n) worst-case complexity. + * @{ + */ + + +struct AVTreeNode; +extern const int av_tree_node_size; + +/** + * Allocate an AVTreeNode. + */ +struct AVTreeNode *av_tree_node_alloc(void); + +/** + * Find an element. + * @param root a pointer to the root node of the tree + * @param next If next is not NULL, then next[0] will contain the previous + * element and next[1] the next element. If either does not exist, + * then the corresponding entry in next is unchanged. + * @param cmp compare function used to compare elements in the tree, + * API identical to that of Standard C's qsort + * It is guaranteed that the first and only the first argument to cmp() + * will be the key parameter to av_tree_find(), thus it could if the + * user wants, be a different type (like an opaque context). + * @return An element with cmp(key, elem) == 0 or NULL if no such element + * exists in the tree. + */ +void *av_tree_find(const struct AVTreeNode *root, void *key, + int (*cmp)(const void *key, const void *b), void *next[2]); + +/** + * Insert or remove an element. + * + * If *next is NULL, then the supplied element will be removed if it exists. + * If *next is non-NULL, then the supplied element will be inserted, unless + * it already exists in the tree. + * + * @param rootp A pointer to a pointer to the root node of the tree; note that + * the root node can change during insertions, this is required + * to keep the tree balanced. + * @param key pointer to the element key to insert in the tree + * @param next Used to allocate and free AVTreeNodes. For insertion the user + * must set it to an allocated and zeroed object of at least + * av_tree_node_size bytes size. av_tree_insert() will set it to + * NULL if it has been consumed. + * For deleting elements *next is set to NULL by the user and + * av_tree_insert() will set it to the AVTreeNode which was + * used for the removed element. + * This allows the use of flat arrays, which have + * lower overhead compared to many malloced elements. + * You might want to define a function like: + * @code + * void *tree_insert(struct AVTreeNode **rootp, void *key, + * int (*cmp)(void *key, const void *b), + * AVTreeNode **next) + * { + * if (!*next) + * *next = av_mallocz(av_tree_node_size); + * return av_tree_insert(rootp, key, cmp, next); + * } + * void *tree_remove(struct AVTreeNode **rootp, void *key, + * int (*cmp)(void *key, const void *b, AVTreeNode **next)) + * { + * av_freep(next); + * return av_tree_insert(rootp, key, cmp, next); + * } + * @endcode + * @param cmp compare function used to compare elements in the tree, API identical + * to that of Standard C's qsort + * @return If no insertion happened, the found element; if an insertion or + * removal happened, then either key or NULL will be returned. + * Which one it is depends on the tree state and the implementation. You + * should make no assumptions that it's one or the other in the code. + */ +void *av_tree_insert(struct AVTreeNode **rootp, void *key, + int (*cmp)(const void *key, const void *b), + struct AVTreeNode **next); + +void av_tree_destroy(struct AVTreeNode *t); + +/** + * Apply enu(opaque, &elem) to all the elements in the tree in a given range. + * + * @param cmp a comparison function that returns < 0 for an element below the + * range, > 0 for an element above the range and == 0 for an + * element inside the range + * + * @note The cmp function should use the same ordering used to construct the + * tree. + */ +void av_tree_enumerate(struct AVTreeNode *t, void *opaque, + int (*cmp)(void *opaque, void *elem), + int (*enu)(void *opaque, void *elem)); + +/** + * @} + */ + +#endif /* AVUTIL_TREE_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/twofish.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/twofish.h new file mode 100644 index 0000000..813cfec --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/twofish.h @@ -0,0 +1,70 @@ +/* + * An implementation of the TwoFish algorithm + * Copyright (c) 2015 Supraja Meedinti + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TWOFISH_H +#define AVUTIL_TWOFISH_H + +#include + + +/** + * @file + * @brief Public header for libavutil TWOFISH algorithm + * @defgroup lavu_twofish TWOFISH + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_twofish_size; + +struct AVTWOFISH; + +/** + * Allocate an AVTWOFISH context + * To free the struct: av_free(ptr) + */ +struct AVTWOFISH *av_twofish_alloc(void); + +/** + * Initialize an AVTWOFISH context. + * + * @param ctx an AVTWOFISH context + * @param key a key of size ranging from 1 to 32 bytes used for encryption/decryption + * @param key_bits number of keybits: 128, 192, 256 If less than the required, padded with zeroes to nearest valid value; return value is 0 if key_bits is 128/192/256, -1 if less than 0, 1 otherwise + */ +int av_twofish_init(struct AVTWOFISH *ctx, const uint8_t *key, int key_bits); + +/** + * Encrypt or decrypt a buffer using a previously initialized context + * + * @param ctx an AVTWOFISH context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 16 byte blocks + * @paran iv initialization vector for CBC mode, NULL for ECB mode + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_twofish_crypt(struct AVTWOFISH *ctx, uint8_t *dst, const uint8_t *src, int count, uint8_t* iv, int decrypt); + +/** + * @} + */ +#endif /* AVUTIL_TWOFISH_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/version.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/version.h new file mode 100644 index 0000000..abea216 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/version.h @@ -0,0 +1,145 @@ +/* + * copyright (c) 2003 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu + * Libavutil version macros + */ + +#ifndef AVUTIL_VERSION_H +#define AVUTIL_VERSION_H + +#include "macros.h" + +/** + * @addtogroup version_utils + * + * Useful to check and match library version in order to maintain + * backward compatibility. + * + * The FFmpeg libraries follow a versioning sheme very similar to + * Semantic Versioning (http://semver.org/) + * The difference is that the component called PATCH is called MICRO in FFmpeg + * and its value is reset to 100 instead of 0 to keep it above or equal to 100. + * Also we do not increase MICRO for every bugfix or change in git master. + * + * Prior to FFmpeg 3.2 point releases did not change any lib version number to + * avoid aliassing different git master checkouts. + * Starting with FFmpeg 3.2, the released library versions will occupy + * a separate MAJOR.MINOR that is not used on the master development branch. + * That is if we branch a release of master 55.10.123 we will bump to 55.11.100 + * for the release and master will continue at 55.12.100 after it. Each new + * point release will then bump the MICRO improving the usefulness of the lib + * versions. + * + * @{ + */ + +#define AV_VERSION_INT(a, b, c) ((a)<<16 | (b)<<8 | (c)) +#define AV_VERSION_DOT(a, b, c) a ##.## b ##.## c +#define AV_VERSION(a, b, c) AV_VERSION_DOT(a, b, c) + +/** + * Extract version components from the full ::AV_VERSION_INT int as returned + * by functions like ::avformat_version() and ::avcodec_version() + */ +#define AV_VERSION_MAJOR(a) ((a) >> 16) +#define AV_VERSION_MINOR(a) (((a) & 0x00FF00) >> 8) +#define AV_VERSION_MICRO(a) ((a) & 0xFF) + +/** + * @} + */ + +/** + * @defgroup lavu_ver Version and Build diagnostics + * + * Macros and function useful to check at compiletime and at runtime + * which version of libavutil is in use. + * + * @{ + */ + +#define LIBAVUTIL_VERSION_MAJOR 55 +#define LIBAVUTIL_VERSION_MINOR 58 +#define LIBAVUTIL_VERSION_MICRO 100 + +#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ + LIBAVUTIL_VERSION_MINOR, \ + LIBAVUTIL_VERSION_MICRO) +#define LIBAVUTIL_VERSION AV_VERSION(LIBAVUTIL_VERSION_MAJOR, \ + LIBAVUTIL_VERSION_MINOR, \ + LIBAVUTIL_VERSION_MICRO) +#define LIBAVUTIL_BUILD LIBAVUTIL_VERSION_INT + +#define LIBAVUTIL_IDENT "Lavu" AV_STRINGIFY(LIBAVUTIL_VERSION) + +/** + * @defgroup lavu_depr_guards Deprecation Guards + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + * + * @note, when bumping the major version it is recommended to manually + * disable each FF_API_* in its own commit instead of disabling them all + * at once through the bump. This improves the git bisect-ability of the change. + * + * @{ + */ + +#ifndef FF_API_VDPAU +#define FF_API_VDPAU (LIBAVUTIL_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_XVMC +#define FF_API_XVMC (LIBAVUTIL_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_OPT_TYPE_METADATA +#define FF_API_OPT_TYPE_METADATA (LIBAVUTIL_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_DLOG +#define FF_API_DLOG (LIBAVUTIL_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_VAAPI +#define FF_API_VAAPI (LIBAVUTIL_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_FRAME_QP +#define FF_API_FRAME_QP (LIBAVUTIL_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_PLUS1_MINUS1 +#define FF_API_PLUS1_MINUS1 (LIBAVUTIL_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_ERROR_FRAME +#define FF_API_ERROR_FRAME (LIBAVUTIL_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_CRC_BIG_TABLE +#define FF_API_CRC_BIG_TABLE (LIBAVUTIL_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_PKT_PTS +#define FF_API_PKT_PTS (LIBAVUTIL_VERSION_MAJOR < 56) +#endif + + +/** + * @} + * @} + */ + +#endif /* AVUTIL_VERSION_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/xtea.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/xtea.h new file mode 100644 index 0000000..735427c --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libavutil/xtea.h @@ -0,0 +1,94 @@ +/* + * A 32-bit implementation of the XTEA algorithm + * Copyright (c) 2012 Samuel Pitoiset + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_XTEA_H +#define AVUTIL_XTEA_H + +#include + +/** + * @file + * @brief Public header for libavutil XTEA algorithm + * @defgroup lavu_xtea XTEA + * @ingroup lavu_crypto + * @{ + */ + +typedef struct AVXTEA { + uint32_t key[16]; +} AVXTEA; + +/** + * Allocate an AVXTEA context. + */ +AVXTEA *av_xtea_alloc(void); + +/** + * Initialize an AVXTEA context. + * + * @param ctx an AVXTEA context + * @param key a key of 16 bytes used for encryption/decryption, + * interpreted as big endian 32 bit numbers + */ +void av_xtea_init(struct AVXTEA *ctx, const uint8_t key[16]); + +/** + * Initialize an AVXTEA context. + * + * @param ctx an AVXTEA context + * @param key a key of 16 bytes used for encryption/decryption, + * interpreted as little endian 32 bit numbers + */ +void av_xtea_le_init(struct AVXTEA *ctx, const uint8_t key[16]); + +/** + * Encrypt or decrypt a buffer using a previously initialized context, + * in big endian format. + * + * @param ctx an AVXTEA context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_xtea_crypt(struct AVXTEA *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context, + * in little endian format. + * + * @param ctx an AVXTEA context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_xtea_le_crypt(struct AVXTEA *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_XTEA_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libswresample/swresample.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libswresample/swresample.h new file mode 100644 index 0000000..a8db5c2 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libswresample/swresample.h @@ -0,0 +1,583 @@ +/* + * Copyright (C) 2011-2013 Michael Niedermayer (michaelni@gmx.at) + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWRESAMPLE_SWRESAMPLE_H +#define SWRESAMPLE_SWRESAMPLE_H + +/** + * @file + * @ingroup lswr + * libswresample public header + */ + +/** + * @defgroup lswr libswresample + * @{ + * + * Audio resampling, sample format conversion and mixing library. + * + * Interaction with lswr is done through SwrContext, which is + * allocated with swr_alloc() or swr_alloc_set_opts(). It is opaque, so all parameters + * must be set with the @ref avoptions API. + * + * The first thing you will need to do in order to use lswr is to allocate + * SwrContext. This can be done with swr_alloc() or swr_alloc_set_opts(). If you + * are using the former, you must set options through the @ref avoptions API. + * The latter function provides the same feature, but it allows you to set some + * common options in the same statement. + * + * For example the following code will setup conversion from planar float sample + * format to interleaved signed 16-bit integer, downsampling from 48kHz to + * 44.1kHz and downmixing from 5.1 channels to stereo (using the default mixing + * matrix). This is using the swr_alloc() function. + * @code + * SwrContext *swr = swr_alloc(); + * av_opt_set_channel_layout(swr, "in_channel_layout", AV_CH_LAYOUT_5POINT1, 0); + * av_opt_set_channel_layout(swr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0); + * av_opt_set_int(swr, "in_sample_rate", 48000, 0); + * av_opt_set_int(swr, "out_sample_rate", 44100, 0); + * av_opt_set_sample_fmt(swr, "in_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); + * av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); + * @endcode + * + * The same job can be done using swr_alloc_set_opts() as well: + * @code + * SwrContext *swr = swr_alloc_set_opts(NULL, // we're allocating a new context + * AV_CH_LAYOUT_STEREO, // out_ch_layout + * AV_SAMPLE_FMT_S16, // out_sample_fmt + * 44100, // out_sample_rate + * AV_CH_LAYOUT_5POINT1, // in_ch_layout + * AV_SAMPLE_FMT_FLTP, // in_sample_fmt + * 48000, // in_sample_rate + * 0, // log_offset + * NULL); // log_ctx + * @endcode + * + * Once all values have been set, it must be initialized with swr_init(). If + * you need to change the conversion parameters, you can change the parameters + * using @ref AVOptions, as described above in the first example; or by using + * swr_alloc_set_opts(), but with the first argument the allocated context. + * You must then call swr_init() again. + * + * The conversion itself is done by repeatedly calling swr_convert(). + * Note that the samples may get buffered in swr if you provide insufficient + * output space or if sample rate conversion is done, which requires "future" + * samples. Samples that do not require future input can be retrieved at any + * time by using swr_convert() (in_count can be set to 0). + * At the end of conversion the resampling buffer can be flushed by calling + * swr_convert() with NULL in and 0 in_count. + * + * The samples used in the conversion process can be managed with the libavutil + * @ref lavu_sampmanip "samples manipulation" API, including av_samples_alloc() + * function used in the following example. + * + * The delay between input and output, can at any time be found by using + * swr_get_delay(). + * + * The following code demonstrates the conversion loop assuming the parameters + * from above and caller-defined functions get_input() and handle_output(): + * @code + * uint8_t **input; + * int in_samples; + * + * while (get_input(&input, &in_samples)) { + * uint8_t *output; + * int out_samples = av_rescale_rnd(swr_get_delay(swr, 48000) + + * in_samples, 44100, 48000, AV_ROUND_UP); + * av_samples_alloc(&output, NULL, 2, out_samples, + * AV_SAMPLE_FMT_S16, 0); + * out_samples = swr_convert(swr, &output, out_samples, + * input, in_samples); + * handle_output(output, out_samples); + * av_freep(&output); + * } + * @endcode + * + * When the conversion is finished, the conversion + * context and everything associated with it must be freed with swr_free(). + * A swr_close() function is also available, but it exists mainly for + * compatibility with libavresample, and is not required to be called. + * + * There will be no memory leak if the data is not completely flushed before + * swr_free(). + */ + +#include +#include "libavutil/channel_layout.h" +#include "libavutil/frame.h" +#include "libavutil/samplefmt.h" + +#include "libswresample/version.h" + +#if LIBSWRESAMPLE_VERSION_MAJOR < 1 +#define SWR_CH_MAX 32 ///< Maximum number of channels +#endif + +/** + * @name Option constants + * These constants are used for the @ref avoptions interface for lswr. + * @{ + * + */ + +#define SWR_FLAG_RESAMPLE 1 ///< Force resampling even if equal sample rate +//TODO use int resample ? +//long term TODO can we enable this dynamically? + +/** Dithering algorithms */ +enum SwrDitherType { + SWR_DITHER_NONE = 0, + SWR_DITHER_RECTANGULAR, + SWR_DITHER_TRIANGULAR, + SWR_DITHER_TRIANGULAR_HIGHPASS, + + SWR_DITHER_NS = 64, ///< not part of API/ABI + SWR_DITHER_NS_LIPSHITZ, + SWR_DITHER_NS_F_WEIGHTED, + SWR_DITHER_NS_MODIFIED_E_WEIGHTED, + SWR_DITHER_NS_IMPROVED_E_WEIGHTED, + SWR_DITHER_NS_SHIBATA, + SWR_DITHER_NS_LOW_SHIBATA, + SWR_DITHER_NS_HIGH_SHIBATA, + SWR_DITHER_NB, ///< not part of API/ABI +}; + +/** Resampling Engines */ +enum SwrEngine { + SWR_ENGINE_SWR, /**< SW Resampler */ + SWR_ENGINE_SOXR, /**< SoX Resampler */ + SWR_ENGINE_NB, ///< not part of API/ABI +}; + +/** Resampling Filter Types */ +enum SwrFilterType { + SWR_FILTER_TYPE_CUBIC, /**< Cubic */ + SWR_FILTER_TYPE_BLACKMAN_NUTTALL, /**< Blackman Nuttall windowed sinc */ + SWR_FILTER_TYPE_KAISER, /**< Kaiser windowed sinc */ +}; + +/** + * @} + */ + +/** + * The libswresample context. Unlike libavcodec and libavformat, this structure + * is opaque. This means that if you would like to set options, you must use + * the @ref avoptions API and cannot directly set values to members of the + * structure. + */ +typedef struct SwrContext SwrContext; + +/** + * Get the AVClass for SwrContext. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + * @return the AVClass of SwrContext + */ +const AVClass *swr_get_class(void); + +/** + * @name SwrContext constructor functions + * @{ + */ + +/** + * Allocate SwrContext. + * + * If you use this function you will need to set the parameters (manually or + * with swr_alloc_set_opts()) before calling swr_init(). + * + * @see swr_alloc_set_opts(), swr_init(), swr_free() + * @return NULL on error, allocated context otherwise + */ +struct SwrContext *swr_alloc(void); + +/** + * Initialize context after user parameters have been set. + * @note The context must be configured using the AVOption API. + * + * @see av_opt_set_int() + * @see av_opt_set_dict() + * + * @param[in,out] s Swr context to initialize + * @return AVERROR error code in case of failure. + */ +int swr_init(struct SwrContext *s); + +/** + * Check whether an swr context has been initialized or not. + * + * @param[in] s Swr context to check + * @see swr_init() + * @return positive if it has been initialized, 0 if not initialized + */ +int swr_is_initialized(struct SwrContext *s); + +/** + * Allocate SwrContext if needed and set/reset common parameters. + * + * This function does not require s to be allocated with swr_alloc(). On the + * other hand, swr_alloc() can use swr_alloc_set_opts() to set the parameters + * on the allocated context. + * + * @param s existing Swr context if available, or NULL if not + * @param out_ch_layout output channel layout (AV_CH_LAYOUT_*) + * @param out_sample_fmt output sample format (AV_SAMPLE_FMT_*). + * @param out_sample_rate output sample rate (frequency in Hz) + * @param in_ch_layout input channel layout (AV_CH_LAYOUT_*) + * @param in_sample_fmt input sample format (AV_SAMPLE_FMT_*). + * @param in_sample_rate input sample rate (frequency in Hz) + * @param log_offset logging level offset + * @param log_ctx parent logging context, can be NULL + * + * @see swr_init(), swr_free() + * @return NULL on error, allocated context otherwise + */ +struct SwrContext *swr_alloc_set_opts(struct SwrContext *s, + int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate, + int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate, + int log_offset, void *log_ctx); + +/** + * @} + * + * @name SwrContext destructor functions + * @{ + */ + +/** + * Free the given SwrContext and set the pointer to NULL. + * + * @param[in] s a pointer to a pointer to Swr context + */ +void swr_free(struct SwrContext **s); + +/** + * Closes the context so that swr_is_initialized() returns 0. + * + * The context can be brought back to life by running swr_init(), + * swr_init() can also be used without swr_close(). + * This function is mainly provided for simplifying the usecase + * where one tries to support libavresample and libswresample. + * + * @param[in,out] s Swr context to be closed + */ +void swr_close(struct SwrContext *s); + +/** + * @} + * + * @name Core conversion functions + * @{ + */ + +/** Convert audio. + * + * in and in_count can be set to 0 to flush the last few samples out at the + * end. + * + * If more input is provided than output space, then the input will be buffered. + * You can avoid this buffering by using swr_get_out_samples() to retrieve an + * upper bound on the required number of output samples for the given number of + * input samples. Conversion will run directly without copying whenever possible. + * + * @param s allocated Swr context, with parameters set + * @param out output buffers, only the first one need be set in case of packed audio + * @param out_count amount of space available for output in samples per channel + * @param in input buffers, only the first one need to be set in case of packed audio + * @param in_count number of input samples available in one channel + * + * @return number of samples output per channel, negative value on error + */ +int swr_convert(struct SwrContext *s, uint8_t **out, int out_count, + const uint8_t **in , int in_count); + +/** + * Convert the next timestamp from input to output + * timestamps are in 1/(in_sample_rate * out_sample_rate) units. + * + * @note There are 2 slightly differently behaving modes. + * @li When automatic timestamp compensation is not used, (min_compensation >= FLT_MAX) + * in this case timestamps will be passed through with delays compensated + * @li When automatic timestamp compensation is used, (min_compensation < FLT_MAX) + * in this case the output timestamps will match output sample numbers. + * See ffmpeg-resampler(1) for the two modes of compensation. + * + * @param s[in] initialized Swr context + * @param pts[in] timestamp for the next input sample, INT64_MIN if unknown + * @see swr_set_compensation(), swr_drop_output(), and swr_inject_silence() are + * function used internally for timestamp compensation. + * @return the output timestamp for the next output sample + */ +int64_t swr_next_pts(struct SwrContext *s, int64_t pts); + +/** + * @} + * + * @name Low-level option setting functions + * These functons provide a means to set low-level options that is not possible + * with the AVOption API. + * @{ + */ + +/** + * Activate resampling compensation ("soft" compensation). This function is + * internally called when needed in swr_next_pts(). + * + * @param[in,out] s allocated Swr context. If it is not initialized, + * or SWR_FLAG_RESAMPLE is not set, swr_init() is + * called with the flag set. + * @param[in] sample_delta delta in PTS per sample + * @param[in] compensation_distance number of samples to compensate for + * @return >= 0 on success, AVERROR error codes if: + * @li @c s is NULL, + * @li @c compensation_distance is less than 0, + * @li @c compensation_distance is 0 but sample_delta is not, + * @li compensation unsupported by resampler, or + * @li swr_init() fails when called. + */ +int swr_set_compensation(struct SwrContext *s, int sample_delta, int compensation_distance); + +/** + * Set a customized input channel mapping. + * + * @param[in,out] s allocated Swr context, not yet initialized + * @param[in] channel_map customized input channel mapping (array of channel + * indexes, -1 for a muted channel) + * @return >= 0 on success, or AVERROR error code in case of failure. + */ +int swr_set_channel_mapping(struct SwrContext *s, const int *channel_map); + +/** + * Generate a channel mixing matrix. + * + * This function is the one used internally by libswresample for building the + * default mixing matrix. It is made public just as a utility function for + * building custom matrices. + * + * @param in_layout input channel layout + * @param out_layout output channel layout + * @param center_mix_level mix level for the center channel + * @param surround_mix_level mix level for the surround channel(s) + * @param lfe_mix_level mix level for the low-frequency effects channel + * @param rematrix_maxval if 1.0, coefficients will be normalized to prevent + * overflow. if INT_MAX, coefficients will not be + * normalized. + * @param[out] matrix mixing coefficients; matrix[i + stride * o] is + * the weight of input channel i in output channel o. + * @param stride distance between adjacent input channels in the + * matrix array + * @param matrix_encoding matrixed stereo downmix mode (e.g. dplii) + * @param log_ctx parent logging context, can be NULL + * @return 0 on success, negative AVERROR code on failure + */ +int swr_build_matrix(uint64_t in_layout, uint64_t out_layout, + double center_mix_level, double surround_mix_level, + double lfe_mix_level, double rematrix_maxval, + double rematrix_volume, double *matrix, + int stride, enum AVMatrixEncoding matrix_encoding, + void *log_ctx); + +/** + * Set a customized remix matrix. + * + * @param s allocated Swr context, not yet initialized + * @param matrix remix coefficients; matrix[i + stride * o] is + * the weight of input channel i in output channel o + * @param stride offset between lines of the matrix + * @return >= 0 on success, or AVERROR error code in case of failure. + */ +int swr_set_matrix(struct SwrContext *s, const double *matrix, int stride); + +/** + * @} + * + * @name Sample handling functions + * @{ + */ + +/** + * Drops the specified number of output samples. + * + * This function, along with swr_inject_silence(), is called by swr_next_pts() + * if needed for "hard" compensation. + * + * @param s allocated Swr context + * @param count number of samples to be dropped + * + * @return >= 0 on success, or a negative AVERROR code on failure + */ +int swr_drop_output(struct SwrContext *s, int count); + +/** + * Injects the specified number of silence samples. + * + * This function, along with swr_drop_output(), is called by swr_next_pts() + * if needed for "hard" compensation. + * + * @param s allocated Swr context + * @param count number of samples to be dropped + * + * @return >= 0 on success, or a negative AVERROR code on failure + */ +int swr_inject_silence(struct SwrContext *s, int count); + +/** + * Gets the delay the next input sample will experience relative to the next output sample. + * + * Swresample can buffer data if more input has been provided than available + * output space, also converting between sample rates needs a delay. + * This function returns the sum of all such delays. + * The exact delay is not necessarily an integer value in either input or + * output sample rate. Especially when downsampling by a large value, the + * output sample rate may be a poor choice to represent the delay, similarly + * for upsampling and the input sample rate. + * + * @param s swr context + * @param base timebase in which the returned delay will be: + * @li if it's set to 1 the returned delay is in seconds + * @li if it's set to 1000 the returned delay is in milliseconds + * @li if it's set to the input sample rate then the returned + * delay is in input samples + * @li if it's set to the output sample rate then the returned + * delay is in output samples + * @li if it's the least common multiple of in_sample_rate and + * out_sample_rate then an exact rounding-free delay will be + * returned + * @returns the delay in 1 / @c base units. + */ +int64_t swr_get_delay(struct SwrContext *s, int64_t base); + +/** + * Find an upper bound on the number of samples that the next swr_convert + * call will output, if called with in_samples of input samples. This + * depends on the internal state, and anything changing the internal state + * (like further swr_convert() calls) will may change the number of samples + * swr_get_out_samples() returns for the same number of input samples. + * + * @param in_samples number of input samples. + * @note any call to swr_inject_silence(), swr_convert(), swr_next_pts() + * or swr_set_compensation() invalidates this limit + * @note it is recommended to pass the correct available buffer size + * to all functions like swr_convert() even if swr_get_out_samples() + * indicates that less would be used. + * @returns an upper bound on the number of samples that the next swr_convert + * will output or a negative value to indicate an error + */ +int swr_get_out_samples(struct SwrContext *s, int in_samples); + +/** + * @} + * + * @name Configuration accessors + * @{ + */ + +/** + * Return the @ref LIBSWRESAMPLE_VERSION_INT constant. + * + * This is useful to check if the build-time libswresample has the same version + * as the run-time one. + * + * @returns the unsigned int-typed version + */ +unsigned swresample_version(void); + +/** + * Return the swr build-time configuration. + * + * @returns the build-time @c ./configure flags + */ +const char *swresample_configuration(void); + +/** + * Return the swr license. + * + * @returns the license of libswresample, determined at build-time + */ +const char *swresample_license(void); + +/** + * @} + * + * @name AVFrame based API + * @{ + */ + +/** + * Convert the samples in the input AVFrame and write them to the output AVFrame. + * + * Input and output AVFrames must have channel_layout, sample_rate and format set. + * + * If the output AVFrame does not have the data pointers allocated the nb_samples + * field will be set using av_frame_get_buffer() + * is called to allocate the frame. + * + * The output AVFrame can be NULL or have fewer allocated samples than required. + * In this case, any remaining samples not written to the output will be added + * to an internal FIFO buffer, to be returned at the next call to this function + * or to swr_convert(). + * + * If converting sample rate, there may be data remaining in the internal + * resampling delay buffer. swr_get_delay() tells the number of + * remaining samples. To get this data as output, call this function or + * swr_convert() with NULL input. + * + * If the SwrContext configuration does not match the output and + * input AVFrame settings the conversion does not take place and depending on + * which AVFrame is not matching AVERROR_OUTPUT_CHANGED, AVERROR_INPUT_CHANGED + * or the result of a bitwise-OR of them is returned. + * + * @see swr_delay() + * @see swr_convert() + * @see swr_get_delay() + * + * @param swr audio resample context + * @param output output AVFrame + * @param input input AVFrame + * @return 0 on success, AVERROR on failure or nonmatching + * configuration. + */ +int swr_convert_frame(SwrContext *swr, + AVFrame *output, const AVFrame *input); + +/** + * Configure or reconfigure the SwrContext using the information + * provided by the AVFrames. + * + * The original resampling context is reset even on failure. + * The function calls swr_close() internally if the context is open. + * + * @see swr_close(); + * + * @param swr audio resample context + * @param output output AVFrame + * @param input input AVFrame + * @return 0 on success, AVERROR on failure. + */ +int swr_config_frame(SwrContext *swr, const AVFrame *out, const AVFrame *in); + +/** + * @} + * @} + */ + +#endif /* SWRESAMPLE_SWRESAMPLE_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libswresample/version.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libswresample/version.h new file mode 100644 index 0000000..fb76f56 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libswresample/version.h @@ -0,0 +1,45 @@ +/* + * Version macros. + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWRESAMPLE_VERSION_H +#define SWRESAMPLE_VERSION_H + +/** + * @file + * Libswresample version macros + */ + +#include "libavutil/avutil.h" + +#define LIBSWRESAMPLE_VERSION_MAJOR 2 +#define LIBSWRESAMPLE_VERSION_MINOR 7 +#define LIBSWRESAMPLE_VERSION_MICRO 100 + +#define LIBSWRESAMPLE_VERSION_INT AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, \ + LIBSWRESAMPLE_VERSION_MINOR, \ + LIBSWRESAMPLE_VERSION_MICRO) +#define LIBSWRESAMPLE_VERSION AV_VERSION(LIBSWRESAMPLE_VERSION_MAJOR, \ + LIBSWRESAMPLE_VERSION_MINOR, \ + LIBSWRESAMPLE_VERSION_MICRO) +#define LIBSWRESAMPLE_BUILD LIBSWRESAMPLE_VERSION_INT + +#define LIBSWRESAMPLE_IDENT "SwR" AV_STRINGIFY(LIBSWRESAMPLE_VERSION) + +#endif /* SWRESAMPLE_VERSION_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libswscale/swscale.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libswscale/swscale.h new file mode 100644 index 0000000..7713f51 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libswscale/swscale.h @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2001-2011 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_SWSCALE_H +#define SWSCALE_SWSCALE_H + +/** + * @file + * @ingroup libsws + * external API header + */ + +#include + +#include "libavutil/avutil.h" +#include "libavutil/log.h" +#include "libavutil/pixfmt.h" +#include "version.h" + +/** + * @defgroup libsws libswscale + * Color conversion and scaling library. + * + * @{ + * + * Return the LIBSWSCALE_VERSION_INT constant. + */ +unsigned swscale_version(void); + +/** + * Return the libswscale build-time configuration. + */ +const char *swscale_configuration(void); + +/** + * Return the libswscale license. + */ +const char *swscale_license(void); + +/* values for the flags, the stuff on the command line is different */ +#define SWS_FAST_BILINEAR 1 +#define SWS_BILINEAR 2 +#define SWS_BICUBIC 4 +#define SWS_X 8 +#define SWS_POINT 0x10 +#define SWS_AREA 0x20 +#define SWS_BICUBLIN 0x40 +#define SWS_GAUSS 0x80 +#define SWS_SINC 0x100 +#define SWS_LANCZOS 0x200 +#define SWS_SPLINE 0x400 + +#define SWS_SRC_V_CHR_DROP_MASK 0x30000 +#define SWS_SRC_V_CHR_DROP_SHIFT 16 + +#define SWS_PARAM_DEFAULT 123456 + +#define SWS_PRINT_INFO 0x1000 + +//the following 3 flags are not completely implemented +//internal chrominance subsampling info +#define SWS_FULL_CHR_H_INT 0x2000 +//input subsampling info +#define SWS_FULL_CHR_H_INP 0x4000 +#define SWS_DIRECT_BGR 0x8000 +#define SWS_ACCURATE_RND 0x40000 +#define SWS_BITEXACT 0x80000 +#define SWS_ERROR_DIFFUSION 0x800000 + +#define SWS_MAX_REDUCE_CUTOFF 0.002 + +#define SWS_CS_ITU709 1 +#define SWS_CS_FCC 4 +#define SWS_CS_ITU601 5 +#define SWS_CS_ITU624 5 +#define SWS_CS_SMPTE170M 5 +#define SWS_CS_SMPTE240M 7 +#define SWS_CS_DEFAULT 5 +#define SWS_CS_BT2020 9 + +/** + * Return a pointer to yuv<->rgb coefficients for the given colorspace + * suitable for sws_setColorspaceDetails(). + * + * @param colorspace One of the SWS_CS_* macros. If invalid, + * SWS_CS_DEFAULT is used. + */ +const int *sws_getCoefficients(int colorspace); + +// when used for filters they must have an odd number of elements +// coeffs cannot be shared between vectors +typedef struct SwsVector { + double *coeff; ///< pointer to the list of coefficients + int length; ///< number of coefficients in the vector +} SwsVector; + +// vectors can be shared +typedef struct SwsFilter { + SwsVector *lumH; + SwsVector *lumV; + SwsVector *chrH; + SwsVector *chrV; +} SwsFilter; + +struct SwsContext; + +/** + * Return a positive value if pix_fmt is a supported input format, 0 + * otherwise. + */ +int sws_isSupportedInput(enum AVPixelFormat pix_fmt); + +/** + * Return a positive value if pix_fmt is a supported output format, 0 + * otherwise. + */ +int sws_isSupportedOutput(enum AVPixelFormat pix_fmt); + +/** + * @param[in] pix_fmt the pixel format + * @return a positive value if an endianness conversion for pix_fmt is + * supported, 0 otherwise. + */ +int sws_isSupportedEndiannessConversion(enum AVPixelFormat pix_fmt); + +/** + * Allocate an empty SwsContext. This must be filled and passed to + * sws_init_context(). For filling see AVOptions, options.c and + * sws_setColorspaceDetails(). + */ +struct SwsContext *sws_alloc_context(void); + +/** + * Initialize the swscaler context sws_context. + * + * @return zero or positive value on success, a negative value on + * error + */ +av_warn_unused_result +int sws_init_context(struct SwsContext *sws_context, SwsFilter *srcFilter, SwsFilter *dstFilter); + +/** + * Free the swscaler context swsContext. + * If swsContext is NULL, then does nothing. + */ +void sws_freeContext(struct SwsContext *swsContext); + +/** + * Allocate and return an SwsContext. You need it to perform + * scaling/conversion operations using sws_scale(). + * + * @param srcW the width of the source image + * @param srcH the height of the source image + * @param srcFormat the source image format + * @param dstW the width of the destination image + * @param dstH the height of the destination image + * @param dstFormat the destination image format + * @param flags specify which algorithm and options to use for rescaling + * @param param extra parameters to tune the used scaler + * For SWS_BICUBIC param[0] and [1] tune the shape of the basis + * function, param[0] tunes f(1) and param[1] f´(1) + * For SWS_GAUSS param[0] tunes the exponent and thus cutoff + * frequency + * For SWS_LANCZOS param[0] tunes the width of the window function + * @return a pointer to an allocated context, or NULL in case of error + * @note this function is to be removed after a saner alternative is + * written + */ +struct SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat, + int dstW, int dstH, enum AVPixelFormat dstFormat, + int flags, SwsFilter *srcFilter, + SwsFilter *dstFilter, const double *param); + +/** + * Scale the image slice in srcSlice and put the resulting scaled + * slice in the image in dst. A slice is a sequence of consecutive + * rows in an image. + * + * Slices have to be provided in sequential order, either in + * top-bottom or bottom-top order. If slices are provided in + * non-sequential order the behavior of the function is undefined. + * + * @param c the scaling context previously created with + * sws_getContext() + * @param srcSlice the array containing the pointers to the planes of + * the source slice + * @param srcStride the array containing the strides for each plane of + * the source image + * @param srcSliceY the position in the source image of the slice to + * process, that is the number (counted starting from + * zero) in the image of the first row of the slice + * @param srcSliceH the height of the source slice, that is the number + * of rows in the slice + * @param dst the array containing the pointers to the planes of + * the destination image + * @param dstStride the array containing the strides for each plane of + * the destination image + * @return the height of the output slice + */ +int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]); + +/** + * @param dstRange flag indicating the while-black range of the output (1=jpeg / 0=mpeg) + * @param srcRange flag indicating the while-black range of the input (1=jpeg / 0=mpeg) + * @param table the yuv2rgb coefficients describing the output yuv space, normally ff_yuv2rgb_coeffs[x] + * @param inv_table the yuv2rgb coefficients describing the input yuv space, normally ff_yuv2rgb_coeffs[x] + * @param brightness 16.16 fixed point brightness correction + * @param contrast 16.16 fixed point contrast correction + * @param saturation 16.16 fixed point saturation correction + * @return -1 if not supported + */ +int sws_setColorspaceDetails(struct SwsContext *c, const int inv_table[4], + int srcRange, const int table[4], int dstRange, + int brightness, int contrast, int saturation); + +/** + * @return -1 if not supported + */ +int sws_getColorspaceDetails(struct SwsContext *c, int **inv_table, + int *srcRange, int **table, int *dstRange, + int *brightness, int *contrast, int *saturation); + +/** + * Allocate and return an uninitialized vector with length coefficients. + */ +SwsVector *sws_allocVec(int length); + +/** + * Return a normalized Gaussian curve used to filter stuff + * quality = 3 is high quality, lower is lower quality. + */ +SwsVector *sws_getGaussianVec(double variance, double quality); + +/** + * Scale all the coefficients of a by the scalar value. + */ +void sws_scaleVec(SwsVector *a, double scalar); + +/** + * Scale all the coefficients of a so that their sum equals height. + */ +void sws_normalizeVec(SwsVector *a, double height); + +#if FF_API_SWS_VECTOR +attribute_deprecated SwsVector *sws_getConstVec(double c, int length); +attribute_deprecated SwsVector *sws_getIdentityVec(void); +attribute_deprecated void sws_convVec(SwsVector *a, SwsVector *b); +attribute_deprecated void sws_addVec(SwsVector *a, SwsVector *b); +attribute_deprecated void sws_subVec(SwsVector *a, SwsVector *b); +attribute_deprecated void sws_shiftVec(SwsVector *a, int shift); +attribute_deprecated SwsVector *sws_cloneVec(SwsVector *a); +attribute_deprecated void sws_printVec2(SwsVector *a, AVClass *log_ctx, int log_level); +#endif + +void sws_freeVec(SwsVector *a); + +SwsFilter *sws_getDefaultFilter(float lumaGBlur, float chromaGBlur, + float lumaSharpen, float chromaSharpen, + float chromaHShift, float chromaVShift, + int verbose); +void sws_freeFilter(SwsFilter *filter); + +/** + * Check if context can be reused, otherwise reallocate a new one. + * + * If context is NULL, just calls sws_getContext() to get a new + * context. Otherwise, checks if the parameters are the ones already + * saved in context. If that is the case, returns the current + * context. Otherwise, frees context and gets a new context with + * the new parameters. + * + * Be warned that srcFilter and dstFilter are not checked, they + * are assumed to remain the same. + */ +struct SwsContext *sws_getCachedContext(struct SwsContext *context, + int srcW, int srcH, enum AVPixelFormat srcFormat, + int dstW, int dstH, enum AVPixelFormat dstFormat, + int flags, SwsFilter *srcFilter, + SwsFilter *dstFilter, const double *param); + +/** + * Convert an 8-bit paletted frame into a frame with a color depth of 32 bits. + * + * The output frame will have the same packed format as the palette. + * + * @param src source frame buffer + * @param dst destination frame buffer + * @param num_pixels number of pixels to convert + * @param palette array with [256] entries, which must match color arrangement (RGB or BGR) of src + */ +void sws_convertPalette8ToPacked32(const uint8_t *src, uint8_t *dst, int num_pixels, const uint8_t *palette); + +/** + * Convert an 8-bit paletted frame into a frame with a color depth of 24 bits. + * + * With the palette format "ABCD", the destination frame ends up with the format "ABC". + * + * @param src source frame buffer + * @param dst destination frame buffer + * @param num_pixels number of pixels to convert + * @param palette array with [256] entries, which must match color arrangement (RGB or BGR) of src + */ +void sws_convertPalette8ToPacked24(const uint8_t *src, uint8_t *dst, int num_pixels, const uint8_t *palette); + +/** + * Get the AVClass for swsContext. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *sws_get_class(void); + +/** + * @} + */ + +#endif /* SWSCALE_SWSCALE_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libswscale/version.h b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libswscale/version.h new file mode 100644 index 0000000..c1090ca --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ffmpeg/libswscale/version.h @@ -0,0 +1,53 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_VERSION_H +#define SWSCALE_VERSION_H + +/** + * @file + * swscale version macros + */ + +#include "libavutil/version.h" + +#define LIBSWSCALE_VERSION_MAJOR 4 +#define LIBSWSCALE_VERSION_MINOR 6 +#define LIBSWSCALE_VERSION_MICRO 100 + +#define LIBSWSCALE_VERSION_INT AV_VERSION_INT(LIBSWSCALE_VERSION_MAJOR, \ + LIBSWSCALE_VERSION_MINOR, \ + LIBSWSCALE_VERSION_MICRO) +#define LIBSWSCALE_VERSION AV_VERSION(LIBSWSCALE_VERSION_MAJOR, \ + LIBSWSCALE_VERSION_MINOR, \ + LIBSWSCALE_VERSION_MICRO) +#define LIBSWSCALE_BUILD LIBSWSCALE_VERSION_INT + +#define LIBSWSCALE_IDENT "SwS" AV_STRINGIFY(LIBSWSCALE_VERSION) + +/** + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + */ + +#ifndef FF_API_SWS_VECTOR +#define FF_API_SWS_VECTOR (LIBSWSCALE_VERSION_MAJOR < 6) +#endif + +#endif /* SWSCALE_VERSION_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/allocator.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/allocator.h new file mode 100644 index 0000000..3a5ebca --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/allocator.h @@ -0,0 +1,448 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_ALLOCATOR_H +#define NCNN_ALLOCATOR_H + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include "platform.h" + +#include + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +#include +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +// the alignment of all the allocated buffers +#if NCNN_AVX512 +#define NCNN_MALLOC_ALIGN 64 +#elif NCNN_AVX +#define NCNN_MALLOC_ALIGN 32 +#else +#define NCNN_MALLOC_ALIGN 16 +#endif + +// we have some optimized kernels that may overread buffer a bit in loop +// it is common to interleave next-loop data load with arithmetic instructions +// allocating more bytes keeps us safe from SEGV_ACCERR failure +#define NCNN_MALLOC_OVERREAD 64 + +// Aligns a pointer to the specified number of bytes +// ptr Aligned pointer +// n Alignment size that must be a power of two +template +static NCNN_FORCEINLINE _Tp* alignPtr(_Tp* ptr, int n = (int)sizeof(_Tp)) +{ + return (_Tp*)(((size_t)ptr + n - 1) & -n); +} + +// Aligns a buffer size to the specified number of bytes +// The function returns the minimum number that is greater or equal to sz and is divisible by n +// sz Buffer size to align +// n Alignment size that must be a power of two +static NCNN_FORCEINLINE size_t alignSize(size_t sz, int n) +{ + return (sz + n - 1) & -n; +} + +static NCNN_FORCEINLINE void* fastMalloc(size_t size) +{ +#if _MSC_VER + return _aligned_malloc(size, NCNN_MALLOC_ALIGN); +#elif (defined(__unix__) || defined(__APPLE__)) && _POSIX_C_SOURCE >= 200112L || (__ANDROID__ && __ANDROID_API__ >= 17) + void* ptr = 0; + if (posix_memalign(&ptr, NCNN_MALLOC_ALIGN, size + NCNN_MALLOC_OVERREAD)) + ptr = 0; + return ptr; +#elif __ANDROID__ && __ANDROID_API__ < 17 + return memalign(NCNN_MALLOC_ALIGN, size + NCNN_MALLOC_OVERREAD); +#else + unsigned char* udata = (unsigned char*)malloc(size + sizeof(void*) + NCNN_MALLOC_ALIGN + NCNN_MALLOC_OVERREAD); + if (!udata) + return 0; + unsigned char** adata = alignPtr((unsigned char**)udata + 1, NCNN_MALLOC_ALIGN); + adata[-1] = udata; + return adata; +#endif +} + +static NCNN_FORCEINLINE void fastFree(void* ptr) +{ + if (ptr) + { +#if _MSC_VER + _aligned_free(ptr); +#elif (defined(__unix__) || defined(__APPLE__)) && _POSIX_C_SOURCE >= 200112L || (__ANDROID__ && __ANDROID_API__ >= 17) + free(ptr); +#elif __ANDROID__ && __ANDROID_API__ < 17 + free(ptr); +#else + unsigned char* udata = ((unsigned char**)ptr)[-1]; + free(udata); +#endif + } +} + +#if NCNN_THREADS +// exchange-add operation for atomic operations on reference counters +#if defined __riscv && !defined __riscv_atomic +// riscv target without A extension +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#elif defined __INTEL_COMPILER && !(defined WIN32 || defined _WIN32) +// atomic increment on the linux version of the Intel(tm) compiler +#define NCNN_XADD(addr, delta) (int)_InterlockedExchangeAdd(const_cast(reinterpret_cast(addr)), delta) +#elif defined __GNUC__ +#if defined __clang__ && __clang_major__ >= 3 && !defined __ANDROID__ && !defined __EMSCRIPTEN__ && !defined(__CUDACC__) +#ifdef __ATOMIC_ACQ_REL +#define NCNN_XADD(addr, delta) __c11_atomic_fetch_add((_Atomic(int)*)(addr), delta, __ATOMIC_ACQ_REL) +#else +#define NCNN_XADD(addr, delta) __atomic_fetch_add((_Atomic(int)*)(addr), delta, 4) +#endif +#else +#if defined __ATOMIC_ACQ_REL && !defined __clang__ +// version for gcc >= 4.7 +#define NCNN_XADD(addr, delta) (int)__atomic_fetch_add((unsigned*)(addr), (unsigned)(delta), __ATOMIC_ACQ_REL) +#else +#define NCNN_XADD(addr, delta) (int)__sync_fetch_and_add((unsigned*)(addr), (unsigned)(delta)) +#endif +#endif +#elif defined _MSC_VER && !defined RC_INVOKED +#define NCNN_XADD(addr, delta) (int)_InterlockedExchangeAdd((long volatile*)addr, delta) +#else +// thread-unsafe branch +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#endif +#else // NCNN_THREADS +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#endif // NCNN_THREADS + +class NCNN_EXPORT Allocator +{ +public: + virtual ~Allocator(); + virtual void* fastMalloc(size_t size) = 0; + virtual void fastFree(void* ptr) = 0; +}; + +class PoolAllocatorPrivate; +class NCNN_EXPORT PoolAllocator : public Allocator +{ +public: + PoolAllocator(); + ~PoolAllocator(); + + // ratio range 0 ~ 1 + // default cr = 0 + void set_size_compare_ratio(float scr); + + // budget drop threshold + // default threshold = 10 + void set_size_drop_threshold(size_t); + + // release all budgets immediately + void clear(); + + virtual void* fastMalloc(size_t size); + virtual void fastFree(void* ptr); + +private: + PoolAllocator(const PoolAllocator&); + PoolAllocator& operator=(const PoolAllocator&); + +private: + PoolAllocatorPrivate* const d; +}; + +class UnlockedPoolAllocatorPrivate; +class NCNN_EXPORT UnlockedPoolAllocator : public Allocator +{ +public: + UnlockedPoolAllocator(); + ~UnlockedPoolAllocator(); + + // ratio range 0 ~ 1 + // default cr = 0 + void set_size_compare_ratio(float scr); + + // budget drop threshold + // default threshold = 10 + void set_size_drop_threshold(size_t); + + // release all budgets immediately + void clear(); + + virtual void* fastMalloc(size_t size); + virtual void fastFree(void* ptr); + +private: + UnlockedPoolAllocator(const UnlockedPoolAllocator&); + UnlockedPoolAllocator& operator=(const UnlockedPoolAllocator&); + +private: + UnlockedPoolAllocatorPrivate* const d; +}; + +#if NCNN_VULKAN + +class VulkanDevice; + +class NCNN_EXPORT VkBufferMemory +{ +public: + VkBuffer buffer; + + // the base offset assigned by allocator + size_t offset; + size_t capacity; + + VkDeviceMemory memory; + void* mapped_ptr; + + // buffer state, modified by command functions internally + mutable VkAccessFlags access_flags; + mutable VkPipelineStageFlags stage_flags; + + // initialize and modified by mat + int refcount; +}; + +class NCNN_EXPORT VkImageMemory +{ +public: + VkImage image; + VkImageView imageview; + + // underlying info assigned by allocator + int width; + int height; + int depth; + VkFormat format; + + VkDeviceMemory memory; + void* mapped_ptr; + + // the base offset assigned by allocator + size_t bind_offset; + size_t bind_capacity; + + // image state, modified by command functions internally + mutable VkAccessFlags access_flags; + mutable VkImageLayout image_layout; + mutable VkPipelineStageFlags stage_flags; + + // in-execution state, modified by command functions internally + mutable int command_refcount; + + // initialize and modified by mat + int refcount; +}; + +class NCNN_EXPORT VkAllocator +{ +public: + explicit VkAllocator(const VulkanDevice* _vkdev); + virtual ~VkAllocator(); + + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size) = 0; + virtual void fastFree(VkBufferMemory* ptr) = 0; + virtual int flush(VkBufferMemory* ptr); + virtual int invalidate(VkBufferMemory* ptr); + + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack) = 0; + virtual void fastFree(VkImageMemory* ptr) = 0; + +public: + const VulkanDevice* vkdev; + uint32_t buffer_memory_type_index; + uint32_t image_memory_type_index; + uint32_t reserved_type_index; + bool mappable; + bool coherent; + +protected: + VkBuffer create_buffer(size_t size, VkBufferUsageFlags usage); + VkDeviceMemory allocate_memory(size_t size, uint32_t memory_type_index); + VkDeviceMemory allocate_dedicated_memory(size_t size, uint32_t memory_type_index, VkImage image, VkBuffer buffer); + + VkImage create_image(int width, int height, int depth, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage); + VkImageView create_imageview(VkImage image, VkFormat format); +}; + +class VkBlobAllocatorPrivate; +class NCNN_EXPORT VkBlobAllocator : public VkAllocator +{ +public: + explicit VkBlobAllocator(const VulkanDevice* vkdev, size_t preferred_block_size = 16 * 1024 * 1024); // 16M + virtual ~VkBlobAllocator(); + +public: + // release all budgets immediately + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkBlobAllocator(const VkBlobAllocator&); + VkBlobAllocator& operator=(const VkBlobAllocator&); + +private: + VkBlobAllocatorPrivate* const d; +}; + +class VkWeightAllocatorPrivate; +class NCNN_EXPORT VkWeightAllocator : public VkAllocator +{ +public: + explicit VkWeightAllocator(const VulkanDevice* vkdev, size_t preferred_block_size = 8 * 1024 * 1024); // 8M + virtual ~VkWeightAllocator(); + +public: + // release all blocks immediately + virtual void clear(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkWeightAllocator(const VkWeightAllocator&); + VkWeightAllocator& operator=(const VkWeightAllocator&); + +private: + VkWeightAllocatorPrivate* const d; +}; + +class VkStagingAllocatorPrivate; +class NCNN_EXPORT VkStagingAllocator : public VkAllocator +{ +public: + explicit VkStagingAllocator(const VulkanDevice* vkdev); + virtual ~VkStagingAllocator(); + +public: + // ratio range 0 ~ 1 + // default cr = 0.75 + void set_size_compare_ratio(float scr); + + // release all budgets immediately + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkStagingAllocator(const VkStagingAllocator&); + VkStagingAllocator& operator=(const VkStagingAllocator&); + +private: + VkStagingAllocatorPrivate* const d; +}; + +class VkWeightStagingAllocatorPrivate; +class NCNN_EXPORT VkWeightStagingAllocator : public VkAllocator +{ +public: + explicit VkWeightStagingAllocator(const VulkanDevice* vkdev); + virtual ~VkWeightStagingAllocator(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkWeightStagingAllocator(const VkWeightStagingAllocator&); + VkWeightStagingAllocator& operator=(const VkWeightStagingAllocator&); + +private: + VkWeightStagingAllocatorPrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class NCNN_EXPORT VkAndroidHardwareBufferImageAllocator : public VkAllocator +{ +public: + VkAndroidHardwareBufferImageAllocator(const VulkanDevice* _vkdev, AHardwareBuffer* _hb); + virtual ~VkAndroidHardwareBufferImageAllocator(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkAndroidHardwareBufferImageAllocator(const VkAndroidHardwareBufferImageAllocator&); + VkAndroidHardwareBufferImageAllocator& operator=(const VkAndroidHardwareBufferImageAllocator&); + +public: + int init(); + + int width() const; + int height() const; + uint64_t external_format() const; + +public: + AHardwareBuffer* hb; + AHardwareBuffer_Desc bufferDesc; + VkAndroidHardwareBufferFormatPropertiesANDROID bufferFormatProperties; + VkAndroidHardwareBufferPropertiesANDROID bufferProperties; + VkSamplerYcbcrConversionKHR samplerYcbcrConversion; +}; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_ALLOCATOR_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/benchmark.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/benchmark.h new file mode 100644 index 0000000..ed42c1a --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/benchmark.h @@ -0,0 +1,39 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_BENCHMARK_H +#define NCNN_BENCHMARK_H + +#include "layer.h" +#include "mat.h" +#include "platform.h" + +namespace ncnn { + +// get now timestamp in ms +NCNN_EXPORT double get_current_time(); + +// sleep milliseconds +NCNN_EXPORT void sleep(unsigned long long int milliseconds = 1000); + +#if NCNN_BENCHMARK + +NCNN_EXPORT void benchmark(const Layer* layer, double start, double end); +NCNN_EXPORT void benchmark(const Layer* layer, const Mat& bottom_blob, Mat& top_blob, double start, double end); + +#endif // NCNN_BENCHMARK + +} // namespace ncnn + +#endif // NCNN_BENCHMARK_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/blob.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/blob.h new file mode 100644 index 0000000..c9f144f --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/blob.h @@ -0,0 +1,44 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_BLOB_H +#define NCNN_BLOB_H + +#include "mat.h" +#include "platform.h" + +namespace ncnn { + +class NCNN_EXPORT Blob +{ +public: + // empty + Blob(); + +public: +#if NCNN_STRING + // blob name + std::string name; +#endif // NCNN_STRING + // layer index which produce this blob as output + int producer; + // layer index which need this blob as input + int consumer; + // shape hint + Mat shape; +}; + +} // namespace ncnn + +#endif // NCNN_BLOB_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/c_api.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/c_api.h new file mode 100644 index 0000000..31d5b6d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/c_api.h @@ -0,0 +1,347 @@ +/* Tencent is pleased to support the open source community by making ncnn available. + * + * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef NCNN_C_API_H +#define NCNN_C_API_H + +#include "platform.h" + +#if NCNN_C_API + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +NCNN_EXPORT const char* ncnn_version(); + +/* allocator api */ +typedef struct __ncnn_allocator_t* ncnn_allocator_t; +struct NCNN_EXPORT __ncnn_allocator_t +{ + void* pthis; + + void* (*fast_malloc)(ncnn_allocator_t allocator, size_t size); + void (*fast_free)(ncnn_allocator_t allocator, void* ptr); +}; + +NCNN_EXPORT ncnn_allocator_t ncnn_allocator_create_pool_allocator(); +NCNN_EXPORT ncnn_allocator_t ncnn_allocator_create_unlocked_pool_allocator(); +NCNN_EXPORT void ncnn_allocator_destroy(ncnn_allocator_t allocator); + +/* option api */ +typedef struct __ncnn_option_t* ncnn_option_t; + +NCNN_EXPORT ncnn_option_t ncnn_option_create(); +NCNN_EXPORT void ncnn_option_destroy(ncnn_option_t opt); + +NCNN_EXPORT int ncnn_option_get_num_threads(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_num_threads(ncnn_option_t opt, int num_threads); + +NCNN_EXPORT int ncnn_option_get_use_local_pool_allocator(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_use_local_pool_allocator(ncnn_option_t opt, int use_local_pool_allocator); + +NCNN_EXPORT void ncnn_option_set_blob_allocator(ncnn_option_t opt, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_option_set_workspace_allocator(ncnn_option_t opt, ncnn_allocator_t allocator); + +NCNN_EXPORT int ncnn_option_get_use_vulkan_compute(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_use_vulkan_compute(ncnn_option_t opt, int use_vulkan_compute); + +/* mat api */ +typedef struct __ncnn_mat_t* ncnn_mat_t; + +NCNN_EXPORT ncnn_mat_t ncnn_mat_create(); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_1d(int w, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_2d(int w, int h, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_3d(int w, int h, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_4d(int w, int h, int d, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_1d(int w, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_2d(int w, int h, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_3d(int w, int h, int c, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_4d(int w, int h, int d, int c, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_1d_elem(int w, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_2d_elem(int w, int h, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_3d_elem(int w, int h, int c, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_4d_elem(int w, int h, int d, int c, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_1d_elem(int w, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_2d_elem(int w, int h, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_3d_elem(int w, int h, int c, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_4d_elem(int w, int h, int d, int c, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_mat_destroy(ncnn_mat_t mat); + +NCNN_EXPORT void ncnn_mat_fill_float(ncnn_mat_t mat, float v); + +NCNN_EXPORT ncnn_mat_t ncnn_mat_clone(const ncnn_mat_t mat, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_1d(const ncnn_mat_t mat, int w, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_2d(const ncnn_mat_t mat, int w, int h, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_3d(const ncnn_mat_t mat, int w, int h, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_4d(const ncnn_mat_t mat, int w, int h, int d, int c, ncnn_allocator_t allocator); + +NCNN_EXPORT int ncnn_mat_get_dims(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_w(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_h(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_d(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_c(const ncnn_mat_t mat); +NCNN_EXPORT size_t ncnn_mat_get_elemsize(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_elempack(const ncnn_mat_t mat); +NCNN_EXPORT size_t ncnn_mat_get_cstep(const ncnn_mat_t mat); +NCNN_EXPORT void* ncnn_mat_get_data(const ncnn_mat_t mat); + +NCNN_EXPORT void* ncnn_mat_get_channel_data(const ncnn_mat_t mat, int c); + +#if NCNN_PIXEL + +/* mat pixel api */ +#define NCNN_MAT_PIXEL_RGB 1 +#define NCNN_MAT_PIXEL_BGR 2 +#define NCNN_MAT_PIXEL_GRAY 3 +#define NCNN_MAT_PIXEL_RGBA 4 +#define NCNN_MAT_PIXEL_BGRA 5 +#define NCNN_MAT_PIXEL_X2Y(X, Y) (X | (Y << 16)) +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels(const unsigned char* pixels, int type, int w, int h, int stride, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, int target_width, int target_height, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_mat_to_pixels(const ncnn_mat_t mat, unsigned char* pixels, int type, int stride); +NCNN_EXPORT void ncnn_mat_to_pixels_resize(const ncnn_mat_t mat, unsigned char* pixels, int type, int target_width, int target_height, int target_stride); + +#endif /* NCNN_PIXEL */ + +NCNN_EXPORT void ncnn_mat_substract_mean_normalize(ncnn_mat_t mat, const float* mean_vals, const float* norm_vals); + +NCNN_EXPORT void ncnn_convert_packing(const ncnn_mat_t src, ncnn_mat_t* dst, int elempack, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_flatten(const ncnn_mat_t src, ncnn_mat_t* dst, const ncnn_option_t opt); + +/* blob api */ +typedef struct __ncnn_blob_t* ncnn_blob_t; + +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_blob_get_name(const ncnn_blob_t blob); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_blob_get_producer(const ncnn_blob_t blob); +NCNN_EXPORT int ncnn_blob_get_consumer(const ncnn_blob_t blob); + +NCNN_EXPORT void ncnn_blob_get_shape(const ncnn_blob_t blob, int* dims, int* w, int* h, int* c); + +/* paramdict api */ +typedef struct __ncnn_paramdict_t* ncnn_paramdict_t; + +NCNN_EXPORT ncnn_paramdict_t ncnn_paramdict_create(); +NCNN_EXPORT void ncnn_paramdict_destroy(ncnn_paramdict_t pd); + +NCNN_EXPORT int ncnn_paramdict_get_type(const ncnn_paramdict_t pd, int id); + +NCNN_EXPORT int ncnn_paramdict_get_int(const ncnn_paramdict_t pd, int id, int def); +NCNN_EXPORT float ncnn_paramdict_get_float(const ncnn_paramdict_t pd, int id, float def); +NCNN_EXPORT ncnn_mat_t ncnn_paramdict_get_array(const ncnn_paramdict_t pd, int id, const ncnn_mat_t def); + +NCNN_EXPORT void ncnn_paramdict_set_int(ncnn_paramdict_t pd, int id, int i); +NCNN_EXPORT void ncnn_paramdict_set_float(ncnn_paramdict_t pd, int id, float f); +NCNN_EXPORT void ncnn_paramdict_set_array(ncnn_paramdict_t pd, int id, const ncnn_mat_t v); + +/* datareader api */ +typedef struct __ncnn_datareader_t* ncnn_datareader_t; +struct NCNN_EXPORT __ncnn_datareader_t +{ + void* pthis; + +#if NCNN_STRING + int (*scan)(ncnn_datareader_t dr, const char* format, void* p); +#endif /* NCNN_STRING */ + size_t (*read)(ncnn_datareader_t dr, void* buf, size_t size); +}; + +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create(); +#if NCNN_STDIO +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create_from_stdio(FILE* fp); +#endif /* NCNN_STDIO */ +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create_from_memory(const unsigned char** mem); +NCNN_EXPORT void ncnn_datareader_destroy(ncnn_datareader_t dr); + +/* modelbin api */ +typedef struct __ncnn_modelbin_t* ncnn_modelbin_t; +struct NCNN_EXPORT __ncnn_modelbin_t +{ + void* pthis; + + ncnn_mat_t (*load_1d)(const ncnn_modelbin_t mb, int w, int type); + ncnn_mat_t (*load_2d)(const ncnn_modelbin_t mb, int w, int h, int type); + ncnn_mat_t (*load_3d)(const ncnn_modelbin_t mb, int w, int h, int c, int type); +}; + +NCNN_EXPORT ncnn_modelbin_t ncnn_modelbin_create_from_datareader(const ncnn_datareader_t dr); +NCNN_EXPORT ncnn_modelbin_t ncnn_modelbin_create_from_mat_array(const ncnn_mat_t* weights, int n); +NCNN_EXPORT void ncnn_modelbin_destroy(ncnn_modelbin_t mb); + +/* layer api */ +typedef struct __ncnn_layer_t* ncnn_layer_t; +struct NCNN_EXPORT __ncnn_layer_t +{ + void* pthis; + + int (*load_param)(ncnn_layer_t layer, const ncnn_paramdict_t pd); + int (*load_model)(ncnn_layer_t layer, const ncnn_modelbin_t mb); + + int (*create_pipeline)(ncnn_layer_t layer, const ncnn_option_t opt); + int (*destroy_pipeline)(ncnn_layer_t layer, const ncnn_option_t opt); + + int (*forward_1)(const ncnn_layer_t layer, const ncnn_mat_t bottom_blob, ncnn_mat_t* top_blob, const ncnn_option_t opt); + int (*forward_n)(const ncnn_layer_t layer, const ncnn_mat_t* bottom_blobs, int n, ncnn_mat_t* top_blobs, int n2, const ncnn_option_t opt); + + int (*forward_inplace_1)(const ncnn_layer_t layer, ncnn_mat_t bottom_top_blob, const ncnn_option_t opt); + int (*forward_inplace_n)(const ncnn_layer_t layer, ncnn_mat_t* bottom_top_blobs, int n, const ncnn_option_t opt); +}; + +NCNN_EXPORT ncnn_layer_t ncnn_layer_create(); +NCNN_EXPORT ncnn_layer_t ncnn_layer_create_by_typeindex(int typeindex); +#if NCNN_STRING +NCNN_EXPORT ncnn_layer_t ncnn_layer_create_by_type(const char* type); +NCNN_EXPORT int ncnn_layer_type_to_index(const char* type); +#endif /* NCNN_STRING */ +NCNN_EXPORT void ncnn_layer_destroy(ncnn_layer_t layer); + +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_layer_get_name(const ncnn_layer_t layer); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_layer_get_typeindex(const ncnn_layer_t layer); +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_layer_get_type(const ncnn_layer_t layer); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_layer_get_one_blob_only(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_inplace(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_vulkan(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_packing(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_bf16_storage(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_fp16_storage(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_image_storage(const ncnn_layer_t layer); + +NCNN_EXPORT void ncnn_layer_set_one_blob_only(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_inplace(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_vulkan(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_packing(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_bf16_storage(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_fp16_storage(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_image_storage(ncnn_layer_t layer, int enable); + +NCNN_EXPORT int ncnn_layer_get_bottom_count(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_bottom(const ncnn_layer_t layer, int i); +NCNN_EXPORT int ncnn_layer_get_top_count(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_top(const ncnn_layer_t layer, int i); + +NCNN_EXPORT void ncnn_blob_get_bottom_shape(const ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c); +NCNN_EXPORT void ncnn_blob_get_top_shape(const ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c); + +/* layer factory function */ +typedef ncnn_layer_t (*ncnn_layer_creator_t)(void* userdata); +typedef void (*ncnn_layer_destroyer_t)(ncnn_layer_t layer, void* userdata); + +typedef struct __ncnn_net_custom_layer_factory_t* ncnn_net_custom_layer_factory_t; +struct __ncnn_net_custom_layer_factory_t +{ + ncnn_layer_creator_t creator; + ncnn_layer_destroyer_t destroyer; + void* userdata; + ncnn_net_custom_layer_factory_t next; +}; + +/* net api */ +typedef struct __ncnn_net_t* ncnn_net_t; +struct __ncnn_net_t +{ + void* pthis; + + ncnn_net_custom_layer_factory_t custom_layer_factory; +}; + +NCNN_EXPORT ncnn_net_t ncnn_net_create(); +NCNN_EXPORT void ncnn_net_destroy(ncnn_net_t net); + +NCNN_EXPORT ncnn_option_t ncnn_net_get_option(ncnn_net_t net); +NCNN_EXPORT void ncnn_net_set_option(ncnn_net_t net, ncnn_option_t opt); + +#if NCNN_STRING +NCNN_EXPORT void ncnn_net_register_custom_layer_by_type(ncnn_net_t net, const char* type, ncnn_layer_creator_t creator, ncnn_layer_destroyer_t destroyer, void* userdata); +#endif /* NCNN_STRING */ +NCNN_EXPORT void ncnn_net_register_custom_layer_by_typeindex(ncnn_net_t net, int typeindex, ncnn_layer_creator_t creator, ncnn_layer_destroyer_t destroyer, void* userdata); + +#if NCNN_STDIO +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param(ncnn_net_t net, const char* path); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_load_param_bin(ncnn_net_t net, const char* path); +NCNN_EXPORT int ncnn_net_load_model(ncnn_net_t net, const char* path); +#endif /* NCNN_STDIO */ + +#if NCNN_STDIO +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param_memory(ncnn_net_t net, const char* mem); +#endif /* NCNN_STRING */ +#endif /* NCNN_STDIO */ +NCNN_EXPORT int ncnn_net_load_param_bin_memory(ncnn_net_t net, const unsigned char* mem); +NCNN_EXPORT int ncnn_net_load_model_memory(ncnn_net_t net, const unsigned char* mem); + +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param_datareader(ncnn_net_t net, const ncnn_datareader_t dr); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_load_param_bin_datareader(ncnn_net_t net, const ncnn_datareader_t dr); +NCNN_EXPORT int ncnn_net_load_model_datareader(ncnn_net_t net, const ncnn_datareader_t dr); + +NCNN_EXPORT void ncnn_net_clear(ncnn_net_t net); + +NCNN_EXPORT int ncnn_net_get_input_count(const ncnn_net_t net); +NCNN_EXPORT int ncnn_net_get_output_count(const ncnn_net_t net); +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_net_get_input_name(const ncnn_net_t net, int i); +NCNN_EXPORT const char* ncnn_net_get_output_name(const ncnn_net_t net, int i); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_get_input_index(const ncnn_net_t net, int i); +NCNN_EXPORT int ncnn_net_get_output_index(const ncnn_net_t net, int i); + +/* extractor api */ +typedef struct __ncnn_extractor_t* ncnn_extractor_t; + +NCNN_EXPORT ncnn_extractor_t ncnn_extractor_create(ncnn_net_t net); +NCNN_EXPORT void ncnn_extractor_destroy(ncnn_extractor_t ex); + +NCNN_EXPORT void ncnn_extractor_set_option(ncnn_extractor_t ex, const ncnn_option_t opt); + +#if NCNN_STRING +NCNN_EXPORT int ncnn_extractor_input(ncnn_extractor_t ex, const char* name, const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_extractor_extract(ncnn_extractor_t ex, const char* name, ncnn_mat_t* mat); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_extractor_input_index(ncnn_extractor_t ex, int index, const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_extractor_extract_index(ncnn_extractor_t ex, int index, ncnn_mat_t* mat); + +/* mat process api */ +#define NCNN_BORDER_CONSTANT 0 +#define NCNN_BORDER_REPLICATE 1 +#define NCNN_BORDER_REFLECT 2 +#define NCNN_BORDER_TRANSPARENT -233 +NCNN_EXPORT void ncnn_copy_make_border(const ncnn_mat_t src, ncnn_mat_t dst, int top, int bottom, int left, int right, int type, float v, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_copy_make_border_3d(const ncnn_mat_t src, ncnn_mat_t dst, int top, int bottom, int left, int right, int front, int behind, int type, float v, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_copy_cut_border(const ncnn_mat_t src, ncnn_mat_t dst, int top, int bottom, int left, int right, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_copy_cut_border_3d(const ncnn_mat_t src, ncnn_mat_t dst, int top, int bottom, int left, int right, int front, int behind, const ncnn_option_t opt); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* NCNN_C_API */ + +#endif /* NCNN_C_API_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/command.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/command.h new file mode 100644 index 0000000..337d085 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/command.h @@ -0,0 +1,136 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_COMMAND_H +#define NCNN_COMMAND_H + +#include "platform.h" + +#if NCNN_VULKAN + +#include "mat.h" + +#include + +namespace ncnn { + +class Pipeline; +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class ImportAndroidHardwareBufferPipeline; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API +class VkComputePrivate; +class NCNN_EXPORT VkCompute +{ +public: + explicit VkCompute(const VulkanDevice* vkdev); + virtual ~VkCompute(); + +public: + void record_upload(const Mat& src, VkMat& dst, const Option& opt); + + void record_upload(const Mat& src, VkImageMat& dst, const Option& opt); + + void record_download(const VkMat& src, Mat& dst, const Option& opt); + + void record_download(const VkImageMat& src, Mat& dst, const Option& opt); + + void record_buffer_to_image(const VkMat& src, VkImageMat& dst, const Option& opt); + + void record_image_to_buffer(const VkImageMat& src, VkMat& dst, const Option& opt); + + void record_clone(const Mat& src, VkMat& dst, const Option& opt); + + void record_clone(const Mat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkMat& src, Mat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, Mat& dst, const Option& opt); + + void record_clone(const VkMat& src, VkMat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkMat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, VkMat& dst, const Option& opt); + + void record_pipeline(const Pipeline* pipeline, const std::vector& bindings, const std::vector& constants, const VkMat& dispatcher); + + void record_pipeline(const Pipeline* pipeline, const std::vector& bindings, const std::vector& constants, const VkImageMat& dispatcher); + + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const VkMat& dispatcher); + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const VkImageMat& dispatcher); + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const Mat& dispatcher); + +#if NCNN_BENCHMARK + void record_write_timestamp(uint32_t query); +#endif // NCNN_BENCHMARK + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 + void record_import_android_hardware_buffer(const ImportAndroidHardwareBufferPipeline* pipeline, const VkImageMat& src, const VkMat& dst); + + void record_import_android_hardware_buffer(const ImportAndroidHardwareBufferPipeline* pipeline, const VkImageMat& src, const VkImageMat& dst); +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + + int submit_and_wait(); + + int reset(); + +#if NCNN_BENCHMARK + int create_query_pool(uint32_t query_count); + + int get_query_pool_results(uint32_t first_query, uint32_t query_count, std::vector& results); +#endif // NCNN_BENCHMARK + +protected: + const VulkanDevice* vkdev; + + void barrier_readwrite(const VkMat& binding); + void barrier_readwrite(const VkImageMat& binding); + void barrier_readonly(const VkImageMat& binding); + +private: + VkComputePrivate* const d; +}; + +class VkTransferPrivate; +class NCNN_EXPORT VkTransfer +{ +public: + explicit VkTransfer(const VulkanDevice* vkdev); + virtual ~VkTransfer(); + +public: + void record_upload(const Mat& src, VkMat& dst, const Option& opt, bool flatten = true); + + void record_upload(const Mat& src, VkImageMat& dst, const Option& opt); + + int submit_and_wait(); + +protected: + const VulkanDevice* vkdev; + +private: + VkTransferPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_VULKAN + +#endif // NCNN_COMMAND_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/cpu.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/cpu.h new file mode 100644 index 0000000..7d6bfce --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/cpu.h @@ -0,0 +1,178 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_CPU_H +#define NCNN_CPU_H + +#include + +#if (defined _WIN32 && !(defined __MINGW32__)) +#define WIN32_LEAN_AND_MEAN +#include +#endif +#if defined __ANDROID__ || defined __linux__ +#include // cpu_set_t +#endif + +#include "platform.h" + +namespace ncnn { + +class NCNN_EXPORT CpuSet +{ +public: + CpuSet(); + void enable(int cpu); + void disable(int cpu); + void disable_all(); + bool is_enabled(int cpu) const; + int num_enabled() const; + +public: +#if (defined _WIN32 && !(defined __MINGW32__)) + ULONG_PTR mask; +#endif +#if defined __ANDROID__ || defined __linux__ + cpu_set_t cpu_set; +#endif +#if __APPLE__ + unsigned int policy; +#endif +}; + +// test optional cpu features +// edsp = armv7 edsp +NCNN_EXPORT int cpu_support_arm_edsp(); +// neon = armv7 neon or aarch64 asimd +NCNN_EXPORT int cpu_support_arm_neon(); +// vfpv4 = armv7 fp16 + fma +NCNN_EXPORT int cpu_support_arm_vfpv4(); +// asimdhp = aarch64 asimd half precision +NCNN_EXPORT int cpu_support_arm_asimdhp(); +// cpuid = aarch64 cpuid info +NCNN_EXPORT int cpu_support_arm_cpuid(); +// asimddp = aarch64 asimd dot product +NCNN_EXPORT int cpu_support_arm_asimddp(); +// asimdfhm = aarch64 asimd fhm +NCNN_EXPORT int cpu_support_arm_asimdfhm(); +// bf16 = aarch64 bf16 +NCNN_EXPORT int cpu_support_arm_bf16(); +// i8mm = aarch64 i8mm +NCNN_EXPORT int cpu_support_arm_i8mm(); +// sve = aarch64 sve +NCNN_EXPORT int cpu_support_arm_sve(); +// sve2 = aarch64 sve2 +NCNN_EXPORT int cpu_support_arm_sve2(); +// svebf16 = aarch64 svebf16 +NCNN_EXPORT int cpu_support_arm_svebf16(); +// svei8mm = aarch64 svei8mm +NCNN_EXPORT int cpu_support_arm_svei8mm(); +// svef32mm = aarch64 svef32mm +NCNN_EXPORT int cpu_support_arm_svef32mm(); + +// avx = x86 avx +NCNN_EXPORT int cpu_support_x86_avx(); +// fma = x86 fma +NCNN_EXPORT int cpu_support_x86_fma(); +// xop = x86 xop +NCNN_EXPORT int cpu_support_x86_xop(); +// f16c = x86 f16c +NCNN_EXPORT int cpu_support_x86_f16c(); +// avx2 = x86 avx2 + fma + f16c +NCNN_EXPORT int cpu_support_x86_avx2(); +// avx_vnni = x86 avx vnni +NCNN_EXPORT int cpu_support_x86_avx_vnni(); +// avx512 = x86 avx512f + avx512cd + avx512bw + avx512dq + avx512vl +NCNN_EXPORT int cpu_support_x86_avx512(); +// avx512_vnni = x86 avx512 vnni +NCNN_EXPORT int cpu_support_x86_avx512_vnni(); +// avx512_bf16 = x86 avx512 bf16 +NCNN_EXPORT int cpu_support_x86_avx512_bf16(); +// avx512_fp16 = x86 avx512 fp16 +NCNN_EXPORT int cpu_support_x86_avx512_fp16(); + +// lsx = loongarch lsx +NCNN_EXPORT int cpu_support_loongarch_lsx(); +// lasx = loongarch lasx +NCNN_EXPORT int cpu_support_loongarch_lasx(); + +// msa = mips mas +NCNN_EXPORT int cpu_support_mips_msa(); +// mmi = loongson mmi +NCNN_EXPORT int cpu_support_loongson_mmi(); + +// v = riscv vector +NCNN_EXPORT int cpu_support_riscv_v(); +// zfh = riscv half-precision float +NCNN_EXPORT int cpu_support_riscv_zfh(); +// vlenb = riscv vector length in bytes +NCNN_EXPORT int cpu_riscv_vlenb(); + +// cpu info +NCNN_EXPORT int get_cpu_count(); +NCNN_EXPORT int get_little_cpu_count(); +NCNN_EXPORT int get_big_cpu_count(); + +NCNN_EXPORT int get_physical_cpu_count(); +NCNN_EXPORT int get_physical_little_cpu_count(); +NCNN_EXPORT int get_physical_big_cpu_count(); + +// cpu l2 varies from 64k to 1M, but l3 can be zero +NCNN_EXPORT int get_cpu_level2_cache_size(); +NCNN_EXPORT int get_cpu_level3_cache_size(); + +// bind all threads on little clusters if powersave enabled +// affects HMP arch cpu like ARM big.LITTLE +// only implemented on android at the moment +// switching powersave is expensive and not thread-safe +// 0 = all cores enabled(default) +// 1 = only little clusters enabled +// 2 = only big clusters enabled +// return 0 if success for setter function +NCNN_EXPORT int get_cpu_powersave(); +NCNN_EXPORT int set_cpu_powersave(int powersave); + +// convenient wrapper +NCNN_EXPORT const CpuSet& get_cpu_thread_affinity_mask(int powersave); + +// set explicit thread affinity +NCNN_EXPORT int set_cpu_thread_affinity(const CpuSet& thread_affinity_mask); + +// runtime thread affinity info +NCNN_EXPORT int is_current_thread_running_on_a53_a55(); + +// misc function wrapper for openmp routines +NCNN_EXPORT int get_omp_num_threads(); +NCNN_EXPORT void set_omp_num_threads(int num_threads); + +NCNN_EXPORT int get_omp_dynamic(); +NCNN_EXPORT void set_omp_dynamic(int dynamic); + +NCNN_EXPORT int get_omp_thread_num(); + +NCNN_EXPORT int get_kmp_blocktime(); +NCNN_EXPORT void set_kmp_blocktime(int time_ms); + +// need to flush denormals on Intel Chipset. +// Other architectures such as ARM can be added as needed. +// 0 = DAZ OFF, FTZ OFF +// 1 = DAZ ON , FTZ OFF +// 2 = DAZ OFF, FTZ ON +// 3 = DAZ ON, FTZ ON +NCNN_EXPORT int get_flush_denormals(); +NCNN_EXPORT int set_flush_denormals(int flush_denormals); + +} // namespace ncnn + +#endif // NCNN_CPU_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/datareader.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/datareader.h new file mode 100644 index 0000000..ed2aba3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/datareader.h @@ -0,0 +1,122 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_DATAREADER_H +#define NCNN_DATAREADER_H + +#include "platform.h" +#if NCNN_STDIO +#include +#endif + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#endif +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +// data read wrapper +class NCNN_EXPORT DataReader +{ +public: + DataReader(); + virtual ~DataReader(); + +#if NCNN_STRING + // parse plain param text + // return 1 if scan success + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + + // read binary param and model data + // return bytes read + virtual size_t read(void* buf, size_t size) const; + + // get model data reference + // return bytes referenced + virtual size_t reference(size_t size, const void** buf) const; +}; + +#if NCNN_STDIO +class DataReaderFromStdioPrivate; +class NCNN_EXPORT DataReaderFromStdio : public DataReader +{ +public: + explicit DataReaderFromStdio(FILE* fp); + virtual ~DataReaderFromStdio(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + +private: + DataReaderFromStdio(const DataReaderFromStdio&); + DataReaderFromStdio& operator=(const DataReaderFromStdio&); + +private: + DataReaderFromStdioPrivate* const d; +}; +#endif // NCNN_STDIO + +class DataReaderFromMemoryPrivate; +class NCNN_EXPORT DataReaderFromMemory : public DataReader +{ +public: + explicit DataReaderFromMemory(const unsigned char*& mem); + virtual ~DataReaderFromMemory(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + virtual size_t reference(size_t size, const void** buf) const; + +private: + DataReaderFromMemory(const DataReaderFromMemory&); + DataReaderFromMemory& operator=(const DataReaderFromMemory&); + +private: + DataReaderFromMemoryPrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +class DataReaderFromAndroidAssetPrivate; +class NCNN_EXPORT DataReaderFromAndroidAsset : public DataReader +{ +public: + explicit DataReaderFromAndroidAsset(AAsset* asset); + virtual ~DataReaderFromAndroidAsset(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + +private: + DataReaderFromAndroidAsset(const DataReaderFromAndroidAsset&); + DataReaderFromAndroidAsset& operator=(const DataReaderFromAndroidAsset&); + +private: + DataReaderFromAndroidAssetPrivate* const d; +}; +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + +} // namespace ncnn + +#endif // NCNN_DATAREADER_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/gpu.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/gpu.h new file mode 100644 index 0000000..1eff228 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/gpu.h @@ -0,0 +1,392 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_GPU_H +#define NCNN_GPU_H + +#include "platform.h" + +#if NCNN_VULKAN + +#include "mat.h" + +#include + +#include "vulkan_header_fix.h" + +namespace ncnn { + +// instance + +// Create VkInstance and initialize some objects that need to be calculated by GPU +// Creates a VkInstance object, Checks the extended attributes supported by the Vulkan instance concerned, +// Initializes, and creates Vulkan validation layers (if ENABLE_VALIDATION_LAYER is enabled), +// Iterates over all supported physical devices, etc. +NCNN_EXPORT int create_gpu_instance(); + +// Get global VkInstance variable +// Must be called after create_gpu_instance() and before destroy_gpu_instance() +NCNN_EXPORT VkInstance get_gpu_instance(); + +// Destroy VkInstance object and free the memory of the associated object +// Usually called in the destructor of the main program exit +NCNN_EXPORT void destroy_gpu_instance(); + +// instance extension capability +extern int support_VK_KHR_external_memory_capabilities; +extern int support_VK_KHR_get_physical_device_properties2; +extern int support_VK_KHR_get_surface_capabilities2; +extern int support_VK_KHR_surface; +extern int support_VK_EXT_debug_utils; +extern int support_VK_EXT_validation_features; +extern int support_VK_EXT_validation_flags; +#if __ANDROID_API__ >= 26 +extern int support_VK_KHR_android_surface; +#endif // __ANDROID_API__ >= 26 + +// VK_KHR_cooperative_matrix +extern PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR; + +// VK_KHR_external_memory_capabilities +extern PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR vkGetPhysicalDeviceExternalBufferPropertiesKHR; + +// VK_KHR_get_physical_device_properties2 +extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; +extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; +extern PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceImageFormatProperties2KHR vkGetPhysicalDeviceImageFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR; +extern PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR; +extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR vkGetPhysicalDeviceSparseImageFormatProperties2KHR; + +// VK_KHR_get_surface_capabilities2 +extern PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR; + +// VK_KHR_surface +extern PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; +extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; +extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; +extern PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; + +#if __ANDROID_API__ >= 26 +// VK_KHR_android_surface +extern PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; +#endif // __ANDROID_API__ >= 26 + +// VK_NV_cooperative_matrix +extern PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV vkGetPhysicalDeviceCooperativeMatrixPropertiesNV; + +// get info +NCNN_EXPORT int get_gpu_count(); +NCNN_EXPORT int get_default_gpu_index(); + +class GpuInfoPrivate; +class NCNN_EXPORT GpuInfo +{ +public: + explicit GpuInfo(); + virtual ~GpuInfo(); + + // vulkan physical device + VkPhysicalDevice physical_device() const; + + // memory properties + const VkPhysicalDeviceMemoryProperties& physical_device_memory_properties() const; + + // info + uint32_t api_version() const; + uint32_t driver_version() const; + uint32_t vendor_id() const; + uint32_t device_id() const; + const char* device_name() const; + uint8_t* pipeline_cache_uuid() const; + + // 0 = discrete gpu + // 1 = integrated gpu + // 2 = virtual gpu + // 3 = cpu + int type() const; + + // hardware limit + uint32_t max_shared_memory_size() const; + uint32_t max_workgroup_count_x() const; + uint32_t max_workgroup_count_y() const; + uint32_t max_workgroup_count_z() const; + uint32_t max_workgroup_invocations() const; + uint32_t max_workgroup_size_x() const; + uint32_t max_workgroup_size_y() const; + uint32_t max_workgroup_size_z() const; + size_t memory_map_alignment() const; + size_t buffer_offset_alignment() const; + size_t non_coherent_atom_size() const; + size_t buffer_image_granularity() const; + uint32_t max_image_dimension_1d() const; + uint32_t max_image_dimension_2d() const; + uint32_t max_image_dimension_3d() const; + float timestamp_period() const; + + // runtime + uint32_t compute_queue_family_index() const; + uint32_t graphics_queue_family_index() const; + uint32_t transfer_queue_family_index() const; + + uint32_t compute_queue_count() const; + uint32_t graphics_queue_count() const; + uint32_t transfer_queue_count() const; + + // property + bool unified_compute_transfer_queue() const; + + // subgroup + uint32_t subgroup_size() const; + bool support_subgroup_basic() const; + bool support_subgroup_vote() const; + bool support_subgroup_ballot() const; + bool support_subgroup_shuffle() const; + + // bug is not feature + bool bug_storage_buffer_no_l1() const; + bool bug_corrupted_online_pipeline_cache() const; + bool bug_buffer_image_load_zero() const; + + // but sometimes bug is a feature + bool bug_implicit_fp16_arithmetic() const; + + // fp16 and int8 feature + bool support_fp16_packed() const; + bool support_fp16_storage() const; + bool support_fp16_arithmetic() const; + bool support_int8_packed() const; + bool support_int8_storage() const; + bool support_int8_arithmetic() const; + + // ycbcr conversion feature + bool support_ycbcr_conversion() const; + + // cooperative matrix feature + bool support_cooperative_matrix() const; + bool support_cooperative_matrix_16_8_8() const; + bool support_cooperative_matrix_16_8_16() const; + bool support_cooperative_matrix_16_16_16() const; + + // extension capability + int support_VK_KHR_8bit_storage() const; + int support_VK_KHR_16bit_storage() const; + int support_VK_KHR_bind_memory2() const; + int support_VK_KHR_buffer_device_address() const; + int support_VK_KHR_create_renderpass2() const; + int support_VK_KHR_cooperative_matrix() const; + int support_VK_KHR_dedicated_allocation() const; + int support_VK_KHR_descriptor_update_template() const; + int support_VK_KHR_external_memory() const; + int support_VK_KHR_get_memory_requirements2() const; + int support_VK_KHR_maintenance1() const; + int support_VK_KHR_maintenance2() const; + int support_VK_KHR_maintenance3() const; + int support_VK_KHR_multiview() const; + int support_VK_KHR_portability_subset() const; + int support_VK_KHR_push_descriptor() const; + int support_VK_KHR_sampler_ycbcr_conversion() const; + int support_VK_KHR_shader_float16_int8() const; + int support_VK_KHR_shader_float_controls() const; + int support_VK_KHR_storage_buffer_storage_class() const; + int support_VK_KHR_swapchain() const; + int support_VK_EXT_buffer_device_address() const; + int support_VK_EXT_descriptor_indexing() const; + int support_VK_EXT_memory_budget() const; + int support_VK_EXT_memory_priority() const; + int support_VK_EXT_queue_family_foreign() const; + int support_VK_AMD_device_coherent_memory() const; +#if __ANDROID_API__ >= 26 + int support_VK_ANDROID_external_memory_android_hardware_buffer() const; +#endif // __ANDROID_API__ >= 26 + int support_VK_NV_cooperative_matrix() const; + +private: + GpuInfo(const GpuInfo&); + GpuInfo& operator=(const GpuInfo&); + +private: + friend int create_gpu_instance(); + GpuInfoPrivate* const d; +}; + +NCNN_EXPORT const GpuInfo& get_gpu_info(int device_index = get_default_gpu_index()); + +class VkAllocator; +class VkCompute; +class Option; +class PipelineCache; +class VulkanDevicePrivate; +class NCNN_EXPORT VulkanDevice +{ +public: + VulkanDevice(int device_index = get_default_gpu_index()); + ~VulkanDevice(); + + const GpuInfo& info; + + VkDevice vkdevice() const; + + VkShaderModule compile_shader_module(const uint32_t* spv_data, size_t spv_data_size) const; + + // with fixed workgroup size + VkShaderModule compile_shader_module(const uint32_t* spv_data, size_t spv_data_size, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z) const; + + // helper for creating pipeline + int create_descriptorset_layout(int binding_count, const int* binding_types, VkDescriptorSetLayout* descriptorset_layout) const; + int create_pipeline_layout(int push_constant_count, VkDescriptorSetLayout descriptorset_layout, VkPipelineLayout* pipeline_layout) const; + int create_pipeline(VkShaderModule shader_module, VkPipelineLayout pipeline_layout, const std::vector& specializations, VkPipeline* pipeline) const; + int create_descriptor_update_template(int binding_count, const int* binding_types, VkDescriptorSetLayout descriptorset_layout, VkPipelineLayout pipeline_layout, VkDescriptorUpdateTemplateKHR* descriptor_update_template) const; + + uint32_t find_memory_index(uint32_t memory_type_bits, VkFlags required, VkFlags preferred, VkFlags preferred_not) const; + bool is_mappable(uint32_t memory_type_index) const; + bool is_coherent(uint32_t memory_type_index) const; + + VkQueue acquire_queue(uint32_t queue_family_index) const; + void reclaim_queue(uint32_t queue_family_index, VkQueue queue) const; + + // allocator on this device + VkAllocator* acquire_blob_allocator() const; + void reclaim_blob_allocator(VkAllocator* allocator) const; + + VkAllocator* acquire_staging_allocator() const; + void reclaim_staging_allocator(VkAllocator* allocator) const; + + // immutable sampler for texelfetch + const VkSampler* immutable_texelfetch_sampler() const; + + // dummy buffer image + VkMat get_dummy_buffer() const; + VkImageMat get_dummy_image() const; + VkImageMat get_dummy_image_readonly() const; + + // pipeline cache on this device + const PipelineCache* get_pipeline_cache() const; + + // test image allocation + bool shape_support_image_storage(const Mat& shape) const; + + // current gpu heap memory budget in MB + uint32_t get_heap_budget() const; + + // utility operator + void convert_packing(const VkMat& src, VkMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkImageMat& src, VkImageMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkMat& src, VkImageMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkImageMat& src, VkMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + + // VK_KHR_bind_memory2 + PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; + PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; + + // VK_KHR_buffer_device_address + PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR; + PFN_vkGetBufferOpaqueCaptureAddressKHR vkGetBufferOpaqueCaptureAddressKHR; + PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR vkGetDeviceMemoryOpaqueCaptureAddressKHR; + + // VK_KHR_create_renderpass2 + PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; + PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; + PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; + + // VK_KHR_descriptor_update_template + PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; + PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; + PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; + + // VK_KHR_get_memory_requirements2 + PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; + PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; + PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; + + // VK_KHR_maintenance1 + PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; + + // VK_KHR_maintenance3 + PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; + + // VK_KHR_push_descriptor + PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; + PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; + + // VK_KHR_sampler_ycbcr_conversion + PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; + PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; + + // VK_KHR_swapchain + PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; + PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; + PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; + PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; + PFN_vkQueuePresentKHR vkQueuePresentKHR; + + // VK_EXT_buffer_device_address + PFN_vkGetBufferDeviceAddressEXT vkGetBufferDeviceAddressEXT; + +#if __ANDROID_API__ >= 26 + // VK_ANDROID_external_memory_android_hardware_buffer + PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; + PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; +#endif // __ANDROID_API__ >= 26 + +protected: + // device extension + int init_device_extension(); + +private: + VulkanDevice(const VulkanDevice&); + VulkanDevice& operator=(const VulkanDevice&); + +private: + VulkanDevicePrivate* const d; +}; + +NCNN_EXPORT VulkanDevice* get_gpu_device(int device_index = get_default_gpu_index()); + +// online spirv compilation +NCNN_EXPORT int compile_spirv_module(const char* comp_string, const Option& opt, std::vector& spirv); +NCNN_EXPORT int compile_spirv_module(const char* comp_data, int comp_data_size, const Option& opt, std::vector& spirv); +NCNN_EXPORT int compile_spirv_module(int shader_type_index, const Option& opt, std::vector& spirv); + +// info from spirv +class NCNN_EXPORT ShaderInfo +{ +public: + int specialization_count; + int binding_count; + int push_constant_count; + + // 0 = null + // 1 = storage buffer + // 2 = storage image + // 3 = combined image sampler + int binding_types[16]; // 16 is large enough I think ... + + int reserved_0; + int reserved_1; + int reserved_2; + int reserved_3; +}; + +NCNN_EXPORT int resolve_shader_info(const uint32_t* spv_data, size_t spv_data_size, ShaderInfo& shader_info); + +} // namespace ncnn + +#endif // NCNN_VULKAN + +#endif // NCNN_GPU_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/layer.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/layer.h new file mode 100644 index 0000000..f0418a9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/layer.h @@ -0,0 +1,222 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_H +#define NCNN_LAYER_H + +#include "mat.h" +#include "modelbin.h" +#include "option.h" +#include "paramdict.h" +#include "platform.h" + +#if NCNN_VULKAN +#include "command.h" +#include "pipeline.h" + +#include +#endif // NCNN_VULKAN + +namespace ncnn { + +class NCNN_EXPORT Layer +{ +public: + // empty + Layer(); + // virtual destructor + virtual ~Layer(); + + // load layer specific parameter from parsed dict + // return 0 if success + virtual int load_param(const ParamDict& pd); + + // load layer specific weight data from model binary + // return 0 if success + virtual int load_model(const ModelBin& mb); + + // layer implementation specific setup + // return 0 if success + virtual int create_pipeline(const Option& opt); + + // layer implementation specific clean + // return 0 if success + virtual int destroy_pipeline(const Option& opt); + +public: + // one input and one output blob + bool one_blob_only; + + // support inplace inference + bool support_inplace; + + // support vulkan compute + bool support_vulkan; + + // accept input blob with packed storage + bool support_packing; + + // accept bf16 + bool support_bf16_storage; + + // accept fp16 + bool support_fp16_storage; + + // accept int8 + bool support_int8_storage; + + // shader image storage + bool support_image_storage; + + // shader tensor storage + bool support_tensor_storage; + + bool support_reserved_00; + + bool support_reserved_0; + bool support_reserved_1; + bool support_reserved_2; + bool support_reserved_3; + bool support_reserved_4; + bool support_reserved_5; + bool support_reserved_6; + bool support_reserved_7; + bool support_reserved_8; + bool support_reserved_9; + + // feature disabled set + int featmask; + +public: + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, const Option& opt) const; + virtual int forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, const Option& opt) const; + virtual int forward_inplace(Mat& bottom_top_blob, const Option& opt) const; + +#if NCNN_VULKAN +public: + // upload weight blob from host to device + virtual int upload_model(VkTransfer& cmd, const Option& opt); + +public: + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward_inplace(VkMat& bottom_top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward_inplace(VkImageMat& bottom_top_blob, VkCompute& cmd, const Option& opt) const; + +public: + // assigned immediately after creating this layer + const VulkanDevice* vkdev; +#endif // NCNN_VULKAN + +public: + // custom user data + void* userdata; + // layer type index + int typeindex; +#if NCNN_STRING + // layer type name + std::string type; + // layer name + std::string name; +#endif // NCNN_STRING + // blob index which this layer needs as input + std::vector bottoms; + // blob index which this layer produces as output + std::vector tops; + // shape hint + std::vector bottom_shapes; + std::vector top_shapes; +}; + +// layer factory function +typedef Layer* (*layer_creator_func)(void*); +typedef void (*layer_destroyer_func)(Layer*, void*); + +struct layer_registry_entry +{ +#if NCNN_STRING + // layer type name + const char* name; +#endif // NCNN_STRING + // layer factory entry + layer_creator_func creator; +}; + +struct custom_layer_registry_entry +{ +#if NCNN_STRING + // layer type name + const char* name; +#endif // NCNN_STRING + // layer factory entry + layer_creator_func creator; + layer_destroyer_func destroyer; + void* userdata; +}; + +struct overwrite_builtin_layer_registry_entry +{ + // layer type index + int typeindex; + // layer factory entry + layer_creator_func creator; + layer_destroyer_func destroyer; + void* userdata; +}; + +#if NCNN_STRING +// get layer type from type name +NCNN_EXPORT int layer_to_index(const char* type); +// create layer from type name +NCNN_EXPORT Layer* create_layer(const char* type); +#endif // NCNN_STRING +// create layer from layer type +NCNN_EXPORT Layer* create_layer(int index); + +#define DEFINE_LAYER_CREATOR(name) \ + ::ncnn::Layer* name##_layer_creator(void* /*userdata*/) \ + { \ + return new name; \ + } + +#define DEFINE_LAYER_DESTROYER(name) \ + void name##_layer_destroyer(::ncnn::Layer* layer, void* /*userdata*/) \ + { \ + delete layer; \ + } + +} // namespace ncnn + +#endif // NCNN_LAYER_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/layer_shader_type.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/layer_shader_type.h new file mode 100644 index 0000000..c143e7d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/layer_shader_type.h @@ -0,0 +1,29 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_SHADER_TYPE_H +#define NCNN_LAYER_SHADER_TYPE_H + +namespace ncnn { + +namespace LayerShaderType { +enum LayerShaderType +{ +#include "layer_shader_type_enum.h" +}; +} // namespace LayerShaderType + +} // namespace ncnn + +#endif // NCNN_LAYER_SHADER_TYPE_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/layer_shader_type_enum.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/layer_shader_type_enum.h new file mode 100644 index 0000000..aac8803 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/layer_shader_type_enum.h @@ -0,0 +1,5 @@ +// Layer Shader Enum header +// +// This file is auto-generated by cmake, don't edit it. + + diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/layer_type.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/layer_type.h new file mode 100644 index 0000000..511c714 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/layer_type.h @@ -0,0 +1,30 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_TYPE_H +#define NCNN_LAYER_TYPE_H + +namespace ncnn { + +namespace LayerType { +enum LayerType +{ +#include "layer_type_enum.h" + CustomBit = (1 << 8), +}; +} // namespace LayerType + +} // namespace ncnn + +#endif // NCNN_LAYER_TYPE_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/layer_type_enum.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/layer_type_enum.h new file mode 100644 index 0000000..97153ed --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/layer_type_enum.h @@ -0,0 +1,109 @@ +// Layer Type Enum header +// +// This file is auto-generated by cmake, don't edit it. + +AbsVal = 0, +ArgMax = 1, +BatchNorm = 2, +Bias = 3, +BNLL = 4, +Concat = 5, +Convolution = 6, +Crop = 7, +Deconvolution = 8, +Dropout = 9, +Eltwise = 10, +ELU = 11, +Embed = 12, +Exp = 13, +Flatten = 14, +InnerProduct = 15, +Input = 16, +Log = 17, +LRN = 18, +MemoryData = 19, +MVN = 20, +Pooling = 21, +Power = 22, +PReLU = 23, +Proposal = 24, +Reduction = 25, +ReLU = 26, +Reshape = 27, +ROIPooling = 28, +Scale = 29, +Sigmoid = 30, +Slice = 31, +Softmax = 32, +Split = 33, +SPP = 34, +TanH = 35, +Threshold = 36, +Tile = 37, +RNN = 38, +LSTM = 39, +BinaryOp = 40, +UnaryOp = 41, +ConvolutionDepthWise = 42, +Padding = 43, +Squeeze = 44, +ExpandDims = 45, +Normalize = 46, +Permute = 47, +PriorBox = 48, +DetectionOutput = 49, +Interp = 50, +DeconvolutionDepthWise = 51, +ShuffleChannel = 52, +InstanceNorm = 53, +Clip = 54, +Reorg = 55, +YoloDetectionOutput = 56, +Quantize = 57, +Dequantize = 58, +Yolov3DetectionOutput = 59, +PSROIPooling = 60, +ROIAlign = 61, +Packing = 62, +Requantize = 63, +Cast = 64, +HardSigmoid = 65, +SELU = 66, +HardSwish = 67, +Noop = 68, +PixelShuffle = 69, +DeepCopy = 70, +Mish = 71, +StatisticsPooling = 72, +Swish = 73, +Gemm = 74, +GroupNorm = 75, +LayerNorm = 76, +Softplus = 77, +GRU = 78, +MultiHeadAttention = 79, +GELU = 80, +Convolution1D = 81, +Pooling1D = 82, +ConvolutionDepthWise1D = 83, +Convolution3D = 84, +ConvolutionDepthWise3D = 85, +Pooling3D = 86, +MatMul = 87, +Deconvolution1D = 88, +DeconvolutionDepthWise1D = 89, +Deconvolution3D = 90, +DeconvolutionDepthWise3D = 91, +Einsum = 92, +DeformableConv2D = 93, +GLU = 94, +Fold = 95, +Unfold = 96, +GridSample = 97, +CumulativeSum = 98, +CopyTo = 99, +Erf = 100, +Diag = 101, +CELU = 102, +Shrink = 103, + diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/mat.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/mat.h new file mode 100644 index 0000000..c6f59ef --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/mat.h @@ -0,0 +1,1843 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_MAT_H +#define NCNN_MAT_H + +#include +#include +#if __ARM_NEON +#include +#endif +#if __SSE2__ +#include +#if __AVX__ +#include +#endif +#endif +#if __mips_msa +#include +#endif +#if __loongarch_sx +#include +#endif +#if __riscv_vector +#include +#include "cpu.h" // cpu_riscv_vlenb() +#endif + +#include "allocator.h" +#include "option.h" +#include "platform.h" + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#if NCNN_PIXEL +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#include +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API +#endif // NCNN_PIXEL + +namespace ncnn { + +#if NCNN_VULKAN +class VkMat; +class VkImageMat; +#endif // NCNN_VULKAN + +// the three dimension matrix +class NCNN_EXPORT Mat +{ +public: + // empty + Mat(); + // vec + Mat(int w, size_t elemsize = 4u, Allocator* allocator = 0); + // image + Mat(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0); + // dim + Mat(int w, int h, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // cube + Mat(int w, int h, int d, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // packed vec + Mat(int w, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed image + Mat(int w, int h, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed dim + Mat(int w, int h, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed cube + Mat(int w, int h, int d, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // copy + Mat(const Mat& m); + // external vec + Mat(int w, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external image + Mat(int w, int h, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external dim + Mat(int w, int h, int c, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external cube + Mat(int w, int h, int d, int c, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external packed vec + Mat(int w, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed image + Mat(int w, int h, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed dim + Mat(int w, int h, int c, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed cube + Mat(int w, int h, int d, int c, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // release + ~Mat(); + // assign + Mat& operator=(const Mat& m); + // set all + void fill(float v); + void fill(int v); +#if __ARM_NEON + void fill(float32x4_t _v); + void fill(uint16x4_t _v); + void fill(int32x4_t _v); + void fill(int32x4_t _v0, int32x4_t _v1); +#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC + void fill(float16x4_t _v); + void fill(float16x8_t _v); +#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +#endif // __ARM_NEON +#if __SSE2__ +#if __AVX__ +#if __AVX512F__ + void fill(__m512 _v); +#endif // __AVX512F__ + void fill(__m256 _v, int i = 0); +#endif // __AVX__ + void fill(__m128 _v); + void fill(__m128i _v); +#endif // __SSE2__ +#if __mips_msa + void fill(v4f32 _v); +#endif // __mips_msa +#if __loongarch_sx + void fill(__m128 _v); +#endif //__loongarch_sx +#if __riscv_vector + void fill(vfloat32m1_t _v); + void fill(vuint16m1_t _v); + void fill(vint8m1_t _v); +#if __riscv_zfh + void fill(vfloat16m1_t _v); +#endif // __riscv_zfh +#endif // __riscv_vector + template + void fill(T v); + // deep copy + Mat clone(Allocator* allocator = 0) const; + // deep copy from other mat, inplace + void clone_from(const ncnn::Mat& mat, Allocator* allocator = 0); + // reshape vec + Mat reshape(int w, Allocator* allocator = 0) const; + // reshape image + Mat reshape(int w, int h, Allocator* allocator = 0) const; + // reshape dim + Mat reshape(int w, int h, int c, Allocator* allocator = 0) const; + // reshape cube + Mat reshape(int w, int h, int d, int c, Allocator* allocator = 0) const; + // allocate vec + void create(int w, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate image + void create(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate dim + void create(int w, int h, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate like + void create_like(const Mat& m, Allocator* allocator = 0); +#if NCNN_VULKAN + // allocate like + void create_like(const VkMat& m, Allocator* allocator = 0); + // allocate like + void create_like(const VkImageMat& im, Allocator* allocator = 0); +#endif // NCNN_VULKAN + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // data reference + Mat channel(int c); + const Mat channel(int c) const; + Mat depth(int z); + const Mat depth(int z) const; + float* row(int y); + const float* row(int y) const; + template + T* row(int y); + template + const T* row(int y) const; + + // range reference + Mat channel_range(int c, int channels); + const Mat channel_range(int c, int channels) const; + Mat depth_range(int z, int depths); + const Mat depth_range(int z, int depths) const; + Mat row_range(int y, int rows); + const Mat row_range(int y, int rows) const; + Mat range(int x, int n); + const Mat range(int x, int n) const; + + // access raw data + template + operator T*(); + template + operator const T*() const; + + // convenient access float vec element + float& operator[](size_t i); + const float& operator[](size_t i) const; + +#if NCNN_PIXEL + enum PixelType + { + PIXEL_CONVERT_SHIFT = 16, + PIXEL_FORMAT_MASK = 0x0000ffff, + PIXEL_CONVERT_MASK = 0xffff0000, + + PIXEL_RGB = 1, + PIXEL_BGR = 2, + PIXEL_GRAY = 3, + PIXEL_RGBA = 4, + PIXEL_BGRA = 5, + + PIXEL_RGB2BGR = PIXEL_RGB | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2GRAY = PIXEL_RGB | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2RGBA = PIXEL_RGB | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2BGRA = PIXEL_RGB | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_BGR2RGB = PIXEL_BGR | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2GRAY = PIXEL_BGR | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2RGBA = PIXEL_BGR | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2BGRA = PIXEL_BGR | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_GRAY2RGB = PIXEL_GRAY | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2BGR = PIXEL_GRAY | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2RGBA = PIXEL_GRAY | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2BGRA = PIXEL_GRAY | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_RGBA2RGB = PIXEL_RGBA | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2BGR = PIXEL_RGBA | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2GRAY = PIXEL_RGBA | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2BGRA = PIXEL_RGBA | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_BGRA2RGB = PIXEL_BGRA | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2BGR = PIXEL_BGRA | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2GRAY = PIXEL_BGRA | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2RGBA = PIXEL_BGRA | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + }; + // convenient construct from pixel data + static Mat from_pixels(const unsigned char* pixels, int type, int w, int h, Allocator* allocator = 0); + // convenient construct from pixel data with stride(bytes-per-row) parameter + static Mat from_pixels(const unsigned char* pixels, int type, int w, int h, int stride, Allocator* allocator = 0); + // convenient construct from pixel data and resize to specific size + static Mat from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data and resize to specific size with stride(bytes-per-row) parameter + static Mat from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data roi + static Mat from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from pixel data roi with stride(bytes-per-row) parameter + static Mat from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from pixel data roi and resize to specific size + static Mat from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data roi and resize to specific size with stride(bytes-per-row) parameter + static Mat from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + + // convenient export to pixel data + void to_pixels(unsigned char* pixels, int type) const; + // convenient export to pixel data with stride(bytes-per-row) parameter + void to_pixels(unsigned char* pixels, int type, int stride) const; + // convenient export to pixel data and resize to specific size + void to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height) const; + // convenient export to pixel data and resize to specific size with stride(bytes-per-row) parameter + void to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height, int target_stride) const; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 + // convenient construct from android Bitmap + static Mat from_android_bitmap(JNIEnv* env, jobject bitmap, int type_to, Allocator* allocator = 0); + // convenient construct from android Bitmap and resize to specific size + static Mat from_android_bitmap_resize(JNIEnv* env, jobject bitmap, int type_to, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from android Bitmap roi + static Mat from_android_bitmap_roi(JNIEnv* env, jobject bitmap, int type_to, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from android Bitmap roi and resize to specific size + static Mat from_android_bitmap_roi_resize(JNIEnv* env, jobject bitmap, int type_to, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + // convenient export to android Bitmap and resize to the android Bitmap size + void to_android_bitmap(JNIEnv* env, jobject bitmap, int type_from) const; +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API +#endif // NCNN_PIXEL + + // substract channel-wise mean values, then multiply by normalize values, pass 0 to skip + void substract_mean_normalize(const float* mean_vals, const float* norm_vals); + + // convenient construct from half precision floating point data + static Mat from_float16(const unsigned short* data, int size); + + // pointer to the data + void* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + Allocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; + + size_t cstep; +}; + +#if NCNN_VULKAN + +// the three dimension matrix, vulkan version +class NCNN_EXPORT VkMat +{ +public: + // empty + VkMat(); + // vec + VkMat(int w, size_t elemsize, VkAllocator* allocator); + // image + VkMat(int w, int h, size_t elemsize, VkAllocator* allocator); + // dim + VkMat(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // cube + VkMat(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // packed vec + VkMat(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // packed image + VkMat(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // packed dim + VkMat(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // packed cube + VkMat(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // copy + VkMat(const VkMat& m); + // external vec + VkMat(int w, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external image + VkMat(int w, int h, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external dim + VkMat(int w, int h, int c, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external cube + VkMat(int w, int h, int d, int c, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external packed vec + VkMat(int w, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed image + VkMat(int w, int h, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed dim + VkMat(int w, int h, int c, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed cube + VkMat(int w, int h, int d, int c, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // release + ~VkMat(); + // assign + VkMat& operator=(const VkMat& m); + // allocate vec + void create(int w, size_t elemsize, VkAllocator* allocator); + // allocate image + void create(int w, int h, size_t elemsize, VkAllocator* allocator); + // allocate dim + void create(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate like + void create_like(const Mat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkMat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkImageMat& im, VkAllocator* allocator); + + // mapped + Mat mapped() const; + void* mapped_ptr() const; + + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // low-level reference + VkBuffer buffer() const; + size_t buffer_offset() const; + size_t buffer_capacity() const; + + // device buffer + VkBufferMemory* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + VkAllocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; + + size_t cstep; +}; + +class NCNN_EXPORT VkImageMat +{ +public: + // empty + VkImageMat(); + // vec + VkImageMat(int w, size_t elemsize, VkAllocator* allocator); + // image + VkImageMat(int w, int h, size_t elemsize, VkAllocator* allocator); + // dim + VkImageMat(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // cube + VkImageMat(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // packed vec + VkImageMat(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // packed image + VkImageMat(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // packed dim + VkImageMat(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // packed cube + VkImageMat(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // copy + VkImageMat(const VkImageMat& m); + // external vec + VkImageMat(int w, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external image + VkImageMat(int w, int h, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external dim + VkImageMat(int w, int h, int c, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external cube + VkImageMat(int w, int h, int d, int c, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external packed vec + VkImageMat(int w, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed image + VkImageMat(int w, int h, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed dim + VkImageMat(int w, int h, int c, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed cube + VkImageMat(int w, int h, int d, int c, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // release + ~VkImageMat(); + // assign + VkImageMat& operator=(const VkImageMat& m); + // allocate vec + void create(int w, size_t elemsize, VkAllocator* allocator); + // allocate image + void create(int w, int h, size_t elemsize, VkAllocator* allocator); + // allocate dim + void create(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate like + void create_like(const Mat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkMat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkImageMat& im, VkAllocator* allocator); + + // mapped + Mat mapped() const; + void* mapped_ptr() const; + + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // low-level reference + VkImage image() const; + VkImageView imageview() const; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 + // convenient construct from android hardware buffer + static VkImageMat from_android_hardware_buffer(VkAndroidHardwareBufferImageAllocator* allocator); +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + + // device image + VkImageMemory* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + VkAllocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; +}; + +// type for vulkan specialization constant and push constant +union vk_specialization_type +{ + int i; + float f; + uint32_t u32; +}; +union vk_constant_type +{ + int i; + float f; +}; +#endif // NCNN_VULKAN + +// misc function +#if NCNN_PIXEL +// convert yuv420sp(nv21) to rgb, the fast approximate version +NCNN_EXPORT void yuv420sp2rgb(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// convert yuv420sp(nv12) to rgb, the fast approximate version +NCNN_EXPORT void yuv420sp2rgb_nv12(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// convert yuv420sp(nv21) to rgb with half resize, the faster approximate version +NCNN_EXPORT void yuv420sp2rgb_half(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// image pixel bilinear resize +NCNN_EXPORT void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +// image pixel bilinear resize with stride(bytes-per-row) parameter +NCNN_EXPORT void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +// image pixel bilinear resize, convenient wrapper for yuv420sp(nv21/nv12) +NCNN_EXPORT void resize_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +#endif // NCNN_PIXEL +#if NCNN_PIXEL_ROTATE +// type is the from type, 6 means rotating from 6 to 1 +// +// 1 2 3 4 5 6 7 8 +// +// 888888 888888 88 88 8888888888 88 88 8888888888 +// 88 88 88 88 88 88 88 88 88 88 88 88 +// 8888 8888 8888 8888 88 8888888888 8888888888 88 +// 88 88 88 88 +// 88 88 888888 888888 +// +// ref http://sylvana.net/jpegcrop/exif_orientation.html +// image pixel kanna rotate +NCNN_EXPORT void kanna_rotate_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +// image pixel kanna rotate with stride(bytes-per-row) parameter +NCNN_EXPORT void kanna_rotate_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +// image pixel kanna rotate, convenient wrapper for yuv420sp(nv21/nv12) +NCNN_EXPORT void kanna_rotate_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +#endif // NCNN_PIXEL_ROTATE +#if NCNN_PIXEL_AFFINE +// resolve affine transform matrix from rotation angle, scale factor and x y offset +NCNN_EXPORT void get_rotation_matrix(float angle, float scale, float dx, float dy, float* tm); +// resolve affine transform matrix from two set of points, num_point must be >= 2 +NCNN_EXPORT void get_affine_transform(const float* points_from, const float* points_to, int num_point, float* tm); +// resolve the inversion affine transform matrix +NCNN_EXPORT void invert_affine_transform(const float* tm, float* tm_inv); +// image pixel bilinear warpaffine inverse transform, set -233 for transparent border color, the color RGBA is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +// image pixel bilinear warpaffine inverse transform with stride(bytes-per-row) parameter, set -233 for transparent border color, the color RGBA is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +// image pixel bilinear warpaffine, convenient wrapper for yuv420sp(nv21/nv12), set -233 for transparent border color, the color YUV_ is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +#endif // NCNN_PIXEL_AFFINE +#if NCNN_PIXEL_DRAWING +// draw rectangle, set thickness -1 for filled rectangle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_rectangle_c1(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c2(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c3(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c4(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw rectangle with stride(bytes-per-row) parameter, set thickness -1 for filled rectangle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_rectangle_c1(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c2(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c3(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c4(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw rectangle, convenient wrapper for yuv420sp(nv21/nv12), set thickness -1 for filled rectangle, the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_rectangle_yuv420sp(unsigned char* yuv420sp, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw circle, set thickness -1 for filled circle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_circle_c1(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c2(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c3(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c4(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +// draw circle with stride(bytes-per-row) parameter, set thickness -1 for filled circle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_circle_c1(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c2(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c3(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c4(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +// draw circle, convenient wrapper for yuv420sp(nv21/nv12), set thickness -1 for filled circle, the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_circle_yuv420sp(unsigned char* yuv420sp, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +// draw line, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_line_c1(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c2(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c3(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c4(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// draw line with stride(bytes-per-row) parameter, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_line_c1(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c2(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c3(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c4(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// draw line, convenient wrapper for yuv420sp(nv21/nv12), the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_line_yuv420sp(unsigned char* yuv420sp, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// resolve text bounding box size +NCNN_EXPORT void get_text_drawing_size(const char* text, int fontpixelsize, int* w, int* h); +// draw ascii printables and newline, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_text_c1(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c2(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c3(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c4(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +// draw ascii printables and newline with stride(bytes-per-row) parameter, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_text_c1(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c2(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c3(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c4(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +// draw ascii printables and newline, convenient wrapper for yuv420sp(nv21/nv12), the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_text_yuv420sp(unsigned char* yuv420sp, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +#endif // NCNN_PIXEL_DRAWING + +// type conversion +// convert float to half precision floating point +NCNN_EXPORT unsigned short float32_to_float16(float value); +// convert half precision floating point to float +NCNN_EXPORT float float16_to_float32(unsigned short value); +// convert float to brain half +NCNN_EXPORT NCNN_FORCEINLINE unsigned short float32_to_bfloat16(float value) +{ + // 16 : 16 + union + { + unsigned int u; + float f; + } tmp; + tmp.f = value; + return tmp.u >> 16; +} +// convert brain half to float +NCNN_EXPORT NCNN_FORCEINLINE float bfloat16_to_float32(unsigned short value) +{ + // 16 : 16 + union + { + unsigned int u; + float f; + } tmp; + tmp.u = value << 16; + return tmp.f; +} + +// mat process +enum BorderType +{ + BORDER_CONSTANT = 0, + BORDER_REPLICATE = 1, + BORDER_REFLECT = 2, + BORDER_TRANSPARENT = -233, +}; +NCNN_EXPORT void copy_make_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int type, float v, const Option& opt = Option()); +NCNN_EXPORT void copy_make_border_3d(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int front, int behind, int type, float v, const Option& opt = Option()); +NCNN_EXPORT void copy_cut_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, const Option& opt = Option()); +NCNN_EXPORT void copy_cut_border_3d(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int front, int behind, const Option& opt = Option()); +NCNN_EXPORT void resize_nearest(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void resize_bilinear(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void resize_bicubic(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void convert_packing(const Mat& src, Mat& dst, int elempack, const Option& opt = Option()); +NCNN_EXPORT void flatten(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float32_to_float16(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float16_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_int8_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float32_to_bfloat16(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_bfloat16_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void quantize_to_int8(const Mat& src, Mat& dst, const Mat& scale_data, const Option& opt = Option()); +NCNN_EXPORT void dequantize_from_int32(const Mat& src, Mat& dst, const Mat& scale_data, const Mat& bias_data, const Option& opt = Option()); +NCNN_EXPORT void requantize_from_int32_to_int8(const Mat& src, Mat& dst, const Mat& scale_in_data, const Mat& scale_out_data, const Mat& bias_data, int activation_type, const Mat& activation_params, const Option& opt = Option()); + +NCNN_FORCEINLINE Mat::Mat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ +} + +NCNN_FORCEINLINE Mat::Mat(int _w, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(const Mat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c), cstep(m.cstep) +{ + addref(); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = (size_t)w * h; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = (size_t)w * h; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::~Mat() +{ + release(); +} + +NCNN_FORCEINLINE void Mat::fill(float _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + + int i = 0; +#if __ARM_NEON + float32x4_t _c = vdupq_n_f32(_v); + for (; i + 3 < size; i += 4) + { + vst1q_f32(ptr, _c); + ptr += 4; + } +#endif // __ARM_NEON + for (; i < size; i++) + { + *ptr++ = _v; + } +} + +NCNN_FORCEINLINE void Mat::fill(int _v) +{ + int size = (int)total(); + int* ptr = (int*)data; + + int i = 0; +#if __ARM_NEON + int32x4_t _c = vdupq_n_s32(_v); + for (; i + 3 < size; i += 4) + { + vst1q_s32(ptr, _c); + ptr += 4; + } +#endif // __ARM_NEON + for (; i < size; i++) + { + *ptr++ = _v; + } +} + +#if __ARM_NEON +NCNN_FORCEINLINE void Mat::fill(float32x4_t _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + vst1q_f32(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(uint16x4_t _v) +{ + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + vst1_u16(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(int32x4_t _v) +{ + int size = (int)total(); + int* ptr = (int*)data; + for (int i = 0; i < size; i++) + { + vst1q_s32(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(int32x4_t _v0, int32x4_t _v1) +{ + int size = (int)total(); + int* ptr = (int*)data; + for (int i = 0; i < size; i++) + { + vst1q_s32(ptr, _v0); + vst1q_s32(ptr + 4, _v1); + ptr += 8; + } +} +#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +NCNN_FORCEINLINE void Mat::fill(float16x4_t _v) +{ + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vst1_f16(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(float16x8_t _v) +{ + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vst1q_f16(ptr, _v); + ptr += 8; + } +} +#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +#endif // __ARM_NEON + +#if __SSE2__ +#if __AVX__ +#if __AVX512F__ +NCNN_FORCEINLINE void Mat::fill(__m512 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm512_storeu_ps(ptr, _v); + ptr += 16; + } +} +#endif // __AVX512F__ +NCNN_FORCEINLINE void Mat::fill(__m256 _v, int _i) +{ + // old gcc cannot overload __m128 and __m256 type + // add a dummy int parameter for different mangled function symbol + (void)_i; + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm256_storeu_ps(ptr, _v); + ptr += 8; + } +} +#endif // __AVX__ +NCNN_FORCEINLINE void Mat::fill(__m128 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm_storeu_ps(ptr, _v); + ptr += 4; + } +} +NCNN_FORCEINLINE void Mat::fill(__m128i _v) +{ + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + _mm_store_si128((__m128i*)ptr, _v); + ptr += 8; + } +} +#endif // __SSE2__ + +#if __mips_msa +NCNN_FORCEINLINE void Mat::fill(v4f32 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + __msa_st_w((v4i32)_v, ptr, 0); + ptr += 4; + } +} +#endif // __mips_msa + +#if __loongarch_sx +NCNN_FORCEINLINE void Mat::fill(__m128 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + __lsx_vst(_v, ptr, 0); + ptr += 4; + } +} +#endif // __loongarch_sx +#if __riscv_vector +NCNN_FORCEINLINE void Mat::fill(vfloat32m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 4; + const size_t vl = vsetvl_e32m1(packn); + + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + vse32_v_f32m1(ptr, _v, vl); + ptr += packn; + } +} + +NCNN_FORCEINLINE void Mat::fill(vuint16m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 2; + const size_t vl = vsetvl_e16m1(packn); + + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + vse16_v_u16m1(ptr, _v, vl); + ptr += packn; + } +} + +NCNN_FORCEINLINE void Mat::fill(vint8m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 1; + const size_t vl = vsetvl_e8m1(packn); + + int size = (int)total(); + signed char* ptr = (signed char*)data; + for (int i = 0; i < size; i++) + { + vse8_v_i8m1(ptr, _v, vl); + ptr += packn; + } +} +#if __riscv_zfh +NCNN_FORCEINLINE void Mat::fill(vfloat16m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 2; + const size_t vl = vsetvl_e16m1(packn); + + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vse16_v_f16m1(ptr, _v, vl); + ptr += packn; + } +} +#endif // __riscv_zfh +#endif // __riscv_vector + +template +NCNN_FORCEINLINE void Mat::fill(T _v) +{ + int size = (int)total(); + T* ptr = (T*)data; + for (int i = 0; i < size; i++) + { + ptr[i] = _v; + } +} + +NCNN_FORCEINLINE Mat& Mat::operator=(const Mat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + cstep = m.cstep; + + return *this; +} + +NCNN_FORCEINLINE void Mat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void Mat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator) + allocator->fastFree(data); + else + fastFree(data); + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + cstep = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool Mat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t Mat::total() const +{ + return cstep * c; +} + +NCNN_FORCEINLINE int Mat::elembits() const +{ + return elempack ? static_cast(elemsize * 8) / elempack : 0; +} + +NCNN_FORCEINLINE Mat Mat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE Mat Mat::channel(int _c) +{ + Mat m(w, h, d, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims - 1; + if (dims == 4) + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::channel(int _c) const +{ + Mat m(w, h, d, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims - 1; + if (dims == 4) + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE Mat Mat::depth(int z) +{ + return Mat(w, h, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::depth(int z) const +{ + return Mat(w, h, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE float* Mat::row(int y) +{ + return (float*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +NCNN_FORCEINLINE const float* Mat::row(int y) const +{ + return (const float*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +template +NCNN_FORCEINLINE T* Mat::row(int y) +{ + return (T*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +template +NCNN_FORCEINLINE const T* Mat::row(int y) const +{ + return (const T*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +NCNN_FORCEINLINE Mat Mat::channel_range(int _c, int channels) +{ + Mat m(w, h, d, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::channel_range(int _c, int channels) const +{ + Mat m(w, h, d, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims; + return m; +} + +NCNN_FORCEINLINE Mat Mat::depth_range(int z, int depths) +{ + Mat m(w, h, depths, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::depth_range(int z, int depths) const +{ + Mat m(w, h, depths, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE Mat Mat::row_range(int y, int rows) +{ + return Mat(w, rows, (unsigned char*)data + (size_t)w * y * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::row_range(int y, int rows) const +{ + return Mat(w, rows, (unsigned char*)data + (size_t)w * y * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE Mat Mat::range(int x, int n) +{ + return Mat(n, (unsigned char*)data + x * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::range(int x, int n) const +{ + return Mat(n, (unsigned char*)data + x * elemsize, elemsize, elempack, allocator); +} + +template +NCNN_FORCEINLINE Mat::operator T*() +{ + return (T*)data; +} + +template +NCNN_FORCEINLINE Mat::operator const T*() const +{ + return (const T*)data; +} + +NCNN_FORCEINLINE float& Mat::operator[](size_t i) +{ + return ((float*)data)[i]; +} + +NCNN_FORCEINLINE const float& Mat::operator[](size_t i) const +{ + return ((const float*)data)[i]; +} + +#if NCNN_VULKAN + +NCNN_FORCEINLINE VkMat::VkMat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(const VkMat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c) +{ + addref(); + + cstep = m.cstep; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = w * h; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize(w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = w * h; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize(w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::~VkMat() +{ + release(); +} + +NCNN_FORCEINLINE VkMat& VkMat::operator=(const VkMat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + cstep = m.cstep; + + return *this; +} + +NCNN_FORCEINLINE Mat VkMat::mapped() const +{ + if (!allocator->mappable) + return Mat(); + + if (dims == 1) + return Mat(w, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 2) + return Mat(w, h, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 3) + return Mat(w, h, c, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 4) + return Mat(w, h, d, c, mapped_ptr(), elemsize, elempack, 0); + + return Mat(); +} + +NCNN_FORCEINLINE void* VkMat::mapped_ptr() const +{ + if (!allocator->mappable) + return 0; + + return (unsigned char*)data->mapped_ptr + data->offset; +} + +NCNN_FORCEINLINE void VkMat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void VkMat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator && data) + { + allocator->fastFree(data); + } + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + cstep = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool VkMat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t VkMat::total() const +{ + return cstep * c; +} + +NCNN_FORCEINLINE int VkMat::elembits() const +{ + return elempack ? static_cast(elemsize) * 8 / elempack : 0; +} + +NCNN_FORCEINLINE Mat VkMat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE VkBuffer VkMat::buffer() const +{ + return data->buffer; +} + +NCNN_FORCEINLINE size_t VkMat::buffer_offset() const +{ + return data->offset; +} + +NCNN_FORCEINLINE size_t VkMat::buffer_capacity() const +{ + return data->capacity; +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(const VkImageMat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c) +{ + addref(); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::~VkImageMat() +{ + release(); +} + +NCNN_FORCEINLINE VkImageMat& VkImageMat::operator=(const VkImageMat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + return *this; +} + +NCNN_FORCEINLINE Mat VkImageMat::mapped() const +{ + if (!allocator->mappable || !data->mapped_ptr) + return Mat(); + + if (dims == 1) + return Mat(w, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 2) + return Mat(w, h, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 3) + return Mat(w, h, c, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 4) + return Mat(w, h, d, c, mapped_ptr(), elemsize, elempack, 0); + + return Mat(); +} + +NCNN_FORCEINLINE void* VkImageMat::mapped_ptr() const +{ + if (!allocator->mappable || !data->mapped_ptr) + return 0; + + return (unsigned char*)data->mapped_ptr + data->bind_offset; +} + +NCNN_FORCEINLINE void VkImageMat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void VkImageMat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator && data) + { + allocator->fastFree(data); + } + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool VkImageMat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t VkImageMat::total() const +{ + return w * h * d * c; +} + +NCNN_FORCEINLINE int VkImageMat::elembits() const +{ + return elempack ? static_cast(elemsize) * 8 / elempack : 0; +} + +NCNN_FORCEINLINE Mat VkImageMat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE VkImage VkImageMat::image() const +{ + return data->image; +} + +NCNN_FORCEINLINE VkImageView VkImageMat::imageview() const +{ + return data->imageview; +} + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_MAT_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/modelbin.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/modelbin.h new file mode 100644 index 0000000..aada5f6 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/modelbin.h @@ -0,0 +1,80 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_MODELBIN_H +#define NCNN_MODELBIN_H + +#include "mat.h" + +namespace ncnn { + +class DataReader; +class NCNN_EXPORT ModelBin +{ +public: + ModelBin(); + virtual ~ModelBin(); + // element type + // 0 = auto + // 1 = float32 + // 2 = float16 + // 3 = int8 + // load vec + virtual Mat load(int w, int type) const; + // load image + virtual Mat load(int w, int h, int type) const; + // load dim + virtual Mat load(int w, int h, int c, int type) const; + // load cube + virtual Mat load(int w, int h, int d, int c, int type) const; +}; + +class ModelBinFromDataReaderPrivate; +class NCNN_EXPORT ModelBinFromDataReader : public ModelBin +{ +public: + explicit ModelBinFromDataReader(const DataReader& dr); + virtual ~ModelBinFromDataReader(); + + virtual Mat load(int w, int type) const; + +private: + ModelBinFromDataReader(const ModelBinFromDataReader&); + ModelBinFromDataReader& operator=(const ModelBinFromDataReader&); + +private: + ModelBinFromDataReaderPrivate* const d; +}; + +class ModelBinFromMatArrayPrivate; +class NCNN_EXPORT ModelBinFromMatArray : public ModelBin +{ +public: + // construct from weight blob array + explicit ModelBinFromMatArray(const Mat* weights); + virtual ~ModelBinFromMatArray(); + + virtual Mat load(int w, int type) const; + +private: + ModelBinFromMatArray(const ModelBinFromMatArray&); + ModelBinFromMatArray& operator=(const ModelBinFromMatArray&); + +private: + ModelBinFromMatArrayPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_MODELBIN_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/ncnn_export.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/ncnn_export.h new file mode 100644 index 0000000..e2f5fde --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/ncnn_export.h @@ -0,0 +1,42 @@ + +#ifndef NCNN_EXPORT_H +#define NCNN_EXPORT_H + +#ifdef NCNN_STATIC_DEFINE +# define NCNN_EXPORT +# define NCNN_NO_EXPORT +#else +# ifndef NCNN_EXPORT +# ifdef ncnn_EXPORTS + /* We are building this library */ +# define NCNN_EXPORT __attribute__((visibility("default"))) +# else + /* We are using this library */ +# define NCNN_EXPORT __attribute__((visibility("default"))) +# endif +# endif + +# ifndef NCNN_NO_EXPORT +# define NCNN_NO_EXPORT __attribute__((visibility("hidden"))) +# endif +#endif + +#ifndef NCNN_DEPRECATED +# define NCNN_DEPRECATED __attribute__ ((__deprecated__)) +#endif + +#ifndef NCNN_DEPRECATED_EXPORT +# define NCNN_DEPRECATED_EXPORT NCNN_EXPORT NCNN_DEPRECATED +#endif + +#ifndef NCNN_DEPRECATED_NO_EXPORT +# define NCNN_DEPRECATED_NO_EXPORT NCNN_NO_EXPORT NCNN_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef NCNN_NO_DEPRECATED +# define NCNN_NO_DEPRECATED +# endif +#endif + +#endif /* NCNN_EXPORT_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/net.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/net.h new file mode 100644 index 0000000..98e3ec3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/net.h @@ -0,0 +1,274 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_NET_H +#define NCNN_NET_H + +#include "blob.h" +#include "layer.h" +#include "mat.h" +#include "option.h" +#include "platform.h" + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +#if NCNN_VULKAN +class VkCompute; +#endif // NCNN_VULKAN +class DataReader; +class Extractor; +class NetPrivate; +class NCNN_EXPORT Net +{ +public: + // empty init + Net(); + // clear and destroy + virtual ~Net(); + +public: + // option can be changed before loading + Option opt; + +#if NCNN_VULKAN + // set gpu device by index + void set_vulkan_device(int device_index); + + // set gpu device by device handle, no owner transfer + void set_vulkan_device(const VulkanDevice* vkdev); + + const VulkanDevice* vulkan_device() const; +#endif // NCNN_VULKAN + +#if NCNN_STRING + // register custom layer or overwrite built-in layer by layer type name + // return 0 if success + int register_custom_layer(const char* type, layer_creator_func creator, layer_destroyer_func destroyer = 0, void* userdata = 0); + virtual int custom_layer_to_index(const char* type); +#endif // NCNN_STRING + // register custom layer or overwrite built-in layer by layer type + // return 0 if success + int register_custom_layer(int index, layer_creator_func creator, layer_destroyer_func destroyer = 0, void* userdata = 0); + +#if NCNN_STRING + int load_param(const DataReader& dr); +#endif // NCNN_STRING + + int load_param_bin(const DataReader& dr); + + int load_model(const DataReader& dr); + +#if NCNN_STDIO +#if NCNN_STRING + // load network structure from plain param file + // return 0 if success + int load_param(FILE* fp); + int load_param(const char* protopath); + int load_param_mem(const char* mem); +#endif // NCNN_STRING + // load network structure from binary param file + // return 0 if success + int load_param_bin(FILE* fp); + int load_param_bin(const char* protopath); + + // load network weight data from model file + // return 0 if success + int load_model(FILE* fp); + int load_model(const char* modelpath); +#endif // NCNN_STDIO + + // load network structure from external memory + // memory pointer must be 32-bit aligned + // return bytes consumed + int load_param(const unsigned char* mem); + + // reference network weight data from external memory + // weight data is not copied but referenced + // so external memory should be retained when used + // memory pointer must be 32-bit aligned + // return bytes consumed + int load_model(const unsigned char* mem); + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#if NCNN_STRING + // convenient load network structure from android asset plain param file + int load_param(AAsset* asset); + int load_param(AAssetManager* mgr, const char* assetpath); +#endif // NCNN_STRING + // convenient load network structure from android asset binary param file + int load_param_bin(AAsset* asset); + int load_param_bin(AAssetManager* mgr, const char* assetpath); + + // convenient load network weight data from android asset model file + int load_model(AAsset* asset); + int load_model(AAssetManager* mgr, const char* assetpath); +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + + // unload network structure and weight data + void clear(); + + // construct an Extractor from network + Extractor create_extractor() const; + + // get input/output indexes/names + const std::vector& input_indexes() const; + const std::vector& output_indexes() const; +#if NCNN_STRING + const std::vector& input_names() const; + const std::vector& output_names() const; +#endif + + const std::vector& blobs() const; + const std::vector& layers() const; + + std::vector& mutable_blobs(); + std::vector& mutable_layers(); + +protected: + friend class Extractor; +#if NCNN_STRING + int find_blob_index_by_name(const char* name) const; + int find_layer_index_by_name(const char* name) const; + virtual Layer* create_custom_layer(const char* type); + virtual Layer* create_overwrite_builtin_layer(const char* type); +#endif // NCNN_STRING + virtual Layer* create_custom_layer(int index); + virtual Layer* create_overwrite_builtin_layer(int typeindex); + +private: + Net(const Net&); + Net& operator=(const Net&); + +private: + NetPrivate* const d; +}; + +class ExtractorPrivate; +class NCNN_EXPORT Extractor +{ +public: + virtual ~Extractor(); + + // copy + Extractor(const Extractor&); + + // assign + Extractor& operator=(const Extractor&); + + // clear blob mats and alloctors + void clear(); + + // enable light mode + // intermediate blob will be recycled when enabled + // enabled by default + void set_light_mode(bool enable); + + // set thread count for this extractor + // this will overwrite the global setting + // default count is system depended + void set_num_threads(int num_threads); + + // set blob memory allocator + void set_blob_allocator(Allocator* allocator); + + // set workspace memory allocator + void set_workspace_allocator(Allocator* allocator); + +#if NCNN_VULKAN + void set_vulkan_compute(bool enable); + + void set_blob_vkallocator(VkAllocator* allocator); + + void set_workspace_vkallocator(VkAllocator* allocator); + + void set_staging_vkallocator(VkAllocator* allocator); +#endif // NCNN_VULKAN + +#if NCNN_STRING + // set input by blob name + // return 0 if success + int input(const char* blob_name, const Mat& in); + + // get result by blob name + // return 0 if success + // type = 0, default + // type = 1, do not convert fp16/bf16 or / and packing + int extract(const char* blob_name, Mat& feat, int type = 0); +#endif // NCNN_STRING + + // set input by blob index + // return 0 if success + int input(int blob_index, const Mat& in); + + // get result by blob index + // return 0 if success + // type = 0, default + // type = 1, do not convert fp16/bf16 or / and packing + int extract(int blob_index, Mat& feat, int type = 0); + +#if NCNN_VULKAN +#if NCNN_STRING + // set input by blob name + // return 0 if success + int input(const char* blob_name, const VkMat& in); + + // get result by blob name + // return 0 if success + int extract(const char* blob_name, VkMat& feat, VkCompute& cmd); + + // set input by blob name + // return 0 if success + int input(const char* blob_name, const VkImageMat& in); + + // get result by blob name + // return 0 if success + int extract(const char* blob_name, VkImageMat& feat, VkCompute& cmd); +#endif // NCNN_STRING + + // set input by blob index + // return 0 if success + int input(int blob_index, const VkMat& in); + + // get result by blob index + // return 0 if success + int extract(int blob_index, VkMat& feat, VkCompute& cmd); + + // set input by blob index + // return 0 if success + int input(int blob_index, const VkImageMat& in); + + // get result by blob index + // return 0 if success + int extract(int blob_index, VkImageMat& feat, VkCompute& cmd); +#endif // NCNN_VULKAN + +protected: + friend Extractor Net::create_extractor() const; + Extractor(const Net* net, size_t blob_count); + +private: + ExtractorPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_NET_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/option.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/option.h new file mode 100644 index 0000000..7d0cc60 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/option.h @@ -0,0 +1,156 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_OPTION_H +#define NCNN_OPTION_H + +#include "platform.h" + +namespace ncnn { + +#if NCNN_VULKAN +class VkAllocator; +class PipelineCache; +#endif // NCNN_VULKAN + +class Allocator; +class NCNN_EXPORT Option +{ +public: + // default option + Option(); + +public: + // light mode + // intermediate blob will be recycled when enabled + // enabled by default + bool lightmode; + + // thread count + // default value is the one returned by get_cpu_count() + int num_threads; + + // blob memory allocator + Allocator* blob_allocator; + + // workspace memory allocator + Allocator* workspace_allocator; + +#if NCNN_VULKAN + // blob memory allocator + VkAllocator* blob_vkallocator; + + // workspace memory allocator + VkAllocator* workspace_vkallocator; + + // staging memory allocator + VkAllocator* staging_vkallocator; + + // pipeline cache + PipelineCache* pipeline_cache; +#endif // NCNN_VULKAN + + // the time openmp threads busy-wait for more work before going to sleep + // default value is 20ms to keep the cores enabled + // without too much extra power consumption afterwards + int openmp_blocktime; + + // enable winograd convolution optimization + // improve convolution 3x3 stride1 performance, may consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_winograd_convolution; + + // enable sgemm convolution optimization + // improve convolution 1x1 stride1 performance, may consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_sgemm_convolution; + + // enable quantized int8 inference + // use low-precision int8 path for quantized model + // changes should be applied before loading network structure and weight + // enabled by default + bool use_int8_inference; + + // enable vulkan compute + bool use_vulkan_compute; + + // enable bf16 data type for storage + // improve most operator performance on all arm devices, may consume more memory + bool use_bf16_storage; + + // enable options for gpu inference + bool use_fp16_packed; + bool use_fp16_storage; + bool use_fp16_arithmetic; + bool use_int8_packed; + bool use_int8_storage; + bool use_int8_arithmetic; + + // enable simd-friendly packed memory layout + // improve all operator performance on all arm devices, will consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_packing_layout; + + bool use_shader_pack8; + + // subgroup option + bool use_subgroup_basic; + bool use_subgroup_vote; + bool use_subgroup_ballot; + bool use_subgroup_shuffle; + + // turn on for adreno + bool use_image_storage; + bool use_tensor_storage; + + bool use_reserved_0; + + // enable DAZ(Denormals-Are-Zero) and FTZ(Flush-To-Zero) + // default value is 3 + // 0 = DAZ OFF, FTZ OFF + // 1 = DAZ ON , FTZ OFF + // 2 = DAZ OFF, FTZ ON + // 3 = DAZ ON, FTZ ON + int flush_denormals; + + bool use_local_pool_allocator; + + // enable local memory optimization for gpu inference + bool use_shader_local_memory; + + // enable cooperative matrix optimization for gpu inference + bool use_cooperative_matrix; + + // more fine-grained control of winograd convolution + bool use_winograd23_convolution; + bool use_winograd43_convolution; + bool use_winograd63_convolution; + + // this option is turned on for A53/A55 automatically + // but you can force this on/off if you wish + bool use_a53_a55_optimized_kernel; + + bool use_reserved_7; + bool use_reserved_8; + bool use_reserved_9; + bool use_reserved_10; + bool use_reserved_11; +}; + +} // namespace ncnn + +#endif // NCNN_OPTION_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/paramdict.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/paramdict.h new file mode 100644 index 0000000..c2ef160 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/paramdict.h @@ -0,0 +1,73 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PARAMDICT_H +#define NCNN_PARAMDICT_H + +#include "mat.h" + +// at most 32 parameters +#define NCNN_MAX_PARAM_COUNT 32 + +namespace ncnn { + +class DataReader; +class Net; +class ParamDictPrivate; +class NCNN_EXPORT ParamDict +{ +public: + // empty + ParamDict(); + + virtual ~ParamDict(); + + // copy + ParamDict(const ParamDict&); + + // assign + ParamDict& operator=(const ParamDict&); + + // get type + int type(int id) const; + + // get int + int get(int id, int def) const; + // get float + float get(int id, float def) const; + // get array + Mat get(int id, const Mat& def) const; + + // set int + void set(int id, int i); + // set float + void set(int id, float f); + // set array + void set(int id, const Mat& v); + +protected: + friend class Net; + + void clear(); + + int load_param(const DataReader& dr); + int load_param_bin(const DataReader& dr); + +private: + ParamDictPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_PARAMDICT_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/pipeline.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/pipeline.h new file mode 100644 index 0000000..c284a14 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/pipeline.h @@ -0,0 +1,113 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PIPELINE_H +#define NCNN_PIPELINE_H + +#include "mat.h" +#include "platform.h" +#if NCNN_VULKAN +#include "gpu.h" + +#include +#endif // NCNN_VULKAN + +namespace ncnn { + +#if NCNN_VULKAN +class Option; +class PipelinePrivate; +class NCNN_EXPORT Pipeline +{ +public: + explicit Pipeline(const VulkanDevice* vkdev); + virtual ~Pipeline(); + +public: + void set_optimal_local_size_xyz(int w = 4, int h = 4, int c = 4); + void set_optimal_local_size_xyz(const Mat& local_size_xyz); + void set_local_size_xyz(int w, int h, int c); + + int create(const uint32_t* spv_data, size_t spv_data_size, const std::vector& specializations); + + int create(int shader_type_index, const Option& opt, const std::vector& specializations); + +public: + VkShaderModule shader_module() const; + VkDescriptorSetLayout descriptorset_layout() const; + VkPipelineLayout pipeline_layout() const; + VkPipeline pipeline() const; + VkDescriptorUpdateTemplateKHR descriptor_update_template() const; + + const ShaderInfo& shader_info() const; + + uint32_t local_size_x() const; + uint32_t local_size_y() const; + uint32_t local_size_z() const; + +protected: + void set_shader_module(VkShaderModule shader_module); + void set_descriptorset_layout(VkDescriptorSetLayout descriptorset_layout); + void set_pipeline_layout(VkPipelineLayout pipeline_layout); + void set_pipeline(VkPipeline pipeline); + void set_descriptor_update_template(VkDescriptorUpdateTemplateKHR descriptor_update_template); + + void set_shader_info(const ShaderInfo& shader_info); + +public: + const VulkanDevice* vkdev; + +private: + Pipeline(const Pipeline&); + Pipeline& operator=(const Pipeline&); + +private: + PipelinePrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class VkCompute; +class NCNN_EXPORT ImportAndroidHardwareBufferPipeline : private Pipeline +{ +public: + explicit ImportAndroidHardwareBufferPipeline(const VulkanDevice* vkdev); + virtual ~ImportAndroidHardwareBufferPipeline(); + + int create(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator, int type_to, int rotate_from, const Option& opt); + int create(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator, int type_to, int rotate_from, int target_width, int target_height, const Option& opt); + void destroy(); + + friend class VkCompute; + +protected: + int create_shader_module(const Option& opt); + int create_sampler(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator); + int create_descriptorset_layout(); + +public: + int type_to; + int rotate_from; + bool need_resize; + + VkSampler sampler; +}; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_PIPELINE_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/pipelinecache.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/pipelinecache.h new file mode 100644 index 0000000..bb6b8fb --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/pipelinecache.h @@ -0,0 +1,85 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PIPELINECACHE_H +#define NCNN_PIPELINECACHE_H + +#include "platform.h" + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#include "mat.h" +#include "gpu.h" + +namespace ncnn { + +#if NCNN_VULKAN + +class VulkanDevice; +class PipelineCachePrivate; +class NCNN_EXPORT PipelineCache +{ +public: + explicit PipelineCache(const VulkanDevice* _vkdev); + + virtual ~PipelineCache(); + + void clear(); + + int get_pipeline(const uint32_t* spv_data, size_t spv_data_size, const std::vector& specializations, + uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* shader_module, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template, + ShaderInfo& shader_info) const; + + int get_pipeline(int shader_type_index, const Option& opt, const std::vector& specializations, + uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* shader_module, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template, + ShaderInfo& shader_info) const; + +protected: + int create_shader_module(int shader_type_index, const Option& opt, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* _shader_module, ShaderInfo& si) const; + + int new_pipeline(VkShaderModule shader_module, const ShaderInfo& shader_info, const std::vector& specializations, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template) const; + +protected: + const VulkanDevice* vkdev; + +private: + PipelineCache(const PipelineCache&); + PipelineCache& operator=(const PipelineCache&); + +private: + PipelineCachePrivate* const d; +}; + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_PIPELINECACHE_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/platform.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/platform.h new file mode 100644 index 0000000..8c46058 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/platform.h @@ -0,0 +1,293 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PLATFORM_H +#define NCNN_PLATFORM_H + +#define NCNN_STDIO 1 +#define NCNN_STRING 1 +#define NCNN_SIMPLEOCV 0 +#define NCNN_SIMPLEOMP 0 +#define NCNN_SIMPLESTL 0 +#define NCNN_SIMPLEMATH 0 +#define NCNN_THREADS 1 +#define NCNN_BENCHMARK 0 +#define NCNN_C_API 1 +#define NCNN_PLATFORM_API 1 +#define NCNN_PIXEL 1 +#define NCNN_PIXEL_ROTATE 1 +#define NCNN_PIXEL_AFFINE 1 +#define NCNN_PIXEL_DRAWING 1 +#define NCNN_VULKAN 0 +#define NCNN_SYSTEM_GLSLANG 0 +#define NCNN_RUNTIME_CPU 1 +#define NCNN_GNU_INLINE_ASM 1 +#define NCNN_AVX 0 +#define NCNN_XOP 0 +#define NCNN_FMA 0 +#define NCNN_F16C 0 +#define NCNN_AVX2 0 +#define NCNN_AVXVNNI 0 +#define NCNN_AVX512 0 +#define NCNN_AVX512VNNI 0 +#define NCNN_AVX512BF16 0 +#define NCNN_AVX512FP16 0 +#define NCNN_VFPV4 1 +#define NCNN_ARM82 1 +#define NCNN_ARM82DOT 1 +#define NCNN_ARM82FP16FML 1 +#define NCNN_ARM84BF16 1 +#define NCNN_ARM84I8MM 1 +#define NCNN_ARM86SVE 1 +#define NCNN_ARM86SVE2 1 +#define NCNN_ARM86SVEBF16 1 +#define NCNN_ARM86SVEI8MM 1 +#define NCNN_ARM86SVEF32MM 1 +#define NCNN_MSA 0 +#define NCNN_LSX 0 +#define NCNN_MMI 0 +#define NCNN_RVV 0 +#define NCNN_INT8 1 +#define NCNN_BF16 1 +#define NCNN_FORCE_INLINE 1 + +#define NCNN_VERSION_STRING "1.0.20231027" + +#include "ncnn_export.h" + +#ifdef __cplusplus + +#if NCNN_THREADS +#if (defined _WIN32 && !(defined __MINGW32__)) +#define WIN32_LEAN_AND_MEAN +#include +#include +#else +#include +#endif +#endif // NCNN_THREADS + +#if __ANDROID_API__ >= 26 +#define VK_USE_PLATFORM_ANDROID_KHR +#endif // __ANDROID_API__ >= 26 + +namespace ncnn { + +#if NCNN_THREADS +#if (defined _WIN32 && !(defined __MINGW32__)) +class NCNN_EXPORT Mutex +{ +public: + Mutex() { InitializeSRWLock(&srwlock); } + ~Mutex() {} + void lock() { AcquireSRWLockExclusive(&srwlock); } + void unlock() { ReleaseSRWLockExclusive(&srwlock); } +private: + friend class ConditionVariable; + // NOTE SRWLock is available from windows vista + SRWLOCK srwlock; +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() { InitializeConditionVariable(&condvar); } + ~ConditionVariable() {} + void wait(Mutex& mutex) { SleepConditionVariableSRW(&condvar, &mutex.srwlock, INFINITE, 0); } + void broadcast() { WakeAllConditionVariable(&condvar); } + void signal() { WakeConditionVariable(&condvar); } +private: + CONDITION_VARIABLE condvar; +}; + +static unsigned __stdcall start_wrapper(void* args); +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*start)(void*), void* args = 0) { _start = start; _args = args; handle = (HANDLE)_beginthreadex(0, 0, start_wrapper, this, 0, 0); } + ~Thread() {} + void join() { WaitForSingleObject(handle, INFINITE); CloseHandle(handle); } +private: + friend unsigned __stdcall start_wrapper(void* args) + { + Thread* t = (Thread*)args; + t->_start(t->_args); + return 0; + } + HANDLE handle; + void* (*_start)(void*); + void* _args; +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { key = TlsAlloc(); } + ~ThreadLocalStorage() { TlsFree(key); } + void set(void* value) { TlsSetValue(key, (LPVOID)value); } + void* get() { return (void*)TlsGetValue(key); } +private: + DWORD key; +}; +#else // (defined _WIN32 && !(defined __MINGW32__)) +class NCNN_EXPORT Mutex +{ +public: + Mutex() { pthread_mutex_init(&mutex, 0); } + ~Mutex() { pthread_mutex_destroy(&mutex); } + void lock() { pthread_mutex_lock(&mutex); } + void unlock() { pthread_mutex_unlock(&mutex); } +private: + friend class ConditionVariable; + pthread_mutex_t mutex; +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() { pthread_cond_init(&cond, 0); } + ~ConditionVariable() { pthread_cond_destroy(&cond); } + void wait(Mutex& mutex) { pthread_cond_wait(&cond, &mutex.mutex); } + void broadcast() { pthread_cond_broadcast(&cond); } + void signal() { pthread_cond_signal(&cond); } +private: + pthread_cond_t cond; +}; + +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*start)(void*), void* args = 0) { pthread_create(&t, 0, start, args); } + ~Thread() {} + void join() { pthread_join(t, 0); } +private: + pthread_t t; +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { pthread_key_create(&key, 0); } + ~ThreadLocalStorage() { pthread_key_delete(key); } + void set(void* value) { pthread_setspecific(key, value); } + void* get() { return pthread_getspecific(key); } +private: + pthread_key_t key; +}; +#endif // (defined _WIN32 && !(defined __MINGW32__)) +#else // NCNN_THREADS +class NCNN_EXPORT Mutex +{ +public: + Mutex() {} + ~Mutex() {} + void lock() {} + void unlock() {} +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() {} + ~ConditionVariable() {} + void wait(Mutex& /*mutex*/) {} + void broadcast() {} + void signal() {} +}; + +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*/*start*/)(void*), void* /*args*/ = 0) {} + ~Thread() {} + void join() {} +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { data = 0; } + ~ThreadLocalStorage() {} + void set(void* value) { data = value; } + void* get() { return data; } +private: + void* data; +}; +#endif // NCNN_THREADS + +class NCNN_EXPORT MutexLockGuard +{ +public: + MutexLockGuard(Mutex& _mutex) : mutex(_mutex) { mutex.lock(); } + ~MutexLockGuard() { mutex.unlock(); } +private: + Mutex& mutex; +}; + +} // namespace ncnn + +#if NCNN_SIMPLESTL +#include "simplestl.h" +#else +#include +#include +#include +#include +#endif + +// simplemath +#if NCNN_SIMPLEMATH +#include "simplemath.h" +#else +#include +#include +#endif + +#endif // __cplusplus + +#if NCNN_STDIO +#if NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#include +#define NCNN_LOGE(...) do { \ + fprintf(stderr, ##__VA_ARGS__); fprintf(stderr, "\n"); \ + __android_log_print(ANDROID_LOG_WARN, "ncnn", ##__VA_ARGS__); } while(0) +#else // NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#include +#define NCNN_LOGE(...) do { \ + fprintf(stderr, ##__VA_ARGS__); fprintf(stderr, "\n"); } while(0) +#endif // NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#else +#define NCNN_LOGE(...) +#endif + + +#if NCNN_FORCE_INLINE +#ifdef _MSC_VER + #define NCNN_FORCEINLINE __forceinline +#elif defined(__GNUC__) + #define NCNN_FORCEINLINE inline __attribute__((__always_inline__)) +#elif defined(__CLANG__) + #if __has_attribute(__always_inline__) + #define NCNN_FORCEINLINE inline __attribute__((__always_inline__)) + #else + #define NCNN_FORCEINLINE inline + #endif +#else + #define NCNN_FORCEINLINE inline +#endif +#else + #define NCNN_FORCEINLINE inline +#endif + +#endif // NCNN_PLATFORM_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/simplemath.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/simplemath.h new file mode 100644 index 0000000..fd7fa69 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/simplemath.h @@ -0,0 +1,102 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEMATH_H +#define NCNN_SIMPLEMATH_H + +#include "platform.h" + +#if NCNN_SIMPLEMATH + +#ifdef __cplusplus +extern "C" { +#endif +/* +* ==================================================== +* discrete functions +* ==================================================== +*/ +NCNN_EXPORT float fabs(float); +NCNN_EXPORT float fabsf(float); +NCNN_EXPORT float fmod(float, float); +NCNN_EXPORT float floor(float); +NCNN_EXPORT float floorf(float); +NCNN_EXPORT float round(float); +NCNN_EXPORT float roundf(float); +NCNN_EXPORT float ceil(float); +NCNN_EXPORT float ceilf(float); +NCNN_EXPORT float fmaxf(float, float); +NCNN_EXPORT float truncf(float); +NCNN_EXPORT float frac(float); +/* +* ==================================================== +* trigonometric functions +* ==================================================== +*/ +NCNN_EXPORT float sinf(float); +NCNN_EXPORT float cosf(float); +NCNN_EXPORT float tanf(float); +NCNN_EXPORT float asinf(float); +NCNN_EXPORT float acosf(float); +NCNN_EXPORT float atanf(float); +NCNN_EXPORT float atan2f(float, float); +NCNN_EXPORT float tanhf(float); + +/* +* ==================================================== +* power functions +* ==================================================== +*/ +NCNN_EXPORT float sqrtf(float); +NCNN_EXPORT float sqrt(float); +NCNN_EXPORT float powf(float, float); + +/* +* ==================================================== +* exponential and logarithm functions +* ==================================================== +*/ +NCNN_EXPORT float expf(float); +NCNN_EXPORT float frexp(float, int*); +NCNN_EXPORT float logf(float); +NCNN_EXPORT float log(float); +NCNN_EXPORT float log10f(float); + +/* +* ==================================================== +* probability functions +* ==================================================== +*/ +NCNN_EXPORT float erf(float); +NCNN_EXPORT float erfcf(float); + +/* +* ==================================================== +* other functions +* ==================================================== +*/ +NCNN_EXPORT int msb(unsigned int); +NCNN_EXPORT float fmaf(float, float, float); +NCNN_EXPORT float copysignf(float, float); +NCNN_EXPORT void fesetround(int); +NCNN_EXPORT int fegetround(); +NCNN_EXPORT float nearbyintf(float); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // NCNN_SIMPLEMATH + +#endif // NCNN_SIMPLEMATH_H \ No newline at end of file diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/simpleocv.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/simpleocv.h new file mode 100644 index 0000000..54b22d9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/simpleocv.h @@ -0,0 +1,503 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEOCV_H +#define NCNN_SIMPLEOCV_H + +#include "platform.h" + +#if NCNN_SIMPLEOCV + +#include +#include +#include "allocator.h" +#include "mat.h" + +#if defined(_MSC_VER) || defined(__GNUC__) +#pragma push_macro("min") +#pragma push_macro("max") +#undef min +#undef max +#endif + +#ifndef NCNN_XADD +using ncnn::NCNN_XADD; +#endif + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; + +enum +{ + CV_LOAD_IMAGE_UNCHANGED = -1, + CV_LOAD_IMAGE_GRAYSCALE = 0, + CV_LOAD_IMAGE_COLOR = 1, +}; + +enum +{ + CV_IMWRITE_JPEG_QUALITY = 1 +}; + +// minimal opencv style data structure implementation +namespace cv { + +template +static inline _Tp saturate_cast(int v) +{ + return _Tp(v); +} +template<> +inline uchar saturate_cast(int v) +{ + return (uchar)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); +} + +template +struct Scalar_ +{ + Scalar_() + { + v[0] = 0; + v[1] = 0; + v[2] = 0; + v[3] = 0; + } + Scalar_(_Tp _v0) + { + v[0] = _v0; + v[1] = 0; + v[2] = 0; + v[3] = 0; + } + Scalar_(_Tp _v0, _Tp _v1, _Tp _v2) + { + v[0] = _v0; + v[1] = _v1; + v[2] = _v2; + v[3] = 0; + } + Scalar_(_Tp _v0, _Tp _v1, _Tp _v2, _Tp _v3) + { + v[0] = _v0; + v[1] = _v1; + v[2] = _v2; + v[3] = _v3; + } + + const _Tp operator[](const int i) const + { + return v[i]; + } + + _Tp operator[](const int i) + { + return v[i]; + } + + _Tp v[4]; +}; + +typedef Scalar_ Scalar; + +template +struct Point_ +{ + Point_() + : x(0), y(0) + { + } + Point_(_Tp _x, _Tp _y) + : x(_x), y(_y) + { + } + + template + operator Point_<_Tp2>() const + { + return Point_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y)); + } + + _Tp x; + _Tp y; +}; + +typedef Point_ Point; +typedef Point_ Point2f; + +template +struct Size_ +{ + Size_() + : width(0), height(0) + { + } + Size_(_Tp _w, _Tp _h) + : width(_w), height(_h) + { + } + + template + operator Size_<_Tp2>() const + { + return Size_<_Tp2>(saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); + } + + _Tp width; + _Tp height; +}; + +typedef Size_ Size; +typedef Size_ Size2f; + +template +struct Rect_ +{ + Rect_() + : x(0), y(0), width(0), height(0) + { + } + Rect_(_Tp _x, _Tp _y, _Tp _w, _Tp _h) + : x(_x), y(_y), width(_w), height(_h) + { + } + Rect_(Point_<_Tp> _p, Size_<_Tp> _size) + : x(_p.x), y(_p.y), width(_size.width), height(_size.height) + { + } + + template + operator Rect_<_Tp2>() const + { + return Rect_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y), saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); + } + + _Tp x; + _Tp y; + _Tp width; + _Tp height; + + // area + _Tp area() const + { + return width * height; + } +}; + +template +static inline Rect_<_Tp>& operator&=(Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + _Tp x1 = std::max(a.x, b.x), y1 = std::max(a.y, b.y); + a.width = std::min(a.x + a.width, b.x + b.width) - x1; + a.height = std::min(a.y + a.height, b.y + b.height) - y1; + a.x = x1; + a.y = y1; + if (a.width <= 0 || a.height <= 0) + a = Rect_<_Tp>(); + return a; +} + +template +static inline Rect_<_Tp>& operator|=(Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + _Tp x1 = std::min(a.x, b.x), y1 = std::min(a.y, b.y); + a.width = std::max(a.x + a.width, b.x + b.width) - x1; + a.height = std::max(a.y + a.height, b.y + b.height) - y1; + a.x = x1; + a.y = y1; + return a; +} + +template +static inline Rect_<_Tp> operator&(const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c &= b; +} + +template +static inline Rect_<_Tp> operator|(const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c |= b; +} + +typedef Rect_ Rect; +typedef Rect_ Rect2f; + +#define CV_8UC1 1 +#define CV_8UC3 3 +#define CV_8UC4 4 +#define CV_32FC1 4 + +struct NCNN_EXPORT Mat +{ + Mat() + : data(0), refcount(0), rows(0), cols(0), c(0) + { + } + + Mat(int _rows, int _cols, int flags) + : data(0), refcount(0) + { + create(_rows, _cols, flags); + } + + // copy + Mat(const Mat& m) + : data(m.data), refcount(m.refcount) + { + if (refcount) + NCNN_XADD(refcount, 1); + + rows = m.rows; + cols = m.cols; + c = m.c; + } + + Mat(int _rows, int _cols, int flags, void* _data) + : data((unsigned char*)_data), refcount(0) + { + rows = _rows; + cols = _cols; + c = flags; + } + + ~Mat() + { + release(); + } + + // assign + Mat& operator=(const Mat& m) + { + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + + rows = m.rows; + cols = m.cols; + c = m.c; + + return *this; + } + + Mat& operator=(const Scalar& s) + { + if (total() > 0) + { + uchar* p = data; + for (int i = 0; i < cols * rows; i++) + { + for (int j = 0; j < c; j++) + { + *p++ = s[j]; + } + } + } + + return *this; + } + + void create(int _rows, int _cols, int flags) + { + release(); + + rows = _rows; + cols = _cols; + c = flags; + + if (total() > 0) + { + // refcount address must be aligned, so we expand totalsize here + size_t totalsize = (total() + 3) >> 2 << 2; + data = (uchar*)ncnn::fastMalloc(totalsize + (int)sizeof(*refcount)); + refcount = (int*)(((uchar*)data) + totalsize); + *refcount = 1; + } + } + + void release() + { + if (refcount && NCNN_XADD(refcount, -1) == 1) + ncnn::fastFree(data); + + data = 0; + + rows = 0; + cols = 0; + c = 0; + + refcount = 0; + } + + Mat clone() const + { + if (empty()) + return Mat(); + + Mat m(rows, cols, c); + + if (total() > 0) + { + memcpy(m.data, data, total()); + } + + return m; + } + + bool empty() const + { + return data == 0 || total() == 0; + } + + int channels() const + { + return c; + } + + int type() const + { + return c; + } + + size_t total() const + { + return cols * rows * c; + } + + const uchar* ptr(int y) const + { + return data + y * cols * c; + } + + uchar* ptr(int y) + { + return data + y * cols * c; + } + + template + const _Tp* ptr(int y) const + { + return (const _Tp*)data + y * cols * c; + } + + template + _Tp* ptr(int y) + { + return (_Tp*)data + y * cols * c; + } + + // roi + Mat operator()(const Rect& roi) const + { + if (empty()) + return Mat(); + + Mat m(roi.height, roi.width, c); + + int sy = roi.y; + for (int y = 0; y < roi.height; y++) + { + const uchar* sptr = ptr(sy) + roi.x * c; + uchar* dptr = m.ptr(y); + memcpy(dptr, sptr, roi.width * c); + sy++; + } + + return m; + } + + uchar* data; + + // pointer to the reference counter; + // when points to user-allocated data, the pointer is NULL + int* refcount; + + int rows; + int cols; + + int c; +}; + +enum ImreadModes +{ + IMREAD_UNCHANGED = -1, + IMREAD_GRAYSCALE = 0, + IMREAD_COLOR = 1 +}; + +NCNN_EXPORT Mat imread(const std::string& path, int flags = IMREAD_COLOR); + +NCNN_EXPORT Mat imdecode(const std::vector& buf, int flags = IMREAD_COLOR); + +enum ImwriteFlags +{ + IMWRITE_JPEG_QUALITY = 1 +}; + +NCNN_EXPORT bool imwrite(const std::string& path, const Mat& m, const std::vector& params = std::vector()); + +NCNN_EXPORT void imshow(const std::string& name, const Mat& m); + +NCNN_EXPORT int waitKey(int delay = 0); + +#if NCNN_PIXEL +NCNN_EXPORT void resize(const Mat& src, Mat& dst, const Size& size, float sw = 0.f, float sh = 0.f, int flags = 0); +#endif // NCNN_PIXEL + +#if NCNN_PIXEL_DRAWING + +enum +{ + FILLED = -1 +}; + +NCNN_EXPORT void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void rectangle(Mat& img, Rect rec, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void circle(Mat& img, Point center, int radius, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void line(Mat& img, Point p0, Point p1, const Scalar& color, int thickness = 1); + +enum +{ + FONT_HERSHEY_SIMPLEX = 0 +}; + +NCNN_EXPORT void putText(Mat& img, const std::string& text, Point org, int fontFace, double fontScale, Scalar color, int thickness = 1); + +NCNN_EXPORT Size getTextSize(const std::string& text, int fontFace, double fontScale, int thickness, int* baseLine); + +#endif // NCNN_PIXEL_DRAWING + +} // namespace cv + +#if defined(_MSC_VER) || defined(__GNUC__) +#pragma pop_macro("min") +#pragma pop_macro("max") +#endif + +#endif // NCNN_SIMPLEOCV + +#endif // NCNN_SIMPLEOCV_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/simpleomp.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/simpleomp.h new file mode 100644 index 0000000..13e2452 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/simpleomp.h @@ -0,0 +1,53 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEOMP_H +#define NCNN_SIMPLEOMP_H + +#include "platform.h" + +#if NCNN_SIMPLEOMP + +#include + +// This minimal openmp runtime implementation only supports the llvm openmp abi +// and only supports #pragma omp parallel for num_threads(X) + +#ifdef __cplusplus +extern "C" { +#endif + +NCNN_EXPORT int omp_get_max_threads(); + +NCNN_EXPORT void omp_set_num_threads(int num_threads); + +NCNN_EXPORT int omp_get_dynamic(); + +NCNN_EXPORT void omp_set_dynamic(int dynamic); + +NCNN_EXPORT int omp_get_num_threads(); + +NCNN_EXPORT int omp_get_thread_num(); + +NCNN_EXPORT int kmp_get_blocktime(); + +NCNN_EXPORT void kmp_set_blocktime(int blocktime); + +#ifdef __cplusplus +} +#endif + +#endif // NCNN_SIMPLEOMP + +#endif // NCNN_SIMPLEOMP_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/simplestl.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/simplestl.h new file mode 100644 index 0000000..00ff468 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/simplestl.h @@ -0,0 +1,565 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLESTL_H +#define NCNN_SIMPLESTL_H + +#include +#include +#include + +#if !NCNN_SIMPLESTL + +#include + +#else + +// allocation functions +NCNN_EXPORT void* operator new(size_t size); +NCNN_EXPORT void* operator new[](size_t size); +// placement allocation functions +NCNN_EXPORT void* operator new(size_t size, void* ptr); +NCNN_EXPORT void* operator new[](size_t size, void* ptr); +// deallocation functions +NCNN_EXPORT void operator delete(void* ptr); +NCNN_EXPORT void operator delete[](void* ptr); +// deallocation functions since c++14 +#if __cplusplus >= 201402L +NCNN_EXPORT void operator delete(void* ptr, size_t sz); +NCNN_EXPORT void operator delete[](void* ptr, size_t sz); +#endif +// placement deallocation functions +NCNN_EXPORT void operator delete(void* ptr, void* voidptr2); +NCNN_EXPORT void operator delete[](void* ptr, void* voidptr2); + +#endif + +// minimal stl data structure implementation +namespace std { + +template +const T& max(const T& a, const T& b) +{ + return (a < b) ? b : a; +} + +template +const T& min(const T& a, const T& b) +{ + return (a > b) ? b : a; +} + +template +void swap(T& a, T& b) +{ + T temp(a); + a = b; + b = temp; +} + +template +struct pair +{ + pair() + : first(), second() + { + } + pair(const T1& t1, const T2& t2) + : first(t1), second(t2) + { + } + + T1 first; + T2 second; +}; + +template +bool operator==(const pair& x, const pair& y) +{ + return (x.first == y.first && x.second == y.second); +} +template +bool operator<(const pair& x, const pair& y) +{ + return x.first < y.first || (!(y.first < x.first) && x.second < y.second); +} +template +bool operator!=(const pair& x, const pair& y) +{ + return !(x == y); +} +template +bool operator>(const pair& x, const pair& y) +{ + return y < x; +} +template +bool operator<=(const pair& x, const pair& y) +{ + return !(y < x); +} +template +bool operator>=(const pair& x, const pair& y) +{ + return !(x < y); +} + +template +pair make_pair(const T1& t1, const T2& t2) +{ + return pair(t1, t2); +} + +template +struct node +{ + node* prev_; + node* next_; + T data_; + + node() + : prev_(0), next_(0), data_() + { + } + node(const T& t) + : prev_(0), next_(0), data_(t) + { + } +}; + +template +struct iter_list +{ + iter_list() + : curr_(0) + { + } + iter_list(node* n) + : curr_(n) + { + } + iter_list(const iter_list& i) + : curr_(i.curr_) + { + } + ~iter_list() + { + } + + iter_list& operator=(const iter_list& i) + { + curr_ = i.curr_; + return *this; + } + + T& operator*() + { + return curr_->data_; + } + T* operator->() + { + return &(curr_->data_); + } + + bool operator==(const iter_list& i) + { + return curr_ == i.curr_; + } + bool operator!=(const iter_list& i) + { + return curr_ != i.curr_; + } + + iter_list& operator++() + { + curr_ = curr_->next_; + return *this; + } + iter_list& operator--() + { + curr_ = curr_->prev_; + return *this; + } + + node* curr_; +}; + +template +struct list +{ + typedef iter_list iterator; + + list() + { + head_ = new node(); + tail_ = head_; + count_ = 0; + } + ~list() + { + clear(); + delete head_; + } + list(const list& l) + { + head_ = new node(); + tail_ = head_; + count_ = 0; + + for (iter_list i = l.begin(); i != l.end(); ++i) + { + push_back(*i); + } + } + + list& operator=(const list& l) + { + if (this == &l) + { + return *this; + } + clear(); + + for (iter_list i = l.begin(); i != l.end(); ++i) + { + push_back(*i); + } + return *this; + } + + void clear() + { + while (count_ > 0) + { + pop_front(); + } + } + + void pop_front() + { + if (count_ > 0) + { + head_ = head_->next_; + delete head_->prev_; + head_->prev_ = 0; + --count_; + } + } + + size_t size() const + { + return count_; + } + iter_list begin() const + { + return iter_list(head_); + } + iter_list end() const + { + return iter_list(tail_); + } + bool empty() const + { + return count_ == 0; + } + + void push_back(const T& t) + { + if (count_ == 0) + { + head_ = new node(t); + head_->prev_ = 0; + head_->next_ = tail_; + tail_->prev_ = head_; + count_ = 1; + } + else + { + node* temp = new node(t); + temp->prev_ = tail_->prev_; + temp->next_ = tail_; + tail_->prev_->next_ = temp; + tail_->prev_ = temp; + ++count_; + } + } + + iter_list erase(iter_list pos) + { + if (pos != end()) + { + node* temp = pos.curr_; + if (temp == head_) + { + ++pos; + temp->next_->prev_ = 0; + head_ = temp->next_; + } + else + { + --pos; + temp->next_->prev_ = temp->prev_; + temp->prev_->next_ = temp->next_; + ++pos; + } + delete temp; + --count_; + } + return pos; + } + +protected: + node* head_; + node* tail_; + size_t count_; +}; + +template +struct greater +{ + bool operator()(const T& x, const T& y) const + { + return (x > y); + } +}; + +template +struct less +{ + bool operator()(const T& x, const T& y) const + { + return (x < y); + } +}; + +template +void partial_sort(RandomAccessIter first, RandomAccessIter middle, RandomAccessIter last, Compare comp) +{ + // [TODO] heap sort should be used here, but we simply use bubble sort now + for (RandomAccessIter i = first; i < middle; ++i) + { + // bubble sort + for (RandomAccessIter j = last - 1; j > first; --j) + { + if (comp(*j, *(j - 1))) + { + swap(*j, *(j - 1)); + } + } + } +} + +template +struct vector +{ + vector() + : data_(0), size_(0), capacity_(0) + { + } + vector(const size_t new_size, const T& value = T()) + : data_(0), size_(0), capacity_(0) + { + resize(new_size, value); + } + ~vector() + { + clear(); + } + vector(const vector& v) + : data_(0), size_(0), capacity_(0) + { + resize(v.size()); + for (size_t i = 0; i < size_; i++) + { + data_[i] = v.data_[i]; + } + } + + vector& operator=(const vector& v) + { + if (this == &v) + { + return *this; + } + resize(0); + resize(v.size()); + for (size_t i = 0; i < size_; i++) + { + data_[i] = v.data_[i]; + } + return *this; + } + + void resize(const size_t new_size, const T& value = T()) + { + try_alloc(new_size); + if (new_size > size_) + { + for (size_t i = size_; i < new_size; i++) + { + new (&data_[i]) T(value); + } + } + else if (new_size < size_) + { + for (size_t i = new_size; i < size_; i++) + { + data_[i].~T(); + } + } + size_ = new_size; + } + + void clear() + { + for (size_t i = 0; i < size_; i++) + { + data_[i].~T(); + } + delete[](char*) data_; + data_ = 0; + size_ = 0; + capacity_ = 0; + } + + T* data() const + { + return data_; + } + size_t size() const + { + return size_; + } + T& operator[](size_t i) const + { + return data_[i]; + } + T* begin() const + { + return &data_[0]; + } + T* end() const + { + return &data_[size_]; + } + bool empty() const + { + return size_ == 0; + } + + void push_back(const T& t) + { + try_alloc(size_ + 1); + new (&data_[size_]) T(t); + size_++; + } + + void insert(T* pos, T* b, T* e) + { + vector* v = 0; + if (b >= begin() && b < end()) + { + //the same vector + v = new vector(*this); + b = v->begin() + (b - begin()); + e = v->begin() + (e - begin()); + } + size_t diff = pos - begin(); + try_alloc(size_ + (e - b)); + pos = begin() + diff; + memmove(pos + (e - b), pos, (end() - pos) * sizeof(T)); + size_t len = e - b; + size_ += len; + for (size_t i = 0; i < len; i++) + { + *pos = *b; + pos++; + b++; + } + delete v; + } + + T* erase(T* pos) + { + pos->~T(); + memmove(pos, pos + 1, (end() - pos - 1) * sizeof(T)); + size_--; + return pos; + } + +protected: + T* data_; + size_t size_; + size_t capacity_; + void try_alloc(size_t new_size) + { + if (new_size * 3 / 2 > capacity_ / 2) + { + capacity_ = new_size * 2; + T* new_data = (T*)new char[capacity_ * sizeof(T)]; + memset(static_cast(new_data), 0, capacity_ * sizeof(T)); + if (data_) + { + memmove(new_data, data_, sizeof(T) * size_); + delete[](char*) data_; + } + data_ = new_data; + } + } +}; + +struct NCNN_EXPORT string : public vector +{ + string() + { + } + string(const char* str) + { + size_t len = strlen(str); + resize(len); + memcpy(data_, str, len); + } + const char* c_str() const + { + return (const char*)data_; + } + bool operator==(const string& str2) const + { + return strcmp(data_, str2.data_) == 0; + } + bool operator==(const char* str2) const + { + return strcmp(data_, str2) == 0; + } + bool operator!=(const char* str2) const + { + return strcmp(data_, str2) != 0; + } + string& operator+=(const string& str1) + { + insert(end(), str1.begin(), str1.end()); + return *this; + } +}; + +inline string operator+(const string& str1, const string& str2) +{ + string str(str1); + str.insert(str.end(), str2.begin(), str2.end()); + return str; +} + +} // namespace std + +#endif // NCNN_SIMPLESTL_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/ncnn/vulkan_header_fix.h b/duix-sdk/src/main/cpp/third/arm/include/ncnn/vulkan_header_fix.h new file mode 100644 index 0000000..0a5ea9b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/ncnn/vulkan_header_fix.h @@ -0,0 +1,449 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_VULKAN_HEADER_FIX_H +#define NCNN_VULKAN_HEADER_FIX_H + +#include + +// This header contains new structure and function declearation to fix build with old vulkan sdk + +#if VK_HEADER_VERSION < 70 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES (VkStructureType)1000094000 +typedef enum VkSubgroupFeatureFlagBits +{ + VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001, + VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002, + VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004, + VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008, + VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010, + VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020, + VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040, + VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080, + VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 0x00000100, + VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubgroupFeatureFlagBits; +typedef VkFlags VkSubgroupFeatureFlags; +typedef struct VkPhysicalDeviceSubgroupProperties +{ + VkStructureType sType; + void* pNext; + uint32_t subgroupSize; + VkShaderStageFlags supportedStages; + VkSubgroupFeatureFlags supportedOperations; + VkBool32 quadOperationsInAllStages; +} VkPhysicalDeviceSubgroupProperties; +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES (VkStructureType)1000168000 +#define VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT (VkStructureType)1000168001 +typedef struct VkPhysicalDeviceMaintenance3Properties +{ + VkStructureType sType; + void* pNext; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceMaintenance3Properties; +typedef struct VkDescriptorSetLayoutSupport +{ + VkStructureType sType; + void* pNext; + VkBool32 supported; +} VkDescriptorSetLayoutSupport; +typedef VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; +typedef VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; +typedef void(VKAPI_PTR* PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); +#endif // VK_HEADER_VERSION < 70 + +#if VK_HEADER_VERSION < 80 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR (VkStructureType)1000177000 +typedef struct VkPhysicalDevice8BitStorageFeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; +} VkPhysicalDevice8BitStorageFeaturesKHR; +#define VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR (VkStructureType)1000109000 +#define VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR (VkStructureType)1000109001 +#define VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR (VkStructureType)1000109002 +#define VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR (VkStructureType)1000109003 +#define VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR (VkStructureType)1000109004 +#define VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR (VkStructureType)1000109005 +#define VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR (VkStructureType)1000109006 +typedef struct VkAttachmentDescription2KHR +{ + VkStructureType sType; + const void* pNext; + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription2KHR; +typedef struct VkAttachmentReference2KHR +{ + VkStructureType sType; + const void* pNext; + uint32_t attachment; + VkImageLayout layout; + VkImageAspectFlags aspectMask; +} VkAttachmentReference2KHR; +typedef struct VkSubpassDescription2KHR +{ + VkStructureType sType; + const void* pNext; + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t viewMask; + uint32_t inputAttachmentCount; + const VkAttachmentReference2KHR* pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference2KHR* pColorAttachments; + const VkAttachmentReference2KHR* pResolveAttachments; + const VkAttachmentReference2KHR* pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t* pPreserveAttachments; +} VkSubpassDescription2KHR; +typedef struct VkSubpassDependency2KHR +{ + VkStructureType sType; + const void* pNext; + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; + int32_t viewOffset; +} VkSubpassDependency2KHR; +typedef struct VkRenderPassCreateInfo2KHR +{ + VkStructureType sType; + const void* pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription2KHR* pAttachments; + uint32_t subpassCount; + const VkSubpassDescription2KHR* pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency2KHR* pDependencies; + uint32_t correlatedViewMaskCount; + const uint32_t* pCorrelatedViewMasks; +} VkRenderPassCreateInfo2KHR; +typedef struct VkSubpassBeginInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkSubpassContents contents; +} VkSubpassBeginInfoKHR; + +typedef struct VkSubpassEndInfoKHR +{ + VkStructureType sType; + const void* pNext; +} VkSubpassEndInfoKHR; +typedef VkResult(VKAPI_PTR* PFN_vkCreateRenderPass2KHR)(VkDevice device, const VkRenderPassCreateInfo2KHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void(VKAPI_PTR* PFN_vkCmdBeginRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfoKHR* pSubpassBeginInfo); +typedef void(VKAPI_PTR* PFN_vkCmdNextSubpass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfoKHR* pSubpassBeginInfo, const VkSubpassEndInfoKHR* pSubpassEndInfo); +typedef void(VKAPI_PTR* PFN_vkCmdEndRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassEndInfoKHR* pSubpassEndInfo); +#endif // VK_HEADER_VERSION < 80 + +#if VK_HEADER_VERSION < 95 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR (VkStructureType)1000082000 +typedef struct VkPhysicalDeviceFloat16Int8FeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; +} VkPhysicalDeviceFloat16Int8FeaturesKHR; +#endif // VK_HEADER_VERSION < 95 + +#if VK_HEADER_VERSION < 97 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT (VkStructureType)1000237000 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT (VkStructureType)1000238000 +#define VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT (VkStructureType)1000238001 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT (VkStructureType)1000244000 +#define VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_EXT (VkStructureType)1000244001 +#define VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT (VkStructureType)1000244002 +#define VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT (VkStructureType)1000247000 +#define VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT (VkBufferCreateFlagBits)0x00020000 +#define VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT (VkBufferUsageFlagBits)0x00020000 +typedef uint64_t VkDeviceAddress; +typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT +{ + VkStructureType sType; + void* pNext; + VkDeviceSize heapBudget[VK_MAX_MEMORY_HEAPS]; + VkDeviceSize heapUsage[VK_MAX_MEMORY_HEAPS]; +} VkPhysicalDeviceMemoryBudgetPropertiesEXT; +typedef struct VkPhysicalDeviceMemoryPriorityFeaturesEXT +{ + VkStructureType sType; + void* pNext; + VkBool32 memoryPriority; +} VkPhysicalDeviceMemoryPriorityFeaturesEXT; +typedef struct VkMemoryPriorityAllocateInfoEXT +{ + VkStructureType sType; + const void* pNext; + float priority; +} VkMemoryPriorityAllocateInfoEXT; +typedef struct VkPhysicalDeviceBufferAddressFeaturesEXT +{ + VkStructureType sType; + void* pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferAddressFeaturesEXT; +typedef struct VkBufferDeviceAddressInfoEXT +{ + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferDeviceAddressInfoEXT; +typedef struct VkBufferDeviceAddressCreateInfoEXT +{ + VkStructureType sType; + const void* pNext; + VkDeviceSize deviceAddress; +} VkBufferDeviceAddressCreateInfoEXT; +typedef VkDeviceAddress(VKAPI_PTR* PFN_vkGetBufferDeviceAddressEXT)(VkDevice device, const VkBufferDeviceAddressInfoEXT* pInfo); +typedef enum VkValidationFeatureEnableEXT +{ + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT = 0, + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT = 1, + VK_VALIDATION_FEATURE_ENABLE_BEGIN_RANGE_EXT = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT, + VK_VALIDATION_FEATURE_ENABLE_END_RANGE_EXT = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT, + VK_VALIDATION_FEATURE_ENABLE_RANGE_SIZE_EXT = (VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT - VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT + 1), + VK_VALIDATION_FEATURE_ENABLE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationFeatureEnableEXT; +typedef enum VkValidationFeatureDisableEXT +{ + VK_VALIDATION_FEATURE_DISABLE_ALL_EXT = 0, + VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT = 1, + VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT = 2, + VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT = 3, + VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT = 4, + VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT = 5, + VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT = 6, + VK_VALIDATION_FEATURE_DISABLE_BEGIN_RANGE_EXT = VK_VALIDATION_FEATURE_DISABLE_ALL_EXT, + VK_VALIDATION_FEATURE_DISABLE_END_RANGE_EXT = VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT, + VK_VALIDATION_FEATURE_DISABLE_RANGE_SIZE_EXT = (VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT - VK_VALIDATION_FEATURE_DISABLE_ALL_EXT + 1), + VK_VALIDATION_FEATURE_DISABLE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationFeatureDisableEXT; +typedef struct VkValidationFeaturesEXT +{ + VkStructureType sType; + const void* pNext; + uint32_t enabledValidationFeatureCount; + const VkValidationFeatureEnableEXT* pEnabledValidationFeatures; + uint32_t disabledValidationFeatureCount; + const VkValidationFeatureDisableEXT* pDisabledValidationFeatures; +} VkValidationFeaturesEXT; +#endif // VK_HEADER_VERSION < 97 + +#if VK_HEADER_VERSION < 101 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV (VkStructureType)1000249000 +#define VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV (VkStructureType)1000249001 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV (VkStructureType)1000249002 +typedef enum VkComponentTypeNV +{ + VK_COMPONENT_TYPE_FLOAT16_NV = 0, + VK_COMPONENT_TYPE_FLOAT32_NV = 1, + VK_COMPONENT_TYPE_FLOAT64_NV = 2, + VK_COMPONENT_TYPE_SINT8_NV = 3, + VK_COMPONENT_TYPE_SINT16_NV = 4, + VK_COMPONENT_TYPE_SINT32_NV = 5, + VK_COMPONENT_TYPE_SINT64_NV = 6, + VK_COMPONENT_TYPE_UINT8_NV = 7, + VK_COMPONENT_TYPE_UINT16_NV = 8, + VK_COMPONENT_TYPE_UINT32_NV = 9, + VK_COMPONENT_TYPE_UINT64_NV = 10, + VK_COMPONENT_TYPE_BEGIN_RANGE_NV = VK_COMPONENT_TYPE_FLOAT16_NV, + VK_COMPONENT_TYPE_END_RANGE_NV = VK_COMPONENT_TYPE_UINT64_NV, + VK_COMPONENT_TYPE_RANGE_SIZE_NV = (VK_COMPONENT_TYPE_UINT64_NV - VK_COMPONENT_TYPE_FLOAT16_NV + 1), + VK_COMPONENT_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkComponentTypeNV; +typedef enum VkScopeNV +{ + VK_SCOPE_DEVICE_NV = 1, + VK_SCOPE_WORKGROUP_NV = 2, + VK_SCOPE_SUBGROUP_NV = 3, + VK_SCOPE_QUEUE_FAMILY_NV = 5, + VK_SCOPE_BEGIN_RANGE_NV = VK_SCOPE_DEVICE_NV, + VK_SCOPE_END_RANGE_NV = VK_SCOPE_QUEUE_FAMILY_NV, + VK_SCOPE_RANGE_SIZE_NV = (VK_SCOPE_QUEUE_FAMILY_NV - VK_SCOPE_DEVICE_NV + 1), + VK_SCOPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkScopeNV; +typedef struct VkCooperativeMatrixPropertiesNV +{ + VkStructureType sType; + void* pNext; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeNV AType; + VkComponentTypeNV BType; + VkComponentTypeNV CType; + VkComponentTypeNV DType; + VkScopeNV scope; +} VkCooperativeMatrixPropertiesNV; +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesNV +{ + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesNV; +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesNV +{ + VkStructureType sType; + void* pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesNV; +typedef VkResult(VKAPI_PTR* PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixPropertiesNV* pProperties); +#endif // VK_HEADER_VERSION < 101 + +#if VK_HEADER_VERSION < 121 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD (VkStructureType)1000229000 +#define VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD (VkMemoryPropertyFlagBits)0x00000040 +#define VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD (VkMemoryPropertyFlagBits)0x00000040 +typedef struct VkPhysicalDeviceCoherentMemoryFeaturesAMD +{ + VkStructureType sType; + void* pNext; + VkBool32 deviceCoherentMemory; +} VkPhysicalDeviceCoherentMemoryFeaturesAMD; +#endif // VK_HEADER_VERSION < 121 + +#if VK_HEADER_VERSION < 129 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR (VkStructureType)1000257000 +#define VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR (VkStructureType)1000244001 +#define VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO_KHR (VkStructureType)1000257002 +#define VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO_KHR (VkStructureType)1000257003 +#define VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO_KHR (VkStructureType)1000257004 +#define VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR (VkBufferCreateFlagBits)0x00020000 +#define VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR (VkBufferUsageFlagBits)0x00020000 +#define VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR (VkMemoryAllocateFlagBits)0x00000002 +#define VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR (VkMemoryAllocateFlagBits)0x00000004 +typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferDeviceAddressFeaturesKHR; +typedef struct VkBufferDeviceAddressInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferDeviceAddressInfoKHR; +typedef struct VkBufferOpaqueCaptureAddressCreateInfoKHR +{ + VkStructureType sType; + const void* pNext; + uint64_t opaqueCaptureAddress; +} VkBufferOpaqueCaptureAddressCreateInfoKHR; +typedef struct VkMemoryOpaqueCaptureAddressAllocateInfoKHR +{ + VkStructureType sType; + const void* pNext; + uint64_t opaqueCaptureAddress; +} VkMemoryOpaqueCaptureAddressAllocateInfoKHR; +typedef struct VkDeviceMemoryOpaqueCaptureAddressInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; +} VkDeviceMemoryOpaqueCaptureAddressInfoKHR; +typedef VkDeviceAddress(VKAPI_PTR* PFN_vkGetBufferDeviceAddressKHR)(VkDevice device, const VkBufferDeviceAddressInfoKHR* pInfo); +typedef uint64_t(VKAPI_PTR* PFN_vkGetBufferOpaqueCaptureAddressKHR)(VkDevice device, const VkBufferDeviceAddressInfoKHR* pInfo); +typedef uint64_t(VKAPI_PTR* PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR)(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfoKHR* pInfo); +#endif // VK_HEADER_VERSION < 129 + +#if VK_HEADER_VERSION < 208 +typedef enum VkInstanceCreateFlagBits +{ + VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR = 0x00000001, + VK_INSTANCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkInstanceCreateFlagBits; +#endif // VK_HEADER_VERSION < 208 + +#if VK_HEADER_VERSION < 255 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR (VkStructureType)1000506000 +#define VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_KHR (VkStructureType)1000506001 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR (VkStructureType)1000506002 +typedef enum VkComponentTypeKHR +{ + VK_COMPONENT_TYPE_FLOAT16_KHR = 0, + VK_COMPONENT_TYPE_FLOAT32_KHR = 1, + VK_COMPONENT_TYPE_FLOAT64_KHR = 2, + VK_COMPONENT_TYPE_SINT8_KHR = 3, + VK_COMPONENT_TYPE_SINT16_KHR = 4, + VK_COMPONENT_TYPE_SINT32_KHR = 5, + VK_COMPONENT_TYPE_SINT64_KHR = 6, + VK_COMPONENT_TYPE_UINT8_KHR = 7, + VK_COMPONENT_TYPE_UINT16_KHR = 8, + VK_COMPONENT_TYPE_UINT32_KHR = 9, + VK_COMPONENT_TYPE_UINT64_KHR = 10, + VK_COMPONENT_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkComponentTypeKHR; +typedef enum VkScopeKHR +{ + VK_SCOPE_DEVICE_KHR = 1, + VK_SCOPE_WORKGROUP_KHR = 2, + VK_SCOPE_SUBGROUP_KHR = 3, + VK_SCOPE_QUEUE_FAMILY_KHR = 5, + VK_SCOPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkScopeKHR; +typedef struct VkCooperativeMatrixPropertiesKHR +{ + VkStructureType sType; + void* pNext; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeKHR AType; + VkComponentTypeKHR BType; + VkComponentTypeKHR CType; + VkComponentTypeKHR ResultType; + VkBool32 saturatingAccumulation; + VkScopeKHR scope; +} VkCooperativeMatrixPropertiesKHR; +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesKHR; +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesKHR +{ + VkStructureType sType; + void* pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesKHR; +typedef VkResult(VKAPI_PTR* PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixPropertiesKHR* pProperties); +#endif // VK_HEADER_VERSION < 255 + +#endif // NCNN_VULKAN_HEADER_FIX_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/onnx/cpu_provider_factory.h b/duix-sdk/src/main/cpp/third/arm/include/onnx/cpu_provider_factory.h new file mode 100644 index 0000000..2926786 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/onnx/cpu_provider_factory.h @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "onnxruntime_c_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \param use_arena zero: false. non-zero: true. + */ +ORT_EXPORT +ORT_API_STATUS(OrtSessionOptionsAppendExecutionProvider_CPU, _In_ OrtSessionOptions* options, int use_arena) +ORT_ALL_ARGS_NONNULL; + +#ifdef __cplusplus +} +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/onnx/nnapi_provider_factory.h b/duix-sdk/src/main/cpp/third/arm/include/onnx/nnapi_provider_factory.h new file mode 100644 index 0000000..a0aeb5a --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/onnx/nnapi_provider_factory.h @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +#pragma once + +#include "onnxruntime_c_api.h" + +// NNAPIFlags are bool options we want to set for NNAPI EP +// This enum is defined as bit flags, and cannot have negative value +// To generate an uint32_t nnapi_flags for using with OrtSessionOptionsAppendExecutionProvider_Nnapi below, +// uint32_t nnapi_flags = 0; +// nnapi_flags |= NNAPI_FLAG_USE_FP16; +enum NNAPIFlags { + NNAPI_FLAG_USE_NONE = 0x000, + + // Using fp16 relaxation in NNAPI EP, this may improve perf but may also reduce precision + NNAPI_FLAG_USE_FP16 = 0x001, + + // Use NCHW layout in NNAPI EP, this is only available after Android API level 29 + // Please note for now, NNAPI perform worse using NCHW compare to using NHWC + NNAPI_FLAG_USE_NCHW = 0x002, + + // Prevent NNAPI from using CPU devices. + // + // NNAPI is more efficient using GPU or NPU for execution, and NNAPI might fall back to its own CPU implementation + // for operations not supported by GPU/NPU. The CPU implementation of NNAPI (which is called nnapi-reference) + // might be less efficient than the optimized versions of the operation of ORT. It might be advantageous to disable + // the NNAPI CPU fallback and handle execution using ORT kernels. + // + // For some models, if NNAPI would use CPU to execute an operation, and this flag is set, the execution of the + // model may fall back to ORT kernels. + // + // This option is only available after Android API level 29, and will be ignored for Android API level 28- + // + // For NNAPI device assignments, see https://developer.android.com/ndk/guides/neuralnetworks#device-assignment + // For NNAPI CPU fallback, see https://developer.android.com/ndk/guides/neuralnetworks#cpu-fallback + // + // Please note, the NNAPI EP will return error status if both NNAPI_FLAG_CPU_DISABLED + // and NNAPI_FLAG_CPU_ONLY flags are set + NNAPI_FLAG_CPU_DISABLED = 0x004, + + // Using CPU only in NNAPI EP, this may decrease the perf but will provide + // reference output value without precision loss, which is useful for validation + // + // Please note, the NNAPI EP will return error status if both NNAPI_FLAG_CPU_DISABLED + // and NNAPI_FLAG_CPU_ONLY flags are set + NNAPI_FLAG_CPU_ONLY = 0x008, + + // Keep NNAPI_FLAG_LAST at the end of the enum definition + // And assign the last NNAPIFlag to it + NNAPI_FLAG_LAST = NNAPI_FLAG_CPU_ONLY, +}; + +#ifdef __cplusplus +extern "C" { +#endif + +ORT_EXPORT ORT_API_STATUS(OrtSessionOptionsAppendExecutionProvider_Nnapi, + _In_ OrtSessionOptions* options, uint32_t nnapi_flags); + +#ifdef __cplusplus +} +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/onnx/onnxruntime_c_api.h b/duix-sdk/src/main/cpp/third/arm/include/onnx/onnxruntime_c_api.h new file mode 100644 index 0000000..456a116 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/onnx/onnxruntime_c_api.h @@ -0,0 +1,4550 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// See docs\c_cxx\README.md on generating the Doxygen documentation from this file + +/** \mainpage ONNX Runtime + * + * ONNX Runtime is a high-performance inference and training graph execution engine for deep learning models. + * + * ONNX Runtime's C, C++ APIs offer an easy to use interface to onboard and execute onnx models. + * - \subpage c_cpp_api "Core C, C++ APIs" + * - \subpage training_c_cpp_api "Training C, C++ APIs for on-device training" + * + * \page c_cpp_api Core C, C++ APIs + *

C

+ * + * ::OrtApi - Click here to go to the structure with all C API functions. + * + *

C++

+ * + * ::Ort - Click here to go to the namespace holding all of the C++ wrapper classes + * + * It is a set of header only wrapper classes around the C API. The goal is to turn the C style return value error codes into C++ exceptions, and to + * automate memory management through standard C++ RAII principles. + * + * \addtogroup Global + * ONNX Runtime C API + * @{ + */ + +#pragma once +#include +#include +#include + +/** \brief The API version defined in this header + * + * This value is used by some API functions to behave as this version of the header expects. + */ +#define ORT_API_VERSION 16 + +#ifdef __cplusplus +extern "C" { +#endif + +//! @} +// SAL2 Definitions +#ifndef _WIN32 +#define _In_ +#define _In_z_ +#define _In_opt_ +#define _In_opt_z_ +#define _Out_ +#define _Outptr_ +#define _Out_opt_ +#define _Inout_ +#define _Inout_opt_ +#define _Frees_ptr_opt_ +#define _Ret_maybenull_ +#define _Ret_notnull_ +#define _Check_return_ +#define _Outptr_result_maybenull_ +#define _In_reads_(X) +#define _Inout_updates_(X) +#define _Out_writes_(X) +#define _Inout_updates_all_(X) +#define _Out_writes_bytes_all_(X) +#define _Out_writes_all_(X) +#define _Success_(X) +#define _Outptr_result_buffer_maybenull_(X) +#define ORT_ALL_ARGS_NONNULL __attribute__((nonnull)) +#else +#include +#define ORT_ALL_ARGS_NONNULL +#endif + +#ifdef _WIN32 +// Define ORT_DLL_IMPORT if your program is dynamically linked to Ort. +// dllexport is not used, we use a .def file. +#ifdef ORT_DLL_IMPORT +#define ORT_EXPORT __declspec(dllimport) +#else +#define ORT_EXPORT +#endif +#define ORT_API_CALL _stdcall +#define ORT_MUST_USE_RESULT +#define ORTCHAR_T wchar_t +#else +// To make symbols visible on macOS/iOS +#ifdef __APPLE__ +#define ORT_EXPORT __attribute__((visibility("default"))) +#else +#define ORT_EXPORT +#endif +#define ORT_API_CALL +#define ORT_MUST_USE_RESULT __attribute__((warn_unused_result)) +#define ORTCHAR_T char +#endif + +/// ORTCHAR_T, ORT_TSTR are reserved specifically for path handling. +/// All other strings are UTF-8 encoded, use char and std::string +#ifndef ORT_TSTR +#ifdef _WIN32 +#define ORT_TSTR(X) L##X +// When X is a macro, L##X is not defined. In this case, we need to use ORT_TSTR_ON_MACRO. +#define ORT_TSTR_ON_MACRO(X) L"" X +#else +#define ORT_TSTR(X) X +#define ORT_TSTR_ON_MACRO(X) X +#endif +#endif + +// On Windows, ORT_FILE is a wchar_t version of the __FILE__ macro. +// Otherwise, ORT_FILE is equivalent to __FILE__. +#ifndef ORT_FILE +#define ORT_FILE_INTERNAL(x) ORT_TSTR(x) +#define ORT_FILE ORT_FILE_INTERNAL(__FILE__) +#endif + +// Any pointer marked with _In_ or _Out_, cannot be NULL. + +// Windows users should use unicode paths when possible to bypass the MAX_PATH limitation +// Every pointer marked with _In_ or _Out_, cannot be NULL. Caller should ensure that. +// for ReleaseXXX(...) functions, they can accept NULL pointer. + +#ifdef __cplusplus +// For any compiler with C++11 support, MSVC 2015 and greater, or Clang version supporting noexcept. +// Such complex condition is needed because compilers set __cplusplus value differently. +#ifndef __has_feature +#define __has_feature(x) 0 +#endif +#if ((__cplusplus >= 201103L) || (_MSC_VER >= 1900) || (defined(__has_feature) && __has_feature(cxx_noexcept))) +#define NO_EXCEPTION noexcept +#else +#define NO_EXCEPTION throw() +#endif +#else +#define NO_EXCEPTION +#endif + +// __VA_ARGS__ on Windows and Linux are different +#define ORT_API(RETURN_TYPE, NAME, ...) RETURN_TYPE ORT_API_CALL NAME(__VA_ARGS__) NO_EXCEPTION + +#define ORT_API_STATUS(NAME, ...) \ + _Success_(return == 0) _Check_return_ _Ret_maybenull_ OrtStatusPtr ORT_API_CALL NAME(__VA_ARGS__) \ + NO_EXCEPTION ORT_MUST_USE_RESULT + +// XXX: Unfortunately, SAL annotations are known to not work with function pointers +#define ORT_API2_STATUS(NAME, ...) \ + _Check_return_ _Ret_maybenull_ OrtStatusPtr(ORT_API_CALL* NAME)(__VA_ARGS__) NO_EXCEPTION ORT_MUST_USE_RESULT + +// Used in *.cc files. Almost as same as ORT_API_STATUS, except without ORT_MUST_USE_RESULT and ORT_EXPORT +#define ORT_API_STATUS_IMPL(NAME, ...) \ + _Success_(return == 0) _Check_return_ _Ret_maybenull_ OrtStatusPtr ORT_API_CALL NAME(__VA_ARGS__) NO_EXCEPTION + +#define ORT_CLASS_RELEASE(X) void(ORT_API_CALL * Release##X)(_Frees_ptr_opt_ Ort##X * input) + +#ifdef __DOXYGEN__ +#undef ORT_API_STATUS +#define ORT_API_STATUS(NAME, ...) OrtStatus* NAME(__VA_ARGS__) +#undef ORT_API2_STATUS +#define ORT_API2_STATUS(NAME, ...) OrtStatus* NAME(__VA_ARGS__) +#undef ORT_CLASS_RELEASE +#define ORT_CLASS_RELEASE(X) void Release##X(Ort##X* input) +#undef NO_EXCEPTION +#define NO_EXCEPTION +#endif +/** \addtogroup Global + * ONNX Runtime C API + * @{ + */ + +/** Copied from TensorProto::DataType + * Currently, Ort doesn't support complex64, complex128 + */ +typedef enum ONNXTensorElementDataType { + ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED, + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, // maps to c type float + ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8, // maps to c type uint8_t + ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8, // maps to c type int8_t + ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16, // maps to c type uint16_t + ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16, // maps to c type int16_t + ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32, // maps to c type int32_t + ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64, // maps to c type int64_t + ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING, // maps to c++ type std::string + ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL, + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16, + ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE, // maps to c type double + ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32, // maps to c type uint32_t + ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64, // maps to c type uint64_t + ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX64, // complex with float32 real and imaginary components + ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX128, // complex with float64 real and imaginary components + ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16, // Non-IEEE floating-point format based on IEEE754 single-precision + // float 8 types were introduced in onnx 1.14, see https://onnx.ai/onnx/technical/float8.html + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FN, // Non-IEEE floating-point format based on IEEE754 single-precision + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FNUZ, // Non-IEEE floating-point format based on IEEE754 single-precision + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2, // Non-IEEE floating-point format based on IEEE754 single-precision + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2FNUZ // Non-IEEE floating-point format based on IEEE754 single-precision +} ONNXTensorElementDataType; + +// Synced with onnx TypeProto oneof +typedef enum ONNXType { + ONNX_TYPE_UNKNOWN, + ONNX_TYPE_TENSOR, + ONNX_TYPE_SEQUENCE, + ONNX_TYPE_MAP, + ONNX_TYPE_OPAQUE, + ONNX_TYPE_SPARSETENSOR, + ONNX_TYPE_OPTIONAL +} ONNXType; + +// These types are synced with internal +// SparseFormatFlags +typedef enum OrtSparseFormat { + ORT_SPARSE_UNDEFINED = 0, + ORT_SPARSE_COO = 0x1, + ORT_SPARSE_CSRC = 0x2, + ORT_SPARSE_BLOCK_SPARSE = 0x4 +} OrtSparseFormat; + +// Enum allows to query sparse tensor indices +enum OrtSparseIndicesFormat { + ORT_SPARSE_COO_INDICES, + ORT_SPARSE_CSR_INNER_INDICES, + ORT_SPARSE_CSR_OUTER_INDICES, + ORT_SPARSE_BLOCK_SPARSE_INDICES +}; + +/** \brief Logging severity levels + * + * In typical API usage, specifying a logging severity level specifies the minimum severity of log messages to show. + */ +typedef enum OrtLoggingLevel { + ORT_LOGGING_LEVEL_VERBOSE, ///< Verbose informational messages (least severe). + ORT_LOGGING_LEVEL_INFO, ///< Informational messages. + ORT_LOGGING_LEVEL_WARNING, ///< Warning messages. + ORT_LOGGING_LEVEL_ERROR, ///< Error messages. + ORT_LOGGING_LEVEL_FATAL, ///< Fatal error messages (most severe). +} OrtLoggingLevel; + +typedef enum OrtErrorCode { + ORT_OK, + ORT_FAIL, + ORT_INVALID_ARGUMENT, + ORT_NO_SUCHFILE, + ORT_NO_MODEL, + ORT_ENGINE_ERROR, + ORT_RUNTIME_EXCEPTION, + ORT_INVALID_PROTOBUF, + ORT_MODEL_LOADED, + ORT_NOT_IMPLEMENTED, + ORT_INVALID_GRAPH, + ORT_EP_FAIL, +} OrtErrorCode; + +typedef enum OrtOpAttrType { + ORT_OP_ATTR_UNDEFINED = 0, + ORT_OP_ATTR_INT, + ORT_OP_ATTR_INTS, + ORT_OP_ATTR_FLOAT, + ORT_OP_ATTR_FLOATS, + ORT_OP_ATTR_STRING, + ORT_OP_ATTR_STRINGS, +} OrtOpAttrType; + +//! @} +#define ORT_RUNTIME_CLASS(X) \ + struct Ort##X; \ + typedef struct Ort##X Ort##X; + +/** \addtogroup Global + * ONNX Runtime C API + * @{ + */ +// The actual types defined have an Ort prefix +ORT_RUNTIME_CLASS(Env); +ORT_RUNTIME_CLASS(Status); // nullptr for Status* indicates success +ORT_RUNTIME_CLASS(MemoryInfo); +ORT_RUNTIME_CLASS(IoBinding); +ORT_RUNTIME_CLASS(Session); // Don't call ReleaseSession from Dllmain (because session owns a thread pool) +ORT_RUNTIME_CLASS(Value); +ORT_RUNTIME_CLASS(RunOptions); +ORT_RUNTIME_CLASS(TypeInfo); +ORT_RUNTIME_CLASS(TensorTypeAndShapeInfo); +ORT_RUNTIME_CLASS(MapTypeInfo); +ORT_RUNTIME_CLASS(SequenceTypeInfo); +ORT_RUNTIME_CLASS(OptionalTypeInfo); +ORT_RUNTIME_CLASS(SessionOptions); +ORT_RUNTIME_CLASS(CustomOpDomain); +ORT_RUNTIME_CLASS(ModelMetadata); +ORT_RUNTIME_CLASS(ThreadPoolParams); +ORT_RUNTIME_CLASS(ThreadingOptions); +ORT_RUNTIME_CLASS(ArenaCfg); +ORT_RUNTIME_CLASS(PrepackedWeightsContainer); +ORT_RUNTIME_CLASS(TensorRTProviderOptionsV2); +ORT_RUNTIME_CLASS(CUDAProviderOptionsV2); +ORT_RUNTIME_CLASS(CANNProviderOptions); +ORT_RUNTIME_CLASS(DnnlProviderOptions); +ORT_RUNTIME_CLASS(Op); +ORT_RUNTIME_CLASS(OpAttr); +ORT_RUNTIME_CLASS(Logger); + +#ifdef _WIN32 +typedef _Return_type_success_(return == 0) OrtStatus* OrtStatusPtr; +#else +typedef OrtStatus* OrtStatusPtr; +#endif + +/** \brief Memory allocation interface + * + * Structure of function pointers that defines a memory allocator. This can be created and filled in by the user for custom allocators. + * + * When an allocator is passed to any function, be sure that the allocator object is not destroyed until the last allocated object using it is freed. + */ +typedef struct OrtAllocator { + uint32_t version; ///< Must be initialized to ORT_API_VERSION + void*(ORT_API_CALL* Alloc)(struct OrtAllocator* this_, size_t size); ///< Returns a pointer to an allocated block of `size` bytes + void(ORT_API_CALL* Free)(struct OrtAllocator* this_, void* p); ///< Free a block of memory previously allocated with OrtAllocator::Alloc + const struct OrtMemoryInfo*(ORT_API_CALL* Info)(const struct OrtAllocator* this_); ///< Return a pointer to an ::OrtMemoryInfo that describes this allocator +} OrtAllocator; + +typedef void(ORT_API_CALL* OrtLoggingFunction)( + void* param, OrtLoggingLevel severity, const char* category, const char* logid, const char* code_location, + const char* message); + +/** \brief Graph optimization level + * + * Refer to https://www.onnxruntime.ai/docs/performance/graph-optimizations.html#graph-optimization-levels + * for an in-depth understanding of the Graph Optimization Levels. + */ +typedef enum GraphOptimizationLevel { + ORT_DISABLE_ALL = 0, + ORT_ENABLE_BASIC = 1, + ORT_ENABLE_EXTENDED = 2, + ORT_ENABLE_ALL = 99 +} GraphOptimizationLevel; + +typedef enum ExecutionMode { + ORT_SEQUENTIAL = 0, + ORT_PARALLEL = 1, +} ExecutionMode; + +/** \brief Language projection identifiers + * /see OrtApi::SetLanguageProjection + */ +typedef enum OrtLanguageProjection { + ORT_PROJECTION_C = 0, + ORT_PROJECTION_CPLUSPLUS = 1, + ORT_PROJECTION_CSHARP = 2, + ORT_PROJECTION_PYTHON = 3, + ORT_PROJECTION_JAVA = 4, + ORT_PROJECTION_WINML = 5, + ORT_PROJECTION_NODEJS = 6, +} OrtLanguageProjection; + +struct OrtKernelInfo; +typedef struct OrtKernelInfo OrtKernelInfo; +struct OrtKernelContext; +typedef struct OrtKernelContext OrtKernelContext; +struct OrtCustomOp; +typedef struct OrtCustomOp OrtCustomOp; + +typedef enum OrtAllocatorType { + OrtInvalidAllocator = -1, + OrtDeviceAllocator = 0, + OrtArenaAllocator = 1 +} OrtAllocatorType; + +/** \brief Memory types for allocated memory, execution provider specific types should be extended in each provider. + */ +// Whenever this struct is updated, please also update the MakeKey function in onnxruntime / core / framework / execution_provider.cc +typedef enum OrtMemType { + OrtMemTypeCPUInput = -2, ///< Any CPU memory used by non-CPU execution provider + OrtMemTypeCPUOutput = -1, ///< CPU accessible memory outputted by non-CPU execution provider, i.e. CUDA_PINNED + OrtMemTypeCPU = OrtMemTypeCPUOutput, ///< Temporary CPU accessible memory allocated by non-CPU execution provider, i.e. CUDA_PINNED + OrtMemTypeDefault = 0, ///< The default allocator for execution provider +} OrtMemType; + +/** \brief This mimics OrtDevice type constants so they can be returned in the API + */ +typedef enum OrtMemoryInfoDeviceType { + OrtMemoryInfoDeviceType_CPU = 0, + OrtMemoryInfoDeviceType_GPU = 1, + OrtMemoryInfoDeviceType_FPGA = 2 +} OrtMemoryInfoDeviceType; + +/** \brief Algorithm to use for cuDNN Convolution Op + */ +typedef enum OrtCudnnConvAlgoSearch { + OrtCudnnConvAlgoSearchExhaustive, // expensive exhaustive benchmarking using cudnnFindConvolutionForwardAlgorithmEx + OrtCudnnConvAlgoSearchHeuristic, // lightweight heuristic based search using cudnnGetConvolutionForwardAlgorithm_v7 + OrtCudnnConvAlgoSearchDefault, // default algorithm using CUDNN_CONVOLUTION_FWD_ALGO_IMPLICIT_PRECOMP_GEMM +} OrtCudnnConvAlgoSearch; + +/** \brief CUDA Provider Options + * + * \see OrtApi::SessionOptionsAppendExecutionProvider_CUDA + */ +typedef struct OrtCUDAProviderOptions { +#ifdef __cplusplus + OrtCUDAProviderOptions() + : device_id{}, + cudnn_conv_algo_search{OrtCudnnConvAlgoSearchExhaustive}, + gpu_mem_limit{SIZE_MAX}, + arena_extend_strategy{}, + do_copy_in_default_stream{1}, + has_user_compute_stream{}, + user_compute_stream{}, + default_memory_arena_cfg{}, + tunable_op_enable{false}, + tunable_op_tuning_enable{false}, + tunable_op_max_tuning_duration_ms{} {} +#endif + + /** \brief CUDA device Id + * Defaults to 0. + */ + int device_id; + + /** \brief CUDA Convolution algorithm search configuration. + * See enum OrtCudnnConvAlgoSearch for more details. + * Defaults to OrtCudnnConvAlgoSearchExhaustive. + */ + OrtCudnnConvAlgoSearch cudnn_conv_algo_search; + + /** \brief CUDA memory limit (To use all possible memory pass in maximum size_t) + * Defaults to SIZE_MAX. + * \note If a ::OrtArenaCfg has been applied, it will override this field + */ + size_t gpu_mem_limit; + + /** \brief Strategy used to grow the memory arena + * 0 = kNextPowerOfTwo
+ * 1 = kSameAsRequested
+ * Defaults to 0. + * \note If a ::OrtArenaCfg has been applied, it will override this field + */ + int arena_extend_strategy; + + /** \brief Flag indicating if copying needs to take place on the same stream as the compute stream in the CUDA EP + * 0 = Use separate streams for copying and compute. + * 1 = Use the same stream for copying and compute. + * Defaults to 1. + * WARNING: Setting this to 0 may result in data races for some models. + * Please see issue #4829 for more details. + */ + int do_copy_in_default_stream; + + /** \brief Flag indicating if there is a user provided compute stream + * Defaults to 0. + */ + int has_user_compute_stream; + + /** \brief User provided compute stream. + * If provided, please set `has_user_compute_stream` to 1. + */ + void* user_compute_stream; + + /** \brief CUDA memory arena configuration parameters + */ + OrtArenaCfg* default_memory_arena_cfg; + + /** \brief Enable TunableOp for using. + * Set it to 1/0 to enable/disable TunableOp. Otherwise, it is disabled by default. + * This option can be overriden by environment variable ORT_CUDA_TUNABLE_OP_ENABLE. + */ + int tunable_op_enable; + + /** \brief Enable TunableOp for tuning. + * Set it to 1/0 to enable/disable TunableOp tuning. Otherwise, it is disabled by default. + * This option can be overriden by environment variable ORT_CUDA_TUNABLE_OP_TUNING_ENABLE. + */ + int tunable_op_tuning_enable; + + /** \brief Max tuning duration time limit for each instance of TunableOp. + * Defaults to 0 to disable the limit. + */ + int tunable_op_max_tuning_duration_ms; + +} OrtCUDAProviderOptions; + +/** \brief ROCM Provider Options + * + * \see OrtApi::SessionOptionsAppendExecutionProvider_ROCM + */ +typedef struct OrtROCMProviderOptions { +#ifdef __cplusplus + OrtROCMProviderOptions() + : device_id{}, + miopen_conv_exhaustive_search{0}, + gpu_mem_limit{SIZE_MAX}, + arena_extend_strategy{}, + do_copy_in_default_stream{1}, + has_user_compute_stream{}, + user_compute_stream{}, + default_memory_arena_cfg{}, + tunable_op_enable{false}, + tunable_op_tuning_enable{false}, + tunable_op_max_tuning_duration_ms{} {} +#endif + + /** \brief ROCM device Id + * Defaults to 0. + */ + int device_id; + + /** \brief ROCM MIOpen Convolution algorithm exaustive search option. + * Defaults to 0 (false). + */ + int miopen_conv_exhaustive_search; + + /** \brief ROCM memory limit (To use all possible memory pass in maximum size_t) + * Defaults to SIZE_MAX. + * \note If a ::OrtArenaCfg has been applied, it will override this field + */ + size_t gpu_mem_limit; + + /** \brief Strategy used to grow the memory arena + * 0 = kNextPowerOfTwo
+ * 1 = kSameAsRequested
+ * Defaults to 0. + * \note If a ::OrtArenaCfg has been applied, it will override this field + */ + int arena_extend_strategy; + + /** \brief Flag indicating if copying needs to take place on the same stream as the compute stream in the ROCM EP + * 0 = Use separate streams for copying and compute. + * 1 = Use the same stream for copying and compute. + * Defaults to 1. + * WARNING: Setting this to 0 may result in data races for some models. + * Please see issue #4829 for more details. + */ + int do_copy_in_default_stream; + + /** \brief Flag indicating if there is a user provided compute stream + * Defaults to 0. + */ + int has_user_compute_stream; + + /** \brief User provided compute stream. + * If provided, please set `has_user_compute_stream` to 1. + */ + void* user_compute_stream; + + /** \brief ROCM memory arena configuration parameters + */ + OrtArenaCfg* default_memory_arena_cfg; + + /** \brief Enable TunableOp for using. + * Set it to 1/0 to enable/disable TunableOp. Otherwise, it is disabled by default. + * This option can be overriden by environment variable ORT_ROCM_TUNABLE_OP_ENABLE. + */ + int tunable_op_enable; + + /** \brief Enable TunableOp for tuning. + * Set it to 1/0 to enable/disable TunableOp tuning. Otherwise, it is disabled by default. + * This option can be overriden by environment variable ORT_ROCM_TUNABLE_OP_TUNING_ENABLE. + */ + int tunable_op_tuning_enable; + + /** \brief Max tuning duration time limit for each instance of TunableOp. + * Defaults to 0 to disable the limit. + */ + int tunable_op_max_tuning_duration_ms; + +} OrtROCMProviderOptions; + +/** \brief TensorRT Provider Options + * + * \see OrtApi::SessionOptionsAppendExecutionProvider_TensorRT + */ +typedef struct OrtTensorRTProviderOptions { + int device_id; ///< CUDA device id (0 = default device) + int has_user_compute_stream; // indicator of user specified CUDA compute stream. + void* user_compute_stream; // user specified CUDA compute stream. + int trt_max_partition_iterations; // maximum iterations for TensorRT parser to get capability + int trt_min_subgraph_size; // minimum size of TensorRT subgraphs + size_t trt_max_workspace_size; // maximum workspace size for TensorRT. + int trt_fp16_enable; // enable TensorRT FP16 precision. Default 0 = false, nonzero = true + int trt_int8_enable; // enable TensorRT INT8 precision. Default 0 = false, nonzero = true + const char* trt_int8_calibration_table_name; // TensorRT INT8 calibration table name. + int trt_int8_use_native_calibration_table; // use native TensorRT generated calibration table. Default 0 = false, nonzero = true + int trt_dla_enable; // enable DLA. Default 0 = false, nonzero = true + int trt_dla_core; // DLA core number. Default 0 + int trt_dump_subgraphs; // dump TRT subgraph. Default 0 = false, nonzero = true + int trt_engine_cache_enable; // enable engine caching. Default 0 = false, nonzero = true + const char* trt_engine_cache_path; // specify engine cache path + int trt_engine_decryption_enable; // enable engine decryption. Default 0 = false, nonzero = true + const char* trt_engine_decryption_lib_path; // specify engine decryption library path + int trt_force_sequential_engine_build; // force building TensorRT engine sequentially. Default 0 = false, nonzero = true + // This is the legacy struct and don't add new fields here. + // For new field that can be represented by string, please add it in include/onnxruntime/core/providers/tensorrt/tensorrt_provider_options.h + // For non-string field, need to create a new separate api to handle it. +} OrtTensorRTProviderOptions; + +/** \brief MIGraphX Provider Options + * + * \see OrtApi::SessionOptionsAppendExecutionProvider_MIGraphX + */ +typedef struct OrtMIGraphXProviderOptions { + int device_id; // hip device id. + int migraphx_fp16_enable; // enable MIGraphX FP16 precision. Default 0 = false, nonzero = true + int migraphx_int8_enable; // enable MIGraphX INT8 precision. Default 0 = false, nonzero = true +} OrtMIGraphXProviderOptions; + +/** \brief OpenVINO Provider Options + * + * \see OrtApi::SessionOptionsAppendExecutionProvider_OpenVINO + */ +typedef struct OrtOpenVINOProviderOptions { +#ifdef __cplusplus + OrtOpenVINOProviderOptions() : device_type{}, + enable_vpu_fast_compile{}, + device_id{}, + num_of_threads{}, + cache_dir{}, + context{}, + enable_opencl_throttling{}, + enable_dynamic_shapes{} {} +#endif + /** \brief Device type string + * + * Valid settings are one of: "CPU_FP32", "CPU_FP16", "GPU_FP32", "GPU_FP16" + */ + const char* device_type; + unsigned char enable_vpu_fast_compile; ///< 0 = disabled, nonzero = enabled + const char* device_id; + size_t num_of_threads; ///< 0 = Use default number of threads + const char* cache_dir; // path is set to empty by default + void* context; + unsigned char enable_opencl_throttling; ///< 0 = disabled, nonzero = enabled + unsigned char enable_dynamic_shapes; ///< 0 = disabled, nonzero = enabled +} OrtOpenVINOProviderOptions; + +struct OrtApi; +typedef struct OrtApi OrtApi; + +struct OrtTrainingApi; +typedef struct OrtTrainingApi OrtTrainingApi; + +/** \brief The helper interface to get the right version of OrtApi + * + * Get a pointer to this structure through ::OrtGetApiBase + */ +struct OrtApiBase { + /** \brief Get a pointer to the requested version of the ::OrtApi + * + * \param[in] version Must be ::ORT_API_VERSION + * \return The ::OrtApi for the version requested, nullptr will be returned if this version is unsupported, for example when using a runtime + * older than the version created with this header file. + * + * One can call GetVersionString() to get the version of the Onnxruntime library for logging + * and error reporting purposes. + */ + const OrtApi*(ORT_API_CALL* GetApi)(uint32_t version)NO_EXCEPTION; + + /** \brief Returns a null terminated string of the version of the Onnxruntime library (eg: "1.8.1") + * + * \return UTF-8 encoded version string. Do not deallocate the returned buffer. + */ + const char*(ORT_API_CALL* GetVersionString)(void)NO_EXCEPTION; +}; + +typedef struct OrtApiBase OrtApiBase; + +/** \brief The Onnxruntime library's entry point to access the C API + * + * Call this to get the a pointer to an ::OrtApiBase + */ +ORT_EXPORT const OrtApiBase* ORT_API_CALL OrtGetApiBase(void) NO_EXCEPTION; + +/** \brief Thread work loop function + * + * Onnxruntime will provide the working loop on custom thread creation + * Argument is an onnxruntime built-in type which will be provided when thread pool calls OrtCustomCreateThreadFn + */ +typedef void (*OrtThreadWorkerFn)(void* ort_worker_fn_param); + +typedef const struct OrtCustomHandleType { + char __place_holder; +}* OrtCustomThreadHandle; + +/** \brief Ort custom thread creation function + * + * The function should return a thread handle to be used in onnxruntime thread pools + * Onnxruntime will throw exception on return value of nullptr or 0, indicating that the function failed to create a thread + */ +typedef OrtCustomThreadHandle (*OrtCustomCreateThreadFn)(void* ort_custom_thread_creation_options, OrtThreadWorkerFn ort_thread_worker_fn, void* ort_worker_fn_param); + +/** \brief Custom thread join function + * + * Onnxruntime thread pool destructor will call the function to join a custom thread. + * Argument ort_custom_thread_handle is the value returned by OrtCustomCreateThreadFn + */ +typedef void (*OrtCustomJoinThreadFn)(OrtCustomThreadHandle ort_custom_thread_handle); + +typedef OrtStatus*(ORT_API_CALL* RegisterCustomOpsFn)(OrtSessionOptions* options, const OrtApiBase* api); + +/** \brief Callback function for RunAsync + * + * \param[in] user_data User specific data that passed back to the callback + * \param[out] outputs On succeed, outputs host inference results, on error, the value will be nullptr + * \param[out] num_outputs Number of outputs, on error, the value will be zero + * \param[out] status On error, status will provide details + */ +typedef void (*RunAsyncCallbackFn)(void* user_data, OrtValue** outputs, size_t num_outputs, OrtStatusPtr status); + +/** \brief The C API + * + * All C API functions are defined inside this structure as pointers to functions. + * Call OrtApiBase::GetApi to get a pointer to it + * + * \nosubgrouping + */ +struct OrtApi { + /// \name OrtStatus + /// @{ + + /** + * \brief Create an OrtStatus from a null terminated string + * + * \param[in] code + * \param[in] msg A null-terminated string. Its contents will be copied. + * \return A new OrtStatus object, must be destroyed with OrtApi::ReleaseStatus + */ + OrtStatus*(ORT_API_CALL* CreateStatus)(OrtErrorCode code, _In_ const char* msg)NO_EXCEPTION ORT_ALL_ARGS_NONNULL; + + /** \brief Get OrtErrorCode from OrtStatus + * + * \param[in] status + * \return OrtErrorCode that \p status was created with + */ + OrtErrorCode(ORT_API_CALL* GetErrorCode)(_In_ const OrtStatus* status) NO_EXCEPTION ORT_ALL_ARGS_NONNULL; + + /** \brief Get error string from OrtStatus + * + * \param[in] status + * \return The error message inside the `status`. Do not free the returned value. + */ + const char*(ORT_API_CALL* GetErrorMessage)(_In_ const OrtStatus* status)NO_EXCEPTION ORT_ALL_ARGS_NONNULL; + + /// @} + /// \name OrtEnv + /// @{ + + /** \brief Create an OrtEnv + * + * \param[in] log_severity_level The log severity level. + * \param[in] logid The log identifier. + * \param[out] out Returned newly created OrtEnv. Must be freed with OrtApi::ReleaseEnv + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateEnv, OrtLoggingLevel log_severity_level, _In_ const char* logid, _Outptr_ OrtEnv** out); + + /** \brief Create an OrtEnv + * + * \param[in] logging_function A pointer to a logging function. + * \param[in] logger_param A pointer to arbitrary data passed as the ::OrtLoggingFunction `param` parameter to + * `logging_function`. + * \param[in] log_severity_level The log severity level. + * \param[in] logid The log identifier. + * \param[out] out Returned newly created OrtEnv. Must be freed with OrtApi::ReleaseEnv + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateEnvWithCustomLogger, OrtLoggingFunction logging_function, _In_opt_ void* logger_param, + OrtLoggingLevel log_severity_level, _In_ const char* logid, _Outptr_ OrtEnv** out); + + /** \brief Enable Telemetry + * + * \note Telemetry events are on by default since they are lightweight + * \param[in] env + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(EnableTelemetryEvents, _In_ const OrtEnv* env); + /** \brief Disable Telemetry + * + * \see OrtApi::EnableTelemetryEvents + * \param[in] env + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(DisableTelemetryEvents, _In_ const OrtEnv* env); + + /// @} + /// \name OrtSession + /// @{ + + /** \brief Create an OrtSession from a model file + * + * \param[in] env + * \param[in] model_path + * \param[in] options + * \param[out] out Returned newly created OrtSession. Must be freed with OrtApi::ReleaseSession + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + // TODO: document the path separator convention? '/' vs '\' + // TODO: should specify the access characteristics of model_path. Is this read only during the + // execution of CreateSession, or does the OrtSession retain a handle to the file/directory + // and continue to access throughout the OrtSession lifetime? + // What sort of access is needed to model_path : read or read/write? + ORT_API2_STATUS(CreateSession, _In_ const OrtEnv* env, _In_ const ORTCHAR_T* model_path, + _In_ const OrtSessionOptions* options, _Outptr_ OrtSession** out); + + /** \brief Create an OrtSession from memory + * + * \param[in] env + * \param[in] model_data + * \param[in] model_data_length + * \param[in] options + * \param[out] out Returned newly created OrtSession. Must be freed with OrtApi::ReleaseSession + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateSessionFromArray, _In_ const OrtEnv* env, _In_ const void* model_data, size_t model_data_length, + _In_ const OrtSessionOptions* options, _Outptr_ OrtSession** out); + + /** \brief Run the model in an ::OrtSession + * + * Will not return until the model run has completed. Multiple threads might be used to run the model based on + * the options in the ::OrtSession and settings used when creating the ::OrtEnv + * + * \param[in] session + * \param[in] run_options If nullptr, will use a default ::OrtRunOptions + * \param[in] input_names Array of null terminated UTF8 encoded strings of the input names + * \param[in] inputs Array of ::OrtValue%s of the input values + * \param[in] input_len Number of elements in the input_names and inputs arrays + * \param[in] output_names Array of null terminated UTF8 encoded strings of the output names + * \param[in] output_names_len Number of elements in the output_names and outputs array + * \param[out] outputs Array of ::OrtValue%s that the outputs are stored in. This can also be + * an array of nullptr values, in this case ::OrtValue objects will be allocated and pointers + * to them will be set into the `outputs` array. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(Run, _Inout_ OrtSession* session, _In_opt_ const OrtRunOptions* run_options, + _In_reads_(input_len) const char* const* input_names, + _In_reads_(input_len) const OrtValue* const* inputs, size_t input_len, + _In_reads_(output_names_len) const char* const* output_names, size_t output_names_len, + _Inout_updates_all_(output_names_len) OrtValue** outputs); + + /// @} + /// \name OrtSessionOptions + /// @{ + + /** \brief Create an ::OrtSessionOptions object + * + * To use additional providers, you must build ORT with the extra providers enabled. Then call one of these + * functions to enable them in the session:
+ * OrtSessionOptionsAppendExecutionProvider_CPU
+ * OrtSessionOptionsAppendExecutionProvider_CUDA
+ * OrtSessionOptionsAppendExecutionProvider_(remaining providers...)
+ * The order they are called indicates the preference order as well. In other words call this method + * on your most preferred execution provider first followed by the less preferred ones. + * If none are called Ort will use its internal CPU execution provider. + * + * \param[out] options The newly created OrtSessionOptions. Must be freed with OrtApi::ReleaseSessionOptions + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateSessionOptions, _Outptr_ OrtSessionOptions** options); + + /** \brief Set filepath to save optimized model after graph level transformations + * + * \param[in] options + * \param[in] optimized_model_filepath + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SetOptimizedModelFilePath, _Inout_ OrtSessionOptions* options, + _In_ const ORTCHAR_T* optimized_model_filepath); + + /** \brief Create a copy of an existing ::OrtSessionOptions + * + * \param[in] in_options OrtSessionOptions to copy + * \param[out] out_options Returned newly created ::OrtSessionOptions. Must be freed with OrtApi::ReleaseSessionOptions + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CloneSessionOptions, _In_ const OrtSessionOptions* in_options, + _Outptr_ OrtSessionOptions** out_options); + + /** \brief Set execution mode + * + * Controls whether you want to execute operators in your graph sequentially or in parallel. Usually when the model + * has many branches, setting this option to ExecutionMode.ORT_PARALLEL will give you better performance. + * See [docs/ONNX_Runtime_Perf_Tuning.md] for more details. + * + * \param[in] options + * \param[in] execution_mode + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SetSessionExecutionMode, _Inout_ OrtSessionOptions* options, ExecutionMode execution_mode); + + /** \brief Enable profiling for a session + * + * \param[in] options + * \param[in] profile_file_prefix + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(EnableProfiling, _Inout_ OrtSessionOptions* options, _In_ const ORTCHAR_T* profile_file_prefix); + + /** \brief Disable profiling for a session + * + * \param[in] options + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(DisableProfiling, _Inout_ OrtSessionOptions* options); + + /** \brief Enable the memory pattern optimization + * + * The idea is if the input shapes are the same, we could trace the internal memory allocation + * and generate a memory pattern for future request. So next time we could just do one allocation + * with a big chunk for all the internal memory allocation. + * \note Memory pattern optimization is only available when Sequential Execution mode is enabled (see OrtApi::SetSessionExecutionMode) + * + * \see OrtApi::DisableMemPattern + * + * \param[in] options + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(EnableMemPattern, _Inout_ OrtSessionOptions* options); + + /** \brief Disable the memory pattern optimization + * + * \see OrtApi::EnableMemPattern + * + * \param[in] options + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(DisableMemPattern, _Inout_ OrtSessionOptions* options); + + /** \brief Enable the memory arena on CPU + * + * Arena may pre-allocate memory for future usage. + * + * \param[in] options + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(EnableCpuMemArena, _Inout_ OrtSessionOptions* options); + + /** \brief Disable the memory arena on CPU + * + * \param[in] options + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(DisableCpuMemArena, _Inout_ OrtSessionOptions* options); + + /** \brief Set session log id + * + * \param[in] options + * \param[in] logid The log identifier. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SetSessionLogId, _Inout_ OrtSessionOptions* options, const char* logid); + + /** \brief Set session log verbosity level + * + * Applies to session load, initialization, etc + * + * \param[in] options + * \param[in] session_log_verbosity_level \snippet{doc} snippets.dox Log Verbosity Level + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SetSessionLogVerbosityLevel, _Inout_ OrtSessionOptions* options, int session_log_verbosity_level); + + /** \brief Set session log severity level + * + * \param[in] options + * \param[in] session_log_severity_level The log severity level (refer to ::OrtLoggingLevel for possible values). + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SetSessionLogSeverityLevel, _Inout_ OrtSessionOptions* options, int session_log_severity_level); + + /** \brief Set the optimization level to apply when loading a graph + * + * Please see https://onnxruntime.ai/docs/performance/model-optimizations/graph-optimizations.html for an in-depth explanation + * \param[in,out] options The session options object + * \param[in] graph_optimization_level The optimization level + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SetSessionGraphOptimizationLevel, _Inout_ OrtSessionOptions* options, + GraphOptimizationLevel graph_optimization_level); + + /** \brief Sets the number of threads used to parallelize the execution within nodes + * + * When running a single node operation, ex. add, this sets the maximum number of threads to use. + * + * \note If built with OpenMP, this has no effect on the number of threads used. In this case + * use the OpenMP env variables to configure the number of intra op num threads. + * + * \param[in] options + * \param[in] intra_op_num_threads Number of threads to use
+ * A value of 0 will use the default number of threads
+ * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SetIntraOpNumThreads, _Inout_ OrtSessionOptions* options, int intra_op_num_threads); + + /** \brief Sets the number of threads used to parallelize the execution of the graph + * + * If nodes can be run in parallel, this sets the maximum number of threads to use to run them in parallel. + * + * \note If sequential execution is enabled this value is ignored, it acts as if it was set to 1. + * + * \param[in] options + * \param[in] inter_op_num_threads Number of threads to use
+ * A value of 0 will use the default number of threads
+ * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SetInterOpNumThreads, _Inout_ OrtSessionOptions* options, int inter_op_num_threads); + + /// @} + /// \name OrtCustomOpDomain + /// @{ + + /** \brief Create a custom op domain + * + * \param[in] domain + * \param[out] out Newly created domain. Must be freed with OrtApi::ReleaseCustomOpDomain + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateCustomOpDomain, _In_ const char* domain, _Outptr_ OrtCustomOpDomain** out); + + /** \brief Add a custom op to a custom op domain + * + * \note The OrtCustomOp* pointer must remain valid until the ::OrtCustomOpDomain using it is released + * + * \param[in] custom_op_domain + * \param[in] op + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CustomOpDomain_Add, _Inout_ OrtCustomOpDomain* custom_op_domain, _In_ const OrtCustomOp* op); + + /// @} + /// \name OrtSessionOptions + /// @{ + + /** \brief Add custom op domain to a session options + * + * \note The OrtCustomOpDomain* must not be deleted until all sessions using it are released + * + * \param[in] options + * \param[in] custom_op_domain + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(AddCustomOpDomain, _Inout_ OrtSessionOptions* options, _In_ OrtCustomOpDomain* custom_op_domain); + + /** \deprecated Use OrtApi::RegisterCustomOpsLibrary_V2. + * + * Registers custom ops from a shared library. + * + * Loads a shared library (dll on windows, so on linux, etc) named 'library_path' and looks for this entry point: + * OrtStatus* RegisterCustomOps(OrtSessionOptions * options, const OrtApiBase* api); + * It then passes in the provided session options to this function along with the api base. + * The handle to the loaded library is returned in library_handle. It can be freed by the caller after all sessions using the passed in + * session options are destroyed, or if an error occurs and it is non null. + * + * \param[in] options + * \param[in] library_path + * \param[out] library_handle OS specific handle to the loaded library (Use FreeLibrary on Windows, dlclose on Linux, etc.. to unload) + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(RegisterCustomOpsLibrary, _Inout_ OrtSessionOptions* options, _In_ const char* library_path, _Outptr_ void** library_handle); + + /// @} + /// \name OrtSession + /// @{ + + /** \brief Get input count for a session + * + * This number must also match the number of inputs passed to OrtApi::Run + * + * \see OrtApi::SessionGetInputTypeInfo, OrtApi::SessionGetInputName, OrtApi::Session + * + * \param[in] session + * \param[out] out Number of inputs + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SessionGetInputCount, _In_ const OrtSession* session, _Out_ size_t* out); + + /** \brief Get output count for a session + * + * This number must also match the number of outputs returned by OrtApi::Run + * + * \see OrtApi::SessionGetOutputTypeInfo, OrtApi::SessionGetOutputName, OrtApi::Session + * + * \param[in] session + * \param[out] out Number of outputs + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SessionGetOutputCount, _In_ const OrtSession* session, _Out_ size_t* out); + + /** \brief Get overridable initializer count + * + * \see OrtApi::SessionGetOverridableInitializerTypeInfo, OrtApi::SessionGetOverridableInitializerName + * + * \param[in] session + * \param[in] out + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SessionGetOverridableInitializerCount, _In_ const OrtSession* session, _Out_ size_t* out); + + /** \brief Get input type information + * + * \param[in] session + * \param[in] index Must be between 0 (inclusive) and what OrtApi::SessionGetInputCount returns (exclusive) + * \param[out] type_info Must be freed with OrtApi::ReleaseTypeInfo + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SessionGetInputTypeInfo, _In_ const OrtSession* session, size_t index, _Outptr_ OrtTypeInfo** type_info); + + /** \brief Get output type information + * + * \param[in] session + * \param[in] index Must be between 0 (inclusive) and what OrtApi::SessionGetOutputCount returns (exclusive) + * \param[out] type_info Must be freed with OrtApi::ReleaseTypeInfo + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SessionGetOutputTypeInfo, _In_ const OrtSession* session, size_t index, _Outptr_ OrtTypeInfo** type_info); + + /** \brief Get overridable initializer type information + * + * \param[in] session + * \param[in] index Must be between 0 (inclusive) and what OrtApi::SessionGetOverridableInitializerCount returns (exclusive) + * \param[out] type_info Must be freed with OrtApi::ReleaseTypeInfo + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SessionGetOverridableInitializerTypeInfo, _In_ const OrtSession* session, size_t index, _Outptr_ OrtTypeInfo** type_info); + + /** \brief Get input name + * + * \param[in] session + * \param[in] index Must be between 0 (inclusive) and what OrtApi::SessionGetInputCount returns (exclusive) + * \param[in] allocator + * \param[out] value Set to a null terminated UTF-8 encoded string allocated using `allocator`. Must be freed using `allocator`. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SessionGetInputName, _In_ const OrtSession* session, size_t index, _Inout_ OrtAllocator* allocator, _Outptr_ char** value); + + /** \brief Get output name + * + * \param[in] session + * \param[in] index Must be between 0 (inclusive) and what OrtApi::SessionGetOutputCount returns (exclusive) + * \param[in] allocator + * \param[out] value Set to a null terminated UTF-8 encoded string allocated using `allocator`. Must be freed using `allocator`. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SessionGetOutputName, _In_ const OrtSession* session, size_t index, _Inout_ OrtAllocator* allocator, _Outptr_ char** value); + + /** \brief Get overridable initializer name + * + * \param[in] session + * \param[in] index Must be between 0 (inclusive) and what OrtApi::SessionGetOverridableInitializerCount returns (exclusive) + * \param[in] allocator + * \param[out] value Set to a null terminated UTF-8 encoded string allocated using `allocator`. Must be freed using `allocator`. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SessionGetOverridableInitializerName, _In_ const OrtSession* session, size_t index, + _Inout_ OrtAllocator* allocator, _Outptr_ char** value); + + /// @} + /// \name OrtRunOptions + /// @{ + + /** \brief Create an OrtRunOptions + * + * \param[out] out Returned newly created ::OrtRunOptions. Must be freed with OrtApi::ReleaseRunOptions + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateRunOptions, _Outptr_ OrtRunOptions** out); + + /** \brief Set per-run log verbosity level + * + * \see OrtApi::RunOptionsGetRunLogVerbosityLevel + * + * \param[in] options + * \param[in] log_verbosity_level \snippet{doc} snippets.dox Log Verbosity Level + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(RunOptionsSetRunLogVerbosityLevel, _Inout_ OrtRunOptions* options, int log_verbosity_level); + + /** \brief Set per-run log severity level + * + * \see OrtApi::RunOptionsGetRunLogSeverityLevel + * + * \param[in] options + * \param[in] log_severity_level The log severity level (refer to ::OrtLoggingLevel for possible values). + */ + ORT_API2_STATUS(RunOptionsSetRunLogSeverityLevel, _Inout_ OrtRunOptions* options, int log_severity_level); + + /** \brief Set per-run tag + * + * This is used in a per-run log identifier. + * + * \see OrtApi::RunOptionsGetRunTag + * + * \param[in] options + * \param[in] run_tag The run tag. + */ + ORT_API2_STATUS(RunOptionsSetRunTag, _Inout_ OrtRunOptions* options, _In_ const char* run_tag); + + /** \brief Get per-run log verbosity level + * + * \see OrtApi::RunOptionsSetRunLogVerbosityLevel + * + * \param[in] options + * \param[out] log_verbosity_level \snippet{doc} snippets.dox Log Verbosity Level + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(RunOptionsGetRunLogVerbosityLevel, _In_ const OrtRunOptions* options, + _Out_ int* log_verbosity_level); + + /** \brief Get per-run log severity level + * + * \see OrtApi::RunOptionsSetRunLogSeverityLevel + * + * \param[in] options + * \param[out] log_severity_level The log severity level (refer to ::OrtLoggingLevel for possible values). + */ + ORT_API2_STATUS(RunOptionsGetRunLogSeverityLevel, _In_ const OrtRunOptions* options, _Out_ int* log_severity_level); + + /** \brief Get per-run tag + * + * This is used in a per-run log identifier. + * + * \see OrtApi::RunOptionsSetRunTag + * + * \param[in] options + * \param[out] run_tag The run tag. + * Do not free this value, it is owned by `options`. It will be invalidated if the run tag + * changes (i.e., with OrtApi::RunOptionsSetRunTag) or `options` is freed. + */ + ORT_API2_STATUS(RunOptionsGetRunTag, _In_ const OrtRunOptions* options, _Out_ const char** run_tag); + + /** \brief Set terminate flag + * + * If a currently executing session needs to be force terminated, this can be called from another thread to force it to fail with an error. + * + * \param[in] options + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(RunOptionsSetTerminate, _Inout_ OrtRunOptions* options); + + /** \brief Clears the terminate flag + * + * Used so the OrtRunOptions instance can be used in a new OrtApi::Run call without it instantly terminating + * + * \param[in] options + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(RunOptionsUnsetTerminate, _Inout_ OrtRunOptions* options); + + /// @} + /// \name OrtValue + /// @{ + + /** \brief Create a tensor + * + * Create a tensor using a supplied ::OrtAllocator + * + * \param[in] allocator + * \param[in] shape Pointer to the tensor shape dimensions. + * \param[in] shape_len The number of tensor shape dimensions. + * \param[in] type + * \param[out] out Returns newly created ::OrtValue. Must be freed with OrtApi::ReleaseValue + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateTensorAsOrtValue, _Inout_ OrtAllocator* allocator, _In_ const int64_t* shape, size_t shape_len, + ONNXTensorElementDataType type, _Outptr_ OrtValue** out); + + /** \brief Create a tensor backed by a user supplied buffer + * + * Create a tensor with user's buffer. You can fill the buffer either before calling this function or after. + * p_data is owned by caller. ReleaseValue won't release p_data. + * + * \param[in] info Memory description of where the p_data buffer resides (CPU vs GPU etc). + * \param[in] p_data Pointer to the data buffer. + * \param[in] p_data_len The number of bytes in the data buffer. + * \param[in] shape Pointer to the tensor shape dimensions. + * \param[in] shape_len The number of tensor shape dimensions. + * \param[in] type The data type. + * \param[out] out Returns newly created ::OrtValue. Must be freed with OrtApi::ReleaseValue + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateTensorWithDataAsOrtValue, _In_ const OrtMemoryInfo* info, _Inout_ void* p_data, + size_t p_data_len, _In_ const int64_t* shape, size_t shape_len, ONNXTensorElementDataType type, + _Outptr_ OrtValue** out); + + /** \brief Return if an ::OrtValue is a tensor type + * + * \param[in] value A tensor type (string tensors are not supported) + * \param[out] out Set to 1 iff ::OrtValue is a tensor, 0 otherwise + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(IsTensor, _In_ const OrtValue* value, _Out_ int* out); + + /** \brief Get a pointer to the raw data inside a tensor + * + * Used to read/write/modify the internal tensor data directly. + * \note The returned pointer is valid until the \p value is destroyed. + * + * \param[in] value A tensor type (string tensors are not supported) + * \param[out] out Filled in with a pointer to the internal storage + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetTensorMutableData, _In_ OrtValue* value, _Outptr_ void** out); + + /** \brief Set all strings at once in a string tensor + * + * \param[in,out] value A tensor of type ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING + * \param[in] s An array of strings. Each string in this array must be null terminated. + * \param[in] s_len Count of strings in s (Must match the size of \p value's tensor shape) + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(FillStringTensor, _Inout_ OrtValue* value, _In_ const char* const* s, size_t s_len); + + /** \brief Get total byte length for all strings in a string tensor + * + * Typically used with OrtApi::GetStringTensorContent + * + * \param[in] value A tensor of type ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING + * \param[out] len Total byte length of all strings (does not include trailing nulls) + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetStringTensorDataLength, _In_ const OrtValue* value, _Out_ size_t* len); + + /** \brief Get all strings from a string tensor + * + * An example of the results:
+ * Given \p value is a string tensor with the strings { "This" "is" "a" "test" }
+ * \p s must have a size of 11 bytes
+ * \p offsets must have 4 elements
+ * After the call, these values will be filled in:
+ * \p s will contain "Thisisatest"
+ * \p offsets will contain { 0, 4, 6, 7 }
+ * The length of the last string is just s_len - offsets[last] + * + * \param[in] value A tensor of type ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING + * \param[in] s Buffer to sequentially write all tensor strings to. Each string is NOT null-terminated. + * \param[in] s_len Number of bytes of buffer pointed to by \p s (Get it from OrtApi::GetStringTensorDataLength) + * \param[out] offsets Array of start offsets into the strings written to \p s + * \param[in] offsets_len Number of elements in offsets + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetStringTensorContent, _In_ const OrtValue* value, _Out_writes_bytes_all_(s_len) void* s, + size_t s_len, _Out_writes_all_(offsets_len) size_t* offsets, size_t offsets_len); + + /// @} + /// \name OrtTypeInfo + /// @{ + + /** \brief Get ::OrtTensorTypeAndShapeInfo from an ::OrtTypeInfo + * + * \param[in] type_info + * \param[out] out Do not free this value, it will be valid until type_info is freed. + * If type_info does not represent tensor, this value will be set to nullptr. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CastTypeInfoToTensorInfo, _In_ const OrtTypeInfo* type_info, + _Outptr_result_maybenull_ const OrtTensorTypeAndShapeInfo** out); + + /** \brief Get ::ONNXType from ::OrtTypeInfo + * + * \param[in] type_info + * \param[out] out + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetOnnxTypeFromTypeInfo, _In_ const OrtTypeInfo* type_info, _Out_ enum ONNXType* out); + + /// @} + /// \name OrtTensorTypeAndShapeInfo + /// @{ + + /** \brief Create an ::OrtTensorTypeAndShapeInfo object + * + * \param[out] out Returns newly created ::OrtTensorTypeAndShapeInfo. Must be freed with OrtApi::ReleaseTensorTypeAndShapeInfo + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateTensorTypeAndShapeInfo, _Outptr_ OrtTensorTypeAndShapeInfo** out); + + /** \brief Set element type in ::OrtTensorTypeAndShapeInfo + * + * \param[in] info + * \param[in] type + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SetTensorElementType, _Inout_ OrtTensorTypeAndShapeInfo* info, enum ONNXTensorElementDataType type); + + /** \brief Set shape information in ::OrtTensorTypeAndShapeInfo + * + * \param[in] info + * \param[in] dim_values Array with `dim_count` elements. Can contain negative values. + * \param[in] dim_count Number of elements in `dim_values` + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SetDimensions, OrtTensorTypeAndShapeInfo* info, _In_ const int64_t* dim_values, size_t dim_count); + + /** \brief Get element type in ::OrtTensorTypeAndShapeInfo + * + * \see OrtApi::SetTensorElementType + * + * \param[in] info + * \param[out] out + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetTensorElementType, _In_ const OrtTensorTypeAndShapeInfo* info, + _Out_ enum ONNXTensorElementDataType* out); + + /** \brief Get dimension count in ::OrtTensorTypeAndShapeInfo + * + * \see OrtApi::GetDimensions + * + * \param[in] info + * \param[out] out + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetDimensionsCount, _In_ const OrtTensorTypeAndShapeInfo* info, _Out_ size_t* out); + + /** \brief Get dimensions in ::OrtTensorTypeAndShapeInfo + * + * \param[in] info + * \param[out] dim_values Array with `dim_values_length` elements. On return, filled with the dimensions stored in the ::OrtTensorTypeAndShapeInfo + * \param[in] dim_values_length Number of elements in `dim_values`. Use OrtApi::GetDimensionsCount to get this value + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetDimensions, _In_ const OrtTensorTypeAndShapeInfo* info, _Out_ int64_t* dim_values, + size_t dim_values_length); + + /** \brief Get symbolic dimension names in ::OrtTensorTypeAndShapeInfo + * + * \param[in] info + * \param[in] dim_params Array with `dim_params_length` elements. On return filled with pointers to null terminated strings of the dimension names + * \param[in] dim_params_length Number of elements in `dim_params`. Use OrtApi::GetDimensionsCount to get this value + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetSymbolicDimensions, _In_ const OrtTensorTypeAndShapeInfo* info, + _Out_writes_all_(dim_params_length) const char* dim_params[], size_t dim_params_length); + + /** \brief Get total number of elements in a tensor shape from an ::OrtTensorTypeAndShapeInfo + * + * Return the number of elements specified by the tensor shape (all dimensions multiplied by each other). + * For 0 dimensions, 1 is returned. If any dimension is less than 0, the result is always -1. + * + * Examples:
+ * [] = 1
+ * [1,3,4] = 12
+ * [2,0,4] = 0
+ * [-1,3,4] = -1
+ * + * \param[in] info + * \param[out] out Number of elements + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetTensorShapeElementCount, _In_ const OrtTensorTypeAndShapeInfo* info, _Out_ size_t* out); + + /// @} + /// \name OrtValue + /// @{ + + /** \brief Get type and shape information from a tensor ::OrtValue + * + * \param[in] value Must be a tensor (not a map/sequence/etc) or will return failure + * \param[out] out Newly created ::OrtTensorTypeAndShapeInfo. Must be freed with OrtApi::ReleaseTensorTypeAndShapeInfo + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetTensorTypeAndShape, _In_ const OrtValue* value, _Outptr_ OrtTensorTypeAndShapeInfo** out); + + /** \brief Get type information of an OrtValue + * + * \param[in] value + * \param[out] out Newly created ::OrtTypeInfo. Must be freed with OrtApi::ReleaseTypeInfo + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetTypeInfo, _In_ const OrtValue* value, _Outptr_result_maybenull_ OrtTypeInfo** out); + + /** \brief Get ONNXType of an ::OrtValue + * + * \param[in] value + * \param[out] out + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetValueType, _In_ const OrtValue* value, _Out_ enum ONNXType* out); + + /// @} + /// \name OrtMemoryInfo + /// @{ + + /** \brief Create an ::OrtMemoryInfo + * + * \param[in] name + * \param[in] type + * \param[in] id + * \param[in] mem_type + * \param[out] out Newly created ::OrtMemoryInfo. Must be freed with OrtAPi::ReleaseMemoryInfo + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateMemoryInfo, _In_ const char* name, enum OrtAllocatorType type, int id, + enum OrtMemType mem_type, _Outptr_ OrtMemoryInfo** out); + + /** \brief Create an ::OrtMemoryInfo for CPU memory + * + * Special case version of OrtApi::CreateMemoryInfo for CPU based memory. Same as using OrtApi::CreateMemoryInfo with name = "Cpu" and id = 0. + * + * \param[in] type + * \param[in] mem_type + * \param[out] out + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateCpuMemoryInfo, enum OrtAllocatorType type, enum OrtMemType mem_type, + _Outptr_ OrtMemoryInfo** out); + + /** \brief Compare ::OrtMemoryInfo objects for equality + * + * Compares all settings of each ::OrtMemoryInfo for equality + * + * \param[in] info1 + * \param[in] info2 + * \param[out] out Set to 0 if equal, -1 if not equal + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CompareMemoryInfo, _In_ const OrtMemoryInfo* info1, _In_ const OrtMemoryInfo* info2, _Out_ int* out); + + /** \brief Get name from ::OrtMemoryInfo + * + * \param[in] ptr + * \param[out] out Writes null terminated string to this pointer. Do NOT free the returned pointer. It is valid for the lifetime of the ::OrtMemoryInfo + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(MemoryInfoGetName, _In_ const OrtMemoryInfo* ptr, _Out_ const char** out); + + /** \brief Get the id from ::OrtMemoryInfo + */ + ORT_API2_STATUS(MemoryInfoGetId, _In_ const OrtMemoryInfo* ptr, _Out_ int* out); + + /** \brief Get the ::OrtMemType from ::OrtMemoryInfo + */ + ORT_API2_STATUS(MemoryInfoGetMemType, _In_ const OrtMemoryInfo* ptr, _Out_ OrtMemType* out); + + /** \brief Get the ::OrtAllocatorType from ::OrtMemoryInfo + */ + ORT_API2_STATUS(MemoryInfoGetType, _In_ const OrtMemoryInfo* ptr, _Out_ OrtAllocatorType* out); + + /// @} + /// \name OrtAllocator + /// @{ + + /// \brief Calls OrtAllocator::Alloc function + ORT_API2_STATUS(AllocatorAlloc, _Inout_ OrtAllocator* ort_allocator, size_t size, _Outptr_ void** out); + /// \brief Calls OrtAllocator::Free function + ORT_API2_STATUS(AllocatorFree, _Inout_ OrtAllocator* ort_allocator, void* p); + /// \brief Calls OrtAllocator::Info function + ORT_API2_STATUS(AllocatorGetInfo, _In_ const OrtAllocator* ort_allocator, _Outptr_ const struct OrtMemoryInfo** out); + + /** \brief Get the default allocator + * + * The default allocator is a CPU based, non-arena. Always returns the same pointer to the same default allocator. + * + * \param[out] out Returned value should NOT be freed + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetAllocatorWithDefaultOptions, _Outptr_ OrtAllocator** out); + + /// @} + /// \name OrtSessionOptions + /// @{ + + /** \brief Override session symbolic dimensions + * + * Override symbolic dimensions (by specific denotation strings) with actual values if known at session initialization time to enable + * optimizations that can take advantage of fixed values (such as memory planning, etc) + * + * \param[in] options + * \param[in] dim_denotation + * \param[in] dim_value + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(AddFreeDimensionOverride, _Inout_ OrtSessionOptions* options, _In_ const char* dim_denotation, + _In_ int64_t dim_value); + + /// @} + /// \name OrtValue + /// @{ + + /* Internal information (not seen in Doxygen) + * + * APIs to support non-tensor types - map and sequence. + * Currently only the following types are supported + * Note: the following types should be kept in sync with data_types.h + * Map types + * ========= + * std::map + * std::map + * std::map + * std::map + * std::map + * std::map + * std::map + * std::map + * + * Sequence types + * ============== + * std::vector + * std::vector + * std::vector + * std::vector + * std::vector> + * std::vector + */ + + /** \brief Get non tensor data from an ::OrtValue + * + * If `value` is of type ONNX_TYPE_MAP, you need to retrieve the keys and values + * separately. Use index=0 to retrieve keys and index=1 to retrieve values. + * If `value` is of type ONNX_TYPE_SEQUENCE, use index to retrieve the index'th element + * of the sequence. + * + * \param[in] value + * \param[in] index See above for usage based on `value` type + * \param[in] allocator Allocator used to allocate ::OrtValue + * \param[out] out Created ::OrtValue that holds the element requested. Must be freed with OrtApi::ReleaseValue + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetValue, _In_ const OrtValue* value, int index, _Inout_ OrtAllocator* allocator, + _Outptr_ OrtValue** out); + + /** \brief Get non tensor value count from an ::OrtValue + * + * If `value` is of type ONNX_TYPE_MAP 2 will always be returned. For ONNX_TYPE_SEQUENCE + * the number of elements in the sequence will be returned + * + * \param[in] value + * \param[out] out + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetValueCount, _In_ const OrtValue* value, _Out_ size_t* out); + + /** \brief Create a map or sequence ::OrtValue + * + * To construct a map (ONNX_TYPE_MAP), use num_values = 2 and `in` should be an array of 2 ::OrtValue%s + * representing keys and values.
+ * + * To construct a sequence (ONNX_TYPE_SEQUENCE), use num_values = N where N is the number of the elements in the + * sequence. 'in' should be an array of N ::OrtValue%s. + * + * \param[in] in See above for details + * \param[in] num_values + * \param[in] value_type Must be either ONNX_TYPE_MAP or ONNX_TYPE_SEQUENCE + * \param[out] out Newly created ::OrtValue. Must be freed with OrtApi::ReleaseValue + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateValue, _In_reads_(num_values) const OrtValue* const* in, size_t num_values, + enum ONNXType value_type, _Outptr_ OrtValue** out); + + /** \brief Create an opaque (custom user defined type) ::OrtValue + * + * Constructs an ::OrtValue that contains a value of non-standard type created for + * experiments or while awaiting standardization. ::OrtValue in this case would contain + * an internal representation of the Opaque type. Opaque types are distinguished from + * each other by two strings 1) domain and 2) type name. The combination of the two + * must be unique, so the type representation is properly identified internally. The combination + * must be properly registered from within ORT at both compile/run time or by another API. + * + * To construct the ::OrtValue pass domain and type names, also a pointer to a data container + * the type of which must be known to both ORT and the client program. That data container may or may + * not match the internal representation of the Opaque type. The sizeof(data_container) is passed for + * verification purposes. + * + * \param[in] domain_name Null terminated string of the domain name + * \param[in] type_name Null terminated string of the type name + * \param[in] data_container User pointer Data to populate ::OrtValue + * \param[in] data_container_size Size in bytes of what `data_container` points to + * \param[out] out Newly created ::OrtValue. Must be freed with OrtApi::ReleaseValue + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateOpaqueValue, _In_z_ const char* domain_name, _In_z_ const char* type_name, + _In_ const void* data_container, size_t data_container_size, _Outptr_ OrtValue** out); + + /** \brief Get internal data from an opaque (custom user defined type) ::OrtValue + * + * Copies internal data from an opaque value into a user provided buffer + * + * \see OrtApi::CreateOpaqueValue + * + * \param[in] domain_name Null terminated string of the domain name + * \param[in] type_name Null terminated string of the type name + * \param[in] in The opaque ::OrtValue + * \param[out] data_container Buffer to copy data into + * \param[out] data_container_size Size in bytes of the buffer pointed to by data_container. Must match the size of the internal buffer. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetOpaqueValue, _In_ const char* domain_name, _In_ const char* type_name, _In_ const OrtValue* in, + _Out_ void* data_container, size_t data_container_size); + + /// @} + /// \name OrtKernelInfo + /// Custom operator APIs. + /// @{ + + /** \brief Get a float stored as an attribute in the graph node + * + * \param[in] info ::OrtKernelInfo instance + * \param[in] name Null terminated string of the name of the attribute + * \param[out] out Pointer to memory where the attribute will be stored + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(KernelInfoGetAttribute_float, _In_ const OrtKernelInfo* info, _In_ const char* name, + _Out_ float* out); + + /** \brief Fetch a 64-bit int stored as an attribute in the graph node + * + * \param[in] info ::OrtKernelInfo instance + * \param[in] name Null terminated string of the name of the attribute + * \param[out] out Pointer to memory where the attribute will be stored + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(KernelInfoGetAttribute_int64, _In_ const OrtKernelInfo* info, _In_ const char* name, + _Out_ int64_t* out); + + /** \brief Fetch a string stored as an attribute in the graph node + * + * If `out` is nullptr, the value of `size` is set to the true size of the string + * attribute, and a success status is returned. + * + * If the `size` parameter is greater than or equal to the actual string attribute's size, + * the value of `size` is set to the true size of the string attribute, the provided memory + * is filled with the attribute's contents, and a success status is returned. + * + * If the `size` parameter is less than the actual string attribute's size and `out` + * is not nullptr, the value of `size` is set to the true size of the string attribute + * and a failure status is returned.) + * + * \param[in] info ::OrtKernelInfo instance + * \param[in] name Null terminated string of the name of the attribute + * \param[out] out Pointer to memory where the attribute will be stored + * \param[in,out] size See above comments for details + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(KernelInfoGetAttribute_string, _In_ const OrtKernelInfo* info, _In_ const char* name, _Out_ char* out, + _Inout_ size_t* size); + + /// @} + /// \name OrtKernelContext + /// Custom operator APIs. + /// @{ + + /** \brief Used for custom operators, get the input count of a kernel + * + * \see ::OrtCustomOp + */ + ORT_API2_STATUS(KernelContext_GetInputCount, _In_ const OrtKernelContext* context, _Out_ size_t* out); + + /** \brief Used for custom operators, get the output count of a kernel + * + * \see ::OrtCustomOp + */ + ORT_API2_STATUS(KernelContext_GetOutputCount, _In_ const OrtKernelContext* context, _Out_ size_t* out); + + /** \brief Used for custom operators, get an input of a kernel + * + * \see ::OrtCustomOp + */ + ORT_API2_STATUS(KernelContext_GetInput, _In_ const OrtKernelContext* context, _In_ size_t index, + _Out_ const OrtValue** out); + + /** \brief Used for custom operators, get an output of a kernel + * + * \see ::OrtCustomOp + */ + ORT_API2_STATUS(KernelContext_GetOutput, _Inout_ OrtKernelContext* context, _In_ size_t index, + _In_ const int64_t* dim_values, size_t dim_count, _Outptr_ OrtValue** out); + + /// @} + /// \name OrtEnv + /// @{ + ORT_CLASS_RELEASE(Env); + /// @} + /// \name OrtStatus + /// @{ + ORT_CLASS_RELEASE(Status); + /// @} + /// \name OrtMemoryInfo + /// @{ + ORT_CLASS_RELEASE(MemoryInfo); + /// @} + /// \name OrtSession + /// @{ + ORT_CLASS_RELEASE(Session); // Don't call ReleaseSession from Dllmain (because session owns a thread pool) + /// @} + /// \name OrtValue + /// @{ + ORT_CLASS_RELEASE(Value); + /// @} + /// \name OrtRunOptions + /// @{ + ORT_CLASS_RELEASE(RunOptions); + /// @} + /// \name OrtTypeInfo + /// @{ + ORT_CLASS_RELEASE(TypeInfo); + /// @} + /// \name OrtTensorTypeAndShapeInfo + /// @{ + ORT_CLASS_RELEASE(TensorTypeAndShapeInfo); + /// @} + /// \name OrtSessionOptions + /// @{ + ORT_CLASS_RELEASE(SessionOptions); + /// @} + /// \name OrtCustomOpDomain + /// @{ + ORT_CLASS_RELEASE(CustomOpDomain); + + /// @} + /// \name OrtTypeInfo + /// @{ + + /** \brief Get denotation from type information + * + * Augments ::OrtTypeInfo to return denotations on the type. + * + * This is used by WinML to determine if an input/output is intended to be an Image or a Tensor. + * + * \param[in] type_info + * \param[out] denotation Pointer to the null terminated denotation string is written to this pointer. This pointer is valid until the object is destroyed or the name is changed, do not free. + * \param[out] len Length in bytes of the string returned in `denotation` + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetDenotationFromTypeInfo, _In_ const OrtTypeInfo* type_info, _Out_ const char** const denotation, + _Out_ size_t* len); + + /** \brief Get detailed map information from an ::OrtTypeInfo + * + * This augments ::OrtTypeInfo to return an ::OrtMapTypeInfo when the type is a map. + * The OrtMapTypeInfo has additional information about the map's key type and value type. + * + * This is used by WinML to support model reflection APIs. + * + * \param[out] type_info + * \param[out] out A pointer to the ::OrtMapTypeInfo. Do not free this value. If type_info + * does not contain a map, this value will be set to nullptr. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CastTypeInfoToMapTypeInfo, _In_ const OrtTypeInfo* type_info, + _Outptr_result_maybenull_ const OrtMapTypeInfo** out); + + /** \brief Cast ::OrtTypeInfo to an ::OrtSequenceTypeInfo + * + * This api augments ::OrtTypeInfo to return an ::OrtSequenceTypeInfo when the type is a sequence. + * The ::OrtSequenceTypeInfo has additional information about the sequence's element type. + * + * This is used by WinML to support model reflection APIs. + * + * \param[in] type_info + * \param[out] out A pointer to the OrtSequenceTypeInfo. Do not free this value. If type_info + * doesn not contain a sequence, this value will be set to nullptr. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CastTypeInfoToSequenceTypeInfo, _In_ const OrtTypeInfo* type_info, + _Outptr_result_maybenull_ const OrtSequenceTypeInfo** out); + + /// @} + /// \name OrtMapTypeInfo + /// @{ + + /** \brief Get key type from an ::OrtMapTypeInfo + * + * Key types are restricted to being scalar types. + * + * This is used by WinML to support model reflection APIs. + * + * \param[in] map_type_info + * \param[out] out + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetMapKeyType, _In_ const OrtMapTypeInfo* map_type_info, _Out_ enum ONNXTensorElementDataType* out); + + /** \brief Get the value type from an ::OrtMapTypeInfo + * + * \param[in] map_type_info + * \param[out] type_info + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetMapValueType, _In_ const OrtMapTypeInfo* map_type_info, _Outptr_ OrtTypeInfo** type_info); + + /// @} + /// \name OrtSequenceTypeInfo + /// @{ + + /** \brief Get element type from an ::OrtSequenceTypeInfo + * + * This is used by WinML to support model reflection APIs. + * + * \param[in] sequence_type_info + * \param[out] type_info + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetSequenceElementType, _In_ const OrtSequenceTypeInfo* sequence_type_info, + _Outptr_ OrtTypeInfo** type_info); + + /// @} + /// \name OrtMapTypeInfo + /// @{ + ORT_CLASS_RELEASE(MapTypeInfo); + /// @} + /// \name OrtSequenceTypeInfo + /// @{ + ORT_CLASS_RELEASE(SequenceTypeInfo); + + /// @} + /// \name OrtSession + /// @{ + + /** \brief End profiling and return filename of the profile data + * + * Profiling is turned on through OrtApi::EnableProfiling + * + * \param[in] session + * \param[in] allocator + * \param[out] out Null terminated string of the filename, allocated using `allocator`. Must be freed using `allocator` + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SessionEndProfiling, _In_ OrtSession* session, _Inout_ OrtAllocator* allocator, _Outptr_ char** out); + + /** \brief Get ::OrtModelMetadata from an ::OrtSession + * + * \param[in] session + * \param[out] out Newly created ::OrtModelMetadata. Must be freed using OrtApi::ReleaseModelMetadata + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SessionGetModelMetadata, _In_ const OrtSession* session, _Outptr_ OrtModelMetadata** out); + + /// @} + /// \name OrtModelMetadata + /// @{ + + /** \brief Get `producer name` from an ::OrtModelMetadata + * + * \param[in] model_metadata + * \param[in] allocator + * \param[out] value Set to a null terminated string allocated using `allocator`. Must be freed using `allocator` + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(ModelMetadataGetProducerName, _In_ const OrtModelMetadata* model_metadata, + _Inout_ OrtAllocator* allocator, _Outptr_ char** value); + + /** \brief Get `graph name` from an ::OrtModelMetadata + * + * \param[in] model_metadata + * \param[in] allocator + * \param[out] value Set to a null terminated string allocated using `allocator`. Must be freed using `allocator` + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(ModelMetadataGetGraphName, _In_ const OrtModelMetadata* model_metadata, + _Inout_ OrtAllocator* allocator, _Outptr_ char** value); + + /** \brief Get `domain` from an ::OrtModelMetadata + * + * \param[in] model_metadata + * \param[in] allocator + * \param[out] value Set to a null terminated string allocated using `allocator`. Must be freed using `allocator` + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(ModelMetadataGetDomain, _In_ const OrtModelMetadata* model_metadata, _Inout_ OrtAllocator* allocator, + _Outptr_ char** value); + + /** \brief Get `description` from an ::OrtModelMetadata + * + * \param[in] model_metadata + * \param[in] allocator + * \param[out] value Set to a null terminated string allocated using `allocator`. Must be freed using `allocator` + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(ModelMetadataGetDescription, _In_ const OrtModelMetadata* model_metadata, + _Inout_ OrtAllocator* allocator, _Outptr_ char** value); + + /** \brief Return data for a key in the custom metadata map in an ::OrtModelMetadata + * + * \param[in] model_metadata + * \param[in] allocator + * \param[in] key Null terminated string + * \param[out] value Set to a null terminated string allocated using `allocator`. Must be freed using `allocator` + * `value` will be set to nullptr if the given key is not found in the custom metadata map. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(ModelMetadataLookupCustomMetadataMap, _In_ const OrtModelMetadata* model_metadata, + _Inout_ OrtAllocator* allocator, _In_ const char* key, _Outptr_result_maybenull_ char** value); + + /** \brief Get version number from an ::OrtModelMetadata + * + * \param[in] model_metadata + * \param[out] value Set to the version number + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(ModelMetadataGetVersion, _In_ const OrtModelMetadata* model_metadata, _Out_ int64_t* value); + + ORT_CLASS_RELEASE(ModelMetadata); + + /// @} + /// \name OrtEnv + /// @{ + + /** \brief Create an OrtEnv + * + * Create an environment with global threadpools that will be shared across sessions. + * Use this in conjunction with OrtApi::DisablePerSessionThreads or else the session will use + * its own thread pools. + * + * \param[in] log_severity_level The log severity level. + * \param[in] logid The log identifier. + * \param[in] tp_options + * \param[out] out Returned newly created OrtEnv. Must be freed with OrtApi::ReleaseEnv + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateEnvWithGlobalThreadPools, OrtLoggingLevel log_severity_level, _In_ const char* logid, + _In_ const OrtThreadingOptions* tp_options, _Outptr_ OrtEnv** out); + + /// @} + /// \name OrtSessionOptions + /// @{ + + /** \brief Use global thread pool on a session + * + * Disable using per session thread pool and use the shared global threadpool. + * This should be used in conjunction with OrtApi::CreateEnvWithGlobalThreadPools. + * + * \param[in] options + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(DisablePerSessionThreads, _Inout_ OrtSessionOptions* options); + + /// @} + /// \name OrtThreadingOptions + /// @{ + + /** \brief Create an ::OrtThreadingOptions + * + * \param[out] out Newly created ::OrtThreadingOptions. Must be freed with OrtApi::ReleaseThreadingOptions + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateThreadingOptions, _Outptr_ OrtThreadingOptions** out); + + ORT_CLASS_RELEASE(ThreadingOptions); + + /// @} + /// \name OrtModelMetadata + /// @{ + + /** + * + * \param[in] model_metadata + * \param[in] allocator + * \param[out] keys Array of null terminated strings (array count = num_keys) allocated using `allocator`. + * The strings and the pointer array must be freed using `allocator` + * `keys` will be set to nullptr if the custom metadata map is empty. + * \param[out] num_keys Set to the number of elements in the `keys` array + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(ModelMetadataGetCustomMetadataMapKeys, _In_ const OrtModelMetadata* model_metadata, + _Inout_ OrtAllocator* allocator, _Outptr_result_buffer_maybenull_(*num_keys) char*** keys, _Out_ int64_t* num_keys); + + /// @} + /// \name OrtSessionOptions + /// @{ + + /** + * + * Override symbolic dimensions (by specific name strings) with actual values + * if known at session initialization time to enable optimizations that can + * take advantage of fixed values (such as memory planning, etc) + * + */ + ORT_API2_STATUS(AddFreeDimensionOverrideByName, + _Inout_ OrtSessionOptions* options, _In_ const char* dim_name, + _In_ int64_t dim_value); + + /// @} + /// \name Misc + /// @{ + + /** \brief Get the names of all available providers + * + * \note The providers in the list are not guaranteed to be usable. They may fail to load due to missing system dependencies. + * For example, if the CUDA/cuDNN libraries are not installed, the CUDA provider will report an error when it is added to the session options. + * + * \param[out] out_ptr Set to a pointer to an array of null terminated strings of the available providers. The entries and the + * array itself must be freed using OrtApi::ReleaseAvailableProviders + * \param[out] provider_length Set to the number of entries in the `out_ptr` array + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetAvailableProviders, _Outptr_ char*** out_ptr, _Out_ int* provider_length); + + /** \brief Release data from OrtApi::GetAvailableProviders. This API will never fail + * so you can rely on it in a noexcept code. + * + * \param[in] ptr The `out_ptr` result from OrtApi::GetAvailableProviders. + * \param[in] providers_length The `provider_length` result from OrtApi::GetAvailableProviders + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(ReleaseAvailableProviders, _In_ char** ptr, + _In_ int providers_length); + + /// @} + /// \name OrtValue + /// @{ + + /** \brief Get the length of a single string in a string tensor + * + * \param[in] value A string tensor + * \param[in] index Index of the string in the tensor + * \param[out] out Set to number of bytes of the string element + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetStringTensorElementLength, _In_ const OrtValue* value, size_t index, _Out_ size_t* out); + + /** \brief Get a single string from a string tensor + * + * \param[in] value A string tensor + * \param[in] s_len Number of bytes in the `s` buffer. Must match the value returned by OrtApi::GetStringTensorElementLength. + * \param[in] index Index of the string in the tensor + * \param[out] s The string element contents in UTF-8 encoding. The string is NOT null-terminated. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetStringTensorElement, _In_ const OrtValue* value, size_t s_len, size_t index, _Out_writes_bytes_all_(s_len) void* s); + + /** \brief Set a single string in a string tensor + * + * \param[in] value A string tensor + * \param[in] s A null terminated UTF-8 encoded string + * \param[in] index Index of the string in the tensor to set + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(FillStringTensorElement, _Inout_ OrtValue* value, _In_ const char* s, size_t index); + + /// @} + /// \name OrtSessionOptions + /// @{ + + /** \brief Set a session configuration entry as a pair of strings + * + * If a configuration with same key exists, this will overwrite the configuration with the given config_value. + * + * The config_key and the format of config_value are defined in onnxruntime_session_options_config_keys.h + * + * \param[in] options + * \param[in] config_key A null terminated string representation of the config key + * \param[in] config_value A null terminated string representation of the config value + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(AddSessionConfigEntry, _Inout_ OrtSessionOptions* options, + _In_z_ const char* config_key, _In_z_ const char* config_value); + + /// @} + /// \name OrtAllocator + /// @{ + + /** \brief Create an allocator for an ::OrtSession following an ::OrtMemoryInfo + * + * \param[in] session + * \param[in] mem_info valid ::OrtMemoryInfo instance + * \param[out] out Newly created ::OrtAllocator. Must be freed with OrtApi::ReleaseAllocator + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateAllocator, _In_ const OrtSession* session, _In_ const OrtMemoryInfo* mem_info, + _Outptr_ OrtAllocator** out); + + /** \brief Release an ::OrtAllocator obtained from OrtApi::CreateAllocator + */ + ORT_CLASS_RELEASE(Allocator); + + /// @} + /// \name OrtSession + /// @{ + + /** \brief Run a model using Io Bindings for the inputs & outputs + * + * \see OrtApi::Run + * + * \param[in] session + * \param[in] run_options + * \param[in] binding_ptr + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(RunWithBinding, _Inout_ OrtSession* session, _In_ const OrtRunOptions* run_options, _In_ const OrtIoBinding* binding_ptr); + + /** \brief Create an ::OrtIoBinding instance + * + * An IoBinding object allows one to bind pre-allocated ::OrtValue%s to input names. + * Thus if you want to use a raw on device buffer as input or output you can avoid + * extra copy during runtime. + * + * \param[in] session + * \param[out] out Newly created ::OrtIoBinding. Must be freed with OrtApi::ReleaseIoBinding + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateIoBinding, _Inout_ OrtSession* session, _Outptr_ OrtIoBinding** out); + + /// @} + /// \name OrtIoBinding + /// @{ + + /** \brief Release an ::OrtIoBinding obtained from OrtApi::CreateIoBinding + */ + ORT_CLASS_RELEASE(IoBinding); + + /** \brief Bind an ::OrtValue to an ::OrtIoBinding input + * + * When using OrtApi::RunWithBinding this value is used for the named input + * + * \param[in] binding_ptr + * \param[in] name Name for the model input + * \param[in] val_ptr ::OrtValue of Tensor type. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(BindInput, _Inout_ OrtIoBinding* binding_ptr, _In_ const char* name, _In_ const OrtValue* val_ptr); + + /** \brief Bind an ::OrtValue to an ::OrtIoBinding output + * + * When using OrtApi::RunWithBinding this value is used for the named output + * + * \param[in] binding_ptr + * \param[in] name Null terminated string of the model output name + * \param[in] val_ptr ::OrtValue of Tensor type. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(BindOutput, _Inout_ OrtIoBinding* binding_ptr, _In_ const char* name, _In_ const OrtValue* val_ptr); + + /** \brief Bind an ::OrtIoBinding output to a device + * + * Binds the ::OrtValue to a device which is specified by ::OrtMemoryInfo. + * You can either create an instance of ::OrtMemoryInfo with a device id or obtain one from the allocator that you have created/are using + * This is useful when one or more outputs have dynamic shapes and, it is hard to pre-allocate and bind a chunk of + * memory within ::OrtValue ahead of time. + * + * \see OrtApi::RunWithBinding + * + * \param[in] binding_ptr + * \param[in] name Null terminated string of the device name + * \param[in] mem_info_ptr + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(BindOutputToDevice, _Inout_ OrtIoBinding* binding_ptr, _In_ const char* name, _In_ const OrtMemoryInfo* mem_info_ptr); + + /** \brief Get the names of an ::OrtIoBinding's outputs + * + * Returns the names of the outputs in the order they were bound. This is useful after running the model + * with bound outputs because the returned names are in order in which output ::OrtValue are returned. This is useful if + * the order of outputs and their names is not known. + * + * \param[in] binding_ptr + * \param[in] allocator Allocator used to allocate continuous buffers for output strings and lengths. + * \param[out] buffer Returns an array of non-null terminated UTF-8 strings. The number of strings stored is returned in the count parameter. + * This buffer is allocated using `allocator` and must be freed using it. + * \param[out] lengths Returns an array of `count` lengths of the strings returned in `buffer` + * This buffer is allocated using `allocator` and must be freed using it. + * \param[out] count Number of strings returned. If `binding_ptr` has no bound outputs, zero is returned, + * no memory allocation is performed and buffer and lengths are set to nullptr. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetBoundOutputNames, _In_ const OrtIoBinding* binding_ptr, _In_ OrtAllocator* allocator, + _Out_ char** buffer, _Out_writes_all_(count) size_t** lengths, _Out_ size_t* count); + + /** \brief Get the output ::OrtValue objects from an ::OrtIoBinding + * + * Returns an array of pointers to individually allocated ::OrtValue%s that contain results of a model execution with OrtApi::RunWithBinding + * The array contains the same number of ::OrtValue%s and they are in the same order as they were bound with OrtApi::BindOutput + * or OrtApi::BindOutputToDevice. + * + * The returned ::OrtValue%s must be released using OrtApi::ReleaseValue after they are no longer needed. + * The array is allocated using the specified instance of the allocator and must be freed using the same allocator after + * all the ::OrtValue%s contained therein are individually released. + * + * \param[in] binding_ptr + * \param[in] allocator Allocator used to allocate output array + * \param[out] output Set to the allocated array of allocated ::OrtValue outputs. Set to nullptr if there are 0 outputs. + * \param[out] output_count Set to number of ::OrtValue%s returned + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetBoundOutputValues, _In_ const OrtIoBinding* binding_ptr, _In_ OrtAllocator* allocator, + _Out_writes_all_(output_count) OrtValue*** output, _Out_ size_t* output_count); + + /** \brief Clears any previously set Inputs for an ::OrtIoBinding + */ + void(ORT_API_CALL* ClearBoundInputs)(_Inout_ OrtIoBinding* binding_ptr) NO_EXCEPTION ORT_ALL_ARGS_NONNULL; + + /** \brief Clears any previously set Outputs for an ::OrtIoBinding + */ + void(ORT_API_CALL* ClearBoundOutputs)(_Inout_ OrtIoBinding* binding_ptr) NO_EXCEPTION ORT_ALL_ARGS_NONNULL; + + /// @} + /// \name OrtValue + /// @{ + + /** \brief Direct memory access to a specified tensor element + * + * For example, given a tensor with shape of [3,224,224], a pointer to the element at location [2,150,128] can be retrieved + * + * This function only works for numeric type tensors (No strings, etc). + * This is a no-copy method whose returned pointer is valid until the passed in ::OrtValue is free'd. + * + * \param[in] value + * \param[in] location_values Pointer to an array of index values that specify an element's location relative to its shape + * \param[in] location_values_count Number of elements in location_values. Must match the number of elements in the tensor's shape. + * \param[out] out Set to a pointer to the element specified + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(TensorAt, _Inout_ OrtValue* value, const int64_t* location_values, size_t location_values_count, _Outptr_ void** out); + + /// @} + /// \name OrtEnv + /// @{ + + /** \brief Create an allocator and register it with the ::OrtEnv + * + * Enables sharing the allocator between multiple sessions that use the same env instance. + * Lifetime of the created allocator will be valid for the duration of the environment. + * Returns an error if an allocator with the same ::OrtMemoryInfo is already registered. + * + * See https://onnxruntime.ai/docs/get-started/with-c.html for details. + * + * \param[in] env ::OrtEnv instance + * \param[in] mem_info + * \param[in] arena_cfg Pass nullptr for defaults + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateAndRegisterAllocator, _Inout_ OrtEnv* env, _In_ const OrtMemoryInfo* mem_info, + _In_ const OrtArenaCfg* arena_cfg); + + /** \brief Set language projection + * + * Set the language projection for collecting telemetry data when Env is created. + * + * The default is ORT_PROJECTION_C, which means it will classify the language not in the list to C also. + * + * \param[in] ort_env + * \param[in] projection + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SetLanguageProjection, _In_ const OrtEnv* ort_env, _In_ OrtLanguageProjection projection); + + /// @} + /// \name OrtSession + /// @{ + + /** \brief Return the time that profiling was started + * + * \note The timer precision varies per platform. On Windows and MacOS, the precision will be ~100ns + * + * \param[in] session + * \param[out] out nanoseconds of profiling's start time + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SessionGetProfilingStartTimeNs, _In_ const OrtSession* session, _Outptr_ uint64_t* out); + + /// @} + /// \name OrtThreadingOptions + /// @{ + + /** \brief Set global intra-op thread count + * + * This configures the global thread pool options to be used in the call to OrtApi::CreateEnvWithGlobalThreadPools + * + * \param[in] tp_options + * \param[in] intra_op_num_threads Number of threads, special values:
+ * 0 = Use default thread count
+ * 1 = The invoking thread will be used; no threads will be created in the thread pool. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SetGlobalIntraOpNumThreads, _Inout_ OrtThreadingOptions* tp_options, int intra_op_num_threads); + + /** \brief Set global inter-op thread count + * + * This configures the global thread pool options to be used in the call to OrtApi::CreateEnvWithGlobalThreadPools + * + * \param[in] tp_options + * \param[in] inter_op_num_threads Number of threads, special values:
+ * 0 = Use default thread count
+ * 1 = The invoking thread will be used; no threads will be created in the thread pool. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SetGlobalInterOpNumThreads, _Inout_ OrtThreadingOptions* tp_options, int inter_op_num_threads); + + /** \brief Set global spin control options + * + * This will configure the global thread pool options to be used in the call to OrtApi::CreateEnvWithGlobalThreadPools. + * Allow spinning of thread pools when their queues are empty. This will set the value for both + * inter_op and intra_op threadpools. + * + * \param[in] tp_options + * \param[in] allow_spinning Valid values are 0 or 1.
+ * 0 = It won't spin (recommended if CPU usage is high)
+ * 1 = Threadpool will spin to wait for queue to become non-empty + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SetGlobalSpinControl, _Inout_ OrtThreadingOptions* tp_options, int allow_spinning); + + /// @} + /// \name OrtSessionOptions + /// @{ + + /** \brief Add a pre-allocated initializer to a session + * + * If a model contains an initializer with a name that is same as the name passed to this call, + * ORT will use this initializer instance instead of deserializing one from the model file. This + * is useful when you want to share the same initializer across sessions. + * + * \param[in] options + * \param[in] name Null terminated string of the initializer name + * \param[in] val ::OrtValue containing the initializer. Its lifetime and the underlying initializer buffer must be + * managed by the user (created using the OrtApi::CreateTensorWithDataAsOrtValue) and it must outlive the session object + * to which it is added. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(AddInitializer, _Inout_ OrtSessionOptions* options, _In_z_ const char* name, + _In_ const OrtValue* val); + + /// @} + /// \name OrtEnv + /// @{ + + /** + * Create a custom environment with global threadpools and logger that will be shared across sessions. + * Use this in conjunction with OrtApi::DisablePerSessionThreads or else the session will use + * its own thread pools. + * + * \param[in] logging_function A pointer to a logging function. + * \param[in] logger_param A pointer to arbitrary data passed as the ::OrtLoggingFunction `param` parameter to + * `logging_function`. + * \param[in] log_severity_level The log severity level. + * \param[in] logid The log identifier. + * \param[in] tp_options + * \param[out] out Newly created OrtEnv. Must be freed with OrtApi::ReleaseEnv + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateEnvWithCustomLoggerAndGlobalThreadPools, OrtLoggingFunction logging_function, _In_opt_ void* logger_param, OrtLoggingLevel log_severity_level, + _In_ const char* logid, _In_ const struct OrtThreadingOptions* tp_options, _Outptr_ OrtEnv** out); + + /// @} + /// \name OrtSessionOptions + /// @{ + + /** \brief Append CUDA provider to session options + * + * If CUDA is not available (due to a non CUDA enabled build, or if CUDA is not installed on the system), this function will return failure. + * + * \param[in] options + * \param[in] cuda_options + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SessionOptionsAppendExecutionProvider_CUDA, + _In_ OrtSessionOptions* options, _In_ const OrtCUDAProviderOptions* cuda_options); + + /** \brief Append ROCM execution provider to the session options + * + * If ROCM is not available (due to a non ROCM enabled build, or if ROCM is not installed on the system), this function will return failure. + * + * \param[in] options + * \param[in] rocm_options + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SessionOptionsAppendExecutionProvider_ROCM, + _In_ OrtSessionOptions* options, _In_ const OrtROCMProviderOptions* rocm_options); + + /** \brief Append OpenVINO execution provider to the session options + * + * If OpenVINO is not available (due to a non OpenVINO enabled build, or if OpenVINO is not installed on the system), this function will fail. + * + * \param[in] options + * \param[in] provider_options + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SessionOptionsAppendExecutionProvider_OpenVINO, + _In_ OrtSessionOptions* options, _In_ const OrtOpenVINOProviderOptions* provider_options); + + /// @} + /// \name OrtThreadingOptions + /// @{ + + /** \brief Set threading flush-to-zero and denormal-as-zero + * + * Sets global thread pool options to be used in the call to OrtApi::CreateEnvWithGlobalThreadPools. + * Flush-to-zero and denormal-as-zero are applied to threads in both intra and inter global thread pool. + * \note This option is not needed if the models used have no denormals. Having no denormals is recommended as this option may hurt model accuracy. + * + * \param[in] tp_options + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SetGlobalDenormalAsZero, _Inout_ OrtThreadingOptions* tp_options); + + /// @} + /// \name OrtArenaCfg + /// @{ + + /** \deprecated Use OrtApi::CreateArenaCfgV2 + * + * This will create the configuration of an arena that can eventually be used to define an arena based allocator's behavior + * + * \param[in] max_mem Use 0 to allow ORT to choose the default + * \param[in] arena_extend_strategy Use -1 to allow ORT to choose the default, 0 = kNextPowerOfTwo, 1 = kSameAsRequested + * \param[in] initial_chunk_size_bytes Use -1 to allow ORT to choose the default + * \param[in] max_dead_bytes_per_chunk Use -1 to allow ORT to choose the default + * \param[in] out A pointer to an OrtArenaCfg instance + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateArenaCfg, _In_ size_t max_mem, int arena_extend_strategy, int initial_chunk_size_bytes, + int max_dead_bytes_per_chunk, _Outptr_ OrtArenaCfg** out); + + ORT_CLASS_RELEASE(ArenaCfg); + + /// @} + /// \name OrtModelMetadata + /// @{ + + /** + * Use this to obtain the description of the graph present in the model + * (doc_string field of the GraphProto message within the ModelProto message). + * If it doesn't exist, an empty string will be returned. + * + * \param[in] model_metadata An instance of ::OrtModelMetadata + * \param[in] allocator Allocator used to allocate the string that will be returned back + * \param[out] value Set to a null terminated string allocated using `allocator`. The caller is responsible for freeing it using `allocator` + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(ModelMetadataGetGraphDescription, _In_ const OrtModelMetadata* model_metadata, + _Inout_ OrtAllocator* allocator, _Outptr_ char** value); + + /// @} + /// \name OrtSessionOptions + /// @{ + + /** \brief Append TensorRT provider to session options + * + * If TensorRT is not available (due to a non TensorRT enabled build, or if TensorRT is not installed on the system), this function will return failure. + * + * \param[in] options + * \param[in] tensorrt_options + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SessionOptionsAppendExecutionProvider_TensorRT, + _In_ OrtSessionOptions* options, _In_ const OrtTensorRTProviderOptions* tensorrt_options); + + /// @} + /// \name Misc + /// @{ + + /** \brief Set current GPU device ID + * + * Set the current device id of the GPU execution provider (CUDA/tensorrt/rocm). The device id should be less + * than the total number of devices available. This is only useful when multiple-GPUs are installed and it is + * required to restrict execution to a single GPU. + * + * \param[in] device_id + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SetCurrentGpuDeviceId, _In_ int device_id); + + /** \brief Get current GPU device ID + * + * Get the current device id of the GPU execution provider (CUDA/tensorrt/rocm). + * + * \see OrtApi::SetCurrentGpuDeviceId + * + * \param[out] device_id + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetCurrentGpuDeviceId, _In_ int* device_id); + + /// @} + /// \name OrtKernelInfo + /// Custom operator APIs. + /// @{ + + /** \brief Fetch an array of int64_t values stored as an attribute in the graph node + * + * + * If `out` is nullptr, the value of `size` is set to the true size of the attribute + * array's size, and a success status is returned. + * + * If the `size` parameter is greater than or equal to the actual attribute array's size, + * the value of `size` is set to the true size of the attribute array's size, + * the provided memory is filled with the attribute's contents, + * and a success status is returned. + * + * If the `size` parameter is less than the actual attribute array's size and `out` + * is not nullptr, the value of `size` is set to the true size of the attribute array's size + * and a failure status is returned.) + * + * \param[in] info instance + * \param[in] name name of the attribute to be parsed + * \param[out] out pointer to memory where the attribute's contents are to be stored + * \param[in, out] size actual size of attribute array + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(KernelInfoGetAttributeArray_float, _In_ const OrtKernelInfo* info, _In_ const char* name, + _Out_ float* out, _Inout_ size_t* size); + + /** \brief Fetch an array of int64_t values stored as an attribute in the graph node + * + * If `out` is nullptr, the value of `size` is set to the true size of the attribute + * array's size, and a success status is returned. + * + * If the `size` parameter is greater than or equal to the actual attribute array's size, + * the value of `size` is set to the true size of the attribute array's size, + * the provided memory is filled with the attribute's contents, + * and a success status is returned. + * + * If the `size` parameter is less than the actual attribute array's size and `out` + * is not nullptr, the value of `size` is set to the true size of the attribute array's size + * and a failure status is returned.) + * + * \param[in] info instance + * \param[in] name name of the attribute to be parsed + * \param[out] out pointer to memory where the attribute's contents are to be stored + * \param[in, out] size actual size of attribute array + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(KernelInfoGetAttributeArray_int64, _In_ const OrtKernelInfo* info, _In_ const char* name, + _Out_ int64_t* out, _Inout_ size_t* size); + + /// @} + /// \name OrtArenaCfg + /// @{ + + /** \brief Create an ::OrtArenaCfg + * + * Create the configuration of an arena that can eventually be used to define an arena based allocator's behavior. + * + * Supported keys are (See https://onnxruntime.ai/docs/get-started/with-c.html for details on what the + * following parameters mean and how to choose these values.): + * "max_mem": Maximum memory that can be allocated by the arena based allocator. + * Use 0 for ORT to pick the best value. Default is 0. + * "arena_extend_strategy": 0 = kNextPowerOfTwo, 1 = kSameAsRequested. + * Use -1 to allow ORT to choose the default. + * "initial_chunk_size_bytes": (Possible) Size of the first allocation in the arena. + * Only relevant if arena strategy is `kNextPowerOfTwo`. Use -1 to allow ORT to choose the default. + * Ultimately, the first allocation size is determined by the allocation memory request. + * "max_dead_bytes_per_chunk": Threshold of unused memory in an allocated chunk of arena memory after + * crossing which the current chunk is chunked into 2. + * "initial_growth_chunk_size_bytes": (Possible) Size of the second allocation in the arena. + * Only relevant if arena strategy is `kNextPowerOfTwo`. Use -1 to allow ORT to choose the default. + * "max_power_of_two_extend_bytes": The maximum enxtend size if arena strategy is `kNextPowerOfTwo`. + * It is not an allocation limit, it is only a limit for extention when requested byte is less than the limit. + * When requested bytes is more than the limit, allocator will still return as requested. + * Use -1 to allow ORT to choose the default 1GB for max_power_of_two_extend_bytes. + * Ultimately, the allocation size is determined by the allocation memory request. + * Further allocation sizes are governed by the arena extend strategy. + * + * \param[in] arena_config_keys Keys to configure the arena + * \param[in] arena_config_values Values to configure the arena + * \param[in] num_keys Number of keys in `arena_config_keys` and `arena_config_values` + * \param[out] out Newly created ::OrtArenaCfg. Must be freed with OrtApi::ReleaseArenaCfg + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateArenaCfgV2, _In_reads_(num_keys) const char* const* arena_config_keys, + _In_reads_(num_keys) const size_t* arena_config_values, _In_ size_t num_keys, + _Outptr_ OrtArenaCfg** out); + + /// @} + /// \name OrtRunOptions + /// @{ + + /** \brief Set a single run configuration entry as a pair of strings + * + * If a configuration with same key exists, this will overwrite the configuration with the given config_value + * + * The config_key and the format of config_value are defined in onnxruntime_run_options_config_keys.h + * + * \param[in] options + * \param[in] config_key A null terminated string representation of the config key + * \param[in] config_value A null terminated string representation of the config value + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(AddRunConfigEntry, _Inout_ OrtRunOptions* options, + _In_z_ const char* config_key, _In_z_ const char* config_value); + + /// @} + /// \name OrtPrepackedWeightsContainer + /// @{ + + /** \brief Create an ::OrtPrepackedWeightsContainer + * + * This container will hold pre-packed buffers of shared initializers for sharing between sessions + * (i.e.) if there are shared initializers that can be shared between sessions, the pre-packed buffers + * of these (if any) may possibly be shared to provide memory footprint savings. Pass this container + * to sessions that you would like to share pre-packed buffers of shared initializers at session + * creation time. + * + * \param[out] out Newly created ::OrtPrepackedWeightsContainer. Must be freed with OrtApi::ReleasePrepackedWeightsContainer + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreatePrepackedWeightsContainer, _Outptr_ OrtPrepackedWeightsContainer** out); + + /** \brief Release OrtPrepackedWeightsContainer instance + * + * \note instance must not be released until the sessions using it are released + */ + ORT_CLASS_RELEASE(PrepackedWeightsContainer); + + /// @} + /// \name OrtSession + /// @{ + + /** \brief Create session with prepacked weights container + * + * Same functionality offered by OrtApi::CreateSession except that a container that contains + * pre-packed weights' buffers is written into/read from by the created session. + * This is useful when used in conjunction with OrtApi::AddInitializer which injects + * shared initializer info into sessions. Wherever possible, the pre-packed versions of these + * shared initializers are cached in this container so that multiple sessions can just re-use + * these instead of duplicating these in memory. + * + * \param[in] env OrtEnv instance instance + * \param[in] model_path Null terminated string of the path (wchar on Windows, char otherwise) + * \param[in] options + * \param[in] prepacked_weights_container + * \param[out] out Newly created ::OrtSession. Must be freed with OrtApi::ReleaseSession + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateSessionWithPrepackedWeightsContainer, _In_ const OrtEnv* env, _In_ const ORTCHAR_T* model_path, + _In_ const OrtSessionOptions* options, _Inout_ OrtPrepackedWeightsContainer* prepacked_weights_container, + _Outptr_ OrtSession** out); + + /** \brief Create session from memory with prepacked weights container + * + * Same functionality offered by OrtApi::CreateSessionFromArray except that a container that contains + * pre-packed weights' buffers is written into/read from by the created session. + * This is useful when used in conjunction with OrtApi::AddInitializer which injects + * shared initializer info into sessions. Wherever possible, the pre-packed versions of these + * shared initializers are cached in this container so that multiple sessions can just re-use + * these instead of duplicating these in memory. + * + * \param[in] env + * \param[in] model_data Array of bytes holding the model + * \param[in] model_data_length Number of bytes in `model_data_model` + * \param[in] options + * \param[in] prepacked_weights_container + * \param[out] out Newly created ::OrtSession. Must be freed with OrtApi::ReleaseSession + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateSessionFromArrayWithPrepackedWeightsContainer, _In_ const OrtEnv* env, + _In_ const void* model_data, size_t model_data_length, + _In_ const OrtSessionOptions* options, _Inout_ OrtPrepackedWeightsContainer* prepacked_weights_container, + _Outptr_ OrtSession** out); + + /// @} + /// \name OrtSessionOptions + /// @{ + + /** \brief Append TensorRT execution provider to the session options + * + * If TensorRT is not available (due to a non TensorRT enabled build), this function will return failure. + * + * This is slightly different from OrtApi::SessionOptionsAppendExecutionProvider_TensorRT, it takes an + * ::OrtTensorRTProviderOptions which is publicly defined. This takes an opaque ::OrtTensorRTProviderOptionsV2 + * which must be created with OrtApi::CreateTensorRTProviderOptions. + * + * For OrtApi::SessionOptionsAppendExecutionProvider_TensorRT, the user needs to instantiate ::OrtTensorRTProviderOptions + * as well as allocate/release buffers for some members of ::OrtTensorRTProviderOptions. + * Here, OrtApi::CreateTensorRTProviderOptions and Ortapi::ReleaseTensorRTProviderOptions will do the memory management for you. + * + * \param[in] options + * \param[in] tensorrt_options + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SessionOptionsAppendExecutionProvider_TensorRT_V2, + _In_ OrtSessionOptions* options, _In_ const OrtTensorRTProviderOptionsV2* tensorrt_options); + + /// @} + /// \name OrtTensorRTProviderOptionsV2 + /// @{ + + /** \brief Create an OrtTensorRTProviderOptionsV2 + * + * \param[out] out Newly created ::OrtTensorRTProviderOptionsV2. Must be released with OrtApi::ReleaseTensorRTProviderOptions + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateTensorRTProviderOptions, _Outptr_ OrtTensorRTProviderOptionsV2** out); + + /** \brief Set options in a TensorRT Execution Provider. + * + * Please refer to https://onnxruntime.ai/docs/execution-providers/TensorRT-ExecutionProvider.html#cc + * to know the available keys and values. Key should be in null terminated string format of the member of ::OrtTensorRTProviderOptionsV2 + * and value should be its related range. + * + * For example, key="trt_max_workspace_size" and value="2147483648" + * + * \param[in] tensorrt_options + * \param[in] provider_options_keys Array of UTF-8 null-terminated string for provider options keys + * \param[in] provider_options_values Array of UTF-8 null-terminated string for provider options values + * \param[in] num_keys Number of elements in the `provider_option_keys` and `provider_options_values` arrays + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(UpdateTensorRTProviderOptions, _Inout_ OrtTensorRTProviderOptionsV2* tensorrt_options, + _In_reads_(num_keys) const char* const* provider_options_keys, + _In_reads_(num_keys) const char* const* provider_options_values, + _In_ size_t num_keys); + + /** \brief Get serialized TensorRT provider options string. + * + * For example, "trt_max_workspace_size=2147483648;trt_max_partition_iterations=10;trt_int8_enable=1;......" + * + * \param tensorrt_options - OrtTensorRTProviderOptionsV2 instance + * \param allocator - a ptr to an instance of OrtAllocator obtained with OrtApi::CreateAllocator or OrtApi::GetAllocatorWithDefaultOptions + * the specified allocator will be used to allocate continuous buffers for output strings and lengths. + * \param ptr - is a UTF-8 null terminated string allocated using 'allocator'. The caller is responsible for using the same allocator to free it. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetTensorRTProviderOptionsAsString, _In_ const OrtTensorRTProviderOptionsV2* tensorrt_options, _Inout_ OrtAllocator* allocator, _Outptr_ char** ptr); + + /** \brief Release an ::OrtTensorRTProviderOptionsV2 + * + * \note This is an exception in the naming convention of other Release* functions, as the name of the method does not have the V2 suffix, but the type does + */ + void(ORT_API_CALL* ReleaseTensorRTProviderOptions)(_Frees_ptr_opt_ OrtTensorRTProviderOptionsV2* input); + + /// @} + /// \name OrtSessionOptions + /// @{ + + /** \brief Enable custom operators + * + * See onnxruntime-extensions: https://github.com/microsoft/onnxruntime-extensions.git + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(EnableOrtCustomOps, _Inout_ OrtSessionOptions* options); + + /// @} + /// \name OrtAllocator + /// @{ + + /** \brief Register a custom allocator + * + * Enables sharing between multiple sessions that use the same env instance. + * Returns an error if an allocator with the same ::OrtMemoryInfo is already registered. + * + * The behavior of this is exactly the same as OrtApi::CreateAndRegisterAllocator except + * instead of ORT creating an allocator based on provided info, in this case + * ORT uses the user-provided custom allocator. + * See https://onnxruntime.ai/docs/get-started/with-c.html for details. + * + * \param[in] env + * \param[in] allocator User provided allocator + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(RegisterAllocator, _Inout_ OrtEnv* env, _In_ OrtAllocator* allocator); + + /** \brief Unregister a custom allocator + * + * It is an error if you provide an ::OrtMemoryInfo not corresponding to any + * registered allocators for sharing. + * + * \param[in] env + * \param[in] mem_info + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(UnregisterAllocator, _Inout_ OrtEnv* env, + _In_ const OrtMemoryInfo* mem_info); + + /// @} + /// \name OrtValue + /// @{ + + /** \brief Sets *out to 1 iff an ::OrtValue is a SparseTensor, and 0 otherwise + * + * \param[in] value existing ::OrtValue + * \param[out] out unless an error occurs, contains 1 iff the value contains an instance + * of sparse tensor or 0 otherwise. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(IsSparseTensor, _In_ const OrtValue* value, _Out_ int* out); + + /** \brief Create an ::OrtValue with a sparse tensor that is empty. + * + * Use FillSparseTensor() functions to populate sparse tensor with non-zero values and + * format specific indices data. + * Use ReleaseValue to destroy the sparse tensor, this will also release the buffer inside the output value + * if any was allocated. + * \param[in,out] allocator allocator to use when performing an allocation. Allocation will be performed + * by FillSparseTensor() APIs. The lifespan of the allocator instance must eclipse the lifespan + * this sparse tensor instance as the same allocator will be used to free memory. + * \param[in] dense_shape shape of the original dense tensor + * \param[in] dense_shape_len number of shape dimensions being passed + * \param[in] type must be one of TENSOR_ELEMENT_DATA_TYPE_xxxx + * \param[out] out Should be freed by calling ReleaseValue + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateSparseTensorAsOrtValue, _Inout_ OrtAllocator* allocator, _In_ const int64_t* dense_shape, + size_t dense_shape_len, ONNXTensorElementDataType type, _Outptr_ OrtValue** out); + + /** + * This fills populates an empty tensor that was created using OrtApi::CreateSparseTensorAsOrtValue. + * This will allocate required memory and copy the supplied NNZ values and COO indices into that memory allocation. + * Memory allocation is performed using the allocator that was specified with OrtApi::CreateSparseTensorAsOrtValue. + * + * \param[in,out] ort_value ::OrtValue to populate with data + * \param[in] data_mem_info serves to identify the location of the data to be copied. If the allocator specified + * at the creation time has memory info that is not the same as mem_info argument to this function a X-device copy will be performed. + * String data is assumed to be on CPU and will only be copied into a CPU allocated buffer. + * \param[in] values_shape pointer to values shape array + * \param[in] values_shape_len length of the values_shape + * \param[in] values pointer to an array of values. For strings, pass const char**. + * \param[in] indices_data pointer to a location of COO indices + * \param[in] indices_num number of COO indices + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(FillSparseTensorCoo, _Inout_ OrtValue* ort_value, _In_ const OrtMemoryInfo* data_mem_info, + _In_ const int64_t* values_shape, size_t values_shape_len, _In_ const void* values, + _In_ const int64_t* indices_data, size_t indices_num); + + /** + * This fills populates an empty tensor that was created using OrtApi::CreateSparseTensorAsOrtValue. + * This will allocate required memory and copy the supplied NNZ values and CSR indices into that memory allocation. + * Memory allocation is performed using the allocator that was specified with OrtApi::CreateSparseTensorAsOrtValue. + * + * \param[in,out] ort_value ::OrtValue to populate with data + * \param[in] data_mem_info serves to identify the location of the data to be copied. If the allocator specified + * at the creation time has memory info that is not the same as mem_info argument to this function a X-device copy will be performed. + * String data is assumed to be on CPU and will only be copied into a CPU allocated buffer. + * \param[in] values_shape pointer to values shape array + * \param[in] values_shape_len length of the values_shape + * \param[in] values - pointer to an array of values. For strings, pass const char**. + * \param[in] inner_indices_data pointer to a location of CSR inner indices + * \param[in] inner_indices_num number of CSR inner indices + * \param[in] outer_indices_data pointer to a location of CSR outer indices + * \param[in] outer_indices_num number of CSR outer indices + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(FillSparseTensorCsr, _Inout_ OrtValue* ort_value, _In_ const OrtMemoryInfo* data_mem_info, + _In_ const int64_t* values_shape, size_t values_shape_len, _In_ const void* values, + _In_ const int64_t* inner_indices_data, size_t inner_indices_num, + _In_ const int64_t* outer_indices_data, size_t outer_indices_num); + + /** + * This fills populates an empty tensor that was created using OrtApi::CreateSparseTensorAsOrtValue. + * This will allocate required memory and copy the supplied NNZ values and BlockSparse indices into that memory allocation. + * Memory allocation is performed using the allocator that was specified with OrtApi::CreateSparseTensorAsOrtValue. + * + * \param[in,out] ort_value ::OrtValue to populate with data + * \param[in] data_mem_info serves to identify the location of the data to be copied. If the allocator specified + * at the creation time has memory info that is not the same as mem_info argument to this function a X-device copy will be performed. + * String data is assumed to be on CPU and will only be copied into a CPU allocated buffer. + * \param[in] values_shape + * \param[in] values_shape_len + * \param[in] values structure with values information + * \param[in] indices_shape_data pointer to a location of indices shape + * \param[in] indices_shape_len length of the block sparse indices shape + * \param[in] indices_data pointer to a location of indices data. Shape will determine the length of the indices data. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(FillSparseTensorBlockSparse, _Inout_ OrtValue* ort_value, _In_ const OrtMemoryInfo* data_mem_info, + _In_ const int64_t* values_shape, size_t values_shape_len, _In_ const void* values, + _In_ const int64_t* indices_shape_data, size_t indices_shape_len, + _In_ const int32_t* indices_data); + + /** + * Create an ::OrtValue with a sparse tensor. This is the first step. + * Next, use UseIndices() functions to supply sparse tensor with + * format specific indices data and set its sparse format to a specific enum value. + * This will not perform memory allocations. It will + * use supplied user buffer which should outlive the created sparse tensor. + * Use OrtApi::ReleaseValue to destroy the sparse tensor. It would not release the supplied values buffer. + * This function can not be used to map strings from the user allocated memory. Strings must always be copied + * and have UTF-8 encoding. Therefore, use OrtApi::CreateSparseTensorAsOrtValue above and then fill it with data + * using appropriate Make*() function. + * + * \param[in] info memory info where sparse values reside. + * \param[in,out] p_data pointer to a user allocated buffer with values. To create a full sparse tensor with no non-zero + * values, pass nullptr + * \param[in] dense_shape shape of the original dense tensor + * \param[in] dense_shape_len number of shape dimensions being passed + * \param[in] values_shape shape of the values data. To create a fully sparse tensor with no non-zero values, + * pass {0} shape. + * \param[in] values_shape_len number of values shape dimensions + * \param[in] type must be one of TENSOR_ELEMENT_DATA_TYPE_xxxx + * \param[out] out Should be freed by calling ReleaseValue + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(CreateSparseTensorWithValuesAsOrtValue, _In_ const OrtMemoryInfo* info, _Inout_ void* p_data, + _In_ const int64_t* dense_shape, size_t dense_shape_len, + _In_ const int64_t* values_shape, size_t values_shape_len, + ONNXTensorElementDataType type, _Outptr_ OrtValue** out); + + /** + * This assigns Coo format indices to the SparseTensor that was created by + * OrtApi::CreateSparseTensorWithValuesAsOrtValue above. It also sets OrtSparseFormat to + * ORT_SPARSE_COO. This will not allocate any additional memory for data. The life span of + * indices_data buffer should eclipse the life span of this ::OrtValue. + * + * \param[in,out] ort_value ::OrtValue instance constructed with OrtApi::CreateSparseTensorWithValuesAsOrtValue + * \param[in,out] indices_data pointer to a user pre-allocated buffer or nullptr for fully sparse tensors. + * \param[in] indices_num number of COO indices. Should either be 0 for fully sparse tensors, be equal + * to the number of nnz values specified to OrtApi::CreateSparseTensorWithValuesAsOrtValue for 1-D {nnz} indices or + * be twice as number of nnz values for a 2-D indices {nnz, 2} + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(UseCooIndices, _Inout_ OrtValue* ort_value, _Inout_ int64_t* indices_data, size_t indices_num); + + /** + * The assigns CSR format indices to the SparseTensor that was created by + * OrtApi::CreateSparseTensorWithValuesAsOrtValue above. It also sets OrtSparseFormat to + * ORT_SPARSE_CSRC. This will not allocate any additional memory for data. The life spans of + * inner_data and outer_data buffers should eclipse the life span of this ::OrtValue. + * + * \param[in,out] ort_value ::OrtValue instance constructed with OrtApi::CreateSparseTensorWithValuesAsOrtValue + * \param[in,out] inner_data pointer to a user pre-allocated buffer or nullptr for fully sparse tensors. + * \param[in] inner_num number of inner CSR indices. Should either be 0 for fully sparse tensors or be equal + * to the number of nnz values specified to OrtApi::CreateSparseTensorWithValuesAsOrtValue. + * \param[in,out] outer_data pointer to user pre-allocated buffer or nullptr for fully sparse tensors. + * \param[in] outer_num number of CSR outer indices. Should either be 0 for fully sparse tensors or + * equal to rows + 1 of the dense shape. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(UseCsrIndices, _Inout_ OrtValue* ort_value, _Inout_ int64_t* inner_data, size_t inner_num, + _Inout_ int64_t* outer_data, size_t outer_num); + + /** + * The assigns BlockSparse format indices to the SparseTensor that was created by + * OrtApi::CreateSparseTensorWithValuesAsOrtValue above. It also sets OrtSparseFormat to + * ORT_SPARSE_BLOCK_SPARSE. This will not allocate any additional memory for data. The life span of + * indices_data buffer must eclipse the lifespan of this ::OrtValue. + * + * \param[in,out] ort_value OrtValue instance constructed with OrtApi::CreateSparseTensorWithValuesAsOrtValue + * \param[in] indices_shape pointer to indices shape. Use {0} for fully sparse tensors + * \param[in] indices_shape_len length of the indices shape + * \param[in,out] indices_data pointer to user pre-allocated buffer or nullptr for fully sparse tensors. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(UseBlockSparseIndices, _Inout_ OrtValue* ort_value, const int64_t* indices_shape, size_t indices_shape_len, _Inout_ int32_t* indices_data); + + /** \brief Returns sparse tensor format enum iff a given ort value contains an instance of sparse tensor. + * + * \param[in] ort_value ::OrtValue that contains an instance of sparse tensor + * \param[out] out pointer to out parameter + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetSparseTensorFormat, _In_ const OrtValue* ort_value, _Out_ enum OrtSparseFormat* out); + + /** \brief Returns data type and shape of sparse tensor values (nnz) iff ::OrtValue contains a SparseTensor. + * + * \param[in] ort_value An ::OrtValue that contains a fully constructed sparse tensor + * \param[out] out Must be freed by OrtApi::ReleaseTensorTypeAndShapeInfo + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetSparseTensorValuesTypeAndShape, _In_ const OrtValue* ort_value, _Outptr_ OrtTensorTypeAndShapeInfo** out); + + /** \brief Returns numeric data for sparse tensor values (nnz). For string values use GetStringTensor*(). + * + * \param[in] ort_value an instance of ::OrtValue containing sparse tensor + * \param[out] out returns a pointer to values data. Do not attempt to free this ptr. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetSparseTensorValues, _In_ const OrtValue* ort_value, _Outptr_ const void** out); + + /** \brief Returns data type, shape for the type of indices specified by indices_format. + * + * \param[in] ort_value ::OrtValue containing sparse tensor. + * \param[in] indices_format One of the indices formats. It is an error to request a format that the sparse + * tensor does not contain. + * \param[out] out an instance of ::OrtTensorTypeAndShapeInfo. Must be freed by OrtApi::ReleaseTensorTypeAndShapeInfo + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetSparseTensorIndicesTypeShape, _In_ const OrtValue* ort_value, enum OrtSparseIndicesFormat indices_format, _Outptr_ OrtTensorTypeAndShapeInfo** out); + + /** \brief Returns indices data for the type of the indices specified by indices_format + * + * \param[in] ort_value ::OrtValue containing sparse tensor. + * \param[in] indices_format One of the indices formats. It is an error to request a format that the sparse tensor does not contain. + * \param[out] num_indices Pointer to where the number of indices entries is returned + * \param[out] indices Returned pointer to the indices data. Do not free the returned pointer as it refers to internal data owned by the ::OrtValue + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetSparseTensorIndices, _In_ const OrtValue* ort_value, enum OrtSparseIndicesFormat indices_format, _Out_ size_t* num_indices, _Outptr_ const void** indices); + /// @} + /// \name OrtSessionOptions + /// @{ + + /** + * \brief Sets out to 1 iff an optional type OrtValue has an element, 0 otherwise (OrtValue is None) + * Use this API to find if the optional type OrtValue is None or not. + * If the optional type OrtValue is not None, use the OrtValue just like any other OrtValue. + * For example, if you get an OrtValue that corresponds to Optional(tensor) and + * if HasValue() returns true, use it as tensor and so on. + + * \param[in] value Input OrtValue. + * \param[out] out indicating if the input OrtValue contains data (1) or if it is a None (0) + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(HasValue, _In_ const OrtValue* value, _Out_ int* out); + + /// @} + /// \name OrtKernelContext + /// Custom operator APIs. + /// @{ + + /** \brief Used for custom operators, gets the GPU compute stream to use to launch the custom a GPU kernel + * \see ::OrtCustomOp + * \param[in] context OrtKernelContext instance + * \param[out] out Returns pointer to a GPU compute stream that can be used to launch the custom GPU kernel. + * If retrieving the GPU compute stream is not relevant (GPU not enabled in the build, kernel partitioned to + * some other EP), then a nullptr is returned as the output param. + * Do not free or mutate the returned pointer as it refers to internal data owned by the underlying session. + * Only use it for custom kernel launching. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(KernelContext_GetGPUComputeStream, _In_ const OrtKernelContext* context, _Outptr_ void** out); + + /// @} + /// \name GetTensorMemoryInfo + /// @{ + /** \brief Returns a pointer to the ::OrtMemoryInfo of a Tensor + * \param[in] value ::OrtValue containing tensor. + * \param[out] mem_info ::OrtMemoryInfo of the tensor. Do NOT free the returned pointer. It is valid for the lifetime of the ::OrtValue + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetTensorMemoryInfo, _In_ const OrtValue* value, _Out_ const OrtMemoryInfo** mem_info); + + /// @} + /// \name GetExecutionProviderApi + /// @{ + /** \brief Get a pointer to the requested version of the Execution Provider specific + * API extensions to the OrtApi + * \param[in] provider_name The name of the execution provider name. Currently only the following + * values are supported: "DML". + * \param[in] version Must be ::ORT_API_VERSION. + * \param[out] provider_api A void pointer containing a reference to the execution provider versioned api structure. + * For example, the provider_api pointer can be cast to the OrtDmlApi* when the provider_name is "DML". + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetExecutionProviderApi, _In_ const char* provider_name, _In_ uint32_t version, _Outptr_ const void** provider_api); + + /// @} + + /// \name SessionOptions + /// @{ + /** \brief Set custom thread creation function + * + * \param[in] options Session options + * \param[in] ort_custom_create_thread_fn Custom thread creation function + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SessionOptionsSetCustomCreateThreadFn, _Inout_ OrtSessionOptions* options, _In_ OrtCustomCreateThreadFn ort_custom_create_thread_fn); + + /** \brief Set creation options for custom thread + * + * \param[in] options Session options + * \param[in] ort_custom_thread_creation_options Custom thread creation options (can be nullptr) + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SessionOptionsSetCustomThreadCreationOptions, _Inout_ OrtSessionOptions* options, _In_ void* ort_custom_thread_creation_options); + + /** \brief Set custom thread join function + * + * \param[in] options Session options + * \param[in] ort_custom_join_thread_fn Custom join thread function, must not be nullptr when ort_custom_create_thread_fn is set + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SessionOptionsSetCustomJoinThreadFn, _Inout_ OrtSessionOptions* options, _In_ OrtCustomJoinThreadFn ort_custom_join_thread_fn); + /// @} + + /// \name OrtThreadingOptions + /// @{ + /** \brief Set custom thread creation function for global thread pools + * + * \param[inout] tp_options + * \param[in] ort_custom_create_thread_fn Custom thread creation function + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SetGlobalCustomCreateThreadFn, _Inout_ OrtThreadingOptions* tp_options, _In_ OrtCustomCreateThreadFn ort_custom_create_thread_fn); + + /** \brief Set custom thread creation options for global thread pools + * + * \param[inout] tp_options + * \param[in] ort_custom_thread_creation_options Custom thread creation options (can be nullptr) + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SetGlobalCustomThreadCreationOptions, _Inout_ OrtThreadingOptions* tp_options, _In_ void* ort_custom_thread_creation_options); + + /** \brief Set custom thread join function for global thread pools + * + * \param[inout] tp_options + * \param[in] ort_custom_join_thread_fn Custom thread join function, must not be nullptr when global ort_custom_create_thread_fn is set + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SetGlobalCustomJoinThreadFn, _Inout_ OrtThreadingOptions* tp_options, _In_ OrtCustomJoinThreadFn ort_custom_join_thread_fn); + /// @} + + /** \brief Synchronize bound inputs. The call may be necessary for some providers, such as cuda, + * in case the system that allocated bound memory operated on a different stream. However, the + * operation is provider specific and could be a no-op. + * + * \param[inout] binding_ptr + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SynchronizeBoundInputs, _Inout_ OrtIoBinding* binding_ptr); + + /** \brief Synchronize bound outputs. The call may be necessary for some providers, such as cuda, + * in case the system that allocated bound memory operated on a different stream. However, the + * operation is provider specific and could be a no-op. + * + * \param[inout] binding_ptr + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(SynchronizeBoundOutputs, _Inout_ OrtIoBinding* binding_ptr); + + /// \name OrtSessionOptions + /// @{ + + /** \brief Append CUDA execution provider to the session options + * + * If CUDA is not available (due to a non CUDA enabled build), this function will return failure. + * + * This is slightly different from OrtApi::SessionOptionsAppendExecutionProvider_CUDA, it takes an + * ::OrtCUDAProviderOptions which is publicly defined. This takes an opaque ::OrtCUDAProviderOptionsV2 + * which must be created with OrtApi::CreateCUDAProviderOptions. + * + * For OrtApi::SessionOptionsAppendExecutionProvider_CUDA, the user needs to instantiate ::OrtCUDAProviderOptions + * as well as allocate/release buffers for some members of ::OrtCUDAProviderOptions. + * Here, OrtApi::CreateCUDAProviderOptions and Ortapi::ReleaseCUDAProviderOptions will do the memory management for you. + * + * \param[in] options + * \param[in] cuda_options + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.11. + */ + ORT_API2_STATUS(SessionOptionsAppendExecutionProvider_CUDA_V2, + _In_ OrtSessionOptions* options, _In_ const OrtCUDAProviderOptionsV2* cuda_options); + + /// @} + /// \name OrtCUDAProviderOptionsV2 + /// @{ + + /** \brief Create an OrtCUDAProviderOptionsV2 + * + * \param[out] out Newly created ::OrtCUDAProviderOptionsV2. Must be released with OrtApi::ReleaseCudaProviderOptions + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.11. + */ + ORT_API2_STATUS(CreateCUDAProviderOptions, _Outptr_ OrtCUDAProviderOptionsV2** out); + + /** \brief Set options in a CUDA Execution Provider. + * + * Please refer to https://onnxruntime.ai/docs/execution-providers/CUDA-ExecutionProvider.html#configuration-options + * to know the available keys and values. Key should be in null terminated string format of the member of ::OrtCUDAProviderOptionsV2 + * and value should be its related range. + * + * For example, key="device_id" and value="0" + * + * \param[in] cuda_options + * \param[in] provider_options_keys Array of UTF-8 null-terminated string for provider options keys + * \param[in] provider_options_values Array of UTF-8 null-terminated string for provider options values + * \param[in] num_keys Number of elements in the `provider_option_keys` and `provider_options_values` arrays + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.11. + */ + ORT_API2_STATUS(UpdateCUDAProviderOptions, _Inout_ OrtCUDAProviderOptionsV2* cuda_options, + _In_reads_(num_keys) const char* const* provider_options_keys, + _In_reads_(num_keys) const char* const* provider_options_values, + _In_ size_t num_keys); + + /** + * Get serialized CUDA provider options string. + * + * For example, "device_id=0;arena_extend_strategy=0;......" + * + * \param cuda_options - OrtCUDAProviderOptionsV2 instance + * \param allocator - a ptr to an instance of OrtAllocator obtained with CreateAllocator() or GetAllocatorWithDefaultOptions() + * the specified allocator will be used to allocate continuous buffers for output strings and lengths. + * \param ptr - is a UTF-8 null terminated string allocated using 'allocator'. The caller is responsible for using the same allocator to free it. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.11. + */ + ORT_API2_STATUS(GetCUDAProviderOptionsAsString, _In_ const OrtCUDAProviderOptionsV2* cuda_options, _Inout_ OrtAllocator* allocator, _Outptr_ char** ptr); + + /** \brief Release an ::OrtCUDAProviderOptionsV2 + * + * \note This is an exception in the naming convention of other Release* functions, as the name of the method does not have the V2 suffix, but the type does + * + * \since Version 1.11. + */ + void(ORT_API_CALL* ReleaseCUDAProviderOptions)(_Frees_ptr_opt_ OrtCUDAProviderOptionsV2* input); + + /// @} + + /** \brief Append MIGraphX provider to session options + * + * If MIGraphX is not available (due to a non MIGraphX enabled build, or if MIGraphX is not installed on the system), this function will return failure. + * + * \param[in] options + * \param[in] migraphx_options + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.11. + */ + ORT_API2_STATUS(SessionOptionsAppendExecutionProvider_MIGraphX, + _In_ OrtSessionOptions* options, _In_ const OrtMIGraphXProviderOptions* migraphx_options); + + /** \brief Replace initialized Tensors with external data with the data provided in initializers. + * + * The function will find the initialized TensorProtos with external data in the graph with the provided names and + * replace them with the provided tensors. The API verifies that the TensorProto being replaced + * has an external data reference and has the same name, dimensions and data type as its replacement. The replacement + * will occur before any of the optimizations take place. The data will be copied into the graph + * since TensorProto can't refer to the user provided buffers. + * + * Once the model has been loaded, the OrtValue(s) added to SessionOptions instance will be removed + * from the internal SessionOptions copy to save memory, the user provided buffers can then be deallocated + * and the SessionOptions instance that refers to them can be destroyed. + * + * \param[in] options + * \param[in] initializer_names Array of null terminated UTF-8 encoded strings of the initializers names. + * \param[in] initializers Array of ::OrtValue type + * \param[in] initializers_num Number of elements in the initializer_names and initializers + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.12. + */ + ORT_API2_STATUS(AddExternalInitializers, _In_ OrtSessionOptions* options, + _In_reads_(input_len) const char* const* initializer_names, + _In_reads_(input_len) const OrtValue* const* initializers, size_t initializers_num); + + /** \brief: Create attribute of onnxruntime operator + * + * \param[in] name Name of the attribute + * \param[in] data Data content of the attribute + * \param[in] len Number of bytes stored in data + * \param[in] type Data type + * \param[out] op_attr Attribute that has been created, which must be released by OrtApi::ReleaseOpAttr + * + * \since Version 1.12. + */ + ORT_API2_STATUS(CreateOpAttr, + _In_ const char* name, + _In_ const void* data, + _In_ int len, + _In_ OrtOpAttrType type, + _Outptr_ OrtOpAttr** op_attr); + + /* \brief: Release op attribute + * + * \param[in] opAttr Attribute created by OrtApi::CreateOpAttr + * + * \since Version 1.12. + */ + ORT_CLASS_RELEASE(OpAttr); + + /** \brief: Create onnxruntime native operator + * + * \param[in] info Kernel info + * \param[in] op_name Operator name + * \param[in] domain Operator domain + * \param[in] version Operator opset version + * \param[in] type_constraint_names Name of the type contraints, such as "T" or "T1" + * \param[in] type_constraint_values Type of each contraints + * \param[in] type_constraint_count Number of contraints + * \param[in] attr_values Attributes used to initialize the operator + * \param[in] attr_count Number of the attributes + * \param[in] input_count Number of inputs + * \param[in] output_count Number of outputs + * \param[out] ort_op Operator that has been created + * + * \since Version 1.12. + */ + ORT_API2_STATUS(CreateOp, + _In_ const OrtKernelInfo* info, + _In_z_ const char* op_name, + _In_z_ const char* domain, + int version, + _In_reads_(type_constraint_count) const char** type_constraint_names, + _In_reads_(type_constraint_count) const ONNXTensorElementDataType* type_constraint_values, + int type_constraint_count, + _In_reads_(attr_count) const OrtOpAttr* const* attr_values, + int attr_count, + int input_count, + int output_count, + _Outptr_ OrtOp** ort_op); + + /** \brief: Invoke the operator created by OrtApi::CreateOp + * The inputs must follow the order as specified in onnx specification + * + * \param[in] context Kernel context + * \param[in] ort_op Operator that has been created + * \param[in] input_values Array of inputs + * \param[in] input_count Number of inputs + * \param[in] output_values Array of outputs + * \param[in] output_count Number of outputs + * + * \since Version 1.12. + */ + ORT_API2_STATUS(InvokeOp, + _In_ const OrtKernelContext* context, + _In_ const OrtOp* ort_op, + _In_ const OrtValue* const* input_values, + _In_ int input_count, + _Inout_ OrtValue* const* output_values, + _In_ int output_count); + + /* \brief: Release an onnxruntime operator + * + * \param[in] Op Operator created by OrtApi::CreateOp + * + * \since Version 1.12. + */ + ORT_CLASS_RELEASE(Op); + + /** \brief: Append execution provider to the session options. + * \param[in] options + * \param[in] provider_name - provider to add. + * \param[in] provider_options_keys - keys to configure the provider options + * \param[in] provider_options_values - values to configure the provider options + * \param[in] num_keys - number of keys passed in + * + * Currently supported providers: + * QNN + * SNPE + * XNNPACK + * + * Note: If an execution provider has a dedicated SessionOptionsAppendExecutionProvider_ function + * that should be used to add it. + * + * QNN supported keys: + * "backend_path": file path to QNN backend library. + * "qnn_context_cache_enable": 1 to enable QNN graph creation from cached QNN context file. If it's enabled: QNN EP will + * load from cached QNN context binary if it exist. It will generate a context binary file if it's not exist + * "qnn_context_cache_path": explicitly provide the QNN context cache file. Default to model_file.onnx.bin if not provided. + * "profiling_level": QNN profiling level, options: "off", "basic", "detailed". Default to off. + * "rpc_control_latency": QNN RPC control latency. + * "htp_performance_mode": QNN performance mode, options: "burst", "balanced", "default", "high_performance", + * "high_power_saver", "low_balanced", "low_power_saver", "power_saver", "sustained_high_performance". Default to "default". + * + * SNPE supported keys: + * "runtime": SNPE runtime engine, options: "CPU", "CPU_FLOAT32", "GPU", "GPU_FLOAT32_16_HYBRID", "GPU_FLOAT16", + * "DSP", "DSP_FIXED8_TF", "AIP_FIXED_TF", "AIP_FIXED8_TF". + * Mapping to SNPE Runtime_t definition: CPU, CPU_FLOAT32 => zdl::DlSystem::Runtime_t::CPU; + * GPU, GPU_FLOAT32_16_HYBRID => zdl::DlSystem::Runtime_t::GPU; + * GPU_FLOAT16 => zdl::DlSystem::Runtime_t::GPU_FLOAT16; + * DSP, DSP_FIXED8_TF => zdl::DlSystem::Runtime_t::DSP. + * AIP_FIXED_TF, AIP_FIXED8_TF => zdl::DlSystem::Runtime_t::AIP_FIXED_TF. + * "priority": execution priority, options: "low", "normal". + * "buffer_type": ITensor or user buffers, options: "ITENSOR", user buffer with different types - "TF8", "TF16", "UINT8", "FLOAT". + * "ITENSOR" -- default, ITensor which is float only. + * "TF8" -- quantized model required, "FLOAT" -- for both quantized or non-quantized model + * "enable_init_cache": enable SNPE init caching feature, set to 1 to enabled it. Disabled by default. + * If SNPE is not available (due to a non Snpe enabled build or its dependencies not being installed), this function will fail. + * + * XNNPACK supported keys: + * "intra_op_num_threads": number of thread-pool size to use for XNNPACK execution provider. + * default value is 0, which means to use the session thread-pool size. + * + * \since Version 1.12. + */ + ORT_API2_STATUS(SessionOptionsAppendExecutionProvider, _In_ OrtSessionOptions* options, + _In_ const char* provider_name, + _In_reads_(num_keys) const char* const* provider_options_keys, + _In_reads_(num_keys) const char* const* provider_options_values, + _In_ size_t num_keys); + + /* \brief: Get a copy of kernel info + * + * \param[in] info Kernel info + * \param[out] info_copy Copy of kernel info + * + * \since Version 1.12. + */ + ORT_API2_STATUS(CopyKernelInfo, + _In_ const OrtKernelInfo* info, + _Outptr_ OrtKernelInfo** info_copy); + + /* \brief: Release kernel info + * + * \param[in] KernelInfo A copy of kernel info returned by CopyKernelInfo + * + * \since Version 1.12. + */ + ORT_CLASS_RELEASE(KernelInfo); + + /// \name Ort Training + /// @{ + /** \brief Gets the Training C Api struct + * + * Call this function to access the ::OrtTrainingApi structure that holds pointers to functions that enable + * training with onnxruntime. + * \note A NULL pointer will be returned and no error message will be printed if the training api + * is not supported with this build. A NULL pointer will be returned and an error message will be + * printed if the provided version is unsupported, for example when using a runtime older than the + * version created with this header file. + * + * \param[in] version Must be ::ORT_API_VERSION + * \return The ::OrtTrainingApi struct for the version requested. + * + * \since Version 1.13 + */ + const OrtTrainingApi*(ORT_API_CALL* GetTrainingApi)(uint32_t version)NO_EXCEPTION; + + /// @} + + /** \brief Append CANN provider to session options + * + * If CANN is not available (due to a non CANN enabled build, or if CANN is not installed on the system), this function will return failure. + * + * \param[in] options + * \param[in] cann_options + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.13. + */ + ORT_API2_STATUS(SessionOptionsAppendExecutionProvider_CANN, + _In_ OrtSessionOptions* options, _In_ const OrtCANNProviderOptions* cann_options); + + /** \brief Create an OrtCANNProviderOptions + * + * \param[out] out created ::OrtCANNProviderOptions. Must be released with OrtApi::ReleaseCANNProviderOptions + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.13. + */ + ORT_API2_STATUS(CreateCANNProviderOptions, _Outptr_ OrtCANNProviderOptions** out); + + /** \brief Set options in a CANN Execution Provider. + * + * \param[in] cann_options + * \param[in] provider_options_keys Array of UTF-8 null-terminated string for provider options keys + * \param[in] provider_options_values Array of UTF-8 null-terminated string for provider options values + * \param[in] num_keys Number of elements in the `provider_option_keys` and `provider_options_values` arrays + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.13. + */ + ORT_API2_STATUS(UpdateCANNProviderOptions, _Inout_ OrtCANNProviderOptions* cann_options, + _In_reads_(num_keys) const char* const* provider_options_keys, + _In_reads_(num_keys) const char* const* provider_options_values, + _In_ size_t num_keys); + + /** \brief Get serialized CANN provider options string. + * + * \param[in] cann_options OrtCANNProviderOptions instance + * \param[in] allocator a ptr to an instance of OrtAllocator obtained with CreateAllocator() + * or GetAllocatorWithDefaultOptions(), the specified allocator will be used to allocate + * continuous buffers for output strings and lengths. + * \param[out] ptr is a UTF-8 null terminated string allocated using 'allocator'. + * The caller is responsible for using the same allocator to free it. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.13. + */ + ORT_API2_STATUS(GetCANNProviderOptionsAsString, _In_ const OrtCANNProviderOptions* cann_options, + _Inout_ OrtAllocator* allocator, _Outptr_ char** ptr); + + /** \brief Release an OrtCANNProviderOptions + * + * \param[in] the pointer of OrtCANNProviderOptions which will been deleted + * + * \since Version 1.13. + */ + void(ORT_API_CALL* ReleaseCANNProviderOptions)(_Frees_ptr_opt_ OrtCANNProviderOptions* input); + + /* \brief Get OrtDevice type from MemoryInfo + * + * \since Version 1.14 + */ + void(ORT_API_CALL* MemoryInfoGetDeviceType)(_In_ const OrtMemoryInfo* ptr, _Out_ OrtMemoryInfoDeviceType* out); + + /* \brief Update the OrtEnv instance with custom log severity level + * + * \param[in] ort_env The OrtEnv instance being used + * \param[in] log_severity_level The log severity level. + * + * \since Version 1.14. + */ + ORT_API2_STATUS(UpdateEnvWithCustomLogLevel, _In_ OrtEnv* ort_env, OrtLoggingLevel log_severity_level); + + /* \brief Set affinities for intra op threads + * + * Affinity string follows format: + * logical_processor_id,logical_processor_id;logical_processor_id,logical_processor_id + * Semicolon isolates configurations among threads, while comma split processors where ith thread expected to attach to. + * e.g. 1,2,3;4,5 + * specifies affinities for two threads, with the 1st thread attach to the 1st, 2nd, and 3rd processor, and 2nd thread to the 4th and 5th. + * To ease the configuration, an "interval" is also allowed: + * e.g. 1-8;8-16;17-24 + * orders that the 1st thread runs on first eight processors, 2nd thread runs on next eight processors, and so forth. + * Note: + * 1. Once set, the number of thread affinities must equal to intra_op_num_threads - 1, + * ort does not set affinity on the main thread which is started and managed by the calling app; + * 2. For windows, ort will infer the group id from a logical processor id, for example, assuming there are two groups with each has 64 logical processors, + * an id of 64 will be inferred as the last processor of the 1st group, while 65 will be interpreted as the 1st processor of the second group. + * Hence 64-65 is an invalid configuration, because a windows thread cannot be attached to processors across group boundary. + * + * \since Version 1.14 + */ + ORT_API2_STATUS(SetGlobalIntraOpThreadAffinity, _Inout_ OrtThreadingOptions* tp_options, const char* affinity_string); + + /** \brief Register custom ops from a shared library. + * + * Loads a shared library (.dll on windows, .so on linux, etc) named 'library_name' and looks for this entry point: + * OrtStatus* RegisterCustomOps(OrtSessionOptions * options, const OrtApiBase* api); + * It then passes in the provided session options to this function along with the api base. + * + * The handle to the loaded library is automatically released by ORT when the last OrtSession that references the + * library handle is released. If no OrtSession is created, then the library handle is released when the provided + * OrtSessionOptions is released. + * + * \param[in] options The session options. + * \param[in] library_name The name of the shared library to load and register. Refer to OS-specific dynamic library + * loading utilities (e.g., LoadLibraryEx on Windows or dlopen on Linux/MacOS) for information + * on the format of library names and search paths. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * \since Version 1.14 + */ + ORT_API2_STATUS(RegisterCustomOpsLibrary_V2, _Inout_ OrtSessionOptions* options, _In_ const ORTCHAR_T* library_name); + + /** \brief Register custom ops by calling a RegisterCustomOpsFn function. + * + * Searches for registration_func_name and if found calls it. + * + * The library containing the function must either be linked against or previously loaded by the executable. + * + * If you want ONNX Runtime to load the library and manage its lifetime, use RegisterCustomOpsLibrary_V2. + * + * RegisterCustomOpsUsingFunction can be used in scenarios where it may not be possible for ONNX Runtime to load + * the library from a path. e.g. mobile platforms where the library must be linked into the app. + * + * The registration function must have the signature of RegisterCustomOpsFn: + * OrtStatus* (*fn)(OrtSessionOptions* options, const OrtApiBase* api); + * + * See https://onnxruntime.ai/docs/reference/operators/add-custom-op.html for details on how the registration + * function should be implemented. + * + * \param[in] options OrtSessionOptions that is passed through as the first argument in the call to the + * registration function. + * \param[in] registration_func_name Name of registration function to use. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * \since Version 1.14 + */ + ORT_API2_STATUS(RegisterCustomOpsUsingFunction, _Inout_ OrtSessionOptions* options, + _In_ const char* registration_func_name); + + /// \name OrtKernelInfo + /// Custom operator APIs. + /// @{ + + /** \brief Get the number of inputs from ::OrtKernelInfo. + * + * Used in the CreateKernel callback of an OrtCustomOp to query the number of inputs + * during kernel/session creation. + * + * \param[in] info Instance of ::OrtKernelInfo. + * \param[out] out Pointer to variable assigned with the result on success. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * \since Version 1.14 + */ + ORT_API2_STATUS(KernelInfo_GetInputCount, _In_ const OrtKernelInfo* info, _Out_ size_t* out); + + /** \brief Get the number of outputs from ::OrtKernelInfo. + * + * Used in the CreateKernel callback of an OrtCustomOp to query the number of outputs + * during kernel/session creation. + * + * \param[in] info Instance of ::OrtKernelInfo. + * \param[out] out Pointer to variable assigned with the result on success. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * \since Version 1.14 + */ + ORT_API2_STATUS(KernelInfo_GetOutputCount, _In_ const OrtKernelInfo* info, _Out_ size_t* out); + + /** \brief Get the name of a ::OrtKernelInfo's input. + * + * Used in the CreateKernel callback of an OrtCustomOp to query an input's name + * during kernel/session creation. + * + * If `out` is nullptr, the value of `size` is set to the size of the name + * string (including null-terminator), and a success status is returned. + * + * If the `size` parameter is greater than or equal to the name string's size, + * the value of `size` is set to the true size of the string (including null-terminator), + * the provided memory is filled with the string's contents, and a success status is returned. + * + * If the `size` parameter is less than the actual string's size and `out` + * is not nullptr, the value of `size` is set to the true size of the string + * and a failure status is returned. + * + * \param[in] info An instance of ::OrtKernelInfo. + * \param[in] index The index of the input name to get. Returns a failure status if out-of-bounds. + * \param[out] out Memory location into which to write the UTF-8 null-terminated string representing the input's name. + * \param[in,out] size Pointer to the size of the `out` buffer. See above comments for details. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * \since Version 1.14 + */ + ORT_API2_STATUS(KernelInfo_GetInputName, _In_ const OrtKernelInfo* info, size_t index, _Out_ char* out, + _Inout_ size_t* size); + + /** \brief Get the name of a ::OrtKernelInfo's output. + * + * Used in the CreateKernel callback of an OrtCustomOp to query an output's name + * during kernel/session creation. + * + * If `out` is nullptr, the value of `size` is set to the size of the name + * string (including null-terminator), and a success status is returned. + * + * If the `size` parameter is greater than or equal to the name string's size, + * the value of `size` is set to the true size of the string (including null-terminator), + * the provided memory is filled with the string's contents, and a success status is returned. + * + * If the `size` parameter is less than the actual string's size and `out` + * is not nullptr, the value of `size` is set to the true size of the string + * and a failure status is returned. + * + * \param[in] info An instance of ::OrtKernelInfo. + * \param[in] index The index of the output name to get. Returns a failure status if out-of-bounds. + * \param[out] out Memory location into which to write the UTF-8 null-terminated string representing the output's + * name. + * \param[in,out] size Pointer to the size of the `out` buffer. See above comments for details. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * \since Version 1.14 + */ + ORT_API2_STATUS(KernelInfo_GetOutputName, _In_ const OrtKernelInfo* info, size_t index, _Out_ char* out, + _Inout_ size_t* size); + + /** \brief Get the type information for a ::OrtKernelInfo's input. + * + * Used in the CreateKernel callback of an OrtCustomOp to query the shape and type information + * of an input during kernel/session creation. + * + * \param[in] info An instance of ::OrtKernelInfo. + * \param[in] index Which input to get the type information for + * \param[out] type_info Pointer set to the resulting ::OrtTypeInfo. Must be freed with OrtApi::ReleaseTypeInfo. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * \since Version 1.14 + */ + ORT_API2_STATUS(KernelInfo_GetInputTypeInfo, _In_ const OrtKernelInfo* info, size_t index, + _Outptr_ OrtTypeInfo** type_info); + + /** \brief Get the type information for a ::OrtKernelInfo's output. + * + * Used in the CreateKernel callback of an OrtCustomOp to query the shape and type information + * of an output during kernel/session creation. + * + * \param[in] info An instance of ::OrtKernelInfo. + * \param[in] index Which input to get the type information for + * \param[out] type_info Pointer set to the resulting ::OrtTypeInfo. Must be freed with OrtApi::ReleaseTypeInfo. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * \since Version 1.14 + */ + ORT_API2_STATUS(KernelInfo_GetOutputTypeInfo, _In_ const OrtKernelInfo* info, size_t index, + _Outptr_ OrtTypeInfo** type_info); + + /** \brief Get a ::OrtValue tensor stored as an attribute in the graph node. + * + * Used in the CreateKernel callback of an OrtCustomOp to get a tensor attribute. + * + * \param[in] info ::OrtKernelInfo instance. + * \param[in] name UTF-8 null-terminated string representing the attribute's name. + * \param[in] allocator Allocator used to allocate the internal tensor state. + * \param[out] out Returns newly created ::OrtValue. Must be freed with OrtApi::ReleaseValue, + * which will also free internal tensor state allocated with the provided allocator. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(KernelInfoGetAttribute_tensor, _In_ const OrtKernelInfo* info, _In_z_ const char* name, + _Inout_ OrtAllocator* allocator, _Outptr_ OrtValue** out); + + /// @} + /// \name OrtSessionOptions + /// Custom operator APIs + /// @{ + + /** \brief Checks if the given session configuration entry exists. + * + * The config_key formats are defined in onnxruntime_session_options_config_keys.h + * + * Can be used in a custom operator library to check for session configuration entries + * that target one or more custom operators in the library. Example: The config entry + * custom_op.myop.some_key targets a custom op named "myop". + * + * \param[in] options The ::OrtSessionOptions instance. + * \param[in] config_key A null-terminated UTF-8 string representation of the configuration key. + * \param[out] out Pointer set to 1 if the entry exists and 0 otherwise. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * \since Version 1.14 + */ + ORT_API2_STATUS(HasSessionConfigEntry, _In_ const OrtSessionOptions* options, + _In_z_ const char* config_key, _Out_ int* out); + + /** \brief Get a session configuration value. + * + * Returns a failure status if the configuration key does not exist. + * The config_key and the format of config_value are defined in onnxruntime_session_options_config_keys.h + * + * If `config_value` is nullptr, the value of `size` is set to the true size of the string + * value (including null-terminator), and a success status is returned. + * + * If the `size` parameter is greater than or equal to the actual string value's size, + * the value of `size` is set to the true size of the string value, the provided memory + * is filled with the value's contents, and a success status is returned. + * + * If the `size` parameter is less than the actual string value's size and `config_value` + * is not nullptr, the value of `size` is set to the true size of the string value + * and a failure status is returned. + * + * Can be used in a custom operator library to get session configuration entries + * that target one or more custom operators in the library. Example: The config entry + * custom_op.myop.some_key targets a custom op named "myop". + * + * \param[in] options The session options. + * \param[in] config_key A null-terminated UTF-8 string representation of the config key. + * \param[in] config_value Pointer to memory where the null-terminated UTF-8 string value will be stored. + * \param[in,out] size Pointer to the size of the `config_value` buffer. See above comments for details. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * \since Version 1.14 + */ + ORT_API2_STATUS(GetSessionConfigEntry, _In_ const OrtSessionOptions* options, + _In_z_ const char* config_key, _Out_ char* config_value, _Inout_ size_t* size); + + /// @} + + /** \brief Append dnnl provider to session options + * + * If oneDNN is not available, this function will return failure. + * + * \param[in] options + * \param[in] dnnl_options + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.15. + */ + ORT_API2_STATUS(SessionOptionsAppendExecutionProvider_Dnnl, + _In_ OrtSessionOptions* options, _In_ const OrtDnnlProviderOptions* dnnl_options); + + /** \brief Create an OrtDnnlProviderOptions + * + * \param[out] out Newly created ::OrtDnnlProviderOptions. Must be released with OrtApi::ReleaseDnnlProviderOptions + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.15. + */ + ORT_API2_STATUS(CreateDnnlProviderOptions, _Outptr_ OrtDnnlProviderOptions** out); + + /** \brief Set options in a oneDNN Execution Provider. + * + * Key should be in null terminated string format of the member of ::OrtDnnlProviderOptions + * and value should be its related range. + * + * For example, key="use_arena" and value="1" + * + * \param[in] dnnl_options + * \param[in] provider_options_keys Array of UTF-8 null-terminated string for provider options keys + * \param[in] provider_options_values Array of UTF-8 null-terminated string for provider options values + * \param[in] num_keys Number of elements in the `provider_option_keys` and `provider_options_values` arrays + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.15. + */ + ORT_API2_STATUS(UpdateDnnlProviderOptions, _Inout_ OrtDnnlProviderOptions* dnnl_options, + _In_reads_(num_keys) const char* const* provider_options_keys, + _In_reads_(num_keys) const char* const* provider_options_values, + _In_ size_t num_keys); + + /** + * Get serialized oneDNN provider options string. + * + * For example, "use_arena=1;......" + * + * \param dnnl_options - OrtDnnlProviderOptions instance + * \param allocator - a ptr to an instance of OrtAllocator obtained with CreateAllocator() or GetAllocatorWithDefaultOptions() + * the specified allocator will be used to allocate continuous buffers for output strings and lengths. + * \param ptr - is a UTF-8 null terminated string allocated using 'allocator'. The caller is responsible for using the same allocator to free it. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.15. + */ + ORT_API2_STATUS(GetDnnlProviderOptionsAsString, _In_ const OrtDnnlProviderOptions* dnnl_options, _Inout_ OrtAllocator* allocator, _Outptr_ char** ptr); + + /** \brief Release an ::OrtDnnlProviderOptions + * + * \since Version 1.15. + */ + void(ORT_API_CALL* ReleaseDnnlProviderOptions)(_Frees_ptr_opt_ OrtDnnlProviderOptions* input); + + /// \name OrtKernelInfo + /// Custom operator APIs. + /// @{ + + /** \brief Get the graph node name from ::OrtKernelInfo. + * + * If `out` is nullptr, the value of `size` is set to the size of the name + * string (including null-terminator), and a success status is returned. + * + * If the `size` parameter is greater than or equal to the name string's size, + * the value of `size` is set to the true size of the string (including null-terminator), + * the provided memory is filled with the string's contents, and a success status is returned. + * + * If the `size` parameter is less than the actual string's size and `out` + * is not nullptr, the value of `size` is set to the true size of the string + * and a failure status is returned. + * + * Can be used in a custom operator's CreateKernel callback to get the name of the operator's node name in the graph. + * + * \param[in] info An instance of ::OrtKernelInfo. + * \param[out] out Memory location into which to write the UTF-8 null-terminated string representing the name. + * \param[in,out] size Pointer to the size of the `out` buffer. See above comments for details. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * \since Version 1.15 + */ + ORT_API2_STATUS(KernelInfo_GetNodeName, _In_ const OrtKernelInfo* info, _Out_ char* out, _Inout_ size_t* size); + + /** \brief Get the session logger from ::OrtKernelInfo. + * + * Used in the CreateKernel callback of an OrtCustomOp to get a logger that can be used to log + * messages. + * + * \param[in] info An instance of ::OrtKernelInfo. + * \param[out] logger Pointer set to the session's ::OrtLogger. Owned by ONNX Runtime, so do not free. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * \since Version 1.15 + */ + ORT_API2_STATUS(KernelInfo_GetLogger, _In_ const OrtKernelInfo* info, _Outptr_ const OrtLogger** logger); + + /// @} + /// \name OrtKernelContext + /// Custom operator APIs. + /// @{ + + /** \brief Get the runtime logger from ::OrtKernelContext. + * + * Used in the KernelCompute callback of an OrtCustomOp to get a logger that can be used to log + * messages during inference. + * + * \param[in] context An instance of ::OrtKernelContext. + * \param[out] logger Pointer set to the kernel context's ::OrtLogger. Owned by ONNX Runtime, so do not free. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * \since Version 1.15 + */ + ORT_API2_STATUS(KernelContext_GetLogger, _In_ const OrtKernelContext* context, _Outptr_ const OrtLogger** logger); + + /// @} + /// \name OrtLogger + /// Custom operator APIs. + /// @{ + + /** \brief Logs a message at the given severity level using the provided ::OrtLogger. + * + * Only messages with a severity level equal or greater than the ::OrtLogger's logging severity level + * are logged. Use OrtApi::Logger_GetLoggingSeverityLevel to get the ::OrtLogger's logging severity + * level. + * + * Can be used in custom operators to log messages with the logger retrieved via OrtApi::KernelInfo_GetLogger. + * + * \param[in] logger The ::OrtLogger instance. + * \param[in] log_severity_level The message's severity level. + * \param[in] message The message to log. + * \param[in] file_path The filepath of the file in which the message is logged. Usually the value of ORT_FILE. + * \param[in] line_number The file line number in which the message is logged. Usually the value of __LINE__. + * \param[in] func_name The name of the function in which the message is logged. Usually the value of __FUNCTION__. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * \since Version 1.15 + */ + ORT_API2_STATUS(Logger_LogMessage, _In_ const OrtLogger* logger, OrtLoggingLevel log_severity_level, + _In_z_ const char* message, _In_z_ const ORTCHAR_T* file_path, int line_number, + _In_z_ const char* func_name); + + /** \brief Get the logging severity level of the ::OrtLogger. + * + * Can be used in a custom operator to get the logging serverity level of the ::OrtLogger associated with + * the ::OrtKernelInfo. + * + * \param[in] logger The ::OrtLogger instance. + * \param[out] out Pointer to variable assigned with the logging severity level on success. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * \since Version 1.15 + */ + ORT_API2_STATUS(Logger_GetLoggingSeverityLevel, _In_ const OrtLogger* logger, _Out_ OrtLoggingLevel* out); + + /// @} + + /** \brief Get a ::OrtValue tensor stored as a constant initializer in the graph node. + * + * Used in the CreateKernel callback of an OrtCustomOp to get a tensor value. + * + * \param[in] info ::OrtKernelInfo instance. + * \param[in] index The node index. + * \param[out] is_constant Is it a constant node input or not. + * \param[out] out The OrtValue tensor value. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.15. + */ + ORT_API2_STATUS(KernelInfoGetConstantInput_tensor, _In_ const OrtKernelInfo* info, size_t index, _Out_ int* is_constant, _Outptr_ const OrtValue** out); + + /** \brief Get Optional Type information from an ::OrtTypeInfo + * + * This augments ::OrtTypeInfo to return an ::OrtOptionalTypeInfo when the type is optional. + * The OrtOptionalTypeInfo also has a nested ::OrtTypeInfo that describes the type of the optional value. + * ::OrtOptionalTypeInfo type can only appear within model metadata to describe inputs/outputs. + * The actual OrtValues that are supplied in place of optional type inputs should contain + * specific type that is described by ::OrtOptionalTypeInfo. + * + * So the picture: ::OrtTypeInfo -> ::OrtOptionalTypeInfo -> ::OrtTypeInfo (describes the type that can be supplied + * in place of the optional type when creating the actual ::OrtValue). + * + * \param[in] type_info + * \param[out] out A pointer to the ::OrtOptionalTypeInfo. Do not free this value, + * it is owned by OrtTypeInfo instance. When the type_info does not represent + * optional type, nullptr is returned in out. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.15. + */ + ORT_API2_STATUS(CastTypeInfoToOptionalTypeInfo, _In_ const OrtTypeInfo* type_info, + _Outptr_result_maybenull_ const OrtOptionalTypeInfo** out); + + /** \brief Get OrtTypeInfo for the allowed contained type from an ::OrtOptionalTypeInfo. + * + * This augments ::OrtOptionalTypeInfo to return an ::OrtTypeInfo for the contained type. + * The OrtOptionalTypeInfo has a nested ::OrtTypeInfo that describes the type of the optional value. + * ::OrtOptionalTypeInfo type can only appear within model metadata to describe inputs/outputs. + * The actual OrtValues that are supplied in place of optional type inputs should contain + * specific type that is described by the returned ::OrtTypeInfo. + * + * \param[in] optional_type_info + * \param[out] out A pointer to the ::OrtTypeInfo for what the optional value could be. + * it is owned by OrtOptionalTypeInfo instance. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.15. + */ + ORT_API2_STATUS(GetOptionalContainedTypeInfo, _In_ const OrtOptionalTypeInfo* optional_type_info, + _Outptr_ OrtTypeInfo** out); + + /** \brief Set a single string in a string tensor + * Do not zero terminate the string data. + * + * \param[in] value A string tensor + * \param[in] index - flat index of the element + * \param[in] length_in_bytes length of the buffer in utf-8 bytes (without the null terminator) + * \param[inout] buffer - address of return value + * + * \snippet{doc} snippets.dox OrtStatus Return Value + */ + ORT_API2_STATUS(GetResizedStringTensorElementBuffer, _Inout_ OrtValue* value, _In_ size_t index, _In_ size_t length_in_bytes, _Inout_ char** buffer); + + /** \brief Get Allocator from KernelContext for a specific memoryInfo. Please use C API ReleaseAllocator to release out object + * + * \param[in] context OrtKernelContext instance + * \param[in] mem_info OrtMemoryInfo instance + * \param[out] out A pointer to OrtAllocator. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.15. + */ + ORT_API2_STATUS(KernelContext_GetAllocator, _In_ const OrtKernelContext* context, _In_ const OrtMemoryInfo* mem_info, _Outptr_ OrtAllocator** out); + + /** \brief Returns a null terminated string of the build info including git info and cxx flags + * + * \return UTF-8 encoded version string. Do not deallocate the returned buffer. + * + * \since Version 1.15. + */ + const char*(ORT_API_CALL* GetBuildInfoString)(void); + + /// \name OrtROCMProviderOptions + /// @{ + + /** \brief Create an OrtROCMProviderOptions + * + * \param[out] out Newly created ::OrtROCMProviderOptions. Must be released with OrtApi::ReleaseROCMProviderOptions + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.16. + */ + ORT_API2_STATUS(CreateROCMProviderOptions, _Outptr_ OrtROCMProviderOptions** out); + + /** \brief Set options in a ROCm Execution Provider. + * + * Please refer to https://onnxruntime.ai/docs/execution-providers/ROCm-ExecutionProvider.html + * to know the available keys and values. Key should be in null terminated string format of the member of + * ::OrtROCMProviderOptions and value should be its related range. + * + * For example, key="device_id" and value="0" + * + * \param[in] rocm_options + * \param[in] provider_options_keys Array of UTF-8 null-terminated string for provider options keys + * \param[in] provider_options_values Array of UTF-8 null-terminated string for provider options values + * \param[in] num_keys Number of elements in the `provider_option_keys` and `provider_options_values` arrays + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.16. + */ + ORT_API2_STATUS(UpdateROCMProviderOptions, _Inout_ OrtROCMProviderOptions* rocm_options, + _In_reads_(num_keys) const char* const* provider_options_keys, + _In_reads_(num_keys) const char* const* provider_options_values, + _In_ size_t num_keys); + + /** + * Get serialized ROCm provider options string. + * + * For example, "device_id=0;arena_extend_strategy=0;......" + * + * \param rocm_options - OrtROCMProviderOptions instance + * \param allocator - a ptr to an instance of OrtAllocator obtained with CreateAllocator() or GetAllocatorWithDefaultOptions() + * the specified allocator will be used to allocate continuous buffers for output strings and lengths. + * \param ptr - is a UTF-8 null terminated string allocated using 'allocator'. The caller is responsible for using the same allocator to free it. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.16. + */ + ORT_API2_STATUS(GetROCMProviderOptionsAsString, _In_ const OrtROCMProviderOptions* rocm_options, _Inout_ OrtAllocator* allocator, _Outptr_ char** ptr); + + /** \brief Release an ::OrtROCMProviderOptions + * + * \note This is an exception in the naming convention of other Release* functions, as the name of the method does not have the V2 suffix, but the type does + * + * \since Version 1.16. + */ + void(ORT_API_CALL* ReleaseROCMProviderOptions)(_Frees_ptr_opt_ OrtROCMProviderOptions* input); + + /** \brief Create an allocator with specific type and register it with the ::OrtEnv + * This API enhance CreateAndRegisterAllocator that it can create an allocator with specific type, not just CPU allocator + * Enables sharing the allocator between multiple sessions that use the same env instance. + * Lifetime of the created allocator will be valid for the duration of the environment. + * Returns an error if an allocator with the same ::OrtMemoryInfo is already registered. + * \param[in] env OrtEnv instance + * \param[in] provider_type ExecutionProvider type + * \param[in] mem_info OrtMemoryInfo instance + * \param[in] arena_cfg Arena configuration + * \param[in] provider_options_keys key of the provider options map + * \param[in] provider_options_values value of the provider options map + * \param[in] num_keys Length of the provider options map + */ + ORT_API2_STATUS(CreateAndRegisterAllocatorV2, _Inout_ OrtEnv* env, _In_ const char* provider_type, _In_ const OrtMemoryInfo* mem_info, _In_ const OrtArenaCfg* arena_cfg, + _In_reads_(num_keys) const char* const* provider_options_keys, _In_reads_(num_keys) const char* const* provider_options_values, _In_ size_t num_keys); + + /** \brief Run the model asynchronously in a thread owned by intra op thread pool + * + * \param[in] session + * \param[in] run_options If nullptr, will use a default ::OrtRunOptions + * \param[in] input_names Array of null terminated UTF8 encoded strings of the input names + * \param[in] input Array of ::OrtValue%s of the input values + * \param[in] input_len Number of elements in the input_names and inputs arrays + * \param[in] output_names Array of null terminated UTF8 encoded strings of the output names + * \param[in] output_names_len Number of elements in the output_names and outputs array + * \param[out] output OrtValue* array of size output_names_len. + * On calling RunAsync, output[i] could either be a null or a pointer to a preallocated OrtValue. + * Later, the output array will be passed to run_async_callback with all null(s) filled with valid + * OrtValue pointer(s) allocated by onnxruntime. + * NOTE: it is customer's duty to finally release the output array and each of its member, + * regardless of whether the member (OrtValue*) is allocated by onnxruntime or preallocated by the customer. + * \param[in] run_async_callback Callback function on model run completion + * \param[in] user_data User data that pass back to run_async_callback + */ + ORT_API2_STATUS(RunAsync, _Inout_ OrtSession* session, _In_opt_ const OrtRunOptions* run_options, + _In_reads_(input_len) const char* const* input_names, + _In_reads_(input_len) const OrtValue* const* input, size_t input_len, + _In_reads_(output_names_len) const char* const* output_names, size_t output_names_len, + _Inout_updates_all_(output_names_len) OrtValue** output, + _In_ RunAsyncCallbackFn run_async_callback, _In_opt_ void* user_data); + + /** + * Update TensorRT EP provider option where its data type is pointer, for example 'user_compute_stream'. + * If the data type of the provider option can be represented by string please use UpdateTensorRTProviderOptions. + * + * Note: It's caller's responsibility to properly manage the lifetime of the instance pointed by this pointer. + * + * \param tensorrt_options - OrtTensorRTProviderOptionsV2 instance + * \param key - Name of the provider option + * \param value - A pointer to the instance that will be assigned to this provider option + * + * \since Version 1.16. + */ + ORT_API2_STATUS(UpdateTensorRTProviderOptionsWithValue, _Inout_ OrtTensorRTProviderOptionsV2* tensorrt_options, _In_ const char* key, _In_ void* value); + + /** + * Get TensorRT EP provider option where its data type is pointer. + * If the data type of the provider option can be represented by string please use GetTensorRTProviderOptionsAsString. + * + * \param tensorrt_options - OrtTensorRTProviderOptionsV2 instance + * \param key - Name of the provider option + * \param ptr - A pointer to the instance that is kept by the provider option + * + * \since Version 1.16. + */ + ORT_API2_STATUS(GetTensorRTProviderOptionsByName, _In_ const OrtTensorRTProviderOptionsV2* tensorrt_options, _In_ const char* key, _Outptr_ void** ptr); + + /** + * Update CUDA EP provider option where its data type is pointer, for example 'user_compute_stream'. + * If the data type of the provider option can be represented by string please use UpdateCUDAProviderOptions. + * + * Note: It's caller's responsibility to properly manage the lifetime of the instance pointed by this pointer. + * + * \param cuda_options - OrtCUDAProviderOptionsV2 instance + * \param key - Name of the provider option + * \param value - A pointer to the instance that will be assigned to this provider option + * + * \since Version 1.16. + */ + ORT_API2_STATUS(UpdateCUDAProviderOptionsWithValue, _Inout_ OrtCUDAProviderOptionsV2* cuda_options, _In_ const char* key, _In_ void* value); + + /** + * Get CUDA EP provider option where its data type is pointer. + * If the data type of the provider option can be represented by string please use GetCUDAProviderOptionsAsString. + * + * \param cuda_options - OrtCUDAProviderOptionsV2 instance + * \param key - Name of the provider option + * \param ptr - A pointer to the instance that is kept by the provider option + * + * \since Version 1.16. + */ + ORT_API2_STATUS(GetCUDAProviderOptionsByName, _In_ const OrtCUDAProviderOptionsV2* cuda_options, _In_ const char* key, _Outptr_ void** ptr); + + /** + * Get a EP resoure. + * E.g. a cuda stream or a cublas handle + * + * \param context - Kernel context + * \param resouce_version - Version of the resource + * \param resource_id - Type of resource + * \param resource - A pointer to returned resource + * + * \since Version 1.16. + */ + ORT_API2_STATUS(KernelContext_GetResource, _In_ const OrtKernelContext* context, _In_ int resouce_version, _In_ int resource_id, _Outptr_ void** resource); +}; + +/* + * Steps to use a custom op: + * 1 Create an OrtCustomOpDomain with the domain name used by the custom ops + * 2 Create an OrtCustomOp structure for each op and add them to the domain + * 3 Call OrtAddCustomOpDomain to add the custom domain of ops to the session options + */ + +// Specifies some characteristics of inputs/outputs of custom ops: +// Specify if the inputs/outputs are one of: +// 1) Non-optional (input/output must be present in the node) +// 2) Optional (input/output may be absent in the node) +// 3) Variadic: A variadic input or output specifies N (i.e., the minimum arity) or more operands. +// Only the last input or output of a custom op may be marked as variadic. +// The homogeneity of the variadic input or output determines whether all operands must be of the same +// tensor element type. +typedef enum OrtCustomOpInputOutputCharacteristic { + INPUT_OUTPUT_REQUIRED = 0, + INPUT_OUTPUT_OPTIONAL, + INPUT_OUTPUT_VARIADIC, +} OrtCustomOpInputOutputCharacteristic; + +/* + * The OrtCustomOp structure defines a custom op's schema and its kernel callbacks. The callbacks are filled in by + * the implementor of the custom op. + */ +struct OrtCustomOp { + uint32_t version; // Must be initialized to ORT_API_VERSION + + // This callback creates the kernel, which is a user defined + // parameter that is passed to the Kernel* callbacks below. It is + // recommended to use CreateKernelV2 which allows for a safe error + // propagation by returning an OrtStatusPtr. + void*(ORT_API_CALL* CreateKernel)(_In_ const struct OrtCustomOp* op, _In_ const OrtApi* api, + _In_ const OrtKernelInfo* info); + + // Returns the name of the op + const char*(ORT_API_CALL* GetName)(_In_ const struct OrtCustomOp* op); + + // Returns the type of the execution provider, return nullptr to use CPU execution provider + const char*(ORT_API_CALL* GetExecutionProviderType)(_In_ const struct OrtCustomOp* op); + + // Returns the count and types of the input & output tensors + ONNXTensorElementDataType(ORT_API_CALL* GetInputType)(_In_ const struct OrtCustomOp* op, _In_ size_t index); + size_t(ORT_API_CALL* GetInputTypeCount)(_In_ const struct OrtCustomOp* op); + ONNXTensorElementDataType(ORT_API_CALL* GetOutputType)(_In_ const struct OrtCustomOp* op, _In_ size_t index); + size_t(ORT_API_CALL* GetOutputTypeCount)(_In_ const struct OrtCustomOp* op); + + // Perform a computation step. It is recommended to use + // KernelComputeV2 which allows for a safe error propagation by + // returning an OrtStatusPtr. + void(ORT_API_CALL* KernelCompute)(_In_ void* op_kernel, _In_ OrtKernelContext* context); + void(ORT_API_CALL* KernelDestroy)(_In_ void* op_kernel); + + // Returns the characteristics of the input & output tensors + OrtCustomOpInputOutputCharacteristic(ORT_API_CALL* GetInputCharacteristic)(_In_ const struct OrtCustomOp* op, _In_ size_t index); + OrtCustomOpInputOutputCharacteristic(ORT_API_CALL* GetOutputCharacteristic)(_In_ const struct OrtCustomOp* op, _In_ size_t index); + + // Returns the memory type of the input tensors. This API allows the custom op + // to place the inputs on specific devices. By default, it returns + // OrtMemTypeDefault, which means the input is placed on the default device for + // the execution provider. If the inputs need to be with different memory tyeps, + // this function can be overridden to return the specific memory types. + OrtMemType(ORT_API_CALL* GetInputMemoryType)(_In_ const struct OrtCustomOp* op, _In_ size_t index); + + // Returns the minimum number of input arguments expected for the variadic input. + // Applicable only for custom ops that have a variadic input. + int(ORT_API_CALL* GetVariadicInputMinArity)(_In_ const struct OrtCustomOp* op); + + // Returns true (non-zero) if all arguments of a variadic input have to be of the same type (homogeneous), + // and false (zero) otherwise. + // Applicable only for custom ops that have a variadic input. + int(ORT_API_CALL* GetVariadicInputHomogeneity)(_In_ const struct OrtCustomOp* op); + + // Returns the minimum number of output values expected for the variadic output. + // Applicable only for custom ops that have a variadic output. + int(ORT_API_CALL* GetVariadicOutputMinArity)(_In_ const struct OrtCustomOp* op); + + // Returns true (non-zero) if all outputs values of a variadic output have to be of the same type (homogeneous), + // and false (zero) otherwise. + // Applicable only for custom ops that have a variadic output. + int(ORT_API_CALL* GetVariadicOutputHomogeneity)(_In_ const struct OrtCustomOp* op); + + // Create the kernel state which is passed to each compute call. + OrtStatusPtr(ORT_API_CALL* CreateKernelV2)(_In_ const struct OrtCustomOp* op, _In_ const OrtApi* api, + _In_ const OrtKernelInfo* info, + _Out_ void** kernel); + + // Perform the computation step. + OrtStatusPtr(ORT_API_CALL* KernelComputeV2)(_In_ void* op_kernel, _In_ OrtKernelContext* context); +}; + +/* + * This is the old way to add the CUDA provider to the session, please use SessionOptionsAppendExecutionProvider_CUDA above to access the latest functionality + * This function always exists, but will only succeed if Onnxruntime was built with CUDA support and the CUDA provider shared library exists + * + * \param device_id CUDA device id, starts from zero. + */ +ORT_API_STATUS(OrtSessionOptionsAppendExecutionProvider_CUDA, _In_ OrtSessionOptions* options, int device_id); + +/* + * This is the old way to add the ROCm provider to the session, please use + * SessionOptionsAppendExecutionProvider_ROCM above to access the latest functionality + * This function always exists, but will only succeed if Onnxruntime was built with + * HIP support and the ROCm provider shared library exists + * + * \param device_id HIP device id, starts from zero. + */ +ORT_API_STATUS(OrtSessionOptionsAppendExecutionProvider_ROCM, _In_ OrtSessionOptions* options, int device_id); + +/* + * This is the old way to add the MIGraphX provider to the session, please use + * SessionOptionsAppendExecutionProvider_MIGraphX above to access the latest functionality + * This function always exists, but will only succeed if Onnxruntime was built with + * HIP support and the MIGraphX provider shared library exists + * + * \param device_id HIP device id, starts from zero. + */ +ORT_API_STATUS(OrtSessionOptionsAppendExecutionProvider_MIGraphX, _In_ OrtSessionOptions* options, int device_id); + +/* + * This is the old way to add the oneDNN provider to the session, please use + * SessionOptionsAppendExecutionProvider_oneDNN above to access the latest functionality + * This function always exists, but will only succeed if Onnxruntime was built with + * oneDNN support and the oneDNN provider shared library exists + * + * \param use_arena zero: false. non-zero: true. + */ +ORT_API_STATUS(OrtSessionOptionsAppendExecutionProvider_Dnnl, _In_ OrtSessionOptions* options, int use_arena); + +#ifdef __cplusplus +} +#endif +/// @} diff --git a/duix-sdk/src/main/cpp/third/arm/include/onnx/onnxruntime_cxx_api.h b/duix-sdk/src/main/cpp/third/arm/include/onnx/onnxruntime_cxx_api.h new file mode 100644 index 0000000..709272d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/onnx/onnxruntime_cxx_api.h @@ -0,0 +1,2268 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// Summary: The Ort C++ API is a header only wrapper around the Ort C API. +// +// The C++ API simplifies usage by returning values directly instead of error codes, throwing exceptions on errors +// and automatically releasing resources in the destructors. The primary purpose of C++ API is exception safety so +// all the resources follow RAII and do not leak memory. +// +// Each of the C++ wrapper classes holds only a pointer to the C internal object. Treat them like smart pointers. +// To create an empty object, pass 'nullptr' to the constructor (for example, Env e{nullptr};). However, you can't use them +// until you assign an instance that actually holds an underlying object. +// +// For Ort objects only move assignment between objects is allowed, there are no copy constructors. +// Some objects have explicit 'Clone' methods for this purpose. +// +// ConstXXXX types are copyable since they do not own the underlying C object, so you can pass them to functions as arguments +// by value or by reference. ConstXXXX types are restricted to const only interfaces. +// +// UnownedXXXX are similar to ConstXXXX but also allow non-const interfaces. +// +// The lifetime of the corresponding owning object must eclipse the lifetimes of the ConstXXXX/UnownedXXXX types. They exists so you do not +// have to fallback to C types and the API with the usual pitfalls. In general, do not use C API from your C++ code. + +#pragma once +#define ORT_NO_EXCEPTIONS TRUE +#include "onnxruntime_c_api.h" +#include "onnxruntime_float16.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef ORT_NO_EXCEPTIONS +#include +#endif + +/** \brief All C++ Onnxruntime APIs are defined inside this namespace + * + */ +namespace Ort { + +/** \brief All C++ methods that can fail will throw an exception of this type + * + * If ORT_NO_EXCEPTIONS is defined, then any error will result in a call to abort() + */ +struct Exception : std::exception { + Exception(std::string&& string, OrtErrorCode code) : message_{std::move(string)}, code_{code} {} + + OrtErrorCode GetOrtErrorCode() const { return code_; } + const char* what() const noexcept override { return message_.c_str(); } + + private: + std::string message_; + OrtErrorCode code_; +}; + +//#define ORT_NO_EXCEPTIONS +#ifdef ORT_NO_EXCEPTIONS +// The #ifndef is for the very special case where the user of this library wants to define their own way of handling errors. +// NOTE: This header expects control flow to not continue after calling ORT_CXX_API_THROW +#ifndef ORT_CXX_API_THROW +#define ORT_CXX_API_THROW(string, code) \ + while(false) { \ + std::cerr << Ort::Exception(string, code) \ + .what() \ + << std::endl; \ + abort(); \ + } +#endif +#else +#define ORT_CXX_API_THROW(string, code) \ + throw Ort::Exception(string, code) +#endif + +// This is used internally by the C++ API. This class holds the global variable that points to the OrtApi, +// it's in a template so that we can define a global variable in a header and make +// it transparent to the users of the API. +template +struct Global { + static const OrtApi* api_; +}; + +// If macro ORT_API_MANUAL_INIT is defined, no static initialization will be performed. Instead, user must call InitApi() before using it. +template +#ifdef ORT_API_MANUAL_INIT +const OrtApi* Global::api_{}; +inline void InitApi() noexcept { Global::api_ = OrtGetApiBase()->GetApi(ORT_API_VERSION); } + +// Used by custom operator libraries that are not linked to onnxruntime. Sets the global API object, which is +// required by C++ APIs. +// +// Example mycustomop.cc: +// +// #define ORT_API_MANUAL_INIT +// #include +// #undef ORT_API_MANUAL_INIT +// +// OrtStatus* ORT_API_CALL RegisterCustomOps(OrtSessionOptions* options, const OrtApiBase* api_base) { +// Ort::InitApi(api_base->GetApi(ORT_API_VERSION)); +// // ... +// } +// +inline void InitApi(const OrtApi* api) noexcept { Global::api_ = api; } +#else +#if defined(_MSC_VER) && !defined(__clang__) +#pragma warning(push) +// "Global initializer calls a non-constexpr function." Therefore you can't use ORT APIs in the other global initializers. +// Please define ORT_API_MANUAL_INIT if it conerns you. +#pragma warning(disable : 26426) +#endif +const OrtApi* Global::api_ = OrtGetApiBase()->GetApi(ORT_API_VERSION); +#if defined(_MSC_VER) && !defined(__clang__) +#pragma warning(pop) +#endif +#endif + +/// This returns a reference to the OrtApi interface in use +inline const OrtApi& GetApi() noexcept { return *Global::api_; } + +/// +/// This function returns the onnxruntime version string +/// +/// version string major.minor.rev +std::string GetVersionString(); + +/// +/// This function returns the onnxruntime build information: including git branch, +/// git commit id, build type(Debug/Release/RelWithDebInfo) and cmake cpp flags. +/// +/// string +std::string GetBuildInfoString(); + +/// +/// This is a C++ wrapper for OrtApi::GetAvailableProviders() and +/// returns a vector of strings representing the available execution providers. +/// +/// vector of strings +std::vector GetAvailableProviders(); + +/** \brief IEEE 754 half-precision floating point data type + * + * \details This struct is used for converting float to float16 and back + * so the user could feed inputs and fetch outputs using these type. + * + * The size of the structure should align with uint16_t and one can freely cast + * uint16_t buffers to/from Ort::Float16_t to feed and retrieve data. + * + * \code{.unparsed} + * // This example demonstrates converion from float to float16 + * constexpr float values[] = {1.f, 2.f, 3.f, 4.f, 5.f}; + * std::vector fp16_values; + * fp16_values.reserve(std::size(values)); + * std::transform(std::begin(values), std::end(values), std::back_inserter(fp16_values), + * [](float value) { return Ort::Float16_t(value); }); + * + * \endcode + */ +struct Float16_t : onnxruntime_float16::Float16Impl { + private: + /// + /// Constructor from a 16-bit representation of a float16 value + /// No conversion is done here. + /// + /// 16-bit representation + constexpr explicit Float16_t(uint16_t v) noexcept { val = v; } + + public: + using Base = onnxruntime_float16::Float16Impl; + + /// + /// Default constructor + /// + Float16_t() = default; + + /// + /// Explicit conversion to uint16_t representation of float16. + /// + /// uint16_t bit representation of float16 + /// new instance of Float16_t + constexpr static Float16_t FromBits(uint16_t v) noexcept { return Float16_t(v); } + + /// + /// __ctor from float. Float is converted into float16 16-bit representation. + /// + /// float value + explicit Float16_t(float v) noexcept { val = Base::ToUint16Impl(v); } + + /// + /// Converts float16 to float + /// + /// float representation of float16 value + float ToFloat() const noexcept { return Base::ToFloatImpl(); } + + /// + /// Checks if the value is negative + /// + /// true if negative + using Base::IsNegative; + + /// + /// Tests if the value is NaN + /// + /// true if NaN + using Base::IsNaN; + + /// + /// Tests if the value is finite + /// + /// true if finite + using Base::IsFinite; + + /// + /// Tests if the value represents positive infinity. + /// + /// true if positive infinity + using Base::IsPositiveInfinity; + + /// + /// Tests if the value represents negative infinity + /// + /// true if negative infinity + using Base::IsNegativeInfinity; + + /// + /// Tests if the value is either positive or negative infinity. + /// + /// True if absolute value is infinity + using Base::IsInfinity; + + /// + /// Tests if the value is NaN or zero. Useful for comparisons. + /// + /// True if NaN or zero. + using Base::IsNaNOrZero; + + /// + /// Tests if the value is normal (not zero, subnormal, infinite, or NaN). + /// + /// True if so + using Base::IsNormal; + + /// + /// Tests if the value is subnormal (denormal). + /// + /// True if so + using Base::IsSubnormal; + + /// + /// Creates an instance that represents absolute value. + /// + /// Absolute value + using Base::Abs; + + /// + /// Creates a new instance with the sign flipped. + /// + /// Flipped sign instance + using Base::Negate; + + /// + /// IEEE defines that positive and negative zero are equal, this gives us a quick equality check + /// for two values by or'ing the private bits together and stripping the sign. They are both zero, + /// and therefore equivalent, if the resulting value is still zero. + /// + /// first value + /// second value + /// True if both arguments represent zero + using Base::AreZero; + + /// + /// User defined conversion operator. Converts Float16_t to float. + /// + explicit operator float() const noexcept { return ToFloat(); } + + using Base::operator==; + using Base::operator!=; + using Base::operator<; +}; + +static_assert(sizeof(Float16_t) == sizeof(uint16_t), "Sizes must match"); + +/** \brief bfloat16 (Brain Floating Point) data type + * + * \details This struct is used for converting float to bfloat16 and back + * so the user could feed inputs and fetch outputs using these type. + * + * The size of the structure should align with uint16_t and one can freely cast + * uint16_t buffers to/from Ort::BFloat16_t to feed and retrieve data. + * + * \code{.unparsed} + * // This example demonstrates converion from float to float16 + * constexpr float values[] = {1.f, 2.f, 3.f, 4.f, 5.f}; + * std::vector bfp16_values; + * bfp16_values.reserve(std::size(values)); + * std::transform(std::begin(values), std::end(values), std::back_inserter(bfp16_values), + * [](float value) { return Ort::BFloat16_t(value); }); + * + * \endcode + */ +struct BFloat16_t : onnxruntime_float16::BFloat16Impl { + private: + /// + /// Constructor from a uint16_t representation of bfloat16 + /// used in FromBits() to escape overload resolution issue with + /// constructor from float. + /// No conversion is done. + /// + /// 16-bit bfloat16 value + constexpr explicit BFloat16_t(uint16_t v) noexcept { val = v; } + + public: + using Base = onnxruntime_float16::BFloat16Impl; + + BFloat16_t() = default; + + /// + /// Explicit conversion to uint16_t representation of bfloat16. + /// + /// uint16_t bit representation of bfloat16 + /// new instance of BFloat16_t + static constexpr BFloat16_t FromBits(uint16_t v) noexcept { return BFloat16_t(v); } + + /// + /// __ctor from float. Float is converted into bfloat16 16-bit representation. + /// + /// float value + explicit BFloat16_t(float v) noexcept { val = Base::ToUint16Impl(v); } + + /// + /// Converts bfloat16 to float + /// + /// float representation of bfloat16 value + float ToFloat() const noexcept { return Base::ToFloatImpl(); } + + /// + /// Checks if the value is negative + /// + /// true if negative + using Base::IsNegative; + + /// + /// Tests if the value is NaN + /// + /// true if NaN + using Base::IsNaN; + + /// + /// Tests if the value is finite + /// + /// true if finite + using Base::IsFinite; + + /// + /// Tests if the value represents positive infinity. + /// + /// true if positive infinity + using Base::IsPositiveInfinity; + + /// + /// Tests if the value represents negative infinity + /// + /// true if negative infinity + using Base::IsNegativeInfinity; + + /// + /// Tests if the value is either positive or negative infinity. + /// + /// True if absolute value is infinity + using Base::IsInfinity; + + /// + /// Tests if the value is NaN or zero. Useful for comparisons. + /// + /// True if NaN or zero. + using Base::IsNaNOrZero; + + /// + /// Tests if the value is normal (not zero, subnormal, infinite, or NaN). + /// + /// True if so + using Base::IsNormal; + + /// + /// Tests if the value is subnormal (denormal). + /// + /// True if so + using Base::IsSubnormal; + + /// + /// Creates an instance that represents absolute value. + /// + /// Absolute value + using Base::Abs; + + /// + /// Creates a new instance with the sign flipped. + /// + /// Flipped sign instance + using Base::Negate; + + /// + /// IEEE defines that positive and negative zero are equal, this gives us a quick equality check + /// for two values by or'ing the private bits together and stripping the sign. They are both zero, + /// and therefore equivalent, if the resulting value is still zero. + /// + /// first value + /// second value + /// True if both arguments represent zero + using Base::AreZero; + + /// + /// User defined conversion operator. Converts BFloat16_t to float. + /// + explicit operator float() const noexcept { return ToFloat(); } + + // We do not have an inherited impl for the below operators + // as the internal class implements them a little differently + bool operator==(const BFloat16_t& rhs) const noexcept; + bool operator!=(const BFloat16_t& rhs) const noexcept { return !(*this == rhs); } + bool operator<(const BFloat16_t& rhs) const noexcept; +}; + +static_assert(sizeof(BFloat16_t) == sizeof(uint16_t), "Sizes must match"); + +/** \brief float8e4m3fn (Float8 Floating Point) data type + * \details It is necessary for type dispatching to make use of C++ API + * The type is implicitly convertible to/from uint8_t. + * See https://onnx.ai/onnx/technical/float8.html for further details. + */ +struct Float8E4M3FN_t { + uint8_t value; + constexpr Float8E4M3FN_t() noexcept : value(0) {} + constexpr Float8E4M3FN_t(uint8_t v) noexcept : value(v) {} + constexpr operator uint8_t() const noexcept { return value; } + // nan values are treated like any other value for operator ==, != + constexpr bool operator==(const Float8E4M3FN_t& rhs) const noexcept { return value == rhs.value; }; + constexpr bool operator!=(const Float8E4M3FN_t& rhs) const noexcept { return value != rhs.value; }; +}; + +static_assert(sizeof(Float8E4M3FN_t) == sizeof(uint8_t), "Sizes must match"); + +/** \brief float8e4m3fnuz (Float8 Floating Point) data type + * \details It is necessary for type dispatching to make use of C++ API + * The type is implicitly convertible to/from uint8_t. + * See https://onnx.ai/onnx/technical/float8.html for further details. + */ +struct Float8E4M3FNUZ_t { + uint8_t value; + constexpr Float8E4M3FNUZ_t() noexcept : value(0) {} + constexpr Float8E4M3FNUZ_t(uint8_t v) noexcept : value(v) {} + constexpr operator uint8_t() const noexcept { return value; } + // nan values are treated like any other value for operator ==, != + constexpr bool operator==(const Float8E4M3FNUZ_t& rhs) const noexcept { return value == rhs.value; }; + constexpr bool operator!=(const Float8E4M3FNUZ_t& rhs) const noexcept { return value != rhs.value; }; +}; + +static_assert(sizeof(Float8E4M3FNUZ_t) == sizeof(uint8_t), "Sizes must match"); + +/** \brief float8e5m2 (Float8 Floating Point) data type + * \details It is necessary for type dispatching to make use of C++ API + * The type is implicitly convertible to/from uint8_t. + * See https://onnx.ai/onnx/technical/float8.html for further details. + */ +struct Float8E5M2_t { + uint8_t value; + constexpr Float8E5M2_t() noexcept : value(0) {} + constexpr Float8E5M2_t(uint8_t v) noexcept : value(v) {} + constexpr operator uint8_t() const noexcept { return value; } + // nan values are treated like any other value for operator ==, != + constexpr bool operator==(const Float8E5M2_t& rhs) const noexcept { return value == rhs.value; }; + constexpr bool operator!=(const Float8E5M2_t& rhs) const noexcept { return value != rhs.value; }; +}; + +static_assert(sizeof(Float8E5M2_t) == sizeof(uint8_t), "Sizes must match"); + +/** \brief float8e5m2fnuz (Float8 Floating Point) data type + * \details It is necessary for type dispatching to make use of C++ API + * The type is implicitly convertible to/from uint8_t. + * See https://onnx.ai/onnx/technical/float8.html for further details. + */ +struct Float8E5M2FNUZ_t { + uint8_t value; + constexpr Float8E5M2FNUZ_t() noexcept : value(0) {} + constexpr Float8E5M2FNUZ_t(uint8_t v) noexcept : value(v) {} + constexpr operator uint8_t() const noexcept { return value; } + // nan values are treated like any other value for operator ==, != + constexpr bool operator==(const Float8E5M2FNUZ_t& rhs) const noexcept { return value == rhs.value; }; + constexpr bool operator!=(const Float8E5M2FNUZ_t& rhs) const noexcept { return value != rhs.value; }; +}; + +static_assert(sizeof(Float8E5M2FNUZ_t) == sizeof(uint8_t), "Sizes must match"); + +namespace detail { +// This is used internally by the C++ API. This macro is to make it easy to generate overloaded methods for all of the various OrtRelease* functions for every Ort* type +// This can't be done in the C API since C doesn't have function overloading. +#define ORT_DEFINE_RELEASE(NAME) \ + inline void OrtRelease(Ort##NAME* ptr) { GetApi().Release##NAME(ptr); } + +ORT_DEFINE_RELEASE(Allocator); +ORT_DEFINE_RELEASE(MemoryInfo); +ORT_DEFINE_RELEASE(CustomOpDomain); +ORT_DEFINE_RELEASE(ThreadingOptions); +ORT_DEFINE_RELEASE(Env); +ORT_DEFINE_RELEASE(RunOptions); +ORT_DEFINE_RELEASE(Session); +ORT_DEFINE_RELEASE(SessionOptions); +ORT_DEFINE_RELEASE(TensorTypeAndShapeInfo); +ORT_DEFINE_RELEASE(SequenceTypeInfo); +ORT_DEFINE_RELEASE(MapTypeInfo); +ORT_DEFINE_RELEASE(TypeInfo); +ORT_DEFINE_RELEASE(Value); +ORT_DEFINE_RELEASE(ModelMetadata); +ORT_DEFINE_RELEASE(IoBinding); +ORT_DEFINE_RELEASE(ArenaCfg); +ORT_DEFINE_RELEASE(Status); +ORT_DEFINE_RELEASE(OpAttr); +ORT_DEFINE_RELEASE(Op); +ORT_DEFINE_RELEASE(KernelInfo); + +#undef ORT_DEFINE_RELEASE + +/** \brief This is a tagging template type. Use it with Base to indicate that the C++ interface object + * has no ownership of the underlying C object. + */ +template +struct Unowned { + using Type = T; +}; + +/** \brief Used internally by the C++ API. C++ wrapper types inherit from this. + * This is a zero cost abstraction to wrap the C API objects and delete them on destruction. + * + * All of the C++ classes + * a) serve as containers for pointers to objects that are created by the underlying C API. + * Their size is just a pointer size, no need to dynamically allocate them. Use them by value. + * b) Each of struct XXXX, XXX instances function as smart pointers to the underlying C API objects. + * they would release objects owned automatically when going out of scope, they are move-only. + * c) ConstXXXX and UnownedXXX structs function as non-owning, copyable containers for the above pointers. + * ConstXXXX allow calling const interfaces only. They give access to objects that are owned by somebody else + * such as Onnxruntime or instances of XXXX classes. + * d) serve convenient interfaces that return C++ objects and further enhance exception and type safety so they can be used + * in C++ code. + * + */ + +/// +/// This is a non-const pointer holder that is move-only. Disposes of the pointer on destruction. +/// +template +struct Base { + using contained_type = T; + + constexpr Base() = default; + constexpr explicit Base(contained_type* p) noexcept : p_{p} {} + ~Base() { OrtRelease(p_); } + + Base(const Base&) = delete; + Base& operator=(const Base&) = delete; + + Base(Base&& v) noexcept : p_{v.p_} { v.p_ = nullptr; } + Base& operator=(Base&& v) noexcept { + OrtRelease(p_); + p_ = v.release(); + return *this; + } + + constexpr operator contained_type*() const noexcept { return p_; } + + /// \brief Relinquishes ownership of the contained C object pointer + /// The underlying object is not destroyed + contained_type* release() { + T* p = p_; + p_ = nullptr; + return p; + } + + protected: + contained_type* p_{}; +}; + +// Undefined. For const types use Base> +template +struct Base; + +/// +/// Covers unowned pointers owned by either the ORT +/// or some other instance of CPP wrappers. +/// Used for ConstXXX and UnownedXXXX types that are copyable. +/// Also convenient to wrap raw OrtXX pointers . +/// +/// +template +struct Base> { + using contained_type = typename Unowned::Type; + + constexpr Base() = default; + constexpr explicit Base(contained_type* p) noexcept : p_{p} {} + + ~Base() = default; + + Base(const Base&) = default; + Base& operator=(const Base&) = default; + + Base(Base&& v) noexcept : p_{v.p_} { v.p_ = nullptr; } + Base& operator=(Base&& v) noexcept { + p_ = nullptr; + std::swap(p_, v.p_); + return *this; + } + + constexpr operator contained_type*() const noexcept { return p_; } + + protected: + contained_type* p_{}; +}; + +// Light functor to release memory with OrtAllocator +struct AllocatedFree { + OrtAllocator* allocator_; + explicit AllocatedFree(OrtAllocator* allocator) + : allocator_(allocator) {} + void operator()(void* ptr) const { + if (ptr) allocator_->Free(allocator_, ptr); + } +}; + +} // namespace detail + +struct AllocatorWithDefaultOptions; +struct Env; +struct TypeInfo; +struct Value; +struct ModelMetadata; + +/** \brief unique_ptr typedef used to own strings allocated by OrtAllocators + * and release them at the end of the scope. The lifespan of the given allocator + * must eclipse the lifespan of AllocatedStringPtr instance + */ +using AllocatedStringPtr = std::unique_ptr; + +/** \brief The Status that holds ownership of OrtStatus received from C API + * Use it to safely destroy OrtStatus* returned from the C API. Use appropriate + * constructors to construct an instance of a Status object from exceptions. + */ +struct Status : detail::Base { + explicit Status(std::nullptr_t) noexcept {} ///< Create an empty object, must be assigned a valid one to be used + explicit Status(OrtStatus* status) noexcept; ///< Takes ownership of OrtStatus instance returned from the C API. + explicit Status(const Exception&) noexcept; ///< Creates status instance out of exception + explicit Status(const std::exception&) noexcept; ///< Creates status instance out of exception + Status(const char* message, OrtErrorCode code) noexcept; ///< Creates status instance out of null-terminated string message. + std::string GetErrorMessage() const; + OrtErrorCode GetErrorCode() const; + bool IsOK() const noexcept; ///< Returns true if instance represents an OK (non-error) status. +}; + +/** \brief The ThreadingOptions + * + * The ThreadingOptions used for set global threadpools' options of The Env. + */ +struct ThreadingOptions : detail::Base { + /// \brief Wraps OrtApi::CreateThreadingOptions + ThreadingOptions(); + + /// \brief Wraps OrtApi::SetGlobalIntraOpNumThreads + ThreadingOptions& SetGlobalIntraOpNumThreads(int intra_op_num_threads); + + /// \brief Wraps OrtApi::SetGlobalInterOpNumThreads + ThreadingOptions& SetGlobalInterOpNumThreads(int inter_op_num_threads); + + /// \brief Wraps OrtApi::SetGlobalSpinControl + ThreadingOptions& SetGlobalSpinControl(int allow_spinning); + + /// \brief Wraps OrtApi::SetGlobalDenormalAsZero + ThreadingOptions& SetGlobalDenormalAsZero(); + + /// \brief Wraps OrtApi::SetGlobalCustomCreateThreadFn + ThreadingOptions& SetGlobalCustomCreateThreadFn(OrtCustomCreateThreadFn ort_custom_create_thread_fn); + + /// \brief Wraps OrtApi::SetGlobalCustomThreadCreationOptions + ThreadingOptions& SetGlobalCustomThreadCreationOptions(void* ort_custom_thread_creation_options); + + /// \brief Wraps OrtApi::SetGlobalCustomJoinThreadFn + ThreadingOptions& SetGlobalCustomJoinThreadFn(OrtCustomJoinThreadFn ort_custom_join_thread_fn); +}; + +/** \brief The Env (Environment) + * + * The Env holds the logging state used by all other objects. + * Note: One Env must be created before using any other Onnxruntime functionality + */ +struct Env : detail::Base { + explicit Env(std::nullptr_t) {} ///< Create an empty Env object, must be assigned a valid one to be used + + /// \brief Wraps OrtApi::CreateEnv + Env(OrtLoggingLevel logging_level = ORT_LOGGING_LEVEL_WARNING, _In_ const char* logid = ""); + + /// \brief Wraps OrtApi::CreateEnvWithCustomLogger + Env(OrtLoggingLevel logging_level, const char* logid, OrtLoggingFunction logging_function, void* logger_param); + + /// \brief Wraps OrtApi::CreateEnvWithGlobalThreadPools + Env(const OrtThreadingOptions* tp_options, OrtLoggingLevel logging_level = ORT_LOGGING_LEVEL_WARNING, _In_ const char* logid = ""); + + /// \brief Wraps OrtApi::CreateEnvWithCustomLoggerAndGlobalThreadPools + Env(const OrtThreadingOptions* tp_options, OrtLoggingFunction logging_function, void* logger_param, + OrtLoggingLevel logging_level = ORT_LOGGING_LEVEL_WARNING, _In_ const char* logid = ""); + + /// \brief C Interop Helper + explicit Env(OrtEnv* p) : Base{p} {} + + Env& EnableTelemetryEvents(); ///< Wraps OrtApi::EnableTelemetryEvents + Env& DisableTelemetryEvents(); ///< Wraps OrtApi::DisableTelemetryEvents + + Env& UpdateEnvWithCustomLogLevel(OrtLoggingLevel log_severity_level); ///< Wraps OrtApi::UpdateEnvWithCustomLogLevel + + Env& CreateAndRegisterAllocator(const OrtMemoryInfo* mem_info, const OrtArenaCfg* arena_cfg); ///< Wraps OrtApi::CreateAndRegisterAllocator + + Env& CreateAndRegisterAllocatorV2(const std::string& provider_type, const OrtMemoryInfo* mem_info, const std::unordered_map& options, const OrtArenaCfg* arena_cfg); ///< Wraps OrtApi::CreateAndRegisterAllocatorV2 +}; + +/** \brief Custom Op Domain + * + */ +struct CustomOpDomain : detail::Base { + explicit CustomOpDomain(std::nullptr_t) {} ///< Create an empty CustomOpDomain object, must be assigned a valid one to be used + + /// \brief Wraps OrtApi::CreateCustomOpDomain + explicit CustomOpDomain(const char* domain); + + // This does not take ownership of the op, simply registers it. + void Add(const OrtCustomOp* op); ///< Wraps CustomOpDomain_Add +}; + +/** \brief RunOptions + * + */ +struct RunOptions : detail::Base { + explicit RunOptions(std::nullptr_t) {} ///< Create an empty RunOptions object, must be assigned a valid one to be used + RunOptions(); ///< Wraps OrtApi::CreateRunOptions + + RunOptions& SetRunLogVerbosityLevel(int); ///< Wraps OrtApi::RunOptionsSetRunLogVerbosityLevel + int GetRunLogVerbosityLevel() const; ///< Wraps OrtApi::RunOptionsGetRunLogVerbosityLevel + + RunOptions& SetRunLogSeverityLevel(int); ///< Wraps OrtApi::RunOptionsSetRunLogSeverityLevel + int GetRunLogSeverityLevel() const; ///< Wraps OrtApi::RunOptionsGetRunLogSeverityLevel + + RunOptions& SetRunTag(const char* run_tag); ///< wraps OrtApi::RunOptionsSetRunTag + const char* GetRunTag() const; ///< Wraps OrtApi::RunOptionsGetRunTag + + RunOptions& AddConfigEntry(const char* config_key, const char* config_value); ///< Wraps OrtApi::AddRunConfigEntry + + /** \brief Terminates all currently executing Session::Run calls that were made using this RunOptions instance + * + * If a currently executing session needs to be force terminated, this can be called from another thread to force it to fail with an error + * Wraps OrtApi::RunOptionsSetTerminate + */ + RunOptions& SetTerminate(); + + /** \brief Clears the terminate flag so this RunOptions instance can be used in a new Session::Run call without it instantly terminating + * + * Wraps OrtApi::RunOptionsUnsetTerminate + */ + RunOptions& UnsetTerminate(); +}; + +namespace detail { +// Utility function that returns a SessionOption config entry key for a specific custom operator. +// Ex: custom_op.[custom_op_name].[config] +std::string MakeCustomOpConfigEntryKey(const char* custom_op_name, const char* config); +} // namespace detail + +/// +/// Class that represents session configuration entries for one or more custom operators. +/// +/// Example: +/// Ort::CustomOpConfigs op_configs; +/// op_configs.AddConfig("my_custom_op", "device_type", "CPU"); +/// +/// Passed to Ort::SessionOptions::RegisterCustomOpsLibrary. +/// +struct CustomOpConfigs { + CustomOpConfigs() = default; + ~CustomOpConfigs() = default; + CustomOpConfigs(const CustomOpConfigs&) = default; + CustomOpConfigs& operator=(const CustomOpConfigs&) = default; + CustomOpConfigs(CustomOpConfigs&& o) = default; + CustomOpConfigs& operator=(CustomOpConfigs&& o) = default; + + /** \brief Adds a session configuration entry/value for a specific custom operator. + * + * \param custom_op_name The name of the custom operator for which to add a configuration entry. + * Must match the name returned by the CustomOp's GetName() method. + * \param config_key The name of the configuration entry. + * \param config_value The value of the configuration entry. + * \return A reference to this object to enable call chaining. + */ + CustomOpConfigs& AddConfig(const char* custom_op_name, const char* config_key, const char* config_value); + + /** \brief Returns a flattened map of custom operator configuration entries and their values. + * + * The keys has been flattened to include both the custom operator name and the configuration entry key name. + * For example, a prior call to AddConfig("my_op", "key", "value") corresponds to the flattened key/value pair + * {"my_op.key", "value"}. + * + * \return An unordered map of flattened configurations. + */ + const std::unordered_map& GetFlattenedConfigs() const; + + private: + std::unordered_map flat_configs_; +}; + +/** \brief Options object used when creating a new Session object + * + * Wraps ::OrtSessionOptions object and methods + */ + +struct SessionOptions; + +namespace detail { +// we separate const-only methods because passing const ptr to non-const methods +// is only discovered when inline methods are compiled which is counter-intuitive +template +struct ConstSessionOptionsImpl : Base { + using B = Base; + using B::B; + + SessionOptions Clone() const; ///< Creates and returns a copy of this SessionOptions object. Wraps OrtApi::CloneSessionOptions + + std::string GetConfigEntry(const char* config_key) const; ///< Wraps OrtApi::GetSessionConfigEntry + bool HasConfigEntry(const char* config_key) const; ///< Wraps OrtApi::HasSessionConfigEntry + std::string GetConfigEntryOrDefault(const char* config_key, const std::string& def); +}; + +template +struct SessionOptionsImpl : ConstSessionOptionsImpl { + using B = ConstSessionOptionsImpl; + using B::B; + + SessionOptionsImpl& SetIntraOpNumThreads(int intra_op_num_threads); ///< Wraps OrtApi::SetIntraOpNumThreads + SessionOptionsImpl& SetInterOpNumThreads(int inter_op_num_threads); ///< Wraps OrtApi::SetInterOpNumThreads + SessionOptionsImpl& SetGraphOptimizationLevel(GraphOptimizationLevel graph_optimization_level); ///< Wraps OrtApi::SetSessionGraphOptimizationLevel + + SessionOptionsImpl& EnableCpuMemArena(); ///< Wraps OrtApi::EnableCpuMemArena + SessionOptionsImpl& DisableCpuMemArena(); ///< Wraps OrtApi::DisableCpuMemArena + + SessionOptionsImpl& SetOptimizedModelFilePath(const ORTCHAR_T* optimized_model_file); ///< Wraps OrtApi::SetOptimizedModelFilePath + + SessionOptionsImpl& EnableProfiling(const ORTCHAR_T* profile_file_prefix); ///< Wraps OrtApi::EnableProfiling + SessionOptionsImpl& DisableProfiling(); ///< Wraps OrtApi::DisableProfiling + + SessionOptionsImpl& EnableOrtCustomOps(); ///< Wraps OrtApi::EnableOrtCustomOps + + SessionOptionsImpl& EnableMemPattern(); ///< Wraps OrtApi::EnableMemPattern + SessionOptionsImpl& DisableMemPattern(); ///< Wraps OrtApi::DisableMemPattern + + SessionOptionsImpl& SetExecutionMode(ExecutionMode execution_mode); ///< Wraps OrtApi::SetSessionExecutionMode + + SessionOptionsImpl& SetLogId(const char* logid); ///< Wraps OrtApi::SetSessionLogId + SessionOptionsImpl& SetLogSeverityLevel(int level); ///< Wraps OrtApi::SetSessionLogSeverityLevel + + SessionOptionsImpl& Add(OrtCustomOpDomain* custom_op_domain); ///< Wraps OrtApi::AddCustomOpDomain + + SessionOptionsImpl& DisablePerSessionThreads(); ///< Wraps OrtApi::DisablePerSessionThreads + + SessionOptionsImpl& AddConfigEntry(const char* config_key, const char* config_value); ///< Wraps OrtApi::AddSessionConfigEntry + + SessionOptionsImpl& AddInitializer(const char* name, const OrtValue* ort_val); ///< Wraps OrtApi::AddInitializer + SessionOptionsImpl& AddExternalInitializers(const std::vector& names, const std::vector& ort_values); ///< Wraps OrtApi::AddExternalInitializers + + SessionOptionsImpl& AppendExecutionProvider_CUDA(const OrtCUDAProviderOptions& provider_options); ///< Wraps OrtApi::SessionOptionsAppendExecutionProvider_CUDA + SessionOptionsImpl& AppendExecutionProvider_CUDA_V2(const OrtCUDAProviderOptionsV2& provider_options); ///< Wraps OrtApi::SessionOptionsAppendExecutionProvider_CUDA_V2 + SessionOptionsImpl& AppendExecutionProvider_ROCM(const OrtROCMProviderOptions& provider_options); ///< Wraps OrtApi::SessionOptionsAppendExecutionProvider_ROCM + SessionOptionsImpl& AppendExecutionProvider_OpenVINO(const OrtOpenVINOProviderOptions& provider_options); ///< Wraps OrtApi::SessionOptionsAppendExecutionProvider_OpenVINO + SessionOptionsImpl& AppendExecutionProvider_TensorRT(const OrtTensorRTProviderOptions& provider_options); ///< Wraps OrtApi::SessionOptionsAppendExecutionProvider_TensorRT + SessionOptionsImpl& AppendExecutionProvider_TensorRT_V2(const OrtTensorRTProviderOptionsV2& provider_options); ///< Wraps OrtApi::SessionOptionsAppendExecutionProvider_TensorRT + SessionOptionsImpl& AppendExecutionProvider_MIGraphX(const OrtMIGraphXProviderOptions& provider_options); ///< Wraps OrtApi::SessionOptionsAppendExecutionProvider_MIGraphX + ///< Wraps OrtApi::SessionOptionsAppendExecutionProvider_CANN + SessionOptionsImpl& AppendExecutionProvider_CANN(const OrtCANNProviderOptions& provider_options); + ///< Wraps OrtApi::SessionOptionsAppendExecutionProvider_Dnnl + SessionOptionsImpl& AppendExecutionProvider_Dnnl(const OrtDnnlProviderOptions& provider_options); + /// Wraps OrtApi::SessionOptionsAppendExecutionProvider. Currently supports QNN, SNPE and XNNPACK. + SessionOptionsImpl& AppendExecutionProvider(const std::string& provider_name, + const std::unordered_map& provider_options = {}); + + SessionOptionsImpl& SetCustomCreateThreadFn(OrtCustomCreateThreadFn ort_custom_create_thread_fn); ///< Wraps OrtApi::SessionOptionsSetCustomCreateThreadFn + SessionOptionsImpl& SetCustomThreadCreationOptions(void* ort_custom_thread_creation_options); ///< Wraps OrtApi::SessionOptionsSetCustomThreadCreationOptions + SessionOptionsImpl& SetCustomJoinThreadFn(OrtCustomJoinThreadFn ort_custom_join_thread_fn); ///< Wraps OrtApi::SessionOptionsSetCustomJoinThreadFn + + ///< Registers the custom operator from the specified shared library via OrtApi::RegisterCustomOpsLibrary_V2. + ///< The custom operator configurations are optional. If provided, custom operator configs are set via + ///< OrtApi::AddSessionConfigEntry. + SessionOptionsImpl& RegisterCustomOpsLibrary(const ORTCHAR_T* library_name, const CustomOpConfigs& custom_op_configs = {}); + + SessionOptionsImpl& RegisterCustomOpsUsingFunction(const char* function_name); ///< Wraps OrtApi::RegisterCustomOpsUsingFunction +}; +} // namespace detail + +using UnownedSessionOptions = detail::SessionOptionsImpl>; +using ConstSessionOptions = detail::ConstSessionOptionsImpl>; + +/** \brief Wrapper around ::OrtSessionOptions + * + */ +struct SessionOptions : detail::SessionOptionsImpl { + explicit SessionOptions(std::nullptr_t) {} ///< Create an empty SessionOptions object, must be assigned a valid one to be used + SessionOptions(); ///< Wraps OrtApi::CreateSessionOptions + explicit SessionOptions(OrtSessionOptions* p) : SessionOptionsImpl{p} {} ///< Used for interop with the C API + UnownedSessionOptions GetUnowned() const { return UnownedSessionOptions{this->p_}; } + ConstSessionOptions GetConst() const { return ConstSessionOptions{this->p_}; } +}; + +/** \brief Wrapper around ::OrtModelMetadata + * + */ +struct ModelMetadata : detail::Base { + explicit ModelMetadata(std::nullptr_t) {} ///< Create an empty ModelMetadata object, must be assigned a valid one to be used + explicit ModelMetadata(OrtModelMetadata* p) : Base{p} {} ///< Used for interop with the C API + + /** \brief Returns a copy of the producer name. + * + * \param allocator to allocate memory for the copy of the name returned + * \return a instance of smart pointer that would deallocate the buffer when out of scope. + * The OrtAllocator instances must be valid at the point of memory release. + */ + AllocatedStringPtr GetProducerNameAllocated(OrtAllocator* allocator) const; ///< Wraps OrtApi::ModelMetadataGetProducerName + + /** \brief Returns a copy of the graph name. + * + * \param allocator to allocate memory for the copy of the name returned + * \return a instance of smart pointer that would deallocate the buffer when out of scope. + * The OrtAllocator instances must be valid at the point of memory release. + */ + AllocatedStringPtr GetGraphNameAllocated(OrtAllocator* allocator) const; ///< Wraps OrtApi::ModelMetadataGetGraphName + + /** \brief Returns a copy of the domain name. + * + * \param allocator to allocate memory for the copy of the name returned + * \return a instance of smart pointer that would deallocate the buffer when out of scope. + * The OrtAllocator instances must be valid at the point of memory release. + */ + AllocatedStringPtr GetDomainAllocated(OrtAllocator* allocator) const; ///< Wraps OrtApi::ModelMetadataGetDomain + + /** \brief Returns a copy of the description. + * + * \param allocator to allocate memory for the copy of the string returned + * \return a instance of smart pointer that would deallocate the buffer when out of scope. + * The OrtAllocator instances must be valid at the point of memory release. + */ + AllocatedStringPtr GetDescriptionAllocated(OrtAllocator* allocator) const; ///< Wraps OrtApi::ModelMetadataGetDescription + + /** \brief Returns a copy of the graph description. + * + * \param allocator to allocate memory for the copy of the string returned + * \return a instance of smart pointer that would deallocate the buffer when out of scope. + * The OrtAllocator instances must be valid at the point of memory release. + */ + AllocatedStringPtr GetGraphDescriptionAllocated(OrtAllocator* allocator) const; ///< Wraps OrtApi::ModelMetadataGetGraphDescription + + /** \brief Returns a vector of copies of the custom metadata keys. + * + * \param allocator to allocate memory for the copy of the string returned + * \return a instance std::vector of smart pointers that would deallocate the buffers when out of scope. + * The OrtAllocator instance must be valid at the point of memory release. + */ + std::vector GetCustomMetadataMapKeysAllocated(OrtAllocator* allocator) const; ///< Wraps OrtApi::ModelMetadataGetCustomMetadataMapKeys + + /** \brief Looks up a value by a key in the Custom Metadata map + * + * \param key zero terminated string key to lookup + * \param allocator to allocate memory for the copy of the string returned + * \return a instance of smart pointer that would deallocate the buffer when out of scope. + * maybe nullptr if key is not found. + * + * The OrtAllocator instances must be valid at the point of memory release. + */ + AllocatedStringPtr LookupCustomMetadataMapAllocated(const char* key, OrtAllocator* allocator) const; ///< Wraps OrtApi::ModelMetadataLookupCustomMetadataMap + + int64_t GetVersion() const; ///< Wraps OrtApi::ModelMetadataGetVersion +}; + +struct IoBinding; + +namespace detail { + +// we separate const-only methods because passing const ptr to non-const methods +// is only discovered when inline methods are compiled which is counter-intuitive +template +struct ConstSessionImpl : Base { + using B = Base; + using B::B; + + size_t GetInputCount() const; ///< Returns the number of model inputs + size_t GetOutputCount() const; ///< Returns the number of model outputs + size_t GetOverridableInitializerCount() const; ///< Returns the number of inputs that have defaults that can be overridden + + /** \brief Returns a copy of input name at the specified index. + * + * \param index must less than the value returned by GetInputCount() + * \param allocator to allocate memory for the copy of the name returned + * \return a instance of smart pointer that would deallocate the buffer when out of scope. + * The OrtAllocator instances must be valid at the point of memory release. + */ + AllocatedStringPtr GetInputNameAllocated(size_t index, OrtAllocator* allocator) const; + + /** \brief Returns a copy of output name at then specified index. + * + * \param index must less than the value returned by GetOutputCount() + * \param allocator to allocate memory for the copy of the name returned + * \return a instance of smart pointer that would deallocate the buffer when out of scope. + * The OrtAllocator instances must be valid at the point of memory release. + */ + AllocatedStringPtr GetOutputNameAllocated(size_t index, OrtAllocator* allocator) const; + + /** \brief Returns a copy of the overridable initializer name at then specified index. + * + * \param index must less than the value returned by GetOverridableInitializerCount() + * \param allocator to allocate memory for the copy of the name returned + * \return a instance of smart pointer that would deallocate the buffer when out of scope. + * The OrtAllocator instances must be valid at the point of memory release. + */ + AllocatedStringPtr GetOverridableInitializerNameAllocated(size_t index, OrtAllocator* allocator) const; ///< Wraps OrtApi::SessionGetOverridableInitializerName + + uint64_t GetProfilingStartTimeNs() const; ///< Wraps OrtApi::SessionGetProfilingStartTimeNs + ModelMetadata GetModelMetadata() const; ///< Wraps OrtApi::SessionGetModelMetadata + + TypeInfo GetInputTypeInfo(size_t index) const; ///< Wraps OrtApi::SessionGetInputTypeInfo + TypeInfo GetOutputTypeInfo(size_t index) const; ///< Wraps OrtApi::SessionGetOutputTypeInfo + TypeInfo GetOverridableInitializerTypeInfo(size_t index) const; ///< Wraps OrtApi::SessionGetOverridableInitializerTypeInfo +}; + +template +struct SessionImpl : ConstSessionImpl { + using B = ConstSessionImpl; + using B::B; + + /** \brief Run the model returning results in an Ort allocated vector. + * + * Wraps OrtApi::Run + * + * The caller provides a list of inputs and a list of the desired outputs to return. + * + * See the output logs for more information on warnings/errors that occur while processing the model. + * Common errors are.. (TODO) + * + * \param[in] run_options + * \param[in] input_names Array of null terminated strings of length input_count that is the list of input names + * \param[in] input_values Array of Value objects of length input_count that is the list of input values + * \param[in] input_count Number of inputs (the size of the input_names & input_values arrays) + * \param[in] output_names Array of C style strings of length output_count that is the list of output names + * \param[in] output_count Number of outputs (the size of the output_names array) + * \return A std::vector of Value objects that directly maps to the output_names array (eg. output_name[0] is the first entry of the returned vector) + */ + std::vector Run(const RunOptions& run_options, const char* const* input_names, const Value* input_values, size_t input_count, + const char* const* output_names, size_t output_count); + + /** \brief Run the model returning results in user provided outputs + * Same as Run(const RunOptions&, const char* const*, const Value*, size_t,const char* const*, size_t) + */ + void Run(const RunOptions& run_options, const char* const* input_names, const Value* input_values, size_t input_count, + const char* const* output_names, Value* output_values, size_t output_count); + + void Run(const RunOptions& run_options, const IoBinding&); ///< Wraps OrtApi::RunWithBinding + + /** \brief Run the model asynchronously in a thread owned by intra op thread pool + * + * Wraps OrtApi::RunAsync + * + * \param[in] run_options + * \param[in] input_names Array of null terminated UTF8 encoded strings of the input names + * \param[in] input_values Array of Value objects of length input_count + * \param[in] input_count Number of elements in the input_names and inputs arrays + * \param[in] output_names Array of null terminated UTF8 encoded strings of the output names + * \param[out] output_values Array of provided Values to be filled with outputs. + * On calling RunAsync, output_values[i] could either be initialized by a null pointer or a preallocated OrtValue*. + * Later, on invoking the callback, each output_values[i] of null will be filled with an OrtValue* allocated by onnxruntime. + * Then, an OrtValue** pointer will be casted from output_values, and pass to the callback. + * NOTE: it is customer's duty to finally release output_values and each of its member, + * regardless of whether the member (Ort::Value) is allocated by onnxruntime or preallocated by the customer. + * \param[in] output_count Number of elements in the output_names and outputs array + * \param[in] callback Callback function on model run completion + * \param[in] user_data User data that pass back to the callback + */ + void RunAsync(const RunOptions& run_options, const char* const* input_names, const Value* input_values, size_t input_count, + const char* const* output_names, Value* output_values, size_t output_count, RunAsyncCallbackFn callback, void* user_data); + + /** \brief End profiling and return a copy of the profiling file name. + * + * \param allocator to allocate memory for the copy of the string returned + * \return a instance of smart pointer that would deallocate the buffer when out of scope. + * The OrtAllocator instances must be valid at the point of memory release. + */ + AllocatedStringPtr EndProfilingAllocated(OrtAllocator* allocator); ///< Wraps OrtApi::SessionEndProfiling +}; + +} // namespace detail + +using ConstSession = detail::ConstSessionImpl>; +using UnownedSession = detail::SessionImpl>; + +/** \brief Wrapper around ::OrtSession + * + */ +struct Session : detail::SessionImpl { + explicit Session(std::nullptr_t) {} ///< Create an empty Session object, must be assigned a valid one to be used + Session(const Env& env, const ORTCHAR_T* model_path, const SessionOptions& options); ///< Wraps OrtApi::CreateSession + Session(const Env& env, const ORTCHAR_T* model_path, const SessionOptions& options, + OrtPrepackedWeightsContainer* prepacked_weights_container); ///< Wraps OrtApi::CreateSessionWithPrepackedWeightsContainer + Session(const Env& env, const void* model_data, size_t model_data_length, const SessionOptions& options); ///< Wraps OrtApi::CreateSessionFromArray + Session(const Env& env, const void* model_data, size_t model_data_length, const SessionOptions& options, + OrtPrepackedWeightsContainer* prepacked_weights_container); ///< Wraps OrtApi::CreateSessionFromArrayWithPrepackedWeightsContainer + + ConstSession GetConst() const { return ConstSession{this->p_}; } + UnownedSession GetUnowned() const { return UnownedSession{this->p_}; } +}; + +namespace detail { +template +struct MemoryInfoImpl : Base { + using B = Base; + using B::B; + + std::string GetAllocatorName() const; + OrtAllocatorType GetAllocatorType() const; + int GetDeviceId() const; + OrtMemoryInfoDeviceType GetDeviceType() const; + OrtMemType GetMemoryType() const; + + template + bool operator==(const MemoryInfoImpl& o) const; +}; +} // namespace detail + +// Const object holder that does not own the underlying object +using ConstMemoryInfo = detail::MemoryInfoImpl>; + +/** \brief Wrapper around ::OrtMemoryInfo + * + */ +struct MemoryInfo : detail::MemoryInfoImpl { + static MemoryInfo CreateCpu(OrtAllocatorType type, OrtMemType mem_type1); + explicit MemoryInfo(std::nullptr_t) {} ///< No instance is created + explicit MemoryInfo(OrtMemoryInfo* p) : MemoryInfoImpl{p} {} ///< Take ownership of a pointer created by C Api + MemoryInfo(const char* name, OrtAllocatorType type, int id, OrtMemType mem_type); + ConstMemoryInfo GetConst() const { return ConstMemoryInfo{this->p_}; } +}; + +namespace detail { +template +struct TensorTypeAndShapeInfoImpl : Base { + using B = Base; + using B::B; + + ONNXTensorElementDataType GetElementType() const; ///< Wraps OrtApi::GetTensorElementType + size_t GetElementCount() const; ///< Wraps OrtApi::GetTensorShapeElementCount + + size_t GetDimensionsCount() const; ///< Wraps OrtApi::GetDimensionsCount + + /** \deprecated use GetShape() returning std::vector + * [[deprecated]] + * This interface is unsafe to use + */ + [[deprecated("use GetShape()")]] void GetDimensions(int64_t* values, size_t values_count) const; ///< Wraps OrtApi::GetDimensions + + void GetSymbolicDimensions(const char** values, size_t values_count) const; ///< Wraps OrtApi::GetSymbolicDimensions + + std::vector GetShape() const; ///< Uses GetDimensionsCount & GetDimensions to return a std::vector of the shape +}; + +} // namespace detail + +using ConstTensorTypeAndShapeInfo = detail::TensorTypeAndShapeInfoImpl>; + +/** \brief Wrapper around ::OrtTensorTypeAndShapeInfo + * + */ +struct TensorTypeAndShapeInfo : detail::TensorTypeAndShapeInfoImpl { + explicit TensorTypeAndShapeInfo(std::nullptr_t) {} ///< Create an empty TensorTypeAndShapeInfo object, must be assigned a valid one to be used + explicit TensorTypeAndShapeInfo(OrtTensorTypeAndShapeInfo* p) : TensorTypeAndShapeInfoImpl{p} {} ///< Used for interop with the C API + ConstTensorTypeAndShapeInfo GetConst() const { return ConstTensorTypeAndShapeInfo{this->p_}; } +}; + +namespace detail { +template +struct SequenceTypeInfoImpl : Base { + using B = Base; + using B::B; + TypeInfo GetSequenceElementType() const; ///< Wraps OrtApi::GetSequenceElementType +}; + +} // namespace detail + +using ConstSequenceTypeInfo = detail::SequenceTypeInfoImpl>; + +/** \brief Wrapper around ::OrtSequenceTypeInfo + * + */ +struct SequenceTypeInfo : detail::SequenceTypeInfoImpl { + explicit SequenceTypeInfo(std::nullptr_t) {} ///< Create an empty SequenceTypeInfo object, must be assigned a valid one to be used + explicit SequenceTypeInfo(OrtSequenceTypeInfo* p) : SequenceTypeInfoImpl{p} {} ///< Used for interop with the C API + ConstSequenceTypeInfo GetConst() const { return ConstSequenceTypeInfo{this->p_}; } +}; + +namespace detail { +template +struct OptionalTypeInfoImpl : Base { + using B = Base; + using B::B; + TypeInfo GetOptionalElementType() const; ///< Wraps OrtApi::CastOptionalTypeToContainedTypeInfo +}; + +} // namespace detail + +// This is always owned by the TypeInfo and can only be obtained from it. +using ConstOptionalTypeInfo = detail::OptionalTypeInfoImpl>; + +namespace detail { +template +struct MapTypeInfoImpl : detail::Base { + using B = Base; + using B::B; + ONNXTensorElementDataType GetMapKeyType() const; ///< Wraps OrtApi::GetMapKeyType + TypeInfo GetMapValueType() const; ///< Wraps OrtApi::GetMapValueType +}; + +} // namespace detail + +using ConstMapTypeInfo = detail::MapTypeInfoImpl>; + +/** \brief Wrapper around ::OrtMapTypeInfo + * + */ +struct MapTypeInfo : detail::MapTypeInfoImpl { + explicit MapTypeInfo(std::nullptr_t) {} ///< Create an empty MapTypeInfo object, must be assigned a valid one to be used + explicit MapTypeInfo(OrtMapTypeInfo* p) : MapTypeInfoImpl{p} {} ///< Used for interop with the C API + ConstMapTypeInfo GetConst() const { return ConstMapTypeInfo{this->p_}; } +}; + +namespace detail { +template +struct TypeInfoImpl : detail::Base { + using B = Base; + using B::B; + + ConstTensorTypeAndShapeInfo GetTensorTypeAndShapeInfo() const; ///< Wraps OrtApi::CastTypeInfoToTensorInfo + ConstSequenceTypeInfo GetSequenceTypeInfo() const; ///< Wraps OrtApi::CastTypeInfoToSequenceTypeInfo + ConstMapTypeInfo GetMapTypeInfo() const; ///< Wraps OrtApi::CastTypeInfoToMapTypeInfo + ConstOptionalTypeInfo GetOptionalTypeInfo() const; ///< wraps OrtApi::CastTypeInfoToOptionalTypeInfo + + ONNXType GetONNXType() const; +}; +} // namespace detail + +/// +/// Contains a constant, unowned OrtTypeInfo that can be copied and passed around by value. +/// Provides access to const OrtTypeInfo APIs. +/// +using ConstTypeInfo = detail::TypeInfoImpl>; + +/// +/// Type information that may contain either TensorTypeAndShapeInfo or +/// the information about contained sequence or map depending on the ONNXType. +/// +struct TypeInfo : detail::TypeInfoImpl { + explicit TypeInfo(std::nullptr_t) {} ///< Create an empty TypeInfo object, must be assigned a valid one to be used + explicit TypeInfo(OrtTypeInfo* p) : TypeInfoImpl{p} {} ///< C API Interop + + ConstTypeInfo GetConst() const { return ConstTypeInfo{this->p_}; } +}; + +namespace detail { +// This structure is used to feed sparse tensor values +// information for use with FillSparseTensor() API +// if the data type for the sparse tensor values is numeric +// use data.p_data, otherwise, use data.str pointer to feed +// values. data.str is an array of const char* that are zero terminated. +// number of strings in the array must match shape size. +// For fully sparse tensors use shape {0} and set p_data/str +// to nullptr. +struct OrtSparseValuesParam { + const int64_t* values_shape; + size_t values_shape_len; + union { + const void* p_data; + const char** str; + } data; +}; + +// Provides a way to pass shape in a single +// argument +struct Shape { + const int64_t* shape; + size_t shape_len; +}; + +template +struct ConstValueImpl : Base { + using B = Base; + using B::B; + + /// + /// Obtains a pointer to a user defined data for experimental purposes + /// + template + void GetOpaqueData(const char* domain, const char* type_name, R&) const; ///< Wraps OrtApi::GetOpaqueValue + + bool IsTensor() const; ///< Returns true if Value is a tensor, false for other types like map/sequence/etc + bool HasValue() const; /// < Return true if OrtValue contains data and returns false if the OrtValue is a None + + size_t GetCount() const; // If a non tensor, returns 2 for map and N for sequence, where N is the number of elements + Value GetValue(int index, OrtAllocator* allocator) const; + + /// + /// This API returns a full length of string data contained within either a tensor or a sparse Tensor. + /// For sparse tensor it returns a full length of stored non-empty strings (values). The API is useful + /// for allocating necessary memory and calling GetStringTensorContent(). + /// + /// total length of UTF-8 encoded bytes contained. No zero terminators counted. + size_t GetStringTensorDataLength() const; + + /// + /// The API copies all of the UTF-8 encoded string data contained within a tensor or a sparse tensor + /// into a supplied buffer. Use GetStringTensorDataLength() to find out the length of the buffer to allocate. + /// The user must also allocate offsets buffer with the number of entries equal to that of the contained + /// strings. + /// + /// Strings are always assumed to be on CPU, no X-device copy. + /// + /// user allocated buffer + /// length in bytes of the allocated buffer + /// a pointer to the offsets user allocated buffer + /// count of offsets, must be equal to the number of strings contained. + /// that can be obtained from the shape of the tensor or from GetSparseTensorValuesTypeAndShapeInfo() + /// for sparse tensors + void GetStringTensorContent(void* buffer, size_t buffer_length, size_t* offsets, size_t offsets_count) const; + + /// + /// Returns a const typed pointer to the tensor contained data. + /// No type checking is performed, the caller must ensure the type matches the tensor type. + /// + /// + /// const pointer to data, no copies made + template + const R* GetTensorData() const; ///< Wraps OrtApi::GetTensorMutableData /// + + /// + /// Returns a non-typed pointer to a tensor contained data. + /// + /// const pointer to data, no copies made + const void* GetTensorRawData() const; + + /// + /// The API returns type information for data contained in a tensor. For sparse + /// tensors it returns type information for contained non-zero values. + /// It returns dense shape for sparse tensors. + /// + /// TypeInfo + TypeInfo GetTypeInfo() const; + + /// + /// The API returns type information for data contained in a tensor. For sparse + /// tensors it returns type information for contained non-zero values. + /// It returns dense shape for sparse tensors. + /// + /// TensorTypeAndShapeInfo + TensorTypeAndShapeInfo GetTensorTypeAndShapeInfo() const; + + /// + /// This API returns information about the memory allocation used to hold data. + /// + /// Non owning instance of MemoryInfo + ConstMemoryInfo GetTensorMemoryInfo() const; + + /// + /// The API copies UTF-8 encoded bytes for the requested string element + /// contained within a tensor or a sparse tensor into a provided buffer. + /// Use GetStringTensorElementLength() to obtain the length of the buffer to allocate. + /// + /// + /// + /// + void GetStringTensorElement(size_t buffer_length, size_t element_index, void* buffer) const; + + /// + /// Returns string tensor UTF-8 encoded string element. + /// Use of this API is recommended over GetStringTensorElement() that takes void* buffer pointer. + /// + /// + /// std::string + std::string GetStringTensorElement(size_t element_index) const; + + /// + /// The API returns a byte length of UTF-8 encoded string element + /// contained in either a tensor or a spare tensor values. + /// + /// + /// byte length for the specified string element + size_t GetStringTensorElementLength(size_t element_index) const; + +#if !defined(DISABLE_SPARSE_TENSORS) + /// + /// The API returns the sparse data format this OrtValue holds in a sparse tensor. + /// If the sparse tensor was not fully constructed, i.e. Use*() or Fill*() API were not used + /// the value returned is ORT_SPARSE_UNDEFINED. + /// + /// Format enum + OrtSparseFormat GetSparseFormat() const; + + /// + /// The API returns type and shape information for stored non-zero values of the + /// sparse tensor. Use GetSparseTensorValues() to obtain values buffer pointer. + /// + /// TensorTypeAndShapeInfo values information + TensorTypeAndShapeInfo GetSparseTensorValuesTypeAndShapeInfo() const; + + /// + /// The API returns type and shape information for the specified indices. Each supported + /// indices have their own enum values even if a give format has more than one kind of indices. + /// Use GetSparseTensorIndicesData() to obtain pointer to indices buffer. + /// + /// enum requested + /// type and shape information + TensorTypeAndShapeInfo GetSparseTensorIndicesTypeShapeInfo(OrtSparseIndicesFormat format) const; + + /// + /// The API retrieves a pointer to the internal indices buffer. The API merely performs + /// a convenience data type casting on the return type pointer. Make sure you are requesting + /// the right type, use GetSparseTensorIndicesTypeShapeInfo(); + /// + /// type to cast to + /// requested indices kind + /// number of indices entries + /// Pinter to the internal sparse tensor buffer containing indices. Do not free this pointer. + template + const R* GetSparseTensorIndicesData(OrtSparseIndicesFormat indices_format, size_t& num_indices) const; + + /// + /// Returns true if the OrtValue contains a sparse tensor + /// + /// + bool IsSparseTensor() const; + + /// + /// The API returns a pointer to an internal buffer of the sparse tensor + /// containing non-zero values. The API merely does casting. Make sure you + /// are requesting the right data type by calling GetSparseTensorValuesTypeAndShapeInfo() + /// first. + /// + /// numeric data types only. Use GetStringTensor*() to retrieve strings. + /// a pointer to the internal values buffer. Do not free this pointer. + template + const R* GetSparseTensorValues() const; + +#endif +}; + +template +struct ValueImpl : ConstValueImpl { + using B = ConstValueImpl; + using B::B; + + /// + /// Returns a non-const typed pointer to an OrtValue/Tensor contained buffer + /// No type checking is performed, the caller must ensure the type matches the tensor type. + /// + /// non-const pointer to data, no copies made + template + R* GetTensorMutableData(); + + /// + /// Returns a non-typed non-const pointer to a tensor contained data. + /// + /// pointer to data, no copies made + void* GetTensorMutableRawData(); + + /// + // Obtain a reference to an element of data at the location specified + /// by the vector of dims. + /// + /// + /// [in] expressed by a vecotr of dimensions offsets + /// + template + R& At(const std::vector& location); + + /// + /// Set all strings at once in a string tensor + /// + /// [in] An array of strings. Each string in this array must be null terminated. + /// [in] Count of strings in s (Must match the size of \p value's tensor shape) + void FillStringTensor(const char* const* s, size_t s_len); + + /// + /// Set a single string in a string tensor + /// + /// [in] A null terminated UTF-8 encoded string + /// [in] Index of the string in the tensor to set + void FillStringTensorElement(const char* s, size_t index); + + /// + /// Allocate if necessary and obtain a pointer to a UTF-8 + /// encoded string element buffer indexed by the flat element index, + /// of the specified length. + /// + /// This API is for advanced usage. It avoids a need to construct + /// an auxiliary array of string pointers, and allows to write data directly + /// (do not zero terminate). + /// + /// + /// + /// a pointer to a writable buffer + char* GetResizedStringTensorElementBuffer(size_t index, size_t buffer_length); + +#if !defined(DISABLE_SPARSE_TENSORS) + /// + /// Supplies COO format specific indices and marks the contained sparse tensor as being a COO format tensor. + /// Values are supplied with a CreateSparseTensor() API. The supplied indices are not copied and the user + /// allocated buffers lifespan must eclipse that of the OrtValue. + /// The location of the indices is assumed to be the same as specified by OrtMemoryInfo argument at the creation time. + /// + /// pointer to the user allocated buffer with indices. Use nullptr for fully sparse tensors. + /// number of indices entries. Use 0 for fully sparse tensors + void UseCooIndices(int64_t* indices_data, size_t indices_num); + + /// + /// Supplies CSR format specific indices and marks the contained sparse tensor as being a CSR format tensor. + /// Values are supplied with a CreateSparseTensor() API. The supplied indices are not copied and the user + /// allocated buffers lifespan must eclipse that of the OrtValue. + /// The location of the indices is assumed to be the same as specified by OrtMemoryInfo argument at the creation time. + /// + /// pointer to the user allocated buffer with inner indices or nullptr for fully sparse tensors + /// number of csr inner indices or 0 for fully sparse tensors + /// pointer to the user allocated buffer with outer indices or nullptr for fully sparse tensors + /// number of csr outer indices or 0 for fully sparse tensors + void UseCsrIndices(int64_t* inner_data, size_t inner_num, int64_t* outer_data, size_t outer_num); + + /// + /// Supplies BlockSparse format specific indices and marks the contained sparse tensor as being a BlockSparse format tensor. + /// Values are supplied with a CreateSparseTensor() API. The supplied indices are not copied and the user + /// allocated buffers lifespan must eclipse that of the OrtValue. + /// The location of the indices is assumed to be the same as specified by OrtMemoryInfo argument at the creation time. + /// + /// indices shape or a {0} for fully sparse + /// user allocated buffer with indices or nullptr for fully spare tensors + void UseBlockSparseIndices(const Shape& indices_shape, int32_t* indices_data); + + /// + /// The API will allocate memory using the allocator instance supplied to the CreateSparseTensor() API + /// and copy the values and COO indices into it. If data_mem_info specifies that the data is located + /// at difference device than the allocator, a X-device copy will be performed if possible. + /// + /// specified buffer memory description + /// values buffer information. + /// coo indices buffer or nullptr for fully sparse data + /// number of COO indices or 0 for fully sparse data + void FillSparseTensorCoo(const OrtMemoryInfo* data_mem_info, const OrtSparseValuesParam& values_param, + const int64_t* indices_data, size_t indices_num); + + /// + /// The API will allocate memory using the allocator instance supplied to the CreateSparseTensor() API + /// and copy the values and CSR indices into it. If data_mem_info specifies that the data is located + /// at difference device than the allocator, a X-device copy will be performed if possible. + /// + /// specified buffer memory description + /// values buffer information + /// csr inner indices pointer or nullptr for fully sparse tensors + /// number of csr inner indices or 0 for fully sparse tensors + /// pointer to csr indices data or nullptr for fully sparse tensors + /// number of csr outer indices or 0 + void FillSparseTensorCsr(const OrtMemoryInfo* data_mem_info, + const OrtSparseValuesParam& values, + const int64_t* inner_indices_data, size_t inner_indices_num, + const int64_t* outer_indices_data, size_t outer_indices_num); + + /// + /// The API will allocate memory using the allocator instance supplied to the CreateSparseTensor() API + /// and copy the values and BlockSparse indices into it. If data_mem_info specifies that the data is located + /// at difference device than the allocator, a X-device copy will be performed if possible. + /// + /// specified buffer memory description + /// values buffer information + /// indices shape. use {0} for fully sparse tensors + /// pointer to indices data or nullptr for fully sparse tensors + void FillSparseTensorBlockSparse(const OrtMemoryInfo* data_mem_info, + const OrtSparseValuesParam& values, + const Shape& indices_shape, + const int32_t* indices_data); + +#endif +}; + +} // namespace detail + +using ConstValue = detail::ConstValueImpl>; +using UnownedValue = detail::ValueImpl>; + +/** \brief Wrapper around ::OrtValue + * + */ +struct Value : detail::ValueImpl { + using Base = detail::ValueImpl; + using OrtSparseValuesParam = detail::OrtSparseValuesParam; + using Shape = detail::Shape; + + explicit Value(std::nullptr_t) {} ///< Create an empty Value object, must be assigned a valid one to be used + explicit Value(OrtValue* p) : Base{p} {} ///< Used for interop with the C API + Value(Value&&) = default; + Value& operator=(Value&&) = default; + + ConstValue GetConst() const { return ConstValue{this->p_}; } + UnownedValue GetUnowned() const { return UnownedValue{this->p_}; } + + /** \brief Creates a tensor with a user supplied buffer. Wraps OrtApi::CreateTensorWithDataAsOrtValue. + * \tparam T The numeric datatype. This API is not suitable for strings. + * \param info Memory description of where the p_data buffer resides (CPU vs GPU etc). + * \param p_data Pointer to the data buffer. + * \param p_data_element_count The number of elements in the data buffer. + * \param shape Pointer to the tensor shape dimensions. + * \param shape_len The number of tensor shape dimensions. + */ + template + static Value CreateTensor(const OrtMemoryInfo* info, T* p_data, size_t p_data_element_count, const int64_t* shape, size_t shape_len); + + /** \brief Creates a tensor with a user supplied buffer. Wraps OrtApi::CreateTensorWithDataAsOrtValue. + * + * \param info Memory description of where the p_data buffer resides (CPU vs GPU etc). + * \param p_data Pointer to the data buffer. + * \param p_data_byte_count The number of bytes in the data buffer. + * \param shape Pointer to the tensor shape dimensions. + * \param shape_len The number of tensor shape dimensions. + * \param type The data type. + */ + static Value CreateTensor(const OrtMemoryInfo* info, void* p_data, size_t p_data_byte_count, const int64_t* shape, size_t shape_len, + ONNXTensorElementDataType type); + + /** \brief Creates an OrtValue with a tensor using a supplied OrtAllocator. Wraps OrtApi::CreateTensorAsOrtValue. + * This overload will allocate the buffer for the tensor according to the supplied shape and data type. + * The allocated buffer will be owned by the returned OrtValue and will be freed when the OrtValue is released. + * The input data would need to be copied into the allocated buffer. + * This API is not suitable for strings. + * + * \tparam T The numeric datatype. This API is not suitable for strings. + * \param allocator The allocator to use. + * \param shape Pointer to the tensor shape dimensions. + * \param shape_len The number of tensor shape dimensions. + */ + template + static Value CreateTensor(OrtAllocator* allocator, const int64_t* shape, size_t shape_len); + + /** \brief Creates an OrtValue with a tensor using the supplied OrtAllocator. + * Wraps OrtApi::CreateTensorAsOrtValue. + * The allocated buffer will be owned by the returned OrtValue and will be freed when the OrtValue is released. + * The input data would need to be copied into the allocated buffer. + * This API is not suitable for strings. + * + * \param allocator The allocator to use. + * \param shape Pointer to the tensor shape dimensions. + * \param shape_len The number of tensor shape dimensions. + * \param type The data type. + */ + static Value CreateTensor(OrtAllocator* allocator, const int64_t* shape, size_t shape_len, ONNXTensorElementDataType type); + + /** \brief Creates an OrtValue with a Map Onnx type representation. + * The API would ref-count the supplied OrtValues and they will be released + * when the returned OrtValue is released. The caller may release keys and values after the call + * returns. + * + * \param keys an OrtValue containing a tensor with primitive data type keys. + * \param values an OrtValue that may contain a tensor. Ort currently supports only primitive data type values. + */ + static Value CreateMap(const Value& keys, const Value& values); ///< Wraps OrtApi::CreateValue + + /** \brief Creates an OrtValue with a Sequence Onnx type representation. + * The API would ref-count the supplied OrtValues and they will be released + * when the returned OrtValue is released. The caller may release the values after the call + * returns. + * + * \param values a vector of OrtValues that must have the same Onnx value type. + */ + static Value CreateSequence(const std::vector& values); ///< Wraps OrtApi::CreateValue + + /** \brief Creates an OrtValue wrapping an Opaque type. + * This is used for experimental support of non-tensor types. + * + * \tparam T - the type of the value. + * \param domain - zero terminated utf-8 string. Domain of the type. + * \param type_name - zero terminated utf-8 string. Name of the type. + * \param value - the value to be wrapped. + */ + template + static Value CreateOpaque(const char* domain, const char* type_name, const T& value); ///< Wraps OrtApi::CreateOpaqueValue + +#if !defined(DISABLE_SPARSE_TENSORS) + /// + /// This is a simple forwarding method to the other overload that helps deducing + /// data type enum value from the type of the buffer. + /// + /// numeric datatype. This API is not suitable for strings. + /// Memory description where the user buffers reside (CPU vs GPU etc) + /// pointer to the user supplied buffer, use nullptr for fully sparse tensors + /// a would be dense shape of the tensor + /// non zero values shape. Use a single 0 shape for fully sparse tensors. + /// + template + static Value CreateSparseTensor(const OrtMemoryInfo* info, T* p_data, const Shape& dense_shape, + const Shape& values_shape); + + /// + /// Creates an OrtValue instance containing SparseTensor. This constructs + /// a sparse tensor that makes use of user allocated buffers. It does not make copies + /// of the user provided data and does not modify it. The lifespan of user provided buffers should + /// eclipse the life span of the resulting OrtValue. This call constructs an instance that only contain + /// a pointer to non-zero values. To fully populate the sparse tensor call UseIndices() API below + /// to supply a sparse format specific indices. + /// This API is not suitable for string data. Use CreateSparseTensor() with allocator specified so strings + /// can be properly copied into the allocated buffer. + /// + /// Memory description where the user buffers reside (CPU vs GPU etc) + /// pointer to the user supplied buffer, use nullptr for fully sparse tensors + /// a would be dense shape of the tensor + /// non zero values shape. Use a single 0 shape for fully sparse tensors. + /// data type + /// Ort::Value instance containing SparseTensor + static Value CreateSparseTensor(const OrtMemoryInfo* info, void* p_data, const Shape& dense_shape, + const Shape& values_shape, ONNXTensorElementDataType type); + + /// + /// This is a simple forwarding method to the below CreateSparseTensor. + /// This helps to specify data type enum in terms of C++ data type. + /// Use CreateSparseTensor + /// + /// numeric data type only. String data enum must be specified explicitly. + /// allocator to use + /// a would be dense shape of the tensor + /// Ort::Value + template + static Value CreateSparseTensor(OrtAllocator* allocator, const Shape& dense_shape); + + /// + /// Creates an instance of OrtValue containing sparse tensor. The created instance has no data. + /// The data must be supplied by on of the FillSparseTensor() methods that take both non-zero values + /// and indices. The data will be copied into a buffer that would be allocated using the supplied allocator. + /// Use this API to create OrtValues that contain sparse tensors with all supported data types including + /// strings. + /// + /// allocator to use. The allocator lifespan must eclipse that of the resulting OrtValue + /// a would be dense shape of the tensor + /// data type + /// an instance of Ort::Value + static Value CreateSparseTensor(OrtAllocator* allocator, const Shape& dense_shape, ONNXTensorElementDataType type); + +#endif // !defined(DISABLE_SPARSE_TENSORS) +}; + +/// +/// Represents native memory allocation coming from one of the +/// OrtAllocators registered with OnnxRuntime. +/// Use it to wrap an allocation made by an allocator +/// so it can be automatically released when no longer needed. +/// +struct MemoryAllocation { + MemoryAllocation(OrtAllocator* allocator, void* p, size_t size); + ~MemoryAllocation(); + MemoryAllocation(const MemoryAllocation&) = delete; + MemoryAllocation& operator=(const MemoryAllocation&) = delete; + MemoryAllocation(MemoryAllocation&&) noexcept; + MemoryAllocation& operator=(MemoryAllocation&&) noexcept; + + void* get() { return p_; } + size_t size() const { return size_; } + + private: + OrtAllocator* allocator_; + void* p_; + size_t size_; +}; + +namespace detail { +template +struct AllocatorImpl : Base { + using B = Base; + using B::B; + + void* Alloc(size_t size); + MemoryAllocation GetAllocation(size_t size); + void Free(void* p); + ConstMemoryInfo GetInfo() const; +}; + +} // namespace detail + +/** \brief Wrapper around ::OrtAllocator default instance that is owned by Onnxruntime + * + */ +struct AllocatorWithDefaultOptions : detail::AllocatorImpl> { + explicit AllocatorWithDefaultOptions(std::nullptr_t) {} ///< Convenience to create a class member and then replace with an instance + AllocatorWithDefaultOptions(); +}; + +/** \brief Wrapper around ::OrtAllocator + * + */ +struct Allocator : detail::AllocatorImpl { + explicit Allocator(std::nullptr_t) {} ///< Convenience to create a class member and then replace with an instance + Allocator(const Session& session, const OrtMemoryInfo*); +}; + +using UnownedAllocator = detail::AllocatorImpl>; + +namespace detail { +namespace binding_utils { +// Bring these out of template +std::vector GetOutputNamesHelper(const OrtIoBinding* binding, OrtAllocator*); +std::vector GetOutputValuesHelper(const OrtIoBinding* binding, OrtAllocator*); +} // namespace binding_utils + +template +struct ConstIoBindingImpl : Base { + using B = Base; + using B::B; + + std::vector GetOutputNames() const; + std::vector GetOutputNames(OrtAllocator*) const; + std::vector GetOutputValues() const; + std::vector GetOutputValues(OrtAllocator*) const; +}; + +template +struct IoBindingImpl : ConstIoBindingImpl { + using B = ConstIoBindingImpl; + using B::B; + + void BindInput(const char* name, const Value&); + void BindOutput(const char* name, const Value&); + void BindOutput(const char* name, const OrtMemoryInfo*); + void ClearBoundInputs(); + void ClearBoundOutputs(); + void SynchronizeInputs(); + void SynchronizeOutputs(); +}; + +} // namespace detail + +using ConstIoBinding = detail::ConstIoBindingImpl>; +using UnownedIoBinding = detail::IoBindingImpl>; + +/** \brief Wrapper around ::OrtIoBinding + * + */ +struct IoBinding : detail::IoBindingImpl { + explicit IoBinding(std::nullptr_t) {} ///< Create an empty object for convenience. Sometimes, we want to initialize members later. + explicit IoBinding(Session& session); + ConstIoBinding GetConst() const { return ConstIoBinding{this->p_}; } + UnownedIoBinding GetUnowned() const { return UnownedIoBinding{this->p_}; } +}; + +/*! \struct Ort::ArenaCfg + * \brief it is a structure that represents the configuration of an arena based allocator + * \details Please see docs/C_API.md for details + */ +struct ArenaCfg : detail::Base { + explicit ArenaCfg(std::nullptr_t) {} ///< Create an empty ArenaCfg object, must be assigned a valid one to be used + /** + * Wraps OrtApi::CreateArenaCfg + * \param max_mem - use 0 to allow ORT to choose the default + * \param arena_extend_strategy - use -1 to allow ORT to choose the default, 0 = kNextPowerOfTwo, 1 = kSameAsRequested + * \param initial_chunk_size_bytes - use -1 to allow ORT to choose the default + * \param max_dead_bytes_per_chunk - use -1 to allow ORT to choose the default + * See docs/C_API.md for details on what the following parameters mean and how to choose these values + */ + ArenaCfg(size_t max_mem, int arena_extend_strategy, int initial_chunk_size_bytes, int max_dead_bytes_per_chunk); +}; + +// +// Custom OPs (only needed to implement custom OPs) +// + +/// +/// This struct provides life time management for custom op attribute +/// +struct OpAttr : detail::Base { + OpAttr(const char* name, const void* data, int len, OrtOpAttrType type); +}; + +/** + * Macro that logs a message using the provided logger. Throws an exception if OrtApi::Logger_LogMessage fails. + * Example: ORT_CXX_LOG(logger, ORT_LOGGING_LEVEL_INFO, "Log a message"); + * + * \param logger The Ort::Logger instance to use. Must be a value or reference. + * \param message_severity The logging severity level of the message. + * \param message A null-terminated UTF-8 message to log. + */ +#define ORT_CXX_LOG(logger, message_severity, message) \ + do { \ + if (message_severity >= logger.GetLoggingSeverityLevel()) { \ + Ort::ThrowOnError(logger.LogMessage(message_severity, ORT_FILE, __LINE__, \ + static_cast(__FUNCTION__), message)); \ + } \ + } while (false) + +/** + * Macro that logs a message using the provided logger. Can be used in noexcept code since errors are silently ignored. + * Example: ORT_CXX_LOG_NOEXCEPT(logger, ORT_LOGGING_LEVEL_INFO, "Log a message"); + * + * \param logger The Ort::Logger instance to use. Must be a value or reference. + * \param message_severity The logging severity level of the message. + * \param message A null-terminated UTF-8 message to log. + */ +#define ORT_CXX_LOG_NOEXCEPT(logger, message_severity, message) \ + do { \ + if (message_severity >= logger.GetLoggingSeverityLevel()) { \ + static_cast(logger.LogMessage(message_severity, ORT_FILE, __LINE__, \ + static_cast(__FUNCTION__), message)); \ + } \ + } while (false) + +/** + * Macro that logs a printf-like formatted message using the provided logger. Throws an exception if + * OrtApi::Logger_LogMessage fails or if a formatting error occurs. + * Example: ORT_CXX_LOGF(logger, ORT_LOGGING_LEVEL_INFO, "Log an int: %d", 12); + * + * \param logger The Ort::Logger instance to use. Must be a value or reference. + * \param message_severity The logging severity level of the message. + * \param format A null-terminated UTF-8 format string forwarded to a printf-like function. + * Refer to https://en.cppreference.com/w/cpp/io/c/fprintf for information on valid formats. + * \param ... Zero or more variadic arguments referenced by the format string. + */ +#define ORT_CXX_LOGF(logger, message_severity, /*format,*/...) \ + do { \ + if (message_severity >= logger.GetLoggingSeverityLevel()) { \ + Ort::ThrowOnError(logger.LogFormattedMessage(message_severity, ORT_FILE, __LINE__, \ + static_cast(__FUNCTION__), __VA_ARGS__)); \ + } \ + } while (false) + +/** + * Macro that logs a printf-like formatted message using the provided logger. Can be used in noexcept code since errors + * are silently ignored. + * Example: ORT_CXX_LOGF_NOEXCEPT(logger, ORT_LOGGING_LEVEL_INFO, "Log an int: %d", 12); + * + * \param logger The Ort::Logger instance to use. Must be a value or reference. + * \param message_severity The logging severity level of the message. + * \param format A null-terminated UTF-8 format string forwarded to a printf-like function. + * Refer to https://en.cppreference.com/w/cpp/io/c/fprintf for information on valid formats. + * \param ... Zero or more variadic arguments referenced by the format string. + */ +#define ORT_CXX_LOGF_NOEXCEPT(logger, message_severity, /*format,*/...) \ + do { \ + if (message_severity >= logger.GetLoggingSeverityLevel()) { \ + static_cast(logger.LogFormattedMessage(message_severity, ORT_FILE, __LINE__, \ + static_cast(__FUNCTION__), __VA_ARGS__)); \ + } \ + } while (false) + +/// +/// This class represents an ONNX Runtime logger that can be used to log information with an +/// associated severity level and source code location (file path, line number, function name). +/// +/// A Logger can be obtained from within custom operators by calling Ort::KernelInfo::GetLogger(). +/// Instances of Ort::Logger are the size of two pointers and can be passed by value. +/// +/// Use the ORT_CXX_LOG macros to ensure the source code location is set properly from the callsite +/// and to take advantage of a cached logging severity level that can bypass calls to the underlying C API. +/// +struct Logger { + /** + * Creates an empty Ort::Logger. Must be initialized from a valid Ort::Logger before use. + */ + Logger() = default; + + /** + * Creates an empty Ort::Logger. Must be initialized from a valid Ort::Logger before use. + */ + explicit Logger(std::nullptr_t) {} + + /** + * Creates a logger from an ::OrtLogger instance. Caches the logger's current severity level by calling + * OrtApi::Logger_GetLoggingSeverityLevel. Throws an exception if OrtApi::Logger_GetLoggingSeverityLevel fails. + * + * \param logger The ::OrtLogger to wrap. + */ + explicit Logger(const OrtLogger* logger); + + ~Logger() = default; + + Logger(const Logger&) = default; + Logger& operator=(const Logger&) = default; + + Logger(Logger&& v) noexcept = default; + Logger& operator=(Logger&& v) noexcept = default; + + /** + * Returns the logger's current severity level from the cached member. + * + * \return The current ::OrtLoggingLevel. + */ + OrtLoggingLevel GetLoggingSeverityLevel() const noexcept; + + /** + * Logs the provided message via OrtApi::Logger_LogMessage. Use the ORT_CXX_LOG or ORT_CXX_LOG_NOEXCEPT + * macros to properly set the source code location and to use the cached severity level to potentially bypass + * calls to the underlying C API. + * + * \param log_severity_level The message's logging severity level. + * \param file_path The filepath of the file in which the message is logged. Usually the value of ORT_FILE. + * \param line_number The file line number in which the message is logged. Usually the value of __LINE__. + * \param func_name The name of the function in which the message is logged. Usually the value of __FUNCTION__. + * \param message The message to log. + * \return A Ort::Status value to indicate error or success. + */ + Status LogMessage(OrtLoggingLevel log_severity_level, const ORTCHAR_T* file_path, int line_number, + const char* func_name, const char* message) const noexcept; + + /** + * Logs a printf-like formatted message via OrtApi::Logger_LogMessage. Use the ORT_CXX_LOGF or ORT_CXX_LOGF_NOEXCEPT + * macros to properly set the source code location and to use the cached severity level to potentially bypass + * calls to the underlying C API. Returns an error status if a formatting error occurs. + * + * \param log_severity_level The message's logging severity level. + * \param file_path The filepath of the file in which the message is logged. Usually the value of ORT_FILE. + * \param line_number The file line number in which the message is logged. Usually the value of __LINE__. + * \param func_name The name of the function in which the message is logged. Usually the value of __FUNCTION__. + * \param format A null-terminated UTF-8 format string forwarded to a printf-like function. + * Refer to https://en.cppreference.com/w/cpp/io/c/fprintf for information on valid formats. + * \param args Zero or more variadic arguments referenced by the format string. + * \return A Ort::Status value to indicate error or success. + */ + template + Status LogFormattedMessage(OrtLoggingLevel log_severity_level, const ORTCHAR_T* file_path, int line_number, + const char* func_name, const char* format, Args&&... args) const noexcept; + + private: + const OrtLogger* logger_{}; + OrtLoggingLevel cached_severity_level_{}; +}; + +/// +/// This class wraps a raw pointer OrtKernelContext* that is being passed +/// to the custom kernel Compute() method. Use it to safely access context +/// attributes, input and output parameters with exception safety guarantees. +/// See usage example in onnxruntime/test/testdata/custom_op_library/custom_op_library.cc +/// +struct KernelContext { + explicit KernelContext(OrtKernelContext* context); + size_t GetInputCount() const; + size_t GetOutputCount() const; + ConstValue GetInput(size_t index) const; + UnownedValue GetOutput(size_t index, const int64_t* dim_values, size_t dim_count) const; + UnownedValue GetOutput(size_t index, const std::vector& dims) const; + void* GetGPUComputeStream() const; + Logger GetLogger() const; + OrtAllocator* GetAllocator(const OrtMemoryInfo& memory_info) const; + + private: + OrtKernelContext* ctx_; +}; + +struct KernelInfo; + +namespace detail { +namespace attr_utils { +void GetAttr(const OrtKernelInfo* p, const char* name, float&); +void GetAttr(const OrtKernelInfo* p, const char* name, int64_t&); +void GetAttr(const OrtKernelInfo* p, const char* name, std::string&); +void GetAttrs(const OrtKernelInfo* p, const char* name, std::vector&); +void GetAttrs(const OrtKernelInfo* p, const char* name, std::vector&); +} // namespace attr_utils + +template +struct KernelInfoImpl : Base { + using B = Base; + using B::B; + + KernelInfo Copy() const; + + template // R is only implemented for float, int64_t, and string + R GetAttribute(const char* name) const { + R val; + attr_utils::GetAttr(this->p_, name, val); + return val; + } + + template // R is only implemented for std::vector, std::vector + std::vector GetAttributes(const char* name) const { + std::vector result; + attr_utils::GetAttrs(this->p_, name, result); + return result; + } + + Value GetTensorAttribute(const char* name, OrtAllocator* allocator) const; + + size_t GetInputCount() const; + size_t GetOutputCount() const; + + std::string GetInputName(size_t index) const; + std::string GetOutputName(size_t index) const; + + TypeInfo GetInputTypeInfo(size_t index) const; + TypeInfo GetOutputTypeInfo(size_t index) const; + + ConstValue GetTensorConstantInput(size_t index, int* is_constant) const; + + std::string GetNodeName() const; + Logger GetLogger() const; +}; + +} // namespace detail + +using ConstKernelInfo = detail::KernelInfoImpl>; + +/// +/// This struct owns the OrtKernInfo* pointer when a copy is made. +/// For convenient wrapping of OrtKernelInfo* passed to kernel constructor +/// and query attributes, warp the pointer with Ort::Unowned instance +/// so it does not destroy the pointer the kernel does not own. +/// +struct KernelInfo : detail::KernelInfoImpl { + explicit KernelInfo(std::nullptr_t) {} ///< Create an empty instance to initialize later + explicit KernelInfo(OrtKernelInfo* info); ///< Take ownership of the instance + ConstKernelInfo GetConst() const { return ConstKernelInfo{this->p_}; } +}; + +/// +/// Create and own custom defined operation. +/// +struct Op : detail::Base { + explicit Op(std::nullptr_t) {} ///< Create an empty Operator object, must be assigned a valid one to be used + + explicit Op(OrtOp*); ///< Take ownership of the OrtOp + + static Op Create(const OrtKernelInfo* info, const char* op_name, const char* domain, + int version, const char** type_constraint_names, + const ONNXTensorElementDataType* type_constraint_values, + size_t type_constraint_count, + const OpAttr* attr_values, + size_t attr_count, + size_t input_count, size_t output_count); + + void Invoke(const OrtKernelContext* context, + const Value* input_values, + size_t input_count, + Value* output_values, + size_t output_count); + + // For easier refactoring + void Invoke(const OrtKernelContext* context, + const OrtValue* const* input_values, + size_t input_count, + OrtValue* const* output_values, + size_t output_count); +}; + +template +struct CustomOpBase : OrtCustomOp { + CustomOpBase() { + OrtCustomOp::version = ORT_API_VERSION; + OrtCustomOp::GetName = [](const OrtCustomOp* this_) { return static_cast(this_)->GetName(); }; + + OrtCustomOp::GetExecutionProviderType = [](const OrtCustomOp* this_) { return static_cast(this_)->GetExecutionProviderType(); }; + + OrtCustomOp::GetInputTypeCount = [](const OrtCustomOp* this_) { return static_cast(this_)->GetInputTypeCount(); }; + OrtCustomOp::GetInputType = [](const OrtCustomOp* this_, size_t index) { return static_cast(this_)->GetInputType(index); }; + OrtCustomOp::GetInputMemoryType = [](const OrtCustomOp* this_, size_t index) { return static_cast(this_)->GetInputMemoryType(index); }; + + OrtCustomOp::GetOutputTypeCount = [](const OrtCustomOp* this_) { return static_cast(this_)->GetOutputTypeCount(); }; + OrtCustomOp::GetOutputType = [](const OrtCustomOp* this_, size_t index) { return static_cast(this_)->GetOutputType(index); }; + +#if defined(_MSC_VER) && !defined(__clang__) +#pragma warning(push) +#pragma warning(disable : 26409) +#endif + OrtCustomOp::KernelDestroy = [](void* op_kernel) { delete static_cast(op_kernel); }; +#if defined(_MSC_VER) && !defined(__clang__) +#pragma warning(pop) +#endif + OrtCustomOp::GetInputCharacteristic = [](const OrtCustomOp* this_, size_t index) { return static_cast(this_)->GetInputCharacteristic(index); }; + OrtCustomOp::GetOutputCharacteristic = [](const OrtCustomOp* this_, size_t index) { return static_cast(this_)->GetOutputCharacteristic(index); }; + + OrtCustomOp::GetVariadicInputMinArity = [](const OrtCustomOp* this_) { return static_cast(this_)->GetVariadicInputMinArity(); }; + OrtCustomOp::GetVariadicInputHomogeneity = [](const OrtCustomOp* this_) { return static_cast(static_cast(this_)->GetVariadicInputHomogeneity()); }; + OrtCustomOp::GetVariadicOutputMinArity = [](const OrtCustomOp* this_) { return static_cast(this_)->GetVariadicOutputMinArity(); }; + OrtCustomOp::GetVariadicOutputHomogeneity = [](const OrtCustomOp* this_) { return static_cast(static_cast(this_)->GetVariadicOutputHomogeneity()); }; +#ifdef __cpp_if_constexpr + if constexpr (WithStatus) { +#else + if (WithStatus) { +#endif + OrtCustomOp::CreateKernelV2 = [](const OrtCustomOp* this_, const OrtApi* api, const OrtKernelInfo* info, void** op_kernel) -> OrtStatusPtr { + return static_cast(this_)->CreateKernelV2(*api, info, op_kernel); + }; + OrtCustomOp::KernelComputeV2 = [](void* op_kernel, OrtKernelContext* context) -> OrtStatusPtr { + return static_cast(op_kernel)->ComputeV2(context); + }; + } else { + OrtCustomOp::CreateKernelV2 = nullptr; + OrtCustomOp::KernelComputeV2 = nullptr; + + OrtCustomOp::CreateKernel = [](const OrtCustomOp* this_, const OrtApi* api, const OrtKernelInfo* info) { return static_cast(this_)->CreateKernel(*api, info); }; + OrtCustomOp::KernelCompute = [](void* op_kernel, OrtKernelContext* context) { + static_cast(op_kernel)->Compute(context); + }; + } + } + + // Default implementation of GetExecutionProviderType that returns nullptr to default to the CPU provider + const char* GetExecutionProviderType() const { return nullptr; } + + // Default implementations of GetInputCharacteristic() and GetOutputCharacteristic() below + // (inputs and outputs are required by default) + OrtCustomOpInputOutputCharacteristic GetInputCharacteristic(size_t /*index*/) const { + return OrtCustomOpInputOutputCharacteristic::INPUT_OUTPUT_REQUIRED; + } + + OrtCustomOpInputOutputCharacteristic GetOutputCharacteristic(size_t /*index*/) const { + return OrtCustomOpInputOutputCharacteristic::INPUT_OUTPUT_REQUIRED; + } + + // Default implemention of GetInputMemoryType() that returns OrtMemTypeDefault + OrtMemType GetInputMemoryType(size_t /*index*/) const { + return OrtMemTypeDefault; + } + + // Default implementation of GetVariadicInputMinArity() returns 1 to specify that a variadic input + // should expect at least 1 argument. + int GetVariadicInputMinArity() const { + return 1; + } + + // Default implementation of GetVariadicInputHomegeneity() returns true to specify that all arguments + // to a variadic input should be of the same type. + bool GetVariadicInputHomogeneity() const { + return true; + } + + // Default implementation of GetVariadicOutputMinArity() returns 1 to specify that a variadic output + // should produce at least 1 output value. + int GetVariadicOutputMinArity() const { + return 1; + } + + // Default implementation of GetVariadicOutputHomegeneity() returns true to specify that all output values + // produced by a variadic output should be of the same type. + bool GetVariadicOutputHomogeneity() const { + return true; + } + + // Declare list of session config entries used by this Custom Op. + // Implement this function in order to get configs from CustomOpBase::GetSessionConfigs(). + // This default implementation returns an empty vector of config entries. + std::vector GetSessionConfigKeys() const { + return std::vector{}; + } + + protected: + // Helper function that returns a map of session config entries specified by CustomOpBase::GetSessionConfigKeys. + void GetSessionConfigs(std::unordered_map& out, ConstSessionOptions options) const; +}; + +} // namespace Ort + +#include "onnxruntime_cxx_inline.h" diff --git a/duix-sdk/src/main/cpp/third/arm/include/onnx/onnxruntime_cxx_inline.h b/duix-sdk/src/main/cpp/third/arm/include/onnx/onnxruntime_cxx_inline.h new file mode 100644 index 0000000..2217283 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/onnx/onnxruntime_cxx_inline.h @@ -0,0 +1,1886 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// Do not include this file directly. Please include "onnxruntime_cxx_api.h" instead. +// If interested in trying out features of the new experimental C++ API, include "experimental_onnxruntime_cxx_api.h" instead. +// +// These are the inline implementations of the C++ header APIs. They're in this separate file as to not clutter +// the main C++ file with implementation details. + +#include + +namespace Ort { + +namespace detail { +inline void ThrowStatus(const Status& st) { + std::string error_message = st.GetErrorMessage(); + OrtErrorCode error_code = st.GetErrorCode(); + ORT_CXX_API_THROW(std::move(error_message), error_code); +} +} // namespace detail + +inline void ThrowOnError(OrtStatus* ort_status) { + if (ort_status) { + Ort::Status st(ort_status); + detail::ThrowStatus(st); + } +} + +inline void ThrowOnError(const Status& st) { + if (st) { + detail::ThrowStatus(st); + } +} + +inline Status::Status(OrtStatus* status) noexcept : Base{status} { +} + +inline Status::Status(const std::exception& e) noexcept { + p_ = GetApi().CreateStatus(ORT_FAIL, e.what()); +} + +inline Status::Status(const Exception& e) noexcept { + p_ = GetApi().CreateStatus(e.GetOrtErrorCode(), e.what()); +} + +inline Status::Status(const char* message, OrtErrorCode code) noexcept { + p_ = GetApi().CreateStatus(code, message); +} + +inline std::string Status::GetErrorMessage() const { + std::string message(GetApi().GetErrorMessage(p_)); + return message; +} + +inline OrtErrorCode Status::GetErrorCode() const { + return GetApi().GetErrorCode(p_); +} + +inline bool Status::IsOK() const noexcept { + return (p_ == nullptr); +} + +// This template converts a C++ type into it's ONNXTensorElementDataType +template +struct TypeToTensorType; +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT; +}; +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16; +}; +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16; +}; +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE; +}; +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8; +}; +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16; +}; +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32; +}; +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64; +}; +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8; +}; +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16; +}; +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32; +}; +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64; +}; +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL; +}; + +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FN; +}; +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FNUZ; +}; +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2; +}; +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2FNUZ; +}; + +inline bool BFloat16_t::operator==(const BFloat16_t& rhs) const noexcept { + if (IsNaN() || rhs.IsNaN()) { + // IEEE defines that NaN is not equal to anything, including itself. + return false; + } + return val == rhs.val; +} + +inline bool BFloat16_t::operator<(const BFloat16_t& rhs) const noexcept { + if (IsNaN() || rhs.IsNaN()) { + // IEEE defines that NaN is unordered with respect to everything, including itself. + return false; + } + + const bool left_is_negative = IsNegative(); + if (left_is_negative != rhs.IsNegative()) { + // When the signs of left and right differ, we know that left is less than right if it is + // the negative value. The exception to this is if both values are zero, in which case IEEE + // says they should be equal, even if the signs differ. + return left_is_negative && !AreZero(*this, rhs); + } + return (val != rhs.val) && ((val < rhs.val) ^ left_is_negative); +} + +inline MemoryAllocation::MemoryAllocation(OrtAllocator* allocator, void* p, size_t size) + : allocator_(allocator), p_(p), size_(size) { +} + +inline MemoryAllocation::~MemoryAllocation() { + if (p_ != nullptr) { + // We do not throw out of destructor + auto ret = GetApi().AllocatorFree(allocator_, p_); + static_cast(ret); + } +} + +inline MemoryAllocation::MemoryAllocation(MemoryAllocation&& o) noexcept : allocator_(nullptr), p_(nullptr), size_(0) { + *this = std::move(o); +} + +inline MemoryAllocation& MemoryAllocation::operator=(MemoryAllocation&& o) noexcept { + OrtAllocator* alloc = nullptr; + void* p = nullptr; + size_t sz = 0; + + // Swap out this + std::swap(alloc, allocator_); + std::swap(p, p_); + std::swap(sz, size_); + + // Swap with incoming + std::swap(allocator_, o.allocator_); + std::swap(p_, o.p_); + std::swap(size_, o.size_); + + // Destroy this instance if needed + MemoryAllocation this_alloc(alloc, p, sz); + return *this; +} + +namespace detail { + +template +inline void* AllocatorImpl::Alloc(size_t size) { + void* out; + ThrowOnError(GetApi().AllocatorAlloc(this->p_, size, &out)); + return out; +} + +template +inline MemoryAllocation AllocatorImpl::GetAllocation(size_t size) { + void* out; + ThrowOnError(GetApi().AllocatorAlloc(this->p_, size, &out)); + MemoryAllocation result(this->p_, out, size); + return result; +} + +template +inline void AllocatorImpl::Free(void* p) { + ThrowOnError(GetApi().AllocatorFree(this->p_, p)); +} + +template +inline ConstMemoryInfo AllocatorImpl::GetInfo() const { + const OrtMemoryInfo* out; + ThrowOnError(GetApi().AllocatorGetInfo(this->p_, &out)); + return ConstMemoryInfo{out}; +} + +} // namespace detail + +inline AllocatorWithDefaultOptions::AllocatorWithDefaultOptions() { + ThrowOnError(GetApi().GetAllocatorWithDefaultOptions(&this->p_)); +} + +inline Allocator::Allocator(const Session& sess, const OrtMemoryInfo* mem_info) { + ThrowOnError(GetApi().CreateAllocator(sess, mem_info, &this->p_)); +} + +namespace detail { + +template +inline std::string MemoryInfoImpl::GetAllocatorName() const { + const char* name = nullptr; + ThrowOnError(GetApi().MemoryInfoGetName(this->p_, &name)); + return std::string(name); +} + +template +inline OrtAllocatorType MemoryInfoImpl::GetAllocatorType() const { + OrtAllocatorType type; + ThrowOnError(GetApi().MemoryInfoGetType(this->p_, &type)); + return type; +} + +template +inline int MemoryInfoImpl::GetDeviceId() const { + int id = 0; + ThrowOnError(GetApi().MemoryInfoGetId(this->p_, &id)); + return id; +} + +template +inline OrtMemoryInfoDeviceType MemoryInfoImpl::GetDeviceType() const { + OrtMemoryInfoDeviceType type; + GetApi().MemoryInfoGetDeviceType(this->p_, &type); + return type; +} + +template +inline OrtMemType MemoryInfoImpl::GetMemoryType() const { + OrtMemType type; + ThrowOnError(GetApi().MemoryInfoGetMemType(this->p_, &type)); + return type; +} + +template +template +inline bool MemoryInfoImpl::operator==(const MemoryInfoImpl& o) const { + int comp_result = 0; + ThrowOnError(Ort::GetApi().CompareMemoryInfo(this->p_, o, &comp_result)); + return comp_result == 0; +} + +} // namespace detail + +inline MemoryInfo MemoryInfo::CreateCpu(OrtAllocatorType type, OrtMemType mem_type) { + OrtMemoryInfo* p; + ThrowOnError(GetApi().CreateCpuMemoryInfo(type, mem_type, &p)); + return MemoryInfo(p); +} + +inline MemoryInfo::MemoryInfo(const char* name, OrtAllocatorType type, int id, OrtMemType mem_type) { + ThrowOnError(GetApi().CreateMemoryInfo(name, type, id, mem_type, &this->p_)); +} + +namespace detail { +template +inline std::vector ConstIoBindingImpl::GetOutputNames() const { + AllocatorWithDefaultOptions allocator; + return binding_utils::GetOutputNamesHelper(this->p_, allocator); +} + +template +inline std::vector ConstIoBindingImpl::GetOutputNames(OrtAllocator* allocator) const { + return binding_utils::GetOutputNamesHelper(this->p_, allocator); +} + +template +inline std::vector ConstIoBindingImpl::GetOutputValues() const { + AllocatorWithDefaultOptions allocator; + return binding_utils::GetOutputValuesHelper(this->p_, allocator); +} + +template +inline std::vector ConstIoBindingImpl::GetOutputValues(OrtAllocator* allocator) const { + return binding_utils::GetOutputValuesHelper(this->p_, allocator); +} + +template +inline void IoBindingImpl::BindInput(const char* name, const Value& value) { + ThrowOnError(GetApi().BindInput(this->p_, name, value)); +} + +template +inline void IoBindingImpl::BindOutput(const char* name, const Value& value) { + ThrowOnError(GetApi().BindOutput(this->p_, name, value)); +} + +template +inline void IoBindingImpl::BindOutput(const char* name, const OrtMemoryInfo* mem_info) { + ThrowOnError(GetApi().BindOutputToDevice(this->p_, name, mem_info)); +} + +template +inline void IoBindingImpl::ClearBoundInputs() { + GetApi().ClearBoundInputs(this->p_); +} + +template +inline void IoBindingImpl::ClearBoundOutputs() { + GetApi().ClearBoundOutputs(this->p_); +} + +template +inline void IoBindingImpl::SynchronizeInputs() { + ThrowOnError(GetApi().SynchronizeBoundInputs(this->p_)); +} + +template +inline void IoBindingImpl::SynchronizeOutputs() { + ThrowOnError(GetApi().SynchronizeBoundOutputs(this->p_)); +} + +namespace binding_utils { +inline std::vector GetOutputNamesHelper(const OrtIoBinding* binding, OrtAllocator* allocator) { + std::vector result; + auto free_fn = detail::AllocatedFree(allocator); + using Ptr = std::unique_ptr; + + char* buffer = nullptr; + size_t* lengths = nullptr; + size_t count = 0; + ThrowOnError(GetApi().GetBoundOutputNames(binding, allocator, &buffer, &lengths, &count)); + + if (count == 0) { + return result; + } + + Ptr buffer_g(buffer, free_fn); + Ptr lengths_g(lengths, free_fn); + + result.reserve(count); + for (size_t i = 0; i < count; ++i) { + auto sz = *lengths; + result.emplace_back(buffer, sz); + buffer += sz; + ++lengths; + } + return result; +} + +inline std::vector GetOutputValuesHelper(const OrtIoBinding* binding, OrtAllocator* allocator) { + std::vector result; + size_t owned = 0; + size_t output_count = 0; + // Lambda to release the buffer when no longer needed and + // make sure that we destroy all instances on exception + auto free_fn = [&owned, &output_count, allocator](OrtValue** buffer) { + if (buffer) { + while (owned < output_count) { + auto* p = buffer + owned++; + GetApi().ReleaseValue(*p); + } + allocator->Free(allocator, buffer); + } + }; + using Ptr = std::unique_ptr; + + OrtValue** output_buffer = nullptr; + ThrowOnError(GetApi().GetBoundOutputValues(binding, allocator, &output_buffer, &output_count)); + if (output_count == 0) { + return result; + } + + Ptr buffer_g(output_buffer, free_fn); + + result.reserve(output_count); + for (size_t i = 0; i < output_count; ++i) { + result.emplace_back(output_buffer[i]); + ++owned; + } + return result; +} + +} // namespace binding_utils +} // namespace detail + +inline IoBinding::IoBinding(Session& session) { + ThrowOnError(GetApi().CreateIoBinding(session, &this->p_)); +} + +inline ArenaCfg::ArenaCfg(size_t max_mem, int arena_extend_strategy, int initial_chunk_size_bytes, int max_dead_bytes_per_chunk) { + ThrowOnError(GetApi().CreateArenaCfg(max_mem, arena_extend_strategy, initial_chunk_size_bytes, max_dead_bytes_per_chunk, &p_)); +} + +inline ThreadingOptions::ThreadingOptions() { + ThrowOnError(GetApi().CreateThreadingOptions(&p_)); +} + +inline ThreadingOptions& ThreadingOptions::SetGlobalIntraOpNumThreads(int intra_op_num_threads) { + ThrowOnError(GetApi().SetGlobalIntraOpNumThreads(p_, intra_op_num_threads)); + return *this; +} + +inline ThreadingOptions& ThreadingOptions::SetGlobalInterOpNumThreads(int inter_op_num_threads) { + ThrowOnError(GetApi().SetGlobalInterOpNumThreads(p_, inter_op_num_threads)); + return *this; +} + +inline ThreadingOptions& ThreadingOptions::SetGlobalSpinControl(int allow_spinning) { + ThrowOnError(GetApi().SetGlobalSpinControl(p_, allow_spinning)); + return *this; +} + +inline ThreadingOptions& ThreadingOptions::SetGlobalDenormalAsZero() { + ThrowOnError(GetApi().SetGlobalDenormalAsZero(p_)); + return *this; +} + +inline ThreadingOptions& ThreadingOptions::SetGlobalCustomCreateThreadFn(OrtCustomCreateThreadFn ort_custom_create_thread_fn) { + ThrowOnError(GetApi().SetGlobalCustomCreateThreadFn(p_, ort_custom_create_thread_fn)); + return *this; +} + +inline ThreadingOptions& ThreadingOptions::SetGlobalCustomThreadCreationOptions(void* ort_custom_thread_creation_options) { + ThrowOnError(GetApi().SetGlobalCustomThreadCreationOptions(p_, ort_custom_thread_creation_options)); + return *this; +} + +inline ThreadingOptions& ThreadingOptions::SetGlobalCustomJoinThreadFn(OrtCustomJoinThreadFn ort_custom_join_thread_fn) { + ThrowOnError(GetApi().SetGlobalCustomJoinThreadFn(p_, ort_custom_join_thread_fn)); + return *this; +} + +inline Env::Env(OrtLoggingLevel logging_level, _In_ const char* logid) { + ThrowOnError(GetApi().CreateEnv(logging_level, logid, &p_)); + if (strcmp(logid, "onnxruntime-node") == 0) { + ThrowOnError(GetApi().SetLanguageProjection(p_, OrtLanguageProjection::ORT_PROJECTION_NODEJS)); + } else { + ThrowOnError(GetApi().SetLanguageProjection(p_, OrtLanguageProjection::ORT_PROJECTION_CPLUSPLUS)); + } +} + +inline Env::Env(OrtLoggingLevel logging_level, const char* logid, OrtLoggingFunction logging_function, void* logger_param) { + ThrowOnError(GetApi().CreateEnvWithCustomLogger(logging_function, logger_param, logging_level, logid, &p_)); + if (strcmp(logid, "onnxruntime-node") == 0) { + ThrowOnError(GetApi().SetLanguageProjection(p_, OrtLanguageProjection::ORT_PROJECTION_NODEJS)); + } else { + ThrowOnError(GetApi().SetLanguageProjection(p_, OrtLanguageProjection::ORT_PROJECTION_CPLUSPLUS)); + } +} + +inline Env::Env(const OrtThreadingOptions* tp_options, OrtLoggingLevel logging_level, _In_ const char* logid) { + ThrowOnError(GetApi().CreateEnvWithGlobalThreadPools(logging_level, logid, tp_options, &p_)); + if (strcmp(logid, "onnxruntime-node") == 0) { + ThrowOnError(GetApi().SetLanguageProjection(p_, OrtLanguageProjection::ORT_PROJECTION_NODEJS)); + } else { + ThrowOnError(GetApi().SetLanguageProjection(p_, OrtLanguageProjection::ORT_PROJECTION_CPLUSPLUS)); + } +} + +inline Env::Env(const OrtThreadingOptions* tp_options, OrtLoggingFunction logging_function, void* logger_param, + OrtLoggingLevel logging_level, _In_ const char* logid) { + ThrowOnError(GetApi().CreateEnvWithCustomLoggerAndGlobalThreadPools(logging_function, logger_param, logging_level, logid, tp_options, &p_)); + if (strcmp(logid, "onnxruntime-node") == 0) { + ThrowOnError(GetApi().SetLanguageProjection(p_, OrtLanguageProjection::ORT_PROJECTION_NODEJS)); + } else { + ThrowOnError(GetApi().SetLanguageProjection(p_, OrtLanguageProjection::ORT_PROJECTION_CPLUSPLUS)); + } +} + +inline Env& Env::EnableTelemetryEvents() { + ThrowOnError(GetApi().EnableTelemetryEvents(p_)); + return *this; +} + +inline Env& Env::DisableTelemetryEvents() { + ThrowOnError(GetApi().DisableTelemetryEvents(p_)); + return *this; +} + +inline Env& Env::UpdateEnvWithCustomLogLevel(OrtLoggingLevel log_severity_level) { + ThrowOnError(GetApi().UpdateEnvWithCustomLogLevel(p_, log_severity_level)); + return *this; +} + +inline Env& Env::CreateAndRegisterAllocator(const OrtMemoryInfo* mem_info, const OrtArenaCfg* arena_cfg) { + ThrowOnError(GetApi().CreateAndRegisterAllocator(p_, mem_info, arena_cfg)); + return *this; +} + +inline Env& Env::CreateAndRegisterAllocatorV2(const std::string& provider_type, const OrtMemoryInfo* mem_info, const std::unordered_map& options, const OrtArenaCfg* arena_cfg) { + std::vector keys, values; + auto num_entries = options.size(); + if (num_entries > 0) { + keys.reserve(num_entries); + values.reserve(num_entries); + for (const auto& entry : options) { + keys.push_back(entry.first.c_str()); + values.push_back(entry.second.c_str()); + } + } + ThrowOnError(GetApi().CreateAndRegisterAllocatorV2(p_, provider_type.c_str(), mem_info, arena_cfg, keys.data(), values.data(), num_entries)); + return *this; +} + +inline CustomOpDomain::CustomOpDomain(const char* domain) { + ThrowOnError(GetApi().CreateCustomOpDomain(domain, &p_)); +} + +inline void CustomOpDomain::Add(const OrtCustomOp* op) { + ThrowOnError(GetApi().CustomOpDomain_Add(p_, op)); +} + +inline RunOptions::RunOptions() { + ThrowOnError(GetApi().CreateRunOptions(&p_)); +} + +inline RunOptions& RunOptions::SetRunLogVerbosityLevel(int level) { + ThrowOnError(GetApi().RunOptionsSetRunLogVerbosityLevel(p_, level)); + return *this; +} + +inline RunOptions& RunOptions::SetRunLogSeverityLevel(int level) { + ThrowOnError(GetApi().RunOptionsSetRunLogSeverityLevel(p_, level)); + return *this; +} + +inline int RunOptions::GetRunLogVerbosityLevel() const { + int out; + ThrowOnError(GetApi().RunOptionsGetRunLogVerbosityLevel(p_, &out)); + return out; +} + +inline int RunOptions::GetRunLogSeverityLevel() const { + int out; + ThrowOnError(GetApi().RunOptionsGetRunLogSeverityLevel(p_, &out)); + return out; +} + +inline RunOptions& RunOptions::SetRunTag(const char* run_tag) { + ThrowOnError(GetApi().RunOptionsSetRunTag(p_, run_tag)); + return *this; +} + +inline const char* RunOptions::GetRunTag() const { + const char* out; + ThrowOnError(GetApi().RunOptionsGetRunTag(p_, &out)); + return out; +} + +inline RunOptions& RunOptions::AddConfigEntry(const char* config_key, const char* config_value) { + ThrowOnError(GetApi().AddRunConfigEntry(p_, config_key, config_value)); + return *this; +} + +inline RunOptions& RunOptions::SetTerminate() { + ThrowOnError(GetApi().RunOptionsSetTerminate(p_)); + return *this; +} + +inline RunOptions& RunOptions::UnsetTerminate() { + ThrowOnError(GetApi().RunOptionsUnsetTerminate(p_)); + return *this; +} + +namespace detail { + +template +inline Ort::SessionOptions ConstSessionOptionsImpl::Clone() const { + OrtSessionOptions* out; + ThrowOnError(GetApi().CloneSessionOptions(this->p_, &out)); + return SessionOptions{out}; +} + +template +inline std::string ConstSessionOptionsImpl::GetConfigEntry(const char* config_key) const { + size_t size = 0; + // Feed nullptr for the data buffer to query the true size of the string value + Ort::ThrowOnError(GetApi().GetSessionConfigEntry(this->p_, config_key, nullptr, &size)); + + std::string out; + out.resize(size); + Ort::ThrowOnError(GetApi().GetSessionConfigEntry(this->p_, config_key, &out[0], &size)); + out.resize(size - 1); // remove the terminating character '\0' + + return out; +} + +template +inline bool ConstSessionOptionsImpl::HasConfigEntry(const char* config_key) const { + int out = 0; + Ort::ThrowOnError(GetApi().HasSessionConfigEntry(this->p_, config_key, &out)); + return static_cast(out); +} + +template +inline std::string ConstSessionOptionsImpl::GetConfigEntryOrDefault(const char* config_key, const std::string& def) { + if (!this->HasConfigEntry(config_key)) { + return def; + } + + return this->GetConfigEntry(config_key); +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::SetIntraOpNumThreads(int intra_op_num_threads) { + ThrowOnError(GetApi().SetIntraOpNumThreads(this->p_, intra_op_num_threads)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::SetInterOpNumThreads(int inter_op_num_threads) { + ThrowOnError(GetApi().SetInterOpNumThreads(this->p_, inter_op_num_threads)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::SetGraphOptimizationLevel(GraphOptimizationLevel graph_optimization_level) { + ThrowOnError(GetApi().SetSessionGraphOptimizationLevel(this->p_, graph_optimization_level)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::SetOptimizedModelFilePath(const ORTCHAR_T* optimized_model_filepath) { + ThrowOnError(GetApi().SetOptimizedModelFilePath(this->p_, optimized_model_filepath)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::EnableProfiling(const ORTCHAR_T* profile_file_prefix) { + ThrowOnError(GetApi().EnableProfiling(this->p_, profile_file_prefix)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::DisableProfiling() { + ThrowOnError(GetApi().DisableProfiling(this->p_)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::EnableOrtCustomOps() { + ThrowOnError(GetApi().EnableOrtCustomOps(this->p_)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::EnableMemPattern() { + ThrowOnError(GetApi().EnableMemPattern(this->p_)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::DisableMemPattern() { + ThrowOnError(GetApi().DisableMemPattern(this->p_)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::EnableCpuMemArena() { + ThrowOnError(GetApi().EnableCpuMemArena(this->p_)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::DisableCpuMemArena() { + ThrowOnError(GetApi().DisableCpuMemArena(this->p_)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::SetExecutionMode(ExecutionMode execution_mode) { + ThrowOnError(GetApi().SetSessionExecutionMode(this->p_, execution_mode)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::SetLogId(const char* logid) { + ThrowOnError(GetApi().SetSessionLogId(this->p_, logid)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::SetLogSeverityLevel(int level) { + ThrowOnError(GetApi().SetSessionLogSeverityLevel(this->p_, level)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::Add(OrtCustomOpDomain* custom_op_domain) { + ThrowOnError(GetApi().AddCustomOpDomain(this->p_, custom_op_domain)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::AddConfigEntry(const char* config_key, const char* config_value) { + ThrowOnError(GetApi().AddSessionConfigEntry(this->p_, config_key, config_value)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::AddInitializer(const char* name, const OrtValue* ort_val) { + ThrowOnError(GetApi().AddInitializer(this->p_, name, ort_val)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::DisablePerSessionThreads() { + ThrowOnError(GetApi().DisablePerSessionThreads(this->p_)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::AddExternalInitializers(const std::vector& names, + const std::vector& ort_values) { + const size_t inputs_num = names.size(); + if (inputs_num != ort_values.size()) { + ORT_CXX_API_THROW("Expecting names and ort_values to have the same length", ORT_INVALID_ARGUMENT); + } + std::vector names_ptr; + std::vector ort_values_ptrs; + names_ptr.reserve(inputs_num); + ort_values_ptrs.reserve(inputs_num); + for (size_t i = 0; i < inputs_num; ++i) { + names_ptr.push_back(names[i].c_str()); + ort_values_ptrs.push_back(ort_values[i]); + } + ThrowOnError(GetApi().AddExternalInitializers(this->p_, names_ptr.data(), ort_values_ptrs.data(), inputs_num)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::AppendExecutionProvider_CUDA(const OrtCUDAProviderOptions& provider_options) { + ThrowOnError(GetApi().SessionOptionsAppendExecutionProvider_CUDA(this->p_, &provider_options)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::AppendExecutionProvider_CUDA_V2(const OrtCUDAProviderOptionsV2& provider_options) { + ThrowOnError(GetApi().SessionOptionsAppendExecutionProvider_CUDA_V2(this->p_, &provider_options)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::AppendExecutionProvider_ROCM(const OrtROCMProviderOptions& provider_options) { + ThrowOnError(GetApi().SessionOptionsAppendExecutionProvider_ROCM(this->p_, &provider_options)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::AppendExecutionProvider_TensorRT(const OrtTensorRTProviderOptions& provider_options) { + ThrowOnError(GetApi().SessionOptionsAppendExecutionProvider_TensorRT(this->p_, &provider_options)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::AppendExecutionProvider_TensorRT_V2(const OrtTensorRTProviderOptionsV2& provider_options) { + ThrowOnError(GetApi().SessionOptionsAppendExecutionProvider_TensorRT_V2(this->p_, &provider_options)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::AppendExecutionProvider_MIGraphX(const OrtMIGraphXProviderOptions& provider_options) { + ThrowOnError(GetApi().SessionOptionsAppendExecutionProvider_MIGraphX(this->p_, &provider_options)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::AppendExecutionProvider_CANN(const OrtCANNProviderOptions& provider_options) { + ThrowOnError(GetApi().SessionOptionsAppendExecutionProvider_CANN(this->p_, &provider_options)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::AppendExecutionProvider_Dnnl(const OrtDnnlProviderOptions& provider_options) { + ThrowOnError(GetApi().SessionOptionsAppendExecutionProvider_Dnnl(this->p_, &provider_options)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::AppendExecutionProvider( + const std::string& provider_name, + const std::unordered_map& provider_options) { + auto num_entries = provider_options.size(); + std::vector keys, values; + if (num_entries > 0) { + keys.reserve(num_entries); + values.reserve(num_entries); + + for (const auto& entry : provider_options) { + keys.push_back(entry.first.c_str()); + values.push_back(entry.second.c_str()); + } + } + + ThrowOnError(GetApi().SessionOptionsAppendExecutionProvider(this->p_, provider_name.c_str(), + keys.data(), values.data(), num_entries)); + + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::SetCustomCreateThreadFn(OrtCustomCreateThreadFn ort_custom_create_thread_fn) { + ThrowOnError(GetApi().SessionOptionsSetCustomCreateThreadFn(this->p_, ort_custom_create_thread_fn)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::SetCustomThreadCreationOptions(void* ort_custom_thread_creation_options) { + ThrowOnError(GetApi().SessionOptionsSetCustomThreadCreationOptions(this->p_, ort_custom_thread_creation_options)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::SetCustomJoinThreadFn(OrtCustomJoinThreadFn ort_custom_join_thread_fn) { + ThrowOnError(GetApi().SessionOptionsSetCustomJoinThreadFn(this->p_, ort_custom_join_thread_fn)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::AppendExecutionProvider_OpenVINO(const OrtOpenVINOProviderOptions& provider_options) { + ThrowOnError(GetApi().SessionOptionsAppendExecutionProvider_OpenVINO(this->p_, &provider_options)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::RegisterCustomOpsLibrary(const ORTCHAR_T* library_name, + const CustomOpConfigs& custom_op_configs) { + // Add custom op config entries before registering the custom op library. Otherwise, the config entries _may_ be ignored by + // the custom op library. + for (const auto& config_iter : custom_op_configs.GetFlattenedConfigs()) { + AddConfigEntry(config_iter.first.c_str(), config_iter.second.c_str()); + } + + ThrowOnError(GetApi().RegisterCustomOpsLibrary_V2(this->p_, library_name)); + return *this; +} + +template +inline SessionOptionsImpl& SessionOptionsImpl::RegisterCustomOpsUsingFunction(const char* registration_function_name) { + ThrowOnError(GetApi().RegisterCustomOpsUsingFunction(this->p_, registration_function_name)); + return *this; +} + +/// Session +template +inline size_t ConstSessionImpl::GetInputCount() const { + size_t out; + ThrowOnError(GetApi().SessionGetInputCount(this->p_, &out)); + return out; +} + +template +inline size_t ConstSessionImpl::GetOutputCount() const { + size_t out; + ThrowOnError(GetApi().SessionGetOutputCount(this->p_, &out)); + return out; +} + +template +inline size_t ConstSessionImpl::GetOverridableInitializerCount() const { + size_t out; + ThrowOnError(GetApi().SessionGetOverridableInitializerCount(this->p_, &out)); + return out; +} + +template +inline AllocatedStringPtr ConstSessionImpl::GetInputNameAllocated(size_t index, OrtAllocator* allocator) const { + char* out; + ThrowOnError(GetApi().SessionGetInputName(this->p_, index, allocator, &out)); + return AllocatedStringPtr(out, detail::AllocatedFree(allocator)); +} + +template +inline AllocatedStringPtr ConstSessionImpl::GetOutputNameAllocated(size_t index, OrtAllocator* allocator) const { + char* out; + ThrowOnError(GetApi().SessionGetOutputName(this->p_, index, allocator, &out)); + return AllocatedStringPtr(out, detail::AllocatedFree(allocator)); +} + +template +inline AllocatedStringPtr ConstSessionImpl::GetOverridableInitializerNameAllocated(size_t index, OrtAllocator* allocator) const { + char* out; + ThrowOnError(GetApi().SessionGetOverridableInitializerName(this->p_, index, allocator, &out)); + return AllocatedStringPtr(out, detail::AllocatedFree(allocator)); +} + +template +inline uint64_t ConstSessionImpl::GetProfilingStartTimeNs() const { + uint64_t out; + ThrowOnError(GetApi().SessionGetProfilingStartTimeNs(this->p_, &out)); + return out; +} + +template +inline ModelMetadata ConstSessionImpl::GetModelMetadata() const { + OrtModelMetadata* out; + ThrowOnError(GetApi().SessionGetModelMetadata(this->p_, &out)); + return ModelMetadata{out}; +} + +template +inline TypeInfo ConstSessionImpl::GetInputTypeInfo(size_t index) const { + OrtTypeInfo* out; + ThrowOnError(GetApi().SessionGetInputTypeInfo(this->p_, index, &out)); + return TypeInfo{out}; +} + +template +inline TypeInfo ConstSessionImpl::GetOutputTypeInfo(size_t index) const { + OrtTypeInfo* out; + ThrowOnError(GetApi().SessionGetOutputTypeInfo(this->p_, index, &out)); + return TypeInfo{out}; +} + +template +inline TypeInfo ConstSessionImpl::GetOverridableInitializerTypeInfo(size_t index) const { + OrtTypeInfo* out; + ThrowOnError(GetApi().SessionGetOverridableInitializerTypeInfo(this->p_, index, &out)); + return TypeInfo{out}; +} + +template +inline std::vector SessionImpl::Run(const RunOptions& run_options, const char* const* input_names, const Value* input_values, size_t input_count, + const char* const* output_names, size_t output_count) { + std::vector output_values; + output_values.reserve(output_count); + for (size_t i = 0; i < output_count; i++) + output_values.emplace_back(nullptr); + Run(run_options, input_names, input_values, input_count, output_names, output_values.data(), output_count); + return output_values; +} + +template +inline void SessionImpl::Run(const RunOptions& run_options, const char* const* input_names, const Value* input_values, size_t input_count, + const char* const* output_names, Value* output_values, size_t output_count) { + static_assert(sizeof(Value) == sizeof(OrtValue*), "Value is really just an array of OrtValue* in memory, so we can reinterpret_cast safely"); + auto ort_input_values = reinterpret_cast(input_values); + auto ort_output_values = reinterpret_cast(output_values); + ThrowOnError(GetApi().Run(this->p_, run_options, input_names, ort_input_values, input_count, output_names, output_count, ort_output_values)); +} + +template +inline void SessionImpl::Run(const RunOptions& run_options, const IoBinding& io_binding) { + ThrowOnError(GetApi().RunWithBinding(this->p_, run_options, io_binding)); +} + +template +inline void SessionImpl::RunAsync(const RunOptions& run_options, const char* const* input_names, const Value* input_values, size_t input_count, + const char* const* output_names, Value* output_values, size_t output_count, RunAsyncCallbackFn callback, void* user_data) { + auto ort_input_values = reinterpret_cast(input_values); + auto ort_output_values = reinterpret_cast(output_values); + ThrowOnError(GetApi().RunAsync(this->p_, run_options, input_names, + ort_input_values, input_count, output_names, output_count, + ort_output_values, callback, user_data)); +} + +template +inline AllocatedStringPtr SessionImpl::EndProfilingAllocated(OrtAllocator* allocator) { + char* out = nullptr; + ThrowOnError(GetApi().SessionEndProfiling(this->p_, allocator, &out)); + return AllocatedStringPtr(out, detail::AllocatedFree(allocator)); +} + +} // namespace detail + +inline SessionOptions::SessionOptions() { + ThrowOnError(GetApi().CreateSessionOptions(&this->p_)); +} + +/// CustomOpConfigs +inline std::string detail::MakeCustomOpConfigEntryKey(const char* custom_op_name, const char* config) { + std::string config_key = "custom_op."; + + config_key += custom_op_name; + config_key += "."; + config_key += config; + + return config_key; +} + +inline CustomOpConfigs& CustomOpConfigs::AddConfig(const char* custom_op_name, const char* config_key, const char* config_value) { + const std::string full_flat_key = detail::MakeCustomOpConfigEntryKey(custom_op_name, config_key); + flat_configs_[full_flat_key] = config_value; + return *this; +} + +inline const std::unordered_map& CustomOpConfigs::GetFlattenedConfigs() const { + return flat_configs_; +} + +inline Session::Session(const Env& env, const ORTCHAR_T* model_path, const SessionOptions& options) { + ThrowOnError(GetApi().CreateSession(env, model_path, options, &this->p_)); +} + +inline Session::Session(const Env& env, const ORTCHAR_T* model_path, const SessionOptions& options, + OrtPrepackedWeightsContainer* prepacked_weights_container) { + ThrowOnError(GetApi().CreateSessionWithPrepackedWeightsContainer(env, model_path, options, prepacked_weights_container, &this->p_)); +} + +inline Session::Session(const Env& env, const void* model_data, size_t model_data_length, const SessionOptions& options) { + ThrowOnError(GetApi().CreateSessionFromArray(env, model_data, model_data_length, options, &this->p_)); +} + +inline Session::Session(const Env& env, const void* model_data, size_t model_data_length, + const SessionOptions& options, OrtPrepackedWeightsContainer* prepacked_weights_container) { + ThrowOnError(GetApi().CreateSessionFromArrayWithPrepackedWeightsContainer(env, model_data, model_data_length, options, + prepacked_weights_container, &this->p_)); +} + +inline AllocatedStringPtr ModelMetadata::GetProducerNameAllocated(OrtAllocator* allocator) const { + char* out; + ThrowOnError(GetApi().ModelMetadataGetProducerName(p_, allocator, &out)); + return AllocatedStringPtr(out, detail::AllocatedFree(allocator)); +} + +inline AllocatedStringPtr ModelMetadata::GetGraphNameAllocated(OrtAllocator* allocator) const { + char* out; + ThrowOnError(GetApi().ModelMetadataGetGraphName(p_, allocator, &out)); + return AllocatedStringPtr(out, detail::AllocatedFree(allocator)); +} + +inline AllocatedStringPtr ModelMetadata::GetDomainAllocated(OrtAllocator* allocator) const { + char* out; + ThrowOnError(GetApi().ModelMetadataGetDomain(p_, allocator, &out)); + return AllocatedStringPtr(out, detail::AllocatedFree(allocator)); +} + +inline AllocatedStringPtr Ort::ModelMetadata::GetDescriptionAllocated(OrtAllocator* allocator) const { + char* out; + ThrowOnError(GetApi().ModelMetadataGetDescription(p_, allocator, &out)); + return AllocatedStringPtr(out, detail::AllocatedFree(allocator)); +} + +inline AllocatedStringPtr ModelMetadata::GetGraphDescriptionAllocated(OrtAllocator* allocator) const { + char* out; + ThrowOnError(GetApi().ModelMetadataGetGraphDescription(p_, allocator, &out)); + return AllocatedStringPtr(out, detail::AllocatedFree(allocator)); +} + +inline AllocatedStringPtr ModelMetadata::LookupCustomMetadataMapAllocated(const char* key, OrtAllocator* allocator) const { + char* out; + ThrowOnError(GetApi().ModelMetadataLookupCustomMetadataMap(p_, allocator, key, &out)); + return AllocatedStringPtr(out, detail::AllocatedFree(allocator)); +} + +inline std::vector ModelMetadata::GetCustomMetadataMapKeysAllocated(OrtAllocator* allocator) const { + auto deletor = detail::AllocatedFree(allocator); + std::vector result; + + char** out = nullptr; + int64_t num_keys = 0; + ThrowOnError(GetApi().ModelMetadataGetCustomMetadataMapKeys(p_, allocator, &out, &num_keys)); + if (num_keys <= 0) { + return result; + } + + // array of pointers will be freed + std::unique_ptr array_guard(out, deletor); + // reserve may throw + auto strings_deletor = [&deletor, num_keys](char** out) { for(int64_t i = 0; i < num_keys; ++i) deletor(out[i]); }; + std::unique_ptr strings_guard(out, strings_deletor); + result.reserve(static_cast(num_keys)); + strings_guard.release(); + for (int64_t i = 0; i < num_keys; ++i) { + result.push_back(AllocatedStringPtr(out[i], deletor)); + } + + return result; +} + +inline int64_t ModelMetadata::GetVersion() const { + int64_t out; + ThrowOnError(GetApi().ModelMetadataGetVersion(p_, &out)); + return out; +} + +namespace detail { + +template +inline ONNXTensorElementDataType TensorTypeAndShapeInfoImpl::GetElementType() const { + ONNXTensorElementDataType out; + ThrowOnError(GetApi().GetTensorElementType(this->p_, &out)); + return out; +} + +template +inline size_t TensorTypeAndShapeInfoImpl::GetElementCount() const { + size_t out; + ThrowOnError(GetApi().GetTensorShapeElementCount(this->p_, &out)); + return static_cast(out); +} + +template +inline size_t TensorTypeAndShapeInfoImpl::GetDimensionsCount() const { + size_t out; + ThrowOnError(GetApi().GetDimensionsCount(this->p_, &out)); + return out; +} + +template +inline void TensorTypeAndShapeInfoImpl::GetDimensions(int64_t* values, size_t values_count) const { + ThrowOnError(GetApi().GetDimensions(this->p_, values, values_count)); +} + +template +inline void TensorTypeAndShapeInfoImpl::GetSymbolicDimensions(const char** values, size_t values_count) const { + ThrowOnError(GetApi().GetSymbolicDimensions(this->p_, values, values_count)); +} + +template +inline std::vector TensorTypeAndShapeInfoImpl::GetShape() const { + std::vector out(GetDimensionsCount(), 0); + ThrowOnError(GetApi().GetDimensions(this->p_, out.data(), out.size())); + return out; +} + +template +inline ConstTensorTypeAndShapeInfo TypeInfoImpl::GetTensorTypeAndShapeInfo() const { + const OrtTensorTypeAndShapeInfo* out; + ThrowOnError(GetApi().CastTypeInfoToTensorInfo(this->p_, &out)); + return ConstTensorTypeAndShapeInfo{out}; +} + +template +inline ConstSequenceTypeInfo TypeInfoImpl::GetSequenceTypeInfo() const { + const OrtSequenceTypeInfo* out; + ThrowOnError(GetApi().CastTypeInfoToSequenceTypeInfo(this->p_, &out)); + return ConstSequenceTypeInfo{out}; +} + +template +inline ConstMapTypeInfo TypeInfoImpl::GetMapTypeInfo() const { + const OrtMapTypeInfo* out; + ThrowOnError(GetApi().CastTypeInfoToMapTypeInfo(this->p_, &out)); + return ConstMapTypeInfo{out}; +} + +template +inline ONNXType TypeInfoImpl::GetONNXType() const { + ONNXType out; + ThrowOnError(GetApi().GetOnnxTypeFromTypeInfo(this->p_, &out)); + return out; +} + +template +inline TypeInfo SequenceTypeInfoImpl::GetSequenceElementType() const { + OrtTypeInfo* output; + ThrowOnError(GetApi().GetSequenceElementType(this->p_, &output)); + return TypeInfo{output}; +} + +template +inline TypeInfo OptionalTypeInfoImpl::GetOptionalElementType() const { + OrtTypeInfo* info; + ThrowOnError(GetApi().GetOptionalContainedTypeInfo(this->p_, &info)); + return TypeInfo{info}; +} + +template +inline ONNXTensorElementDataType MapTypeInfoImpl::GetMapKeyType() const { + ONNXTensorElementDataType out; + ThrowOnError(GetApi().GetMapKeyType(this->p_, &out)); + return out; +} + +template +inline TypeInfo MapTypeInfoImpl::GetMapValueType() const { + OrtTypeInfo* output; + ThrowOnError(GetApi().GetMapValueType(this->p_, &output)); + return TypeInfo{output}; +} + +template +inline ConstOptionalTypeInfo TypeInfoImpl::GetOptionalTypeInfo() const { + const OrtOptionalTypeInfo* info; + ThrowOnError(GetApi().CastTypeInfoToOptionalTypeInfo(this->p_, &info)); + return ConstOptionalTypeInfo{info}; +} + +} // namespace detail + +namespace detail { + +template +template +inline void ConstValueImpl::GetOpaqueData(const char* domain, const char* type_name, R& out) const { + ThrowOnError(GetApi().GetOpaqueValue(domain, type_name, this->p_, &out, sizeof(R))); +} + +template +inline bool ConstValueImpl::IsTensor() const { + int out; + ThrowOnError(GetApi().IsTensor(this->p_, &out)); + return out != 0; +} + +template +inline bool ConstValueImpl::HasValue() const { + int out; + ThrowOnError(GetApi().HasValue(this->p_, &out)); + return out != 0; +} + +template +inline size_t ConstValueImpl::GetCount() const { + size_t out; + ThrowOnError(GetApi().GetValueCount(this->p_, &out)); + return out; +} + +template +inline Value ConstValueImpl::GetValue(int index, OrtAllocator* allocator) const { + OrtValue* out; + ThrowOnError(GetApi().GetValue(this->p_, index, allocator, &out)); + return Value{out}; +} + +template +inline size_t ConstValueImpl::GetStringTensorDataLength() const { + size_t out; + ThrowOnError(GetApi().GetStringTensorDataLength(this->p_, &out)); + return out; +} + +template +inline size_t ConstValueImpl::GetStringTensorElementLength(size_t element_index) const { + size_t out; + ThrowOnError(GetApi().GetStringTensorElementLength(this->p_, element_index, &out)); + return out; +} + +template +template +inline const R* ConstValueImpl::GetTensorData() const { + R* out; + ThrowOnError(GetApi().GetTensorMutableData(const_cast(this->p_), (void**)&out)); + return out; +} + +template +inline const void* ConstValueImpl::GetTensorRawData() const { + void* out; + ThrowOnError(GetApi().GetTensorMutableData(const_cast(this->p_), &out)); + return out; +} + +template +inline TypeInfo ConstValueImpl::GetTypeInfo() const { + OrtTypeInfo* output; + ThrowOnError(GetApi().GetTypeInfo(this->p_, &output)); + return TypeInfo{output}; +} + +template +inline TensorTypeAndShapeInfo ConstValueImpl::GetTensorTypeAndShapeInfo() const { + OrtTensorTypeAndShapeInfo* output; + ThrowOnError(GetApi().GetTensorTypeAndShape(this->p_, &output)); + return TensorTypeAndShapeInfo{output}; +} + +template +inline ConstMemoryInfo ConstValueImpl::GetTensorMemoryInfo() const { + const OrtMemoryInfo* mem_info; + ThrowOnError(GetApi().GetTensorMemoryInfo(this->p_, &mem_info)); + return ConstMemoryInfo(mem_info); +} + +template +inline void ConstValueImpl::GetStringTensorElement(size_t buffer_length, size_t element_index, void* buffer) const { + ThrowOnError(GetApi().GetStringTensorElement(this->p_, buffer_length, element_index, buffer)); +} + +template +inline std::string ConstValueImpl::GetStringTensorElement(size_t element_index) const { + size_t buffer_length; + ThrowOnError(GetApi().GetStringTensorElementLength(this->p_, element_index, &buffer_length)); + + std::string s; + s.resize(buffer_length); + ThrowOnError(GetApi().GetStringTensorElement(this->p_, buffer_length, element_index, &s[0])); + return s; +} + +template +inline void ConstValueImpl::GetStringTensorContent(void* buffer, size_t buffer_length, size_t* offsets, size_t offsets_count) const { + ThrowOnError(GetApi().GetStringTensorContent(this->p_, buffer, buffer_length, offsets, offsets_count)); +} + +#if !defined(DISABLE_SPARSE_TENSORS) +template +inline OrtSparseFormat ConstValueImpl::GetSparseFormat() const { + OrtSparseFormat format; + ThrowOnError(GetApi().GetSparseTensorFormat(this->p_, &format)); + return format; +} + +template +inline TensorTypeAndShapeInfo ConstValueImpl::GetSparseTensorValuesTypeAndShapeInfo() const { + OrtTensorTypeAndShapeInfo* output; + ThrowOnError(GetApi().GetSparseTensorValuesTypeAndShape(this->p_, &output)); + return TensorTypeAndShapeInfo{output}; +} + +template +inline TensorTypeAndShapeInfo ConstValueImpl::GetSparseTensorIndicesTypeShapeInfo(OrtSparseIndicesFormat indices_format) const { + OrtTensorTypeAndShapeInfo* output; + ThrowOnError(GetApi().GetSparseTensorIndicesTypeShape(this->p_, indices_format, &output)); + return TensorTypeAndShapeInfo{output}; +} + +template +template +inline const R* ConstValueImpl::GetSparseTensorIndicesData(OrtSparseIndicesFormat indices_format, size_t& num_indices) const { + const void* out; + ThrowOnError(GetApi().GetSparseTensorIndices(this->p_, indices_format, &num_indices, &out)); + return reinterpret_cast(out); +} + +template +inline bool ConstValueImpl::IsSparseTensor() const { + int out; + ThrowOnError(GetApi().IsSparseTensor(this->p_, &out)); + return out != 0; +} + +template +template +inline const R* ConstValueImpl::GetSparseTensorValues() const { + const void* out; + ThrowOnError(GetApi().GetSparseTensorValues(this->p_, &out)); + return reinterpret_cast(out); +} + +#endif + +template +void ValueImpl::FillStringTensor(const char* const* s, size_t s_len) { + ThrowOnError(GetApi().FillStringTensor(this->p_, s, s_len)); +} + +template +void ValueImpl::FillStringTensorElement(const char* s, size_t index) { + ThrowOnError(GetApi().FillStringTensorElement(this->p_, s, index)); +} + +template +inline char* ValueImpl::GetResizedStringTensorElementBuffer(size_t index, size_t buffer_length) { + char* result; + ThrowOnError(GetApi().GetResizedStringTensorElementBuffer(this->p_, index, buffer_length, &result)); + return result; +} + +template +void* ValueImpl::GetTensorMutableRawData() { + void* out; + ThrowOnError(GetApi().GetTensorMutableData(this->p_, &out)); + return out; +} + +template +template +R* ValueImpl::GetTensorMutableData() { + R* out; + ThrowOnError(GetApi().GetTensorMutableData(this->p_, (void**)&out)); + return out; +} + +template +template +R& ValueImpl::At(const std::vector& location) { + static_assert(!std::is_same::value, "this api does not support std::string"); + R* out; + ThrowOnError(GetApi().TensorAt(this->p_, location.data(), location.size(), (void**)&out)); + return *out; +} + +#if !defined(DISABLE_SPARSE_TENSORS) +template +void ValueImpl::UseCooIndices(int64_t* indices_data, size_t indices_num) { + ThrowOnError(GetApi().UseCooIndices(this->p_, indices_data, indices_num)); +} + +template +void ValueImpl::UseCsrIndices(int64_t* inner_data, size_t inner_num, int64_t* outer_data, size_t outer_num) { + ThrowOnError(GetApi().UseCsrIndices(this->p_, inner_data, inner_num, outer_data, outer_num)); +} + +template +void ValueImpl::UseBlockSparseIndices(const Shape& indices_shape, int32_t* indices_data) { + ThrowOnError(GetApi().UseBlockSparseIndices(this->p_, indices_shape.shape, indices_shape.shape_len, indices_data)); +} + +template +void ValueImpl::FillSparseTensorCoo(const OrtMemoryInfo* mem_info, const OrtSparseValuesParam& values_param, + const int64_t* indices_data, size_t indices_num) { + ThrowOnError(GetApi().FillSparseTensorCoo(this->p_, mem_info, values_param.values_shape, + values_param.values_shape_len, values_param.data.p_data, + indices_data, indices_num)); +} + +template +void ValueImpl::FillSparseTensorCsr(const OrtMemoryInfo* data_mem_info, + const OrtSparseValuesParam& values, + const int64_t* inner_indices_data, size_t inner_indices_num, + const int64_t* outer_indices_data, size_t outer_indices_num) { + ThrowOnError(GetApi().FillSparseTensorCsr(this->p_, data_mem_info, values.values_shape, values.values_shape_len, values.data.p_data, + inner_indices_data, inner_indices_num, + outer_indices_data, outer_indices_num)); +} + +template +void ValueImpl::FillSparseTensorBlockSparse(const OrtMemoryInfo* data_mem_info, + const OrtSparseValuesParam& values, + const Shape& indices_shape, + const int32_t* indices_data) { + ThrowOnError(GetApi().FillSparseTensorBlockSparse(this->p_, data_mem_info, values.values_shape, values.values_shape_len, values.data.p_data, + indices_shape.shape, indices_shape.shape_len, + indices_data)); +} + +#endif // !defined(DISABLE_SPARSE_TENSORS) + +} // namespace detail + +template +inline Value Value::CreateTensor(const OrtMemoryInfo* info, T* p_data, size_t p_data_element_count, const int64_t* shape, size_t shape_len) { + return CreateTensor(info, p_data, p_data_element_count * sizeof(T), shape, shape_len, TypeToTensorType::type); +} + +inline Value Value::CreateTensor(const OrtMemoryInfo* info, void* p_data, size_t p_data_byte_count, const int64_t* shape, size_t shape_len, + ONNXTensorElementDataType type) { + OrtValue* out; + ThrowOnError(GetApi().CreateTensorWithDataAsOrtValue(info, p_data, p_data_byte_count, shape, shape_len, type, &out)); + return Value{out}; +} + +template +inline Value Value::CreateTensor(OrtAllocator* allocator, const int64_t* shape, size_t shape_len) { + return CreateTensor(allocator, shape, shape_len, TypeToTensorType::type); +} + +inline Value Value::CreateTensor(OrtAllocator* allocator, const int64_t* shape, size_t shape_len, ONNXTensorElementDataType type) { + OrtValue* out; + ThrowOnError(GetApi().CreateTensorAsOrtValue(allocator, shape, shape_len, type, &out)); + return Value{out}; +} + +#if !defined(DISABLE_SPARSE_TENSORS) + +template +inline Value Value::CreateSparseTensor(const OrtMemoryInfo* info, T* p_data, const Shape& dense_shape, + const Shape& values_shape) { + return CreateSparseTensor(info, p_data, dense_shape, values_shape, TypeToTensorType::type); +} + +inline Value Value::CreateSparseTensor(const OrtMemoryInfo* info, void* p_data, const Shape& dense_shape, + const Shape& values_shape, ONNXTensorElementDataType type) { + OrtValue* out; + ThrowOnError(GetApi().CreateSparseTensorWithValuesAsOrtValue(info, p_data, dense_shape.shape, dense_shape.shape_len, + values_shape.shape, values_shape.shape_len, type, &out)); + return Value{out}; +} + +template +inline Value Value::CreateSparseTensor(OrtAllocator* allocator, const Shape& dense_shape) { + return CreateSparseTensor(allocator, dense_shape, TypeToTensorType::type); +} + +inline Value Value::CreateSparseTensor(OrtAllocator* allocator, const Shape& dense_shape, + ONNXTensorElementDataType type) { + OrtValue* out; + ThrowOnError(GetApi().CreateSparseTensorAsOrtValue(allocator, dense_shape.shape, dense_shape.shape_len, type, &out)); + return Value{out}; +} +#endif // !defined(DISABLE_SPARSE_TENSORS) + +inline Value Value::CreateMap(const Value& keys, const Value& values) { + OrtValue* out; + const OrtValue* inputs[2] = {keys, values}; + ThrowOnError(GetApi().CreateValue(inputs, 2, ONNX_TYPE_MAP, &out)); + return Value{out}; +} + +inline Value Value::CreateSequence(const std::vector& values) { + OrtValue* out; + std::vector values_ort{values.data(), values.data() + values.size()}; + ThrowOnError(GetApi().CreateValue(values_ort.data(), values_ort.size(), ONNX_TYPE_SEQUENCE, &out)); + return Value{out}; +} + +template +inline Value Value::CreateOpaque(const char* domain, const char* type_name, const T& data_container) { + OrtValue* out; + ThrowOnError(GetApi().CreateOpaqueValue(domain, type_name, &data_container, sizeof(T), &out)); + return Value{out}; +} + +// +// Custom OP Inlines +// +inline Logger::Logger(const OrtLogger* logger) : logger_(logger) { + Ort::ThrowOnError(GetApi().Logger_GetLoggingSeverityLevel(this->logger_, &this->cached_severity_level_)); +} + +inline OrtLoggingLevel Logger::GetLoggingSeverityLevel() const noexcept { + return cached_severity_level_; +} + +inline Status Logger::LogMessage(OrtLoggingLevel log_severity_level, const ORTCHAR_T* file_path, int line_number, + const char* func_name, const char* message) const noexcept { + OrtStatus* status = GetApi().Logger_LogMessage(logger_, log_severity_level, message, file_path, line_number, + func_name); + return Status{status}; +} + +// Disable warnings about the format string not being a literal (-Wformat-nonliteral and -Wformat-security) +// for gcc and clang. The alternative is to use actual C-style variadic parameters and apply +// __attribute__(format(printf...)), which does not work with variadic templates. +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +#pragma GCC diagnostic ignored "-Wformat-security" +#elif defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" +#pragma clang diagnostic ignored "-Wformat-security" +#endif +template +inline Status Logger::LogFormattedMessage(OrtLoggingLevel log_severity_level, const ORTCHAR_T* file_path, + int line_number, const char* func_name, const char* format, + Args&&... args) const noexcept { + int msg_len = std::snprintf(nullptr, 0U, format, std::forward(args)...); + + if (msg_len < 0) { // Formatting error + return Status("Failed to log message due to formatting error", OrtErrorCode::ORT_FAIL); + } + + OrtStatus* status = nullptr; + const size_t buffer_size = static_cast(msg_len) + 1U; + + constexpr size_t kStackBufferSize = 1024; + + if (buffer_size < kStackBufferSize) { + char buffer[kStackBufferSize]; + snprintf(buffer, kStackBufferSize, format, std::forward(args)...); + status = GetApi().Logger_LogMessage(logger_, log_severity_level, buffer, file_path, line_number, func_name); + } else { + // std::make_unique is only supported starting at C++14. +#if (__cplusplus >= 201402L) || (_MSC_VER >= 1900) + auto buffer = std::make_unique(buffer_size); +#else + std::unique_ptr buffer(new char[buffer_size]); +#endif + std::snprintf(buffer.get(), buffer_size, format, std::forward(args)...); + status = GetApi().Logger_LogMessage(logger_, log_severity_level, buffer.get(), file_path, line_number, func_name); + } + + return Status{status}; +} +// Re-enable -Wformat-nonliteral and -Wformat-security +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#elif defined(__clang__) +#pragma clang diagnostic pop +#endif + +inline KernelContext::KernelContext(OrtKernelContext* context) : ctx_(context) { +} + +inline size_t KernelContext::GetInputCount() const { + size_t out = 0; + Ort::ThrowOnError(GetApi().KernelContext_GetInputCount(ctx_, &out)); + return out; +} + +inline size_t KernelContext::GetOutputCount() const { + size_t out = 0; + Ort::ThrowOnError(GetApi().KernelContext_GetOutputCount(ctx_, &out)); + return out; +} + +inline ConstValue KernelContext::GetInput(size_t index) const { + const OrtValue* out = nullptr; + Ort::ThrowOnError(GetApi().KernelContext_GetInput(ctx_, index, &out)); + return ConstValue{out}; +} + +inline UnownedValue KernelContext::GetOutput(size_t index, const int64_t* dim_values, size_t dim_count) const { + OrtValue* out = nullptr; + Ort::ThrowOnError(GetApi().KernelContext_GetOutput(ctx_, index, dim_values, dim_count, &out)); + return UnownedValue(out); +} + +inline UnownedValue KernelContext::GetOutput(size_t index, const std::vector& dims) const { + OrtValue* out = nullptr; + Ort::ThrowOnError(GetApi().KernelContext_GetOutput(ctx_, index, dims.data(), dims.size(), &out)); + return UnownedValue(out); +} + +inline void* KernelContext::GetGPUComputeStream() const { + void* out = nullptr; + Ort::ThrowOnError(GetApi().KernelContext_GetGPUComputeStream(ctx_, &out)); + return out; +} + +inline OrtAllocator* KernelContext::GetAllocator(const OrtMemoryInfo& memory_info) const { + OrtAllocator* out = nullptr; + Ort::ThrowOnError(GetApi().KernelContext_GetAllocator(ctx_, &memory_info, &out)); + return out; +} + +inline Logger KernelContext::GetLogger() const { + const OrtLogger* out = nullptr; + ThrowOnError(GetApi().KernelContext_GetLogger(this->ctx_, &out)); + return Logger{out}; +} + +inline OpAttr::OpAttr(const char* name, const void* data, int len, OrtOpAttrType type) { + Ort::ThrowOnError(GetApi().CreateOpAttr(name, data, len, type, &p_)); +} + +namespace detail { +template +inline KernelInfo KernelInfoImpl::Copy() const { + OrtKernelInfo* info_copy = nullptr; + Ort::ThrowOnError(GetApi().CopyKernelInfo(this->p_, &info_copy)); + return KernelInfo{info_copy}; +} + +template +inline size_t KernelInfoImpl::GetInputCount() const { + size_t out = 0; + ThrowOnError(GetApi().KernelInfo_GetInputCount(this->p_, &out)); + return out; +} + +template +inline size_t KernelInfoImpl::GetOutputCount() const { + size_t out = 0; + ThrowOnError(GetApi().KernelInfo_GetOutputCount(this->p_, &out)); + return out; +} + +template +inline std::string KernelInfoImpl::GetInputName(size_t index) const { + size_t size = 0; + + // Feed nullptr for the data buffer to query the true size of the string value + Ort::ThrowOnError(GetApi().KernelInfo_GetInputName(this->p_, index, nullptr, &size)); + + std::string out; + out.resize(size); + Ort::ThrowOnError(GetApi().KernelInfo_GetInputName(this->p_, index, &out[0], &size)); + out.resize(size - 1); // remove the terminating character '\0' + + return out; +} + +template +inline std::string KernelInfoImpl::GetOutputName(size_t index) const { + size_t size = 0; + + // Feed nullptr for the data buffer to query the true size of the string value + Ort::ThrowOnError(GetApi().KernelInfo_GetOutputName(this->p_, index, nullptr, &size)); + + std::string out; + out.resize(size); + Ort::ThrowOnError(GetApi().KernelInfo_GetOutputName(this->p_, index, &out[0], &size)); + out.resize(size - 1); // remove the terminating character '\0' + + return out; +} + +template +inline TypeInfo KernelInfoImpl::GetInputTypeInfo(size_t index) const { + OrtTypeInfo* out = nullptr; + ThrowOnError(GetApi().KernelInfo_GetInputTypeInfo(this->p_, index, &out)); + return TypeInfo{out}; +} + +template +inline TypeInfo KernelInfoImpl::GetOutputTypeInfo(size_t index) const { + OrtTypeInfo* out = nullptr; + ThrowOnError(GetApi().KernelInfo_GetOutputTypeInfo(this->p_, index, &out)); + return TypeInfo{out}; +} + +template +inline Value KernelInfoImpl::GetTensorAttribute(const char* name, OrtAllocator* allocator) const { + OrtValue* out = nullptr; + ThrowOnError(GetApi().KernelInfoGetAttribute_tensor(this->p_, name, allocator, &out)); + return Value{out}; +} + +template +inline ConstValue KernelInfoImpl::GetTensorConstantInput(size_t index, int* is_constant) const { + const OrtValue* out = nullptr; + ThrowOnError(GetApi().KernelInfoGetConstantInput_tensor(this->p_, index, is_constant, &out)); + return ConstValue{out}; +} + +template +inline std::string KernelInfoImpl::GetNodeName() const { + size_t size = 0; + + // Feed nullptr for the data buffer to query the true size of the string value + Ort::ThrowOnError(GetApi().KernelInfo_GetNodeName(this->p_, nullptr, &size)); + + std::string out; + out.resize(size); + Ort::ThrowOnError(GetApi().KernelInfo_GetNodeName(this->p_, &out[0], &size)); + out.resize(size - 1); // remove the terminating character '\0' + + return out; +} + +template +inline Logger KernelInfoImpl::GetLogger() const { + const OrtLogger* out = nullptr; + ThrowOnError(GetApi().KernelInfo_GetLogger(this->p_, &out)); + return Logger{out}; +} + +inline void attr_utils::GetAttr(const OrtKernelInfo* p, const char* name, float& out) { + Ort::ThrowOnError(GetApi().KernelInfoGetAttribute_float(p, name, &out)); +} + +inline void attr_utils::GetAttr(const OrtKernelInfo* p, const char* name, int64_t& out) { + Ort::ThrowOnError(GetApi().KernelInfoGetAttribute_int64(p, name, &out)); +} + +inline void attr_utils::GetAttr(const OrtKernelInfo* p, const char* name, std::string& result) { + size_t size = 0; + // Feed nullptr for the data buffer to query the true size of the string attribute + Ort::ThrowOnError(GetApi().KernelInfoGetAttribute_string(p, name, nullptr, &size)); + + std::string out; + out.resize(size); + Ort::ThrowOnError(GetApi().KernelInfoGetAttribute_string(p, name, &out[0], &size)); + out.resize(size - 1); // remove the terminating character '\0' + out.swap(result); +} + +inline void attr_utils::GetAttrs(const OrtKernelInfo* p, const char* name, std::vector& result) { + size_t size = 0; + // Feed nullptr for the data buffer to query the true size of the attribute + Ort::ThrowOnError(GetApi().KernelInfoGetAttributeArray_float(p, name, nullptr, &size)); + + std::vector out; + out.resize(size); + Ort::ThrowOnError(GetApi().KernelInfoGetAttributeArray_float(p, name, out.data(), &size)); + out.swap(result); +} + +inline void attr_utils::GetAttrs(const OrtKernelInfo* p, const char* name, std::vector& result) { + size_t size = 0; + + // Feed nullptr for the data buffer to query the true size of the attribute + Ort::ThrowOnError(GetApi().KernelInfoGetAttributeArray_int64(p, name, nullptr, &size)); + + std::vector out; + out.resize(size); + Ort::ThrowOnError(GetApi().KernelInfoGetAttributeArray_int64(p, name, out.data(), &size)); + out.swap(result); +} +} // namespace detail + +inline KernelInfo::KernelInfo(OrtKernelInfo* info) : detail::KernelInfoImpl{info} {} + +inline Op::Op(OrtOp* p) : Base(p) {} + +inline Op Op::Create(const OrtKernelInfo* info, const char* op_name, const char* domain, int version, + const char** type_constraint_names, + const ONNXTensorElementDataType* type_constraint_values, + size_t type_constraint_count, + const OpAttr* attr_values, size_t attr_count, + size_t input_count, size_t output_count) { + static_assert(sizeof(OpAttr) == sizeof(OrtOpAttr*), + "OpAttr's is expected to be just an array of OrtOpAttr in memory so we can reinterpret safely"); + auto attr_input_values = reinterpret_cast(attr_values); + OrtOp* op; + Ort::ThrowOnError(GetApi().CreateOp(info, op_name, domain, version, type_constraint_names, type_constraint_values, + static_cast(type_constraint_count), + attr_input_values, + static_cast(attr_count), + static_cast(input_count), + static_cast(output_count), &op)); + return Op{op}; +} + +inline void Op::Invoke(const OrtKernelContext* context, + const Value* input_values, + size_t input_count, + Value* output_values, + size_t output_count) { + static_assert(sizeof(Value) == sizeof(OrtValue*), + "Value is really just an array of OrtValue* in memory, so we can reinterpret_cast safely"); + auto ort_input_values = reinterpret_cast(input_values); + auto ort_output_values = reinterpret_cast(output_values); + Ort::ThrowOnError(GetApi().InvokeOp(context, p_, ort_input_values, static_cast(input_count), + ort_output_values, static_cast(output_count))); +} + +inline void Op::Invoke(const OrtKernelContext* context, + const OrtValue* const* input_values, + size_t input_count, + OrtValue* const* output_values, + size_t output_count) { + Ort::ThrowOnError(GetApi().InvokeOp(context, p_, input_values, static_cast(input_count), + output_values, static_cast(output_count))); +} + +inline std::string GetVersionString() { + return OrtGetApiBase()->GetVersionString(); +} + +inline std::string GetBuildInfoString() { + return GetApi().GetBuildInfoString(); +} + +inline std::vector GetAvailableProviders() { + char** providers; + int len; + + auto release_fn = [&len](char** providers) { + // This should always return nullptr. + ThrowOnError(GetApi().ReleaseAvailableProviders(providers, len)); + }; + + ThrowOnError(GetApi().GetAvailableProviders(&providers, &len)); + std::unique_ptr guard(providers, release_fn); + std::vector available_providers; + available_providers.reserve(static_cast(len)); + for (int i = 0; i < len; ++i) { + available_providers.emplace_back(providers[i]); + } + return available_providers; +} + +template +void CustomOpBase::GetSessionConfigs(std::unordered_map& out, + ConstSessionOptions options) const { + const TOp* derived = static_cast(this); + std::vector keys = derived->GetSessionConfigKeys(); + + out.reserve(keys.size()); + + std::string config_entry_key = detail::MakeCustomOpConfigEntryKey(derived->GetName(), ""); + const size_t prefix_size = config_entry_key.length(); + + for (const auto& key : keys) { + config_entry_key.resize(prefix_size); + config_entry_key.append(key); + out[key] = options.GetConfigEntryOrDefault(config_entry_key.c_str(), ""); + } +} + +} // namespace Ort diff --git a/duix-sdk/src/main/cpp/third/arm/include/onnx/onnxruntime_float16.h b/duix-sdk/src/main/cpp/third/arm/include/onnx/onnxruntime_float16.h new file mode 100644 index 0000000..0b066a9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/onnx/onnxruntime_float16.h @@ -0,0 +1,540 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include +#include + +namespace onnxruntime_float16 { + +namespace detail { + +enum class endian { +#if defined(_WIN32) + little = 0, + big = 1, + native = little, +#elif defined(__GNUC__) || defined(__clang__) + little = __ORDER_LITTLE_ENDIAN__, + big = __ORDER_BIG_ENDIAN__, + native = __BYTE_ORDER__, +#else +#error onnxruntime_float16::detail::endian is not implemented in this environment. +#endif +}; + +static_assert( + endian::native == endian::little || endian::native == endian::big, + "Only little-endian or big-endian native byte orders are supported."); + +} // namespace detail + +/// +/// Shared implementation between public and internal classes. CRTP pattern. +/// +template +struct Float16Impl { + protected: + /// + /// Converts from float to uint16_t float16 representation + /// + /// + /// + constexpr static uint16_t ToUint16Impl(float v) noexcept; + + /// + /// Converts float16 to float + /// + /// float representation of float16 value + float ToFloatImpl() const noexcept; + + /// + /// Creates an instance that represents absolute value. + /// + /// Absolute value + uint16_t AbsImpl() const noexcept { + return static_cast(val & ~kSignMask); + } + + /// + /// Creates a new instance with the sign flipped. + /// + /// Flipped sign instance + uint16_t NegateImpl() const noexcept { + return IsNaN() ? val : static_cast(val ^ kSignMask); + } + + public: + // uint16_t special values + static constexpr uint16_t kSignMask = 0x8000U; + static constexpr uint16_t kBiasedExponentMask = 0x7C00U; + static constexpr uint16_t kPositiveInfinityBits = 0x7C00U; + static constexpr uint16_t kNegativeInfinityBits = 0xFC00U; + static constexpr uint16_t kPositiveQNaNBits = 0x7E00U; + static constexpr uint16_t kNegativeQNaNBits = 0xFE00U; + static constexpr uint16_t kEpsilonBits = 0x4170U; + static constexpr uint16_t kMinValueBits = 0xFBFFU; // Minimum normal number + static constexpr uint16_t kMaxValueBits = 0x7BFFU; // Largest normal number + static constexpr uint16_t kOneBits = 0x3C00U; + static constexpr uint16_t kMinusOneBits = 0xBC00U; + + uint16_t val{0}; + + Float16Impl() = default; + + /// + /// Checks if the value is negative + /// + /// true if negative + bool IsNegative() const noexcept { + return static_cast(val) < 0; + } + + /// + /// Tests if the value is NaN + /// + /// true if NaN + bool IsNaN() const noexcept { + return AbsImpl() > kPositiveInfinityBits; + } + + /// + /// Tests if the value is finite + /// + /// true if finite + bool IsFinite() const noexcept { + return AbsImpl() < kPositiveInfinityBits; + } + + /// + /// Tests if the value represents positive infinity. + /// + /// true if positive infinity + bool IsPositiveInfinity() const noexcept { + return val == kPositiveInfinityBits; + } + + /// + /// Tests if the value represents negative infinity + /// + /// true if negative infinity + bool IsNegativeInfinity() const noexcept { + return val == kNegativeInfinityBits; + } + + /// + /// Tests if the value is either positive or negative infinity. + /// + /// True if absolute value is infinity + bool IsInfinity() const noexcept { + return AbsImpl() == kPositiveInfinityBits; + } + + /// + /// Tests if the value is NaN or zero. Useful for comparisons. + /// + /// True if NaN or zero. + bool IsNaNOrZero() const noexcept { + auto abs = AbsImpl(); + return (abs == 0 || abs > kPositiveInfinityBits); + } + + /// + /// Tests if the value is normal (not zero, subnormal, infinite, or NaN). + /// + /// True if so + bool IsNormal() const noexcept { + auto abs = AbsImpl(); + return (abs < kPositiveInfinityBits) // is finite + && (abs != 0) // is not zero + && ((abs & kBiasedExponentMask) != 0); // is not subnormal (has a non-zero exponent) + } + + /// + /// Tests if the value is subnormal (denormal). + /// + /// True if so + bool IsSubnormal() const noexcept { + auto abs = AbsImpl(); + return (abs < kPositiveInfinityBits) // is finite + && (abs != 0) // is not zero + && ((abs & kBiasedExponentMask) == 0); // is subnormal (has a zero exponent) + } + + /// + /// Creates an instance that represents absolute value. + /// + /// Absolute value + Derived Abs() const noexcept { return Derived::FromBits(AbsImpl()); } + + /// + /// Creates a new instance with the sign flipped. + /// + /// Flipped sign instance + Derived Negate() const noexcept { return Derived::FromBits(NegateImpl()); } + + /// + /// IEEE defines that positive and negative zero are equal, this gives us a quick equality check + /// for two values by or'ing the private bits together and stripping the sign. They are both zero, + /// and therefore equivalent, if the resulting value is still zero. + /// + /// first value + /// second value + /// True if both arguments represent zero + static bool AreZero(const Float16Impl& lhs, const Float16Impl& rhs) noexcept { + return static_cast((lhs.val | rhs.val) & ~kSignMask) == 0; + } + + bool operator==(const Float16Impl& rhs) const noexcept { + if (IsNaN() || rhs.IsNaN()) { + // IEEE defines that NaN is not equal to anything, including itself. + return false; + } + return val == rhs.val; + } + + bool operator!=(const Float16Impl& rhs) const noexcept { return !(*this == rhs); } + + bool operator<(const Float16Impl& rhs) const noexcept { + if (IsNaN() || rhs.IsNaN()) { + // IEEE defines that NaN is unordered with respect to everything, including itself. + return false; + } + + const bool left_is_negative = IsNegative(); + if (left_is_negative != rhs.IsNegative()) { + // When the signs of left and right differ, we know that left is less than right if it is + // the negative value. The exception to this is if both values are zero, in which case IEEE + // says they should be equal, even if the signs differ. + return left_is_negative && !AreZero(*this, rhs); + } + return (val != rhs.val) && ((val < rhs.val) ^ left_is_negative); + } +}; + +// The following Float16_t conversions are based on the code from +// Eigen library. + +// The conversion routines are Copyright (c) Fabian Giesen, 2016. +// The original license follows: +// +// Copyright (c) Fabian Giesen, 2016 +// All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted. +// 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. + +namespace detail { +union float32_bits { + unsigned int u; + float f; +}; +} // namespace detail + +template +inline constexpr uint16_t Float16Impl::ToUint16Impl(float v) noexcept { + detail::float32_bits f{}; + f.f = v; + + constexpr detail::float32_bits f32infty = {255 << 23}; + constexpr detail::float32_bits f16max = {(127 + 16) << 23}; + constexpr detail::float32_bits denorm_magic = {((127 - 15) + (23 - 10) + 1) << 23}; + constexpr unsigned int sign_mask = 0x80000000u; + uint16_t val = static_cast(0x0u); + + unsigned int sign = f.u & sign_mask; + f.u ^= sign; + + // NOTE all the integer compares in this function can be safely + // compiled into signed compares since all operands are below + // 0x80000000. Important if you want fast straight SSE2 code + // (since there's no unsigned PCMPGTD). + + if (f.u >= f16max.u) { // result is Inf or NaN (all exponent bits set) + val = (f.u > f32infty.u) ? 0x7e00 : 0x7c00; // NaN->qNaN and Inf->Inf + } else { // (De)normalized number or zero + if (f.u < (113 << 23)) { // resulting FP16 is subnormal or zero + // use a magic value to align our 10 mantissa bits at the bottom of + // the float. as long as FP addition is round-to-nearest-even this + // just works. + f.f += denorm_magic.f; + + // and one integer subtract of the bias later, we have our final float! + val = static_cast(f.u - denorm_magic.u); + } else { + unsigned int mant_odd = (f.u >> 13) & 1; // resulting mantissa is odd + + // update exponent, rounding bias part 1 + // Equivalent to `f.u += ((unsigned int)(15 - 127) << 23) + 0xfff`, but + // without arithmetic overflow. + f.u += 0xc8000fffU; + // rounding bias part 2 + f.u += mant_odd; + // take the bits! + val = static_cast(f.u >> 13); + } + } + + val |= static_cast(sign >> 16); + return val; +} + +template +inline float Float16Impl::ToFloatImpl() const noexcept { + constexpr detail::float32_bits magic = {113 << 23}; + constexpr unsigned int shifted_exp = 0x7c00 << 13; // exponent mask after shift + detail::float32_bits o{}; + + o.u = (val & 0x7fff) << 13; // exponent/mantissa bits + unsigned int exp = shifted_exp & o.u; // just the exponent + o.u += (127 - 15) << 23; // exponent adjust + + // handle exponent special cases + if (exp == shifted_exp) { // Inf/NaN? + o.u += (128 - 16) << 23; // extra exp adjust + } else if (exp == 0) { // Zero/Denormal? + o.u += 1 << 23; // extra exp adjust + o.f -= magic.f; // re-normalize + } + + // Attempt to workaround the Internal Compiler Error on ARM64 + // for bitwise | operator, including std::bitset +#if (defined _MSC_VER) && (defined _M_ARM || defined _M_ARM64 || defined _M_ARM64EC) + if (IsNegative()) { + return -o.f; + } +#else + // original code: + o.u |= (val & 0x8000U) << 16U; // sign bit +#endif + return o.f; +} + +/// Shared implementation between public and internal classes. CRTP pattern. +template +struct BFloat16Impl { + protected: + /// + /// Converts from float to uint16_t float16 representation + /// + /// + /// + static uint16_t ToUint16Impl(float v) noexcept; + + /// + /// Converts bfloat16 to float + /// + /// float representation of bfloat16 value + float ToFloatImpl() const noexcept; + + /// + /// Creates an instance that represents absolute value. + /// + /// Absolute value + uint16_t AbsImpl() const noexcept { + return static_cast(val & ~kSignMask); + } + + /// + /// Creates a new instance with the sign flipped. + /// + /// Flipped sign instance + uint16_t NegateImpl() const noexcept { + return IsNaN() ? val : static_cast(val ^ kSignMask); + } + + public: + // uint16_t special values + static constexpr uint16_t kSignMask = 0x8000U; + static constexpr uint16_t kBiasedExponentMask = 0x7F80U; + static constexpr uint16_t kPositiveInfinityBits = 0x7F80U; + static constexpr uint16_t kNegativeInfinityBits = 0xFF80U; + static constexpr uint16_t kPositiveQNaNBits = 0x7FC1U; + static constexpr uint16_t kNegativeQNaNBits = 0xFFC1U; + static constexpr uint16_t kSignaling_NaNBits = 0x7F80U; + static constexpr uint16_t kEpsilonBits = 0x0080U; + static constexpr uint16_t kMinValueBits = 0xFF7FU; + static constexpr uint16_t kMaxValueBits = 0x7F7FU; + static constexpr uint16_t kRoundToNearest = 0x7FFFU; + static constexpr uint16_t kOneBits = 0x3F80U; + static constexpr uint16_t kMinusOneBits = 0xBF80U; + + uint16_t val{0}; + + BFloat16Impl() = default; + + /// + /// Checks if the value is negative + /// + /// true if negative + bool IsNegative() const noexcept { + return static_cast(val) < 0; + } + + /// + /// Tests if the value is NaN + /// + /// true if NaN + bool IsNaN() const noexcept { + return AbsImpl() > kPositiveInfinityBits; + } + + /// + /// Tests if the value is finite + /// + /// true if finite + bool IsFinite() const noexcept { + return AbsImpl() < kPositiveInfinityBits; + } + + /// + /// Tests if the value represents positive infinity. + /// + /// true if positive infinity + bool IsPositiveInfinity() const noexcept { + return val == kPositiveInfinityBits; + } + + /// + /// Tests if the value represents negative infinity + /// + /// true if negative infinity + bool IsNegativeInfinity() const noexcept { + return val == kNegativeInfinityBits; + } + + /// + /// Tests if the value is either positive or negative infinity. + /// + /// True if absolute value is infinity + bool IsInfinity() const noexcept { + return AbsImpl() == kPositiveInfinityBits; + } + + /// + /// Tests if the value is NaN or zero. Useful for comparisons. + /// + /// True if NaN or zero. + bool IsNaNOrZero() const noexcept { + auto abs = AbsImpl(); + return (abs == 0 || abs > kPositiveInfinityBits); + } + + /// + /// Tests if the value is normal (not zero, subnormal, infinite, or NaN). + /// + /// True if so + bool IsNormal() const noexcept { + auto abs = AbsImpl(); + return (abs < kPositiveInfinityBits) // is finite + && (abs != 0) // is not zero + && ((abs & kBiasedExponentMask) != 0); // is not subnormal (has a non-zero exponent) + } + + /// + /// Tests if the value is subnormal (denormal). + /// + /// True if so + bool IsSubnormal() const noexcept { + auto abs = AbsImpl(); + return (abs < kPositiveInfinityBits) // is finite + && (abs != 0) // is not zero + && ((abs & kBiasedExponentMask) == 0); // is subnormal (has a zero exponent) + } + + /// + /// Creates an instance that represents absolute value. + /// + /// Absolute value + Derived Abs() const noexcept { return Derived::FromBits(AbsImpl()); } + + /// + /// Creates a new instance with the sign flipped. + /// + /// Flipped sign instance + Derived Negate() const noexcept { return Derived::FromBits(NegateImpl()); } + + /// + /// IEEE defines that positive and negative zero are equal, this gives us a quick equality check + /// for two values by or'ing the private bits together and stripping the sign. They are both zero, + /// and therefore equivalent, if the resulting value is still zero. + /// + /// first value + /// second value + /// True if both arguments represent zero + static bool AreZero(const BFloat16Impl& lhs, const BFloat16Impl& rhs) noexcept { + // IEEE defines that positive and negative zero are equal, this gives us a quick equality check + // for two values by or'ing the private bits together and stripping the sign. They are both zero, + // and therefore equivalent, if the resulting value is still zero. + return static_cast((lhs.val | rhs.val) & ~kSignMask) == 0; + } +}; + +template +inline uint16_t BFloat16Impl::ToUint16Impl(float v) noexcept { + uint16_t result; + if (std::isnan(v)) { + result = kPositiveQNaNBits; + } else { + auto get_msb_half = [](float fl) { + uint16_t result; +#ifdef __cpp_if_constexpr + if constexpr (detail::endian::native == detail::endian::little) { +#else + if (detail::endian::native == detail::endian::little) { +#endif + std::memcpy(&result, reinterpret_cast(&fl) + sizeof(uint16_t), sizeof(uint16_t)); + } else { + std::memcpy(&result, &fl, sizeof(uint16_t)); + } + return result; + }; + + uint16_t upper_bits = get_msb_half(v); + union { + uint32_t U32; + float F32; + }; + F32 = v; + U32 += (upper_bits & 1) + kRoundToNearest; + result = get_msb_half(F32); + } + return result; +} + +template +inline float BFloat16Impl::ToFloatImpl() const noexcept { + if (IsNaN()) { + return std::numeric_limits::quiet_NaN(); + } + float result; + char* const first = reinterpret_cast(&result); + char* const second = first + sizeof(uint16_t); +#ifdef __cpp_if_constexpr + if constexpr (detail::endian::native == detail::endian::little) { +#else + if (detail::endian::native == detail::endian::little) { +#endif + std::memset(first, 0, sizeof(uint16_t)); + std::memcpy(second, &val, sizeof(uint16_t)); + } else { + std::memcpy(first, &val, sizeof(uint16_t)); + std::memset(second, 0, sizeof(uint16_t)); + } + return result; +} + +} // namespace onnxruntime_float16 diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core.hpp new file mode 100644 index 0000000..f7807e3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core.hpp @@ -0,0 +1,3354 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2015, Intel Corporation, all rights reserved. +// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. +// Copyright (C) 2015, OpenCV Foundation, all rights reserved. +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_HPP +#define OPENCV_CORE_HPP + +#ifndef __cplusplus +# error core.hpp header must be compiled as C++ +#endif + +#include "opencv2/core/cvdef.h" +#include "opencv2/core/base.hpp" +#include "opencv2/core/cvstd.hpp" +#include "opencv2/core/traits.hpp" +#include "opencv2/core/matx.hpp" +#include "opencv2/core/types.hpp" +#include "opencv2/core/mat.hpp" +#include "opencv2/core/persistence.hpp" + +/** +@defgroup core Core functionality +@{ + @defgroup core_basic Basic structures + @defgroup core_c C structures and operations + @{ + @defgroup core_c_glue Connections with C++ + @} + @defgroup core_array Operations on arrays + @defgroup core_async Asynchronous API + @defgroup core_xml XML/YAML Persistence + @defgroup core_cluster Clustering + @defgroup core_utils Utility and system functions and macros + @{ + @defgroup core_logging Logging facilities + @defgroup core_utils_sse SSE utilities + @defgroup core_utils_neon NEON utilities + @defgroup core_utils_vsx VSX utilities + @defgroup core_utils_softfloat Softfloat support + @defgroup core_utils_samples Utility functions for OpenCV samples + @} + @defgroup core_opengl OpenGL interoperability + @defgroup core_ipp Intel IPP Asynchronous C/C++ Converters + @defgroup core_optim Optimization Algorithms + @defgroup core_directx DirectX interoperability + @defgroup core_eigen Eigen support + @defgroup core_opencl OpenCL support + @defgroup core_va_intel Intel VA-API/OpenCL (CL-VA) interoperability + @defgroup core_hal Hardware Acceleration Layer + @{ + @defgroup core_hal_functions Functions + @defgroup core_hal_interface Interface + @defgroup core_hal_intrin Universal intrinsics + @{ + @defgroup core_hal_intrin_impl Private implementation helpers + @} + @defgroup core_lowlevel_api Low-level API for external libraries / plugins + @} + @defgroup core_parallel Parallel Processing + @{ + @defgroup core_parallel_backend Parallel backends API + @} +@} + */ + +namespace cv { + +//! @addtogroup core_utils +//! @{ + +/*! @brief Class passed to an error. + +This class encapsulates all or almost all necessary +information about the error happened in the program. The exception is +usually constructed and thrown implicitly via CV_Error and CV_Error_ macros. +@see error + */ +class CV_EXPORTS Exception : public std::exception +{ +public: + /*! + Default constructor + */ + Exception(); + /*! + Full constructor. Normally the constructor is not called explicitly. + Instead, the macros CV_Error(), CV_Error_() and CV_Assert() are used. + */ + Exception(int _code, const String& _err, const String& _func, const String& _file, int _line); + virtual ~Exception() throw(); + + /*! + \return the error description and the context as a text string. + */ + virtual const char *what() const throw() CV_OVERRIDE; + void formatMessage(); + + String msg; ///< the formatted error message + + int code; ///< error code @see CVStatus + String err; ///< error description + String func; ///< function name. Available only when the compiler supports getting it + String file; ///< source file name where the error has occurred + int line; ///< line number in the source file where the error has occurred +}; + +/*! @brief Signals an error and raises the exception. + +By default the function prints information about the error to stderr, +then it either stops if cv::setBreakOnError() had been called before or raises the exception. +It is possible to alternate error processing by using #redirectError(). +@param exc the exception raisen. +@deprecated drop this version + */ +CV_EXPORTS CV_NORETURN void error(const Exception& exc); + +enum SortFlags { SORT_EVERY_ROW = 0, //!< each matrix row is sorted independently + SORT_EVERY_COLUMN = 1, //!< each matrix column is sorted + //!< independently; this flag and the previous one are + //!< mutually exclusive. + SORT_ASCENDING = 0, //!< each matrix row is sorted in the ascending + //!< order. + SORT_DESCENDING = 16 //!< each matrix row is sorted in the + //!< descending order; this flag and the previous one are also + //!< mutually exclusive. + }; + +//! @} core_utils + +//! @addtogroup core +//! @{ + +//! Covariation flags +enum CovarFlags { + /** The output covariance matrix is calculated as: + \f[\texttt{scale} \cdot [ \texttt{vects} [0]- \texttt{mean} , \texttt{vects} [1]- \texttt{mean} ,...]^T \cdot [ \texttt{vects} [0]- \texttt{mean} , \texttt{vects} [1]- \texttt{mean} ,...],\f] + The covariance matrix will be nsamples x nsamples. Such an unusual covariance matrix is used + for fast PCA of a set of very large vectors (see, for example, the EigenFaces technique for + face recognition). Eigenvalues of this "scrambled" matrix match the eigenvalues of the true + covariance matrix. The "true" eigenvectors can be easily calculated from the eigenvectors of + the "scrambled" covariance matrix. */ + COVAR_SCRAMBLED = 0, + /**The output covariance matrix is calculated as: + \f[\texttt{scale} \cdot [ \texttt{vects} [0]- \texttt{mean} , \texttt{vects} [1]- \texttt{mean} ,...] \cdot [ \texttt{vects} [0]- \texttt{mean} , \texttt{vects} [1]- \texttt{mean} ,...]^T,\f] + covar will be a square matrix of the same size as the total number of elements in each input + vector. One and only one of #COVAR_SCRAMBLED and #COVAR_NORMAL must be specified.*/ + COVAR_NORMAL = 1, + /** If the flag is specified, the function does not calculate mean from + the input vectors but, instead, uses the passed mean vector. This is useful if mean has been + pre-calculated or known in advance, or if the covariance matrix is calculated by parts. In + this case, mean is not a mean vector of the input sub-set of vectors but rather the mean + vector of the whole set.*/ + COVAR_USE_AVG = 2, + /** If the flag is specified, the covariance matrix is scaled. In the + "normal" mode, scale is 1./nsamples . In the "scrambled" mode, scale is the reciprocal of the + total number of elements in each input vector. By default (if the flag is not specified), the + covariance matrix is not scaled ( scale=1 ).*/ + COVAR_SCALE = 4, + /** If the flag is + specified, all the input vectors are stored as rows of the samples matrix. mean should be a + single-row vector in this case.*/ + COVAR_ROWS = 8, + /** If the flag is + specified, all the input vectors are stored as columns of the samples matrix. mean should be a + single-column vector in this case.*/ + COVAR_COLS = 16 +}; + +//! @addtogroup core_cluster +//! @{ + +//! k-Means flags +enum KmeansFlags { + /** Select random initial centers in each attempt.*/ + KMEANS_RANDOM_CENTERS = 0, + /** Use kmeans++ center initialization by Arthur and Vassilvitskii [Arthur2007].*/ + KMEANS_PP_CENTERS = 2, + /** During the first (and possibly the only) attempt, use the + user-supplied labels instead of computing them from the initial centers. For the second and + further attempts, use the random or semi-random centers. Use one of KMEANS_\*_CENTERS flag + to specify the exact method.*/ + KMEANS_USE_INITIAL_LABELS = 1 +}; + +//! @} core_cluster + +//! @addtogroup core_array +//! @{ + +enum ReduceTypes { REDUCE_SUM = 0, //!< the output is the sum of all rows/columns of the matrix. + REDUCE_AVG = 1, //!< the output is the mean vector of all rows/columns of the matrix. + REDUCE_MAX = 2, //!< the output is the maximum (column/row-wise) of all rows/columns of the matrix. + REDUCE_MIN = 3 //!< the output is the minimum (column/row-wise) of all rows/columns of the matrix. + }; + +//! @} core_array + +/** @brief Swaps two matrices +*/ +CV_EXPORTS void swap(Mat& a, Mat& b); +/** @overload */ +CV_EXPORTS void swap( UMat& a, UMat& b ); + +//! @} core + +//! @addtogroup core_array +//! @{ + +/** @brief Computes the source location of an extrapolated pixel. + +The function computes and returns the coordinate of a donor pixel corresponding to the specified +extrapolated pixel when using the specified extrapolation border mode. For example, if you use +cv::BORDER_WRAP mode in the horizontal direction, cv::BORDER_REFLECT_101 in the vertical direction and +want to compute value of the "virtual" pixel Point(-5, 100) in a floating-point image img , it +looks like: +@code{.cpp} + float val = img.at(borderInterpolate(100, img.rows, cv::BORDER_REFLECT_101), + borderInterpolate(-5, img.cols, cv::BORDER_WRAP)); +@endcode +Normally, the function is not called directly. It is used inside filtering functions and also in +copyMakeBorder. +@param p 0-based coordinate of the extrapolated pixel along one of the axes, likely \<0 or \>= len +@param len Length of the array along the corresponding axis. +@param borderType Border type, one of the #BorderTypes, except for #BORDER_TRANSPARENT and +#BORDER_ISOLATED . When borderType==#BORDER_CONSTANT , the function always returns -1, regardless +of p and len. + +@sa copyMakeBorder +*/ +CV_EXPORTS_W int borderInterpolate(int p, int len, int borderType); + +/** @example samples/cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp +An example using copyMakeBorder function. +Check @ref tutorial_copyMakeBorder "the corresponding tutorial" for more details +*/ + +/** @brief Forms a border around an image. + +The function copies the source image into the middle of the destination image. The areas to the +left, to the right, above and below the copied source image will be filled with extrapolated +pixels. This is not what filtering functions based on it do (they extrapolate pixels on-fly), but +what other more complex functions, including your own, may do to simplify image boundary handling. + +The function supports the mode when src is already in the middle of dst . In this case, the +function does not copy src itself but simply constructs the border, for example: + +@code{.cpp} + // let border be the same in all directions + int border=2; + // constructs a larger image to fit both the image and the border + Mat gray_buf(rgb.rows + border*2, rgb.cols + border*2, rgb.depth()); + // select the middle part of it w/o copying data + Mat gray(gray_canvas, Rect(border, border, rgb.cols, rgb.rows)); + // convert image from RGB to grayscale + cvtColor(rgb, gray, COLOR_RGB2GRAY); + // form a border in-place + copyMakeBorder(gray, gray_buf, border, border, + border, border, BORDER_REPLICATE); + // now do some custom filtering ... + ... +@endcode +@note When the source image is a part (ROI) of a bigger image, the function will try to use the +pixels outside of the ROI to form a border. To disable this feature and always do extrapolation, as +if src was not a ROI, use borderType | #BORDER_ISOLATED. + +@param src Source image. +@param dst Destination image of the same type as src and the size Size(src.cols+left+right, +src.rows+top+bottom) . +@param top the top pixels +@param bottom the bottom pixels +@param left the left pixels +@param right Parameter specifying how many pixels in each direction from the source image rectangle +to extrapolate. For example, top=1, bottom=1, left=1, right=1 mean that 1 pixel-wide border needs +to be built. +@param borderType Border type. See borderInterpolate for details. +@param value Border value if borderType==BORDER_CONSTANT . + +@sa borderInterpolate +*/ +CV_EXPORTS_W void copyMakeBorder(InputArray src, OutputArray dst, + int top, int bottom, int left, int right, + int borderType, const Scalar& value = Scalar() ); + +/** @brief Calculates the per-element sum of two arrays or an array and a scalar. + +The function add calculates: +- Sum of two arrays when both input arrays have the same size and the same number of channels: +\f[\texttt{dst}(I) = \texttt{saturate} ( \texttt{src1}(I) + \texttt{src2}(I)) \quad \texttt{if mask}(I) \ne0\f] +- Sum of an array and a scalar when src2 is constructed from Scalar or has the same number of +elements as `src1.channels()`: +\f[\texttt{dst}(I) = \texttt{saturate} ( \texttt{src1}(I) + \texttt{src2} ) \quad \texttt{if mask}(I) \ne0\f] +- Sum of a scalar and an array when src1 is constructed from Scalar or has the same number of +elements as `src2.channels()`: +\f[\texttt{dst}(I) = \texttt{saturate} ( \texttt{src1} + \texttt{src2}(I) ) \quad \texttt{if mask}(I) \ne0\f] +where `I` is a multi-dimensional index of array elements. In case of multi-channel arrays, each +channel is processed independently. + +The first function in the list above can be replaced with matrix expressions: +@code{.cpp} + dst = src1 + src2; + dst += src1; // equivalent to add(dst, src1, dst); +@endcode +The input arrays and the output array can all have the same or different depths. For example, you +can add a 16-bit unsigned array to a 8-bit signed array and store the sum as a 32-bit +floating-point array. Depth of the output array is determined by the dtype parameter. In the second +and third cases above, as well as in the first case, when src1.depth() == src2.depth(), dtype can +be set to the default -1. In this case, the output array will have the same depth as the input +array, be it src1, src2 or both. +@note Saturation is not applied when the output array has the depth CV_32S. You may even get +result of an incorrect sign in the case of overflow. +@param src1 first input array or a scalar. +@param src2 second input array or a scalar. +@param dst output array that has the same size and number of channels as the input array(s); the +depth is defined by dtype or src1/src2. +@param mask optional operation mask - 8-bit single channel array, that specifies elements of the +output array to be changed. +@param dtype optional depth of the output array (see the discussion below). +@sa subtract, addWeighted, scaleAdd, Mat::convertTo +*/ +CV_EXPORTS_W void add(InputArray src1, InputArray src2, OutputArray dst, + InputArray mask = noArray(), int dtype = -1); + +/** @brief Calculates the per-element difference between two arrays or array and a scalar. + +The function subtract calculates: +- Difference between two arrays, when both input arrays have the same size and the same number of +channels: + \f[\texttt{dst}(I) = \texttt{saturate} ( \texttt{src1}(I) - \texttt{src2}(I)) \quad \texttt{if mask}(I) \ne0\f] +- Difference between an array and a scalar, when src2 is constructed from Scalar or has the same +number of elements as `src1.channels()`: + \f[\texttt{dst}(I) = \texttt{saturate} ( \texttt{src1}(I) - \texttt{src2} ) \quad \texttt{if mask}(I) \ne0\f] +- Difference between a scalar and an array, when src1 is constructed from Scalar or has the same +number of elements as `src2.channels()`: + \f[\texttt{dst}(I) = \texttt{saturate} ( \texttt{src1} - \texttt{src2}(I) ) \quad \texttt{if mask}(I) \ne0\f] +- The reverse difference between a scalar and an array in the case of `SubRS`: + \f[\texttt{dst}(I) = \texttt{saturate} ( \texttt{src2} - \texttt{src1}(I) ) \quad \texttt{if mask}(I) \ne0\f] +where I is a multi-dimensional index of array elements. In case of multi-channel arrays, each +channel is processed independently. + +The first function in the list above can be replaced with matrix expressions: +@code{.cpp} + dst = src1 - src2; + dst -= src1; // equivalent to subtract(dst, src1, dst); +@endcode +The input arrays and the output array can all have the same or different depths. For example, you +can subtract to 8-bit unsigned arrays and store the difference in a 16-bit signed array. Depth of +the output array is determined by dtype parameter. In the second and third cases above, as well as +in the first case, when src1.depth() == src2.depth(), dtype can be set to the default -1. In this +case the output array will have the same depth as the input array, be it src1, src2 or both. +@note Saturation is not applied when the output array has the depth CV_32S. You may even get +result of an incorrect sign in the case of overflow. +@param src1 first input array or a scalar. +@param src2 second input array or a scalar. +@param dst output array of the same size and the same number of channels as the input array. +@param mask optional operation mask; this is an 8-bit single channel array that specifies elements +of the output array to be changed. +@param dtype optional depth of the output array +@sa add, addWeighted, scaleAdd, Mat::convertTo + */ +CV_EXPORTS_W void subtract(InputArray src1, InputArray src2, OutputArray dst, + InputArray mask = noArray(), int dtype = -1); + + +/** @brief Calculates the per-element scaled product of two arrays. + +The function multiply calculates the per-element product of two arrays: + +\f[\texttt{dst} (I)= \texttt{saturate} ( \texttt{scale} \cdot \texttt{src1} (I) \cdot \texttt{src2} (I))\f] + +There is also a @ref MatrixExpressions -friendly variant of the first function. See Mat::mul . + +For a not-per-element matrix product, see gemm . + +@note Saturation is not applied when the output array has the depth +CV_32S. You may even get result of an incorrect sign in the case of +overflow. +@param src1 first input array. +@param src2 second input array of the same size and the same type as src1. +@param dst output array of the same size and type as src1. +@param scale optional scale factor. +@param dtype optional depth of the output array +@sa add, subtract, divide, scaleAdd, addWeighted, accumulate, accumulateProduct, accumulateSquare, +Mat::convertTo +*/ +CV_EXPORTS_W void multiply(InputArray src1, InputArray src2, + OutputArray dst, double scale = 1, int dtype = -1); + +/** @brief Performs per-element division of two arrays or a scalar by an array. + +The function cv::divide divides one array by another: +\f[\texttt{dst(I) = saturate(src1(I)*scale/src2(I))}\f] +or a scalar by an array when there is no src1 : +\f[\texttt{dst(I) = saturate(scale/src2(I))}\f] + +Different channels of multi-channel arrays are processed independently. + +For integer types when src2(I) is zero, dst(I) will also be zero. + +@note In case of floating point data there is no special defined behavior for zero src2(I) values. +Regular floating-point division is used. +Expect correct IEEE-754 behaviour for floating-point data (with NaN, Inf result values). + +@note Saturation is not applied when the output array has the depth CV_32S. You may even get +result of an incorrect sign in the case of overflow. +@param src1 first input array. +@param src2 second input array of the same size and type as src1. +@param scale scalar factor. +@param dst output array of the same size and type as src2. +@param dtype optional depth of the output array; if -1, dst will have depth src2.depth(), but in +case of an array-by-array division, you can only pass -1 when src1.depth()==src2.depth(). +@sa multiply, add, subtract +*/ +CV_EXPORTS_W void divide(InputArray src1, InputArray src2, OutputArray dst, + double scale = 1, int dtype = -1); + +/** @overload */ +CV_EXPORTS_W void divide(double scale, InputArray src2, + OutputArray dst, int dtype = -1); + +/** @brief Calculates the sum of a scaled array and another array. + +The function scaleAdd is one of the classical primitive linear algebra operations, known as DAXPY +or SAXPY in [BLAS](http://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms). It calculates +the sum of a scaled array and another array: +\f[\texttt{dst} (I)= \texttt{scale} \cdot \texttt{src1} (I) + \texttt{src2} (I)\f] +The function can also be emulated with a matrix expression, for example: +@code{.cpp} + Mat A(3, 3, CV_64F); + ... + A.row(0) = A.row(1)*2 + A.row(2); +@endcode +@param src1 first input array. +@param alpha scale factor for the first array. +@param src2 second input array of the same size and type as src1. +@param dst output array of the same size and type as src1. +@sa add, addWeighted, subtract, Mat::dot, Mat::convertTo +*/ +CV_EXPORTS_W void scaleAdd(InputArray src1, double alpha, InputArray src2, OutputArray dst); + +/** @example samples/cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp +Check @ref tutorial_trackbar "the corresponding tutorial" for more details +*/ + +/** @brief Calculates the weighted sum of two arrays. + +The function addWeighted calculates the weighted sum of two arrays as follows: +\f[\texttt{dst} (I)= \texttt{saturate} ( \texttt{src1} (I)* \texttt{alpha} + \texttt{src2} (I)* \texttt{beta} + \texttt{gamma} )\f] +where I is a multi-dimensional index of array elements. In case of multi-channel arrays, each +channel is processed independently. +The function can be replaced with a matrix expression: +@code{.cpp} + dst = src1*alpha + src2*beta + gamma; +@endcode +@note Saturation is not applied when the output array has the depth CV_32S. You may even get +result of an incorrect sign in the case of overflow. +@param src1 first input array. +@param alpha weight of the first array elements. +@param src2 second input array of the same size and channel number as src1. +@param beta weight of the second array elements. +@param gamma scalar added to each sum. +@param dst output array that has the same size and number of channels as the input arrays. +@param dtype optional depth of the output array; when both input arrays have the same depth, dtype +can be set to -1, which will be equivalent to src1.depth(). +@sa add, subtract, scaleAdd, Mat::convertTo +*/ +CV_EXPORTS_W void addWeighted(InputArray src1, double alpha, InputArray src2, + double beta, double gamma, OutputArray dst, int dtype = -1); + +/** @brief Scales, calculates absolute values, and converts the result to 8-bit. + +On each element of the input array, the function convertScaleAbs +performs three operations sequentially: scaling, taking an absolute +value, conversion to an unsigned 8-bit type: +\f[\texttt{dst} (I)= \texttt{saturate\_cast} (| \texttt{src} (I)* \texttt{alpha} + \texttt{beta} |)\f] +In case of multi-channel arrays, the function processes each channel +independently. When the output is not 8-bit, the operation can be +emulated by calling the Mat::convertTo method (or by using matrix +expressions) and then by calculating an absolute value of the result. +For example: +@code{.cpp} + Mat_ A(30,30); + randu(A, Scalar(-100), Scalar(100)); + Mat_ B = A*5 + 3; + B = abs(B); + // Mat_ B = abs(A*5+3) will also do the job, + // but it will allocate a temporary matrix +@endcode +@param src input array. +@param dst output array. +@param alpha optional scale factor. +@param beta optional delta added to the scaled values. +@sa Mat::convertTo, cv::abs(const Mat&) +*/ +CV_EXPORTS_W void convertScaleAbs(InputArray src, OutputArray dst, + double alpha = 1, double beta = 0); + +/** @brief Converts an array to half precision floating number. + +This function converts FP32 (single precision floating point) from/to FP16 (half precision floating point). CV_16S format is used to represent FP16 data. +There are two use modes (src -> dst): CV_32F -> CV_16S and CV_16S -> CV_32F. The input array has to have type of CV_32F or +CV_16S to represent the bit depth. If the input array is neither of them, the function will raise an error. +The format of half precision floating point is defined in IEEE 754-2008. + +@param src input array. +@param dst output array. +*/ +CV_EXPORTS_W void convertFp16(InputArray src, OutputArray dst); + +/** @brief Performs a look-up table transform of an array. + +The function LUT fills the output array with values from the look-up table. Indices of the entries +are taken from the input array. That is, the function processes each element of src as follows: +\f[\texttt{dst} (I) \leftarrow \texttt{lut(src(I) + d)}\f] +where +\f[d = \fork{0}{if \(\texttt{src}\) has depth \(\texttt{CV_8U}\)}{128}{if \(\texttt{src}\) has depth \(\texttt{CV_8S}\)}\f] +@param src input array of 8-bit elements. +@param lut look-up table of 256 elements; in case of multi-channel input array, the table should +either have a single channel (in this case the same table is used for all channels) or the same +number of channels as in the input array. +@param dst output array of the same size and number of channels as src, and the same depth as lut. +@sa convertScaleAbs, Mat::convertTo +*/ +CV_EXPORTS_W void LUT(InputArray src, InputArray lut, OutputArray dst); + +/** @brief Calculates the sum of array elements. + +The function cv::sum calculates and returns the sum of array elements, +independently for each channel. +@param src input array that must have from 1 to 4 channels. +@sa countNonZero, mean, meanStdDev, norm, minMaxLoc, reduce +*/ +CV_EXPORTS_AS(sumElems) Scalar sum(InputArray src); + +/** @brief Counts non-zero array elements. + +The function returns the number of non-zero elements in src : +\f[\sum _{I: \; \texttt{src} (I) \ne0 } 1\f] +@param src single-channel array. +@sa mean, meanStdDev, norm, minMaxLoc, calcCovarMatrix +*/ +CV_EXPORTS_W int countNonZero( InputArray src ); + +/** @brief Returns the list of locations of non-zero pixels + +Given a binary matrix (likely returned from an operation such +as threshold(), compare(), >, ==, etc, return all of +the non-zero indices as a cv::Mat or std::vector (x,y) +For example: +@code{.cpp} + cv::Mat binaryImage; // input, binary image + cv::Mat locations; // output, locations of non-zero pixels + cv::findNonZero(binaryImage, locations); + + // access pixel coordinates + Point pnt = locations.at(i); +@endcode +or +@code{.cpp} + cv::Mat binaryImage; // input, binary image + vector locations; // output, locations of non-zero pixels + cv::findNonZero(binaryImage, locations); + + // access pixel coordinates + Point pnt = locations[i]; +@endcode +@param src single-channel array +@param idx the output array, type of cv::Mat or std::vector, corresponding to non-zero indices in the input +*/ +CV_EXPORTS_W void findNonZero( InputArray src, OutputArray idx ); + +/** @brief Calculates an average (mean) of array elements. + +The function cv::mean calculates the mean value M of array elements, +independently for each channel, and return it: +\f[\begin{array}{l} N = \sum _{I: \; \texttt{mask} (I) \ne 0} 1 \\ M_c = \left ( \sum _{I: \; \texttt{mask} (I) \ne 0}{ \texttt{mtx} (I)_c} \right )/N \end{array}\f] +When all the mask elements are 0's, the function returns Scalar::all(0) +@param src input array that should have from 1 to 4 channels so that the result can be stored in +Scalar_ . +@param mask optional operation mask. +@sa countNonZero, meanStdDev, norm, minMaxLoc +*/ +CV_EXPORTS_W Scalar mean(InputArray src, InputArray mask = noArray()); + +/** Calculates a mean and standard deviation of array elements. + +The function cv::meanStdDev calculates the mean and the standard deviation M +of array elements independently for each channel and returns it via the +output parameters: +\f[\begin{array}{l} N = \sum _{I, \texttt{mask} (I) \ne 0} 1 \\ \texttt{mean} _c = \frac{\sum_{ I: \; \texttt{mask}(I) \ne 0} \texttt{src} (I)_c}{N} \\ \texttt{stddev} _c = \sqrt{\frac{\sum_{ I: \; \texttt{mask}(I) \ne 0} \left ( \texttt{src} (I)_c - \texttt{mean} _c \right )^2}{N}} \end{array}\f] +When all the mask elements are 0's, the function returns +mean=stddev=Scalar::all(0). +@note The calculated standard deviation is only the diagonal of the +complete normalized covariance matrix. If the full matrix is needed, you +can reshape the multi-channel array M x N to the single-channel array +M\*N x mtx.channels() (only possible when the matrix is continuous) and +then pass the matrix to calcCovarMatrix . +@param src input array that should have from 1 to 4 channels so that the results can be stored in +Scalar_ 's. +@param mean output parameter: calculated mean value. +@param stddev output parameter: calculated standard deviation. +@param mask optional operation mask. +@sa countNonZero, mean, norm, minMaxLoc, calcCovarMatrix +*/ +CV_EXPORTS_W void meanStdDev(InputArray src, OutputArray mean, OutputArray stddev, + InputArray mask=noArray()); + +/** @brief Calculates the absolute norm of an array. + +This version of #norm calculates the absolute norm of src1. The type of norm to calculate is specified using #NormTypes. + +As example for one array consider the function \f$r(x)= \begin{pmatrix} x \\ 1-x \end{pmatrix}, x \in [-1;1]\f$. +The \f$ L_{1}, L_{2} \f$ and \f$ L_{\infty} \f$ norm for the sample value \f$r(-1) = \begin{pmatrix} -1 \\ 2 \end{pmatrix}\f$ +is calculated as follows +\f{align*} + \| r(-1) \|_{L_1} &= |-1| + |2| = 3 \\ + \| r(-1) \|_{L_2} &= \sqrt{(-1)^{2} + (2)^{2}} = \sqrt{5} \\ + \| r(-1) \|_{L_\infty} &= \max(|-1|,|2|) = 2 +\f} +and for \f$r(0.5) = \begin{pmatrix} 0.5 \\ 0.5 \end{pmatrix}\f$ the calculation is +\f{align*} + \| r(0.5) \|_{L_1} &= |0.5| + |0.5| = 1 \\ + \| r(0.5) \|_{L_2} &= \sqrt{(0.5)^{2} + (0.5)^{2}} = \sqrt{0.5} \\ + \| r(0.5) \|_{L_\infty} &= \max(|0.5|,|0.5|) = 0.5. +\f} +The following graphic shows all values for the three norm functions \f$\| r(x) \|_{L_1}, \| r(x) \|_{L_2}\f$ and \f$\| r(x) \|_{L_\infty}\f$. +It is notable that the \f$ L_{1} \f$ norm forms the upper and the \f$ L_{\infty} \f$ norm forms the lower border for the example function \f$ r(x) \f$. +![Graphs for the different norm functions from the above example](pics/NormTypes_OneArray_1-2-INF.png) + +When the mask parameter is specified and it is not empty, the norm is + +If normType is not specified, #NORM_L2 is used. +calculated only over the region specified by the mask. + +Multi-channel input arrays are treated as single-channel arrays, that is, +the results for all channels are combined. + +Hamming norms can only be calculated with CV_8U depth arrays. + +@param src1 first input array. +@param normType type of the norm (see #NormTypes). +@param mask optional operation mask; it must have the same size as src1 and CV_8UC1 type. +*/ +CV_EXPORTS_W double norm(InputArray src1, int normType = NORM_L2, InputArray mask = noArray()); + +/** @brief Calculates an absolute difference norm or a relative difference norm. + +This version of cv::norm calculates the absolute difference norm +or the relative difference norm of arrays src1 and src2. +The type of norm to calculate is specified using #NormTypes. + +@param src1 first input array. +@param src2 second input array of the same size and the same type as src1. +@param normType type of the norm (see #NormTypes). +@param mask optional operation mask; it must have the same size as src1 and CV_8UC1 type. +*/ +CV_EXPORTS_W double norm(InputArray src1, InputArray src2, + int normType = NORM_L2, InputArray mask = noArray()); +/** @overload +@param src first input array. +@param normType type of the norm (see #NormTypes). +*/ +CV_EXPORTS double norm( const SparseMat& src, int normType ); + +/** @brief Computes the Peak Signal-to-Noise Ratio (PSNR) image quality metric. + +This function calculates the Peak Signal-to-Noise Ratio (PSNR) image quality metric in decibels (dB), +between two input arrays src1 and src2. The arrays must have the same type. + +The PSNR is calculated as follows: + +\f[ +\texttt{PSNR} = 10 \cdot \log_{10}{\left( \frac{R^2}{MSE} \right) } +\f] + +where R is the maximum integer value of depth (e.g. 255 in the case of CV_8U data) +and MSE is the mean squared error between the two arrays. + +@param src1 first input array. +@param src2 second input array of the same size as src1. +@param R the maximum pixel value (255 by default) + + */ +CV_EXPORTS_W double PSNR(InputArray src1, InputArray src2, double R=255.); + +/** @brief naive nearest neighbor finder + +see http://en.wikipedia.org/wiki/Nearest_neighbor_search +@todo document + */ +CV_EXPORTS_W void batchDistance(InputArray src1, InputArray src2, + OutputArray dist, int dtype, OutputArray nidx, + int normType = NORM_L2, int K = 0, + InputArray mask = noArray(), int update = 0, + bool crosscheck = false); + +/** @brief Normalizes the norm or value range of an array. + +The function cv::normalize normalizes scale and shift the input array elements so that +\f[\| \texttt{dst} \| _{L_p}= \texttt{alpha}\f] +(where p=Inf, 1 or 2) when normType=NORM_INF, NORM_L1, or NORM_L2, respectively; or so that +\f[\min _I \texttt{dst} (I)= \texttt{alpha} , \, \, \max _I \texttt{dst} (I)= \texttt{beta}\f] + +when normType=NORM_MINMAX (for dense arrays only). The optional mask specifies a sub-array to be +normalized. This means that the norm or min-n-max are calculated over the sub-array, and then this +sub-array is modified to be normalized. If you want to only use the mask to calculate the norm or +min-max but modify the whole array, you can use norm and Mat::convertTo. + +In case of sparse matrices, only the non-zero values are analyzed and transformed. Because of this, +the range transformation for sparse matrices is not allowed since it can shift the zero level. + +Possible usage with some positive example data: +@code{.cpp} + vector positiveData = { 2.0, 8.0, 10.0 }; + vector normalizedData_l1, normalizedData_l2, normalizedData_inf, normalizedData_minmax; + + // Norm to probability (total count) + // sum(numbers) = 20.0 + // 2.0 0.1 (2.0/20.0) + // 8.0 0.4 (8.0/20.0) + // 10.0 0.5 (10.0/20.0) + normalize(positiveData, normalizedData_l1, 1.0, 0.0, NORM_L1); + + // Norm to unit vector: ||positiveData|| = 1.0 + // 2.0 0.15 + // 8.0 0.62 + // 10.0 0.77 + normalize(positiveData, normalizedData_l2, 1.0, 0.0, NORM_L2); + + // Norm to max element + // 2.0 0.2 (2.0/10.0) + // 8.0 0.8 (8.0/10.0) + // 10.0 1.0 (10.0/10.0) + normalize(positiveData, normalizedData_inf, 1.0, 0.0, NORM_INF); + + // Norm to range [0.0;1.0] + // 2.0 0.0 (shift to left border) + // 8.0 0.75 (6.0/8.0) + // 10.0 1.0 (shift to right border) + normalize(positiveData, normalizedData_minmax, 1.0, 0.0, NORM_MINMAX); +@endcode + +@param src input array. +@param dst output array of the same size as src . +@param alpha norm value to normalize to or the lower range boundary in case of the range +normalization. +@param beta upper range boundary in case of the range normalization; it is not used for the norm +normalization. +@param norm_type normalization type (see cv::NormTypes). +@param dtype when negative, the output array has the same type as src; otherwise, it has the same +number of channels as src and the depth =CV_MAT_DEPTH(dtype). +@param mask optional operation mask. +@sa norm, Mat::convertTo, SparseMat::convertTo +*/ +CV_EXPORTS_W void normalize( InputArray src, InputOutputArray dst, double alpha = 1, double beta = 0, + int norm_type = NORM_L2, int dtype = -1, InputArray mask = noArray()); + +/** @overload +@param src input array. +@param dst output array of the same size as src . +@param alpha norm value to normalize to or the lower range boundary in case of the range +normalization. +@param normType normalization type (see cv::NormTypes). +*/ +CV_EXPORTS void normalize( const SparseMat& src, SparseMat& dst, double alpha, int normType ); + +/** @brief Finds the global minimum and maximum in an array. + +The function cv::minMaxLoc finds the minimum and maximum element values and their positions. The +extremums are searched across the whole array or, if mask is not an empty array, in the specified +array region. + +The function do not work with multi-channel arrays. If you need to find minimum or maximum +elements across all the channels, use Mat::reshape first to reinterpret the array as +single-channel. Or you may extract the particular channel using either extractImageCOI , or +mixChannels , or split . +@param src input single-channel array. +@param minVal pointer to the returned minimum value; NULL is used if not required. +@param maxVal pointer to the returned maximum value; NULL is used if not required. +@param minLoc pointer to the returned minimum location (in 2D case); NULL is used if not required. +@param maxLoc pointer to the returned maximum location (in 2D case); NULL is used if not required. +@param mask optional mask used to select a sub-array. +@sa max, min, reduceArgMin, reduceArgMax, compare, inRange, extractImageCOI, mixChannels, split, Mat::reshape +*/ +CV_EXPORTS_W void minMaxLoc(InputArray src, CV_OUT double* minVal, + CV_OUT double* maxVal = 0, CV_OUT Point* minLoc = 0, + CV_OUT Point* maxLoc = 0, InputArray mask = noArray()); + +/** + * @brief Finds indices of min elements along provided axis + * + * @note + * - If input or output array is not continuous, this function will create an internal copy. + * - NaN handling is left unspecified, see patchNaNs(). + * - The returned index is always in bounds of input matrix. + * + * @param src input single-channel array. + * @param dst output array of type CV_32SC1 with the same dimensionality as src, + * except for axis being reduced - it should be set to 1. + * @param lastIndex whether to get the index of first or last occurrence of min. + * @param axis axis to reduce along. + * @sa reduceArgMax, minMaxLoc, min, max, compare, reduce + */ +CV_EXPORTS_W void reduceArgMin(InputArray src, OutputArray dst, int axis, bool lastIndex = false); + +/** + * @brief Finds indices of max elements along provided axis + * + * @note + * - If input or output array is not continuous, this function will create an internal copy. + * - NaN handling is left unspecified, see patchNaNs(). + * - The returned index is always in bounds of input matrix. + * + * @param src input single-channel array. + * @param dst output array of type CV_32SC1 with the same dimensionality as src, + * except for axis being reduced - it should be set to 1. + * @param lastIndex whether to get the index of first or last occurrence of max. + * @param axis axis to reduce along. + * @sa reduceArgMin, minMaxLoc, min, max, compare, reduce + */ +CV_EXPORTS_W void reduceArgMax(InputArray src, OutputArray dst, int axis, bool lastIndex = false); + +/** @brief Finds the global minimum and maximum in an array + +The function cv::minMaxIdx finds the minimum and maximum element values and their positions. The +extremums are searched across the whole array or, if mask is not an empty array, in the specified +array region. The function does not work with multi-channel arrays. If you need to find minimum or +maximum elements across all the channels, use Mat::reshape first to reinterpret the array as +single-channel. Or you may extract the particular channel using either extractImageCOI , or +mixChannels , or split . In case of a sparse matrix, the minimum is found among non-zero elements +only. +@note When minIdx is not NULL, it must have at least 2 elements (as well as maxIdx), even if src is +a single-row or single-column matrix. In OpenCV (following MATLAB) each array has at least 2 +dimensions, i.e. single-column matrix is Mx1 matrix (and therefore minIdx/maxIdx will be +(i1,0)/(i2,0)) and single-row matrix is 1xN matrix (and therefore minIdx/maxIdx will be +(0,j1)/(0,j2)). +@param src input single-channel array. +@param minVal pointer to the returned minimum value; NULL is used if not required. +@param maxVal pointer to the returned maximum value; NULL is used if not required. +@param minIdx pointer to the returned minimum location (in nD case); NULL is used if not required; +Otherwise, it must point to an array of src.dims elements, the coordinates of the minimum element +in each dimension are stored there sequentially. +@param maxIdx pointer to the returned maximum location (in nD case). NULL is used if not required. +@param mask specified array region +*/ +CV_EXPORTS void minMaxIdx(InputArray src, double* minVal, double* maxVal = 0, + int* minIdx = 0, int* maxIdx = 0, InputArray mask = noArray()); + +/** @overload +@param a input single-channel array. +@param minVal pointer to the returned minimum value; NULL is used if not required. +@param maxVal pointer to the returned maximum value; NULL is used if not required. +@param minIdx pointer to the returned minimum location (in nD case); NULL is used if not required; +Otherwise, it must point to an array of src.dims elements, the coordinates of the minimum element +in each dimension are stored there sequentially. +@param maxIdx pointer to the returned maximum location (in nD case). NULL is used if not required. +*/ +CV_EXPORTS void minMaxLoc(const SparseMat& a, double* minVal, + double* maxVal, int* minIdx = 0, int* maxIdx = 0); + +/** @brief Reduces a matrix to a vector. + +The function #reduce reduces the matrix to a vector by treating the matrix rows/columns as a set of +1D vectors and performing the specified operation on the vectors until a single row/column is +obtained. For example, the function can be used to compute horizontal and vertical projections of a +raster image. In case of #REDUCE_MAX and #REDUCE_MIN , the output image should have the same type as the source one. +In case of #REDUCE_SUM and #REDUCE_AVG , the output may have a larger element bit-depth to preserve accuracy. +And multi-channel arrays are also supported in these two reduction modes. + +The following code demonstrates its usage for a single channel matrix. +@snippet snippets/core_reduce.cpp example + +And the following code demonstrates its usage for a two-channel matrix. +@snippet snippets/core_reduce.cpp example2 + +@param src input 2D matrix. +@param dst output vector. Its size and type is defined by dim and dtype parameters. +@param dim dimension index along which the matrix is reduced. 0 means that the matrix is reduced to +a single row. 1 means that the matrix is reduced to a single column. +@param rtype reduction operation that could be one of #ReduceTypes +@param dtype when negative, the output vector will have the same type as the input matrix, +otherwise, its type will be CV_MAKE_TYPE(CV_MAT_DEPTH(dtype), src.channels()). +@sa repeat, reduceArgMin, reduceArgMax +*/ +CV_EXPORTS_W void reduce(InputArray src, OutputArray dst, int dim, int rtype, int dtype = -1); + +/** @brief Creates one multi-channel array out of several single-channel ones. + +The function cv::merge merges several arrays to make a single multi-channel array. That is, each +element of the output array will be a concatenation of the elements of the input arrays, where +elements of i-th input array are treated as mv[i].channels()-element vectors. + +The function cv::split does the reverse operation. If you need to shuffle channels in some other +advanced way, use cv::mixChannels. + +The following example shows how to merge 3 single channel matrices into a single 3-channel matrix. +@snippet snippets/core_merge.cpp example + +@param mv input array of matrices to be merged; all the matrices in mv must have the same +size and the same depth. +@param count number of input matrices when mv is a plain C array; it must be greater than zero. +@param dst output array of the same size and the same depth as mv[0]; The number of channels will +be equal to the parameter count. +@sa mixChannels, split, Mat::reshape +*/ +CV_EXPORTS void merge(const Mat* mv, size_t count, OutputArray dst); + +/** @overload +@param mv input vector of matrices to be merged; all the matrices in mv must have the same +size and the same depth. +@param dst output array of the same size and the same depth as mv[0]; The number of channels will +be the total number of channels in the matrix array. + */ +CV_EXPORTS_W void merge(InputArrayOfArrays mv, OutputArray dst); + +/** @brief Divides a multi-channel array into several single-channel arrays. + +The function cv::split splits a multi-channel array into separate single-channel arrays: +\f[\texttt{mv} [c](I) = \texttt{src} (I)_c\f] +If you need to extract a single channel or do some other sophisticated channel permutation, use +mixChannels . + +The following example demonstrates how to split a 3-channel matrix into 3 single channel matrices. +@snippet snippets/core_split.cpp example + +@param src input multi-channel array. +@param mvbegin output array; the number of arrays must match src.channels(); the arrays themselves are +reallocated, if needed. +@sa merge, mixChannels, cvtColor +*/ +CV_EXPORTS void split(const Mat& src, Mat* mvbegin); + +/** @overload +@param m input multi-channel array. +@param mv output vector of arrays; the arrays themselves are reallocated, if needed. +*/ +CV_EXPORTS_W void split(InputArray m, OutputArrayOfArrays mv); + +/** @brief Copies specified channels from input arrays to the specified channels of +output arrays. + +The function cv::mixChannels provides an advanced mechanism for shuffling image channels. + +cv::split,cv::merge,cv::extractChannel,cv::insertChannel and some forms of cv::cvtColor are partial cases of cv::mixChannels. + +In the example below, the code splits a 4-channel BGRA image into a 3-channel BGR (with B and R +channels swapped) and a separate alpha-channel image: +@code{.cpp} + Mat bgra( 100, 100, CV_8UC4, Scalar(255,0,0,255) ); + Mat bgr( bgra.rows, bgra.cols, CV_8UC3 ); + Mat alpha( bgra.rows, bgra.cols, CV_8UC1 ); + + // forming an array of matrices is a quite efficient operation, + // because the matrix data is not copied, only the headers + Mat out[] = { bgr, alpha }; + // bgra[0] -> bgr[2], bgra[1] -> bgr[1], + // bgra[2] -> bgr[0], bgra[3] -> alpha[0] + int from_to[] = { 0,2, 1,1, 2,0, 3,3 }; + mixChannels( &bgra, 1, out, 2, from_to, 4 ); +@endcode +@note Unlike many other new-style C++ functions in OpenCV (see the introduction section and +Mat::create ), cv::mixChannels requires the output arrays to be pre-allocated before calling the +function. +@param src input array or vector of matrices; all of the matrices must have the same size and the +same depth. +@param nsrcs number of matrices in `src`. +@param dst output array or vector of matrices; all the matrices **must be allocated**; their size and +depth must be the same as in `src[0]`. +@param ndsts number of matrices in `dst`. +@param fromTo array of index pairs specifying which channels are copied and where; fromTo[k\*2] is +a 0-based index of the input channel in src, fromTo[k\*2+1] is an index of the output channel in +dst; the continuous channel numbering is used: the first input image channels are indexed from 0 to +src[0].channels()-1, the second input image channels are indexed from src[0].channels() to +src[0].channels() + src[1].channels()-1, and so on, the same scheme is used for the output image +channels; as a special case, when fromTo[k\*2] is negative, the corresponding output channel is +filled with zero . +@param npairs number of index pairs in `fromTo`. +@sa split, merge, extractChannel, insertChannel, cvtColor +*/ +CV_EXPORTS void mixChannels(const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts, + const int* fromTo, size_t npairs); + +/** @overload +@param src input array or vector of matrices; all of the matrices must have the same size and the +same depth. +@param dst output array or vector of matrices; all the matrices **must be allocated**; their size and +depth must be the same as in src[0]. +@param fromTo array of index pairs specifying which channels are copied and where; fromTo[k\*2] is +a 0-based index of the input channel in src, fromTo[k\*2+1] is an index of the output channel in +dst; the continuous channel numbering is used: the first input image channels are indexed from 0 to +src[0].channels()-1, the second input image channels are indexed from src[0].channels() to +src[0].channels() + src[1].channels()-1, and so on, the same scheme is used for the output image +channels; as a special case, when fromTo[k\*2] is negative, the corresponding output channel is +filled with zero . +@param npairs number of index pairs in fromTo. +*/ +CV_EXPORTS void mixChannels(InputArrayOfArrays src, InputOutputArrayOfArrays dst, + const int* fromTo, size_t npairs); + +/** @overload +@param src input array or vector of matrices; all of the matrices must have the same size and the +same depth. +@param dst output array or vector of matrices; all the matrices **must be allocated**; their size and +depth must be the same as in src[0]. +@param fromTo array of index pairs specifying which channels are copied and where; fromTo[k\*2] is +a 0-based index of the input channel in src, fromTo[k\*2+1] is an index of the output channel in +dst; the continuous channel numbering is used: the first input image channels are indexed from 0 to +src[0].channels()-1, the second input image channels are indexed from src[0].channels() to +src[0].channels() + src[1].channels()-1, and so on, the same scheme is used for the output image +channels; as a special case, when fromTo[k\*2] is negative, the corresponding output channel is +filled with zero . +*/ +CV_EXPORTS_W void mixChannels(InputArrayOfArrays src, InputOutputArrayOfArrays dst, + const std::vector& fromTo); + +/** @brief Extracts a single channel from src (coi is 0-based index) +@param src input array +@param dst output array +@param coi index of channel to extract +@sa mixChannels, split +*/ +CV_EXPORTS_W void extractChannel(InputArray src, OutputArray dst, int coi); + +/** @brief Inserts a single channel to dst (coi is 0-based index) +@param src input array +@param dst output array +@param coi index of channel for insertion +@sa mixChannels, merge +*/ +CV_EXPORTS_W void insertChannel(InputArray src, InputOutputArray dst, int coi); + +/** @brief Flips a 2D array around vertical, horizontal, or both axes. + +The function cv::flip flips the array in one of three different ways (row +and column indices are 0-based): +\f[\texttt{dst} _{ij} = +\left\{ +\begin{array}{l l} +\texttt{src} _{\texttt{src.rows}-i-1,j} & if\; \texttt{flipCode} = 0 \\ +\texttt{src} _{i, \texttt{src.cols} -j-1} & if\; \texttt{flipCode} > 0 \\ +\texttt{src} _{ \texttt{src.rows} -i-1, \texttt{src.cols} -j-1} & if\; \texttt{flipCode} < 0 \\ +\end{array} +\right.\f] +The example scenarios of using the function are the following: +* Vertical flipping of the image (flipCode == 0) to switch between + top-left and bottom-left image origin. This is a typical operation + in video processing on Microsoft Windows\* OS. +* Horizontal flipping of the image with the subsequent horizontal + shift and absolute difference calculation to check for a + vertical-axis symmetry (flipCode \> 0). +* Simultaneous horizontal and vertical flipping of the image with + the subsequent shift and absolute difference calculation to check + for a central symmetry (flipCode \< 0). +* Reversing the order of point arrays (flipCode \> 0 or + flipCode == 0). +@param src input array. +@param dst output array of the same size and type as src. +@param flipCode a flag to specify how to flip the array; 0 means +flipping around the x-axis and positive value (for example, 1) means +flipping around y-axis. Negative value (for example, -1) means flipping +around both axes. +@sa transpose , repeat , completeSymm +*/ +CV_EXPORTS_W void flip(InputArray src, OutputArray dst, int flipCode); + +enum RotateFlags { + ROTATE_90_CLOCKWISE = 0, //! A = (cv::Mat_(3, 2) << 1, 4, + 2, 5, + 3, 6); + cv::Mat_ B = (cv::Mat_(3, 2) << 7, 10, + 8, 11, + 9, 12); + + cv::Mat C; + cv::hconcat(A, B, C); + //C: + //[1, 4, 7, 10; + // 2, 5, 8, 11; + // 3, 6, 9, 12] + @endcode + @param src1 first input array to be considered for horizontal concatenation. + @param src2 second input array to be considered for horizontal concatenation. + @param dst output array. It has the same number of rows and depth as the src1 and src2, and the sum of cols of the src1 and src2. + */ +CV_EXPORTS void hconcat(InputArray src1, InputArray src2, OutputArray dst); +/** @overload + @code{.cpp} + std::vector matrices = { cv::Mat(4, 1, CV_8UC1, cv::Scalar(1)), + cv::Mat(4, 1, CV_8UC1, cv::Scalar(2)), + cv::Mat(4, 1, CV_8UC1, cv::Scalar(3)),}; + + cv::Mat out; + cv::hconcat( matrices, out ); + //out: + //[1, 2, 3; + // 1, 2, 3; + // 1, 2, 3; + // 1, 2, 3] + @endcode + @param src input array or vector of matrices. all of the matrices must have the same number of rows and the same depth. + @param dst output array. It has the same number of rows and depth as the src, and the sum of cols of the src. +same depth. + */ +CV_EXPORTS_W void hconcat(InputArrayOfArrays src, OutputArray dst); + +/** @brief Applies vertical concatenation to given matrices. + +The function vertically concatenates two or more cv::Mat matrices (with the same number of cols). +@code{.cpp} + cv::Mat matArray[] = { cv::Mat(1, 4, CV_8UC1, cv::Scalar(1)), + cv::Mat(1, 4, CV_8UC1, cv::Scalar(2)), + cv::Mat(1, 4, CV_8UC1, cv::Scalar(3)),}; + + cv::Mat out; + cv::vconcat( matArray, 3, out ); + //out: + //[1, 1, 1, 1; + // 2, 2, 2, 2; + // 3, 3, 3, 3] +@endcode +@param src input array or vector of matrices. all of the matrices must have the same number of cols and the same depth. +@param nsrc number of matrices in src. +@param dst output array. It has the same number of cols and depth as the src, and the sum of rows of the src. +@sa cv::hconcat(const Mat*, size_t, OutputArray), @sa cv::hconcat(InputArrayOfArrays, OutputArray) and @sa cv::hconcat(InputArray, InputArray, OutputArray) +*/ +CV_EXPORTS void vconcat(const Mat* src, size_t nsrc, OutputArray dst); +/** @overload + @code{.cpp} + cv::Mat_ A = (cv::Mat_(3, 2) << 1, 7, + 2, 8, + 3, 9); + cv::Mat_ B = (cv::Mat_(3, 2) << 4, 10, + 5, 11, + 6, 12); + + cv::Mat C; + cv::vconcat(A, B, C); + //C: + //[1, 7; + // 2, 8; + // 3, 9; + // 4, 10; + // 5, 11; + // 6, 12] + @endcode + @param src1 first input array to be considered for vertical concatenation. + @param src2 second input array to be considered for vertical concatenation. + @param dst output array. It has the same number of cols and depth as the src1 and src2, and the sum of rows of the src1 and src2. + */ +CV_EXPORTS void vconcat(InputArray src1, InputArray src2, OutputArray dst); +/** @overload + @code{.cpp} + std::vector matrices = { cv::Mat(1, 4, CV_8UC1, cv::Scalar(1)), + cv::Mat(1, 4, CV_8UC1, cv::Scalar(2)), + cv::Mat(1, 4, CV_8UC1, cv::Scalar(3)),}; + + cv::Mat out; + cv::vconcat( matrices, out ); + //out: + //[1, 1, 1, 1; + // 2, 2, 2, 2; + // 3, 3, 3, 3] + @endcode + @param src input array or vector of matrices. all of the matrices must have the same number of cols and the same depth + @param dst output array. It has the same number of cols and depth as the src, and the sum of rows of the src. +same depth. + */ +CV_EXPORTS_W void vconcat(InputArrayOfArrays src, OutputArray dst); + +/** @brief computes bitwise conjunction of the two arrays (dst = src1 & src2) +Calculates the per-element bit-wise conjunction of two arrays or an +array and a scalar. + +The function cv::bitwise_and calculates the per-element bit-wise logical conjunction for: +* Two arrays when src1 and src2 have the same size: + \f[\texttt{dst} (I) = \texttt{src1} (I) \wedge \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0\f] +* An array and a scalar when src2 is constructed from Scalar or has + the same number of elements as `src1.channels()`: + \f[\texttt{dst} (I) = \texttt{src1} (I) \wedge \texttt{src2} \quad \texttt{if mask} (I) \ne0\f] +* A scalar and an array when src1 is constructed from Scalar or has + the same number of elements as `src2.channels()`: + \f[\texttt{dst} (I) = \texttt{src1} \wedge \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0\f] +In case of floating-point arrays, their machine-specific bit +representations (usually IEEE754-compliant) are used for the operation. +In case of multi-channel arrays, each channel is processed +independently. In the second and third cases above, the scalar is first +converted to the array type. +@param src1 first input array or a scalar. +@param src2 second input array or a scalar. +@param dst output array that has the same size and type as the input +arrays. +@param mask optional operation mask, 8-bit single channel array, that +specifies elements of the output array to be changed. +*/ +CV_EXPORTS_W void bitwise_and(InputArray src1, InputArray src2, + OutputArray dst, InputArray mask = noArray()); + +/** @brief Calculates the per-element bit-wise disjunction of two arrays or an +array and a scalar. + +The function cv::bitwise_or calculates the per-element bit-wise logical disjunction for: +* Two arrays when src1 and src2 have the same size: + \f[\texttt{dst} (I) = \texttt{src1} (I) \vee \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0\f] +* An array and a scalar when src2 is constructed from Scalar or has + the same number of elements as `src1.channels()`: + \f[\texttt{dst} (I) = \texttt{src1} (I) \vee \texttt{src2} \quad \texttt{if mask} (I) \ne0\f] +* A scalar and an array when src1 is constructed from Scalar or has + the same number of elements as `src2.channels()`: + \f[\texttt{dst} (I) = \texttt{src1} \vee \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0\f] +In case of floating-point arrays, their machine-specific bit +representations (usually IEEE754-compliant) are used for the operation. +In case of multi-channel arrays, each channel is processed +independently. In the second and third cases above, the scalar is first +converted to the array type. +@param src1 first input array or a scalar. +@param src2 second input array or a scalar. +@param dst output array that has the same size and type as the input +arrays. +@param mask optional operation mask, 8-bit single channel array, that +specifies elements of the output array to be changed. +*/ +CV_EXPORTS_W void bitwise_or(InputArray src1, InputArray src2, + OutputArray dst, InputArray mask = noArray()); + +/** @brief Calculates the per-element bit-wise "exclusive or" operation on two +arrays or an array and a scalar. + +The function cv::bitwise_xor calculates the per-element bit-wise logical "exclusive-or" +operation for: +* Two arrays when src1 and src2 have the same size: + \f[\texttt{dst} (I) = \texttt{src1} (I) \oplus \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0\f] +* An array and a scalar when src2 is constructed from Scalar or has + the same number of elements as `src1.channels()`: + \f[\texttt{dst} (I) = \texttt{src1} (I) \oplus \texttt{src2} \quad \texttt{if mask} (I) \ne0\f] +* A scalar and an array when src1 is constructed from Scalar or has + the same number of elements as `src2.channels()`: + \f[\texttt{dst} (I) = \texttt{src1} \oplus \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0\f] +In case of floating-point arrays, their machine-specific bit +representations (usually IEEE754-compliant) are used for the operation. +In case of multi-channel arrays, each channel is processed +independently. In the 2nd and 3rd cases above, the scalar is first +converted to the array type. +@param src1 first input array or a scalar. +@param src2 second input array or a scalar. +@param dst output array that has the same size and type as the input +arrays. +@param mask optional operation mask, 8-bit single channel array, that +specifies elements of the output array to be changed. +*/ +CV_EXPORTS_W void bitwise_xor(InputArray src1, InputArray src2, + OutputArray dst, InputArray mask = noArray()); + +/** @brief Inverts every bit of an array. + +The function cv::bitwise_not calculates per-element bit-wise inversion of the input +array: +\f[\texttt{dst} (I) = \neg \texttt{src} (I)\f] +In case of a floating-point input array, its machine-specific bit +representation (usually IEEE754-compliant) is used for the operation. In +case of multi-channel arrays, each channel is processed independently. +@param src input array. +@param dst output array that has the same size and type as the input +array. +@param mask optional operation mask, 8-bit single channel array, that +specifies elements of the output array to be changed. +*/ +CV_EXPORTS_W void bitwise_not(InputArray src, OutputArray dst, + InputArray mask = noArray()); + +/** @brief Calculates the per-element absolute difference between two arrays or between an array and a scalar. + +The function cv::absdiff calculates: +* Absolute difference between two arrays when they have the same + size and type: + \f[\texttt{dst}(I) = \texttt{saturate} (| \texttt{src1}(I) - \texttt{src2}(I)|)\f] +* Absolute difference between an array and a scalar when the second + array is constructed from Scalar or has as many elements as the + number of channels in `src1`: + \f[\texttt{dst}(I) = \texttt{saturate} (| \texttt{src1}(I) - \texttt{src2} |)\f] +* Absolute difference between a scalar and an array when the first + array is constructed from Scalar or has as many elements as the + number of channels in `src2`: + \f[\texttt{dst}(I) = \texttt{saturate} (| \texttt{src1} - \texttt{src2}(I) |)\f] + where I is a multi-dimensional index of array elements. In case of + multi-channel arrays, each channel is processed independently. +@note Saturation is not applied when the arrays have the depth CV_32S. +You may even get a negative value in the case of overflow. +@param src1 first input array or a scalar. +@param src2 second input array or a scalar. +@param dst output array that has the same size and type as input arrays. +@sa cv::abs(const Mat&) +*/ +CV_EXPORTS_W void absdiff(InputArray src1, InputArray src2, OutputArray dst); + +/** @brief This is an overloaded member function, provided for convenience (python) +Copies the matrix to another one. +When the operation mask is specified, if the Mat::create call shown above reallocates the matrix, the newly allocated matrix is initialized with all zeros before copying the data. +@param src source matrix. +@param dst Destination matrix. If it does not have a proper size or type before the operation, it is +reallocated. +@param mask Operation mask of the same size as \*this. Its non-zero elements indicate which matrix +elements need to be copied. The mask has to be of type CV_8U and can have 1 or multiple channels. +*/ + +void CV_EXPORTS_W copyTo(InputArray src, OutputArray dst, InputArray mask); +/** @brief Checks if array elements lie between the elements of two other arrays. + +The function checks the range as follows: +- For every element of a single-channel input array: + \f[\texttt{dst} (I)= \texttt{lowerb} (I)_0 \leq \texttt{src} (I)_0 \leq \texttt{upperb} (I)_0\f] +- For two-channel arrays: + \f[\texttt{dst} (I)= \texttt{lowerb} (I)_0 \leq \texttt{src} (I)_0 \leq \texttt{upperb} (I)_0 \land \texttt{lowerb} (I)_1 \leq \texttt{src} (I)_1 \leq \texttt{upperb} (I)_1\f] +- and so forth. + +That is, dst (I) is set to 255 (all 1 -bits) if src (I) is within the +specified 1D, 2D, 3D, ... box and 0 otherwise. + +When the lower and/or upper boundary parameters are scalars, the indexes +(I) at lowerb and upperb in the above formulas should be omitted. +@param src first input array. +@param lowerb inclusive lower boundary array or a scalar. +@param upperb inclusive upper boundary array or a scalar. +@param dst output array of the same size as src and CV_8U type. +*/ +CV_EXPORTS_W void inRange(InputArray src, InputArray lowerb, + InputArray upperb, OutputArray dst); + +/** @brief Performs the per-element comparison of two arrays or an array and scalar value. + +The function compares: +* Elements of two arrays when src1 and src2 have the same size: + \f[\texttt{dst} (I) = \texttt{src1} (I) \,\texttt{cmpop}\, \texttt{src2} (I)\f] +* Elements of src1 with a scalar src2 when src2 is constructed from + Scalar or has a single element: + \f[\texttt{dst} (I) = \texttt{src1}(I) \,\texttt{cmpop}\, \texttt{src2}\f] +* src1 with elements of src2 when src1 is constructed from Scalar or + has a single element: + \f[\texttt{dst} (I) = \texttt{src1} \,\texttt{cmpop}\, \texttt{src2} (I)\f] +When the comparison result is true, the corresponding element of output +array is set to 255. The comparison operations can be replaced with the +equivalent matrix expressions: +@code{.cpp} + Mat dst1 = src1 >= src2; + Mat dst2 = src1 < 8; + ... +@endcode +@param src1 first input array or a scalar; when it is an array, it must have a single channel. +@param src2 second input array or a scalar; when it is an array, it must have a single channel. +@param dst output array of type ref CV_8U that has the same size and the same number of channels as + the input arrays. +@param cmpop a flag, that specifies correspondence between the arrays (cv::CmpTypes) +@sa checkRange, min, max, threshold +*/ +CV_EXPORTS_W void compare(InputArray src1, InputArray src2, OutputArray dst, int cmpop); + +/** @brief Calculates per-element minimum of two arrays or an array and a scalar. + +The function cv::min calculates the per-element minimum of two arrays: +\f[\texttt{dst} (I)= \min ( \texttt{src1} (I), \texttt{src2} (I))\f] +or array and a scalar: +\f[\texttt{dst} (I)= \min ( \texttt{src1} (I), \texttt{value} )\f] +@param src1 first input array. +@param src2 second input array of the same size and type as src1. +@param dst output array of the same size and type as src1. +@sa max, compare, inRange, minMaxLoc +*/ +CV_EXPORTS_W void min(InputArray src1, InputArray src2, OutputArray dst); +/** @overload +needed to avoid conflicts with const _Tp& std::min(const _Tp&, const _Tp&, _Compare) +*/ +CV_EXPORTS void min(const Mat& src1, const Mat& src2, Mat& dst); +/** @overload +needed to avoid conflicts with const _Tp& std::min(const _Tp&, const _Tp&, _Compare) +*/ +CV_EXPORTS void min(const UMat& src1, const UMat& src2, UMat& dst); + +/** @brief Calculates per-element maximum of two arrays or an array and a scalar. + +The function cv::max calculates the per-element maximum of two arrays: +\f[\texttt{dst} (I)= \max ( \texttt{src1} (I), \texttt{src2} (I))\f] +or array and a scalar: +\f[\texttt{dst} (I)= \max ( \texttt{src1} (I), \texttt{value} )\f] +@param src1 first input array. +@param src2 second input array of the same size and type as src1 . +@param dst output array of the same size and type as src1. +@sa min, compare, inRange, minMaxLoc, @ref MatrixExpressions +*/ +CV_EXPORTS_W void max(InputArray src1, InputArray src2, OutputArray dst); +/** @overload +needed to avoid conflicts with const _Tp& std::min(const _Tp&, const _Tp&, _Compare) +*/ +CV_EXPORTS void max(const Mat& src1, const Mat& src2, Mat& dst); +/** @overload +needed to avoid conflicts with const _Tp& std::min(const _Tp&, const _Tp&, _Compare) +*/ +CV_EXPORTS void max(const UMat& src1, const UMat& src2, UMat& dst); + +/** @brief Calculates a square root of array elements. + +The function cv::sqrt calculates a square root of each input array element. +In case of multi-channel arrays, each channel is processed +independently. The accuracy is approximately the same as of the built-in +std::sqrt . +@param src input floating-point array. +@param dst output array of the same size and type as src. +*/ +CV_EXPORTS_W void sqrt(InputArray src, OutputArray dst); + +/** @brief Raises every array element to a power. + +The function cv::pow raises every element of the input array to power : +\f[\texttt{dst} (I) = \fork{\texttt{src}(I)^{power}}{if \(\texttt{power}\) is integer}{|\texttt{src}(I)|^{power}}{otherwise}\f] + +So, for a non-integer power exponent, the absolute values of input array +elements are used. However, it is possible to get true values for +negative values using some extra operations. In the example below, +computing the 5th root of array src shows: +@code{.cpp} + Mat mask = src < 0; + pow(src, 1./5, dst); + subtract(Scalar::all(0), dst, dst, mask); +@endcode +For some values of power, such as integer values, 0.5 and -0.5, +specialized faster algorithms are used. + +Special values (NaN, Inf) are not handled. +@param src input array. +@param power exponent of power. +@param dst output array of the same size and type as src. +@sa sqrt, exp, log, cartToPolar, polarToCart +*/ +CV_EXPORTS_W void pow(InputArray src, double power, OutputArray dst); + +/** @brief Calculates the exponent of every array element. + +The function cv::exp calculates the exponent of every element of the input +array: +\f[\texttt{dst} [I] = e^{ src(I) }\f] + +The maximum relative error is about 7e-6 for single-precision input and +less than 1e-10 for double-precision input. Currently, the function +converts denormalized values to zeros on output. Special values (NaN, +Inf) are not handled. +@param src input array. +@param dst output array of the same size and type as src. +@sa log , cartToPolar , polarToCart , phase , pow , sqrt , magnitude +*/ +CV_EXPORTS_W void exp(InputArray src, OutputArray dst); + +/** @brief Calculates the natural logarithm of every array element. + +The function cv::log calculates the natural logarithm of every element of the input array: +\f[\texttt{dst} (I) = \log (\texttt{src}(I)) \f] + +Output on zero, negative and special (NaN, Inf) values is undefined. + +@param src input array. +@param dst output array of the same size and type as src . +@sa exp, cartToPolar, polarToCart, phase, pow, sqrt, magnitude +*/ +CV_EXPORTS_W void log(InputArray src, OutputArray dst); + +/** @brief Calculates x and y coordinates of 2D vectors from their magnitude and angle. + +The function cv::polarToCart calculates the Cartesian coordinates of each 2D +vector represented by the corresponding elements of magnitude and angle: +\f[\begin{array}{l} \texttt{x} (I) = \texttt{magnitude} (I) \cos ( \texttt{angle} (I)) \\ \texttt{y} (I) = \texttt{magnitude} (I) \sin ( \texttt{angle} (I)) \\ \end{array}\f] + +The relative accuracy of the estimated coordinates is about 1e-6. +@param magnitude input floating-point array of magnitudes of 2D vectors; +it can be an empty matrix (=Mat()), in this case, the function assumes +that all the magnitudes are =1; if it is not empty, it must have the +same size and type as angle. +@param angle input floating-point array of angles of 2D vectors. +@param x output array of x-coordinates of 2D vectors; it has the same +size and type as angle. +@param y output array of y-coordinates of 2D vectors; it has the same +size and type as angle. +@param angleInDegrees when true, the input angles are measured in +degrees, otherwise, they are measured in radians. +@sa cartToPolar, magnitude, phase, exp, log, pow, sqrt +*/ +CV_EXPORTS_W void polarToCart(InputArray magnitude, InputArray angle, + OutputArray x, OutputArray y, bool angleInDegrees = false); + +/** @brief Calculates the magnitude and angle of 2D vectors. + +The function cv::cartToPolar calculates either the magnitude, angle, or both +for every 2D vector (x(I),y(I)): +\f[\begin{array}{l} \texttt{magnitude} (I)= \sqrt{\texttt{x}(I)^2+\texttt{y}(I)^2} , \\ \texttt{angle} (I)= \texttt{atan2} ( \texttt{y} (I), \texttt{x} (I))[ \cdot180 / \pi ] \end{array}\f] + +The angles are calculated with accuracy about 0.3 degrees. For the point +(0,0), the angle is set to 0. +@param x array of x-coordinates; this must be a single-precision or +double-precision floating-point array. +@param y array of y-coordinates, that must have the same size and same type as x. +@param magnitude output array of magnitudes of the same size and type as x. +@param angle output array of angles that has the same size and type as +x; the angles are measured in radians (from 0 to 2\*Pi) or in degrees (0 to 360 degrees). +@param angleInDegrees a flag, indicating whether the angles are measured +in radians (which is by default), or in degrees. +@sa Sobel, Scharr +*/ +CV_EXPORTS_W void cartToPolar(InputArray x, InputArray y, + OutputArray magnitude, OutputArray angle, + bool angleInDegrees = false); + +/** @brief Calculates the rotation angle of 2D vectors. + +The function cv::phase calculates the rotation angle of each 2D vector that +is formed from the corresponding elements of x and y : +\f[\texttt{angle} (I) = \texttt{atan2} ( \texttt{y} (I), \texttt{x} (I))\f] + +The angle estimation accuracy is about 0.3 degrees. When x(I)=y(I)=0 , +the corresponding angle(I) is set to 0. +@param x input floating-point array of x-coordinates of 2D vectors. +@param y input array of y-coordinates of 2D vectors; it must have the +same size and the same type as x. +@param angle output array of vector angles; it has the same size and +same type as x . +@param angleInDegrees when true, the function calculates the angle in +degrees, otherwise, they are measured in radians. +*/ +CV_EXPORTS_W void phase(InputArray x, InputArray y, OutputArray angle, + bool angleInDegrees = false); + +/** @brief Calculates the magnitude of 2D vectors. + +The function cv::magnitude calculates the magnitude of 2D vectors formed +from the corresponding elements of x and y arrays: +\f[\texttt{dst} (I) = \sqrt{\texttt{x}(I)^2 + \texttt{y}(I)^2}\f] +@param x floating-point array of x-coordinates of the vectors. +@param y floating-point array of y-coordinates of the vectors; it must +have the same size as x. +@param magnitude output array of the same size and type as x. +@sa cartToPolar, polarToCart, phase, sqrt +*/ +CV_EXPORTS_W void magnitude(InputArray x, InputArray y, OutputArray magnitude); + +/** @brief Checks every element of an input array for invalid values. + +The function cv::checkRange checks that every array element is neither NaN nor infinite. When minVal \> +-DBL_MAX and maxVal \< DBL_MAX, the function also checks that each value is between minVal and +maxVal. In case of multi-channel arrays, each channel is processed independently. If some values +are out of range, position of the first outlier is stored in pos (when pos != NULL). Then, the +function either returns false (when quiet=true) or throws an exception. +@param a input array. +@param quiet a flag, indicating whether the functions quietly return false when the array elements +are out of range or they throw an exception. +@param pos optional output parameter, when not NULL, must be a pointer to array of src.dims +elements. +@param minVal inclusive lower boundary of valid values range. +@param maxVal exclusive upper boundary of valid values range. +*/ +CV_EXPORTS_W bool checkRange(InputArray a, bool quiet = true, CV_OUT Point* pos = 0, + double minVal = -DBL_MAX, double maxVal = DBL_MAX); + +/** @brief converts NaNs to the given number +@param a input/output matrix (CV_32F type). +@param val value to convert the NaNs +*/ +CV_EXPORTS_W void patchNaNs(InputOutputArray a, double val = 0); + +/** @brief Performs generalized matrix multiplication. + +The function cv::gemm performs generalized matrix multiplication similar to the +gemm functions in BLAS level 3. For example, +`gemm(src1, src2, alpha, src3, beta, dst, GEMM_1_T + GEMM_3_T)` +corresponds to +\f[\texttt{dst} = \texttt{alpha} \cdot \texttt{src1} ^T \cdot \texttt{src2} + \texttt{beta} \cdot \texttt{src3} ^T\f] + +In case of complex (two-channel) data, performed a complex matrix +multiplication. + +The function can be replaced with a matrix expression. For example, the +above call can be replaced with: +@code{.cpp} + dst = alpha*src1.t()*src2 + beta*src3.t(); +@endcode +@param src1 first multiplied input matrix that could be real(CV_32FC1, +CV_64FC1) or complex(CV_32FC2, CV_64FC2). +@param src2 second multiplied input matrix of the same type as src1. +@param alpha weight of the matrix product. +@param src3 third optional delta matrix added to the matrix product; it +should have the same type as src1 and src2. +@param beta weight of src3. +@param dst output matrix; it has the proper size and the same type as +input matrices. +@param flags operation flags (cv::GemmFlags) +@sa mulTransposed , transform +*/ +CV_EXPORTS_W void gemm(InputArray src1, InputArray src2, double alpha, + InputArray src3, double beta, OutputArray dst, int flags = 0); + +/** @brief Calculates the product of a matrix and its transposition. + +The function cv::mulTransposed calculates the product of src and its +transposition: +\f[\texttt{dst} = \texttt{scale} ( \texttt{src} - \texttt{delta} )^T ( \texttt{src} - \texttt{delta} )\f] +if aTa=true , and +\f[\texttt{dst} = \texttt{scale} ( \texttt{src} - \texttt{delta} ) ( \texttt{src} - \texttt{delta} )^T\f] +otherwise. The function is used to calculate the covariance matrix. With +zero delta, it can be used as a faster substitute for general matrix +product A\*B when B=A' +@param src input single-channel matrix. Note that unlike gemm, the +function can multiply not only floating-point matrices. +@param dst output square matrix. +@param aTa Flag specifying the multiplication ordering. See the +description below. +@param delta Optional delta matrix subtracted from src before the +multiplication. When the matrix is empty ( delta=noArray() ), it is +assumed to be zero, that is, nothing is subtracted. If it has the same +size as src , it is simply subtracted. Otherwise, it is "repeated" (see +repeat ) to cover the full src and then subtracted. Type of the delta +matrix, when it is not empty, must be the same as the type of created +output matrix. See the dtype parameter description below. +@param scale Optional scale factor for the matrix product. +@param dtype Optional type of the output matrix. When it is negative, +the output matrix will have the same type as src . Otherwise, it will be +type=CV_MAT_DEPTH(dtype) that should be either CV_32F or CV_64F . +@sa calcCovarMatrix, gemm, repeat, reduce +*/ +CV_EXPORTS_W void mulTransposed( InputArray src, OutputArray dst, bool aTa, + InputArray delta = noArray(), + double scale = 1, int dtype = -1 ); + +/** @brief Transposes a matrix. + +The function cv::transpose transposes the matrix src : +\f[\texttt{dst} (i,j) = \texttt{src} (j,i)\f] +@note No complex conjugation is done in case of a complex matrix. It +should be done separately if needed. +@param src input array. +@param dst output array of the same type as src. +*/ +CV_EXPORTS_W void transpose(InputArray src, OutputArray dst); + +/** @brief Transpose for n-dimensional matrices. + * + * @note Input should be continuous single-channel matrix. + * @param src input array. + * @param order a permutation of [0,1,..,N-1] where N is the number of axes of src. + * The i’th axis of dst will correspond to the axis numbered order[i] of the input. + * @param dst output array of the same type as src. + */ +CV_EXPORTS_W void transposeND(InputArray src, const std::vector& order, OutputArray dst); + +/** @brief Performs the matrix transformation of every array element. + +The function cv::transform performs the matrix transformation of every +element of the array src and stores the results in dst : +\f[\texttt{dst} (I) = \texttt{m} \cdot \texttt{src} (I)\f] +(when m.cols=src.channels() ), or +\f[\texttt{dst} (I) = \texttt{m} \cdot [ \texttt{src} (I); 1]\f] +(when m.cols=src.channels()+1 ) + +Every element of the N -channel array src is interpreted as N -element +vector that is transformed using the M x N or M x (N+1) matrix m to +M-element vector - the corresponding element of the output array dst . + +The function may be used for geometrical transformation of +N -dimensional points, arbitrary linear color space transformation (such +as various kinds of RGB to YUV transforms), shuffling the image +channels, and so forth. +@param src input array that must have as many channels (1 to 4) as +m.cols or m.cols-1. +@param dst output array of the same size and depth as src; it has as +many channels as m.rows. +@param m transformation 2x2 or 2x3 floating-point matrix. +@sa perspectiveTransform, getAffineTransform, estimateAffine2D, warpAffine, warpPerspective +*/ +CV_EXPORTS_W void transform(InputArray src, OutputArray dst, InputArray m ); + +/** @brief Performs the perspective matrix transformation of vectors. + +The function cv::perspectiveTransform transforms every element of src by +treating it as a 2D or 3D vector, in the following way: +\f[(x, y, z) \rightarrow (x'/w, y'/w, z'/w)\f] +where +\f[(x', y', z', w') = \texttt{mat} \cdot \begin{bmatrix} x & y & z & 1 \end{bmatrix}\f] +and +\f[w = \fork{w'}{if \(w' \ne 0\)}{\infty}{otherwise}\f] + +Here a 3D vector transformation is shown. In case of a 2D vector +transformation, the z component is omitted. + +@note The function transforms a sparse set of 2D or 3D vectors. If you +want to transform an image using perspective transformation, use +warpPerspective . If you have an inverse problem, that is, you want to +compute the most probable perspective transformation out of several +pairs of corresponding points, you can use getPerspectiveTransform or +findHomography . +@param src input two-channel or three-channel floating-point array; each +element is a 2D/3D vector to be transformed. +@param dst output array of the same size and type as src. +@param m 3x3 or 4x4 floating-point transformation matrix. +@sa transform, warpPerspective, getPerspectiveTransform, findHomography +*/ +CV_EXPORTS_W void perspectiveTransform(InputArray src, OutputArray dst, InputArray m ); + +/** @brief Copies the lower or the upper half of a square matrix to its another half. + +The function cv::completeSymm copies the lower or the upper half of a square matrix to +its another half. The matrix diagonal remains unchanged: + - \f$\texttt{m}_{ij}=\texttt{m}_{ji}\f$ for \f$i > j\f$ if + lowerToUpper=false + - \f$\texttt{m}_{ij}=\texttt{m}_{ji}\f$ for \f$i < j\f$ if + lowerToUpper=true + +@param m input-output floating-point square matrix. +@param lowerToUpper operation flag; if true, the lower half is copied to +the upper half. Otherwise, the upper half is copied to the lower half. +@sa flip, transpose +*/ +CV_EXPORTS_W void completeSymm(InputOutputArray m, bool lowerToUpper = false); + +/** @brief Initializes a scaled identity matrix. + +The function cv::setIdentity initializes a scaled identity matrix: +\f[\texttt{mtx} (i,j)= \fork{\texttt{value}}{ if \(i=j\)}{0}{otherwise}\f] + +The function can also be emulated using the matrix initializers and the +matrix expressions: +@code + Mat A = Mat::eye(4, 3, CV_32F)*5; + // A will be set to [[5, 0, 0], [0, 5, 0], [0, 0, 5], [0, 0, 0]] +@endcode +@param mtx matrix to initialize (not necessarily square). +@param s value to assign to diagonal elements. +@sa Mat::zeros, Mat::ones, Mat::setTo, Mat::operator= +*/ +CV_EXPORTS_W void setIdentity(InputOutputArray mtx, const Scalar& s = Scalar(1)); + +/** @brief Returns the determinant of a square floating-point matrix. + +The function cv::determinant calculates and returns the determinant of the +specified matrix. For small matrices ( mtx.cols=mtx.rows\<=3 ), the +direct method is used. For larger matrices, the function uses LU +factorization with partial pivoting. + +For symmetric positively-determined matrices, it is also possible to use +eigen decomposition to calculate the determinant. +@param mtx input matrix that must have CV_32FC1 or CV_64FC1 type and +square size. +@sa trace, invert, solve, eigen, @ref MatrixExpressions +*/ +CV_EXPORTS_W double determinant(InputArray mtx); + +/** @brief Returns the trace of a matrix. + +The function cv::trace returns the sum of the diagonal elements of the +matrix mtx . +\f[\mathrm{tr} ( \texttt{mtx} ) = \sum _i \texttt{mtx} (i,i)\f] +@param mtx input matrix. +*/ +CV_EXPORTS_W Scalar trace(InputArray mtx); + +/** @brief Finds the inverse or pseudo-inverse of a matrix. + +The function cv::invert inverts the matrix src and stores the result in dst +. When the matrix src is singular or non-square, the function calculates +the pseudo-inverse matrix (the dst matrix) so that norm(src\*dst - I) is +minimal, where I is an identity matrix. + +In case of the #DECOMP_LU method, the function returns non-zero value if +the inverse has been successfully calculated and 0 if src is singular. + +In case of the #DECOMP_SVD method, the function returns the inverse +condition number of src (the ratio of the smallest singular value to the +largest singular value) and 0 if src is singular. The SVD method +calculates a pseudo-inverse matrix if src is singular. + +Similarly to #DECOMP_LU, the method #DECOMP_CHOLESKY works only with +non-singular square matrices that should also be symmetrical and +positively defined. In this case, the function stores the inverted +matrix in dst and returns non-zero. Otherwise, it returns 0. + +@param src input floating-point M x N matrix. +@param dst output matrix of N x M size and the same type as src. +@param flags inversion method (cv::DecompTypes) +@sa solve, SVD +*/ +CV_EXPORTS_W double invert(InputArray src, OutputArray dst, int flags = DECOMP_LU); + +/** @brief Solves one or more linear systems or least-squares problems. + +The function cv::solve solves a linear system or least-squares problem (the +latter is possible with SVD or QR methods, or by specifying the flag +#DECOMP_NORMAL ): +\f[\texttt{dst} = \arg \min _X \| \texttt{src1} \cdot \texttt{X} - \texttt{src2} \|\f] + +If #DECOMP_LU or #DECOMP_CHOLESKY method is used, the function returns 1 +if src1 (or \f$\texttt{src1}^T\texttt{src1}\f$ ) is non-singular. Otherwise, +it returns 0. In the latter case, dst is not valid. Other methods find a +pseudo-solution in case of a singular left-hand side part. + +@note If you want to find a unity-norm solution of an under-defined +singular system \f$\texttt{src1}\cdot\texttt{dst}=0\f$ , the function solve +will not do the work. Use SVD::solveZ instead. + +@param src1 input matrix on the left-hand side of the system. +@param src2 input matrix on the right-hand side of the system. +@param dst output solution. +@param flags solution (matrix inversion) method (#DecompTypes) +@sa invert, SVD, eigen +*/ +CV_EXPORTS_W bool solve(InputArray src1, InputArray src2, + OutputArray dst, int flags = DECOMP_LU); + +/** @brief Sorts each row or each column of a matrix. + +The function cv::sort sorts each matrix row or each matrix column in +ascending or descending order. So you should pass two operation flags to +get desired behaviour. If you want to sort matrix rows or columns +lexicographically, you can use STL std::sort generic function with the +proper comparison predicate. + +@param src input single-channel array. +@param dst output array of the same size and type as src. +@param flags operation flags, a combination of #SortFlags +@sa sortIdx, randShuffle +*/ +CV_EXPORTS_W void sort(InputArray src, OutputArray dst, int flags); + +/** @brief Sorts each row or each column of a matrix. + +The function cv::sortIdx sorts each matrix row or each matrix column in the +ascending or descending order. So you should pass two operation flags to +get desired behaviour. Instead of reordering the elements themselves, it +stores the indices of sorted elements in the output array. For example: +@code + Mat A = Mat::eye(3,3,CV_32F), B; + sortIdx(A, B, SORT_EVERY_ROW + SORT_ASCENDING); + // B will probably contain + // (because of equal elements in A some permutations are possible): + // [[1, 2, 0], [0, 2, 1], [0, 1, 2]] +@endcode +@param src input single-channel array. +@param dst output integer array of the same size as src. +@param flags operation flags that could be a combination of cv::SortFlags +@sa sort, randShuffle +*/ +CV_EXPORTS_W void sortIdx(InputArray src, OutputArray dst, int flags); + +/** @brief Finds the real roots of a cubic equation. + +The function solveCubic finds the real roots of a cubic equation: +- if coeffs is a 4-element vector: +\f[\texttt{coeffs} [0] x^3 + \texttt{coeffs} [1] x^2 + \texttt{coeffs} [2] x + \texttt{coeffs} [3] = 0\f] +- if coeffs is a 3-element vector: +\f[x^3 + \texttt{coeffs} [0] x^2 + \texttt{coeffs} [1] x + \texttt{coeffs} [2] = 0\f] + +The roots are stored in the roots array. +@param coeffs equation coefficients, an array of 3 or 4 elements. +@param roots output array of real roots that has 1 or 3 elements. +@return number of real roots. It can be 0, 1 or 2. +*/ +CV_EXPORTS_W int solveCubic(InputArray coeffs, OutputArray roots); + +/** @brief Finds the real or complex roots of a polynomial equation. + +The function cv::solvePoly finds real and complex roots of a polynomial equation: +\f[\texttt{coeffs} [n] x^{n} + \texttt{coeffs} [n-1] x^{n-1} + ... + \texttt{coeffs} [1] x + \texttt{coeffs} [0] = 0\f] +@param coeffs array of polynomial coefficients. +@param roots output (complex) array of roots. +@param maxIters maximum number of iterations the algorithm does. +*/ +CV_EXPORTS_W double solvePoly(InputArray coeffs, OutputArray roots, int maxIters = 300); + +/** @brief Calculates eigenvalues and eigenvectors of a symmetric matrix. + +The function cv::eigen calculates just eigenvalues, or eigenvalues and eigenvectors of the symmetric +matrix src: +@code + src*eigenvectors.row(i).t() = eigenvalues.at(i)*eigenvectors.row(i).t() +@endcode + +@note Use cv::eigenNonSymmetric for calculation of real eigenvalues and eigenvectors of non-symmetric matrix. + +@param src input matrix that must have CV_32FC1 or CV_64FC1 type, square size and be symmetrical +(src ^T^ == src). +@param eigenvalues output vector of eigenvalues of the same type as src; the eigenvalues are stored +in the descending order. +@param eigenvectors output matrix of eigenvectors; it has the same size and type as src; the +eigenvectors are stored as subsequent matrix rows, in the same order as the corresponding +eigenvalues. +@sa eigenNonSymmetric, completeSymm , PCA +*/ +CV_EXPORTS_W bool eigen(InputArray src, OutputArray eigenvalues, + OutputArray eigenvectors = noArray()); + +/** @brief Calculates eigenvalues and eigenvectors of a non-symmetric matrix (real eigenvalues only). + +@note Assumes real eigenvalues. + +The function calculates eigenvalues and eigenvectors (optional) of the square matrix src: +@code + src*eigenvectors.row(i).t() = eigenvalues.at(i)*eigenvectors.row(i).t() +@endcode + +@param src input matrix (CV_32FC1 or CV_64FC1 type). +@param eigenvalues output vector of eigenvalues (type is the same type as src). +@param eigenvectors output matrix of eigenvectors (type is the same type as src). The eigenvectors are stored as subsequent matrix rows, in the same order as the corresponding eigenvalues. +@sa eigen +*/ +CV_EXPORTS_W void eigenNonSymmetric(InputArray src, OutputArray eigenvalues, + OutputArray eigenvectors); + +/** @brief Calculates the covariance matrix of a set of vectors. + +The function cv::calcCovarMatrix calculates the covariance matrix and, optionally, the mean vector of +the set of input vectors. +@param samples samples stored as separate matrices +@param nsamples number of samples +@param covar output covariance matrix of the type ctype and square size. +@param mean input or output (depending on the flags) array as the average value of the input vectors. +@param flags operation flags as a combination of #CovarFlags +@param ctype type of the matrixl; it equals 'CV_64F' by default. +@sa PCA, mulTransposed, Mahalanobis +@todo InputArrayOfArrays +*/ +CV_EXPORTS void calcCovarMatrix( const Mat* samples, int nsamples, Mat& covar, Mat& mean, + int flags, int ctype = CV_64F); + +/** @overload +@note use #COVAR_ROWS or #COVAR_COLS flag +@param samples samples stored as rows/columns of a single matrix. +@param covar output covariance matrix of the type ctype and square size. +@param mean input or output (depending on the flags) array as the average value of the input vectors. +@param flags operation flags as a combination of #CovarFlags +@param ctype type of the matrixl; it equals 'CV_64F' by default. +*/ +CV_EXPORTS_W void calcCovarMatrix( InputArray samples, OutputArray covar, + InputOutputArray mean, int flags, int ctype = CV_64F); + +/** wrap PCA::operator() */ +CV_EXPORTS_W void PCACompute(InputArray data, InputOutputArray mean, + OutputArray eigenvectors, int maxComponents = 0); + +/** wrap PCA::operator() and add eigenvalues output parameter */ +CV_EXPORTS_AS(PCACompute2) void PCACompute(InputArray data, InputOutputArray mean, + OutputArray eigenvectors, OutputArray eigenvalues, + int maxComponents = 0); + +/** wrap PCA::operator() */ +CV_EXPORTS_W void PCACompute(InputArray data, InputOutputArray mean, + OutputArray eigenvectors, double retainedVariance); + +/** wrap PCA::operator() and add eigenvalues output parameter */ +CV_EXPORTS_AS(PCACompute2) void PCACompute(InputArray data, InputOutputArray mean, + OutputArray eigenvectors, OutputArray eigenvalues, + double retainedVariance); + +/** wrap PCA::project */ +CV_EXPORTS_W void PCAProject(InputArray data, InputArray mean, + InputArray eigenvectors, OutputArray result); + +/** wrap PCA::backProject */ +CV_EXPORTS_W void PCABackProject(InputArray data, InputArray mean, + InputArray eigenvectors, OutputArray result); + +/** wrap SVD::compute */ +CV_EXPORTS_W void SVDecomp( InputArray src, OutputArray w, OutputArray u, OutputArray vt, int flags = 0 ); + +/** wrap SVD::backSubst */ +CV_EXPORTS_W void SVBackSubst( InputArray w, InputArray u, InputArray vt, + InputArray rhs, OutputArray dst ); + +/** @brief Calculates the Mahalanobis distance between two vectors. + +The function cv::Mahalanobis calculates and returns the weighted distance between two vectors: +\f[d( \texttt{vec1} , \texttt{vec2} )= \sqrt{\sum_{i,j}{\texttt{icovar(i,j)}\cdot(\texttt{vec1}(I)-\texttt{vec2}(I))\cdot(\texttt{vec1(j)}-\texttt{vec2(j)})} }\f] +The covariance matrix may be calculated using the #calcCovarMatrix function and then inverted using +the invert function (preferably using the #DECOMP_SVD method, as the most accurate). +@param v1 first 1D input vector. +@param v2 second 1D input vector. +@param icovar inverse covariance matrix. +*/ +CV_EXPORTS_W double Mahalanobis(InputArray v1, InputArray v2, InputArray icovar); + +/** @brief Performs a forward or inverse Discrete Fourier transform of a 1D or 2D floating-point array. + +The function cv::dft performs one of the following: +- Forward the Fourier transform of a 1D vector of N elements: + \f[Y = F^{(N)} \cdot X,\f] + where \f$F^{(N)}_{jk}=\exp(-2\pi i j k/N)\f$ and \f$i=\sqrt{-1}\f$ +- Inverse the Fourier transform of a 1D vector of N elements: + \f[\begin{array}{l} X'= \left (F^{(N)} \right )^{-1} \cdot Y = \left (F^{(N)} \right )^* \cdot y \\ X = (1/N) \cdot X, \end{array}\f] + where \f$F^*=\left(\textrm{Re}(F^{(N)})-\textrm{Im}(F^{(N)})\right)^T\f$ +- Forward the 2D Fourier transform of a M x N matrix: + \f[Y = F^{(M)} \cdot X \cdot F^{(N)}\f] +- Inverse the 2D Fourier transform of a M x N matrix: + \f[\begin{array}{l} X'= \left (F^{(M)} \right )^* \cdot Y \cdot \left (F^{(N)} \right )^* \\ X = \frac{1}{M \cdot N} \cdot X' \end{array}\f] + +In case of real (single-channel) data, the output spectrum of the forward Fourier transform or input +spectrum of the inverse Fourier transform can be represented in a packed format called *CCS* +(complex-conjugate-symmetrical). It was borrowed from IPL (Intel\* Image Processing Library). Here +is how 2D *CCS* spectrum looks: +\f[\begin{bmatrix} Re Y_{0,0} & Re Y_{0,1} & Im Y_{0,1} & Re Y_{0,2} & Im Y_{0,2} & \cdots & Re Y_{0,N/2-1} & Im Y_{0,N/2-1} & Re Y_{0,N/2} \\ Re Y_{1,0} & Re Y_{1,1} & Im Y_{1,1} & Re Y_{1,2} & Im Y_{1,2} & \cdots & Re Y_{1,N/2-1} & Im Y_{1,N/2-1} & Re Y_{1,N/2} \\ Im Y_{1,0} & Re Y_{2,1} & Im Y_{2,1} & Re Y_{2,2} & Im Y_{2,2} & \cdots & Re Y_{2,N/2-1} & Im Y_{2,N/2-1} & Im Y_{1,N/2} \\ \hdotsfor{9} \\ Re Y_{M/2-1,0} & Re Y_{M-3,1} & Im Y_{M-3,1} & \hdotsfor{3} & Re Y_{M-3,N/2-1} & Im Y_{M-3,N/2-1}& Re Y_{M/2-1,N/2} \\ Im Y_{M/2-1,0} & Re Y_{M-2,1} & Im Y_{M-2,1} & \hdotsfor{3} & Re Y_{M-2,N/2-1} & Im Y_{M-2,N/2-1}& Im Y_{M/2-1,N/2} \\ Re Y_{M/2,0} & Re Y_{M-1,1} & Im Y_{M-1,1} & \hdotsfor{3} & Re Y_{M-1,N/2-1} & Im Y_{M-1,N/2-1}& Re Y_{M/2,N/2} \end{bmatrix}\f] + +In case of 1D transform of a real vector, the output looks like the first row of the matrix above. + +So, the function chooses an operation mode depending on the flags and size of the input array: +- If #DFT_ROWS is set or the input array has a single row or single column, the function + performs a 1D forward or inverse transform of each row of a matrix when #DFT_ROWS is set. + Otherwise, it performs a 2D transform. +- If the input array is real and #DFT_INVERSE is not set, the function performs a forward 1D or + 2D transform: + - When #DFT_COMPLEX_OUTPUT is set, the output is a complex matrix of the same size as + input. + - When #DFT_COMPLEX_OUTPUT is not set, the output is a real matrix of the same size as + input. In case of 2D transform, it uses the packed format as shown above. In case of a + single 1D transform, it looks like the first row of the matrix above. In case of + multiple 1D transforms (when using the #DFT_ROWS flag), each row of the output matrix + looks like the first row of the matrix above. +- If the input array is complex and either #DFT_INVERSE or #DFT_REAL_OUTPUT are not set, the + output is a complex array of the same size as input. The function performs a forward or + inverse 1D or 2D transform of the whole input array or each row of the input array + independently, depending on the flags DFT_INVERSE and DFT_ROWS. +- When #DFT_INVERSE is set and the input array is real, or it is complex but #DFT_REAL_OUTPUT + is set, the output is a real array of the same size as input. The function performs a 1D or 2D + inverse transformation of the whole input array or each individual row, depending on the flags + #DFT_INVERSE and #DFT_ROWS. + +If #DFT_SCALE is set, the scaling is done after the transformation. + +Unlike dct , the function supports arrays of arbitrary size. But only those arrays are processed +efficiently, whose sizes can be factorized in a product of small prime numbers (2, 3, and 5 in the +current implementation). Such an efficient DFT size can be calculated using the getOptimalDFTSize +method. + +The sample below illustrates how to calculate a DFT-based convolution of two 2D real arrays: +@code + void convolveDFT(InputArray A, InputArray B, OutputArray C) + { + // reallocate the output array if needed + C.create(abs(A.rows - B.rows)+1, abs(A.cols - B.cols)+1, A.type()); + Size dftSize; + // calculate the size of DFT transform + dftSize.width = getOptimalDFTSize(A.cols + B.cols - 1); + dftSize.height = getOptimalDFTSize(A.rows + B.rows - 1); + + // allocate temporary buffers and initialize them with 0's + Mat tempA(dftSize, A.type(), Scalar::all(0)); + Mat tempB(dftSize, B.type(), Scalar::all(0)); + + // copy A and B to the top-left corners of tempA and tempB, respectively + Mat roiA(tempA, Rect(0,0,A.cols,A.rows)); + A.copyTo(roiA); + Mat roiB(tempB, Rect(0,0,B.cols,B.rows)); + B.copyTo(roiB); + + // now transform the padded A & B in-place; + // use "nonzeroRows" hint for faster processing + dft(tempA, tempA, 0, A.rows); + dft(tempB, tempB, 0, B.rows); + + // multiply the spectrums; + // the function handles packed spectrum representations well + mulSpectrums(tempA, tempB, tempA); + + // transform the product back from the frequency domain. + // Even though all the result rows will be non-zero, + // you need only the first C.rows of them, and thus you + // pass nonzeroRows == C.rows + dft(tempA, tempA, DFT_INVERSE + DFT_SCALE, C.rows); + + // now copy the result back to C. + tempA(Rect(0, 0, C.cols, C.rows)).copyTo(C); + + // all the temporary buffers will be deallocated automatically + } +@endcode +To optimize this sample, consider the following approaches: +- Since nonzeroRows != 0 is passed to the forward transform calls and since A and B are copied to + the top-left corners of tempA and tempB, respectively, it is not necessary to clear the whole + tempA and tempB. It is only necessary to clear the tempA.cols - A.cols ( tempB.cols - B.cols) + rightmost columns of the matrices. +- This DFT-based convolution does not have to be applied to the whole big arrays, especially if B + is significantly smaller than A or vice versa. Instead, you can calculate convolution by parts. + To do this, you need to split the output array C into multiple tiles. For each tile, estimate + which parts of A and B are required to calculate convolution in this tile. If the tiles in C are + too small, the speed will decrease a lot because of repeated work. In the ultimate case, when + each tile in C is a single pixel, the algorithm becomes equivalent to the naive convolution + algorithm. If the tiles are too big, the temporary arrays tempA and tempB become too big and + there is also a slowdown because of bad cache locality. So, there is an optimal tile size + somewhere in the middle. +- If different tiles in C can be calculated in parallel and, thus, the convolution is done by + parts, the loop can be threaded. + +All of the above improvements have been implemented in #matchTemplate and #filter2D . Therefore, by +using them, you can get the performance even better than with the above theoretically optimal +implementation. Though, those two functions actually calculate cross-correlation, not convolution, +so you need to "flip" the second convolution operand B vertically and horizontally using flip . +@note +- An example using the discrete fourier transform can be found at + opencv_source_code/samples/cpp/dft.cpp +- (Python) An example using the dft functionality to perform Wiener deconvolution can be found + at opencv_source/samples/python/deconvolution.py +- (Python) An example rearranging the quadrants of a Fourier image can be found at + opencv_source/samples/python/dft.py +@param src input array that could be real or complex. +@param dst output array whose size and type depends on the flags . +@param flags transformation flags, representing a combination of the #DftFlags +@param nonzeroRows when the parameter is not zero, the function assumes that only the first +nonzeroRows rows of the input array (#DFT_INVERSE is not set) or only the first nonzeroRows of the +output array (#DFT_INVERSE is set) contain non-zeros, thus, the function can handle the rest of the +rows more efficiently and save some time; this technique is very useful for calculating array +cross-correlation or convolution using DFT. +@sa dct , getOptimalDFTSize , mulSpectrums, filter2D , matchTemplate , flip , cartToPolar , +magnitude , phase +*/ +CV_EXPORTS_W void dft(InputArray src, OutputArray dst, int flags = 0, int nonzeroRows = 0); + +/** @brief Calculates the inverse Discrete Fourier Transform of a 1D or 2D array. + +idft(src, dst, flags) is equivalent to dft(src, dst, flags | #DFT_INVERSE) . +@note None of dft and idft scales the result by default. So, you should pass #DFT_SCALE to one of +dft or idft explicitly to make these transforms mutually inverse. +@sa dft, dct, idct, mulSpectrums, getOptimalDFTSize +@param src input floating-point real or complex array. +@param dst output array whose size and type depend on the flags. +@param flags operation flags (see dft and #DftFlags). +@param nonzeroRows number of dst rows to process; the rest of the rows have undefined content (see +the convolution sample in dft description. +*/ +CV_EXPORTS_W void idft(InputArray src, OutputArray dst, int flags = 0, int nonzeroRows = 0); + +/** @brief Performs a forward or inverse discrete Cosine transform of 1D or 2D array. + +The function cv::dct performs a forward or inverse discrete Cosine transform (DCT) of a 1D or 2D +floating-point array: +- Forward Cosine transform of a 1D vector of N elements: + \f[Y = C^{(N)} \cdot X\f] + where + \f[C^{(N)}_{jk}= \sqrt{\alpha_j/N} \cos \left ( \frac{\pi(2k+1)j}{2N} \right )\f] + and + \f$\alpha_0=1\f$, \f$\alpha_j=2\f$ for *j \> 0*. +- Inverse Cosine transform of a 1D vector of N elements: + \f[X = \left (C^{(N)} \right )^{-1} \cdot Y = \left (C^{(N)} \right )^T \cdot Y\f] + (since \f$C^{(N)}\f$ is an orthogonal matrix, \f$C^{(N)} \cdot \left(C^{(N)}\right)^T = I\f$ ) +- Forward 2D Cosine transform of M x N matrix: + \f[Y = C^{(N)} \cdot X \cdot \left (C^{(N)} \right )^T\f] +- Inverse 2D Cosine transform of M x N matrix: + \f[X = \left (C^{(N)} \right )^T \cdot X \cdot C^{(N)}\f] + +The function chooses the mode of operation by looking at the flags and size of the input array: +- If (flags & #DCT_INVERSE) == 0 , the function does a forward 1D or 2D transform. Otherwise, it + is an inverse 1D or 2D transform. +- If (flags & #DCT_ROWS) != 0 , the function performs a 1D transform of each row. +- If the array is a single column or a single row, the function performs a 1D transform. +- If none of the above is true, the function performs a 2D transform. + +@note Currently dct supports even-size arrays (2, 4, 6 ...). For data analysis and approximation, you +can pad the array when necessary. +Also, the function performance depends very much, and not monotonically, on the array size (see +getOptimalDFTSize ). In the current implementation DCT of a vector of size N is calculated via DFT +of a vector of size N/2 . Thus, the optimal DCT size N1 \>= N can be calculated as: +@code + size_t getOptimalDCTSize(size_t N) { return 2*getOptimalDFTSize((N+1)/2); } + N1 = getOptimalDCTSize(N); +@endcode +@param src input floating-point array. +@param dst output array of the same size and type as src . +@param flags transformation flags as a combination of cv::DftFlags (DCT_*) +@sa dft , getOptimalDFTSize , idct +*/ +CV_EXPORTS_W void dct(InputArray src, OutputArray dst, int flags = 0); + +/** @brief Calculates the inverse Discrete Cosine Transform of a 1D or 2D array. + +idct(src, dst, flags) is equivalent to dct(src, dst, flags | DCT_INVERSE). +@param src input floating-point single-channel array. +@param dst output array of the same size and type as src. +@param flags operation flags. +@sa dct, dft, idft, getOptimalDFTSize +*/ +CV_EXPORTS_W void idct(InputArray src, OutputArray dst, int flags = 0); + +/** @brief Performs the per-element multiplication of two Fourier spectrums. + +The function cv::mulSpectrums performs the per-element multiplication of the two CCS-packed or complex +matrices that are results of a real or complex Fourier transform. + +The function, together with dft and idft , may be used to calculate convolution (pass conjB=false ) +or correlation (pass conjB=true ) of two arrays rapidly. When the arrays are complex, they are +simply multiplied (per element) with an optional conjugation of the second-array elements. When the +arrays are real, they are assumed to be CCS-packed (see dft for details). +@param a first input array. +@param b second input array of the same size and type as src1 . +@param c output array of the same size and type as src1 . +@param flags operation flags; currently, the only supported flag is cv::DFT_ROWS, which indicates that +each row of src1 and src2 is an independent 1D Fourier spectrum. If you do not want to use this flag, then simply add a `0` as value. +@param conjB optional flag that conjugates the second input array before the multiplication (true) +or not (false). +*/ +CV_EXPORTS_W void mulSpectrums(InputArray a, InputArray b, OutputArray c, + int flags, bool conjB = false); + +/** @brief Returns the optimal DFT size for a given vector size. + +DFT performance is not a monotonic function of a vector size. Therefore, when you calculate +convolution of two arrays or perform the spectral analysis of an array, it usually makes sense to +pad the input data with zeros to get a bit larger array that can be transformed much faster than the +original one. Arrays whose size is a power-of-two (2, 4, 8, 16, 32, ...) are the fastest to process. +Though, the arrays whose size is a product of 2's, 3's, and 5's (for example, 300 = 5\*5\*3\*2\*2) +are also processed quite efficiently. + +The function cv::getOptimalDFTSize returns the minimum number N that is greater than or equal to vecsize +so that the DFT of a vector of size N can be processed efficiently. In the current implementation N += 2 ^p^ \* 3 ^q^ \* 5 ^r^ for some integer p, q, r. + +The function returns a negative number if vecsize is too large (very close to INT_MAX ). + +While the function cannot be used directly to estimate the optimal vector size for DCT transform +(since the current DCT implementation supports only even-size vectors), it can be easily processed +as getOptimalDFTSize((vecsize+1)/2)\*2. +@param vecsize vector size. +@sa dft , dct , idft , idct , mulSpectrums +*/ +CV_EXPORTS_W int getOptimalDFTSize(int vecsize); + +/** @brief Returns the default random number generator. + +The function cv::theRNG returns the default random number generator. For each thread, there is a +separate random number generator, so you can use the function safely in multi-thread environments. +If you just need to get a single random number using this generator or initialize an array, you can +use randu or randn instead. But if you are going to generate many random numbers inside a loop, it +is much faster to use this function to retrieve the generator and then use RNG::operator _Tp() . +@sa RNG, randu, randn +*/ +CV_EXPORTS RNG& theRNG(); + +/** @brief Sets state of default random number generator. + +The function cv::setRNGSeed sets state of default random number generator to custom value. +@param seed new state for default random number generator +@sa RNG, randu, randn +*/ +CV_EXPORTS_W void setRNGSeed(int seed); + +/** @brief Generates a single uniformly-distributed random number or an array of random numbers. + +Non-template variant of the function fills the matrix dst with uniformly-distributed +random numbers from the specified range: +\f[\texttt{low} _c \leq \texttt{dst} (I)_c < \texttt{high} _c\f] +@param dst output array of random numbers; the array must be pre-allocated. +@param low inclusive lower boundary of the generated random numbers. +@param high exclusive upper boundary of the generated random numbers. +@sa RNG, randn, theRNG +*/ +CV_EXPORTS_W void randu(InputOutputArray dst, InputArray low, InputArray high); + +/** @brief Fills the array with normally distributed random numbers. + +The function cv::randn fills the matrix dst with normally distributed random numbers with the specified +mean vector and the standard deviation matrix. The generated random numbers are clipped to fit the +value range of the output array data type. +@param dst output array of random numbers; the array must be pre-allocated and have 1 to 4 channels. +@param mean mean value (expectation) of the generated random numbers. +@param stddev standard deviation of the generated random numbers; it can be either a vector (in +which case a diagonal standard deviation matrix is assumed) or a square matrix. +@sa RNG, randu +*/ +CV_EXPORTS_W void randn(InputOutputArray dst, InputArray mean, InputArray stddev); + +/** @brief Shuffles the array elements randomly. + +The function cv::randShuffle shuffles the specified 1D array by randomly choosing pairs of elements and +swapping them. The number of such swap operations will be dst.rows\*dst.cols\*iterFactor . +@param dst input/output numerical 1D array. +@param iterFactor scale factor that determines the number of random swap operations (see the details +below). +@param rng optional random number generator used for shuffling; if it is zero, theRNG () is used +instead. +@sa RNG, sort +*/ +CV_EXPORTS_W void randShuffle(InputOutputArray dst, double iterFactor = 1., RNG* rng = 0); + +/** @brief Principal Component Analysis + +The class is used to calculate a special basis for a set of vectors. The +basis will consist of eigenvectors of the covariance matrix calculated +from the input set of vectors. The class %PCA can also transform +vectors to/from the new coordinate space defined by the basis. Usually, +in this new coordinate system, each vector from the original set (and +any linear combination of such vectors) can be quite accurately +approximated by taking its first few components, corresponding to the +eigenvectors of the largest eigenvalues of the covariance matrix. +Geometrically it means that you calculate a projection of the vector to +a subspace formed by a few eigenvectors corresponding to the dominant +eigenvalues of the covariance matrix. And usually such a projection is +very close to the original vector. So, you can represent the original +vector from a high-dimensional space with a much shorter vector +consisting of the projected vector's coordinates in the subspace. Such a +transformation is also known as Karhunen-Loeve Transform, or KLT. +See http://en.wikipedia.org/wiki/Principal_component_analysis + +The sample below is the function that takes two matrices. The first +function stores a set of vectors (a row per vector) that is used to +calculate PCA. The second function stores another "test" set of vectors +(a row per vector). First, these vectors are compressed with PCA, then +reconstructed back, and then the reconstruction error norm is computed +and printed for each vector. : + +@code{.cpp} +using namespace cv; + +PCA compressPCA(const Mat& pcaset, int maxComponents, + const Mat& testset, Mat& compressed) +{ + PCA pca(pcaset, // pass the data + Mat(), // we do not have a pre-computed mean vector, + // so let the PCA engine to compute it + PCA::DATA_AS_ROW, // indicate that the vectors + // are stored as matrix rows + // (use PCA::DATA_AS_COL if the vectors are + // the matrix columns) + maxComponents // specify, how many principal components to retain + ); + // if there is no test data, just return the computed basis, ready-to-use + if( !testset.data ) + return pca; + CV_Assert( testset.cols == pcaset.cols ); + + compressed.create(testset.rows, maxComponents, testset.type()); + + Mat reconstructed; + for( int i = 0; i < testset.rows; i++ ) + { + Mat vec = testset.row(i), coeffs = compressed.row(i), reconstructed; + // compress the vector, the result will be stored + // in the i-th row of the output matrix + pca.project(vec, coeffs); + // and then reconstruct it + pca.backProject(coeffs, reconstructed); + // and measure the error + printf("%d. diff = %g\n", i, norm(vec, reconstructed, NORM_L2)); + } + return pca; +} +@endcode +@sa calcCovarMatrix, mulTransposed, SVD, dft, dct +*/ +class CV_EXPORTS PCA +{ +public: + enum Flags { DATA_AS_ROW = 0, //!< indicates that the input samples are stored as matrix rows + DATA_AS_COL = 1, //!< indicates that the input samples are stored as matrix columns + USE_AVG = 2 //! + }; + + /** @brief default constructor + + The default constructor initializes an empty %PCA structure. The other + constructors initialize the structure and call PCA::operator()(). + */ + PCA(); + + /** @overload + @param data input samples stored as matrix rows or matrix columns. + @param mean optional mean value; if the matrix is empty (@c noArray()), + the mean is computed from the data. + @param flags operation flags; currently the parameter is only used to + specify the data layout (PCA::Flags) + @param maxComponents maximum number of components that %PCA should + retain; by default, all the components are retained. + */ + PCA(InputArray data, InputArray mean, int flags, int maxComponents = 0); + + /** @overload + @param data input samples stored as matrix rows or matrix columns. + @param mean optional mean value; if the matrix is empty (noArray()), + the mean is computed from the data. + @param flags operation flags; currently the parameter is only used to + specify the data layout (PCA::Flags) + @param retainedVariance Percentage of variance that PCA should retain. + Using this parameter will let the PCA decided how many components to + retain but it will always keep at least 2. + */ + PCA(InputArray data, InputArray mean, int flags, double retainedVariance); + + /** @brief performs %PCA + + The operator performs %PCA of the supplied dataset. It is safe to reuse + the same PCA structure for multiple datasets. That is, if the structure + has been previously used with another dataset, the existing internal + data is reclaimed and the new @ref eigenvalues, @ref eigenvectors and @ref + mean are allocated and computed. + + The computed @ref eigenvalues are sorted from the largest to the smallest and + the corresponding @ref eigenvectors are stored as eigenvectors rows. + + @param data input samples stored as the matrix rows or as the matrix + columns. + @param mean optional mean value; if the matrix is empty (noArray()), + the mean is computed from the data. + @param flags operation flags; currently the parameter is only used to + specify the data layout. (Flags) + @param maxComponents maximum number of components that PCA should + retain; by default, all the components are retained. + */ + PCA& operator()(InputArray data, InputArray mean, int flags, int maxComponents = 0); + + /** @overload + @param data input samples stored as the matrix rows or as the matrix + columns. + @param mean optional mean value; if the matrix is empty (noArray()), + the mean is computed from the data. + @param flags operation flags; currently the parameter is only used to + specify the data layout. (PCA::Flags) + @param retainedVariance Percentage of variance that %PCA should retain. + Using this parameter will let the %PCA decided how many components to + retain but it will always keep at least 2. + */ + PCA& operator()(InputArray data, InputArray mean, int flags, double retainedVariance); + + /** @brief Projects vector(s) to the principal component subspace. + + The methods project one or more vectors to the principal component + subspace, where each vector projection is represented by coefficients in + the principal component basis. The first form of the method returns the + matrix that the second form writes to the result. So the first form can + be used as a part of expression while the second form can be more + efficient in a processing loop. + @param vec input vector(s); must have the same dimensionality and the + same layout as the input data used at %PCA phase, that is, if + DATA_AS_ROW are specified, then `vec.cols==data.cols` + (vector dimensionality) and `vec.rows` is the number of vectors to + project, and the same is true for the PCA::DATA_AS_COL case. + */ + Mat project(InputArray vec) const; + + /** @overload + @param vec input vector(s); must have the same dimensionality and the + same layout as the input data used at PCA phase, that is, if + DATA_AS_ROW are specified, then `vec.cols==data.cols` + (vector dimensionality) and `vec.rows` is the number of vectors to + project, and the same is true for the PCA::DATA_AS_COL case. + @param result output vectors; in case of PCA::DATA_AS_COL, the + output matrix has as many columns as the number of input vectors, this + means that `result.cols==vec.cols` and the number of rows match the + number of principal components (for example, `maxComponents` parameter + passed to the constructor). + */ + void project(InputArray vec, OutputArray result) const; + + /** @brief Reconstructs vectors from their PC projections. + + The methods are inverse operations to PCA::project. They take PC + coordinates of projected vectors and reconstruct the original vectors. + Unless all the principal components have been retained, the + reconstructed vectors are different from the originals. But typically, + the difference is small if the number of components is large enough (but + still much smaller than the original vector dimensionality). As a + result, PCA is used. + @param vec coordinates of the vectors in the principal component + subspace, the layout and size are the same as of PCA::project output + vectors. + */ + Mat backProject(InputArray vec) const; + + /** @overload + @param vec coordinates of the vectors in the principal component + subspace, the layout and size are the same as of PCA::project output + vectors. + @param result reconstructed vectors; the layout and size are the same as + of PCA::project input vectors. + */ + void backProject(InputArray vec, OutputArray result) const; + + /** @brief write PCA objects + + Writes @ref eigenvalues @ref eigenvectors and @ref mean to specified FileStorage + */ + void write(FileStorage& fs) const; + + /** @brief load PCA objects + + Loads @ref eigenvalues @ref eigenvectors and @ref mean from specified FileNode + */ + void read(const FileNode& fn); + + Mat eigenvectors; //!< eigenvectors of the covariation matrix + Mat eigenvalues; //!< eigenvalues of the covariation matrix + Mat mean; //!< mean value subtracted before the projection and added after the back projection +}; + +/** @example samples/cpp/pca.cpp +An example using %PCA for dimensionality reduction while maintaining an amount of variance +*/ + +/** @example samples/cpp/tutorial_code/ml/introduction_to_pca/introduction_to_pca.cpp +Check @ref tutorial_introduction_to_pca "the corresponding tutorial" for more details +*/ + +/** +@brief Linear Discriminant Analysis +@todo document this class +*/ +class CV_EXPORTS LDA +{ +public: + /** @brief constructor + Initializes a LDA with num_components (default 0). + */ + explicit LDA(int num_components = 0); + + /** Initializes and performs a Discriminant Analysis with Fisher's + Optimization Criterion on given data in src and corresponding labels + in labels. If 0 (or less) number of components are given, they are + automatically determined for given data in computation. + */ + LDA(InputArrayOfArrays src, InputArray labels, int num_components = 0); + + /** Serializes this object to a given filename. + */ + void save(const String& filename) const; + + /** Deserializes this object from a given filename. + */ + void load(const String& filename); + + /** Serializes this object to a given cv::FileStorage. + */ + void save(FileStorage& fs) const; + + /** Deserializes this object from a given cv::FileStorage. + */ + void load(const FileStorage& node); + + /** destructor + */ + ~LDA(); + + /** Compute the discriminants for data in src (row aligned) and labels. + */ + void compute(InputArrayOfArrays src, InputArray labels); + + /** Projects samples into the LDA subspace. + src may be one or more row aligned samples. + */ + Mat project(InputArray src); + + /** Reconstructs projections from the LDA subspace. + src may be one or more row aligned projections. + */ + Mat reconstruct(InputArray src); + + /** Returns the eigenvectors of this LDA. + */ + Mat eigenvectors() const { return _eigenvectors; } + + /** Returns the eigenvalues of this LDA. + */ + Mat eigenvalues() const { return _eigenvalues; } + + static Mat subspaceProject(InputArray W, InputArray mean, InputArray src); + static Mat subspaceReconstruct(InputArray W, InputArray mean, InputArray src); + +protected: + int _num_components; + Mat _eigenvectors; + Mat _eigenvalues; + void lda(InputArrayOfArrays src, InputArray labels); +}; + +/** @brief Singular Value Decomposition + +Class for computing Singular Value Decomposition of a floating-point +matrix. The Singular Value Decomposition is used to solve least-square +problems, under-determined linear systems, invert matrices, compute +condition numbers, and so on. + +If you want to compute a condition number of a matrix or an absolute value of +its determinant, you do not need `u` and `vt`. You can pass +flags=SVD::NO_UV|... . Another flag SVD::FULL_UV indicates that full-size u +and vt must be computed, which is not necessary most of the time. + +@sa invert, solve, eigen, determinant +*/ +class CV_EXPORTS SVD +{ +public: + enum Flags { + /** allow the algorithm to modify the decomposed matrix; it can save space and speed up + processing. currently ignored. */ + MODIFY_A = 1, + /** indicates that only a vector of singular values `w` is to be processed, while u and vt + will be set to empty matrices */ + NO_UV = 2, + /** when the matrix is not square, by default the algorithm produces u and vt matrices of + sufficiently large size for the further A reconstruction; if, however, FULL_UV flag is + specified, u and vt will be full-size square orthogonal matrices.*/ + FULL_UV = 4 + }; + + /** @brief the default constructor + + initializes an empty SVD structure + */ + SVD(); + + /** @overload + initializes an empty SVD structure and then calls SVD::operator() + @param src decomposed matrix. The depth has to be CV_32F or CV_64F. + @param flags operation flags (SVD::Flags) + */ + SVD( InputArray src, int flags = 0 ); + + /** @brief the operator that performs SVD. The previously allocated u, w and vt are released. + + The operator performs the singular value decomposition of the supplied + matrix. The u,`vt` , and the vector of singular values w are stored in + the structure. The same SVD structure can be reused many times with + different matrices. Each time, if needed, the previous u,`vt` , and w + are reclaimed and the new matrices are created, which is all handled by + Mat::create. + @param src decomposed matrix. The depth has to be CV_32F or CV_64F. + @param flags operation flags (SVD::Flags) + */ + SVD& operator ()( InputArray src, int flags = 0 ); + + /** @brief decomposes matrix and stores the results to user-provided matrices + + The methods/functions perform SVD of matrix. Unlike SVD::SVD constructor + and SVD::operator(), they store the results to the user-provided + matrices: + + @code{.cpp} + Mat A, w, u, vt; + SVD::compute(A, w, u, vt); + @endcode + + @param src decomposed matrix. The depth has to be CV_32F or CV_64F. + @param w calculated singular values + @param u calculated left singular vectors + @param vt transposed matrix of right singular vectors + @param flags operation flags - see SVD::Flags. + */ + static void compute( InputArray src, OutputArray w, + OutputArray u, OutputArray vt, int flags = 0 ); + + /** @overload + computes singular values of a matrix + @param src decomposed matrix. The depth has to be CV_32F or CV_64F. + @param w calculated singular values + @param flags operation flags - see SVD::Flags. + */ + static void compute( InputArray src, OutputArray w, int flags = 0 ); + + /** @brief performs back substitution + */ + static void backSubst( InputArray w, InputArray u, + InputArray vt, InputArray rhs, + OutputArray dst ); + + /** @brief solves an under-determined singular linear system + + The method finds a unit-length solution x of a singular linear system + A\*x = 0. Depending on the rank of A, there can be no solutions, a + single solution or an infinite number of solutions. In general, the + algorithm solves the following problem: + \f[dst = \arg \min _{x: \| x \| =1} \| src \cdot x \|\f] + @param src left-hand-side matrix. + @param dst found solution. + */ + static void solveZ( InputArray src, OutputArray dst ); + + /** @brief performs a singular value back substitution. + + The method calculates a back substitution for the specified right-hand + side: + + \f[\texttt{x} = \texttt{vt} ^T \cdot diag( \texttt{w} )^{-1} \cdot \texttt{u} ^T \cdot \texttt{rhs} \sim \texttt{A} ^{-1} \cdot \texttt{rhs}\f] + + Using this technique you can either get a very accurate solution of the + convenient linear system, or the best (in the least-squares terms) + pseudo-solution of an overdetermined linear system. + + @param rhs right-hand side of a linear system (u\*w\*v')\*dst = rhs to + be solved, where A has been previously decomposed. + + @param dst found solution of the system. + + @note Explicit SVD with the further back substitution only makes sense + if you need to solve many linear systems with the same left-hand side + (for example, src ). If all you need is to solve a single system + (possibly with multiple rhs immediately available), simply call solve + add pass #DECOMP_SVD there. It does absolutely the same thing. + */ + void backSubst( InputArray rhs, OutputArray dst ) const; + + /** @todo document */ + template static + void compute( const Matx<_Tp, m, n>& a, Matx<_Tp, nm, 1>& w, Matx<_Tp, m, nm>& u, Matx<_Tp, n, nm>& vt ); + + /** @todo document */ + template static + void compute( const Matx<_Tp, m, n>& a, Matx<_Tp, nm, 1>& w ); + + /** @todo document */ + template static + void backSubst( const Matx<_Tp, nm, 1>& w, const Matx<_Tp, m, nm>& u, const Matx<_Tp, n, nm>& vt, const Matx<_Tp, m, nb>& rhs, Matx<_Tp, n, nb>& dst ); + + Mat u, w, vt; +}; + +/** @brief Random Number Generator + +Random number generator. It encapsulates the state (currently, a 64-bit +integer) and has methods to return scalar random values and to fill +arrays with random values. Currently it supports uniform and Gaussian +(normal) distributions. The generator uses Multiply-With-Carry +algorithm, introduced by G. Marsaglia ( + ). +Gaussian-distribution random numbers are generated using the Ziggurat +algorithm ( ), +introduced by G. Marsaglia and W. W. Tsang. +*/ +class CV_EXPORTS RNG +{ +public: + enum { UNIFORM = 0, + NORMAL = 1 + }; + + /** @brief constructor + + These are the RNG constructors. The first form sets the state to some + pre-defined value, equal to 2\*\*32-1 in the current implementation. The + second form sets the state to the specified value. If you passed state=0 + , the constructor uses the above default value instead to avoid the + singular random number sequence, consisting of all zeros. + */ + RNG(); + /** @overload + @param state 64-bit value used to initialize the RNG. + */ + RNG(uint64 state); + /**The method updates the state using the MWC algorithm and returns the + next 32-bit random number.*/ + unsigned next(); + + /**Each of the methods updates the state using the MWC algorithm and + returns the next random number of the specified type. In case of integer + types, the returned number is from the available value range for the + specified type. In case of floating-point types, the returned value is + from [0,1) range. + */ + operator uchar(); + /** @overload */ + operator schar(); + /** @overload */ + operator ushort(); + /** @overload */ + operator short(); + /** @overload */ + operator unsigned(); + /** @overload */ + operator int(); + /** @overload */ + operator float(); + /** @overload */ + operator double(); + + /** @brief returns a random integer sampled uniformly from [0, N). + + The methods transform the state using the MWC algorithm and return the + next random number. The first form is equivalent to RNG::next . The + second form returns the random number modulo N , which means that the + result is in the range [0, N) . + */ + unsigned operator ()(); + /** @overload + @param N upper non-inclusive boundary of the returned random number. + */ + unsigned operator ()(unsigned N); + + /** @brief returns uniformly distributed integer random number from [a,b) range + + The methods transform the state using the MWC algorithm and return the + next uniformly-distributed random number of the specified type, deduced + from the input parameter type, from the range [a, b) . There is a nuance + illustrated by the following sample: + + @code{.cpp} + RNG rng; + + // always produces 0 + double a = rng.uniform(0, 1); + + // produces double from [0, 1) + double a1 = rng.uniform((double)0, (double)1); + + // produces float from [0, 1) + float b = rng.uniform(0.f, 1.f); + + // produces double from [0, 1) + double c = rng.uniform(0., 1.); + + // may cause compiler error because of ambiguity: + // RNG::uniform(0, (int)0.999999)? or RNG::uniform((double)0, 0.99999)? + double d = rng.uniform(0, 0.999999); + @endcode + + The compiler does not take into account the type of the variable to + which you assign the result of RNG::uniform . The only thing that + matters to the compiler is the type of a and b parameters. So, if you + want a floating-point random number, but the range boundaries are + integer numbers, either put dots in the end, if they are constants, or + use explicit type cast operators, as in the a1 initialization above. + @param a lower inclusive boundary of the returned random number. + @param b upper non-inclusive boundary of the returned random number. + */ + int uniform(int a, int b); + /** @overload */ + float uniform(float a, float b); + /** @overload */ + double uniform(double a, double b); + + /** @brief Fills arrays with random numbers. + + @param mat 2D or N-dimensional matrix; currently matrices with more than + 4 channels are not supported by the methods, use Mat::reshape as a + possible workaround. + @param distType distribution type, RNG::UNIFORM or RNG::NORMAL. + @param a first distribution parameter; in case of the uniform + distribution, this is an inclusive lower boundary, in case of the normal + distribution, this is a mean value. + @param b second distribution parameter; in case of the uniform + distribution, this is a non-inclusive upper boundary, in case of the + normal distribution, this is a standard deviation (diagonal of the + standard deviation matrix or the full standard deviation matrix). + @param saturateRange pre-saturation flag; for uniform distribution only; + if true, the method will first convert a and b to the acceptable value + range (according to the mat datatype) and then will generate uniformly + distributed random numbers within the range [saturate(a), saturate(b)), + if saturateRange=false, the method will generate uniformly distributed + random numbers in the original range [a, b) and then will saturate them, + it means, for example, that + theRNG().fill(mat_8u, RNG::UNIFORM, -DBL_MAX, DBL_MAX) will likely + produce array mostly filled with 0's and 255's, since the range (0, 255) + is significantly smaller than [-DBL_MAX, DBL_MAX). + + Each of the methods fills the matrix with the random values from the + specified distribution. As the new numbers are generated, the RNG state + is updated accordingly. In case of multiple-channel images, every + channel is filled independently, which means that RNG cannot generate + samples from the multi-dimensional Gaussian distribution with + non-diagonal covariance matrix directly. To do that, the method + generates samples from multi-dimensional standard Gaussian distribution + with zero mean and identity covariation matrix, and then transforms them + using transform to get samples from the specified Gaussian distribution. + */ + void fill( InputOutputArray mat, int distType, InputArray a, InputArray b, bool saturateRange = false ); + + /** @brief Returns the next random number sampled from the Gaussian distribution + @param sigma standard deviation of the distribution. + + The method transforms the state using the MWC algorithm and returns the + next random number from the Gaussian distribution N(0,sigma) . That is, + the mean value of the returned random numbers is zero and the standard + deviation is the specified sigma . + */ + double gaussian(double sigma); + + uint64 state; + + bool operator ==(const RNG& other) const; +}; + +/** @brief Mersenne Twister random number generator + +Inspired by http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c +@todo document +*/ +class CV_EXPORTS RNG_MT19937 +{ +public: + RNG_MT19937(); + RNG_MT19937(unsigned s); + void seed(unsigned s); + + unsigned next(); + + operator int(); + operator unsigned(); + operator float(); + operator double(); + + unsigned operator ()(unsigned N); + unsigned operator ()(); + + /** @brief returns uniformly distributed integer random number from [a,b) range*/ + int uniform(int a, int b); + /** @brief returns uniformly distributed floating-point random number from [a,b) range*/ + float uniform(float a, float b); + /** @brief returns uniformly distributed double-precision floating-point random number from [a,b) range*/ + double uniform(double a, double b); + +private: + enum PeriodParameters {N = 624, M = 397}; + unsigned state[N]; + int mti; +}; + +//! @} core_array + +//! @addtogroup core_cluster +//! @{ + +/** @example samples/cpp/kmeans.cpp +An example on K-means clustering +*/ + +/** @brief Finds centers of clusters and groups input samples around the clusters. + +The function kmeans implements a k-means algorithm that finds the centers of cluster_count clusters +and groups the input samples around the clusters. As an output, \f$\texttt{bestLabels}_i\f$ contains a +0-based cluster index for the sample stored in the \f$i^{th}\f$ row of the samples matrix. + +@note +- (Python) An example on K-means clustering can be found at + opencv_source_code/samples/python/kmeans.py +@param data Data for clustering. An array of N-Dimensional points with float coordinates is needed. +Examples of this array can be: +- Mat points(count, 2, CV_32F); +- Mat points(count, 1, CV_32FC2); +- Mat points(1, count, CV_32FC2); +- std::vector\ points(sampleCount); +@param K Number of clusters to split the set by. +@param bestLabels Input/output integer array that stores the cluster indices for every sample. +@param criteria The algorithm termination criteria, that is, the maximum number of iterations and/or +the desired accuracy. The accuracy is specified as criteria.epsilon. As soon as each of the cluster +centers moves by less than criteria.epsilon on some iteration, the algorithm stops. +@param attempts Flag to specify the number of times the algorithm is executed using different +initial labellings. The algorithm returns the labels that yield the best compactness (see the last +function parameter). +@param flags Flag that can take values of cv::KmeansFlags +@param centers Output matrix of the cluster centers, one row per each cluster center. +@return The function returns the compactness measure that is computed as +\f[\sum _i \| \texttt{samples} _i - \texttt{centers} _{ \texttt{labels} _i} \| ^2\f] +after every attempt. The best (minimum) value is chosen and the corresponding labels and the +compactness value are returned by the function. Basically, you can use only the core of the +function, set the number of attempts to 1, initialize labels each time using a custom algorithm, +pass them with the ( flags = #KMEANS_USE_INITIAL_LABELS ) flag, and then choose the best +(most-compact) clustering. +*/ +CV_EXPORTS_W double kmeans( InputArray data, int K, InputOutputArray bestLabels, + TermCriteria criteria, int attempts, + int flags, OutputArray centers = noArray() ); + +//! @} core_cluster + +//! @addtogroup core_basic +//! @{ + +/////////////////////////////// Formatted output of cv::Mat /////////////////////////// + +/** @todo document */ +class CV_EXPORTS Formatted +{ +public: + virtual const char* next() = 0; + virtual void reset() = 0; + virtual ~Formatted(); +}; + +/** @todo document */ +class CV_EXPORTS Formatter +{ +public: + enum FormatType { + FMT_DEFAULT = 0, + FMT_MATLAB = 1, + FMT_CSV = 2, + FMT_PYTHON = 3, + FMT_NUMPY = 4, + FMT_C = 5 + }; + + virtual ~Formatter(); + + virtual Ptr format(const Mat& mtx) const = 0; + + virtual void set16fPrecision(int p = 4) = 0; + virtual void set32fPrecision(int p = 8) = 0; + virtual void set64fPrecision(int p = 16) = 0; + virtual void setMultiline(bool ml = true) = 0; + + static Ptr get(Formatter::FormatType fmt = FMT_DEFAULT); + +}; + +static inline +String& operator << (String& out, Ptr fmtd) +{ + fmtd->reset(); + for(const char* str = fmtd->next(); str; str = fmtd->next()) + out += cv::String(str); + return out; +} + +static inline +String& operator << (String& out, const Mat& mtx) +{ + return out << Formatter::get()->format(mtx); +} + +//////////////////////////////////////// Algorithm //////////////////////////////////// + +class CV_EXPORTS Algorithm; + +template struct ParamType {}; + + +/** @brief This is a base class for all more or less complex algorithms in OpenCV + +especially for classes of algorithms, for which there can be multiple implementations. The examples +are stereo correspondence (for which there are algorithms like block matching, semi-global block +matching, graph-cut etc.), background subtraction (which can be done using mixture-of-gaussians +models, codebook-based algorithm etc.), optical flow (block matching, Lucas-Kanade, Horn-Schunck +etc.). + +Here is example of SimpleBlobDetector use in your application via Algorithm interface: +@snippet snippets/core_various.cpp Algorithm +*/ +class CV_EXPORTS_W Algorithm +{ +public: + Algorithm(); + virtual ~Algorithm(); + + /** @brief Clears the algorithm state + */ + CV_WRAP virtual void clear() {} + + /** @brief Stores algorithm parameters in a file storage + */ + virtual void write(FileStorage& fs) const { CV_UNUSED(fs); } + + /** @brief simplified API for language bindings + * @overload + */ + CV_WRAP void write(const Ptr& fs, const String& name = String()) const; + + /** @brief Reads algorithm parameters from a file storage + */ + CV_WRAP virtual void read(const FileNode& fn) { CV_UNUSED(fn); } + + /** @brief Returns true if the Algorithm is empty (e.g. in the very beginning or after unsuccessful read + */ + CV_WRAP virtual bool empty() const { return false; } + + /** @brief Reads algorithm from the file node + + This is static template method of Algorithm. It's usage is following (in the case of SVM): + @code + cv::FileStorage fsRead("example.xml", FileStorage::READ); + Ptr svm = Algorithm::read(fsRead.root()); + @endcode + In order to make this method work, the derived class must overwrite Algorithm::read(const + FileNode& fn) and also have static create() method without parameters + (or with all the optional parameters) + */ + template static Ptr<_Tp> read(const FileNode& fn) + { + Ptr<_Tp> obj = _Tp::create(); + obj->read(fn); + return !obj->empty() ? obj : Ptr<_Tp>(); + } + + /** @brief Loads algorithm from the file + + @param filename Name of the file to read. + @param objname The optional name of the node to read (if empty, the first top-level node will be used) + + This is static template method of Algorithm. It's usage is following (in the case of SVM): + @code + Ptr svm = Algorithm::load("my_svm_model.xml"); + @endcode + In order to make this method work, the derived class must overwrite Algorithm::read(const + FileNode& fn). + */ + template static Ptr<_Tp> load(const String& filename, const String& objname=String()) + { + FileStorage fs(filename, FileStorage::READ); + CV_Assert(fs.isOpened()); + FileNode fn = objname.empty() ? fs.getFirstTopLevelNode() : fs[objname]; + if (fn.empty()) return Ptr<_Tp>(); + Ptr<_Tp> obj = _Tp::create(); + obj->read(fn); + return !obj->empty() ? obj : Ptr<_Tp>(); + } + + /** @brief Loads algorithm from a String + + @param strModel The string variable containing the model you want to load. + @param objname The optional name of the node to read (if empty, the first top-level node will be used) + + This is static template method of Algorithm. It's usage is following (in the case of SVM): + @code + Ptr svm = Algorithm::loadFromString(myStringModel); + @endcode + */ + template static Ptr<_Tp> loadFromString(const String& strModel, const String& objname=String()) + { + FileStorage fs(strModel, FileStorage::READ + FileStorage::MEMORY); + FileNode fn = objname.empty() ? fs.getFirstTopLevelNode() : fs[objname]; + Ptr<_Tp> obj = _Tp::create(); + obj->read(fn); + return !obj->empty() ? obj : Ptr<_Tp>(); + } + + /** Saves the algorithm to a file. + In order to make this method work, the derived class must implement Algorithm::write(FileStorage& fs). */ + CV_WRAP virtual void save(const String& filename) const; + + /** Returns the algorithm string identifier. + This string is used as top level xml/yml node tag when the object is saved to a file or string. */ + CV_WRAP virtual String getDefaultName() const; + +protected: + void writeFormat(FileStorage& fs) const; +}; + +enum struct Param { + INT=0, BOOLEAN=1, REAL=2, STRING=3, MAT=4, MAT_VECTOR=5, ALGORITHM=6, FLOAT=7, + UNSIGNED_INT=8, UINT64=9, UCHAR=11, SCALAR=12 +}; + + + +template<> struct ParamType +{ + typedef bool const_param_type; + typedef bool member_type; + + static const Param type = Param::BOOLEAN; +}; + +template<> struct ParamType +{ + typedef int const_param_type; + typedef int member_type; + + static const Param type = Param::INT; +}; + +template<> struct ParamType +{ + typedef double const_param_type; + typedef double member_type; + + static const Param type = Param::REAL; +}; + +template<> struct ParamType +{ + typedef const String& const_param_type; + typedef String member_type; + + static const Param type = Param::STRING; +}; + +template<> struct ParamType +{ + typedef const Mat& const_param_type; + typedef Mat member_type; + + static const Param type = Param::MAT; +}; + +template<> struct ParamType > +{ + typedef const std::vector& const_param_type; + typedef std::vector member_type; + + static const Param type = Param::MAT_VECTOR; +}; + +template<> struct ParamType +{ + typedef const Ptr& const_param_type; + typedef Ptr member_type; + + static const Param type = Param::ALGORITHM; +}; + +template<> struct ParamType +{ + typedef float const_param_type; + typedef float member_type; + + static const Param type = Param::FLOAT; +}; + +template<> struct ParamType +{ + typedef unsigned const_param_type; + typedef unsigned member_type; + + static const Param type = Param::UNSIGNED_INT; +}; + +template<> struct ParamType +{ + typedef uint64 const_param_type; + typedef uint64 member_type; + + static const Param type = Param::UINT64; +}; + +template<> struct ParamType +{ + typedef uchar const_param_type; + typedef uchar member_type; + + static const Param type = Param::UCHAR; +}; + +template<> struct ParamType +{ + typedef const Scalar& const_param_type; + typedef Scalar member_type; + + static const Param type = Param::SCALAR; +}; + +template +struct ParamType<_Tp, typename std::enable_if< std::is_enum<_Tp>::value >::type> +{ + typedef typename std::underlying_type<_Tp>::type const_param_type; + typedef typename std::underlying_type<_Tp>::type member_type; + + static const Param type = Param::INT; +}; + +//! @} core_basic + +} //namespace cv + +#include "opencv2/core/operations.hpp" +#include "opencv2/core/cvstd.inl.hpp" +#include "opencv2/core/utility.hpp" +#include "opencv2/core/optim.hpp" +#include "opencv2/core/ovx.hpp" + +#endif /*OPENCV_CORE_HPP*/ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/affine.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/affine.hpp new file mode 100644 index 0000000..1806382 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/affine.hpp @@ -0,0 +1,678 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_AFFINE3_HPP +#define OPENCV_CORE_AFFINE3_HPP + +#ifdef __cplusplus + +#include + +namespace cv +{ + +//! @addtogroup core +//! @{ + + /** @brief Affine transform + * + * It represents a 4x4 homogeneous transformation matrix \f$T\f$ + * + * \f[T = + * \begin{bmatrix} + * R & t\\ + * 0 & 1\\ + * \end{bmatrix} + * \f] + * + * where \f$R\f$ is a 3x3 rotation matrix and \f$t\f$ is a 3x1 translation vector. + * + * You can specify \f$R\f$ either by a 3x3 rotation matrix or by a 3x1 rotation vector, + * which is converted to a 3x3 rotation matrix by the Rodrigues formula. + * + * To construct a matrix \f$T\f$ representing first rotation around the axis \f$r\f$ with rotation + * angle \f$|r|\f$ in radian (right hand rule) and then translation by the vector \f$t\f$, you can use + * + * @code + * cv::Vec3f r, t; + * cv::Affine3f T(r, t); + * @endcode + * + * If you already have the rotation matrix \f$R\f$, then you can use + * + * @code + * cv::Matx33f R; + * cv::Affine3f T(R, t); + * @endcode + * + * To extract the rotation matrix \f$R\f$ from \f$T\f$, use + * + * @code + * cv::Matx33f R = T.rotation(); + * @endcode + * + * To extract the translation vector \f$t\f$ from \f$T\f$, use + * + * @code + * cv::Vec3f t = T.translation(); + * @endcode + * + * To extract the rotation vector \f$r\f$ from \f$T\f$, use + * + * @code + * cv::Vec3f r = T.rvec(); + * @endcode + * + * Note that since the mapping from rotation vectors to rotation matrices + * is many to one. The returned rotation vector is not necessarily the one + * you used before to set the matrix. + * + * If you have two transformations \f$T = T_1 * T_2\f$, use + * + * @code + * cv::Affine3f T, T1, T2; + * T = T2.concatenate(T1); + * @endcode + * + * To get the inverse transform of \f$T\f$, use + * + * @code + * cv::Affine3f T, T_inv; + * T_inv = T.inv(); + * @endcode + * + */ + template + class Affine3 + { + public: + typedef T float_type; + typedef Matx Mat3; + typedef Matx Mat4; + typedef Vec Vec3; + + //! Default constructor. It represents a 4x4 identity matrix. + Affine3(); + + //! Augmented affine matrix + Affine3(const Mat4& affine); + + /** + * The resulting 4x4 matrix is + * + * \f[ + * \begin{bmatrix} + * R & t\\ + * 0 & 1\\ + * \end{bmatrix} + * \f] + * + * @param R 3x3 rotation matrix. + * @param t 3x1 translation vector. + */ + Affine3(const Mat3& R, const Vec3& t = Vec3::all(0)); + + /** + * Rodrigues vector. + * + * The last row of the current matrix is set to [0,0,0,1]. + * + * @param rvec 3x1 rotation vector. Its direction indicates the rotation axis and its length + * indicates the rotation angle in radian (using right hand rule). + * @param t 3x1 translation vector. + */ + Affine3(const Vec3& rvec, const Vec3& t = Vec3::all(0)); + + /** + * Combines all constructors above. Supports 4x4, 3x4, 3x3, 1x3, 3x1 sizes of data matrix. + * + * The last row of the current matrix is set to [0,0,0,1] when data is not 4x4. + * + * @param data 1-channel matrix. + * when it is 4x4, it is copied to the current matrix and t is not used. + * When it is 3x4, it is copied to the upper part 3x4 of the current matrix and t is not used. + * When it is 3x3, it is copied to the upper left 3x3 part of the current matrix. + * When it is 3x1 or 1x3, it is treated as a rotation vector and the Rodrigues formula is used + * to compute a 3x3 rotation matrix. + * @param t 3x1 translation vector. It is used only when data is neither 4x4 nor 3x4. + */ + explicit Affine3(const Mat& data, const Vec3& t = Vec3::all(0)); + + //! From 16-element array + explicit Affine3(const float_type* vals); + + //! Create an 4x4 identity transform + static Affine3 Identity(); + + /** + * Rotation matrix. + * + * Copy the rotation matrix to the upper left 3x3 part of the current matrix. + * The remaining elements of the current matrix are not changed. + * + * @param R 3x3 rotation matrix. + * + */ + void rotation(const Mat3& R); + + /** + * Rodrigues vector. + * + * It sets the upper left 3x3 part of the matrix. The remaining part is unaffected. + * + * @param rvec 3x1 rotation vector. The direction indicates the rotation axis and + * its length indicates the rotation angle in radian (using the right thumb convention). + */ + void rotation(const Vec3& rvec); + + /** + * Combines rotation methods above. Supports 3x3, 1x3, 3x1 sizes of data matrix. + * + * It sets the upper left 3x3 part of the matrix. The remaining part is unaffected. + * + * @param data 1-channel matrix. + * When it is a 3x3 matrix, it sets the upper left 3x3 part of the current matrix. + * When it is a 1x3 or 3x1 matrix, it is used as a rotation vector. The Rodrigues formula + * is used to compute the rotation matrix and sets the upper left 3x3 part of the current matrix. + */ + void rotation(const Mat& data); + + /** + * Copy the 3x3 matrix L to the upper left part of the current matrix + * + * It sets the upper left 3x3 part of the matrix. The remaining part is unaffected. + * + * @param L 3x3 matrix. + */ + void linear(const Mat3& L); + + /** + * Copy t to the first three elements of the last column of the current matrix + * + * It sets the upper right 3x1 part of the matrix. The remaining part is unaffected. + * + * @param t 3x1 translation vector. + */ + void translation(const Vec3& t); + + //! @return the upper left 3x3 part + Mat3 rotation() const; + + //! @return the upper left 3x3 part + Mat3 linear() const; + + //! @return the upper right 3x1 part + Vec3 translation() const; + + //! Rodrigues vector. + //! @return a vector representing the upper left 3x3 rotation matrix of the current matrix. + //! @warning Since the mapping between rotation vectors and rotation matrices is many to one, + //! this function returns only one rotation vector that represents the current rotation matrix, + //! which is not necessarily the same one set by `rotation(const Vec3& rvec)`. + Vec3 rvec() const; + + //! @return the inverse of the current matrix. + Affine3 inv(int method = cv::DECOMP_SVD) const; + + //! a.rotate(R) is equivalent to Affine(R, 0) * a; + Affine3 rotate(const Mat3& R) const; + + //! a.rotate(rvec) is equivalent to Affine(rvec, 0) * a; + Affine3 rotate(const Vec3& rvec) const; + + //! a.translate(t) is equivalent to Affine(E, t) * a, where E is an identity matrix + Affine3 translate(const Vec3& t) const; + + //! a.concatenate(affine) is equivalent to affine * a; + Affine3 concatenate(const Affine3& affine) const; + + template operator Affine3() const; + + template Affine3 cast() const; + + Mat4 matrix; + +#if defined EIGEN_WORLD_VERSION && defined EIGEN_GEOMETRY_MODULE_H + Affine3(const Eigen::Transform& affine); + Affine3(const Eigen::Transform& affine); + operator Eigen::Transform() const; + operator Eigen::Transform() const; +#endif + }; + + template static + Affine3 operator*(const Affine3& affine1, const Affine3& affine2); + + //! V is a 3-element vector with member fields x, y and z + template static + V operator*(const Affine3& affine, const V& vector); + + typedef Affine3 Affine3f; + typedef Affine3 Affine3d; + + static Vec3f operator*(const Affine3f& affine, const Vec3f& vector); + static Vec3d operator*(const Affine3d& affine, const Vec3d& vector); + + template class DataType< Affine3<_Tp> > + { + public: + typedef Affine3<_Tp> value_type; + typedef Affine3::work_type> work_type; + typedef _Tp channel_type; + + enum { generic_type = 0, + channels = 16, + fmt = traits::SafeFmt::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif + }; + + typedef Vec vec_type; + }; + + namespace traits { + template + struct Depth< Affine3<_Tp> > { enum { value = Depth<_Tp>::value }; }; + template + struct Type< Affine3<_Tp> > { enum { value = CV_MAKETYPE(Depth<_Tp>::value, 16) }; }; + } // namespace + +//! @} core + +} + +//! @cond IGNORED + +/////////////////////////////////////////////////////////////////////////////////// +// Implementation + +template inline +cv::Affine3::Affine3() + : matrix(Mat4::eye()) +{} + +template inline +cv::Affine3::Affine3(const Mat4& affine) + : matrix(affine) +{} + +template inline +cv::Affine3::Affine3(const Mat3& R, const Vec3& t) +{ + rotation(R); + translation(t); + matrix.val[12] = matrix.val[13] = matrix.val[14] = 0; + matrix.val[15] = 1; +} + +template inline +cv::Affine3::Affine3(const Vec3& _rvec, const Vec3& t) +{ + rotation(_rvec); + translation(t); + matrix.val[12] = matrix.val[13] = matrix.val[14] = 0; + matrix.val[15] = 1; +} + +template inline +cv::Affine3::Affine3(const cv::Mat& data, const Vec3& t) +{ + CV_Assert(data.type() == cv::traits::Type::value); + CV_Assert(data.channels() == 1); + + if (data.cols == 4 && data.rows == 4) + { + data.copyTo(matrix); + return; + } + else if (data.cols == 4 && data.rows == 3) + { + rotation(data(Rect(0, 0, 3, 3))); + translation(data(Rect(3, 0, 1, 3))); + } + else + { + rotation(data); + translation(t); + } + + matrix.val[12] = matrix.val[13] = matrix.val[14] = 0; + matrix.val[15] = 1; +} + +template inline +cv::Affine3::Affine3(const float_type* vals) : matrix(vals) +{} + +template inline +cv::Affine3 cv::Affine3::Identity() +{ + return Affine3(cv::Affine3::Mat4::eye()); +} + +template inline +void cv::Affine3::rotation(const Mat3& R) +{ + linear(R); +} + +template inline +void cv::Affine3::rotation(const Vec3& _rvec) +{ + double theta = norm(_rvec); + + if (theta < DBL_EPSILON) + rotation(Mat3::eye()); + else + { + double c = std::cos(theta); + double s = std::sin(theta); + double c1 = 1. - c; + double itheta = (theta != 0) ? 1./theta : 0.; + + Point3_ r = _rvec*itheta; + + Mat3 rrt( r.x*r.x, r.x*r.y, r.x*r.z, r.x*r.y, r.y*r.y, r.y*r.z, r.x*r.z, r.y*r.z, r.z*r.z ); + Mat3 r_x( 0, -r.z, r.y, r.z, 0, -r.x, -r.y, r.x, 0 ); + + // R = cos(theta)*I + (1 - cos(theta))*r*rT + sin(theta)*[r_x] + // where [r_x] is [0 -rz ry; rz 0 -rx; -ry rx 0] + Mat3 R = c*Mat3::eye() + c1*rrt + s*r_x; + + rotation(R); + } +} + +//Combines rotation methods above. Supports 3x3, 1x3, 3x1 sizes of data matrix; +template inline +void cv::Affine3::rotation(const cv::Mat& data) +{ + CV_Assert(data.type() == cv::traits::Type::value); + CV_Assert(data.channels() == 1); + + if (data.cols == 3 && data.rows == 3) + { + Mat3 R; + data.copyTo(R); + rotation(R); + } + else if ((data.cols == 3 && data.rows == 1) || (data.cols == 1 && data.rows == 3)) + { + Vec3 _rvec; + data.reshape(1, 3).copyTo(_rvec); + rotation(_rvec); + } + else + CV_Error(Error::StsError, "Input matrix can only be 3x3, 1x3 or 3x1"); +} + +template inline +void cv::Affine3::linear(const Mat3& L) +{ + matrix.val[0] = L.val[0]; matrix.val[1] = L.val[1]; matrix.val[ 2] = L.val[2]; + matrix.val[4] = L.val[3]; matrix.val[5] = L.val[4]; matrix.val[ 6] = L.val[5]; + matrix.val[8] = L.val[6]; matrix.val[9] = L.val[7]; matrix.val[10] = L.val[8]; +} + +template inline +void cv::Affine3::translation(const Vec3& t) +{ + matrix.val[3] = t[0]; matrix.val[7] = t[1]; matrix.val[11] = t[2]; +} + +template inline +typename cv::Affine3::Mat3 cv::Affine3::rotation() const +{ + return linear(); +} + +template inline +typename cv::Affine3::Mat3 cv::Affine3::linear() const +{ + typename cv::Affine3::Mat3 R; + R.val[0] = matrix.val[0]; R.val[1] = matrix.val[1]; R.val[2] = matrix.val[ 2]; + R.val[3] = matrix.val[4]; R.val[4] = matrix.val[5]; R.val[5] = matrix.val[ 6]; + R.val[6] = matrix.val[8]; R.val[7] = matrix.val[9]; R.val[8] = matrix.val[10]; + return R; +} + +template inline +typename cv::Affine3::Vec3 cv::Affine3::translation() const +{ + return Vec3(matrix.val[3], matrix.val[7], matrix.val[11]); +} + +template inline +typename cv::Affine3::Vec3 cv::Affine3::rvec() const +{ + cv::Vec3d w; + cv::Matx33d u, vt, R = rotation(); + cv::SVD::compute(R, w, u, vt, cv::SVD::FULL_UV + cv::SVD::MODIFY_A); + R = u * vt; + + double rx = R.val[7] - R.val[5]; + double ry = R.val[2] - R.val[6]; + double rz = R.val[3] - R.val[1]; + + double s = std::sqrt((rx*rx + ry*ry + rz*rz)*0.25); + double c = (R.val[0] + R.val[4] + R.val[8] - 1) * 0.5; + c = c > 1.0 ? 1.0 : c < -1.0 ? -1.0 : c; + double theta = std::acos(c); + + if( s < 1e-5 ) + { + if( c > 0 ) + rx = ry = rz = 0; + else + { + double t; + t = (R.val[0] + 1) * 0.5; + rx = std::sqrt(std::max(t, 0.0)); + t = (R.val[4] + 1) * 0.5; + ry = std::sqrt(std::max(t, 0.0)) * (R.val[1] < 0 ? -1.0 : 1.0); + t = (R.val[8] + 1) * 0.5; + rz = std::sqrt(std::max(t, 0.0)) * (R.val[2] < 0 ? -1.0 : 1.0); + + if( fabs(rx) < fabs(ry) && fabs(rx) < fabs(rz) && (R.val[5] > 0) != (ry*rz > 0) ) + rz = -rz; + theta /= std::sqrt(rx*rx + ry*ry + rz*rz); + rx *= theta; + ry *= theta; + rz *= theta; + } + } + else + { + double vth = 1/(2*s); + vth *= theta; + rx *= vth; ry *= vth; rz *= vth; + } + + return cv::Vec3d(rx, ry, rz); +} + +template inline +cv::Affine3 cv::Affine3::inv(int method) const +{ + return matrix.inv(method); +} + +template inline +cv::Affine3 cv::Affine3::rotate(const Mat3& R) const +{ + Mat3 Lc = linear(); + Vec3 tc = translation(); + Mat4 result; + result.val[12] = result.val[13] = result.val[14] = 0; + result.val[15] = 1; + + for(int j = 0; j < 3; ++j) + { + for(int i = 0; i < 3; ++i) + { + float_type value = 0; + for(int k = 0; k < 3; ++k) + value += R(j, k) * Lc(k, i); + result(j, i) = value; + } + + result(j, 3) = R.row(j).dot(tc.t()); + } + return result; +} + +template inline +cv::Affine3 cv::Affine3::rotate(const Vec3& _rvec) const +{ + return rotate(Affine3f(_rvec).rotation()); +} + +template inline +cv::Affine3 cv::Affine3::translate(const Vec3& t) const +{ + Mat4 m = matrix; + m.val[ 3] += t[0]; + m.val[ 7] += t[1]; + m.val[11] += t[2]; + return m; +} + +template inline +cv::Affine3 cv::Affine3::concatenate(const Affine3& affine) const +{ + return (*this).rotate(affine.rotation()).translate(affine.translation()); +} + +template template inline +cv::Affine3::operator Affine3() const +{ + return Affine3(matrix); +} + +template template inline +cv::Affine3 cv::Affine3::cast() const +{ + return Affine3(matrix); +} + +template inline +cv::Affine3 cv::operator*(const cv::Affine3& affine1, const cv::Affine3& affine2) +{ + return affine2.concatenate(affine1); +} + +template inline +V cv::operator*(const cv::Affine3& affine, const V& v) +{ + const typename Affine3::Mat4& m = affine.matrix; + + V r; + r.x = m.val[0] * v.x + m.val[1] * v.y + m.val[ 2] * v.z + m.val[ 3]; + r.y = m.val[4] * v.x + m.val[5] * v.y + m.val[ 6] * v.z + m.val[ 7]; + r.z = m.val[8] * v.x + m.val[9] * v.y + m.val[10] * v.z + m.val[11]; + return r; +} + +static inline +cv::Vec3f cv::operator*(const cv::Affine3f& affine, const cv::Vec3f& v) +{ + const cv::Matx44f& m = affine.matrix; + cv::Vec3f r; + r.val[0] = m.val[0] * v[0] + m.val[1] * v[1] + m.val[ 2] * v[2] + m.val[ 3]; + r.val[1] = m.val[4] * v[0] + m.val[5] * v[1] + m.val[ 6] * v[2] + m.val[ 7]; + r.val[2] = m.val[8] * v[0] + m.val[9] * v[1] + m.val[10] * v[2] + m.val[11]; + return r; +} + +static inline +cv::Vec3d cv::operator*(const cv::Affine3d& affine, const cv::Vec3d& v) +{ + const cv::Matx44d& m = affine.matrix; + cv::Vec3d r; + r.val[0] = m.val[0] * v[0] + m.val[1] * v[1] + m.val[ 2] * v[2] + m.val[ 3]; + r.val[1] = m.val[4] * v[0] + m.val[5] * v[1] + m.val[ 6] * v[2] + m.val[ 7]; + r.val[2] = m.val[8] * v[0] + m.val[9] * v[1] + m.val[10] * v[2] + m.val[11]; + return r; +} + + + +#if defined EIGEN_WORLD_VERSION && defined EIGEN_GEOMETRY_MODULE_H + +template inline +cv::Affine3::Affine3(const Eigen::Transform& affine) +{ + cv::Mat(4, 4, cv::traits::Type::value, affine.matrix().data()).copyTo(matrix); +} + +template inline +cv::Affine3::Affine3(const Eigen::Transform& affine) +{ + Eigen::Transform a = affine; + cv::Mat(4, 4, cv::traits::Type::value, a.matrix().data()).copyTo(matrix); +} + +template inline +cv::Affine3::operator Eigen::Transform() const +{ + Eigen::Transform r; + cv::Mat hdr(4, 4, cv::traits::Type::value, r.matrix().data()); + cv::Mat(matrix, false).copyTo(hdr); + return r; +} + +template inline +cv::Affine3::operator Eigen::Transform() const +{ + return this->operator Eigen::Transform(); +} + +#endif /* defined EIGEN_WORLD_VERSION && defined EIGEN_GEOMETRY_MODULE_H */ + +//! @endcond + +#endif /* __cplusplus */ + +#endif /* OPENCV_CORE_AFFINE3_HPP */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/async.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/async.hpp new file mode 100644 index 0000000..54560c7 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/async.hpp @@ -0,0 +1,105 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_ASYNC_HPP +#define OPENCV_CORE_ASYNC_HPP + +#include + +#ifdef CV_CXX11 +//#include +#include +#endif + +namespace cv { + +/** @addtogroup core_async + +@{ +*/ + + +/** @brief Returns result of asynchronous operations + +Object has attached asynchronous state. +Assignment operator doesn't clone asynchronous state (it is shared between all instances). + +Result can be fetched via get() method only once. + +*/ +class CV_EXPORTS_W AsyncArray +{ +public: + ~AsyncArray() CV_NOEXCEPT; + CV_WRAP AsyncArray() CV_NOEXCEPT; + AsyncArray(const AsyncArray& o) CV_NOEXCEPT; + AsyncArray& operator=(const AsyncArray& o) CV_NOEXCEPT; + CV_WRAP void release() CV_NOEXCEPT; + + /** Fetch the result. + @param[out] dst destination array + + Waits for result until container has valid result. + Throws exception if exception was stored as a result. + + Throws exception on invalid container state. + + @note Result or stored exception can be fetched only once. + */ + CV_WRAP void get(OutputArray dst) const; + + /** Retrieving the result with timeout + @param[out] dst destination array + @param[in] timeoutNs timeout in nanoseconds, -1 for infinite wait + + @returns true if result is ready, false if the timeout has expired + + @note Result or stored exception can be fetched only once. + */ + bool get(OutputArray dst, int64 timeoutNs) const; + + CV_WRAP inline + bool get(OutputArray dst, double timeoutNs) const { return get(dst, (int64)timeoutNs); } + + bool wait_for(int64 timeoutNs) const; + + CV_WRAP inline + bool wait_for(double timeoutNs) const { return wait_for((int64)timeoutNs); } + + CV_WRAP bool valid() const CV_NOEXCEPT; + +#ifdef CV_CXX11 + inline AsyncArray(AsyncArray&& o) { p = o.p; o.p = NULL; } + inline AsyncArray& operator=(AsyncArray&& o) CV_NOEXCEPT { std::swap(p, o.p); return *this; } + + template + inline bool get(OutputArray dst, const std::chrono::duration<_Rep, _Period>& timeout) + { + return get(dst, (int64)(std::chrono::nanoseconds(timeout).count())); + } + + template + inline bool wait_for(const std::chrono::duration<_Rep, _Period>& timeout) + { + return wait_for((int64)(std::chrono::nanoseconds(timeout).count())); + } + +#if 0 + std::future getFutureMat() const; + std::future getFutureUMat() const; +#endif +#endif + + + // PImpl + struct Impl; friend struct Impl; + inline void* _getImpl() const CV_NOEXCEPT { return p; } +protected: + Impl* p; +}; + + +//! @} +} // namespace +#endif // OPENCV_CORE_ASYNC_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/base.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/base.hpp new file mode 100644 index 0000000..21a61a4 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/base.hpp @@ -0,0 +1,664 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2014, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_BASE_HPP +#define OPENCV_CORE_BASE_HPP + +#ifndef __cplusplus +# error base.hpp header must be compiled as C++ +#endif + +#include "opencv2/opencv_modules.hpp" + +#include +#include + +#include "opencv2/core/cvdef.h" +#include "opencv2/core/cvstd.hpp" + +namespace cv +{ + +//! @addtogroup core_utils +//! @{ + +namespace Error { +//! error codes +enum Code { + StsOk= 0, //!< everything is ok + StsBackTrace= -1, //!< pseudo error for back trace + StsError= -2, //!< unknown /unspecified error + StsInternal= -3, //!< internal error (bad state) + StsNoMem= -4, //!< insufficient memory + StsBadArg= -5, //!< function arg/param is bad + StsBadFunc= -6, //!< unsupported function + StsNoConv= -7, //!< iteration didn't converge + StsAutoTrace= -8, //!< tracing + HeaderIsNull= -9, //!< image header is NULL + BadImageSize= -10, //!< image size is invalid + BadOffset= -11, //!< offset is invalid + BadDataPtr= -12, //!< + BadStep= -13, //!< image step is wrong, this may happen for a non-continuous matrix. + BadModelOrChSeq= -14, //!< + BadNumChannels= -15, //!< bad number of channels, for example, some functions accept only single channel matrices. + BadNumChannel1U= -16, //!< + BadDepth= -17, //!< input image depth is not supported by the function + BadAlphaChannel= -18, //!< + BadOrder= -19, //!< number of dimensions is out of range + BadOrigin= -20, //!< incorrect input origin + BadAlign= -21, //!< incorrect input align + BadCallBack= -22, //!< + BadTileSize= -23, //!< + BadCOI= -24, //!< input COI is not supported + BadROISize= -25, //!< incorrect input roi + MaskIsTiled= -26, //!< + StsNullPtr= -27, //!< null pointer + StsVecLengthErr= -28, //!< incorrect vector length + StsFilterStructContentErr= -29, //!< incorrect filter structure content + StsKernelStructContentErr= -30, //!< incorrect transform kernel content + StsFilterOffsetErr= -31, //!< incorrect filter offset value + StsBadSize= -201, //!< the input/output structure size is incorrect + StsDivByZero= -202, //!< division by zero + StsInplaceNotSupported= -203, //!< in-place operation is not supported + StsObjectNotFound= -204, //!< request can't be completed + StsUnmatchedFormats= -205, //!< formats of input/output arrays differ + StsBadFlag= -206, //!< flag is wrong or not supported + StsBadPoint= -207, //!< bad CvPoint + StsBadMask= -208, //!< bad format of mask (neither 8uC1 nor 8sC1) + StsUnmatchedSizes= -209, //!< sizes of input/output structures do not match + StsUnsupportedFormat= -210, //!< the data format/type is not supported by the function + StsOutOfRange= -211, //!< some of parameters are out of range + StsParseError= -212, //!< invalid syntax/structure of the parsed file + StsNotImplemented= -213, //!< the requested function/feature is not implemented + StsBadMemBlock= -214, //!< an allocated block has been corrupted + StsAssert= -215, //!< assertion failed + GpuNotSupported= -216, //!< no CUDA support + GpuApiCallError= -217, //!< GPU API call error + OpenGlNotSupported= -218, //!< no OpenGL support + OpenGlApiCallError= -219, //!< OpenGL API call error + OpenCLApiCallError= -220, //!< OpenCL API call error + OpenCLDoubleNotSupported= -221, + OpenCLInitError= -222, //!< OpenCL initialization error + OpenCLNoAMDBlasFft= -223 +}; +} //Error + +//! @} core_utils + +//! @addtogroup core_array +//! @{ + +//! matrix decomposition types +enum DecompTypes { + /** Gaussian elimination with the optimal pivot element chosen. */ + DECOMP_LU = 0, + /** singular value decomposition (SVD) method; the system can be over-defined and/or the matrix + src1 can be singular */ + DECOMP_SVD = 1, + /** eigenvalue decomposition; the matrix src1 must be symmetrical */ + DECOMP_EIG = 2, + /** Cholesky \f$LL^T\f$ factorization; the matrix src1 must be symmetrical and positively + defined */ + DECOMP_CHOLESKY = 3, + /** QR factorization; the system can be over-defined and/or the matrix src1 can be singular */ + DECOMP_QR = 4, + /** while all the previous flags are mutually exclusive, this flag can be used together with + any of the previous; it means that the normal equations + \f$\texttt{src1}^T\cdot\texttt{src1}\cdot\texttt{dst}=\texttt{src1}^T\texttt{src2}\f$ are + solved instead of the original system + \f$\texttt{src1}\cdot\texttt{dst}=\texttt{src2}\f$ */ + DECOMP_NORMAL = 16 +}; + +/** norm types + +src1 and src2 denote input arrays. +*/ + +enum NormTypes { + /** + \f[ + norm = \forkthree + {\|\texttt{src1}\|_{L_{\infty}} = \max _I | \texttt{src1} (I)|}{if \(\texttt{normType} = \texttt{NORM_INF}\) } + {\|\texttt{src1}-\texttt{src2}\|_{L_{\infty}} = \max _I | \texttt{src1} (I) - \texttt{src2} (I)|}{if \(\texttt{normType} = \texttt{NORM_INF}\) } + {\frac{\|\texttt{src1}-\texttt{src2}\|_{L_{\infty}} }{\|\texttt{src2}\|_{L_{\infty}} }}{if \(\texttt{normType} = \texttt{NORM_RELATIVE | NORM_INF}\) } + \f] + */ + NORM_INF = 1, + /** + \f[ + norm = \forkthree + {\| \texttt{src1} \| _{L_1} = \sum _I | \texttt{src1} (I)|}{if \(\texttt{normType} = \texttt{NORM_L1}\)} + { \| \texttt{src1} - \texttt{src2} \| _{L_1} = \sum _I | \texttt{src1} (I) - \texttt{src2} (I)|}{if \(\texttt{normType} = \texttt{NORM_L1}\) } + { \frac{\|\texttt{src1}-\texttt{src2}\|_{L_1} }{\|\texttt{src2}\|_{L_1}} }{if \(\texttt{normType} = \texttt{NORM_RELATIVE | NORM_L1}\) } + \f]*/ + NORM_L1 = 2, + /** + \f[ + norm = \forkthree + { \| \texttt{src1} \| _{L_2} = \sqrt{\sum_I \texttt{src1}(I)^2} }{if \(\texttt{normType} = \texttt{NORM_L2}\) } + { \| \texttt{src1} - \texttt{src2} \| _{L_2} = \sqrt{\sum_I (\texttt{src1}(I) - \texttt{src2}(I))^2} }{if \(\texttt{normType} = \texttt{NORM_L2}\) } + { \frac{\|\texttt{src1}-\texttt{src2}\|_{L_2} }{\|\texttt{src2}\|_{L_2}} }{if \(\texttt{normType} = \texttt{NORM_RELATIVE | NORM_L2}\) } + \f] + */ + NORM_L2 = 4, + /** + \f[ + norm = \forkthree + { \| \texttt{src1} \| _{L_2} ^{2} = \sum_I \texttt{src1}(I)^2} {if \(\texttt{normType} = \texttt{NORM_L2SQR}\)} + { \| \texttt{src1} - \texttt{src2} \| _{L_2} ^{2} = \sum_I (\texttt{src1}(I) - \texttt{src2}(I))^2 }{if \(\texttt{normType} = \texttt{NORM_L2SQR}\) } + { \left(\frac{\|\texttt{src1}-\texttt{src2}\|_{L_2} }{\|\texttt{src2}\|_{L_2}}\right)^2 }{if \(\texttt{normType} = \texttt{NORM_RELATIVE | NORM_L2SQR}\) } + \f] + */ + NORM_L2SQR = 5, + /** + In the case of one input array, calculates the Hamming distance of the array from zero, + In the case of two input arrays, calculates the Hamming distance between the arrays. + */ + NORM_HAMMING = 6, + /** + Similar to NORM_HAMMING, but in the calculation, each two bits of the input sequence will + be added and treated as a single bit to be used in the same calculation as NORM_HAMMING. + */ + NORM_HAMMING2 = 7, + NORM_TYPE_MASK = 7, //!< bit-mask which can be used to separate norm type from norm flags + NORM_RELATIVE = 8, //!< flag + NORM_MINMAX = 32 //!< flag + }; + +//! comparison types +enum CmpTypes { CMP_EQ = 0, //!< src1 is equal to src2. + CMP_GT = 1, //!< src1 is greater than src2. + CMP_GE = 2, //!< src1 is greater than or equal to src2. + CMP_LT = 3, //!< src1 is less than src2. + CMP_LE = 4, //!< src1 is less than or equal to src2. + CMP_NE = 5 //!< src1 is unequal to src2. + }; + +//! generalized matrix multiplication flags +enum GemmFlags { GEMM_1_T = 1, //!< transposes src1 + GEMM_2_T = 2, //!< transposes src2 + GEMM_3_T = 4 //!< transposes src3 + }; + +enum DftFlags { + /** performs an inverse 1D or 2D transform instead of the default forward + transform. */ + DFT_INVERSE = 1, + /** scales the result: divide it by the number of array elements. Normally, it is + combined with DFT_INVERSE. */ + DFT_SCALE = 2, + /** performs a forward or inverse transform of every individual row of the input + matrix; this flag enables you to transform multiple vectors simultaneously and can be used to + decrease the overhead (which is sometimes several times larger than the processing itself) to + perform 3D and higher-dimensional transformations and so forth.*/ + DFT_ROWS = 4, + /** performs a forward transformation of 1D or 2D real array; the result, + though being a complex array, has complex-conjugate symmetry (*CCS*, see the function + description below for details), and such an array can be packed into a real array of the same + size as input, which is the fastest option and which is what the function does by default; + however, you may wish to get a full complex array (for simpler spectrum analysis, and so on) - + pass the flag to enable the function to produce a full-size complex output array. */ + DFT_COMPLEX_OUTPUT = 16, + /** performs an inverse transformation of a 1D or 2D complex array; the + result is normally a complex array of the same size, however, if the input array has + conjugate-complex symmetry (for example, it is a result of forward transformation with + DFT_COMPLEX_OUTPUT flag), the output is a real array; while the function itself does not + check whether the input is symmetrical or not, you can pass the flag and then the function + will assume the symmetry and produce the real output array (note that when the input is packed + into a real array and inverse transformation is executed, the function treats the input as a + packed complex-conjugate symmetrical array, and the output will also be a real array). */ + DFT_REAL_OUTPUT = 32, + /** specifies that input is complex input. If this flag is set, the input must have 2 channels. + On the other hand, for backwards compatibility reason, if input has 2 channels, input is + already considered complex. */ + DFT_COMPLEX_INPUT = 64, + /** performs an inverse 1D or 2D transform instead of the default forward transform. */ + DCT_INVERSE = DFT_INVERSE, + /** performs a forward or inverse transform of every individual row of the input + matrix. This flag enables you to transform multiple vectors simultaneously and can be used to + decrease the overhead (which is sometimes several times larger than the processing itself) to + perform 3D and higher-dimensional transforms and so forth.*/ + DCT_ROWS = DFT_ROWS +}; + +//! Various border types, image boundaries are denoted with `|` +//! @see borderInterpolate, copyMakeBorder +enum BorderTypes { + BORDER_CONSTANT = 0, //!< `iiiiii|abcdefgh|iiiiiii` with some specified `i` + BORDER_REPLICATE = 1, //!< `aaaaaa|abcdefgh|hhhhhhh` + BORDER_REFLECT = 2, //!< `fedcba|abcdefgh|hgfedcb` + BORDER_WRAP = 3, //!< `cdefgh|abcdefgh|abcdefg` + BORDER_REFLECT_101 = 4, //!< `gfedcb|abcdefgh|gfedcba` + BORDER_TRANSPARENT = 5, //!< `uvwxyz|abcdefgh|ijklmno` + + BORDER_REFLECT101 = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101 + BORDER_DEFAULT = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101 + BORDER_ISOLATED = 16 //!< do not look outside of ROI +}; + +//! @} core_array + +//! @addtogroup core_utils +//! @{ + +/*! @brief Signals an error and raises the exception. + +By default the function prints information about the error to stderr, +then it either stops if setBreakOnError() had been called before or raises the exception. +It is possible to alternate error processing by using redirectError(). +@param _code - error code (Error::Code) +@param _err - error description +@param _func - function name. Available only when the compiler supports getting it +@param _file - source file name where the error has occurred +@param _line - line number in the source file where the error has occurred +@see CV_Error, CV_Error_, CV_Assert, CV_DbgAssert + */ +CV_EXPORTS CV_NORETURN void error(int _code, const String& _err, const char* _func, const char* _file, int _line); + +#ifdef CV_STATIC_ANALYSIS + +// In practice, some macro are not processed correctly (noreturn is not detected). +// We need to use simplified definition for them. +#define CV_Error(code, msg) do { (void)(code); (void)(msg); abort(); } while (0) +#define CV_Error_(code, args) do { (void)(code); (void)(cv::format args); abort(); } while (0) +#define CV_Assert( expr ) do { if (!(expr)) abort(); } while (0) + +#else // CV_STATIC_ANALYSIS + +/** @brief Call the error handler. + +Currently, the error handler prints the error code and the error message to the standard +error stream `stderr`. In the Debug configuration, it then provokes memory access violation, so that +the execution stack and all the parameters can be analyzed by the debugger. In the Release +configuration, the exception is thrown. + +@param code one of Error::Code +@param msg error message +*/ +#define CV_Error( code, msg ) cv::error( code, msg, CV_Func, __FILE__, __LINE__ ) + +/** @brief Call the error handler. + +This macro can be used to construct an error message on-fly to include some dynamic information, +for example: +@code + // note the extra parentheses around the formatted text message + CV_Error_(Error::StsOutOfRange, + ("the value at (%d, %d)=%g is out of range", badPt.x, badPt.y, badValue)); +@endcode +@param code one of Error::Code +@param args printf-like formatted error message in parentheses +*/ +#define CV_Error_( code, args ) cv::error( code, cv::format args, CV_Func, __FILE__, __LINE__ ) + +/** @brief Checks a condition at runtime and throws exception if it fails + +The macros CV_Assert (and CV_DbgAssert(expr)) evaluate the specified expression. If it is 0, the macros +raise an error (see cv::error). The macro CV_Assert checks the condition in both Debug and Release +configurations while CV_DbgAssert is only retained in the Debug configuration. +*/ +#define CV_Assert( expr ) do { if(!!(expr)) ; else cv::error( cv::Error::StsAssert, #expr, CV_Func, __FILE__, __LINE__ ); } while(0) + +#endif // CV_STATIC_ANALYSIS + +//! @cond IGNORED +#if !defined(__OPENCV_BUILD) // TODO: backward compatibility only +#ifndef CV_ErrorNoReturn +#define CV_ErrorNoReturn CV_Error +#endif +#ifndef CV_ErrorNoReturn_ +#define CV_ErrorNoReturn_ CV_Error_ +#endif +#endif + +#define CV_Assert_1 CV_Assert +#define CV_Assert_2( expr, ... ) CV_Assert_1(expr); __CV_EXPAND(CV_Assert_1( __VA_ARGS__ )) +#define CV_Assert_3( expr, ... ) CV_Assert_1(expr); __CV_EXPAND(CV_Assert_2( __VA_ARGS__ )) +#define CV_Assert_4( expr, ... ) CV_Assert_1(expr); __CV_EXPAND(CV_Assert_3( __VA_ARGS__ )) +#define CV_Assert_5( expr, ... ) CV_Assert_1(expr); __CV_EXPAND(CV_Assert_4( __VA_ARGS__ )) +#define CV_Assert_6( expr, ... ) CV_Assert_1(expr); __CV_EXPAND(CV_Assert_5( __VA_ARGS__ )) +#define CV_Assert_7( expr, ... ) CV_Assert_1(expr); __CV_EXPAND(CV_Assert_6( __VA_ARGS__ )) +#define CV_Assert_8( expr, ... ) CV_Assert_1(expr); __CV_EXPAND(CV_Assert_7( __VA_ARGS__ )) +#define CV_Assert_9( expr, ... ) CV_Assert_1(expr); __CV_EXPAND(CV_Assert_8( __VA_ARGS__ )) +#define CV_Assert_10( expr, ... ) CV_Assert_1(expr); __CV_EXPAND(CV_Assert_9( __VA_ARGS__ )) + +#define CV_Assert_N(...) do { __CV_EXPAND(__CV_CAT(CV_Assert_, __CV_VA_NUM_ARGS(__VA_ARGS__)) (__VA_ARGS__)); } while(0) + +//! @endcond + +#if defined _DEBUG || defined CV_STATIC_ANALYSIS +# define CV_DbgAssert(expr) CV_Assert(expr) +#else +/** replaced with CV_Assert(expr) in Debug configuration */ +# define CV_DbgAssert(expr) +#endif + +/* + * Hamming distance functor - counts the bit differences between two strings - useful for the Brief descriptor + * bit count of A exclusive XOR'ed with B + */ +struct CV_EXPORTS Hamming +{ + static const NormTypes normType = NORM_HAMMING; + typedef unsigned char ValueType; + typedef int ResultType; + + /** this will count the bits in a ^ b + */ + ResultType operator()( const unsigned char* a, const unsigned char* b, int size ) const; +}; + +typedef Hamming HammingLUT; + +/////////////////////////////////// inline norms //////////////////////////////////// + +template inline _Tp cv_abs(_Tp x) { return std::abs(x); } +inline int cv_abs(uchar x) { return x; } +inline int cv_abs(schar x) { return std::abs(x); } +inline int cv_abs(ushort x) { return x; } +inline int cv_abs(short x) { return std::abs(x); } + +template static inline +_AccTp normL2Sqr(const _Tp* a, int n) +{ + _AccTp s = 0; + int i=0; +#if CV_ENABLE_UNROLLED + for( ; i <= n - 4; i += 4 ) + { + _AccTp v0 = a[i], v1 = a[i+1], v2 = a[i+2], v3 = a[i+3]; + s += v0*v0 + v1*v1 + v2*v2 + v3*v3; + } +#endif + for( ; i < n; i++ ) + { + _AccTp v = a[i]; + s += v*v; + } + return s; +} + +template static inline +_AccTp normL1(const _Tp* a, int n) +{ + _AccTp s = 0; + int i = 0; +#if CV_ENABLE_UNROLLED + for(; i <= n - 4; i += 4 ) + { + s += (_AccTp)cv_abs(a[i]) + (_AccTp)cv_abs(a[i+1]) + + (_AccTp)cv_abs(a[i+2]) + (_AccTp)cv_abs(a[i+3]); + } +#endif + for( ; i < n; i++ ) + s += cv_abs(a[i]); + return s; +} + +template static inline +_AccTp normInf(const _Tp* a, int n) +{ + _AccTp s = 0; + for( int i = 0; i < n; i++ ) + s = std::max(s, (_AccTp)cv_abs(a[i])); + return s; +} + +template static inline +_AccTp normL2Sqr(const _Tp* a, const _Tp* b, int n) +{ + _AccTp s = 0; + int i= 0; +#if CV_ENABLE_UNROLLED + for(; i <= n - 4; i += 4 ) + { + _AccTp v0 = _AccTp(a[i] - b[i]), v1 = _AccTp(a[i+1] - b[i+1]), v2 = _AccTp(a[i+2] - b[i+2]), v3 = _AccTp(a[i+3] - b[i+3]); + s += v0*v0 + v1*v1 + v2*v2 + v3*v3; + } +#endif + for( ; i < n; i++ ) + { + _AccTp v = _AccTp(a[i] - b[i]); + s += v*v; + } + return s; +} + +static inline float normL2Sqr(const float* a, const float* b, int n) +{ + float s = 0.f; + for( int i = 0; i < n; i++ ) + { + float v = a[i] - b[i]; + s += v*v; + } + return s; +} + +template static inline +_AccTp normL1(const _Tp* a, const _Tp* b, int n) +{ + _AccTp s = 0; + int i= 0; +#if CV_ENABLE_UNROLLED + for(; i <= n - 4; i += 4 ) + { + _AccTp v0 = _AccTp(a[i] - b[i]), v1 = _AccTp(a[i+1] - b[i+1]), v2 = _AccTp(a[i+2] - b[i+2]), v3 = _AccTp(a[i+3] - b[i+3]); + s += std::abs(v0) + std::abs(v1) + std::abs(v2) + std::abs(v3); + } +#endif + for( ; i < n; i++ ) + { + _AccTp v = _AccTp(a[i] - b[i]); + s += std::abs(v); + } + return s; +} + +inline float normL1(const float* a, const float* b, int n) +{ + float s = 0.f; + for( int i = 0; i < n; i++ ) + { + s += std::abs(a[i] - b[i]); + } + return s; +} + +inline int normL1(const uchar* a, const uchar* b, int n) +{ + int s = 0; + for( int i = 0; i < n; i++ ) + { + s += std::abs(a[i] - b[i]); + } + return s; +} + +template static inline +_AccTp normInf(const _Tp* a, const _Tp* b, int n) +{ + _AccTp s = 0; + for( int i = 0; i < n; i++ ) + { + _AccTp v0 = a[i] - b[i]; + s = std::max(s, std::abs(v0)); + } + return s; +} + +/** @brief Computes the cube root of an argument. + + The function cubeRoot computes \f$\sqrt[3]{\texttt{val}}\f$. Negative arguments are handled correctly. + NaN and Inf are not handled. The accuracy approaches the maximum possible accuracy for + single-precision data. + @param val A function argument. + */ +CV_EXPORTS_W float cubeRoot(float val); + +/** @overload + +cubeRoot with argument of `double` type calls `std::cbrt(double)` +*/ +static inline +double cubeRoot(double val) +{ + return std::cbrt(val); +} + +/** @brief Calculates the angle of a 2D vector in degrees. + + The function fastAtan2 calculates the full-range angle of an input 2D vector. The angle is measured + in degrees and varies from 0 to 360 degrees. The accuracy is about 0.3 degrees. + @param x x-coordinate of the vector. + @param y y-coordinate of the vector. + */ +CV_EXPORTS_W float fastAtan2(float y, float x); + +/** proxy for hal::LU */ +CV_EXPORTS int LU(float* A, size_t astep, int m, float* b, size_t bstep, int n); +/** proxy for hal::LU */ +CV_EXPORTS int LU(double* A, size_t astep, int m, double* b, size_t bstep, int n); +/** proxy for hal::Cholesky */ +CV_EXPORTS bool Cholesky(float* A, size_t astep, int m, float* b, size_t bstep, int n); +/** proxy for hal::Cholesky */ +CV_EXPORTS bool Cholesky(double* A, size_t astep, int m, double* b, size_t bstep, int n); + +////////////////// forward declarations for important OpenCV types ////////////////// + +//! @cond IGNORED + +template class Vec; +template class Matx; + +template class Complex; +template class Point_; +template class Point3_; +template class Size_; +template class Rect_; +template class Scalar_; + +class CV_EXPORTS RotatedRect; +class CV_EXPORTS Range; +class CV_EXPORTS TermCriteria; +class CV_EXPORTS KeyPoint; +class CV_EXPORTS DMatch; +class CV_EXPORTS RNG; + +class CV_EXPORTS Mat; +class CV_EXPORTS MatExpr; + +class CV_EXPORTS UMat; + +class CV_EXPORTS SparseMat; +typedef Mat MatND; + +template class Mat_; +template class SparseMat_; + +class CV_EXPORTS MatConstIterator; +class CV_EXPORTS SparseMatIterator; +class CV_EXPORTS SparseMatConstIterator; +template class MatIterator_; +template class MatConstIterator_; +template class SparseMatIterator_; +template class SparseMatConstIterator_; + +namespace ogl +{ + class CV_EXPORTS Buffer; + class CV_EXPORTS Texture2D; + class CV_EXPORTS Arrays; +} + +namespace cuda +{ + class CV_EXPORTS GpuMat; + class CV_EXPORTS HostMem; + class CV_EXPORTS Stream; + class CV_EXPORTS Event; +} + +namespace cudev +{ + template class GpuMat_; +} + +namespace ipp +{ +CV_EXPORTS unsigned long long getIppFeatures(); +CV_EXPORTS void setIppStatus(int status, const char * const funcname = NULL, const char * const filename = NULL, + int line = 0); +CV_EXPORTS int getIppStatus(); +CV_EXPORTS String getIppErrorLocation(); +CV_EXPORTS_W bool useIPP(); +CV_EXPORTS_W void setUseIPP(bool flag); +CV_EXPORTS_W String getIppVersion(); + +// IPP Not-Exact mode. This function may force use of IPP then both IPP and OpenCV provide proper results +// but have internal accuracy differences which have too much direct or indirect impact on accuracy tests. +CV_EXPORTS_W bool useIPP_NotExact(); +CV_EXPORTS_W void setUseIPP_NotExact(bool flag); +#ifndef DISABLE_OPENCV_3_COMPATIBILITY +static inline bool useIPP_NE() { return useIPP_NotExact(); } +static inline void setUseIPP_NE(bool flag) { setUseIPP_NotExact(flag); } +#endif + +} // ipp + +//! @endcond + +//! @} core_utils + + + + +} // cv + +#include "opencv2/core/neon_utils.hpp" +#include "opencv2/core/vsx_utils.hpp" +#include "opencv2/core/check.hpp" + +#endif //OPENCV_CORE_BASE_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/bindings_utils.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/bindings_utils.hpp new file mode 100644 index 0000000..1c14334 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/bindings_utils.hpp @@ -0,0 +1,287 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_BINDINGS_UTILS_HPP +#define OPENCV_CORE_BINDINGS_UTILS_HPP + +#include +#include +#include + +#include + +namespace cv { namespace utils { +//! @addtogroup core_utils +//! @{ + +CV_EXPORTS_W String dumpInputArray(InputArray argument); + +CV_EXPORTS_W String dumpInputArrayOfArrays(InputArrayOfArrays argument); + +CV_EXPORTS_W String dumpInputOutputArray(InputOutputArray argument); + +CV_EXPORTS_W String dumpInputOutputArrayOfArrays(InputOutputArrayOfArrays argument); + +CV_WRAP static inline +String dumpBool(bool argument) +{ + return (argument) ? String("Bool: True") : String("Bool: False"); +} + +CV_WRAP static inline +String dumpInt(int argument) +{ + return cv::format("Int: %d", argument); +} + +CV_WRAP static inline +String dumpSizeT(size_t argument) +{ + std::ostringstream oss("size_t: ", std::ios::ate); + oss << argument; + return oss.str(); +} + +CV_WRAP static inline +String dumpFloat(float argument) +{ + return cv::format("Float: %.2f", argument); +} + +CV_WRAP static inline +String dumpDouble(double argument) +{ + return cv::format("Double: %.2f", argument); +} + +CV_WRAP static inline +String dumpCString(const char* argument) +{ + return cv::format("String: %s", argument); +} + +CV_WRAP static inline +String dumpString(const String& argument) +{ + return cv::format("String: %s", argument.c_str()); +} + +CV_WRAP static inline +String testOverloadResolution(int value, const Point& point = Point(42, 24)) +{ + return format("overload (int=%d, point=(x=%d, y=%d))", value, point.x, + point.y); +} + +CV_WRAP static inline +String testOverloadResolution(const Rect& rect) +{ + return format("overload (rect=(x=%d, y=%d, w=%d, h=%d))", rect.x, rect.y, + rect.width, rect.height); +} + +CV_WRAP static inline +String dumpRect(const Rect& argument) +{ + return format("rect: (x=%d, y=%d, w=%d, h=%d)", argument.x, argument.y, + argument.width, argument.height); +} + +CV_WRAP static inline +String dumpTermCriteria(const TermCriteria& argument) +{ + return format("term_criteria: (type=%d, max_count=%d, epsilon=%lf", + argument.type, argument.maxCount, argument.epsilon); +} + +CV_WRAP static inline +String dumpRotatedRect(const RotatedRect& argument) +{ + return format("rotated_rect: (c_x=%f, c_y=%f, w=%f, h=%f, a=%f)", + argument.center.x, argument.center.y, argument.size.width, + argument.size.height, argument.angle); +} + +CV_WRAP static inline +RotatedRect testRotatedRect(float x, float y, float w, float h, float angle) +{ + return RotatedRect(Point2f(x, y), Size2f(w, h), angle); +} + +CV_WRAP static inline +std::vector testRotatedRectVector(float x, float y, float w, float h, float angle) +{ + std::vector result; + for (int i = 0; i < 10; i++) + result.push_back(RotatedRect(Point2f(x + i, y + 2 * i), Size2f(w, h), angle + 10 * i)); + return result; +} + +CV_WRAP static inline +String dumpRange(const Range& argument) +{ + if (argument == Range::all()) + { + return "range: all"; + } + else + { + return format("range: (s=%d, e=%d)", argument.start, argument.end); + } +} + +CV_WRAP static inline +int testOverwriteNativeMethod(int argument) +{ + return argument; +} + +CV_WRAP static inline +String testReservedKeywordConversion(int positional_argument, int lambda = 2, int from = 3) +{ + return format("arg=%d, lambda=%d, from=%d", positional_argument, lambda, from); +} + +CV_EXPORTS_W String dumpVectorOfInt(const std::vector& vec); + +CV_EXPORTS_W String dumpVectorOfDouble(const std::vector& vec); + +CV_EXPORTS_W String dumpVectorOfRect(const std::vector& vec); + +CV_WRAP static inline +void generateVectorOfRect(size_t len, CV_OUT std::vector& vec) +{ + vec.resize(len); + if (len > 0) + { + RNG rng(12345); + Mat tmp(static_cast(len), 1, CV_32SC4); + rng.fill(tmp, RNG::UNIFORM, 10, 20); + tmp.copyTo(vec); + } +} + +CV_WRAP static inline +void generateVectorOfInt(size_t len, CV_OUT std::vector& vec) +{ + vec.resize(len); + if (len > 0) + { + RNG rng(554433); + Mat tmp(static_cast(len), 1, CV_32SC1); + rng.fill(tmp, RNG::UNIFORM, -10, 10); + tmp.copyTo(vec); + } +} + +CV_WRAP static inline +void generateVectorOfMat(size_t len, int rows, int cols, int dtype, CV_OUT std::vector& vec) +{ + vec.resize(len); + if (len > 0) + { + RNG rng(65431); + for (size_t i = 0; i < len; ++i) + { + vec[i].create(rows, cols, dtype); + rng.fill(vec[i], RNG::UNIFORM, 0, 10); + } + } +} + +CV_WRAP static inline +AsyncArray testAsyncArray(InputArray argument) +{ + AsyncPromise p; + p.setValue(argument); + return p.getArrayResult(); +} + +CV_WRAP static inline +AsyncArray testAsyncException() +{ + AsyncPromise p; + return p.getArrayResult(); +} + +namespace nested { +CV_WRAP static inline bool testEchoBooleanFunction(bool flag) { + return flag; +} + +class CV_EXPORTS_W CV_WRAP_AS(ExportClassName) OriginalClassName +{ +public: + struct CV_EXPORTS_W_SIMPLE Params + { + CV_PROP_RW int int_value; + CV_PROP_RW float float_value; + + CV_WRAP explicit Params(int int_param = 123, float float_param = 3.5f) + { + int_value = int_param; + float_value = float_param; + } + }; + + explicit OriginalClassName(const OriginalClassName::Params& params = OriginalClassName::Params()) + { + params_ = params; + } + + CV_WRAP int getIntParam() const + { + return params_.int_value; + } + + CV_WRAP float getFloatParam() const + { + return params_.float_value; + } + + CV_WRAP static std::string originalName() + { + return "OriginalClassName"; + } + + CV_WRAP static Ptr + create(const OriginalClassName::Params& params = OriginalClassName::Params()) + { + return makePtr(params); + } + +private: + OriginalClassName::Params params_; +}; + +typedef OriginalClassName::Params OriginalClassName_Params; +} // namespace nested + +namespace fs { + CV_EXPORTS_W cv::String getCacheDirectoryForDownloads(); +} // namespace fs + +//! @} // core_utils +} // namespace cv::utils + +//! @cond IGNORED + +CV_WRAP static inline +int setLogLevel(int level) +{ + // NB: Binding generators doesn't work with enums properly yet, so we define separate overload here + return cv::utils::logging::setLogLevel((cv::utils::logging::LogLevel)level); +} + +CV_WRAP static inline +int getLogLevel() +{ + return cv::utils::logging::getLogLevel(); +} + +//! @endcond IGNORED + +} // namespaces cv / utils + +#endif // OPENCV_CORE_BINDINGS_UTILS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/bufferpool.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/bufferpool.hpp new file mode 100644 index 0000000..4698e5d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/bufferpool.hpp @@ -0,0 +1,40 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// Copyright (C) 2014, Advanced Micro Devices, Inc., all rights reserved. + +#ifndef OPENCV_CORE_BUFFER_POOL_HPP +#define OPENCV_CORE_BUFFER_POOL_HPP + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4265) +#endif + +namespace cv +{ + +//! @addtogroup core +//! @{ + +class BufferPoolController +{ +protected: + ~BufferPoolController() { } +public: + virtual size_t getReservedSize() const = 0; + virtual size_t getMaxReservedSize() const = 0; + virtual void setMaxReservedSize(size_t size) = 0; + virtual void freeAllReservedBuffers() = 0; +}; + +//! @} + +} + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif // OPENCV_CORE_BUFFER_POOL_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/check.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/check.hpp new file mode 100644 index 0000000..a32b811 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/check.hpp @@ -0,0 +1,160 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_CHECK_HPP +#define OPENCV_CORE_CHECK_HPP + +#include + +namespace cv { + +/** Returns string of cv::Mat depth value: CV_8U -> "CV_8U" or "" */ +CV_EXPORTS const char* depthToString(int depth); + +/** Returns string of cv::Mat depth value: CV_8UC3 -> "CV_8UC3" or "" */ +CV_EXPORTS String typeToString(int type); + + +//! @cond IGNORED +namespace detail { + +/** Returns string of cv::Mat depth value: CV_8U -> "CV_8U" or NULL */ +CV_EXPORTS const char* depthToString_(int depth); + +/** Returns string of cv::Mat depth value: CV_8UC3 -> "CV_8UC3" or cv::String() */ +CV_EXPORTS cv::String typeToString_(int type); + +enum TestOp { + TEST_CUSTOM = 0, + TEST_EQ = 1, + TEST_NE = 2, + TEST_LE = 3, + TEST_LT = 4, + TEST_GE = 5, + TEST_GT = 6, + CV__LAST_TEST_OP +}; + +struct CheckContext { + const char* func; + const char* file; + int line; + enum TestOp testOp; + const char* message; + const char* p1_str; + const char* p2_str; +}; + +#ifndef CV__CHECK_FILENAME +# define CV__CHECK_FILENAME __FILE__ +#endif + +#ifndef CV__CHECK_FUNCTION +# if defined _MSC_VER +# define CV__CHECK_FUNCTION __FUNCSIG__ +# elif defined __GNUC__ +# define CV__CHECK_FUNCTION __PRETTY_FUNCTION__ +# else +# define CV__CHECK_FUNCTION "" +# endif +#endif + +#define CV__CHECK_LOCATION_VARNAME(id) CVAUX_CONCAT(CVAUX_CONCAT(__cv_check_, id), __LINE__) +#define CV__DEFINE_CHECK_CONTEXT(id, message, testOp, p1_str, p2_str) \ + static const cv::detail::CheckContext CV__CHECK_LOCATION_VARNAME(id) = \ + { CV__CHECK_FUNCTION, CV__CHECK_FILENAME, __LINE__, testOp, "" message, "" p1_str, "" p2_str } + +CV_EXPORTS void CV_NORETURN check_failed_auto(const int v1, const int v2, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const size_t v1, const size_t v2, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const float v1, const float v2, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const double v1, const double v2, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const Size_ v1, const Size_ v2, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_MatDepth(const int v1, const int v2, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_MatType(const int v1, const int v2, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_MatChannels(const int v1, const int v2, const CheckContext& ctx); + +CV_EXPORTS void CV_NORETURN check_failed_auto(const int v, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const size_t v, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const float v, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const double v, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const Size_ v, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const std::string& v1, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_MatDepth(const int v, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_MatType(const int v, const CheckContext& ctx); +CV_EXPORTS void CV_NORETURN check_failed_MatChannels(const int v, const CheckContext& ctx); + + +#define CV__TEST_EQ(v1, v2) ((v1) == (v2)) +#define CV__TEST_NE(v1, v2) ((v1) != (v2)) +#define CV__TEST_LE(v1, v2) ((v1) <= (v2)) +#define CV__TEST_LT(v1, v2) ((v1) < (v2)) +#define CV__TEST_GE(v1, v2) ((v1) >= (v2)) +#define CV__TEST_GT(v1, v2) ((v1) > (v2)) + +#define CV__CHECK(id, op, type, v1, v2, v1_str, v2_str, msg_str) do { \ + if(CV__TEST_##op((v1), (v2))) ; else { \ + CV__DEFINE_CHECK_CONTEXT(id, msg_str, cv::detail::TEST_ ## op, v1_str, v2_str); \ + cv::detail::check_failed_ ## type((v1), (v2), CV__CHECK_LOCATION_VARNAME(id)); \ + } \ +} while (0) + +#define CV__CHECK_CUSTOM_TEST(id, type, v, test_expr, v_str, test_expr_str, msg_str) do { \ + if(!!(test_expr)) ; else { \ + CV__DEFINE_CHECK_CONTEXT(id, msg_str, cv::detail::TEST_CUSTOM, v_str, test_expr_str); \ + cv::detail::check_failed_ ## type((v), CV__CHECK_LOCATION_VARNAME(id)); \ + } \ +} while (0) + +} // namespace +//! @endcond + + +/// Supported values of these types: int, float, double +#define CV_CheckEQ(v1, v2, msg) CV__CHECK(_, EQ, auto, v1, v2, #v1, #v2, msg) +#define CV_CheckNE(v1, v2, msg) CV__CHECK(_, NE, auto, v1, v2, #v1, #v2, msg) +#define CV_CheckLE(v1, v2, msg) CV__CHECK(_, LE, auto, v1, v2, #v1, #v2, msg) +#define CV_CheckLT(v1, v2, msg) CV__CHECK(_, LT, auto, v1, v2, #v1, #v2, msg) +#define CV_CheckGE(v1, v2, msg) CV__CHECK(_, GE, auto, v1, v2, #v1, #v2, msg) +#define CV_CheckGT(v1, v2, msg) CV__CHECK(_, GT, auto, v1, v2, #v1, #v2, msg) + +/// Check with additional "decoding" of type values in error message +#define CV_CheckTypeEQ(t1, t2, msg) CV__CHECK(_, EQ, MatType, t1, t2, #t1, #t2, msg) +/// Check with additional "decoding" of depth values in error message +#define CV_CheckDepthEQ(d1, d2, msg) CV__CHECK(_, EQ, MatDepth, d1, d2, #d1, #d2, msg) + +#define CV_CheckChannelsEQ(c1, c2, msg) CV__CHECK(_, EQ, MatChannels, c1, c2, #c1, #c2, msg) + +/// Example: type == CV_8UC1 || type == CV_8UC3 +#define CV_CheckType(t, test_expr, msg) CV__CHECK_CUSTOM_TEST(_, MatType, t, (test_expr), #t, #test_expr, msg) + +/// Example: depth == CV_32F || depth == CV_64F +#define CV_CheckDepth(t, test_expr, msg) CV__CHECK_CUSTOM_TEST(_, MatDepth, t, (test_expr), #t, #test_expr, msg) + +/// Example: v == A || v == B +#define CV_Check(v, test_expr, msg) CV__CHECK_CUSTOM_TEST(_, auto, v, (test_expr), #v, #test_expr, msg) + +/// Some complex conditions: CV_Check(src2, src2.empty() || (src2.type() == src1.type() && src2.size() == src1.size()), "src2 should have same size/type as src1") +// TODO define pretty-printers + +#ifndef NDEBUG +#define CV_DbgCheck(v, test_expr, msg) CV__CHECK_CUSTOM_TEST(_, auto, v, (test_expr), #v, #test_expr, msg) +#define CV_DbgCheckEQ(v1, v2, msg) CV__CHECK(_, EQ, auto, v1, v2, #v1, #v2, msg) +#define CV_DbgCheckNE(v1, v2, msg) CV__CHECK(_, NE, auto, v1, v2, #v1, #v2, msg) +#define CV_DbgCheckLE(v1, v2, msg) CV__CHECK(_, LE, auto, v1, v2, #v1, #v2, msg) +#define CV_DbgCheckLT(v1, v2, msg) CV__CHECK(_, LT, auto, v1, v2, #v1, #v2, msg) +#define CV_DbgCheckGE(v1, v2, msg) CV__CHECK(_, GE, auto, v1, v2, #v1, #v2, msg) +#define CV_DbgCheckGT(v1, v2, msg) CV__CHECK(_, GT, auto, v1, v2, #v1, #v2, msg) +#else +#define CV_DbgCheck(v, test_expr, msg) do { } while (0) +#define CV_DbgCheckEQ(v1, v2, msg) do { } while (0) +#define CV_DbgCheckNE(v1, v2, msg) do { } while (0) +#define CV_DbgCheckLE(v1, v2, msg) do { } while (0) +#define CV_DbgCheckLT(v1, v2, msg) do { } while (0) +#define CV_DbgCheckGE(v1, v2, msg) do { } while (0) +#define CV_DbgCheckGT(v1, v2, msg) do { } while (0) +#endif + +} // namespace + +#endif // OPENCV_CORE_CHECK_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/core.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/core.hpp new file mode 100644 index 0000000..4389183 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/core.hpp @@ -0,0 +1,48 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifdef __OPENCV_BUILD +#error this is a compatibility header which should not be used inside the OpenCV library +#endif + +#include "opencv2/core.hpp" diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/core_c.h b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/core_c.h new file mode 100644 index 0000000..7b686b8 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/core_c.h @@ -0,0 +1,3128 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + + +#ifndef OPENCV_CORE_C_H +#define OPENCV_CORE_C_H + +#include "opencv2/core/types_c.h" + +#ifdef __cplusplus +/* disable MSVC warning C4190 / clang-cl -Wreturn-type-c-linkage: + 'function' has C-linkage specified, but returns UDT 'typename' + which is incompatible with C + + It is OK to disable it because we only extend few plain structures with + C++ constructors for simpler interoperability with C++ API of the library +*/ +# if defined(__clang__) + // handle clang on Linux and clang-cl (i. e. clang on Windows) first +# pragma GCC diagnostic ignored "-Wreturn-type-c-linkage" +# elif defined(_MSC_VER) + // then handle MSVC +# pragma warning(disable:4190) +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup core_c + @{ +*/ + +/****************************************************************************************\ +* Array allocation, deallocation, initialization and access to elements * +\****************************************************************************************/ + +/** `malloc` wrapper. + If there is no enough memory, the function + (as well as other OpenCV functions that call cvAlloc) + raises an error. */ +CVAPI(void*) cvAlloc( size_t size ); + +/** `free` wrapper. + Here and further all the memory releasing functions + (that all call cvFree) take double pointer in order to + to clear pointer to the data after releasing it. + Passing pointer to NULL pointer is Ok: nothing happens in this case +*/ +CVAPI(void) cvFree_( void* ptr ); +#define cvFree(ptr) (cvFree_(*(ptr)), *(ptr)=0) + +/** @brief Creates an image header but does not allocate the image data. + +@param size Image width and height +@param depth Image depth (see cvCreateImage ) +@param channels Number of channels (see cvCreateImage ) + */ +CVAPI(IplImage*) cvCreateImageHeader( CvSize size, int depth, int channels ); + +/** @brief Initializes an image header that was previously allocated. + +The returned IplImage\* points to the initialized header. +@param image Image header to initialize +@param size Image width and height +@param depth Image depth (see cvCreateImage ) +@param channels Number of channels (see cvCreateImage ) +@param origin Top-left IPL_ORIGIN_TL or bottom-left IPL_ORIGIN_BL +@param align Alignment for image rows, typically 4 or 8 bytes + */ +CVAPI(IplImage*) cvInitImageHeader( IplImage* image, CvSize size, int depth, + int channels, int origin CV_DEFAULT(0), + int align CV_DEFAULT(4)); + +/** @brief Creates an image header and allocates the image data. + +This function call is equivalent to the following code: +@code + header = cvCreateImageHeader(size, depth, channels); + cvCreateData(header); +@endcode +@param size Image width and height +@param depth Bit depth of image elements. See IplImage for valid depths. +@param channels Number of channels per pixel. See IplImage for details. This function only creates +images with interleaved channels. + */ +CVAPI(IplImage*) cvCreateImage( CvSize size, int depth, int channels ); + +/** @brief Deallocates an image header. + +This call is an analogue of : +@code + if(image ) + { + iplDeallocate(*image, IPL_IMAGE_HEADER | IPL_IMAGE_ROI); + *image = 0; + } +@endcode +but it does not use IPL functions by default (see the CV_TURN_ON_IPL_COMPATIBILITY macro). +@param image Double pointer to the image header + */ +CVAPI(void) cvReleaseImageHeader( IplImage** image ); + +/** @brief Deallocates the image header and the image data. + +This call is a shortened form of : +@code + if(*image ) + { + cvReleaseData(*image); + cvReleaseImageHeader(image); + } +@endcode +@param image Double pointer to the image header +*/ +CVAPI(void) cvReleaseImage( IplImage** image ); + +/** Creates a copy of IPL image (widthStep may differ) */ +CVAPI(IplImage*) cvCloneImage( const IplImage* image ); + +/** @brief Sets the channel of interest in an IplImage. + +If the ROI is set to NULL and the coi is *not* 0, the ROI is allocated. Most OpenCV functions do +*not* support the COI setting, so to process an individual image/matrix channel one may copy (via +cvCopy or cvSplit) the channel to a separate image/matrix, process it and then copy the result +back (via cvCopy or cvMerge) if needed. +@param image A pointer to the image header +@param coi The channel of interest. 0 - all channels are selected, 1 - first channel is selected, +etc. Note that the channel indices become 1-based. + */ +CVAPI(void) cvSetImageCOI( IplImage* image, int coi ); + +/** @brief Returns the index of the channel of interest. + +Returns the channel of interest of in an IplImage. Returned values correspond to the coi in +cvSetImageCOI. +@param image A pointer to the image header + */ +CVAPI(int) cvGetImageCOI( const IplImage* image ); + +/** @brief Sets an image Region Of Interest (ROI) for a given rectangle. + +If the original image ROI was NULL and the rect is not the whole image, the ROI structure is +allocated. + +Most OpenCV functions support the use of ROI and treat the image rectangle as a separate image. For +example, all of the pixel coordinates are counted from the top-left (or bottom-left) corner of the +ROI, not the original image. +@param image A pointer to the image header +@param rect The ROI rectangle + */ +CVAPI(void) cvSetImageROI( IplImage* image, CvRect rect ); + +/** @brief Resets the image ROI to include the entire image and releases the ROI structure. + +This produces a similar result to the following, but in addition it releases the ROI structure. : +@code + cvSetImageROI(image, cvRect(0, 0, image->width, image->height )); + cvSetImageCOI(image, 0); +@endcode +@param image A pointer to the image header + */ +CVAPI(void) cvResetImageROI( IplImage* image ); + +/** @brief Returns the image ROI. + +If there is no ROI set, cvRect(0,0,image-\>width,image-\>height) is returned. +@param image A pointer to the image header + */ +CVAPI(CvRect) cvGetImageROI( const IplImage* image ); + +/** @brief Creates a matrix header but does not allocate the matrix data. + +The function allocates a new matrix header and returns a pointer to it. The matrix data can then be +allocated using cvCreateData or set explicitly to user-allocated data via cvSetData. +@param rows Number of rows in the matrix +@param cols Number of columns in the matrix +@param type Type of the matrix elements, see cvCreateMat + */ +CVAPI(CvMat*) cvCreateMatHeader( int rows, int cols, int type ); + +#define CV_AUTOSTEP 0x7fffffff + +/** @brief Initializes a pre-allocated matrix header. + +This function is often used to process raw data with OpenCV matrix functions. For example, the +following code computes the matrix product of two matrices, stored as ordinary arrays: +@code + double a[] = { 1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12 }; + + double b[] = { 1, 5, 9, + 2, 6, 10, + 3, 7, 11, + 4, 8, 12 }; + + double c[9]; + CvMat Ma, Mb, Mc ; + + cvInitMatHeader(&Ma, 3, 4, CV_64FC1, a); + cvInitMatHeader(&Mb, 4, 3, CV_64FC1, b); + cvInitMatHeader(&Mc, 3, 3, CV_64FC1, c); + + cvMatMulAdd(&Ma, &Mb, 0, &Mc); + // the c array now contains the product of a (3x4) and b (4x3) +@endcode +@param mat A pointer to the matrix header to be initialized +@param rows Number of rows in the matrix +@param cols Number of columns in the matrix +@param type Type of the matrix elements, see cvCreateMat . +@param data Optional: data pointer assigned to the matrix header +@param step Optional: full row width in bytes of the assigned data. By default, the minimal +possible step is used which assumes there are no gaps between subsequent rows of the matrix. + */ +CVAPI(CvMat*) cvInitMatHeader( CvMat* mat, int rows, int cols, + int type, void* data CV_DEFAULT(NULL), + int step CV_DEFAULT(CV_AUTOSTEP) ); + +/** @brief Creates a matrix header and allocates the matrix data. + +The function call is equivalent to the following code: +@code + CvMat* mat = cvCreateMatHeader(rows, cols, type); + cvCreateData(mat); +@endcode +@param rows Number of rows in the matrix +@param cols Number of columns in the matrix +@param type The type of the matrix elements in the form +CV_\\C\ , where S=signed, U=unsigned, F=float. For +example, CV _ 8UC1 means the elements are 8-bit unsigned and the there is 1 channel, and CV _ +32SC2 means the elements are 32-bit signed and there are 2 channels. + */ +CVAPI(CvMat*) cvCreateMat( int rows, int cols, int type ); + +/** @brief Deallocates a matrix. + +The function decrements the matrix data reference counter and deallocates matrix header. If the data +reference counter is 0, it also deallocates the data. : +@code + if(*mat ) + cvDecRefData(*mat); + cvFree((void**)mat); +@endcode +@param mat Double pointer to the matrix + */ +CVAPI(void) cvReleaseMat( CvMat** mat ); + +/** @brief Decrements an array data reference counter. + +The function decrements the data reference counter in a CvMat or CvMatND if the reference counter + +pointer is not NULL. If the counter reaches zero, the data is deallocated. In the current +implementation the reference counter is not NULL only if the data was allocated using the +cvCreateData function. The counter will be NULL in other cases such as: external data was assigned +to the header using cvSetData, header is part of a larger matrix or image, or the header was +converted from an image or n-dimensional matrix header. +@param arr Pointer to an array header + */ +CV_INLINE void cvDecRefData( CvArr* arr ) +{ + if( CV_IS_MAT( arr )) + { + CvMat* mat = (CvMat*)arr; + mat->data.ptr = NULL; + if( mat->refcount != NULL && --*mat->refcount == 0 ) + cvFree( &mat->refcount ); + mat->refcount = NULL; + } + else if( CV_IS_MATND( arr )) + { + CvMatND* mat = (CvMatND*)arr; + mat->data.ptr = NULL; + if( mat->refcount != NULL && --*mat->refcount == 0 ) + cvFree( &mat->refcount ); + mat->refcount = NULL; + } +} + +/** @brief Increments array data reference counter. + +The function increments CvMat or CvMatND data reference counter and returns the new counter value if +the reference counter pointer is not NULL, otherwise it returns zero. +@param arr Array header + */ +CV_INLINE int cvIncRefData( CvArr* arr ) +{ + int refcount = 0; + if( CV_IS_MAT( arr )) + { + CvMat* mat = (CvMat*)arr; + if( mat->refcount != NULL ) + refcount = ++*mat->refcount; + } + else if( CV_IS_MATND( arr )) + { + CvMatND* mat = (CvMatND*)arr; + if( mat->refcount != NULL ) + refcount = ++*mat->refcount; + } + return refcount; +} + + +/** Creates an exact copy of the input matrix (except, may be, step value) */ +CVAPI(CvMat*) cvCloneMat( const CvMat* mat ); + + +/** @brief Returns matrix header corresponding to the rectangular sub-array of input image or matrix. + +The function returns header, corresponding to a specified rectangle of the input array. In other + +words, it allows the user to treat a rectangular part of input array as a stand-alone array. ROI is +taken into account by the function so the sub-array of ROI is actually extracted. +@param arr Input array +@param submat Pointer to the resultant sub-array header +@param rect Zero-based coordinates of the rectangle of interest + */ +CVAPI(CvMat*) cvGetSubRect( const CvArr* arr, CvMat* submat, CvRect rect ); +#define cvGetSubArr cvGetSubRect + +/** @brief Returns array row or row span. + +The function returns the header, corresponding to a specified row/row span of the input array. +cvGetRow(arr, submat, row) is a shortcut for cvGetRows(arr, submat, row, row+1). +@param arr Input array +@param submat Pointer to the resulting sub-array header +@param start_row Zero-based index of the starting row (inclusive) of the span +@param end_row Zero-based index of the ending row (exclusive) of the span +@param delta_row Index step in the row span. That is, the function extracts every delta_row -th +row from start_row and up to (but not including) end_row . + */ +CVAPI(CvMat*) cvGetRows( const CvArr* arr, CvMat* submat, + int start_row, int end_row, + int delta_row CV_DEFAULT(1)); + +/** @overload +@param arr Input array +@param submat Pointer to the resulting sub-array header +@param row Zero-based index of the selected row +*/ +CV_INLINE CvMat* cvGetRow( const CvArr* arr, CvMat* submat, int row ) +{ + return cvGetRows( arr, submat, row, row + 1, 1 ); +} + + +/** @brief Returns one of more array columns. + +The function returns the header, corresponding to a specified column span of the input array. That + +is, no data is copied. Therefore, any modifications of the submatrix will affect the original array. +If you need to copy the columns, use cvCloneMat. cvGetCol(arr, submat, col) is a shortcut for +cvGetCols(arr, submat, col, col+1). +@param arr Input array +@param submat Pointer to the resulting sub-array header +@param start_col Zero-based index of the starting column (inclusive) of the span +@param end_col Zero-based index of the ending column (exclusive) of the span + */ +CVAPI(CvMat*) cvGetCols( const CvArr* arr, CvMat* submat, + int start_col, int end_col ); + +/** @overload +@param arr Input array +@param submat Pointer to the resulting sub-array header +@param col Zero-based index of the selected column +*/ +CV_INLINE CvMat* cvGetCol( const CvArr* arr, CvMat* submat, int col ) +{ + return cvGetCols( arr, submat, col, col + 1 ); +} + +/** @brief Returns one of array diagonals. + +The function returns the header, corresponding to a specified diagonal of the input array. +@param arr Input array +@param submat Pointer to the resulting sub-array header +@param diag Index of the array diagonal. Zero value corresponds to the main diagonal, -1 +corresponds to the diagonal above the main, 1 corresponds to the diagonal below the main, and so +forth. + */ +CVAPI(CvMat*) cvGetDiag( const CvArr* arr, CvMat* submat, + int diag CV_DEFAULT(0)); + +/** low-level scalar <-> raw data conversion functions */ +CVAPI(void) cvScalarToRawData( const CvScalar* scalar, void* data, int type, + int extend_to_12 CV_DEFAULT(0) ); + +CVAPI(void) cvRawDataToScalar( const void* data, int type, CvScalar* scalar ); + +/** @brief Creates a new matrix header but does not allocate the matrix data. + +The function allocates a header for a multi-dimensional dense array. The array data can further be +allocated using cvCreateData or set explicitly to user-allocated data via cvSetData. +@param dims Number of array dimensions +@param sizes Array of dimension sizes +@param type Type of array elements, see cvCreateMat + */ +CVAPI(CvMatND*) cvCreateMatNDHeader( int dims, const int* sizes, int type ); + +/** @brief Creates the header and allocates the data for a multi-dimensional dense array. + +This function call is equivalent to the following code: +@code + CvMatND* mat = cvCreateMatNDHeader(dims, sizes, type); + cvCreateData(mat); +@endcode +@param dims Number of array dimensions. This must not exceed CV_MAX_DIM (32 by default, but can be +changed at build time). +@param sizes Array of dimension sizes. +@param type Type of array elements, see cvCreateMat . + */ +CVAPI(CvMatND*) cvCreateMatND( int dims, const int* sizes, int type ); + +/** @brief Initializes a pre-allocated multi-dimensional array header. + +@param mat A pointer to the array header to be initialized +@param dims The number of array dimensions +@param sizes An array of dimension sizes +@param type Type of array elements, see cvCreateMat +@param data Optional data pointer assigned to the matrix header + */ +CVAPI(CvMatND*) cvInitMatNDHeader( CvMatND* mat, int dims, const int* sizes, + int type, void* data CV_DEFAULT(NULL) ); + +/** @brief Deallocates a multi-dimensional array. + +The function decrements the array data reference counter and releases the array header. If the +reference counter reaches 0, it also deallocates the data. : +@code + if(*mat ) + cvDecRefData(*mat); + cvFree((void**)mat); +@endcode +@param mat Double pointer to the array + */ +CV_INLINE void cvReleaseMatND( CvMatND** mat ) +{ + cvReleaseMat( (CvMat**)mat ); +} + +/** Creates a copy of CvMatND (except, may be, steps) */ +CVAPI(CvMatND*) cvCloneMatND( const CvMatND* mat ); + +/** @brief Creates sparse array. + +The function allocates a multi-dimensional sparse array. Initially the array contain no elements, +that is PtrND and other related functions will return 0 for every index. +@param dims Number of array dimensions. In contrast to the dense matrix, the number of dimensions is +practically unlimited (up to \f$2^{16}\f$ ). +@param sizes Array of dimension sizes +@param type Type of array elements. The same as for CvMat + */ +CVAPI(CvSparseMat*) cvCreateSparseMat( int dims, const int* sizes, int type ); + +/** @brief Deallocates sparse array. + +The function releases the sparse array and clears the array pointer upon exit. +@param mat Double pointer to the array + */ +CVAPI(void) cvReleaseSparseMat( CvSparseMat** mat ); + +/** Creates a copy of CvSparseMat (except, may be, zero items) */ +CVAPI(CvSparseMat*) cvCloneSparseMat( const CvSparseMat* mat ); + +/** @brief Initializes sparse array elements iterator. + +The function initializes iterator of sparse array elements and returns pointer to the first element, +or NULL if the array is empty. +@param mat Input array +@param mat_iterator Initialized iterator + */ +CVAPI(CvSparseNode*) cvInitSparseMatIterator( const CvSparseMat* mat, + CvSparseMatIterator* mat_iterator ); + +/** @brief Returns the next sparse matrix element + +The function moves iterator to the next sparse matrix element and returns pointer to it. In the +current version there is no any particular order of the elements, because they are stored in the +hash table. The sample below demonstrates how to iterate through the sparse matrix: +@code + // print all the non-zero sparse matrix elements and compute their sum + double sum = 0; + int i, dims = cvGetDims(sparsemat); + CvSparseMatIterator it; + CvSparseNode* node = cvInitSparseMatIterator(sparsemat, &it); + + for(; node != 0; node = cvGetNextSparseNode(&it)) + { + int* idx = CV_NODE_IDX(array, node); + float val = *(float*)CV_NODE_VAL(array, node); + printf("M"); + for(i = 0; i < dims; i++ ) + printf("[%d]", idx[i]); + printf("=%g\n", val); + + sum += val; + } + + printf("nTotal sum = %g\n", sum); +@endcode +@param mat_iterator Sparse array iterator + */ +CV_INLINE CvSparseNode* cvGetNextSparseNode( CvSparseMatIterator* mat_iterator ) +{ + if( mat_iterator->node->next ) + return mat_iterator->node = mat_iterator->node->next; + else + { + int idx; + for( idx = ++mat_iterator->curidx; idx < mat_iterator->mat->hashsize; idx++ ) + { + CvSparseNode* node = (CvSparseNode*)mat_iterator->mat->hashtable[idx]; + if( node ) + { + mat_iterator->curidx = idx; + return mat_iterator->node = node; + } + } + return NULL; + } +} + + +#define CV_MAX_ARR 10 + +/** matrix iterator: used for n-ary operations on dense arrays */ +typedef struct CvNArrayIterator +{ + int count; /**< number of arrays */ + int dims; /**< number of dimensions to iterate */ + CvSize size; /**< maximal common linear size: { width = size, height = 1 } */ + uchar* ptr[CV_MAX_ARR]; /**< pointers to the array slices */ + int stack[CV_MAX_DIM]; /**< for internal use */ + CvMatND* hdr[CV_MAX_ARR]; /**< pointers to the headers of the + matrices that are processed */ +} +CvNArrayIterator; + +#define CV_NO_DEPTH_CHECK 1 +#define CV_NO_CN_CHECK 2 +#define CV_NO_SIZE_CHECK 4 + +/** initializes iterator that traverses through several arrays simultaneously + (the function together with cvNextArraySlice is used for + N-ari element-wise operations) */ +CVAPI(int) cvInitNArrayIterator( int count, CvArr** arrs, + const CvArr* mask, CvMatND* stubs, + CvNArrayIterator* array_iterator, + int flags CV_DEFAULT(0) ); + +/** returns zero value if iteration is finished, non-zero (slice length) otherwise */ +CVAPI(int) cvNextNArraySlice( CvNArrayIterator* array_iterator ); + + +/** @brief Returns type of array elements. + +The function returns type of the array elements. In the case of IplImage the type is converted to +CvMat-like representation. For example, if the image has been created as: +@code + IplImage* img = cvCreateImage(cvSize(640, 480), IPL_DEPTH_8U, 3); +@endcode +The code cvGetElemType(img) will return CV_8UC3. +@param arr Input array + */ +CVAPI(int) cvGetElemType( const CvArr* arr ); + +/** @brief Return number of array dimensions + +The function returns the array dimensionality and the array of dimension sizes. In the case of +IplImage or CvMat it always returns 2 regardless of number of image/matrix rows. For example, the +following code calculates total number of array elements: +@code + int sizes[CV_MAX_DIM]; + int i, total = 1; + int dims = cvGetDims(arr, size); + for(i = 0; i < dims; i++ ) + total *= sizes[i]; +@endcode +@param arr Input array +@param sizes Optional output vector of the array dimension sizes. For 2d arrays the number of rows +(height) goes first, number of columns (width) next. + */ +CVAPI(int) cvGetDims( const CvArr* arr, int* sizes CV_DEFAULT(NULL) ); + + +/** @brief Returns array size along the specified dimension. + +@param arr Input array +@param index Zero-based dimension index (for matrices 0 means number of rows, 1 means number of +columns; for images 0 means height, 1 means width) + */ +CVAPI(int) cvGetDimSize( const CvArr* arr, int index ); + + +/** @brief Return pointer to a particular array element. + +The functions return a pointer to a specific array element. Number of array dimension should match +to the number of indices passed to the function except for cvPtr1D function that can be used for +sequential access to 1D, 2D or nD dense arrays. + +The functions can be used for sparse arrays as well - if the requested node does not exist they +create it and set it to zero. + +All these as well as other functions accessing array elements ( cvGetND , cvGetRealND , cvSet +, cvSetND , cvSetRealND ) raise an error in case if the element index is out of range. +@param arr Input array +@param idx0 The first zero-based component of the element index +@param type Optional output parameter: type of matrix elements + */ +CVAPI(uchar*) cvPtr1D( const CvArr* arr, int idx0, int* type CV_DEFAULT(NULL)); +/** @overload */ +CVAPI(uchar*) cvPtr2D( const CvArr* arr, int idx0, int idx1, int* type CV_DEFAULT(NULL) ); +/** @overload */ +CVAPI(uchar*) cvPtr3D( const CvArr* arr, int idx0, int idx1, int idx2, + int* type CV_DEFAULT(NULL)); +/** @overload +@param arr Input array +@param idx Array of the element indices +@param type Optional output parameter: type of matrix elements +@param create_node Optional input parameter for sparse matrices. Non-zero value of the parameter +means that the requested element is created if it does not exist already. +@param precalc_hashval Optional input parameter for sparse matrices. If the pointer is not NULL, +the function does not recalculate the node hash value, but takes it from the specified location. +It is useful for speeding up pair-wise operations (TODO: provide an example) +*/ +CVAPI(uchar*) cvPtrND( const CvArr* arr, const int* idx, int* type CV_DEFAULT(NULL), + int create_node CV_DEFAULT(1), + unsigned* precalc_hashval CV_DEFAULT(NULL)); + +/** @brief Return a specific array element. + +The functions return a specific array element. In the case of a sparse array the functions return 0 +if the requested node does not exist (no new node is created by the functions). +@param arr Input array +@param idx0 The first zero-based component of the element index + */ +CVAPI(CvScalar) cvGet1D( const CvArr* arr, int idx0 ); +/** @overload */ +CVAPI(CvScalar) cvGet2D( const CvArr* arr, int idx0, int idx1 ); +/** @overload */ +CVAPI(CvScalar) cvGet3D( const CvArr* arr, int idx0, int idx1, int idx2 ); +/** @overload +@param arr Input array +@param idx Array of the element indices +*/ +CVAPI(CvScalar) cvGetND( const CvArr* arr, const int* idx ); + +/** @brief Return a specific element of single-channel 1D, 2D, 3D or nD array. + +Returns a specific element of a single-channel array. If the array has multiple channels, a runtime +error is raised. Note that Get?D functions can be used safely for both single-channel and +multiple-channel arrays though they are a bit slower. + +In the case of a sparse array the functions return 0 if the requested node does not exist (no new +node is created by the functions). +@param arr Input array. Must have a single channel. +@param idx0 The first zero-based component of the element index + */ +CVAPI(double) cvGetReal1D( const CvArr* arr, int idx0 ); +/** @overload */ +CVAPI(double) cvGetReal2D( const CvArr* arr, int idx0, int idx1 ); +/** @overload */ +CVAPI(double) cvGetReal3D( const CvArr* arr, int idx0, int idx1, int idx2 ); +/** @overload +@param arr Input array. Must have a single channel. +@param idx Array of the element indices +*/ +CVAPI(double) cvGetRealND( const CvArr* arr, const int* idx ); + +/** @brief Change the particular array element. + +The functions assign the new value to a particular array element. In the case of a sparse array the +functions create the node if it does not exist yet. +@param arr Input array +@param idx0 The first zero-based component of the element index +@param value The assigned value + */ +CVAPI(void) cvSet1D( CvArr* arr, int idx0, CvScalar value ); +/** @overload */ +CVAPI(void) cvSet2D( CvArr* arr, int idx0, int idx1, CvScalar value ); +/** @overload */ +CVAPI(void) cvSet3D( CvArr* arr, int idx0, int idx1, int idx2, CvScalar value ); +/** @overload +@param arr Input array +@param idx Array of the element indices +@param value The assigned value +*/ +CVAPI(void) cvSetND( CvArr* arr, const int* idx, CvScalar value ); + +/** @brief Change a specific array element. + +The functions assign a new value to a specific element of a single-channel array. If the array has +multiple channels, a runtime error is raised. Note that the Set\*D function can be used safely for +both single-channel and multiple-channel arrays, though they are a bit slower. + +In the case of a sparse array the functions create the node if it does not yet exist. +@param arr Input array +@param idx0 The first zero-based component of the element index +@param value The assigned value + */ +CVAPI(void) cvSetReal1D( CvArr* arr, int idx0, double value ); +/** @overload */ +CVAPI(void) cvSetReal2D( CvArr* arr, int idx0, int idx1, double value ); +/** @overload */ +CVAPI(void) cvSetReal3D( CvArr* arr, int idx0, + int idx1, int idx2, double value ); +/** @overload +@param arr Input array +@param idx Array of the element indices +@param value The assigned value +*/ +CVAPI(void) cvSetRealND( CvArr* arr, const int* idx, double value ); + +/** clears element of ND dense array, + in case of sparse arrays it deletes the specified node */ +CVAPI(void) cvClearND( CvArr* arr, const int* idx ); + +/** @brief Returns matrix header for arbitrary array. + +The function returns a matrix header for the input array that can be a matrix - CvMat, an image - +IplImage, or a multi-dimensional dense array - CvMatND (the third option is allowed only if +allowND != 0) . In the case of matrix the function simply returns the input pointer. In the case of +IplImage\* or CvMatND it initializes the header structure with parameters of the current image ROI +and returns &header. Because COI is not supported by CvMat, it is returned separately. + +The function provides an easy way to handle both types of arrays - IplImage and CvMat using the same +code. Input array must have non-zero data pointer, otherwise the function will report an error. + +@note If the input array is IplImage with planar data layout and COI set, the function returns the +pointer to the selected plane and COI == 0. This feature allows user to process IplImage structures +with planar data layout, even though OpenCV does not support such images. +@param arr Input array +@param header Pointer to CvMat structure used as a temporary buffer +@param coi Optional output parameter for storing COI +@param allowND If non-zero, the function accepts multi-dimensional dense arrays (CvMatND\*) and +returns 2D matrix (if CvMatND has two dimensions) or 1D matrix (when CvMatND has 1 dimension or +more than 2 dimensions). The CvMatND array must be continuous. +@sa cvGetImage, cvarrToMat. + */ +CVAPI(CvMat*) cvGetMat( const CvArr* arr, CvMat* header, + int* coi CV_DEFAULT(NULL), + int allowND CV_DEFAULT(0)); + +/** @brief Returns image header for arbitrary array. + +The function returns the image header for the input array that can be a matrix (CvMat) or image +(IplImage). In the case of an image the function simply returns the input pointer. In the case of +CvMat it initializes an image_header structure with the parameters of the input matrix. Note that +if we transform IplImage to CvMat using cvGetMat and then transform CvMat back to IplImage using +this function, we will get different headers if the ROI is set in the original image. +@param arr Input array +@param image_header Pointer to IplImage structure used as a temporary buffer + */ +CVAPI(IplImage*) cvGetImage( const CvArr* arr, IplImage* image_header ); + + +/** @brief Changes the shape of a multi-dimensional array without copying the data. + +The function is an advanced version of cvReshape that can work with multi-dimensional arrays as +well (though it can work with ordinary images and matrices) and change the number of dimensions. + +Below are the two samples from the cvReshape description rewritten using cvReshapeMatND: +@code + IplImage* color_img = cvCreateImage(cvSize(320,240), IPL_DEPTH_8U, 3); + IplImage gray_img_hdr, *gray_img; + gray_img = (IplImage*)cvReshapeMatND(color_img, sizeof(gray_img_hdr), &gray_img_hdr, 1, 0, 0); + ... + int size[] = { 2, 2, 2 }; + CvMatND* mat = cvCreateMatND(3, size, CV_32F); + CvMat row_header, *row; + row = (CvMat*)cvReshapeMatND(mat, sizeof(row_header), &row_header, 0, 1, 0); +@endcode +In C, the header file for this function includes a convenient macro cvReshapeND that does away with +the sizeof_header parameter. So, the lines containing the call to cvReshapeMatND in the examples +may be replaced as follow: +@code + gray_img = (IplImage*)cvReshapeND(color_img, &gray_img_hdr, 1, 0, 0); + ... + row = (CvMat*)cvReshapeND(mat, &row_header, 0, 1, 0); +@endcode +@param arr Input array +@param sizeof_header Size of output header to distinguish between IplImage, CvMat and CvMatND +output headers +@param header Output header to be filled +@param new_cn New number of channels. new_cn = 0 means that the number of channels remains +unchanged. +@param new_dims New number of dimensions. new_dims = 0 means that the number of dimensions +remains the same. +@param new_sizes Array of new dimension sizes. Only new_dims-1 values are used, because the +total number of elements must remain the same. Thus, if new_dims = 1, new_sizes array is not +used. + */ +CVAPI(CvArr*) cvReshapeMatND( const CvArr* arr, + int sizeof_header, CvArr* header, + int new_cn, int new_dims, int* new_sizes ); + +#define cvReshapeND( arr, header, new_cn, new_dims, new_sizes ) \ + cvReshapeMatND( (arr), sizeof(*(header)), (header), \ + (new_cn), (new_dims), (new_sizes)) + +/** @brief Changes shape of matrix/image without copying data. + +The function initializes the CvMat header so that it points to the same data as the original array +but has a different shape - different number of channels, different number of rows, or both. + +The following example code creates one image buffer and two image headers, the first is for a +320x240x3 image and the second is for a 960x240x1 image: +@code + IplImage* color_img = cvCreateImage(cvSize(320,240), IPL_DEPTH_8U, 3); + CvMat gray_mat_hdr; + IplImage gray_img_hdr, *gray_img; + cvReshape(color_img, &gray_mat_hdr, 1); + gray_img = cvGetImage(&gray_mat_hdr, &gray_img_hdr); +@endcode +And the next example converts a 3x3 matrix to a single 1x9 vector: +@code + CvMat* mat = cvCreateMat(3, 3, CV_32F); + CvMat row_header, *row; + row = cvReshape(mat, &row_header, 0, 1); +@endcode +@param arr Input array +@param header Output header to be filled +@param new_cn New number of channels. 'new_cn = 0' means that the number of channels remains +unchanged. +@param new_rows New number of rows. 'new_rows = 0' means that the number of rows remains +unchanged unless it needs to be changed according to new_cn value. +*/ +CVAPI(CvMat*) cvReshape( const CvArr* arr, CvMat* header, + int new_cn, int new_rows CV_DEFAULT(0) ); + +/** Repeats source 2d array several times in both horizontal and + vertical direction to fill destination array */ +CVAPI(void) cvRepeat( const CvArr* src, CvArr* dst ); + +/** @brief Allocates array data + +The function allocates image, matrix or multi-dimensional dense array data. Note that in the case of +matrix types OpenCV allocation functions are used. In the case of IplImage they are used unless +CV_TURN_ON_IPL_COMPATIBILITY() has been called before. In the latter case IPL functions are used +to allocate the data. +@param arr Array header + */ +CVAPI(void) cvCreateData( CvArr* arr ); + +/** @brief Releases array data. + +The function releases the array data. In the case of CvMat or CvMatND it simply calls +cvDecRefData(), that is the function can not deallocate external data. See also the note to +cvCreateData . +@param arr Array header + */ +CVAPI(void) cvReleaseData( CvArr* arr ); + +/** @brief Assigns user data to the array header. + +The function assigns user data to the array header. Header should be initialized before using +cvCreateMatHeader, cvCreateImageHeader, cvCreateMatNDHeader, cvInitMatHeader, +cvInitImageHeader or cvInitMatNDHeader. +@param arr Array header +@param data User data +@param step Full row length in bytes + */ +CVAPI(void) cvSetData( CvArr* arr, void* data, int step ); + +/** @brief Retrieves low-level information about the array. + +The function fills output variables with low-level information about the array data. All output + +parameters are optional, so some of the pointers may be set to NULL. If the array is IplImage with +ROI set, the parameters of ROI are returned. + +The following example shows how to get access to array elements. It computes absolute values of the +array elements : +@code + float* data; + int step; + CvSize size; + + cvGetRawData(array, (uchar**)&data, &step, &size); + step /= sizeof(data[0]); + + for(int y = 0; y < size.height; y++, data += step ) + for(int x = 0; x < size.width; x++ ) + data[x] = (float)fabs(data[x]); +@endcode +@param arr Array header +@param data Output pointer to the whole image origin or ROI origin if ROI is set +@param step Output full row length in bytes +@param roi_size Output ROI size + */ +CVAPI(void) cvGetRawData( const CvArr* arr, uchar** data, + int* step CV_DEFAULT(NULL), + CvSize* roi_size CV_DEFAULT(NULL)); + +/** @brief Returns size of matrix or image ROI. + +The function returns number of rows (CvSize::height) and number of columns (CvSize::width) of the +input matrix or image. In the case of image the size of ROI is returned. +@param arr array header + */ +CVAPI(CvSize) cvGetSize( const CvArr* arr ); + +/** @brief Copies one array to another. + +The function copies selected elements from an input array to an output array: + +\f[\texttt{dst} (I)= \texttt{src} (I) \quad \text{if} \quad \texttt{mask} (I) \ne 0.\f] + +If any of the passed arrays is of IplImage type, then its ROI and COI fields are used. Both arrays +must have the same type, the same number of dimensions, and the same size. The function can also +copy sparse arrays (mask is not supported in this case). +@param src The source array +@param dst The destination array +@param mask Operation mask, 8-bit single channel array; specifies elements of the destination array +to be changed + */ +CVAPI(void) cvCopy( const CvArr* src, CvArr* dst, + const CvArr* mask CV_DEFAULT(NULL) ); + +/** @brief Sets every element of an array to a given value. + +The function copies the scalar value to every selected element of the destination array: +\f[\texttt{arr} (I)= \texttt{value} \quad \text{if} \quad \texttt{mask} (I) \ne 0\f] +If array arr is of IplImage type, then is ROI used, but COI must not be set. +@param arr The destination array +@param value Fill value +@param mask Operation mask, 8-bit single channel array; specifies elements of the destination +array to be changed + */ +CVAPI(void) cvSet( CvArr* arr, CvScalar value, + const CvArr* mask CV_DEFAULT(NULL) ); + +/** @brief Clears the array. + +The function clears the array. In the case of dense arrays (CvMat, CvMatND or IplImage), +cvZero(array) is equivalent to cvSet(array,cvScalarAll(0),0). In the case of sparse arrays all the +elements are removed. +@param arr Array to be cleared + */ +CVAPI(void) cvSetZero( CvArr* arr ); +#define cvZero cvSetZero + + +/** Splits a multi-channel array into the set of single-channel arrays or + extracts particular [color] plane */ +CVAPI(void) cvSplit( const CvArr* src, CvArr* dst0, CvArr* dst1, + CvArr* dst2, CvArr* dst3 ); + +/** Merges a set of single-channel arrays into the single multi-channel array + or inserts one particular [color] plane to the array */ +CVAPI(void) cvMerge( const CvArr* src0, const CvArr* src1, + const CvArr* src2, const CvArr* src3, + CvArr* dst ); + +/** Copies several channels from input arrays to + certain channels of output arrays */ +CVAPI(void) cvMixChannels( const CvArr** src, int src_count, + CvArr** dst, int dst_count, + const int* from_to, int pair_count ); + +/** @brief Converts one array to another with optional linear transformation. + +The function has several different purposes, and thus has several different names. It copies one +array to another with optional scaling, which is performed first, and/or optional type conversion, +performed after: + +\f[\texttt{dst} (I) = \texttt{scale} \texttt{src} (I) + ( \texttt{shift} _0, \texttt{shift} _1,...)\f] + +All the channels of multi-channel arrays are processed independently. + +The type of conversion is done with rounding and saturation, that is if the result of scaling + +conversion can not be represented exactly by a value of the destination array element type, it is +set to the nearest representable value on the real axis. +@param src Source array +@param dst Destination array +@param scale Scale factor +@param shift Value added to the scaled source array elements + */ +CVAPI(void) cvConvertScale( const CvArr* src, CvArr* dst, + double scale CV_DEFAULT(1), + double shift CV_DEFAULT(0) ); +#define cvCvtScale cvConvertScale +#define cvScale cvConvertScale +#define cvConvert( src, dst ) cvConvertScale( (src), (dst), 1, 0 ) + + +/** Performs linear transformation on every source array element, + stores absolute value of the result: + dst(x,y,c) = abs(scale*src(x,y,c)+shift). + destination array must have 8u type. + In other cases one may use cvConvertScale + cvAbsDiffS */ +CVAPI(void) cvConvertScaleAbs( const CvArr* src, CvArr* dst, + double scale CV_DEFAULT(1), + double shift CV_DEFAULT(0) ); +#define cvCvtScaleAbs cvConvertScaleAbs + + +/** checks termination criteria validity and + sets eps to default_eps (if it is not set), + max_iter to default_max_iters (if it is not set) +*/ +CVAPI(CvTermCriteria) cvCheckTermCriteria( CvTermCriteria criteria, + double default_eps, + int default_max_iters ); + +/****************************************************************************************\ +* Arithmetic, logic and comparison operations * +\****************************************************************************************/ + +/** dst(mask) = src1(mask) + src2(mask) */ +CVAPI(void) cvAdd( const CvArr* src1, const CvArr* src2, CvArr* dst, + const CvArr* mask CV_DEFAULT(NULL)); + +/** dst(mask) = src(mask) + value */ +CVAPI(void) cvAddS( const CvArr* src, CvScalar value, CvArr* dst, + const CvArr* mask CV_DEFAULT(NULL)); + +/** dst(mask) = src1(mask) - src2(mask) */ +CVAPI(void) cvSub( const CvArr* src1, const CvArr* src2, CvArr* dst, + const CvArr* mask CV_DEFAULT(NULL)); + +/** dst(mask) = src(mask) - value = src(mask) + (-value) */ +CV_INLINE void cvSubS( const CvArr* src, CvScalar value, CvArr* dst, + const CvArr* mask CV_DEFAULT(NULL)) +{ + cvAddS( src, cvScalar( -value.val[0], -value.val[1], -value.val[2], -value.val[3]), + dst, mask ); +} + +/** dst(mask) = value - src(mask) */ +CVAPI(void) cvSubRS( const CvArr* src, CvScalar value, CvArr* dst, + const CvArr* mask CV_DEFAULT(NULL)); + +/** dst(idx) = src1(idx) * src2(idx) * scale + (scaled element-wise multiplication of 2 arrays) */ +CVAPI(void) cvMul( const CvArr* src1, const CvArr* src2, + CvArr* dst, double scale CV_DEFAULT(1) ); + +/** element-wise division/inversion with scaling: + dst(idx) = src1(idx) * scale / src2(idx) + or dst(idx) = scale / src2(idx) if src1 == 0 */ +CVAPI(void) cvDiv( const CvArr* src1, const CvArr* src2, + CvArr* dst, double scale CV_DEFAULT(1)); + +/** dst = src1 * scale + src2 */ +CVAPI(void) cvScaleAdd( const CvArr* src1, CvScalar scale, + const CvArr* src2, CvArr* dst ); +#define cvAXPY( A, real_scalar, B, C ) cvScaleAdd(A, cvRealScalar(real_scalar), B, C) + +/** dst = src1 * alpha + src2 * beta + gamma */ +CVAPI(void) cvAddWeighted( const CvArr* src1, double alpha, + const CvArr* src2, double beta, + double gamma, CvArr* dst ); + +/** @brief Calculates the dot product of two arrays in Euclidean metrics. + +The function calculates and returns the Euclidean dot product of two arrays. + +\f[src1 \bullet src2 = \sum _I ( \texttt{src1} (I) \texttt{src2} (I))\f] + +In the case of multiple channel arrays, the results for all channels are accumulated. In particular, +cvDotProduct(a,a) where a is a complex vector, will return \f$||\texttt{a}||^2\f$. The function can +process multi-dimensional arrays, row by row, layer by layer, and so on. +@param src1 The first source array +@param src2 The second source array + */ +CVAPI(double) cvDotProduct( const CvArr* src1, const CvArr* src2 ); + +/** dst(idx) = src1(idx) & src2(idx) */ +CVAPI(void) cvAnd( const CvArr* src1, const CvArr* src2, + CvArr* dst, const CvArr* mask CV_DEFAULT(NULL)); + +/** dst(idx) = src(idx) & value */ +CVAPI(void) cvAndS( const CvArr* src, CvScalar value, + CvArr* dst, const CvArr* mask CV_DEFAULT(NULL)); + +/** dst(idx) = src1(idx) | src2(idx) */ +CVAPI(void) cvOr( const CvArr* src1, const CvArr* src2, + CvArr* dst, const CvArr* mask CV_DEFAULT(NULL)); + +/** dst(idx) = src(idx) | value */ +CVAPI(void) cvOrS( const CvArr* src, CvScalar value, + CvArr* dst, const CvArr* mask CV_DEFAULT(NULL)); + +/** dst(idx) = src1(idx) ^ src2(idx) */ +CVAPI(void) cvXor( const CvArr* src1, const CvArr* src2, + CvArr* dst, const CvArr* mask CV_DEFAULT(NULL)); + +/** dst(idx) = src(idx) ^ value */ +CVAPI(void) cvXorS( const CvArr* src, CvScalar value, + CvArr* dst, const CvArr* mask CV_DEFAULT(NULL)); + +/** dst(idx) = ~src(idx) */ +CVAPI(void) cvNot( const CvArr* src, CvArr* dst ); + +/** dst(idx) = lower(idx) <= src(idx) < upper(idx) */ +CVAPI(void) cvInRange( const CvArr* src, const CvArr* lower, + const CvArr* upper, CvArr* dst ); + +/** dst(idx) = lower <= src(idx) < upper */ +CVAPI(void) cvInRangeS( const CvArr* src, CvScalar lower, + CvScalar upper, CvArr* dst ); + +#define CV_CMP_EQ 0 +#define CV_CMP_GT 1 +#define CV_CMP_GE 2 +#define CV_CMP_LT 3 +#define CV_CMP_LE 4 +#define CV_CMP_NE 5 + +/** The comparison operation support single-channel arrays only. + Destination image should be 8uC1 or 8sC1 */ + +/** dst(idx) = src1(idx) _cmp_op_ src2(idx) */ +CVAPI(void) cvCmp( const CvArr* src1, const CvArr* src2, CvArr* dst, int cmp_op ); + +/** dst(idx) = src1(idx) _cmp_op_ value */ +CVAPI(void) cvCmpS( const CvArr* src, double value, CvArr* dst, int cmp_op ); + +/** dst(idx) = min(src1(idx),src2(idx)) */ +CVAPI(void) cvMin( const CvArr* src1, const CvArr* src2, CvArr* dst ); + +/** dst(idx) = max(src1(idx),src2(idx)) */ +CVAPI(void) cvMax( const CvArr* src1, const CvArr* src2, CvArr* dst ); + +/** dst(idx) = min(src(idx),value) */ +CVAPI(void) cvMinS( const CvArr* src, double value, CvArr* dst ); + +/** dst(idx) = max(src(idx),value) */ +CVAPI(void) cvMaxS( const CvArr* src, double value, CvArr* dst ); + +/** dst(x,y,c) = abs(src1(x,y,c) - src2(x,y,c)) */ +CVAPI(void) cvAbsDiff( const CvArr* src1, const CvArr* src2, CvArr* dst ); + +/** dst(x,y,c) = abs(src(x,y,c) - value(c)) */ +CVAPI(void) cvAbsDiffS( const CvArr* src, CvArr* dst, CvScalar value ); +#define cvAbs( src, dst ) cvAbsDiffS( (src), (dst), cvScalarAll(0)) + +/****************************************************************************************\ +* Math operations * +\****************************************************************************************/ + +/** Does cartesian->polar coordinates conversion. + Either of output components (magnitude or angle) is optional */ +CVAPI(void) cvCartToPolar( const CvArr* x, const CvArr* y, + CvArr* magnitude, CvArr* angle CV_DEFAULT(NULL), + int angle_in_degrees CV_DEFAULT(0)); + +/** Does polar->cartesian coordinates conversion. + Either of output components (magnitude or angle) is optional. + If magnitude is missing it is assumed to be all 1's */ +CVAPI(void) cvPolarToCart( const CvArr* magnitude, const CvArr* angle, + CvArr* x, CvArr* y, + int angle_in_degrees CV_DEFAULT(0)); + +/** Does powering: dst(idx) = src(idx)^power */ +CVAPI(void) cvPow( const CvArr* src, CvArr* dst, double power ); + +/** Does exponention: dst(idx) = exp(src(idx)). + Overflow is not handled yet. Underflow is handled. + Maximal relative error is ~7e-6 for single-precision input */ +CVAPI(void) cvExp( const CvArr* src, CvArr* dst ); + +/** Calculates natural logarithms: dst(idx) = log(abs(src(idx))). + Logarithm of 0 gives large negative number(~-700) + Maximal relative error is ~3e-7 for single-precision output +*/ +CVAPI(void) cvLog( const CvArr* src, CvArr* dst ); + +/** Fast arctangent calculation */ +CVAPI(float) cvFastArctan( float y, float x ); + +/** Fast cubic root calculation */ +CVAPI(float) cvCbrt( float value ); + +#define CV_CHECK_RANGE 1 +#define CV_CHECK_QUIET 2 +/** Checks array values for NaNs, Infs or simply for too large numbers + (if CV_CHECK_RANGE is set). If CV_CHECK_QUIET is set, + no runtime errors is raised (function returns zero value in case of "bad" values). + Otherwise cvError is called */ +CVAPI(int) cvCheckArr( const CvArr* arr, int flags CV_DEFAULT(0), + double min_val CV_DEFAULT(0), double max_val CV_DEFAULT(0)); +#define cvCheckArray cvCheckArr + +#define CV_RAND_UNI 0 +#define CV_RAND_NORMAL 1 + +/** @brief Fills an array with random numbers and updates the RNG state. + +The function fills the destination array with uniformly or normally distributed random numbers. +@param rng CvRNG state initialized by cvRNG +@param arr The destination array +@param dist_type Distribution type +> - **CV_RAND_UNI** uniform distribution +> - **CV_RAND_NORMAL** normal or Gaussian distribution +@param param1 The first parameter of the distribution. In the case of a uniform distribution it is +the inclusive lower boundary of the random numbers range. In the case of a normal distribution it +is the mean value of the random numbers. +@param param2 The second parameter of the distribution. In the case of a uniform distribution it +is the exclusive upper boundary of the random numbers range. In the case of a normal distribution +it is the standard deviation of the random numbers. +@sa randu, randn, RNG::fill. + */ +CVAPI(void) cvRandArr( CvRNG* rng, CvArr* arr, int dist_type, + CvScalar param1, CvScalar param2 ); + +CVAPI(void) cvRandShuffle( CvArr* mat, CvRNG* rng, + double iter_factor CV_DEFAULT(1.)); + +#define CV_SORT_EVERY_ROW 0 +#define CV_SORT_EVERY_COLUMN 1 +#define CV_SORT_ASCENDING 0 +#define CV_SORT_DESCENDING 16 + +CVAPI(void) cvSort( const CvArr* src, CvArr* dst CV_DEFAULT(NULL), + CvArr* idxmat CV_DEFAULT(NULL), + int flags CV_DEFAULT(0)); + +/** Finds real roots of a cubic equation */ +CVAPI(int) cvSolveCubic( const CvMat* coeffs, CvMat* roots ); + +/** Finds all real and complex roots of a polynomial equation */ +CVAPI(void) cvSolvePoly(const CvMat* coeffs, CvMat *roots2, + int maxiter CV_DEFAULT(20), int fig CV_DEFAULT(100)); + +/****************************************************************************************\ +* Matrix operations * +\****************************************************************************************/ + +/** @brief Calculates the cross product of two 3D vectors. + +The function calculates the cross product of two 3D vectors: +\f[\texttt{dst} = \texttt{src1} \times \texttt{src2}\f] +or: +\f[\begin{array}{l} \texttt{dst} _1 = \texttt{src1} _2 \texttt{src2} _3 - \texttt{src1} _3 \texttt{src2} _2 \\ \texttt{dst} _2 = \texttt{src1} _3 \texttt{src2} _1 - \texttt{src1} _1 \texttt{src2} _3 \\ \texttt{dst} _3 = \texttt{src1} _1 \texttt{src2} _2 - \texttt{src1} _2 \texttt{src2} _1 \end{array}\f] +@param src1 The first source vector +@param src2 The second source vector +@param dst The destination vector + */ +CVAPI(void) cvCrossProduct( const CvArr* src1, const CvArr* src2, CvArr* dst ); + +/** Matrix transform: dst = A*B + C, C is optional */ +#define cvMatMulAdd( src1, src2, src3, dst ) cvGEMM( (src1), (src2), 1., (src3), 1., (dst), 0 ) +#define cvMatMul( src1, src2, dst ) cvMatMulAdd( (src1), (src2), NULL, (dst)) + +#define CV_GEMM_A_T 1 +#define CV_GEMM_B_T 2 +#define CV_GEMM_C_T 4 +/** Extended matrix transform: + dst = alpha*op(A)*op(B) + beta*op(C), where op(X) is X or X^T */ +CVAPI(void) cvGEMM( const CvArr* src1, const CvArr* src2, double alpha, + const CvArr* src3, double beta, CvArr* dst, + int tABC CV_DEFAULT(0)); +#define cvMatMulAddEx cvGEMM + +/** Transforms each element of source array and stores + resultant vectors in destination array */ +CVAPI(void) cvTransform( const CvArr* src, CvArr* dst, + const CvMat* transmat, + const CvMat* shiftvec CV_DEFAULT(NULL)); +#define cvMatMulAddS cvTransform + +/** Does perspective transform on every element of input array */ +CVAPI(void) cvPerspectiveTransform( const CvArr* src, CvArr* dst, + const CvMat* mat ); + +/** Calculates (A-delta)*(A-delta)^T (order=0) or (A-delta)^T*(A-delta) (order=1) */ +CVAPI(void) cvMulTransposed( const CvArr* src, CvArr* dst, int order, + const CvArr* delta CV_DEFAULT(NULL), + double scale CV_DEFAULT(1.) ); + +/** Transposes matrix. Square matrices can be transposed in-place */ +CVAPI(void) cvTranspose( const CvArr* src, CvArr* dst ); +#define cvT cvTranspose + +/** Completes the symmetric matrix from the lower (LtoR=0) or from the upper (LtoR!=0) part */ +CVAPI(void) cvCompleteSymm( CvMat* matrix, int LtoR CV_DEFAULT(0) ); + +/** Mirror array data around horizontal (flip=0), + vertical (flip=1) or both(flip=-1) axises: + cvFlip(src) flips images vertically and sequences horizontally (inplace) */ +CVAPI(void) cvFlip( const CvArr* src, CvArr* dst CV_DEFAULT(NULL), + int flip_mode CV_DEFAULT(0)); +#define cvMirror cvFlip + + +#define CV_SVD_MODIFY_A 1 +#define CV_SVD_U_T 2 +#define CV_SVD_V_T 4 + +/** Performs Singular Value Decomposition of a matrix */ +CVAPI(void) cvSVD( CvArr* A, CvArr* W, CvArr* U CV_DEFAULT(NULL), + CvArr* V CV_DEFAULT(NULL), int flags CV_DEFAULT(0)); + +/** Performs Singular Value Back Substitution (solves A*X = B): + flags must be the same as in cvSVD */ +CVAPI(void) cvSVBkSb( const CvArr* W, const CvArr* U, + const CvArr* V, const CvArr* B, + CvArr* X, int flags ); + +#define CV_LU 0 +#define CV_SVD 1 +#define CV_SVD_SYM 2 +#define CV_CHOLESKY 3 +#define CV_QR 4 +#define CV_NORMAL 16 + +/** Inverts matrix */ +CVAPI(double) cvInvert( const CvArr* src, CvArr* dst, + int method CV_DEFAULT(CV_LU)); +#define cvInv cvInvert + +/** Solves linear system (src1)*(dst) = (src2) + (returns 0 if src1 is a singular and CV_LU method is used) */ +CVAPI(int) cvSolve( const CvArr* src1, const CvArr* src2, CvArr* dst, + int method CV_DEFAULT(CV_LU)); + +/** Calculates determinant of input matrix */ +CVAPI(double) cvDet( const CvArr* mat ); + +/** Calculates trace of the matrix (sum of elements on the main diagonal) */ +CVAPI(CvScalar) cvTrace( const CvArr* mat ); + +/** Finds eigen values and vectors of a symmetric matrix */ +CVAPI(void) cvEigenVV( CvArr* mat, CvArr* evects, CvArr* evals, + double eps CV_DEFAULT(0), + int lowindex CV_DEFAULT(-1), + int highindex CV_DEFAULT(-1)); + +///* Finds selected eigen values and vectors of a symmetric matrix */ +//CVAPI(void) cvSelectedEigenVV( CvArr* mat, CvArr* evects, CvArr* evals, +// int lowindex, int highindex ); + +/** Makes an identity matrix (mat_ij = i == j) */ +CVAPI(void) cvSetIdentity( CvArr* mat, CvScalar value CV_DEFAULT(cvRealScalar(1)) ); + +/** Fills matrix with given range of numbers */ +CVAPI(CvArr*) cvRange( CvArr* mat, double start, double end ); + +/** @anchor core_c_CovarFlags +@name Flags for cvCalcCovarMatrix +@see cvCalcCovarMatrix + @{ +*/ + +/** flag for cvCalcCovarMatrix, transpose([v1-avg, v2-avg,...]) * [v1-avg,v2-avg,...] */ +#define CV_COVAR_SCRAMBLED 0 + +/** flag for cvCalcCovarMatrix, [v1-avg, v2-avg,...] * transpose([v1-avg,v2-avg,...]) */ +#define CV_COVAR_NORMAL 1 + +/** flag for cvCalcCovarMatrix, do not calc average (i.e. mean vector) - use the input vector instead + (useful for calculating covariance matrix by parts) */ +#define CV_COVAR_USE_AVG 2 + +/** flag for cvCalcCovarMatrix, scale the covariance matrix coefficients by number of the vectors */ +#define CV_COVAR_SCALE 4 + +/** flag for cvCalcCovarMatrix, all the input vectors are stored in a single matrix, as its rows */ +#define CV_COVAR_ROWS 8 + +/** flag for cvCalcCovarMatrix, all the input vectors are stored in a single matrix, as its columns */ +#define CV_COVAR_COLS 16 + +/** @} */ + +/** Calculates covariation matrix for a set of vectors +@see @ref core_c_CovarFlags "flags" +*/ +CVAPI(void) cvCalcCovarMatrix( const CvArr** vects, int count, + CvArr* cov_mat, CvArr* avg, int flags ); + +#define CV_PCA_DATA_AS_ROW 0 +#define CV_PCA_DATA_AS_COL 1 +#define CV_PCA_USE_AVG 2 +CVAPI(void) cvCalcPCA( const CvArr* data, CvArr* mean, + CvArr* eigenvals, CvArr* eigenvects, int flags ); + +CVAPI(void) cvProjectPCA( const CvArr* data, const CvArr* mean, + const CvArr* eigenvects, CvArr* result ); + +CVAPI(void) cvBackProjectPCA( const CvArr* proj, const CvArr* mean, + const CvArr* eigenvects, CvArr* result ); + +/** Calculates Mahalanobis(weighted) distance */ +CVAPI(double) cvMahalanobis( const CvArr* vec1, const CvArr* vec2, const CvArr* mat ); +#define cvMahalonobis cvMahalanobis + +/****************************************************************************************\ +* Array Statistics * +\****************************************************************************************/ + +/** Finds sum of array elements */ +CVAPI(CvScalar) cvSum( const CvArr* arr ); + +/** Calculates number of non-zero pixels */ +CVAPI(int) cvCountNonZero( const CvArr* arr ); + +/** Calculates mean value of array elements */ +CVAPI(CvScalar) cvAvg( const CvArr* arr, const CvArr* mask CV_DEFAULT(NULL) ); + +/** Calculates mean and standard deviation of pixel values */ +CVAPI(void) cvAvgSdv( const CvArr* arr, CvScalar* mean, CvScalar* std_dev, + const CvArr* mask CV_DEFAULT(NULL) ); + +/** Finds global minimum, maximum and their positions */ +CVAPI(void) cvMinMaxLoc( const CvArr* arr, double* min_val, double* max_val, + CvPoint* min_loc CV_DEFAULT(NULL), + CvPoint* max_loc CV_DEFAULT(NULL), + const CvArr* mask CV_DEFAULT(NULL) ); + +/** @anchor core_c_NormFlags + @name Flags for cvNorm and cvNormalize + @{ +*/ +#define CV_C 1 +#define CV_L1 2 +#define CV_L2 4 +#define CV_NORM_MASK 7 +#define CV_RELATIVE 8 +#define CV_DIFF 16 +#define CV_MINMAX 32 + +#define CV_DIFF_C (CV_DIFF | CV_C) +#define CV_DIFF_L1 (CV_DIFF | CV_L1) +#define CV_DIFF_L2 (CV_DIFF | CV_L2) +#define CV_RELATIVE_C (CV_RELATIVE | CV_C) +#define CV_RELATIVE_L1 (CV_RELATIVE | CV_L1) +#define CV_RELATIVE_L2 (CV_RELATIVE | CV_L2) +/** @} */ + +/** Finds norm, difference norm or relative difference norm for an array (or two arrays) +@see ref core_c_NormFlags "flags" +*/ +CVAPI(double) cvNorm( const CvArr* arr1, const CvArr* arr2 CV_DEFAULT(NULL), + int norm_type CV_DEFAULT(CV_L2), + const CvArr* mask CV_DEFAULT(NULL) ); + +/** @see ref core_c_NormFlags "flags" */ +CVAPI(void) cvNormalize( const CvArr* src, CvArr* dst, + double a CV_DEFAULT(1.), double b CV_DEFAULT(0.), + int norm_type CV_DEFAULT(CV_L2), + const CvArr* mask CV_DEFAULT(NULL) ); + +/** @anchor core_c_ReduceFlags + @name Flags for cvReduce + @{ +*/ +#define CV_REDUCE_SUM 0 +#define CV_REDUCE_AVG 1 +#define CV_REDUCE_MAX 2 +#define CV_REDUCE_MIN 3 +/** @} */ + +/** @see @ref core_c_ReduceFlags "flags" */ +CVAPI(void) cvReduce( const CvArr* src, CvArr* dst, int dim CV_DEFAULT(-1), + int op CV_DEFAULT(CV_REDUCE_SUM) ); + +/****************************************************************************************\ +* Discrete Linear Transforms and Related Functions * +\****************************************************************************************/ + +/** @anchor core_c_DftFlags + @name Flags for cvDFT, cvDCT and cvMulSpectrums + @{ + */ +#define CV_DXT_FORWARD 0 +#define CV_DXT_INVERSE 1 +#define CV_DXT_SCALE 2 /**< divide result by size of array */ +#define CV_DXT_INV_SCALE (CV_DXT_INVERSE + CV_DXT_SCALE) +#define CV_DXT_INVERSE_SCALE CV_DXT_INV_SCALE +#define CV_DXT_ROWS 4 /**< transform each row individually */ +#define CV_DXT_MUL_CONJ 8 /**< conjugate the second argument of cvMulSpectrums */ +/** @} */ + +/** Discrete Fourier Transform: + complex->complex, + real->ccs (forward), + ccs->real (inverse) +@see core_c_DftFlags "flags" +*/ +CVAPI(void) cvDFT( const CvArr* src, CvArr* dst, int flags, + int nonzero_rows CV_DEFAULT(0) ); +#define cvFFT cvDFT + +/** Multiply results of DFTs: DFT(X)*DFT(Y) or DFT(X)*conj(DFT(Y)) +@see core_c_DftFlags "flags" +*/ +CVAPI(void) cvMulSpectrums( const CvArr* src1, const CvArr* src2, + CvArr* dst, int flags ); + +/** Finds optimal DFT vector size >= size0 */ +CVAPI(int) cvGetOptimalDFTSize( int size0 ); + +/** Discrete Cosine Transform +@see core_c_DftFlags "flags" +*/ +CVAPI(void) cvDCT( const CvArr* src, CvArr* dst, int flags ); + +/****************************************************************************************\ +* Dynamic data structures * +\****************************************************************************************/ + +/** Calculates length of sequence slice (with support of negative indices). */ +CVAPI(int) cvSliceLength( CvSlice slice, const CvSeq* seq ); + + +/** Creates new memory storage. + block_size == 0 means that default, + somewhat optimal size, is used (currently, it is 64K) */ +CVAPI(CvMemStorage*) cvCreateMemStorage( int block_size CV_DEFAULT(0)); + + +/** Creates a memory storage that will borrow memory blocks from parent storage */ +CVAPI(CvMemStorage*) cvCreateChildMemStorage( CvMemStorage* parent ); + + +/** Releases memory storage. All the children of a parent must be released before + the parent. A child storage returns all the blocks to parent when it is released */ +CVAPI(void) cvReleaseMemStorage( CvMemStorage** storage ); + + +/** Clears memory storage. This is the only way(!!!) (besides cvRestoreMemStoragePos) + to reuse memory allocated for the storage - cvClearSeq,cvClearSet ... + do not free any memory. + A child storage returns all the blocks to the parent when it is cleared */ +CVAPI(void) cvClearMemStorage( CvMemStorage* storage ); + +/** Remember a storage "free memory" position */ +CVAPI(void) cvSaveMemStoragePos( const CvMemStorage* storage, CvMemStoragePos* pos ); + +/** Restore a storage "free memory" position */ +CVAPI(void) cvRestoreMemStoragePos( CvMemStorage* storage, CvMemStoragePos* pos ); + +/** Allocates continuous buffer of the specified size in the storage */ +CVAPI(void*) cvMemStorageAlloc( CvMemStorage* storage, size_t size ); + +/** Allocates string in memory storage */ +//CVAPI(CvString) cvMemStorageAllocString( CvMemStorage* storage, const char* ptr, +// int len CV_DEFAULT(-1) ); + +/** Creates new empty sequence that will reside in the specified storage */ +CVAPI(CvSeq*) cvCreateSeq( int seq_flags, size_t header_size, + size_t elem_size, CvMemStorage* storage ); + +/** Changes default size (granularity) of sequence blocks. + The default size is ~1Kbyte */ +CVAPI(void) cvSetSeqBlockSize( CvSeq* seq, int delta_elems ); + + +/** Adds new element to the end of sequence. Returns pointer to the element */ +CVAPI(schar*) cvSeqPush( CvSeq* seq, const void* element CV_DEFAULT(NULL)); + + +/** Adds new element to the beginning of sequence. Returns pointer to it */ +CVAPI(schar*) cvSeqPushFront( CvSeq* seq, const void* element CV_DEFAULT(NULL)); + + +/** Removes the last element from sequence and optionally saves it */ +CVAPI(void) cvSeqPop( CvSeq* seq, void* element CV_DEFAULT(NULL)); + + +/** Removes the first element from sequence and optioanally saves it */ +CVAPI(void) cvSeqPopFront( CvSeq* seq, void* element CV_DEFAULT(NULL)); + + +#define CV_FRONT 1 +#define CV_BACK 0 +/** Adds several new elements to the end of sequence */ +CVAPI(void) cvSeqPushMulti( CvSeq* seq, const void* elements, + int count, int in_front CV_DEFAULT(0) ); + +/** Removes several elements from the end of sequence and optionally saves them */ +CVAPI(void) cvSeqPopMulti( CvSeq* seq, void* elements, + int count, int in_front CV_DEFAULT(0) ); + +/** Inserts a new element in the middle of sequence. + cvSeqInsert(seq,0,elem) == cvSeqPushFront(seq,elem) */ +CVAPI(schar*) cvSeqInsert( CvSeq* seq, int before_index, + const void* element CV_DEFAULT(NULL)); + +/** Removes specified sequence element */ +CVAPI(void) cvSeqRemove( CvSeq* seq, int index ); + + +/** Removes all the elements from the sequence. The freed memory + can be reused later only by the same sequence unless cvClearMemStorage + or cvRestoreMemStoragePos is called */ +CVAPI(void) cvClearSeq( CvSeq* seq ); + + +/** Retrieves pointer to specified sequence element. + Negative indices are supported and mean counting from the end + (e.g -1 means the last sequence element) */ +CVAPI(schar*) cvGetSeqElem( const CvSeq* seq, int index ); + +/** Calculates index of the specified sequence element. + Returns -1 if element does not belong to the sequence */ +CVAPI(int) cvSeqElemIdx( const CvSeq* seq, const void* element, + CvSeqBlock** block CV_DEFAULT(NULL) ); + +/** Initializes sequence writer. The new elements will be added to the end of sequence */ +CVAPI(void) cvStartAppendToSeq( CvSeq* seq, CvSeqWriter* writer ); + + +/** Combination of cvCreateSeq and cvStartAppendToSeq */ +CVAPI(void) cvStartWriteSeq( int seq_flags, int header_size, + int elem_size, CvMemStorage* storage, + CvSeqWriter* writer ); + +/** Closes sequence writer, updates sequence header and returns pointer + to the resultant sequence + (which may be useful if the sequence was created using cvStartWriteSeq)) +*/ +CVAPI(CvSeq*) cvEndWriteSeq( CvSeqWriter* writer ); + + +/** Updates sequence header. May be useful to get access to some of previously + written elements via cvGetSeqElem or sequence reader */ +CVAPI(void) cvFlushSeqWriter( CvSeqWriter* writer ); + + +/** Initializes sequence reader. + The sequence can be read in forward or backward direction */ +CVAPI(void) cvStartReadSeq( const CvSeq* seq, CvSeqReader* reader, + int reverse CV_DEFAULT(0) ); + + +/** Returns current sequence reader position (currently observed sequence element) */ +CVAPI(int) cvGetSeqReaderPos( CvSeqReader* reader ); + + +/** Changes sequence reader position. It may seek to an absolute or + to relative to the current position */ +CVAPI(void) cvSetSeqReaderPos( CvSeqReader* reader, int index, + int is_relative CV_DEFAULT(0)); + +/** Copies sequence content to a continuous piece of memory */ +CVAPI(void*) cvCvtSeqToArray( const CvSeq* seq, void* elements, + CvSlice slice CV_DEFAULT(CV_WHOLE_SEQ) ); + +/** Creates sequence header for array. + After that all the operations on sequences that do not alter the content + can be applied to the resultant sequence */ +CVAPI(CvSeq*) cvMakeSeqHeaderForArray( int seq_type, int header_size, + int elem_size, void* elements, int total, + CvSeq* seq, CvSeqBlock* block ); + +/** Extracts sequence slice (with or without copying sequence elements) */ +CVAPI(CvSeq*) cvSeqSlice( const CvSeq* seq, CvSlice slice, + CvMemStorage* storage CV_DEFAULT(NULL), + int copy_data CV_DEFAULT(0)); + +CV_INLINE CvSeq* cvCloneSeq( const CvSeq* seq, CvMemStorage* storage CV_DEFAULT(NULL)) +{ + return cvSeqSlice( seq, CV_WHOLE_SEQ, storage, 1 ); +} + +/** Removes sequence slice */ +CVAPI(void) cvSeqRemoveSlice( CvSeq* seq, CvSlice slice ); + +/** Inserts a sequence or array into another sequence */ +CVAPI(void) cvSeqInsertSlice( CvSeq* seq, int before_index, const CvArr* from_arr ); + +/** a < b ? -1 : a > b ? 1 : 0 */ +typedef int (CV_CDECL* CvCmpFunc)(const void* a, const void* b, void* userdata ); + +/** Sorts sequence in-place given element comparison function */ +CVAPI(void) cvSeqSort( CvSeq* seq, CvCmpFunc func, void* userdata CV_DEFAULT(NULL) ); + +/** Finds element in a [sorted] sequence */ +CVAPI(schar*) cvSeqSearch( CvSeq* seq, const void* elem, CvCmpFunc func, + int is_sorted, int* elem_idx, + void* userdata CV_DEFAULT(NULL) ); + +/** Reverses order of sequence elements in-place */ +CVAPI(void) cvSeqInvert( CvSeq* seq ); + +/** Splits sequence into one or more equivalence classes using the specified criteria */ +CVAPI(int) cvSeqPartition( const CvSeq* seq, CvMemStorage* storage, + CvSeq** labels, CvCmpFunc is_equal, void* userdata ); + +/************ Internal sequence functions ************/ +CVAPI(void) cvChangeSeqBlock( void* reader, int direction ); +CVAPI(void) cvCreateSeqBlock( CvSeqWriter* writer ); + + +/** Creates a new set */ +CVAPI(CvSet*) cvCreateSet( int set_flags, int header_size, + int elem_size, CvMemStorage* storage ); + +/** Adds new element to the set and returns pointer to it */ +CVAPI(int) cvSetAdd( CvSet* set_header, CvSetElem* elem CV_DEFAULT(NULL), + CvSetElem** inserted_elem CV_DEFAULT(NULL) ); + +/** Fast variant of cvSetAdd */ +CV_INLINE CvSetElem* cvSetNew( CvSet* set_header ) +{ + CvSetElem* elem = set_header->free_elems; + if( elem ) + { + set_header->free_elems = elem->next_free; + elem->flags = elem->flags & CV_SET_ELEM_IDX_MASK; + set_header->active_count++; + } + else + cvSetAdd( set_header, NULL, &elem ); + return elem; +} + +/** Removes set element given its pointer */ +CV_INLINE void cvSetRemoveByPtr( CvSet* set_header, void* elem ) +{ + CvSetElem* _elem = (CvSetElem*)elem; + assert( _elem->flags >= 0 /*&& (elem->flags & CV_SET_ELEM_IDX_MASK) < set_header->total*/ ); + _elem->next_free = set_header->free_elems; + _elem->flags = (_elem->flags & CV_SET_ELEM_IDX_MASK) | CV_SET_ELEM_FREE_FLAG; + set_header->free_elems = _elem; + set_header->active_count--; +} + +/** Removes element from the set by its index */ +CVAPI(void) cvSetRemove( CvSet* set_header, int index ); + +/** Returns a set element by index. If the element doesn't belong to the set, + NULL is returned */ +CV_INLINE CvSetElem* cvGetSetElem( const CvSet* set_header, int idx ) +{ + CvSetElem* elem = (CvSetElem*)(void *)cvGetSeqElem( (CvSeq*)set_header, idx ); + return elem && CV_IS_SET_ELEM( elem ) ? elem : 0; +} + +/** Removes all the elements from the set */ +CVAPI(void) cvClearSet( CvSet* set_header ); + +/** Creates new graph */ +CVAPI(CvGraph*) cvCreateGraph( int graph_flags, int header_size, + int vtx_size, int edge_size, + CvMemStorage* storage ); + +/** Adds new vertex to the graph */ +CVAPI(int) cvGraphAddVtx( CvGraph* graph, const CvGraphVtx* vtx CV_DEFAULT(NULL), + CvGraphVtx** inserted_vtx CV_DEFAULT(NULL) ); + + +/** Removes vertex from the graph together with all incident edges */ +CVAPI(int) cvGraphRemoveVtx( CvGraph* graph, int index ); +CVAPI(int) cvGraphRemoveVtxByPtr( CvGraph* graph, CvGraphVtx* vtx ); + + +/** Link two vertices specified by indices or pointers if they + are not connected or return pointer to already existing edge + connecting the vertices. + Functions return 1 if a new edge was created, 0 otherwise */ +CVAPI(int) cvGraphAddEdge( CvGraph* graph, + int start_idx, int end_idx, + const CvGraphEdge* edge CV_DEFAULT(NULL), + CvGraphEdge** inserted_edge CV_DEFAULT(NULL) ); + +CVAPI(int) cvGraphAddEdgeByPtr( CvGraph* graph, + CvGraphVtx* start_vtx, CvGraphVtx* end_vtx, + const CvGraphEdge* edge CV_DEFAULT(NULL), + CvGraphEdge** inserted_edge CV_DEFAULT(NULL) ); + +/** Remove edge connecting two vertices */ +CVAPI(void) cvGraphRemoveEdge( CvGraph* graph, int start_idx, int end_idx ); +CVAPI(void) cvGraphRemoveEdgeByPtr( CvGraph* graph, CvGraphVtx* start_vtx, + CvGraphVtx* end_vtx ); + +/** Find edge connecting two vertices */ +CVAPI(CvGraphEdge*) cvFindGraphEdge( const CvGraph* graph, int start_idx, int end_idx ); +CVAPI(CvGraphEdge*) cvFindGraphEdgeByPtr( const CvGraph* graph, + const CvGraphVtx* start_vtx, + const CvGraphVtx* end_vtx ); +#define cvGraphFindEdge cvFindGraphEdge +#define cvGraphFindEdgeByPtr cvFindGraphEdgeByPtr + +/** Remove all vertices and edges from the graph */ +CVAPI(void) cvClearGraph( CvGraph* graph ); + + +/** Count number of edges incident to the vertex */ +CVAPI(int) cvGraphVtxDegree( const CvGraph* graph, int vtx_idx ); +CVAPI(int) cvGraphVtxDegreeByPtr( const CvGraph* graph, const CvGraphVtx* vtx ); + + +/** Retrieves graph vertex by given index */ +#define cvGetGraphVtx( graph, idx ) (CvGraphVtx*)cvGetSetElem((CvSet*)(graph), (idx)) + +/** Retrieves index of a graph vertex given its pointer */ +#define cvGraphVtxIdx( graph, vtx ) ((vtx)->flags & CV_SET_ELEM_IDX_MASK) + +/** Retrieves index of a graph edge given its pointer */ +#define cvGraphEdgeIdx( graph, edge ) ((edge)->flags & CV_SET_ELEM_IDX_MASK) + +#define cvGraphGetVtxCount( graph ) ((graph)->active_count) +#define cvGraphGetEdgeCount( graph ) ((graph)->edges->active_count) + +#define CV_GRAPH_VERTEX 1 +#define CV_GRAPH_TREE_EDGE 2 +#define CV_GRAPH_BACK_EDGE 4 +#define CV_GRAPH_FORWARD_EDGE 8 +#define CV_GRAPH_CROSS_EDGE 16 +#define CV_GRAPH_ANY_EDGE 30 +#define CV_GRAPH_NEW_TREE 32 +#define CV_GRAPH_BACKTRACKING 64 +#define CV_GRAPH_OVER -1 + +#define CV_GRAPH_ALL_ITEMS -1 + +/** flags for graph vertices and edges */ +#define CV_GRAPH_ITEM_VISITED_FLAG (1 << 30) +#define CV_IS_GRAPH_VERTEX_VISITED(vtx) \ + (((CvGraphVtx*)(vtx))->flags & CV_GRAPH_ITEM_VISITED_FLAG) +#define CV_IS_GRAPH_EDGE_VISITED(edge) \ + (((CvGraphEdge*)(edge))->flags & CV_GRAPH_ITEM_VISITED_FLAG) +#define CV_GRAPH_SEARCH_TREE_NODE_FLAG (1 << 29) +#define CV_GRAPH_FORWARD_EDGE_FLAG (1 << 28) + +typedef struct CvGraphScanner +{ + CvGraphVtx* vtx; /* current graph vertex (or current edge origin) */ + CvGraphVtx* dst; /* current graph edge destination vertex */ + CvGraphEdge* edge; /* current edge */ + + CvGraph* graph; /* the graph */ + CvSeq* stack; /* the graph vertex stack */ + int index; /* the lower bound of certainly visited vertices */ + int mask; /* event mask */ +} +CvGraphScanner; + +/** Creates new graph scanner. */ +CVAPI(CvGraphScanner*) cvCreateGraphScanner( CvGraph* graph, + CvGraphVtx* vtx CV_DEFAULT(NULL), + int mask CV_DEFAULT(CV_GRAPH_ALL_ITEMS)); + +/** Releases graph scanner. */ +CVAPI(void) cvReleaseGraphScanner( CvGraphScanner** scanner ); + +/** Get next graph element */ +CVAPI(int) cvNextGraphItem( CvGraphScanner* scanner ); + +/** Creates a copy of graph */ +CVAPI(CvGraph*) cvCloneGraph( const CvGraph* graph, CvMemStorage* storage ); + + +/** Does look-up transformation. Elements of the source array + (that should be 8uC1 or 8sC1) are used as indexes in lutarr 256-element table */ +CVAPI(void) cvLUT( const CvArr* src, CvArr* dst, const CvArr* lut ); + + +/******************* Iteration through the sequence tree *****************/ +typedef struct CvTreeNodeIterator +{ + const void* node; + int level; + int max_level; +} +CvTreeNodeIterator; + +CVAPI(void) cvInitTreeNodeIterator( CvTreeNodeIterator* tree_iterator, + const void* first, int max_level ); +CVAPI(void*) cvNextTreeNode( CvTreeNodeIterator* tree_iterator ); +CVAPI(void*) cvPrevTreeNode( CvTreeNodeIterator* tree_iterator ); + +/** Inserts sequence into tree with specified "parent" sequence. + If parent is equal to frame (e.g. the most external contour), + then added contour will have null pointer to parent. */ +CVAPI(void) cvInsertNodeIntoTree( void* node, void* parent, void* frame ); + +/** Removes contour from tree (together with the contour children). */ +CVAPI(void) cvRemoveNodeFromTree( void* node, void* frame ); + +/** Gathers pointers to all the sequences, + accessible from the `first`, to the single sequence */ +CVAPI(CvSeq*) cvTreeToNodeSeq( const void* first, int header_size, + CvMemStorage* storage ); + +/** The function implements the K-means algorithm for clustering an array of sample + vectors in a specified number of classes */ +#define CV_KMEANS_USE_INITIAL_LABELS 1 +CVAPI(int) cvKMeans2( const CvArr* samples, int cluster_count, CvArr* labels, + CvTermCriteria termcrit, int attempts CV_DEFAULT(1), + CvRNG* rng CV_DEFAULT(0), int flags CV_DEFAULT(0), + CvArr* _centers CV_DEFAULT(0), double* compactness CV_DEFAULT(0) ); + +/****************************************************************************************\ +* System functions * +\****************************************************************************************/ + +/** Loads optimized functions from IPP, MKL etc. or switches back to pure C code */ +CVAPI(int) cvUseOptimized( int on_off ); + +typedef IplImage* (CV_STDCALL* Cv_iplCreateImageHeader) + (int,int,int,char*,char*,int,int,int,int,int, + IplROI*,IplImage*,void*,IplTileInfo*); +typedef void (CV_STDCALL* Cv_iplAllocateImageData)(IplImage*,int,int); +typedef void (CV_STDCALL* Cv_iplDeallocate)(IplImage*,int); +typedef IplROI* (CV_STDCALL* Cv_iplCreateROI)(int,int,int,int,int); +typedef IplImage* (CV_STDCALL* Cv_iplCloneImage)(const IplImage*); + +/** @brief Makes OpenCV use IPL functions for allocating IplImage and IplROI structures. + +Normally, the function is not called directly. Instead, a simple macro +CV_TURN_ON_IPL_COMPATIBILITY() is used that calls cvSetIPLAllocators and passes there pointers +to IPL allocation functions. : +@code + ... + CV_TURN_ON_IPL_COMPATIBILITY() + ... +@endcode +@param create_header pointer to a function, creating IPL image header. +@param allocate_data pointer to a function, allocating IPL image data. +@param deallocate pointer to a function, deallocating IPL image. +@param create_roi pointer to a function, creating IPL image ROI (i.e. Region of Interest). +@param clone_image pointer to a function, cloning an IPL image. + */ +CVAPI(void) cvSetIPLAllocators( Cv_iplCreateImageHeader create_header, + Cv_iplAllocateImageData allocate_data, + Cv_iplDeallocate deallocate, + Cv_iplCreateROI create_roi, + Cv_iplCloneImage clone_image ); + +#define CV_TURN_ON_IPL_COMPATIBILITY() \ + cvSetIPLAllocators( iplCreateImageHeader, iplAllocateImage, \ + iplDeallocate, iplCreateROI, iplCloneImage ) + +/****************************************************************************************\ +* Data Persistence * +\****************************************************************************************/ + +#if 0 +/********************************** High-level functions ********************************/ + +/** @brief Opens file storage for reading or writing data. + +The function opens file storage for reading or writing data. In the latter case, a new file is +created or an existing file is rewritten. The type of the read or written file is determined by the +filename extension: .xml for XML, .yml or .yaml for YAML and .json for JSON. + +At the same time, it also supports adding parameters like "example.xml?base64". + +The function returns a pointer to the CvFileStorage structure. +If the file cannot be opened then the function returns NULL. +@param filename Name of the file associated with the storage +@param memstorage Memory storage used for temporary data and for +: storing dynamic structures, such as CvSeq or CvGraph . If it is NULL, a temporary memory + storage is created and used. +@param flags Can be one of the following: +> - **CV_STORAGE_READ** the storage is open for reading +> - **CV_STORAGE_WRITE** the storage is open for writing + (use **CV_STORAGE_WRITE | CV_STORAGE_WRITE_BASE64** to write rawdata in Base64) +@param encoding + */ +CVAPI(CvFileStorage*) cvOpenFileStorage( const char* filename, CvMemStorage* memstorage, + int flags, const char* encoding CV_DEFAULT(NULL) ); + +/** @brief Releases file storage. + +The function closes the file associated with the storage and releases all the temporary structures. +It must be called after all I/O operations with the storage are finished. +@param fs Double pointer to the released file storage + */ +CVAPI(void) cvReleaseFileStorage( CvFileStorage** fs ); + +/** returns attribute value or 0 (NULL) if there is no such attribute */ +CVAPI(const char*) cvAttrValue( const CvAttrList* attr, const char* attr_name ); + +/** @brief Starts writing a new structure. + +The function starts writing a compound structure (collection) that can be a sequence or a map. After +all the structure fields, which can be scalars or structures, are written, cvEndWriteStruct should +be called. The function can be used to group some objects or to implement the write function for a +some user object (see CvTypeInfo). +@param fs File storage +@param name Name of the written structure. The structure can be accessed by this name when the +storage is read. +@param struct_flags A combination one of the following values: +- **CV_NODE_SEQ** the written structure is a sequence (see discussion of CvFileStorage ), + that is, its elements do not have a name. +- **CV_NODE_MAP** the written structure is a map (see discussion of CvFileStorage ), that + is, all its elements have names. +One and only one of the two above flags must be specified +- **CV_NODE_FLOW** the optional flag that makes sense only for YAML streams. It means that + the structure is written as a flow (not as a block), which is more compact. It is + recommended to use this flag for structures or arrays whose elements are all scalars. +@param type_name Optional parameter - the object type name. In + case of XML it is written as a type_id attribute of the structure opening tag. In the case of + YAML it is written after a colon following the structure name (see the example in + CvFileStorage description). In case of JSON it is written as a name/value pair. + Mainly it is used with user objects. When the storage is read, the + encoded type name is used to determine the object type (see CvTypeInfo and cvFindType ). +@param attributes This parameter is not used in the current implementation + */ +CVAPI(void) cvStartWriteStruct( CvFileStorage* fs, const char* name, + int struct_flags, const char* type_name CV_DEFAULT(NULL), + CvAttrList attributes CV_DEFAULT(cvAttrList())); + +/** @brief Finishes writing to a file node collection. +@param fs File storage +@sa cvStartWriteStruct. + */ +CVAPI(void) cvEndWriteStruct( CvFileStorage* fs ); + +/** @brief Writes an integer value. + +The function writes a single integer value (with or without a name) to the file storage. +@param fs File storage +@param name Name of the written value. Should be NULL if and only if the parent structure is a +sequence. +@param value The written value + */ +CVAPI(void) cvWriteInt( CvFileStorage* fs, const char* name, int value ); + +/** @brief Writes a floating-point value. + +The function writes a single floating-point value (with or without a name) to file storage. Special +values are encoded as follows: NaN (Not A Number) as .NaN, infinity as +.Inf or -.Inf. + +The following example shows how to use the low-level writing functions to store custom structures, +such as termination criteria, without registering a new type. : +@code + void write_termcriteria( CvFileStorage* fs, const char* struct_name, + CvTermCriteria* termcrit ) + { + cvStartWriteStruct( fs, struct_name, CV_NODE_MAP, NULL, cvAttrList(0,0)); + cvWriteComment( fs, "termination criteria", 1 ); // just a description + if( termcrit->type & CV_TERMCRIT_ITER ) + cvWriteInteger( fs, "max_iterations", termcrit->max_iter ); + if( termcrit->type & CV_TERMCRIT_EPS ) + cvWriteReal( fs, "accuracy", termcrit->epsilon ); + cvEndWriteStruct( fs ); + } +@endcode +@param fs File storage +@param name Name of the written value. Should be NULL if and only if the parent structure is a +sequence. +@param value The written value +*/ +CVAPI(void) cvWriteReal( CvFileStorage* fs, const char* name, double value ); + +/** @brief Writes a text string. + +The function writes a text string to file storage. +@param fs File storage +@param name Name of the written string . Should be NULL if and only if the parent structure is a +sequence. +@param str The written text string +@param quote If non-zero, the written string is put in quotes, regardless of whether they are +required. Otherwise, if the flag is zero, quotes are used only when they are required (e.g. when +the string starts with a digit or contains spaces). + */ +CVAPI(void) cvWriteString( CvFileStorage* fs, const char* name, + const char* str, int quote CV_DEFAULT(0) ); + +/** @brief Writes a comment. + +The function writes a comment into file storage. The comments are skipped when the storage is read. +@param fs File storage +@param comment The written comment, single-line or multi-line +@param eol_comment If non-zero, the function tries to put the comment at the end of current line. +If the flag is zero, if the comment is multi-line, or if it does not fit at the end of the current +line, the comment starts a new line. + */ +CVAPI(void) cvWriteComment( CvFileStorage* fs, const char* comment, + int eol_comment ); + +/** @brief Writes an object to file storage. + +The function writes an object to file storage. First, the appropriate type info is found using +cvTypeOf. Then, the write method associated with the type info is called. + +Attributes are used to customize the writing procedure. The standard types support the following +attributes (all the dt attributes have the same format as in cvWriteRawData): + +-# CvSeq + - **header_dt** description of user fields of the sequence header that follow CvSeq, or + CvChain (if the sequence is a Freeman chain) or CvContour (if the sequence is a contour or + point sequence) + - **dt** description of the sequence elements. + - **recursive** if the attribute is present and is not equal to "0" or "false", the whole + tree of sequences (contours) is stored. +-# CvGraph + - **header_dt** description of user fields of the graph header that follows CvGraph; + - **vertex_dt** description of user fields of graph vertices + - **edge_dt** description of user fields of graph edges (note that the edge weight is + always written, so there is no need to specify it explicitly) + +Below is the code that creates the YAML file shown in the CvFileStorage description: +@code + #include "cxcore.h" + + int main( int argc, char** argv ) + { + CvMat* mat = cvCreateMat( 3, 3, CV_32F ); + CvFileStorage* fs = cvOpenFileStorage( "example.yml", 0, CV_STORAGE_WRITE ); + + cvSetIdentity( mat ); + cvWrite( fs, "A", mat, cvAttrList(0,0) ); + + cvReleaseFileStorage( &fs ); + cvReleaseMat( &mat ); + return 0; + } +@endcode +@param fs File storage +@param name Name of the written object. Should be NULL if and only if the parent structure is a +sequence. +@param ptr Pointer to the object +@param attributes The attributes of the object. They are specific for each particular type (see +the discussion below). + */ +CVAPI(void) cvWrite( CvFileStorage* fs, const char* name, const void* ptr, + CvAttrList attributes CV_DEFAULT(cvAttrList())); + +/** @brief Starts the next stream. + +The function finishes the currently written stream and starts the next stream. In the case of XML +the file with multiple streams looks like this: +@code{.xml} + + + + + + + ... +@endcode +The YAML file will look like this: +@code{.yaml} + %YAML 1.0 + # stream #1 data + ... + --- + # stream #2 data +@endcode +This is useful for concatenating files or for resuming the writing process. +@param fs File storage + */ +CVAPI(void) cvStartNextStream( CvFileStorage* fs ); + +/** @brief Writes multiple numbers. + +The function writes an array, whose elements consist of single or multiple numbers. The function +call can be replaced with a loop containing a few cvWriteInt and cvWriteReal calls, but a single +call is more efficient. Note that because none of the elements have a name, they should be written +to a sequence rather than a map. +@param fs File storage +@param src Pointer to the written array +@param len Number of the array elements to write +@param dt Specification of each array element, see @ref format_spec "format specification" + */ +CVAPI(void) cvWriteRawData( CvFileStorage* fs, const void* src, + int len, const char* dt ); + +/** @brief Writes multiple numbers in Base64. + +If either CV_STORAGE_WRITE_BASE64 or cv::FileStorage::WRITE_BASE64 is used, +this function will be the same as cvWriteRawData. If neither, the main +difference is that it outputs a sequence in Base64 encoding rather than +in plain text. + +This function can only be used to write a sequence with a type "binary". + +@param fs File storage +@param src Pointer to the written array +@param len Number of the array elements to write +@param dt Specification of each array element, see @ref format_spec "format specification" +*/ +CVAPI(void) cvWriteRawDataBase64( CvFileStorage* fs, const void* src, + int len, const char* dt ); + +/** @brief Returns a unique pointer for a given name. + +The function returns a unique pointer for each particular file node name. This pointer can be then +passed to the cvGetFileNode function that is faster than cvGetFileNodeByName because it compares +text strings by comparing pointers rather than the strings' content. + +Consider the following example where an array of points is encoded as a sequence of 2-entry maps: +@code + points: + - { x: 10, y: 10 } + - { x: 20, y: 20 } + - { x: 30, y: 30 } + # ... +@endcode +Then, it is possible to get hashed "x" and "y" pointers to speed up decoding of the points. : +@code + #include "cxcore.h" + + int main( int argc, char** argv ) + { + CvFileStorage* fs = cvOpenFileStorage( "points.yml", 0, CV_STORAGE_READ ); + CvStringHashNode* x_key = cvGetHashedNode( fs, "x", -1, 1 ); + CvStringHashNode* y_key = cvGetHashedNode( fs, "y", -1, 1 ); + CvFileNode* points = cvGetFileNodeByName( fs, 0, "points" ); + + if( CV_NODE_IS_SEQ(points->tag) ) + { + CvSeq* seq = points->data.seq; + int i, total = seq->total; + CvSeqReader reader; + cvStartReadSeq( seq, &reader, 0 ); + for( i = 0; i < total; i++ ) + { + CvFileNode* pt = (CvFileNode*)reader.ptr; + #if 1 // faster variant + CvFileNode* xnode = cvGetFileNode( fs, pt, x_key, 0 ); + CvFileNode* ynode = cvGetFileNode( fs, pt, y_key, 0 ); + assert( xnode && CV_NODE_IS_INT(xnode->tag) && + ynode && CV_NODE_IS_INT(ynode->tag)); + int x = xnode->data.i; // or x = cvReadInt( xnode, 0 ); + int y = ynode->data.i; // or y = cvReadInt( ynode, 0 ); + #elif 1 // slower variant; does not use x_key & y_key + CvFileNode* xnode = cvGetFileNodeByName( fs, pt, "x" ); + CvFileNode* ynode = cvGetFileNodeByName( fs, pt, "y" ); + assert( xnode && CV_NODE_IS_INT(xnode->tag) && + ynode && CV_NODE_IS_INT(ynode->tag)); + int x = xnode->data.i; // or x = cvReadInt( xnode, 0 ); + int y = ynode->data.i; // or y = cvReadInt( ynode, 0 ); + #else // the slowest yet the easiest to use variant + int x = cvReadIntByName( fs, pt, "x", 0 ); + int y = cvReadIntByName( fs, pt, "y", 0 ); + #endif + CV_NEXT_SEQ_ELEM( seq->elem_size, reader ); + printf(" + } + } + cvReleaseFileStorage( &fs ); + return 0; + } +@endcode +Please note that whatever method of accessing a map you are using, it is still much slower than +using plain sequences; for example, in the above example, it is more efficient to encode the points +as pairs of integers in a single numeric sequence. +@param fs File storage +@param name Literal node name +@param len Length of the name (if it is known apriori), or -1 if it needs to be calculated +@param create_missing Flag that specifies, whether an absent key should be added into the hash table +*/ +CVAPI(CvStringHashNode*) cvGetHashedKey( CvFileStorage* fs, const char* name, + int len CV_DEFAULT(-1), + int create_missing CV_DEFAULT(0)); + +/** @brief Retrieves one of the top-level nodes of the file storage. + +The function returns one of the top-level file nodes. The top-level nodes do not have a name, they +correspond to the streams that are stored one after another in the file storage. If the index is out +of range, the function returns a NULL pointer, so all the top-level nodes can be iterated by +subsequent calls to the function with stream_index=0,1,..., until the NULL pointer is returned. +This function can be used as a base for recursive traversal of the file storage. +@param fs File storage +@param stream_index Zero-based index of the stream. See cvStartNextStream . In most cases, +there is only one stream in the file; however, there can be several. + */ +CVAPI(CvFileNode*) cvGetRootFileNode( const CvFileStorage* fs, + int stream_index CV_DEFAULT(0) ); + +/** @brief Finds a node in a map or file storage. + +The function finds a file node. It is a faster version of cvGetFileNodeByName (see +cvGetHashedKey discussion). Also, the function can insert a new node, if it is not in the map yet. +@param fs File storage +@param map The parent map. If it is NULL, the function searches a top-level node. If both map and +key are NULLs, the function returns the root file node - a map that contains top-level nodes. +@param key Unique pointer to the node name, retrieved with cvGetHashedKey +@param create_missing Flag that specifies whether an absent node should be added to the map + */ +CVAPI(CvFileNode*) cvGetFileNode( CvFileStorage* fs, CvFileNode* map, + const CvStringHashNode* key, + int create_missing CV_DEFAULT(0) ); + +/** @brief Finds a node in a map or file storage. + +The function finds a file node by name. The node is searched either in map or, if the pointer is +NULL, among the top-level file storage nodes. Using this function for maps and cvGetSeqElem (or +sequence reader) for sequences, it is possible to navigate through the file storage. To speed up +multiple queries for a certain key (e.g., in the case of an array of structures) one may use a +combination of cvGetHashedKey and cvGetFileNode. +@param fs File storage +@param map The parent map. If it is NULL, the function searches in all the top-level nodes +(streams), starting with the first one. +@param name The file node name + */ +CVAPI(CvFileNode*) cvGetFileNodeByName( const CvFileStorage* fs, + const CvFileNode* map, + const char* name ); + +/** @brief Retrieves an integer value from a file node. + +The function returns an integer that is represented by the file node. If the file node is NULL, the +default_value is returned (thus, it is convenient to call the function right after cvGetFileNode +without checking for a NULL pointer). If the file node has type CV_NODE_INT, then node-\>data.i is +returned. If the file node has type CV_NODE_REAL, then node-\>data.f is converted to an integer +and returned. Otherwise the error is reported. +@param node File node +@param default_value The value that is returned if node is NULL + */ +CV_INLINE int cvReadInt( const CvFileNode* node, int default_value CV_DEFAULT(0) ) +{ + return !node ? default_value : + CV_NODE_IS_INT(node->tag) ? node->data.i : + CV_NODE_IS_REAL(node->tag) ? cvRound(node->data.f) : 0x7fffffff; +} + +/** @brief Finds a file node and returns its value. + +The function is a simple superposition of cvGetFileNodeByName and cvReadInt. +@param fs File storage +@param map The parent map. If it is NULL, the function searches a top-level node. +@param name The node name +@param default_value The value that is returned if the file node is not found + */ +CV_INLINE int cvReadIntByName( const CvFileStorage* fs, const CvFileNode* map, + const char* name, int default_value CV_DEFAULT(0) ) +{ + return cvReadInt( cvGetFileNodeByName( fs, map, name ), default_value ); +} + +/** @brief Retrieves a floating-point value from a file node. + +The function returns a floating-point value that is represented by the file node. If the file node +is NULL, the default_value is returned (thus, it is convenient to call the function right after +cvGetFileNode without checking for a NULL pointer). If the file node has type CV_NODE_REAL , +then node-\>data.f is returned. If the file node has type CV_NODE_INT , then node-:math:\>data.f +is converted to floating-point and returned. Otherwise the result is not determined. +@param node File node +@param default_value The value that is returned if node is NULL + */ +CV_INLINE double cvReadReal( const CvFileNode* node, double default_value CV_DEFAULT(0.) ) +{ + return !node ? default_value : + CV_NODE_IS_INT(node->tag) ? (double)node->data.i : + CV_NODE_IS_REAL(node->tag) ? node->data.f : 1e300; +} + +/** @brief Finds a file node and returns its value. + +The function is a simple superposition of cvGetFileNodeByName and cvReadReal . +@param fs File storage +@param map The parent map. If it is NULL, the function searches a top-level node. +@param name The node name +@param default_value The value that is returned if the file node is not found + */ +CV_INLINE double cvReadRealByName( const CvFileStorage* fs, const CvFileNode* map, + const char* name, double default_value CV_DEFAULT(0.) ) +{ + return cvReadReal( cvGetFileNodeByName( fs, map, name ), default_value ); +} + +/** @brief Retrieves a text string from a file node. + +The function returns a text string that is represented by the file node. If the file node is NULL, +the default_value is returned (thus, it is convenient to call the function right after +cvGetFileNode without checking for a NULL pointer). If the file node has type CV_NODE_STR , then +node-:math:\>data.str.ptr is returned. Otherwise the result is not determined. +@param node File node +@param default_value The value that is returned if node is NULL + */ +CV_INLINE const char* cvReadString( const CvFileNode* node, + const char* default_value CV_DEFAULT(NULL) ) +{ + return !node ? default_value : CV_NODE_IS_STRING(node->tag) ? node->data.str.ptr : 0; +} + +/** @brief Finds a file node by its name and returns its value. + +The function is a simple superposition of cvGetFileNodeByName and cvReadString . +@param fs File storage +@param map The parent map. If it is NULL, the function searches a top-level node. +@param name The node name +@param default_value The value that is returned if the file node is not found + */ +CV_INLINE const char* cvReadStringByName( const CvFileStorage* fs, const CvFileNode* map, + const char* name, const char* default_value CV_DEFAULT(NULL) ) +{ + return cvReadString( cvGetFileNodeByName( fs, map, name ), default_value ); +} + + +/** @brief Decodes an object and returns a pointer to it. + +The function decodes a user object (creates an object in a native representation from the file +storage subtree) and returns it. The object to be decoded must be an instance of a registered type +that supports the read method (see CvTypeInfo). The type of the object is determined by the type +name that is encoded in the file. If the object is a dynamic structure, it is created either in +memory storage and passed to cvOpenFileStorage or, if a NULL pointer was passed, in temporary +memory storage, which is released when cvReleaseFileStorage is called. Otherwise, if the object is +not a dynamic structure, it is created in a heap and should be released with a specialized function +or by using the generic cvRelease. +@param fs File storage +@param node The root object node +@param attributes Unused parameter + */ +CVAPI(void*) cvRead( CvFileStorage* fs, CvFileNode* node, + CvAttrList* attributes CV_DEFAULT(NULL)); + +/** @brief Finds an object by name and decodes it. + +The function is a simple superposition of cvGetFileNodeByName and cvRead. +@param fs File storage +@param map The parent map. If it is NULL, the function searches a top-level node. +@param name The node name +@param attributes Unused parameter + */ +CV_INLINE void* cvReadByName( CvFileStorage* fs, const CvFileNode* map, + const char* name, CvAttrList* attributes CV_DEFAULT(NULL) ) +{ + return cvRead( fs, cvGetFileNodeByName( fs, map, name ), attributes ); +} + + +/** @brief Initializes the file node sequence reader. + +The function initializes the sequence reader to read data from a file node. The initialized reader +can be then passed to cvReadRawDataSlice. +@param fs File storage +@param src The file node (a sequence) to read numbers from +@param reader Pointer to the sequence reader + */ +CVAPI(void) cvStartReadRawData( const CvFileStorage* fs, const CvFileNode* src, + CvSeqReader* reader ); + +/** @brief Initializes file node sequence reader. + +The function reads one or more elements from the file node, representing a sequence, to a +user-specified array. The total number of read sequence elements is a product of total and the +number of components in each array element. For example, if dt=2if, the function will read total\*3 +sequence elements. As with any sequence, some parts of the file node sequence can be skipped or read +repeatedly by repositioning the reader using cvSetSeqReaderPos. +@param fs File storage +@param reader The sequence reader. Initialize it with cvStartReadRawData . +@param count The number of elements to read +@param dst Pointer to the destination array +@param dt Specification of each array element. It has the same format as in cvWriteRawData . + */ +CVAPI(void) cvReadRawDataSlice( const CvFileStorage* fs, CvSeqReader* reader, + int count, void* dst, const char* dt ); + +/** @brief Reads multiple numbers. + +The function reads elements from a file node that represents a sequence of scalars. +@param fs File storage +@param src The file node (a sequence) to read numbers from +@param dst Pointer to the destination array +@param dt Specification of each array element. It has the same format as in cvWriteRawData . + */ +CVAPI(void) cvReadRawData( const CvFileStorage* fs, const CvFileNode* src, + void* dst, const char* dt ); + +/** @brief Writes a file node to another file storage. + +The function writes a copy of a file node to file storage. Possible applications of the function are +merging several file storages into one and conversion between XML, YAML and JSON formats. +@param fs Destination file storage +@param new_node_name New name of the file node in the destination file storage. To keep the +existing name, use cvcvGetFileNodeName +@param node The written node +@param embed If the written node is a collection and this parameter is not zero, no extra level of +hierarchy is created. Instead, all the elements of node are written into the currently written +structure. Of course, map elements can only be embedded into another map, and sequence elements +can only be embedded into another sequence. + */ +CVAPI(void) cvWriteFileNode( CvFileStorage* fs, const char* new_node_name, + const CvFileNode* node, int embed ); + +/** @brief Returns the name of a file node. + +The function returns the name of a file node or NULL, if the file node does not have a name or if +node is NULL. +@param node File node + */ +CVAPI(const char*) cvGetFileNodeName( const CvFileNode* node ); + +/*********************************** Adding own types ***********************************/ + +/** @brief Registers a new type. + +The function registers a new type, which is described by info . The function creates a copy of the +structure, so the user should delete it after calling the function. +@param info Type info structure + */ +CVAPI(void) cvRegisterType( const CvTypeInfo* info ); + +/** @brief Unregisters the type. + +The function unregisters a type with a specified name. If the name is unknown, it is possible to +locate the type info by an instance of the type using cvTypeOf or by iterating the type list, +starting from cvFirstType, and then calling cvUnregisterType(info-\>typeName). +@param type_name Name of an unregistered type + */ +CVAPI(void) cvUnregisterType( const char* type_name ); + +/** @brief Returns the beginning of a type list. + +The function returns the first type in the list of registered types. Navigation through the list can +be done via the prev and next fields of the CvTypeInfo structure. + */ +CVAPI(CvTypeInfo*) cvFirstType(void); + +/** @brief Finds a type by its name. + +The function finds a registered type by its name. It returns NULL if there is no type with the +specified name. +@param type_name Type name + */ +CVAPI(CvTypeInfo*) cvFindType( const char* type_name ); + +/** @brief Returns the type of an object. + +The function finds the type of a given object. It iterates through the list of registered types and +calls the is_instance function/method for every type info structure with that object until one of +them returns non-zero or until the whole list has been traversed. In the latter case, the function +returns NULL. +@param struct_ptr The object pointer + */ +CVAPI(CvTypeInfo*) cvTypeOf( const void* struct_ptr ); + +#endif + +/** @brief Releases an object. + + The function finds the type of a given object and calls release with the double pointer. + @param struct_ptr Double pointer to the object + */ +CVAPI(void) cvRelease( void** struct_ptr ); + +/** @brief Makes a clone of an object. + +The function finds the type of a given object and calls clone with the passed object. Of course, if +you know the object type, for example, struct_ptr is CvMat\*, it is faster to call the specific +function, like cvCloneMat. +@param struct_ptr The object to clone + */ +CVAPI(void*) cvClone( const void* struct_ptr ); + +/*********************************** Measuring Execution Time ***************************/ + +/** helper functions for RNG initialization and accurate time measurement: + uses internal clock counter on x86 */ +CVAPI(int64) cvGetTickCount( void ); +CVAPI(double) cvGetTickFrequency( void ); + +/*********************************** CPU capabilities ***********************************/ + +CVAPI(int) cvCheckHardwareSupport(int feature); + +/*********************************** Multi-Threading ************************************/ + +/** retrieve/set the number of threads used in OpenMP implementations */ +CVAPI(int) cvGetNumThreads( void ); +CVAPI(void) cvSetNumThreads( int threads CV_DEFAULT(0) ); +/** get index of the thread being executed */ +CVAPI(int) cvGetThreadNum( void ); + + +/********************************** Error Handling **************************************/ + +/** Get current OpenCV error status */ +CVAPI(int) cvGetErrStatus( void ); + +/** Sets error status silently */ +CVAPI(void) cvSetErrStatus( int status ); + +#define CV_ErrModeLeaf 0 /* Print error and exit program */ +#define CV_ErrModeParent 1 /* Print error and continue */ +#define CV_ErrModeSilent 2 /* Don't print and continue */ + +/** Retrieves current error processing mode */ +CVAPI(int) cvGetErrMode( void ); + +/** Sets error processing mode, returns previously used mode */ +CVAPI(int) cvSetErrMode( int mode ); + +/** Sets error status and performs some additional actions (displaying message box, + writing message to stderr, terminating application etc.) + depending on the current error mode */ +CVAPI(void) cvError( int status, const char* func_name, + const char* err_msg, const char* file_name, int line ); + +/** Retrieves textual description of the error given its code */ +CVAPI(const char*) cvErrorStr( int status ); + +/** Retrieves detailed information about the last error occurred */ +CVAPI(int) cvGetErrInfo( const char** errcode_desc, const char** description, + const char** filename, int* line ); + +/** Maps IPP error codes to the counterparts from OpenCV */ +CVAPI(int) cvErrorFromIppStatus( int ipp_status ); + +typedef int (CV_CDECL *CvErrorCallback)( int status, const char* func_name, + const char* err_msg, const char* file_name, int line, void* userdata ); + +/** Assigns a new error-handling function */ +CVAPI(CvErrorCallback) cvRedirectError( CvErrorCallback error_handler, + void* userdata CV_DEFAULT(NULL), + void** prev_userdata CV_DEFAULT(NULL) ); + +/** Output nothing */ +CVAPI(int) cvNulDevReport( int status, const char* func_name, const char* err_msg, + const char* file_name, int line, void* userdata ); + +/** Output to console(fprintf(stderr,...)) */ +CVAPI(int) cvStdErrReport( int status, const char* func_name, const char* err_msg, + const char* file_name, int line, void* userdata ); + +/** Output to MessageBox(WIN32) */ +CVAPI(int) cvGuiBoxReport( int status, const char* func_name, const char* err_msg, + const char* file_name, int line, void* userdata ); + +#define OPENCV_ERROR(status,func,context) \ +cvError((status),(func),(context),__FILE__,__LINE__) + +#define OPENCV_ASSERT(expr,func,context) \ +{if (! (expr)) \ +{OPENCV_ERROR(CV_StsInternal,(func),(context));}} + +#define OPENCV_CALL( Func ) \ +{ \ +Func; \ +} + + +/** CV_FUNCNAME macro defines icvFuncName constant which is used by CV_ERROR macro */ +#ifdef CV_NO_FUNC_NAMES +#define CV_FUNCNAME( Name ) +#define cvFuncName "" +#else +#define CV_FUNCNAME( Name ) \ +static char cvFuncName[] = Name +#endif + + +/** + CV_ERROR macro unconditionally raises error with passed code and message. + After raising error, control will be transferred to the exit label. + */ +#define CV_ERROR( Code, Msg ) \ +{ \ + cvError( (Code), cvFuncName, Msg, __FILE__, __LINE__ ); \ + __CV_EXIT__; \ +} + +/** + CV_CHECK macro checks error status after CV (or IPL) + function call. If error detected, control will be transferred to the exit + label. + */ +#define CV_CHECK() \ +{ \ + if( cvGetErrStatus() < 0 ) \ + CV_ERROR( CV_StsBackTrace, "Inner function failed." ); \ +} + + +/** + CV_CALL macro calls CV (or IPL) function, checks error status and + signals a error if the function failed. Useful in "parent node" + error processing mode + */ +#define CV_CALL( Func ) \ +{ \ + Func; \ + CV_CHECK(); \ +} + + +/** Runtime assertion macro */ +#define CV_ASSERT( Condition ) \ +{ \ + if( !(Condition) ) \ + CV_ERROR( CV_StsInternal, "Assertion: " #Condition " failed" ); \ +} + +#define __CV_BEGIN__ { +#define __CV_END__ goto exit; exit: ; } +#define __CV_EXIT__ goto exit + +/** @} core_c */ + +#ifdef __cplusplus +} // extern "C" +#endif + +#ifdef __cplusplus + +#include "opencv2/core/utility.hpp" + +namespace cv +{ + +//! @addtogroup core_c_glue +//! @{ + +/////////////////////////////////////////// glue /////////////////////////////////////////// + +//! converts array (CvMat or IplImage) to cv::Mat +CV_EXPORTS Mat cvarrToMat(const CvArr* arr, bool copyData=false, + bool allowND=true, int coiMode=0, + AutoBuffer* buf=0); + +static inline Mat cvarrToMatND(const CvArr* arr, bool copyData=false, int coiMode=0) +{ + return cvarrToMat(arr, copyData, true, coiMode); +} + + +//! extracts Channel of Interest from CvMat or IplImage and makes cv::Mat out of it. +CV_EXPORTS void extractImageCOI(const CvArr* arr, OutputArray coiimg, int coi=-1); +//! inserts single-channel cv::Mat into a multi-channel CvMat or IplImage +CV_EXPORTS void insertImageCOI(InputArray coiimg, CvArr* arr, int coi=-1); + + + +////// specialized implementations of DefaultDeleter::operator() for classic OpenCV types ////// + +template<> struct DefaultDeleter{ CV_EXPORTS void operator ()(CvMat* obj) const; }; +template<> struct DefaultDeleter{ CV_EXPORTS void operator ()(IplImage* obj) const; }; +template<> struct DefaultDeleter{ CV_EXPORTS void operator ()(CvMatND* obj) const; }; +template<> struct DefaultDeleter{ CV_EXPORTS void operator ()(CvSparseMat* obj) const; }; +template<> struct DefaultDeleter{ CV_EXPORTS void operator ()(CvMemStorage* obj) const; }; + +////////////// convenient wrappers for operating old-style dynamic structures ////////////// + +template class SeqIterator; + +typedef Ptr MemStorage; + +/*! + Template Sequence Class derived from CvSeq + + The class provides more convenient access to sequence elements, + STL-style operations and iterators. + + \note The class is targeted for simple data types, + i.e. no constructors or destructors + are called for the sequence elements. +*/ +template class Seq +{ +public: + typedef SeqIterator<_Tp> iterator; + typedef SeqIterator<_Tp> const_iterator; + + //! the default constructor + Seq(); + //! the constructor for wrapping CvSeq structure. The real element type in CvSeq should match _Tp. + Seq(const CvSeq* seq); + //! creates the empty sequence that resides in the specified storage + Seq(MemStorage& storage, int headerSize = sizeof(CvSeq)); + //! returns read-write reference to the specified element + _Tp& operator [](int idx); + //! returns read-only reference to the specified element + const _Tp& operator[](int idx) const; + //! returns iterator pointing to the beginning of the sequence + SeqIterator<_Tp> begin() const; + //! returns iterator pointing to the element following the last sequence element + SeqIterator<_Tp> end() const; + //! returns the number of elements in the sequence + size_t size() const; + //! returns the type of sequence elements (CV_8UC1 ... CV_64FC(CV_CN_MAX) ...) + int type() const; + //! returns the depth of sequence elements (CV_8U ... CV_64F) + int depth() const; + //! returns the number of channels in each sequence element + int channels() const; + //! returns the size of each sequence element + size_t elemSize() const; + //! returns index of the specified sequence element + size_t index(const _Tp& elem) const; + //! appends the specified element to the end of the sequence + void push_back(const _Tp& elem); + //! appends the specified element to the front of the sequence + void push_front(const _Tp& elem); + //! appends zero or more elements to the end of the sequence + void push_back(const _Tp* elems, size_t count); + //! appends zero or more elements to the front of the sequence + void push_front(const _Tp* elems, size_t count); + //! inserts the specified element to the specified position + void insert(int idx, const _Tp& elem); + //! inserts zero or more elements to the specified position + void insert(int idx, const _Tp* elems, size_t count); + //! removes element at the specified position + void remove(int idx); + //! removes the specified subsequence + void remove(const Range& r); + + //! returns reference to the first sequence element + _Tp& front(); + //! returns read-only reference to the first sequence element + const _Tp& front() const; + //! returns reference to the last sequence element + _Tp& back(); + //! returns read-only reference to the last sequence element + const _Tp& back() const; + //! returns true iff the sequence contains no elements + bool empty() const; + + //! removes all the elements from the sequence + void clear(); + //! removes the first element from the sequence + void pop_front(); + //! removes the last element from the sequence + void pop_back(); + //! removes zero or more elements from the beginning of the sequence + void pop_front(_Tp* elems, size_t count); + //! removes zero or more elements from the end of the sequence + void pop_back(_Tp* elems, size_t count); + + //! copies the whole sequence or the sequence slice to the specified vector + void copyTo(std::vector<_Tp>& vec, const Range& range=Range::all()) const; + //! returns the vector containing all the sequence elements + operator std::vector<_Tp>() const; + + CvSeq* seq; +}; + + +/*! + STL-style Sequence Iterator inherited from the CvSeqReader structure +*/ +template class SeqIterator : public CvSeqReader +{ +public: + //! the default constructor + SeqIterator(); + //! the constructor setting the iterator to the beginning or to the end of the sequence + SeqIterator(const Seq<_Tp>& seq, bool seekEnd=false); + //! positions the iterator within the sequence + void seek(size_t pos); + //! reports the current iterator position + size_t tell() const; + //! returns reference to the current sequence element + _Tp& operator *(); + //! returns read-only reference to the current sequence element + const _Tp& operator *() const; + //! moves iterator to the next sequence element + SeqIterator& operator ++(); + //! moves iterator to the next sequence element + SeqIterator operator ++(int) const; + //! moves iterator to the previous sequence element + SeqIterator& operator --(); + //! moves iterator to the previous sequence element + SeqIterator operator --(int) const; + + //! moves iterator forward by the specified offset (possibly negative) + SeqIterator& operator +=(int); + //! moves iterator backward by the specified offset (possibly negative) + SeqIterator& operator -=(int); + + // this is index of the current element module seq->total*2 + // (to distinguish between 0 and seq->total) + int index; +}; + + + +// bridge C++ => C Seq API +CV_EXPORTS schar* seqPush( CvSeq* seq, const void* element=0); +CV_EXPORTS schar* seqPushFront( CvSeq* seq, const void* element=0); +CV_EXPORTS void seqPop( CvSeq* seq, void* element=0); +CV_EXPORTS void seqPopFront( CvSeq* seq, void* element=0); +CV_EXPORTS void seqPopMulti( CvSeq* seq, void* elements, + int count, int in_front=0 ); +CV_EXPORTS void seqRemove( CvSeq* seq, int index ); +CV_EXPORTS void clearSeq( CvSeq* seq ); +CV_EXPORTS schar* getSeqElem( const CvSeq* seq, int index ); +CV_EXPORTS void seqRemoveSlice( CvSeq* seq, CvSlice slice ); +CV_EXPORTS void seqInsertSlice( CvSeq* seq, int before_index, const CvArr* from_arr ); + +template inline Seq<_Tp>::Seq() : seq(0) {} +template inline Seq<_Tp>::Seq( const CvSeq* _seq ) : seq((CvSeq*)_seq) +{ + CV_Assert(!_seq || _seq->elem_size == sizeof(_Tp)); +} + +template inline Seq<_Tp>::Seq( MemStorage& storage, + int headerSize ) +{ + CV_Assert(headerSize >= (int)sizeof(CvSeq)); + seq = cvCreateSeq(DataType<_Tp>::type, headerSize, sizeof(_Tp), storage); +} + +template inline _Tp& Seq<_Tp>::operator [](int idx) +{ return *(_Tp*)getSeqElem(seq, idx); } + +template inline const _Tp& Seq<_Tp>::operator [](int idx) const +{ return *(_Tp*)getSeqElem(seq, idx); } + +template inline SeqIterator<_Tp> Seq<_Tp>::begin() const +{ return SeqIterator<_Tp>(*this); } + +template inline SeqIterator<_Tp> Seq<_Tp>::end() const +{ return SeqIterator<_Tp>(*this, true); } + +template inline size_t Seq<_Tp>::size() const +{ return seq ? seq->total : 0; } + +template inline int Seq<_Tp>::type() const +{ return seq ? CV_MAT_TYPE(seq->flags) : 0; } + +template inline int Seq<_Tp>::depth() const +{ return seq ? CV_MAT_DEPTH(seq->flags) : 0; } + +template inline int Seq<_Tp>::channels() const +{ return seq ? CV_MAT_CN(seq->flags) : 0; } + +template inline size_t Seq<_Tp>::elemSize() const +{ return seq ? seq->elem_size : 0; } + +template inline size_t Seq<_Tp>::index(const _Tp& elem) const +{ return cvSeqElemIdx(seq, &elem); } + +template inline void Seq<_Tp>::push_back(const _Tp& elem) +{ cvSeqPush(seq, &elem); } + +template inline void Seq<_Tp>::push_front(const _Tp& elem) +{ cvSeqPushFront(seq, &elem); } + +template inline void Seq<_Tp>::push_back(const _Tp* elem, size_t count) +{ cvSeqPushMulti(seq, elem, (int)count, 0); } + +template inline void Seq<_Tp>::push_front(const _Tp* elem, size_t count) +{ cvSeqPushMulti(seq, elem, (int)count, 1); } + +template inline _Tp& Seq<_Tp>::back() +{ return *(_Tp*)getSeqElem(seq, -1); } + +template inline const _Tp& Seq<_Tp>::back() const +{ return *(const _Tp*)getSeqElem(seq, -1); } + +template inline _Tp& Seq<_Tp>::front() +{ return *(_Tp*)getSeqElem(seq, 0); } + +template inline const _Tp& Seq<_Tp>::front() const +{ return *(const _Tp*)getSeqElem(seq, 0); } + +template inline bool Seq<_Tp>::empty() const +{ return !seq || seq->total == 0; } + +template inline void Seq<_Tp>::clear() +{ if(seq) clearSeq(seq); } + +template inline void Seq<_Tp>::pop_back() +{ seqPop(seq); } + +template inline void Seq<_Tp>::pop_front() +{ seqPopFront(seq); } + +template inline void Seq<_Tp>::pop_back(_Tp* elem, size_t count) +{ seqPopMulti(seq, elem, (int)count, 0); } + +template inline void Seq<_Tp>::pop_front(_Tp* elem, size_t count) +{ seqPopMulti(seq, elem, (int)count, 1); } + +template inline void Seq<_Tp>::insert(int idx, const _Tp& elem) +{ seqInsert(seq, idx, &elem); } + +template inline void Seq<_Tp>::insert(int idx, const _Tp* elems, size_t count) +{ + CvMat m = cvMat(1, count, DataType<_Tp>::type, elems); + seqInsertSlice(seq, idx, &m); +} + +template inline void Seq<_Tp>::remove(int idx) +{ seqRemove(seq, idx); } + +template inline void Seq<_Tp>::remove(const Range& r) +{ seqRemoveSlice(seq, cvSlice(r.start, r.end)); } + +template inline void Seq<_Tp>::copyTo(std::vector<_Tp>& vec, const Range& range) const +{ + size_t len = !seq ? 0 : range == Range::all() ? seq->total : range.end - range.start; + vec.resize(len); + if( seq && len ) + cvCvtSeqToArray(seq, &vec[0], cvSlice(range)); +} + +template inline Seq<_Tp>::operator std::vector<_Tp>() const +{ + std::vector<_Tp> vec; + copyTo(vec); + return vec; +} + +template inline SeqIterator<_Tp>::SeqIterator() +{ memset(this, 0, sizeof(*this)); } + +template inline SeqIterator<_Tp>::SeqIterator(const Seq<_Tp>& _seq, bool seekEnd) +{ + cvStartReadSeq(_seq.seq, this); + index = seekEnd ? _seq.seq->total : 0; +} + +template inline void SeqIterator<_Tp>::seek(size_t pos) +{ + cvSetSeqReaderPos(this, (int)pos, false); + index = pos; +} + +template inline size_t SeqIterator<_Tp>::tell() const +{ return index; } + +template inline _Tp& SeqIterator<_Tp>::operator *() +{ return *(_Tp*)ptr; } + +template inline const _Tp& SeqIterator<_Tp>::operator *() const +{ return *(const _Tp*)ptr; } + +template inline SeqIterator<_Tp>& SeqIterator<_Tp>::operator ++() +{ + CV_NEXT_SEQ_ELEM(sizeof(_Tp), *this); + if( ++index >= seq->total*2 ) + index = 0; + return *this; +} + +template inline SeqIterator<_Tp> SeqIterator<_Tp>::operator ++(int) const +{ + SeqIterator<_Tp> it = *this; + ++*this; + return it; +} + +template inline SeqIterator<_Tp>& SeqIterator<_Tp>::operator --() +{ + CV_PREV_SEQ_ELEM(sizeof(_Tp), *this); + if( --index < 0 ) + index = seq->total*2-1; + return *this; +} + +template inline SeqIterator<_Tp> SeqIterator<_Tp>::operator --(int) const +{ + SeqIterator<_Tp> it = *this; + --*this; + return it; +} + +template inline SeqIterator<_Tp>& SeqIterator<_Tp>::operator +=(int delta) +{ + cvSetSeqReaderPos(this, delta, 1); + index += delta; + int n = seq->total*2; + if( index < 0 ) + index += n; + if( index >= n ) + index -= n; + return *this; +} + +template inline SeqIterator<_Tp>& SeqIterator<_Tp>::operator -=(int delta) +{ + return (*this += -delta); +} + +template inline ptrdiff_t operator - (const SeqIterator<_Tp>& a, + const SeqIterator<_Tp>& b) +{ + ptrdiff_t delta = a.index - b.index, n = a.seq->total; + if( delta > n || delta < -n ) + delta += delta < 0 ? n : -n; + return delta; +} + +template inline bool operator == (const SeqIterator<_Tp>& a, + const SeqIterator<_Tp>& b) +{ + return a.seq == b.seq && a.index == b.index; +} + +template inline bool operator != (const SeqIterator<_Tp>& a, + const SeqIterator<_Tp>& b) +{ + return !(a == b); +} + +//! @} + +} // cv + +#endif + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda.hpp new file mode 100644 index 0000000..1ebea07 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda.hpp @@ -0,0 +1,1271 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_CUDA_HPP +#define OPENCV_CORE_CUDA_HPP + +#ifndef __cplusplus +# error cuda.hpp header must be compiled as C++ +#endif + +#include "opencv2/core.hpp" +#include "opencv2/core/cuda_types.hpp" + +/** + @defgroup cuda CUDA-accelerated Computer Vision + @{ + @defgroup cudacore Core part + @{ + @defgroup cudacore_init Initialization and Information + @defgroup cudacore_struct Data Structures + @} + @} + */ + +namespace cv { namespace cuda { + +//! @addtogroup cudacore_struct +//! @{ + +//=================================================================================== +// GpuMat +//=================================================================================== + +/** @brief Base storage class for GPU memory with reference counting. + +Its interface matches the Mat interface with the following limitations: + +- no arbitrary dimensions support (only 2D) +- no functions that return references to their data (because references on GPU are not valid for + CPU) +- no expression templates technique support + +Beware that the latter limitation may lead to overloaded matrix operators that cause memory +allocations. The GpuMat class is convertible to cuda::PtrStepSz and cuda::PtrStep so it can be +passed directly to the kernel. + +@note In contrast with Mat, in most cases GpuMat::isContinuous() == false . This means that rows are +aligned to a size depending on the hardware. Single-row GpuMat is always a continuous matrix. + +@note You are not recommended to leave static or global GpuMat variables allocated, that is, to rely +on its destructor. The destruction order of such variables and CUDA context is undefined. GPU memory +release function returns error if the CUDA context has been destroyed before. + +Some member functions are described as a "Blocking Call" while some are described as a +"Non-Blocking Call". Blocking functions are synchronous to host. It is guaranteed that the GPU +operation is finished when the function returns. However, non-blocking functions are asynchronous to +host. Those functions may return even if the GPU operation is not finished. + +Compared to their blocking counterpart, non-blocking functions accept Stream as an additional +argument. If a non-default stream is passed, the GPU operation may overlap with operations in other +streams. + +@sa Mat + */ +class CV_EXPORTS_W GpuMat +{ +public: + class CV_EXPORTS_W Allocator + { + public: + virtual ~Allocator() {} + + // allocator must fill data, step and refcount fields + virtual bool allocate(GpuMat* mat, int rows, int cols, size_t elemSize) = 0; + virtual void free(GpuMat* mat) = 0; + }; + + //! default allocator + CV_WRAP static GpuMat::Allocator* defaultAllocator(); + CV_WRAP static void setDefaultAllocator(GpuMat::Allocator* allocator); + + //! default constructor + CV_WRAP explicit GpuMat(GpuMat::Allocator* allocator = GpuMat::defaultAllocator()); + + //! constructs GpuMat of the specified size and type + CV_WRAP GpuMat(int rows, int cols, int type, GpuMat::Allocator* allocator = GpuMat::defaultAllocator()); + CV_WRAP GpuMat(Size size, int type, GpuMat::Allocator* allocator = GpuMat::defaultAllocator()); + + //! constructs GpuMat and fills it with the specified value _s + CV_WRAP GpuMat(int rows, int cols, int type, Scalar s, GpuMat::Allocator* allocator = GpuMat::defaultAllocator()); + CV_WRAP GpuMat(Size size, int type, Scalar s, GpuMat::Allocator* allocator = GpuMat::defaultAllocator()); + + //! copy constructor + CV_WRAP GpuMat(const GpuMat& m); + + //! constructor for GpuMat headers pointing to user-allocated data + GpuMat(int rows, int cols, int type, void* data, size_t step = Mat::AUTO_STEP); + GpuMat(Size size, int type, void* data, size_t step = Mat::AUTO_STEP); + + //! creates a GpuMat header for a part of the bigger matrix + CV_WRAP GpuMat(const GpuMat& m, Range rowRange, Range colRange); + CV_WRAP GpuMat(const GpuMat& m, Rect roi); + + //! builds GpuMat from host memory (Blocking call) + CV_WRAP explicit GpuMat(InputArray arr, GpuMat::Allocator* allocator = GpuMat::defaultAllocator()); + + //! destructor - calls release() + ~GpuMat(); + + //! assignment operators + GpuMat& operator =(const GpuMat& m); + + //! allocates new GpuMat data unless the GpuMat already has specified size and type + CV_WRAP void create(int rows, int cols, int type); + CV_WRAP void create(Size size, int type); + + //! decreases reference counter, deallocate the data when reference counter reaches 0 + CV_WRAP void release(); + + //! swaps with other smart pointer + CV_WRAP void swap(GpuMat& mat); + + /** @brief Performs data upload to GpuMat (Blocking call) + + This function copies data from host memory to device memory. As being a blocking call, it is + guaranteed that the copy operation is finished when this function returns. + */ + CV_WRAP void upload(InputArray arr); + + /** @brief Performs data upload to GpuMat (Non-Blocking call) + + This function copies data from host memory to device memory. As being a non-blocking call, this + function may return even if the copy operation is not finished. + + The copy operation may be overlapped with operations in other non-default streams if \p stream is + not the default stream and \p dst is HostMem allocated with HostMem::PAGE_LOCKED option. + */ + CV_WRAP void upload(InputArray arr, Stream& stream); + + /** @brief Performs data download from GpuMat (Blocking call) + + This function copies data from device memory to host memory. As being a blocking call, it is + guaranteed that the copy operation is finished when this function returns. + */ + CV_WRAP void download(OutputArray dst) const; + + /** @brief Performs data download from GpuMat (Non-Blocking call) + + This function copies data from device memory to host memory. As being a non-blocking call, this + function may return even if the copy operation is not finished. + + The copy operation may be overlapped with operations in other non-default streams if \p stream is + not the default stream and \p dst is HostMem allocated with HostMem::PAGE_LOCKED option. + */ + CV_WRAP void download(OutputArray dst, Stream& stream) const; + + //! returns deep copy of the GpuMat, i.e. the data is copied + CV_WRAP GpuMat clone() const; + + //! copies the GpuMat content to device memory (Blocking call) + CV_WRAP void copyTo(OutputArray dst) const; + + //! copies the GpuMat content to device memory (Non-Blocking call) + CV_WRAP void copyTo(OutputArray dst, Stream& stream) const; + + //! copies those GpuMat elements to "m" that are marked with non-zero mask elements (Blocking call) + CV_WRAP void copyTo(OutputArray dst, InputArray mask) const; + + //! copies those GpuMat elements to "m" that are marked with non-zero mask elements (Non-Blocking call) + CV_WRAP void copyTo(OutputArray dst, InputArray mask, Stream& stream) const; + + //! sets some of the GpuMat elements to s (Blocking call) + CV_WRAP GpuMat& setTo(Scalar s); + + //! sets some of the GpuMat elements to s (Non-Blocking call) + CV_WRAP GpuMat& setTo(Scalar s, Stream& stream); + + //! sets some of the GpuMat elements to s, according to the mask (Blocking call) + CV_WRAP GpuMat& setTo(Scalar s, InputArray mask); + + //! sets some of the GpuMat elements to s, according to the mask (Non-Blocking call) + CV_WRAP GpuMat& setTo(Scalar s, InputArray mask, Stream& stream); + + //! converts GpuMat to another datatype (Blocking call) + CV_WRAP void convertTo(OutputArray dst, int rtype) const; + + //! converts GpuMat to another datatype (Non-Blocking call) + CV_WRAP void convertTo(OutputArray dst, int rtype, Stream& stream) const; + + //! converts GpuMat to another datatype with scaling (Blocking call) + CV_WRAP void convertTo(OutputArray dst, int rtype, double alpha, double beta = 0.0) const; + + //! converts GpuMat to another datatype with scaling (Non-Blocking call) + CV_WRAP void convertTo(OutputArray dst, int rtype, double alpha, Stream& stream) const; + + //! converts GpuMat to another datatype with scaling (Non-Blocking call) + CV_WRAP void convertTo(OutputArray dst, int rtype, double alpha, double beta, Stream& stream) const; + + CV_WRAP void assignTo(GpuMat& m, int type = -1) const; + + //! returns pointer to y-th row + uchar* ptr(int y = 0); + const uchar* ptr(int y = 0) const; + + //! template version of the above method + template _Tp* ptr(int y = 0); + template const _Tp* ptr(int y = 0) const; + + template operator PtrStepSz<_Tp>() const; + template operator PtrStep<_Tp>() const; + + //! returns a new GpuMat header for the specified row + CV_WRAP GpuMat row(int y) const; + + //! returns a new GpuMat header for the specified column + CV_WRAP GpuMat col(int x) const; + + //! ... for the specified row span + CV_WRAP GpuMat rowRange(int startrow, int endrow) const; + CV_WRAP GpuMat rowRange(Range r) const; + + //! ... for the specified column span + CV_WRAP GpuMat colRange(int startcol, int endcol) const; + CV_WRAP GpuMat colRange(Range r) const; + + //! extracts a rectangular sub-GpuMat (this is a generalized form of row, rowRange etc.) + GpuMat operator ()(Range rowRange, Range colRange) const; + GpuMat operator ()(Rect roi) const; + + //! creates alternative GpuMat header for the same data, with different + //! number of channels and/or different number of rows + CV_WRAP GpuMat reshape(int cn, int rows = 0) const; + + //! locates GpuMat header within a parent GpuMat + CV_WRAP void locateROI(Size& wholeSize, Point& ofs) const; + + //! moves/resizes the current GpuMat ROI inside the parent GpuMat + CV_WRAP GpuMat& adjustROI(int dtop, int dbottom, int dleft, int dright); + + //! returns true iff the GpuMat data is continuous + //! (i.e. when there are no gaps between successive rows) + CV_WRAP bool isContinuous() const; + + //! returns element size in bytes + CV_WRAP size_t elemSize() const; + + //! returns the size of element channel in bytes + CV_WRAP size_t elemSize1() const; + + //! returns element type + CV_WRAP int type() const; + + //! returns element type + CV_WRAP int depth() const; + + //! returns number of channels + CV_WRAP int channels() const; + + //! returns step/elemSize1() + CV_WRAP size_t step1() const; + + //! returns GpuMat size : width == number of columns, height == number of rows + CV_WRAP Size size() const; + + //! returns true if GpuMat data is NULL + CV_WRAP bool empty() const; + + // returns pointer to cuda memory + CV_WRAP void* cudaPtr() const; + + //! internal use method: updates the continuity flag + CV_WRAP void updateContinuityFlag(); + + /*! includes several bit-fields: + - the magic signature + - continuity flag + - depth + - number of channels + */ + int flags; + + //! the number of rows and columns + int rows, cols; + + //! a distance between successive rows in bytes; includes the gap if any + CV_PROP size_t step; + + //! pointer to the data + uchar* data; + + //! pointer to the reference counter; + //! when GpuMat points to user-allocated data, the pointer is NULL + int* refcount; + + //! helper fields used in locateROI and adjustROI + uchar* datastart; + const uchar* dataend; + + //! allocator + Allocator* allocator; +}; + +struct CV_EXPORTS_W GpuData +{ + explicit GpuData(size_t _size); + ~GpuData(); + + GpuData(const GpuData&) = delete; + GpuData& operator=(const GpuData&) = delete; + + GpuData(GpuData&&) = delete; + GpuData& operator=(GpuData&&) = delete; + + uchar* data; + size_t size; +}; + +class CV_EXPORTS_W GpuMatND +{ +public: + using SizeArray = std::vector; + using StepArray = std::vector; + using IndexArray = std::vector; + + //! destructor + ~GpuMatND(); + + //! default constructor + GpuMatND(); + + /** @overload + @param size Array of integers specifying an n-dimensional array shape. + @param type Array type. Use CV_8UC1, ..., CV_16FC4 to create 1-4 channel matrices, or + CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices. + */ + GpuMatND(SizeArray size, int type); + + /** @overload + @param size Array of integers specifying an n-dimensional array shape. + @param type Array type. Use CV_8UC1, ..., CV_16FC4 to create 1-4 channel matrices, or + CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices. + @param data Pointer to the user data. Matrix constructors that take data and step parameters do not + allocate matrix data. Instead, they just initialize the matrix header that points to the specified + data, which means that no data is copied. This operation is very efficient and can be used to + process external data using OpenCV functions. The external data is not automatically deallocated, so + you should take care of it. + @param step Array of _size.size()-1 steps in case of a multi-dimensional array (the last step is always + set to the element size). If not specified, the matrix is assumed to be continuous. + */ + GpuMatND(SizeArray size, int type, void* data, StepArray step = StepArray()); + + /** @brief Allocates GPU memory. + Suppose there is some GPU memory already allocated. In that case, this method may choose to reuse that + GPU memory under the specific condition: it must be of the same size and type, not externally allocated, + the GPU memory is continuous(i.e., isContinuous() is true), and is not a sub-matrix of another GpuMatND + (i.e., isSubmatrix() is false). In other words, this method guarantees that the GPU memory allocated by + this method is always continuous and is not a sub-region of another GpuMatND. + */ + void create(SizeArray size, int type); + + void release(); + + void swap(GpuMatND& m) noexcept; + + /** @brief Creates a full copy of the array and the underlying data. + The method creates a full copy of the array. It mimics the behavior of Mat::clone(), i.e. + the original step is not taken into account. So, the array copy is a continuous array + occupying total()\*elemSize() bytes. + */ + GpuMatND clone() const; + + /** @overload + This overload is non-blocking, so it may return even if the copy operation is not finished. + */ + GpuMatND clone(Stream& stream) const; + + /** @brief Extracts a sub-matrix. + The operator makes a new header for the specified sub-array of \*this. + The operator is an O(1) operation, that is, no matrix data is copied. + @param ranges Array of selected ranges along each dimension. + */ + GpuMatND operator()(const std::vector& ranges) const; + + /** @brief Creates a GpuMat header for a 2D plane part of an n-dim matrix. + @note The returned GpuMat is constructed with the constructor for user-allocated data. + That is, It does not perform reference counting. + @note This function does not increment this GpuMatND's reference counter. + */ + GpuMat createGpuMatHeader(IndexArray idx, Range rowRange, Range colRange) const; + + /** @overload + Creates a GpuMat header if this GpuMatND is effectively 2D. + @note The returned GpuMat is constructed with the constructor for user-allocated data. + That is, It does not perform reference counting. + @note This function does not increment this GpuMatND's reference counter. + */ + GpuMat createGpuMatHeader() const; + + /** @brief Extracts a 2D plane part of an n-dim matrix. + It differs from createGpuMatHeader(IndexArray, Range, Range) in that it clones a part of this + GpuMatND to the returned GpuMat. + @note This operator does not increment this GpuMatND's reference counter; + */ + GpuMat operator()(IndexArray idx, Range rowRange, Range colRange) const; + + /** @brief Extracts a 2D plane part of an n-dim matrix if this GpuMatND is effectively 2D. + It differs from createGpuMatHeader() in that it clones a part of this GpuMatND. + @note This operator does not increment this GpuMatND's reference counter; + */ + operator GpuMat() const; + + GpuMatND(const GpuMatND&) = default; + GpuMatND& operator=(const GpuMatND&) = default; + +#if defined(__GNUC__) && __GNUC__ < 5 + // error: function '...' defaulted on its first declaration with an exception-specification + // that differs from the implicit declaration '...' + + GpuMatND(GpuMatND&&) = default; + GpuMatND& operator=(GpuMatND&&) = default; +#else + GpuMatND(GpuMatND&&) noexcept = default; + GpuMatND& operator=(GpuMatND&&) noexcept = default; +#endif + + void upload(InputArray src); + void upload(InputArray src, Stream& stream); + void download(OutputArray dst) const; + void download(OutputArray dst, Stream& stream) const; + + //! returns true iff the GpuMatND data is continuous + //! (i.e. when there are no gaps between successive rows) + bool isContinuous() const; + + //! returns true if the matrix is a sub-matrix of another matrix + bool isSubmatrix() const; + + //! returns element size in bytes + size_t elemSize() const; + + //! returns the size of element channel in bytes + size_t elemSize1() const; + + //! returns true if data is null + bool empty() const; + + //! returns true if not empty and points to external(user-allocated) gpu memory + bool external() const; + + //! returns pointer to the first byte of the GPU memory + uchar* getDevicePtr() const; + + //! returns the total number of array elements + size_t total() const; + + //! returns the size of underlying memory in bytes + size_t totalMemSize() const; + + //! returns element type + int type() const; + +private: + //! internal use + void setFields(SizeArray size, int type, StepArray step = StepArray()); + +public: + /*! includes several bit-fields: + - the magic signature + - continuity flag + - depth + - number of channels + */ + int flags; + + //! matrix dimensionality + int dims; + + //! shape of this array + SizeArray size; + + /*! step values + Their semantics is identical to the semantics of step for Mat. + */ + StepArray step; + +private: + /*! internal use + If this GpuMatND holds external memory, this is empty. + */ + std::shared_ptr data_; + + /*! internal use + If this GpuMatND manages memory with reference counting, this value is + always equal to data_->data. If this GpuMatND holds external memory, + data_ is empty and data points to the external memory. + */ + uchar* data; + + /*! internal use + If this GpuMatND is a sub-matrix of a larger matrix, this value is the + difference of the first byte between the sub-matrix and the whole matrix. + */ + size_t offset; +}; + +/** @brief Creates a continuous matrix. + +@param rows Row count. +@param cols Column count. +@param type Type of the matrix. +@param arr Destination matrix. This parameter changes only if it has a proper type and area ( +\f$\texttt{rows} \times \texttt{cols}\f$ ). + +Matrix is called continuous if its elements are stored continuously, that is, without gaps at the +end of each row. + */ +CV_EXPORTS_W void createContinuous(int rows, int cols, int type, OutputArray arr); + +/** @brief Ensures that the size of a matrix is big enough and the matrix has a proper type. + +@param rows Minimum desired number of rows. +@param cols Minimum desired number of columns. +@param type Desired matrix type. +@param arr Destination matrix. + +The function does not reallocate memory if the matrix has proper attributes already. + */ +CV_EXPORTS_W void ensureSizeIsEnough(int rows, int cols, int type, OutputArray arr); + +/** @brief BufferPool for use with CUDA streams + +BufferPool utilizes Stream's allocator to create new buffers for GpuMat's. It is +only useful when enabled with #setBufferPoolUsage. + +@code + setBufferPoolUsage(true); +@endcode + +@note #setBufferPoolUsage must be called \em before any Stream declaration. + +Users may specify custom allocator for Stream and may implement their own stream based +functions utilizing the same underlying GPU memory management. + +If custom allocator is not specified, BufferPool utilizes StackAllocator by +default. StackAllocator allocates a chunk of GPU device memory beforehand, +and when GpuMat is declared later on, it is given the pre-allocated memory. +This kind of strategy reduces the number of calls for memory allocating APIs +such as cudaMalloc or cudaMallocPitch. + +Below is an example that utilizes BufferPool with StackAllocator: + +@code + #include + + using namespace cv; + using namespace cv::cuda + + int main() + { + setBufferPoolUsage(true); // Tell OpenCV that we are going to utilize BufferPool + setBufferPoolConfig(getDevice(), 1024 * 1024 * 64, 2); // Allocate 64 MB, 2 stacks (default is 10 MB, 5 stacks) + + Stream stream1, stream2; // Each stream uses 1 stack + BufferPool pool1(stream1), pool2(stream2); + + GpuMat d_src1 = pool1.getBuffer(4096, 4096, CV_8UC1); // 16MB + GpuMat d_dst1 = pool1.getBuffer(4096, 4096, CV_8UC3); // 48MB, pool1 is now full + + GpuMat d_src2 = pool2.getBuffer(1024, 1024, CV_8UC1); // 1MB + GpuMat d_dst2 = pool2.getBuffer(1024, 1024, CV_8UC3); // 3MB + + cvtColor(d_src1, d_dst1, CV_GRAY2BGR, 0, stream1); + cvtColor(d_src2, d_dst2, CV_GRAY2BGR, 0, stream2); + } +@endcode + +If we allocate another GpuMat on pool1 in the above example, it will be carried out by +the DefaultAllocator since the stack for pool1 is full. + +@code + GpuMat d_add1 = pool1.getBuffer(1024, 1024, CV_8UC1); // Stack for pool1 is full, memory is allocated with DefaultAllocator +@endcode + +If a third stream is declared in the above example, allocating with #getBuffer +within that stream will also be carried out by the DefaultAllocator because we've run out of +stacks. + +@code + Stream stream3; // Only 2 stacks were allocated, we've run out of stacks + BufferPool pool3(stream3); + GpuMat d_src3 = pool3.getBuffer(1024, 1024, CV_8UC1); // Memory is allocated with DefaultAllocator +@endcode + +@warning When utilizing StackAllocator, deallocation order is important. + +Just like a stack, deallocation must be done in LIFO order. Below is an example of +erroneous usage that violates LIFO rule. If OpenCV is compiled in Debug mode, this +sample code will emit CV_Assert error. + +@code + int main() + { + setBufferPoolUsage(true); // Tell OpenCV that we are going to utilize BufferPool + Stream stream; // A default size (10 MB) stack is allocated to this stream + BufferPool pool(stream); + + GpuMat mat1 = pool.getBuffer(1024, 1024, CV_8UC1); // Allocate mat1 (1MB) + GpuMat mat2 = pool.getBuffer(1024, 1024, CV_8UC1); // Allocate mat2 (1MB) + + mat1.release(); // erroneous usage : mat2 must be deallocated before mat1 + } +@endcode + +Since C++ local variables are destroyed in the reverse order of construction, +the code sample below satisfies the LIFO rule. Local GpuMat's are deallocated +and the corresponding memory is automatically returned to the pool for later usage. + +@code + int main() + { + setBufferPoolUsage(true); // Tell OpenCV that we are going to utilize BufferPool + setBufferPoolConfig(getDevice(), 1024 * 1024 * 64, 2); // Allocate 64 MB, 2 stacks (default is 10 MB, 5 stacks) + + Stream stream1, stream2; // Each stream uses 1 stack + BufferPool pool1(stream1), pool2(stream2); + + for (int i = 0; i < 10; i++) + { + GpuMat d_src1 = pool1.getBuffer(4096, 4096, CV_8UC1); // 16MB + GpuMat d_dst1 = pool1.getBuffer(4096, 4096, CV_8UC3); // 48MB, pool1 is now full + + GpuMat d_src2 = pool2.getBuffer(1024, 1024, CV_8UC1); // 1MB + GpuMat d_dst2 = pool2.getBuffer(1024, 1024, CV_8UC3); // 3MB + + d_src1.setTo(Scalar(i), stream1); + d_src2.setTo(Scalar(i), stream2); + + cvtColor(d_src1, d_dst1, CV_GRAY2BGR, 0, stream1); + cvtColor(d_src2, d_dst2, CV_GRAY2BGR, 0, stream2); + // The order of destruction of the local variables is: + // d_dst2 => d_src2 => d_dst1 => d_src1 + // LIFO rule is satisfied, this code runs without error + } + } +@endcode + */ +class CV_EXPORTS_W BufferPool +{ +public: + + //! Gets the BufferPool for the given stream. + CV_WRAP explicit BufferPool(Stream& stream); + + //! Allocates a new GpuMat of given size and type. + CV_WRAP GpuMat getBuffer(int rows, int cols, int type); + + //! Allocates a new GpuMat of given size and type. + CV_WRAP GpuMat getBuffer(Size size, int type) { return getBuffer(size.height, size.width, type); } + + //! Returns the allocator associated with the stream. + CV_WRAP Ptr getAllocator() const { return allocator_; } + +private: + Ptr allocator_; +}; + +//! BufferPool management (must be called before Stream creation) +CV_EXPORTS_W void setBufferPoolUsage(bool on); +CV_EXPORTS_W void setBufferPoolConfig(int deviceId, size_t stackSize, int stackCount); + +//=================================================================================== +// HostMem +//=================================================================================== + +/** @brief Class with reference counting wrapping special memory type allocation functions from CUDA. + +Its interface is also Mat-like but with additional memory type parameters. + +- **PAGE_LOCKED** sets a page locked memory type used commonly for fast and asynchronous + uploading/downloading data from/to GPU. +- **SHARED** specifies a zero copy memory allocation that enables mapping the host memory to GPU + address space, if supported. +- **WRITE_COMBINED** sets the write combined buffer that is not cached by CPU. Such buffers are + used to supply GPU with data when GPU only reads it. The advantage is a better CPU cache + utilization. + +@note Allocation size of such memory types is usually limited. For more details, see *CUDA 2.2 +Pinned Memory APIs* document or *CUDA C Programming Guide*. + */ +class CV_EXPORTS_W HostMem +{ +public: + enum AllocType { PAGE_LOCKED = 1, SHARED = 2, WRITE_COMBINED = 4 }; + + static MatAllocator* getAllocator(HostMem::AllocType alloc_type = HostMem::AllocType::PAGE_LOCKED); + + CV_WRAP explicit HostMem(HostMem::AllocType alloc_type = HostMem::AllocType::PAGE_LOCKED); + + HostMem(const HostMem& m); + + CV_WRAP HostMem(int rows, int cols, int type, HostMem::AllocType alloc_type = HostMem::AllocType::PAGE_LOCKED); + CV_WRAP HostMem(Size size, int type, HostMem::AllocType alloc_type = HostMem::AllocType::PAGE_LOCKED); + + //! creates from host memory with coping data + CV_WRAP explicit HostMem(InputArray arr, HostMem::AllocType alloc_type = HostMem::AllocType::PAGE_LOCKED); + + ~HostMem(); + + HostMem& operator =(const HostMem& m); + + //! swaps with other smart pointer + CV_WRAP void swap(HostMem& b); + + //! returns deep copy of the matrix, i.e. the data is copied + CV_WRAP HostMem clone() const; + + //! allocates new matrix data unless the matrix already has specified size and type. + CV_WRAP void create(int rows, int cols, int type); + void create(Size size, int type); + + //! creates alternative HostMem header for the same data, with different + //! number of channels and/or different number of rows + CV_WRAP HostMem reshape(int cn, int rows = 0) const; + + //! decrements reference counter and released memory if needed. + void release(); + + //! returns matrix header with disabled reference counting for HostMem data. + CV_WRAP Mat createMatHeader() const; + + /** @brief Maps CPU memory to GPU address space and creates the cuda::GpuMat header without reference counting + for it. + + This can be done only if memory was allocated with the SHARED flag and if it is supported by the + hardware. Laptops often share video and CPU memory, so address spaces can be mapped, which + eliminates an extra copy. + */ + GpuMat createGpuMatHeader() const; + + // Please see cv::Mat for descriptions + CV_WRAP bool isContinuous() const; + CV_WRAP size_t elemSize() const; + CV_WRAP size_t elemSize1() const; + CV_WRAP int type() const; + CV_WRAP int depth() const; + CV_WRAP int channels() const; + CV_WRAP size_t step1() const; + CV_WRAP Size size() const; + CV_WRAP bool empty() const; + + // Please see cv::Mat for descriptions + int flags; + int rows, cols; + CV_PROP size_t step; + + uchar* data; + int* refcount; + + uchar* datastart; + const uchar* dataend; + + AllocType alloc_type; +}; + +/** @brief Page-locks the memory of matrix and maps it for the device(s). + +@param m Input matrix. + */ +CV_EXPORTS_W void registerPageLocked(Mat& m); + +/** @brief Unmaps the memory of matrix and makes it pageable again. + +@param m Input matrix. + */ +CV_EXPORTS_W void unregisterPageLocked(Mat& m); + +//=================================================================================== +// Stream +//=================================================================================== + +/** @brief This class encapsulates a queue of asynchronous calls. + +@note Currently, you may face problems if an operation is enqueued twice with different data. Some +functions use the constant GPU memory, and next call may update the memory before the previous one +has been finished. But calling different operations asynchronously is safe because each operation +has its own constant buffer. Memory copy/upload/download/set operations to the buffers you hold are +also safe. + +@note The Stream class is not thread-safe. Please use different Stream objects for different CPU threads. + +@code +void thread1() +{ + cv::cuda::Stream stream1; + cv::cuda::func1(..., stream1); +} + +void thread2() +{ + cv::cuda::Stream stream2; + cv::cuda::func2(..., stream2); +} +@endcode + +@note By default all CUDA routines are launched in Stream::Null() object, if the stream is not specified by user. +In multi-threading environment the stream objects must be passed explicitly (see previous note). + */ +class CV_EXPORTS_W Stream +{ + typedef void (Stream::*bool_type)() const; + void this_type_does_not_support_comparisons() const {} + +public: + typedef void (*StreamCallback)(int status, void* userData); + + //! creates a new asynchronous stream + CV_WRAP Stream(); + + //! creates a new asynchronous stream with custom allocator + CV_WRAP Stream(const Ptr& allocator); + + /** @brief creates a new Stream using the cudaFlags argument to determine the behaviors of the stream + + @note The cudaFlags parameter is passed to the underlying api cudaStreamCreateWithFlags() and + supports the same parameter values. + @code + // creates an OpenCV cuda::Stream that manages an asynchronous, non-blocking, + // non-default CUDA stream + cv::cuda::Stream cvStream(cudaStreamNonBlocking); + @endcode + */ + CV_WRAP Stream(const size_t cudaFlags); + + /** @brief Returns true if the current stream queue is finished. Otherwise, it returns false. + */ + CV_WRAP bool queryIfComplete() const; + + /** @brief Blocks the current CPU thread until all operations in the stream are complete. + */ + CV_WRAP void waitForCompletion(); + + /** @brief Makes a compute stream wait on an event. + */ + CV_WRAP void waitEvent(const Event& event); + + /** @brief Adds a callback to be called on the host after all currently enqueued items in the stream have + completed. + + @note Callbacks must not make any CUDA API calls. Callbacks must not perform any synchronization + that may depend on outstanding device work or other callbacks that are not mandated to run earlier. + Callbacks without a mandated order (in independent streams) execute in undefined order and may be + serialized. + */ + void enqueueHostCallback(StreamCallback callback, void* userData); + + //! return Stream object for default CUDA stream + CV_WRAP static Stream& Null(); + + //! returns true if stream object is not default (!= 0) + operator bool_type() const; + + //! return Pointer to CUDA stream + CV_WRAP void* cudaPtr() const; + + class Impl; + +private: + Ptr impl_; + Stream(const Ptr& impl); + + friend struct StreamAccessor; + friend class BufferPool; + friend class DefaultDeviceInitializer; +}; + +class CV_EXPORTS_W Event +{ +public: + enum CreateFlags + { + DEFAULT = 0x00, /**< Default event flag */ + BLOCKING_SYNC = 0x01, /**< Event uses blocking synchronization */ + DISABLE_TIMING = 0x02, /**< Event will not record timing data */ + INTERPROCESS = 0x04 /**< Event is suitable for interprocess use. DisableTiming must be set */ + }; + + CV_WRAP explicit Event(const Event::CreateFlags flags = Event::CreateFlags::DEFAULT); + + //! records an event + CV_WRAP void record(Stream& stream = Stream::Null()); + + //! queries an event's status + CV_WRAP bool queryIfComplete() const; + + //! waits for an event to complete + CV_WRAP void waitForCompletion(); + + //! computes the elapsed time between events + CV_WRAP static float elapsedTime(const Event& start, const Event& end); + + class Impl; + +private: + Ptr impl_; + Event(const Ptr& impl); + + friend struct EventAccessor; +}; +CV_ENUM_FLAGS(Event::CreateFlags) + +//! @} cudacore_struct + +//=================================================================================== +// Initialization & Info +//=================================================================================== + +//! @addtogroup cudacore_init +//! @{ + +/** @brief Returns the number of installed CUDA-enabled devices. + +Use this function before any other CUDA functions calls. If OpenCV is compiled without CUDA support, +this function returns 0. If the CUDA driver is not installed, or is incompatible, this function +returns -1. + */ +CV_EXPORTS_W int getCudaEnabledDeviceCount(); + +/** @brief Sets a device and initializes it for the current thread. + +@param device System index of a CUDA device starting with 0. + +If the call of this function is omitted, a default device is initialized at the fist CUDA usage. + */ +CV_EXPORTS_W void setDevice(int device); + +/** @brief Returns the current device index set by cuda::setDevice or initialized by default. + */ +CV_EXPORTS_W int getDevice(); + +/** @brief Explicitly destroys and cleans up all resources associated with the current device in the current +process. + +Any subsequent API call to this device will reinitialize the device. + */ +CV_EXPORTS_W void resetDevice(); + +/** @brief Enumeration providing CUDA computing features. + */ +enum FeatureSet +{ + FEATURE_SET_COMPUTE_10 = 10, + FEATURE_SET_COMPUTE_11 = 11, + FEATURE_SET_COMPUTE_12 = 12, + FEATURE_SET_COMPUTE_13 = 13, + FEATURE_SET_COMPUTE_20 = 20, + FEATURE_SET_COMPUTE_21 = 21, + FEATURE_SET_COMPUTE_30 = 30, + FEATURE_SET_COMPUTE_32 = 32, + FEATURE_SET_COMPUTE_35 = 35, + FEATURE_SET_COMPUTE_50 = 50, + + GLOBAL_ATOMICS = FEATURE_SET_COMPUTE_11, + SHARED_ATOMICS = FEATURE_SET_COMPUTE_12, + NATIVE_DOUBLE = FEATURE_SET_COMPUTE_13, + WARP_SHUFFLE_FUNCTIONS = FEATURE_SET_COMPUTE_30, + DYNAMIC_PARALLELISM = FEATURE_SET_COMPUTE_35 +}; + +//! checks whether current device supports the given feature +CV_EXPORTS bool deviceSupports(FeatureSet feature_set); + +/** @brief Class providing a set of static methods to check what NVIDIA\* card architecture the CUDA module was +built for. + +According to the CUDA C Programming Guide Version 3.2: "PTX code produced for some specific compute +capability can always be compiled to binary code of greater or equal compute capability". + */ +class CV_EXPORTS_W TargetArchs +{ +public: + /** @brief The following method checks whether the module was built with the support of the given feature: + + @param feature_set Features to be checked. See :ocvcuda::FeatureSet. + */ + static bool builtWith(FeatureSet feature_set); + + /** @brief There is a set of methods to check whether the module contains intermediate (PTX) or binary CUDA + code for the given architecture(s): + + @param major Major compute capability version. + @param minor Minor compute capability version. + */ + CV_WRAP static bool has(int major, int minor); + CV_WRAP static bool hasPtx(int major, int minor); + CV_WRAP static bool hasBin(int major, int minor); + + CV_WRAP static bool hasEqualOrLessPtx(int major, int minor); + CV_WRAP static bool hasEqualOrGreater(int major, int minor); + CV_WRAP static bool hasEqualOrGreaterPtx(int major, int minor); + CV_WRAP static bool hasEqualOrGreaterBin(int major, int minor); +}; + +/** @brief Class providing functionality for querying the specified GPU properties. + */ +class CV_EXPORTS_W DeviceInfo +{ +public: + //! creates DeviceInfo object for the current GPU + CV_WRAP DeviceInfo(); + + /** @brief The constructors. + + @param device_id System index of the CUDA device starting with 0. + + Constructs the DeviceInfo object for the specified device. If device_id parameter is missed, it + constructs an object for the current device. + */ + CV_WRAP DeviceInfo(int device_id); + + /** @brief Returns system index of the CUDA device starting with 0. + */ + CV_WRAP int deviceID() const; + + //! ASCII string identifying device + const char* name() const; + + //! global memory available on device in bytes + CV_WRAP size_t totalGlobalMem() const; + + //! shared memory available per block in bytes + CV_WRAP size_t sharedMemPerBlock() const; + + //! 32-bit registers available per block + CV_WRAP int regsPerBlock() const; + + //! warp size in threads + CV_WRAP int warpSize() const; + + //! maximum pitch in bytes allowed by memory copies + CV_WRAP size_t memPitch() const; + + //! maximum number of threads per block + CV_WRAP int maxThreadsPerBlock() const; + + //! maximum size of each dimension of a block + CV_WRAP Vec3i maxThreadsDim() const; + + //! maximum size of each dimension of a grid + CV_WRAP Vec3i maxGridSize() const; + + //! clock frequency in kilohertz + CV_WRAP int clockRate() const; + + //! constant memory available on device in bytes + CV_WRAP size_t totalConstMem() const; + + //! major compute capability + CV_WRAP int majorVersion() const; + + //! minor compute capability + CV_WRAP int minorVersion() const; + + //! alignment requirement for textures + CV_WRAP size_t textureAlignment() const; + + //! pitch alignment requirement for texture references bound to pitched memory + CV_WRAP size_t texturePitchAlignment() const; + + //! number of multiprocessors on device + CV_WRAP int multiProcessorCount() const; + + //! specified whether there is a run time limit on kernels + CV_WRAP bool kernelExecTimeoutEnabled() const; + + //! device is integrated as opposed to discrete + CV_WRAP bool integrated() const; + + //! device can map host memory with cudaHostAlloc/cudaHostGetDevicePointer + CV_WRAP bool canMapHostMemory() const; + + enum ComputeMode + { + ComputeModeDefault, /**< default compute mode (Multiple threads can use cudaSetDevice with this device) */ + ComputeModeExclusive, /**< compute-exclusive-thread mode (Only one thread in one process will be able to use cudaSetDevice with this device) */ + ComputeModeProhibited, /**< compute-prohibited mode (No threads can use cudaSetDevice with this device) */ + ComputeModeExclusiveProcess /**< compute-exclusive-process mode (Many threads in one process will be able to use cudaSetDevice with this device) */ + }; + + //! compute mode + CV_WRAP DeviceInfo::ComputeMode computeMode() const; + + //! maximum 1D texture size + CV_WRAP int maxTexture1D() const; + + //! maximum 1D mipmapped texture size + CV_WRAP int maxTexture1DMipmap() const; + + //! maximum size for 1D textures bound to linear memory + CV_WRAP int maxTexture1DLinear() const; + + //! maximum 2D texture dimensions + CV_WRAP Vec2i maxTexture2D() const; + + //! maximum 2D mipmapped texture dimensions + CV_WRAP Vec2i maxTexture2DMipmap() const; + + //! maximum dimensions (width, height, pitch) for 2D textures bound to pitched memory + CV_WRAP Vec3i maxTexture2DLinear() const; + + //! maximum 2D texture dimensions if texture gather operations have to be performed + CV_WRAP Vec2i maxTexture2DGather() const; + + //! maximum 3D texture dimensions + CV_WRAP Vec3i maxTexture3D() const; + + //! maximum Cubemap texture dimensions + CV_WRAP int maxTextureCubemap() const; + + //! maximum 1D layered texture dimensions + CV_WRAP Vec2i maxTexture1DLayered() const; + + //! maximum 2D layered texture dimensions + CV_WRAP Vec3i maxTexture2DLayered() const; + + //! maximum Cubemap layered texture dimensions + CV_WRAP Vec2i maxTextureCubemapLayered() const; + + //! maximum 1D surface size + CV_WRAP int maxSurface1D() const; + + //! maximum 2D surface dimensions + CV_WRAP Vec2i maxSurface2D() const; + + //! maximum 3D surface dimensions + CV_WRAP Vec3i maxSurface3D() const; + + //! maximum 1D layered surface dimensions + CV_WRAP Vec2i maxSurface1DLayered() const; + + //! maximum 2D layered surface dimensions + CV_WRAP Vec3i maxSurface2DLayered() const; + + //! maximum Cubemap surface dimensions + CV_WRAP int maxSurfaceCubemap() const; + + //! maximum Cubemap layered surface dimensions + CV_WRAP Vec2i maxSurfaceCubemapLayered() const; + + //! alignment requirements for surfaces + CV_WRAP size_t surfaceAlignment() const; + + //! device can possibly execute multiple kernels concurrently + CV_WRAP bool concurrentKernels() const; + + //! device has ECC support enabled + CV_WRAP bool ECCEnabled() const; + + //! PCI bus ID of the device + CV_WRAP int pciBusID() const; + + //! PCI device ID of the device + CV_WRAP int pciDeviceID() const; + + //! PCI domain ID of the device + CV_WRAP int pciDomainID() const; + + //! true if device is a Tesla device using TCC driver, false otherwise + CV_WRAP bool tccDriver() const; + + //! number of asynchronous engines + CV_WRAP int asyncEngineCount() const; + + //! device shares a unified address space with the host + CV_WRAP bool unifiedAddressing() const; + + //! peak memory clock frequency in kilohertz + CV_WRAP int memoryClockRate() const; + + //! global memory bus width in bits + CV_WRAP int memoryBusWidth() const; + + //! size of L2 cache in bytes + CV_WRAP int l2CacheSize() const; + + //! maximum resident threads per multiprocessor + CV_WRAP int maxThreadsPerMultiProcessor() const; + + //! gets free and total device memory + CV_WRAP void queryMemory(size_t& totalMemory, size_t& freeMemory) const; + CV_WRAP size_t freeMemory() const; + CV_WRAP size_t totalMemory() const; + + /** @brief Provides information on CUDA feature support. + + @param feature_set Features to be checked. See cuda::FeatureSet. + + This function returns true if the device has the specified CUDA feature. Otherwise, it returns false + */ + bool supports(FeatureSet feature_set) const; + + /** @brief Checks the CUDA module and device compatibility. + + This function returns true if the CUDA module can be run on the specified device. Otherwise, it + returns false . + */ + CV_WRAP bool isCompatible() const; + +private: + int device_id_; +}; + +CV_EXPORTS_W void printCudaDeviceInfo(int device); +CV_EXPORTS_W void printShortCudaDeviceInfo(int device); + +/** @brief Converts an array to half precision floating number. + +@param _src input array. +@param _dst output array. +@param stream Stream for the asynchronous version. +@sa convertFp16 +*/ +CV_EXPORTS void convertFp16(InputArray _src, OutputArray _dst, Stream& stream = Stream::Null()); + +//! @} cudacore_init + +}} // namespace cv { namespace cuda { + + +#include "opencv2/core/cuda.inl.hpp" + +#endif /* OPENCV_CORE_CUDA_HPP */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda.inl.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda.inl.hpp new file mode 100644 index 0000000..3f2a0c7 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda.inl.hpp @@ -0,0 +1,723 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_CUDAINL_HPP +#define OPENCV_CORE_CUDAINL_HPP + +#include "opencv2/core/cuda.hpp" + +//! @cond IGNORED + +namespace cv { namespace cuda { + +//=================================================================================== +// GpuMat +//=================================================================================== + +inline +GpuMat::GpuMat(Allocator* allocator_) + : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0), allocator(allocator_) +{} + +inline +GpuMat::GpuMat(int rows_, int cols_, int type_, Allocator* allocator_) + : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0), allocator(allocator_) +{ + if (rows_ > 0 && cols_ > 0) + create(rows_, cols_, type_); +} + +inline +GpuMat::GpuMat(Size size_, int type_, Allocator* allocator_) + : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0), allocator(allocator_) +{ + if (size_.height > 0 && size_.width > 0) + create(size_.height, size_.width, type_); +} + +inline +GpuMat::GpuMat(int rows_, int cols_, int type_, Scalar s_, Allocator* allocator_) + : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0), allocator(allocator_) +{ + if (rows_ > 0 && cols_ > 0) + { + create(rows_, cols_, type_); + setTo(s_); + } +} + +inline +GpuMat::GpuMat(Size size_, int type_, Scalar s_, Allocator* allocator_) + : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0), allocator(allocator_) +{ + if (size_.height > 0 && size_.width > 0) + { + create(size_.height, size_.width, type_); + setTo(s_); + } +} + +inline +GpuMat::GpuMat(const GpuMat& m) + : flags(m.flags), rows(m.rows), cols(m.cols), step(m.step), data(m.data), refcount(m.refcount), datastart(m.datastart), dataend(m.dataend), allocator(m.allocator) +{ + if (refcount) + CV_XADD(refcount, 1); +} + +inline +GpuMat::GpuMat(InputArray arr, Allocator* allocator_) : + flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0), allocator(allocator_) +{ + upload(arr); +} + +inline +GpuMat::~GpuMat() +{ + release(); +} + +inline +GpuMat& GpuMat::operator =(const GpuMat& m) +{ + if (this != &m) + { + GpuMat temp(m); + swap(temp); + } + + return *this; +} + +inline +void GpuMat::create(Size size_, int type_) +{ + create(size_.height, size_.width, type_); +} + +inline +void GpuMat::swap(GpuMat& b) +{ + std::swap(flags, b.flags); + std::swap(rows, b.rows); + std::swap(cols, b.cols); + std::swap(step, b.step); + std::swap(data, b.data); + std::swap(datastart, b.datastart); + std::swap(dataend, b.dataend); + std::swap(refcount, b.refcount); + std::swap(allocator, b.allocator); +} + +inline +GpuMat GpuMat::clone() const +{ + GpuMat m; + copyTo(m); + return m; +} + +inline +void GpuMat::copyTo(OutputArray dst, InputArray mask) const +{ + copyTo(dst, mask, Stream::Null()); +} + +inline +GpuMat& GpuMat::setTo(Scalar s) +{ + return setTo(s, Stream::Null()); +} + +inline +GpuMat& GpuMat::setTo(Scalar s, InputArray mask) +{ + return setTo(s, mask, Stream::Null()); +} + +inline +void GpuMat::convertTo(OutputArray dst, int rtype) const +{ + convertTo(dst, rtype, Stream::Null()); +} + +inline +void GpuMat::convertTo(OutputArray dst, int rtype, double alpha, double beta) const +{ + convertTo(dst, rtype, alpha, beta, Stream::Null()); +} + +inline +void GpuMat::convertTo(OutputArray dst, int rtype, double alpha, Stream& stream) const +{ + convertTo(dst, rtype, alpha, 0.0, stream); +} + +inline +void GpuMat::assignTo(GpuMat& m, int _type) const +{ + if (_type < 0) + m = *this; + else + convertTo(m, _type); +} + +inline +uchar* GpuMat::ptr(int y) +{ + CV_DbgAssert( (unsigned)y < (unsigned)rows ); + return data + step * y; +} + +inline +const uchar* GpuMat::ptr(int y) const +{ + CV_DbgAssert( (unsigned)y < (unsigned)rows ); + return data + step * y; +} + +template inline +_Tp* GpuMat::ptr(int y) +{ + return (_Tp*)ptr(y); +} + +template inline +const _Tp* GpuMat::ptr(int y) const +{ + return (const _Tp*)ptr(y); +} + +template inline +GpuMat::operator PtrStepSz() const +{ + return PtrStepSz(rows, cols, (T*)data, step); +} + +template inline +GpuMat::operator PtrStep() const +{ + return PtrStep((T*)data, step); +} + +inline +GpuMat GpuMat::row(int y) const +{ + return GpuMat(*this, Range(y, y+1), Range::all()); +} + +inline +GpuMat GpuMat::col(int x) const +{ + return GpuMat(*this, Range::all(), Range(x, x+1)); +} + +inline +GpuMat GpuMat::rowRange(int startrow, int endrow) const +{ + return GpuMat(*this, Range(startrow, endrow), Range::all()); +} + +inline +GpuMat GpuMat::rowRange(Range r) const +{ + return GpuMat(*this, r, Range::all()); +} + +inline +GpuMat GpuMat::colRange(int startcol, int endcol) const +{ + return GpuMat(*this, Range::all(), Range(startcol, endcol)); +} + +inline +GpuMat GpuMat::colRange(Range r) const +{ + return GpuMat(*this, Range::all(), r); +} + +inline +GpuMat GpuMat::operator ()(Range rowRange_, Range colRange_) const +{ + return GpuMat(*this, rowRange_, colRange_); +} + +inline +GpuMat GpuMat::operator ()(Rect roi) const +{ + return GpuMat(*this, roi); +} + +inline +bool GpuMat::isContinuous() const +{ + return (flags & Mat::CONTINUOUS_FLAG) != 0; +} + +inline +size_t GpuMat::elemSize() const +{ + return CV_ELEM_SIZE(flags); +} + +inline +size_t GpuMat::elemSize1() const +{ + return CV_ELEM_SIZE1(flags); +} + +inline +int GpuMat::type() const +{ + return CV_MAT_TYPE(flags); +} + +inline +int GpuMat::depth() const +{ + return CV_MAT_DEPTH(flags); +} + +inline +int GpuMat::channels() const +{ + return CV_MAT_CN(flags); +} + +inline +size_t GpuMat::step1() const +{ + return step / elemSize1(); +} + +inline +Size GpuMat::size() const +{ + return Size(cols, rows); +} + +inline +bool GpuMat::empty() const +{ + return data == 0; +} + +inline +void* GpuMat::cudaPtr() const +{ + return data; +} + +static inline +GpuMat createContinuous(int rows, int cols, int type) +{ + GpuMat m; + createContinuous(rows, cols, type, m); + return m; +} + +static inline +void createContinuous(Size size, int type, OutputArray arr) +{ + createContinuous(size.height, size.width, type, arr); +} + +static inline +GpuMat createContinuous(Size size, int type) +{ + GpuMat m; + createContinuous(size, type, m); + return m; +} + +static inline +void ensureSizeIsEnough(Size size, int type, OutputArray arr) +{ + ensureSizeIsEnough(size.height, size.width, type, arr); +} + +static inline +void swap(GpuMat& a, GpuMat& b) +{ + a.swap(b); +} + +//=================================================================================== +// GpuMatND +//=================================================================================== + +inline +GpuMatND::GpuMatND() : + flags(0), dims(0), data(nullptr), offset(0) +{ +} + +inline +GpuMatND::GpuMatND(SizeArray _size, int _type) : + flags(0), dims(0), data(nullptr), offset(0) +{ + create(std::move(_size), _type); +} + +inline +void GpuMatND::swap(GpuMatND& m) noexcept +{ + std::swap(*this, m); +} + +inline +bool GpuMatND::isContinuous() const +{ + return (flags & Mat::CONTINUOUS_FLAG) != 0; +} + +inline +bool GpuMatND::isSubmatrix() const +{ + return (flags & Mat::SUBMATRIX_FLAG) != 0; +} + +inline +size_t GpuMatND::elemSize() const +{ + return CV_ELEM_SIZE(flags); +} + +inline +size_t GpuMatND::elemSize1() const +{ + return CV_ELEM_SIZE1(flags); +} + +inline +bool GpuMatND::empty() const +{ + return data == nullptr; +} + +inline +bool GpuMatND::external() const +{ + return !empty() && data_.use_count() == 0; +} + +inline +uchar* GpuMatND::getDevicePtr() const +{ + return data + offset; +} + +inline +size_t GpuMatND::total() const +{ + size_t p = 1; + for(auto s : size) + p *= s; + return p; +} + +inline +size_t GpuMatND::totalMemSize() const +{ + return size[0] * step[0]; +} + +inline +int GpuMatND::type() const +{ + return CV_MAT_TYPE(flags); +} + +//=================================================================================== +// HostMem +//=================================================================================== + +inline +HostMem::HostMem(AllocType alloc_type_) + : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0), alloc_type(alloc_type_) +{ +} + +inline +HostMem::HostMem(const HostMem& m) + : flags(m.flags), rows(m.rows), cols(m.cols), step(m.step), data(m.data), refcount(m.refcount), datastart(m.datastart), dataend(m.dataend), alloc_type(m.alloc_type) +{ + if( refcount ) + CV_XADD(refcount, 1); +} + +inline +HostMem::HostMem(int rows_, int cols_, int type_, AllocType alloc_type_) + : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0), alloc_type(alloc_type_) +{ + if (rows_ > 0 && cols_ > 0) + create(rows_, cols_, type_); +} + +inline +HostMem::HostMem(Size size_, int type_, AllocType alloc_type_) + : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0), alloc_type(alloc_type_) +{ + if (size_.height > 0 && size_.width > 0) + create(size_.height, size_.width, type_); +} + +inline +HostMem::HostMem(InputArray arr, AllocType alloc_type_) + : flags(0), rows(0), cols(0), step(0), data(0), refcount(0), datastart(0), dataend(0), alloc_type(alloc_type_) +{ + arr.getMat().copyTo(*this); +} + +inline +HostMem::~HostMem() +{ + release(); +} + +inline +HostMem& HostMem::operator =(const HostMem& m) +{ + if (this != &m) + { + HostMem temp(m); + swap(temp); + } + + return *this; +} + +inline +void HostMem::swap(HostMem& b) +{ + std::swap(flags, b.flags); + std::swap(rows, b.rows); + std::swap(cols, b.cols); + std::swap(step, b.step); + std::swap(data, b.data); + std::swap(datastart, b.datastart); + std::swap(dataend, b.dataend); + std::swap(refcount, b.refcount); + std::swap(alloc_type, b.alloc_type); +} + +inline +HostMem HostMem::clone() const +{ + HostMem m(size(), type(), alloc_type); + createMatHeader().copyTo(m); + return m; +} + +inline +void HostMem::create(Size size_, int type_) +{ + create(size_.height, size_.width, type_); +} + +inline +Mat HostMem::createMatHeader() const +{ + return Mat(size(), type(), data, step); +} + +inline +bool HostMem::isContinuous() const +{ + return (flags & Mat::CONTINUOUS_FLAG) != 0; +} + +inline +size_t HostMem::elemSize() const +{ + return CV_ELEM_SIZE(flags); +} + +inline +size_t HostMem::elemSize1() const +{ + return CV_ELEM_SIZE1(flags); +} + +inline +int HostMem::type() const +{ + return CV_MAT_TYPE(flags); +} + +inline +int HostMem::depth() const +{ + return CV_MAT_DEPTH(flags); +} + +inline +int HostMem::channels() const +{ + return CV_MAT_CN(flags); +} + +inline +size_t HostMem::step1() const +{ + return step / elemSize1(); +} + +inline +Size HostMem::size() const +{ + return Size(cols, rows); +} + +inline +bool HostMem::empty() const +{ + return data == 0; +} + +static inline +void swap(HostMem& a, HostMem& b) +{ + a.swap(b); +} + +//=================================================================================== +// Stream +//=================================================================================== + +inline +Stream::Stream(const Ptr& impl) + : impl_(impl) +{ +} + +//=================================================================================== +// Event +//=================================================================================== + +inline +Event::Event(const Ptr& impl) + : impl_(impl) +{ +} + +//=================================================================================== +// Initialization & Info +//=================================================================================== + +inline +bool TargetArchs::has(int major, int minor) +{ + return hasPtx(major, minor) || hasBin(major, minor); +} + +inline +bool TargetArchs::hasEqualOrGreater(int major, int minor) +{ + return hasEqualOrGreaterPtx(major, minor) || hasEqualOrGreaterBin(major, minor); +} + +inline +DeviceInfo::DeviceInfo() +{ + device_id_ = getDevice(); +} + +inline +DeviceInfo::DeviceInfo(int device_id) +{ + CV_Assert( device_id >= 0 && device_id < getCudaEnabledDeviceCount() ); + device_id_ = device_id; +} + +inline +int DeviceInfo::deviceID() const +{ + return device_id_; +} + +inline +size_t DeviceInfo::freeMemory() const +{ + size_t _totalMemory = 0, _freeMemory = 0; + queryMemory(_totalMemory, _freeMemory); + return _freeMemory; +} + +inline +size_t DeviceInfo::totalMemory() const +{ + size_t _totalMemory = 0, _freeMemory = 0; + queryMemory(_totalMemory, _freeMemory); + return _totalMemory; +} + +inline +bool DeviceInfo::supports(FeatureSet feature_set) const +{ + int version = majorVersion() * 10 + minorVersion(); + return version >= feature_set; +} + + +}} // namespace cv { namespace cuda { + +//=================================================================================== +// Mat +//=================================================================================== + +namespace cv { + +inline +Mat::Mat(const cuda::GpuMat& m) + : flags(0), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0), datalimit(0), allocator(0), u(0), size(&rows) +{ + m.download(*this); +} + +} + +//! @endcond + +#endif // OPENCV_CORE_CUDAINL_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/block.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/block.hpp new file mode 100644 index 0000000..c277f0e --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/block.hpp @@ -0,0 +1,211 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_DEVICE_BLOCK_HPP +#define OPENCV_CUDA_DEVICE_BLOCK_HPP + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + struct Block + { + static __device__ __forceinline__ unsigned int id() + { + return blockIdx.x; + } + + static __device__ __forceinline__ unsigned int stride() + { + return blockDim.x * blockDim.y * blockDim.z; + } + + static __device__ __forceinline__ void sync() + { + __syncthreads(); + } + + static __device__ __forceinline__ int flattenedThreadId() + { + return threadIdx.z * blockDim.x * blockDim.y + threadIdx.y * blockDim.x + threadIdx.x; + } + + template + static __device__ __forceinline__ void fill(It beg, It end, const T& value) + { + int STRIDE = stride(); + It t = beg + flattenedThreadId(); + + for(; t < end; t += STRIDE) + *t = value; + } + + template + static __device__ __forceinline__ void yota(OutIt beg, OutIt end, T value) + { + int STRIDE = stride(); + int tid = flattenedThreadId(); + value += tid; + + for(OutIt t = beg + tid; t < end; t += STRIDE, value += STRIDE) + *t = value; + } + + template + static __device__ __forceinline__ void copy(InIt beg, InIt end, OutIt out) + { + int STRIDE = stride(); + InIt t = beg + flattenedThreadId(); + OutIt o = out + (t - beg); + + for(; t < end; t += STRIDE, o += STRIDE) + *o = *t; + } + + template + static __device__ __forceinline__ void transform(InIt beg, InIt end, OutIt out, UnOp op) + { + int STRIDE = stride(); + InIt t = beg + flattenedThreadId(); + OutIt o = out + (t - beg); + + for(; t < end; t += STRIDE, o += STRIDE) + *o = op(*t); + } + + template + static __device__ __forceinline__ void transform(InIt1 beg1, InIt1 end1, InIt2 beg2, OutIt out, BinOp op) + { + int STRIDE = stride(); + InIt1 t1 = beg1 + flattenedThreadId(); + InIt2 t2 = beg2 + flattenedThreadId(); + OutIt o = out + (t1 - beg1); + + for(; t1 < end1; t1 += STRIDE, t2 += STRIDE, o += STRIDE) + *o = op(*t1, *t2); + } + + template + static __device__ __forceinline__ void reduce(volatile T* buffer, BinOp op) + { + int tid = flattenedThreadId(); + T val = buffer[tid]; + + if (CTA_SIZE >= 1024) { if (tid < 512) buffer[tid] = val = op(val, buffer[tid + 512]); __syncthreads(); } + if (CTA_SIZE >= 512) { if (tid < 256) buffer[tid] = val = op(val, buffer[tid + 256]); __syncthreads(); } + if (CTA_SIZE >= 256) { if (tid < 128) buffer[tid] = val = op(val, buffer[tid + 128]); __syncthreads(); } + if (CTA_SIZE >= 128) { if (tid < 64) buffer[tid] = val = op(val, buffer[tid + 64]); __syncthreads(); } + + if (tid < 32) + { + if (CTA_SIZE >= 64) { buffer[tid] = val = op(val, buffer[tid + 32]); } + if (CTA_SIZE >= 32) { buffer[tid] = val = op(val, buffer[tid + 16]); } + if (CTA_SIZE >= 16) { buffer[tid] = val = op(val, buffer[tid + 8]); } + if (CTA_SIZE >= 8) { buffer[tid] = val = op(val, buffer[tid + 4]); } + if (CTA_SIZE >= 4) { buffer[tid] = val = op(val, buffer[tid + 2]); } + if (CTA_SIZE >= 2) { buffer[tid] = val = op(val, buffer[tid + 1]); } + } + } + + template + static __device__ __forceinline__ T reduce(volatile T* buffer, T init, BinOp op) + { + int tid = flattenedThreadId(); + T val = buffer[tid] = init; + __syncthreads(); + + if (CTA_SIZE >= 1024) { if (tid < 512) buffer[tid] = val = op(val, buffer[tid + 512]); __syncthreads(); } + if (CTA_SIZE >= 512) { if (tid < 256) buffer[tid] = val = op(val, buffer[tid + 256]); __syncthreads(); } + if (CTA_SIZE >= 256) { if (tid < 128) buffer[tid] = val = op(val, buffer[tid + 128]); __syncthreads(); } + if (CTA_SIZE >= 128) { if (tid < 64) buffer[tid] = val = op(val, buffer[tid + 64]); __syncthreads(); } + + if (tid < 32) + { + if (CTA_SIZE >= 64) { buffer[tid] = val = op(val, buffer[tid + 32]); } + if (CTA_SIZE >= 32) { buffer[tid] = val = op(val, buffer[tid + 16]); } + if (CTA_SIZE >= 16) { buffer[tid] = val = op(val, buffer[tid + 8]); } + if (CTA_SIZE >= 8) { buffer[tid] = val = op(val, buffer[tid + 4]); } + if (CTA_SIZE >= 4) { buffer[tid] = val = op(val, buffer[tid + 2]); } + if (CTA_SIZE >= 2) { buffer[tid] = val = op(val, buffer[tid + 1]); } + } + __syncthreads(); + return buffer[0]; + } + + template + static __device__ __forceinline__ void reduce_n(T* data, unsigned int n, BinOp op) + { + int ftid = flattenedThreadId(); + int sft = stride(); + + if (sft < n) + { + for (unsigned int i = sft + ftid; i < n; i += sft) + data[ftid] = op(data[ftid], data[i]); + + __syncthreads(); + + n = sft; + } + + while (n > 1) + { + unsigned int half = n/2; + + if (ftid < half) + data[ftid] = op(data[ftid], data[n - ftid - 1]); + + __syncthreads(); + + n = n - half; + } + } + }; +}}} + +//! @endcond + +#endif /* OPENCV_CUDA_DEVICE_BLOCK_HPP */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/border_interpolate.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/border_interpolate.hpp new file mode 100644 index 0000000..874f705 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/border_interpolate.hpp @@ -0,0 +1,722 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_BORDER_INTERPOLATE_HPP +#define OPENCV_CUDA_BORDER_INTERPOLATE_HPP + +#include "saturate_cast.hpp" +#include "vec_traits.hpp" +#include "vec_math.hpp" + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + ////////////////////////////////////////////////////////////// + // BrdConstant + + template struct BrdRowConstant + { + typedef D result_type; + + explicit __host__ __device__ __forceinline__ BrdRowConstant(int width_, const D& val_ = VecTraits::all(0)) : width(width_), val(val_) {} + + template __device__ __forceinline__ D at_low(int x, const T* data) const + { + return x >= 0 ? saturate_cast(data[x]) : val; + } + + template __device__ __forceinline__ D at_high(int x, const T* data) const + { + return x < width ? saturate_cast(data[x]) : val; + } + + template __device__ __forceinline__ D at(int x, const T* data) const + { + return (x >= 0 && x < width) ? saturate_cast(data[x]) : val; + } + + int width; + D val; + }; + + template struct BrdColConstant + { + typedef D result_type; + + explicit __host__ __device__ __forceinline__ BrdColConstant(int height_, const D& val_ = VecTraits::all(0)) : height(height_), val(val_) {} + + template __device__ __forceinline__ D at_low(int y, const T* data, size_t step) const + { + return y >= 0 ? saturate_cast(*(const T*)((const char*)data + y * step)) : val; + } + + template __device__ __forceinline__ D at_high(int y, const T* data, size_t step) const + { + return y < height ? saturate_cast(*(const T*)((const char*)data + y * step)) : val; + } + + template __device__ __forceinline__ D at(int y, const T* data, size_t step) const + { + return (y >= 0 && y < height) ? saturate_cast(*(const T*)((const char*)data + y * step)) : val; + } + + int height; + D val; + }; + + template struct BrdConstant + { + typedef D result_type; + + __host__ __device__ __forceinline__ BrdConstant(int height_, int width_, const D& val_ = VecTraits::all(0)) : height(height_), width(width_), val(val_) + { + } + + template __device__ __forceinline__ D at(int y, int x, const T* data, size_t step) const + { + return (x >= 0 && x < width && y >= 0 && y < height) ? saturate_cast(((const T*)((const uchar*)data + y * step))[x]) : val; + } + + template __device__ __forceinline__ D at(typename Ptr2D::index_type y, typename Ptr2D::index_type x, const Ptr2D& src) const + { + return (x >= 0 && x < width && y >= 0 && y < height) ? saturate_cast(src(y, x)) : val; + } + + int height; + int width; + D val; + }; + + ////////////////////////////////////////////////////////////// + // BrdReplicate + + template struct BrdRowReplicate + { + typedef D result_type; + + explicit __host__ __device__ __forceinline__ BrdRowReplicate(int width) : last_col(width - 1) {} + template __host__ __device__ __forceinline__ BrdRowReplicate(int width, U) : last_col(width - 1) {} + + __device__ __forceinline__ int idx_col_low(int x) const + { + return ::max(x, 0); + } + + __device__ __forceinline__ int idx_col_high(int x) const + { + return ::min(x, last_col); + } + + __device__ __forceinline__ int idx_col(int x) const + { + return idx_col_low(idx_col_high(x)); + } + + template __device__ __forceinline__ D at_low(int x, const T* data) const + { + return saturate_cast(data[idx_col_low(x)]); + } + + template __device__ __forceinline__ D at_high(int x, const T* data) const + { + return saturate_cast(data[idx_col_high(x)]); + } + + template __device__ __forceinline__ D at(int x, const T* data) const + { + return saturate_cast(data[idx_col(x)]); + } + + int last_col; + }; + + template struct BrdColReplicate + { + typedef D result_type; + + explicit __host__ __device__ __forceinline__ BrdColReplicate(int height) : last_row(height - 1) {} + template __host__ __device__ __forceinline__ BrdColReplicate(int height, U) : last_row(height - 1) {} + + __device__ __forceinline__ int idx_row_low(int y) const + { + return ::max(y, 0); + } + + __device__ __forceinline__ int idx_row_high(int y) const + { + return ::min(y, last_row); + } + + __device__ __forceinline__ int idx_row(int y) const + { + return idx_row_low(idx_row_high(y)); + } + + template __device__ __forceinline__ D at_low(int y, const T* data, size_t step) const + { + return saturate_cast(*(const T*)((const char*)data + idx_row_low(y) * step)); + } + + template __device__ __forceinline__ D at_high(int y, const T* data, size_t step) const + { + return saturate_cast(*(const T*)((const char*)data + idx_row_high(y) * step)); + } + + template __device__ __forceinline__ D at(int y, const T* data, size_t step) const + { + return saturate_cast(*(const T*)((const char*)data + idx_row(y) * step)); + } + + int last_row; + }; + + template struct BrdReplicate + { + typedef D result_type; + + __host__ __device__ __forceinline__ BrdReplicate(int height, int width) : last_row(height - 1), last_col(width - 1) {} + template __host__ __device__ __forceinline__ BrdReplicate(int height, int width, U) : last_row(height - 1), last_col(width - 1) {} + + __device__ __forceinline__ int idx_row_low(int y) const + { + return ::max(y, 0); + } + + __device__ __forceinline__ int idx_row_high(int y) const + { + return ::min(y, last_row); + } + + __device__ __forceinline__ int idx_row(int y) const + { + return idx_row_low(idx_row_high(y)); + } + + __device__ __forceinline__ int idx_col_low(int x) const + { + return ::max(x, 0); + } + + __device__ __forceinline__ int idx_col_high(int x) const + { + return ::min(x, last_col); + } + + __device__ __forceinline__ int idx_col(int x) const + { + return idx_col_low(idx_col_high(x)); + } + + template __device__ __forceinline__ D at(int y, int x, const T* data, size_t step) const + { + return saturate_cast(((const T*)((const char*)data + idx_row(y) * step))[idx_col(x)]); + } + + template __device__ __forceinline__ D at(typename Ptr2D::index_type y, typename Ptr2D::index_type x, const Ptr2D& src) const + { + return saturate_cast(src(idx_row(y), idx_col(x))); + } + + int last_row; + int last_col; + }; + + ////////////////////////////////////////////////////////////// + // BrdReflect101 + + template struct BrdRowReflect101 + { + typedef D result_type; + + explicit __host__ __device__ __forceinline__ BrdRowReflect101(int width) : last_col(width - 1) {} + template __host__ __device__ __forceinline__ BrdRowReflect101(int width, U) : last_col(width - 1) {} + + __device__ __forceinline__ int idx_col_low(int x) const + { + return ::abs(x) % (last_col + 1); + } + + __device__ __forceinline__ int idx_col_high(int x) const + { + return ::abs(last_col - ::abs(last_col - x)) % (last_col + 1); + } + + __device__ __forceinline__ int idx_col(int x) const + { + return idx_col_low(idx_col_high(x)); + } + + template __device__ __forceinline__ D at_low(int x, const T* data) const + { + return saturate_cast(data[idx_col_low(x)]); + } + + template __device__ __forceinline__ D at_high(int x, const T* data) const + { + return saturate_cast(data[idx_col_high(x)]); + } + + template __device__ __forceinline__ D at(int x, const T* data) const + { + return saturate_cast(data[idx_col(x)]); + } + + int last_col; + }; + + template struct BrdColReflect101 + { + typedef D result_type; + + explicit __host__ __device__ __forceinline__ BrdColReflect101(int height) : last_row(height - 1) {} + template __host__ __device__ __forceinline__ BrdColReflect101(int height, U) : last_row(height - 1) {} + + __device__ __forceinline__ int idx_row_low(int y) const + { + return ::abs(y) % (last_row + 1); + } + + __device__ __forceinline__ int idx_row_high(int y) const + { + return ::abs(last_row - ::abs(last_row - y)) % (last_row + 1); + } + + __device__ __forceinline__ int idx_row(int y) const + { + return idx_row_low(idx_row_high(y)); + } + + template __device__ __forceinline__ D at_low(int y, const T* data, size_t step) const + { + return saturate_cast(*(const D*)((const char*)data + idx_row_low(y) * step)); + } + + template __device__ __forceinline__ D at_high(int y, const T* data, size_t step) const + { + return saturate_cast(*(const D*)((const char*)data + idx_row_high(y) * step)); + } + + template __device__ __forceinline__ D at(int y, const T* data, size_t step) const + { + return saturate_cast(*(const D*)((const char*)data + idx_row(y) * step)); + } + + int last_row; + }; + + template struct BrdReflect101 + { + typedef D result_type; + + __host__ __device__ __forceinline__ BrdReflect101(int height, int width) : last_row(height - 1), last_col(width - 1) {} + template __host__ __device__ __forceinline__ BrdReflect101(int height, int width, U) : last_row(height - 1), last_col(width - 1) {} + + __device__ __forceinline__ int idx_row_low(int y) const + { + return ::abs(y) % (last_row + 1); + } + + __device__ __forceinline__ int idx_row_high(int y) const + { + return ::abs(last_row - ::abs(last_row - y)) % (last_row + 1); + } + + __device__ __forceinline__ int idx_row(int y) const + { + return idx_row_low(idx_row_high(y)); + } + + __device__ __forceinline__ int idx_col_low(int x) const + { + return ::abs(x) % (last_col + 1); + } + + __device__ __forceinline__ int idx_col_high(int x) const + { + return ::abs(last_col - ::abs(last_col - x)) % (last_col + 1); + } + + __device__ __forceinline__ int idx_col(int x) const + { + return idx_col_low(idx_col_high(x)); + } + + template __device__ __forceinline__ D at(int y, int x, const T* data, size_t step) const + { + return saturate_cast(((const T*)((const char*)data + idx_row(y) * step))[idx_col(x)]); + } + + template __device__ __forceinline__ D at(typename Ptr2D::index_type y, typename Ptr2D::index_type x, const Ptr2D& src) const + { + return saturate_cast(src(idx_row(y), idx_col(x))); + } + + int last_row; + int last_col; + }; + + ////////////////////////////////////////////////////////////// + // BrdReflect + + template struct BrdRowReflect + { + typedef D result_type; + + explicit __host__ __device__ __forceinline__ BrdRowReflect(int width) : last_col(width - 1) {} + template __host__ __device__ __forceinline__ BrdRowReflect(int width, U) : last_col(width - 1) {} + + __device__ __forceinline__ int idx_col_low(int x) const + { + return (::abs(x) - (x < 0)) % (last_col + 1); + } + + __device__ __forceinline__ int idx_col_high(int x) const + { + return ::abs(last_col - ::abs(last_col - x) + (x > last_col)) % (last_col + 1); + } + + __device__ __forceinline__ int idx_col(int x) const + { + return idx_col_high(::abs(x) - (x < 0)); + } + + template __device__ __forceinline__ D at_low(int x, const T* data) const + { + return saturate_cast(data[idx_col_low(x)]); + } + + template __device__ __forceinline__ D at_high(int x, const T* data) const + { + return saturate_cast(data[idx_col_high(x)]); + } + + template __device__ __forceinline__ D at(int x, const T* data) const + { + return saturate_cast(data[idx_col(x)]); + } + + int last_col; + }; + + template struct BrdColReflect + { + typedef D result_type; + + explicit __host__ __device__ __forceinline__ BrdColReflect(int height) : last_row(height - 1) {} + template __host__ __device__ __forceinline__ BrdColReflect(int height, U) : last_row(height - 1) {} + + __device__ __forceinline__ int idx_row_low(int y) const + { + return (::abs(y) - (y < 0)) % (last_row + 1); + } + + __device__ __forceinline__ int idx_row_high(int y) const + { + return ::abs(last_row - ::abs(last_row - y) + (y > last_row)) % (last_row + 1); + } + + __device__ __forceinline__ int idx_row(int y) const + { + return idx_row_high(::abs(y) - (y < 0)); + } + + template __device__ __forceinline__ D at_low(int y, const T* data, size_t step) const + { + return saturate_cast(*(const D*)((const char*)data + idx_row_low(y) * step)); + } + + template __device__ __forceinline__ D at_high(int y, const T* data, size_t step) const + { + return saturate_cast(*(const D*)((const char*)data + idx_row_high(y) * step)); + } + + template __device__ __forceinline__ D at(int y, const T* data, size_t step) const + { + return saturate_cast(*(const D*)((const char*)data + idx_row(y) * step)); + } + + int last_row; + }; + + template struct BrdReflect + { + typedef D result_type; + + __host__ __device__ __forceinline__ BrdReflect(int height, int width) : last_row(height - 1), last_col(width - 1) {} + template __host__ __device__ __forceinline__ BrdReflect(int height, int width, U) : last_row(height - 1), last_col(width - 1) {} + + __device__ __forceinline__ int idx_row_low(int y) const + { + return (::abs(y) - (y < 0)) % (last_row + 1); + } + + __device__ __forceinline__ int idx_row_high(int y) const + { + return /*::abs*/(last_row - ::abs(last_row - y) + (y > last_row)) /*% (last_row + 1)*/; + } + + __device__ __forceinline__ int idx_row(int y) const + { + return idx_row_low(idx_row_high(y)); + } + + __device__ __forceinline__ int idx_col_low(int x) const + { + return (::abs(x) - (x < 0)) % (last_col + 1); + } + + __device__ __forceinline__ int idx_col_high(int x) const + { + return (last_col - ::abs(last_col - x) + (x > last_col)); + } + + __device__ __forceinline__ int idx_col(int x) const + { + return idx_col_low(idx_col_high(x)); + } + + template __device__ __forceinline__ D at(int y, int x, const T* data, size_t step) const + { + return saturate_cast(((const T*)((const char*)data + idx_row(y) * step))[idx_col(x)]); + } + + template __device__ __forceinline__ D at(typename Ptr2D::index_type y, typename Ptr2D::index_type x, const Ptr2D& src) const + { + return saturate_cast(src(idx_row(y), idx_col(x))); + } + + int last_row; + int last_col; + }; + + ////////////////////////////////////////////////////////////// + // BrdWrap + + template struct BrdRowWrap + { + typedef D result_type; + + explicit __host__ __device__ __forceinline__ BrdRowWrap(int width_) : width(width_) {} + template __host__ __device__ __forceinline__ BrdRowWrap(int width_, U) : width(width_) {} + + __device__ __forceinline__ int idx_col_low(int x) const + { + return (x >= 0) * x + (x < 0) * (x - ((x - width + 1) / width) * width); + } + + __device__ __forceinline__ int idx_col_high(int x) const + { + return (x < width) * x + (x >= width) * (x % width); + } + + __device__ __forceinline__ int idx_col(int x) const + { + return idx_col_high(idx_col_low(x)); + } + + template __device__ __forceinline__ D at_low(int x, const T* data) const + { + return saturate_cast(data[idx_col_low(x)]); + } + + template __device__ __forceinline__ D at_high(int x, const T* data) const + { + return saturate_cast(data[idx_col_high(x)]); + } + + template __device__ __forceinline__ D at(int x, const T* data) const + { + return saturate_cast(data[idx_col(x)]); + } + + int width; + }; + + template struct BrdColWrap + { + typedef D result_type; + + explicit __host__ __device__ __forceinline__ BrdColWrap(int height_) : height(height_) {} + template __host__ __device__ __forceinline__ BrdColWrap(int height_, U) : height(height_) {} + + __device__ __forceinline__ int idx_row_low(int y) const + { + return (y >= 0) * y + (y < 0) * (y - ((y - height + 1) / height) * height); + } + + __device__ __forceinline__ int idx_row_high(int y) const + { + return (y < height) * y + (y >= height) * (y % height); + } + + __device__ __forceinline__ int idx_row(int y) const + { + return idx_row_high(idx_row_low(y)); + } + + template __device__ __forceinline__ D at_low(int y, const T* data, size_t step) const + { + return saturate_cast(*(const D*)((const char*)data + idx_row_low(y) * step)); + } + + template __device__ __forceinline__ D at_high(int y, const T* data, size_t step) const + { + return saturate_cast(*(const D*)((const char*)data + idx_row_high(y) * step)); + } + + template __device__ __forceinline__ D at(int y, const T* data, size_t step) const + { + return saturate_cast(*(const D*)((const char*)data + idx_row(y) * step)); + } + + int height; + }; + + template struct BrdWrap + { + typedef D result_type; + + __host__ __device__ __forceinline__ BrdWrap(int height_, int width_) : + height(height_), width(width_) + { + } + template + __host__ __device__ __forceinline__ BrdWrap(int height_, int width_, U) : + height(height_), width(width_) + { + } + + __device__ __forceinline__ int idx_row_low(int y) const + { + return (y >= 0) ? y : (y - ((y - height + 1) / height) * height); + } + + __device__ __forceinline__ int idx_row_high(int y) const + { + return (y < height) ? y : (y % height); + } + + __device__ __forceinline__ int idx_row(int y) const + { + return idx_row_high(idx_row_low(y)); + } + + __device__ __forceinline__ int idx_col_low(int x) const + { + return (x >= 0) ? x : (x - ((x - width + 1) / width) * width); + } + + __device__ __forceinline__ int idx_col_high(int x) const + { + return (x < width) ? x : (x % width); + } + + __device__ __forceinline__ int idx_col(int x) const + { + return idx_col_high(idx_col_low(x)); + } + + template __device__ __forceinline__ D at(int y, int x, const T* data, size_t step) const + { + return saturate_cast(((const T*)((const char*)data + idx_row(y) * step))[idx_col(x)]); + } + + template __device__ __forceinline__ D at(typename Ptr2D::index_type y, typename Ptr2D::index_type x, const Ptr2D& src) const + { + return saturate_cast(src(idx_row(y), idx_col(x))); + } + + int height; + int width; + }; + + ////////////////////////////////////////////////////////////// + // BorderReader + + template struct BorderReader + { + typedef typename B::result_type elem_type; + typedef typename Ptr2D::index_type index_type; + + __host__ __device__ __forceinline__ BorderReader(const Ptr2D& ptr_, const B& b_) : ptr(ptr_), b(b_) {} + + __device__ __forceinline__ elem_type operator ()(index_type y, index_type x) const + { + return b.at(y, x, ptr); + } + + Ptr2D ptr; + B b; + }; + + // under win32 there is some bug with templated types that passed as kernel parameters + // with this specialization all works fine + template struct BorderReader< Ptr2D, BrdConstant > + { + typedef typename BrdConstant::result_type elem_type; + typedef typename Ptr2D::index_type index_type; + + __host__ __device__ __forceinline__ BorderReader(const Ptr2D& src_, const BrdConstant& b) : + src(src_), height(b.height), width(b.width), val(b.val) + { + } + + __device__ __forceinline__ D operator ()(index_type y, index_type x) const + { + return (x >= 0 && x < width && y >= 0 && y < height) ? saturate_cast(src(y, x)) : val; + } + + Ptr2D src; + int height; + int width; + D val; + }; +}}} // namespace cv { namespace cuda { namespace cudev + +//! @endcond + +#endif // OPENCV_CUDA_BORDER_INTERPOLATE_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/color.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/color.hpp new file mode 100644 index 0000000..dcce280 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/color.hpp @@ -0,0 +1,309 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_COLOR_HPP +#define OPENCV_CUDA_COLOR_HPP + +#include "detail/color_detail.hpp" + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + // All OPENCV_CUDA_IMPLEMENT_*_TRAITS(ColorSpace1_to_ColorSpace2, ...) macros implements + // template class ColorSpace1_to_ColorSpace2_traits + // { + // typedef ... functor_type; + // static __host__ __device__ functor_type create_functor(); + // }; + + OPENCV_CUDA_IMPLEMENT_RGB2RGB_TRAITS(bgr_to_rgb, 3, 3, 2) + OPENCV_CUDA_IMPLEMENT_RGB2RGB_TRAITS(bgr_to_bgra, 3, 4, 0) + OPENCV_CUDA_IMPLEMENT_RGB2RGB_TRAITS(bgr_to_rgba, 3, 4, 2) + OPENCV_CUDA_IMPLEMENT_RGB2RGB_TRAITS(bgra_to_bgr, 4, 3, 0) + OPENCV_CUDA_IMPLEMENT_RGB2RGB_TRAITS(bgra_to_rgb, 4, 3, 2) + OPENCV_CUDA_IMPLEMENT_RGB2RGB_TRAITS(bgra_to_rgba, 4, 4, 2) + + #undef OPENCV_CUDA_IMPLEMENT_RGB2RGB_TRAITS + + OPENCV_CUDA_IMPLEMENT_RGB2RGB5x5_TRAITS(bgr_to_bgr555, 3, 0, 5) + OPENCV_CUDA_IMPLEMENT_RGB2RGB5x5_TRAITS(bgr_to_bgr565, 3, 0, 6) + OPENCV_CUDA_IMPLEMENT_RGB2RGB5x5_TRAITS(rgb_to_bgr555, 3, 2, 5) + OPENCV_CUDA_IMPLEMENT_RGB2RGB5x5_TRAITS(rgb_to_bgr565, 3, 2, 6) + OPENCV_CUDA_IMPLEMENT_RGB2RGB5x5_TRAITS(bgra_to_bgr555, 4, 0, 5) + OPENCV_CUDA_IMPLEMENT_RGB2RGB5x5_TRAITS(bgra_to_bgr565, 4, 0, 6) + OPENCV_CUDA_IMPLEMENT_RGB2RGB5x5_TRAITS(rgba_to_bgr555, 4, 2, 5) + OPENCV_CUDA_IMPLEMENT_RGB2RGB5x5_TRAITS(rgba_to_bgr565, 4, 2, 6) + + #undef OPENCV_CUDA_IMPLEMENT_RGB2RGB5x5_TRAITS + + OPENCV_CUDA_IMPLEMENT_RGB5x52RGB_TRAITS(bgr555_to_rgb, 3, 2, 5) + OPENCV_CUDA_IMPLEMENT_RGB5x52RGB_TRAITS(bgr565_to_rgb, 3, 2, 6) + OPENCV_CUDA_IMPLEMENT_RGB5x52RGB_TRAITS(bgr555_to_bgr, 3, 0, 5) + OPENCV_CUDA_IMPLEMENT_RGB5x52RGB_TRAITS(bgr565_to_bgr, 3, 0, 6) + OPENCV_CUDA_IMPLEMENT_RGB5x52RGB_TRAITS(bgr555_to_rgba, 4, 2, 5) + OPENCV_CUDA_IMPLEMENT_RGB5x52RGB_TRAITS(bgr565_to_rgba, 4, 2, 6) + OPENCV_CUDA_IMPLEMENT_RGB5x52RGB_TRAITS(bgr555_to_bgra, 4, 0, 5) + OPENCV_CUDA_IMPLEMENT_RGB5x52RGB_TRAITS(bgr565_to_bgra, 4, 0, 6) + + #undef OPENCV_CUDA_IMPLEMENT_RGB5x52RGB_TRAITS + + OPENCV_CUDA_IMPLEMENT_GRAY2RGB_TRAITS(gray_to_bgr, 3) + OPENCV_CUDA_IMPLEMENT_GRAY2RGB_TRAITS(gray_to_bgra, 4) + + #undef OPENCV_CUDA_IMPLEMENT_GRAY2RGB_TRAITS + + OPENCV_CUDA_IMPLEMENT_GRAY2RGB5x5_TRAITS(gray_to_bgr555, 5) + OPENCV_CUDA_IMPLEMENT_GRAY2RGB5x5_TRAITS(gray_to_bgr565, 6) + + #undef OPENCV_CUDA_IMPLEMENT_GRAY2RGB5x5_TRAITS + + OPENCV_CUDA_IMPLEMENT_RGB5x52GRAY_TRAITS(bgr555_to_gray, 5) + OPENCV_CUDA_IMPLEMENT_RGB5x52GRAY_TRAITS(bgr565_to_gray, 6) + + #undef OPENCV_CUDA_IMPLEMENT_RGB5x52GRAY_TRAITS + + OPENCV_CUDA_IMPLEMENT_RGB2GRAY_TRAITS(rgb_to_gray, 3, 2) + OPENCV_CUDA_IMPLEMENT_RGB2GRAY_TRAITS(bgr_to_gray, 3, 0) + OPENCV_CUDA_IMPLEMENT_RGB2GRAY_TRAITS(rgba_to_gray, 4, 2) + OPENCV_CUDA_IMPLEMENT_RGB2GRAY_TRAITS(bgra_to_gray, 4, 0) + + #undef OPENCV_CUDA_IMPLEMENT_RGB2GRAY_TRAITS + + OPENCV_CUDA_IMPLEMENT_RGB2YUV_TRAITS(rgb_to_yuv, 3, 3, 2) + OPENCV_CUDA_IMPLEMENT_RGB2YUV_TRAITS(rgba_to_yuv, 4, 3, 2) + OPENCV_CUDA_IMPLEMENT_RGB2YUV_TRAITS(rgb_to_yuv4, 3, 4, 2) + OPENCV_CUDA_IMPLEMENT_RGB2YUV_TRAITS(rgba_to_yuv4, 4, 4, 2) + OPENCV_CUDA_IMPLEMENT_RGB2YUV_TRAITS(bgr_to_yuv, 3, 3, 0) + OPENCV_CUDA_IMPLEMENT_RGB2YUV_TRAITS(bgra_to_yuv, 4, 3, 0) + OPENCV_CUDA_IMPLEMENT_RGB2YUV_TRAITS(bgr_to_yuv4, 3, 4, 0) + OPENCV_CUDA_IMPLEMENT_RGB2YUV_TRAITS(bgra_to_yuv4, 4, 4, 0) + + #undef OPENCV_CUDA_IMPLEMENT_RGB2YUV_TRAITS + + OPENCV_CUDA_IMPLEMENT_YUV2RGB_TRAITS(yuv_to_rgb, 3, 3, 2) + OPENCV_CUDA_IMPLEMENT_YUV2RGB_TRAITS(yuv_to_rgba, 3, 4, 2) + OPENCV_CUDA_IMPLEMENT_YUV2RGB_TRAITS(yuv4_to_rgb, 4, 3, 2) + OPENCV_CUDA_IMPLEMENT_YUV2RGB_TRAITS(yuv4_to_rgba, 4, 4, 2) + OPENCV_CUDA_IMPLEMENT_YUV2RGB_TRAITS(yuv_to_bgr, 3, 3, 0) + OPENCV_CUDA_IMPLEMENT_YUV2RGB_TRAITS(yuv_to_bgra, 3, 4, 0) + OPENCV_CUDA_IMPLEMENT_YUV2RGB_TRAITS(yuv4_to_bgr, 4, 3, 0) + OPENCV_CUDA_IMPLEMENT_YUV2RGB_TRAITS(yuv4_to_bgra, 4, 4, 0) + + #undef OPENCV_CUDA_IMPLEMENT_YUV2RGB_TRAITS + + OPENCV_CUDA_IMPLEMENT_RGB2YCrCb_TRAITS(rgb_to_YCrCb, 3, 3, 2) + OPENCV_CUDA_IMPLEMENT_RGB2YCrCb_TRAITS(rgba_to_YCrCb, 4, 3, 2) + OPENCV_CUDA_IMPLEMENT_RGB2YCrCb_TRAITS(rgb_to_YCrCb4, 3, 4, 2) + OPENCV_CUDA_IMPLEMENT_RGB2YCrCb_TRAITS(rgba_to_YCrCb4, 4, 4, 2) + OPENCV_CUDA_IMPLEMENT_RGB2YCrCb_TRAITS(bgr_to_YCrCb, 3, 3, 0) + OPENCV_CUDA_IMPLEMENT_RGB2YCrCb_TRAITS(bgra_to_YCrCb, 4, 3, 0) + OPENCV_CUDA_IMPLEMENT_RGB2YCrCb_TRAITS(bgr_to_YCrCb4, 3, 4, 0) + OPENCV_CUDA_IMPLEMENT_RGB2YCrCb_TRAITS(bgra_to_YCrCb4, 4, 4, 0) + + #undef OPENCV_CUDA_IMPLEMENT_RGB2YCrCb_TRAITS + + OPENCV_CUDA_IMPLEMENT_YCrCb2RGB_TRAITS(YCrCb_to_rgb, 3, 3, 2) + OPENCV_CUDA_IMPLEMENT_YCrCb2RGB_TRAITS(YCrCb_to_rgba, 3, 4, 2) + OPENCV_CUDA_IMPLEMENT_YCrCb2RGB_TRAITS(YCrCb4_to_rgb, 4, 3, 2) + OPENCV_CUDA_IMPLEMENT_YCrCb2RGB_TRAITS(YCrCb4_to_rgba, 4, 4, 2) + OPENCV_CUDA_IMPLEMENT_YCrCb2RGB_TRAITS(YCrCb_to_bgr, 3, 3, 0) + OPENCV_CUDA_IMPLEMENT_YCrCb2RGB_TRAITS(YCrCb_to_bgra, 3, 4, 0) + OPENCV_CUDA_IMPLEMENT_YCrCb2RGB_TRAITS(YCrCb4_to_bgr, 4, 3, 0) + OPENCV_CUDA_IMPLEMENT_YCrCb2RGB_TRAITS(YCrCb4_to_bgra, 4, 4, 0) + + #undef OPENCV_CUDA_IMPLEMENT_YCrCb2RGB_TRAITS + + OPENCV_CUDA_IMPLEMENT_RGB2XYZ_TRAITS(rgb_to_xyz, 3, 3, 2) + OPENCV_CUDA_IMPLEMENT_RGB2XYZ_TRAITS(rgba_to_xyz, 4, 3, 2) + OPENCV_CUDA_IMPLEMENT_RGB2XYZ_TRAITS(rgb_to_xyz4, 3, 4, 2) + OPENCV_CUDA_IMPLEMENT_RGB2XYZ_TRAITS(rgba_to_xyz4, 4, 4, 2) + OPENCV_CUDA_IMPLEMENT_RGB2XYZ_TRAITS(bgr_to_xyz, 3, 3, 0) + OPENCV_CUDA_IMPLEMENT_RGB2XYZ_TRAITS(bgra_to_xyz, 4, 3, 0) + OPENCV_CUDA_IMPLEMENT_RGB2XYZ_TRAITS(bgr_to_xyz4, 3, 4, 0) + OPENCV_CUDA_IMPLEMENT_RGB2XYZ_TRAITS(bgra_to_xyz4, 4, 4, 0) + + #undef OPENCV_CUDA_IMPLEMENT_RGB2XYZ_TRAITS + + OPENCV_CUDA_IMPLEMENT_XYZ2RGB_TRAITS(xyz_to_rgb, 3, 3, 2) + OPENCV_CUDA_IMPLEMENT_XYZ2RGB_TRAITS(xyz4_to_rgb, 4, 3, 2) + OPENCV_CUDA_IMPLEMENT_XYZ2RGB_TRAITS(xyz_to_rgba, 3, 4, 2) + OPENCV_CUDA_IMPLEMENT_XYZ2RGB_TRAITS(xyz4_to_rgba, 4, 4, 2) + OPENCV_CUDA_IMPLEMENT_XYZ2RGB_TRAITS(xyz_to_bgr, 3, 3, 0) + OPENCV_CUDA_IMPLEMENT_XYZ2RGB_TRAITS(xyz4_to_bgr, 4, 3, 0) + OPENCV_CUDA_IMPLEMENT_XYZ2RGB_TRAITS(xyz_to_bgra, 3, 4, 0) + OPENCV_CUDA_IMPLEMENT_XYZ2RGB_TRAITS(xyz4_to_bgra, 4, 4, 0) + + #undef OPENCV_CUDA_IMPLEMENT_XYZ2RGB_TRAITS + + OPENCV_CUDA_IMPLEMENT_RGB2HSV_TRAITS(rgb_to_hsv, 3, 3, 2) + OPENCV_CUDA_IMPLEMENT_RGB2HSV_TRAITS(rgba_to_hsv, 4, 3, 2) + OPENCV_CUDA_IMPLEMENT_RGB2HSV_TRAITS(rgb_to_hsv4, 3, 4, 2) + OPENCV_CUDA_IMPLEMENT_RGB2HSV_TRAITS(rgba_to_hsv4, 4, 4, 2) + OPENCV_CUDA_IMPLEMENT_RGB2HSV_TRAITS(bgr_to_hsv, 3, 3, 0) + OPENCV_CUDA_IMPLEMENT_RGB2HSV_TRAITS(bgra_to_hsv, 4, 3, 0) + OPENCV_CUDA_IMPLEMENT_RGB2HSV_TRAITS(bgr_to_hsv4, 3, 4, 0) + OPENCV_CUDA_IMPLEMENT_RGB2HSV_TRAITS(bgra_to_hsv4, 4, 4, 0) + + #undef OPENCV_CUDA_IMPLEMENT_RGB2HSV_TRAITS + + OPENCV_CUDA_IMPLEMENT_HSV2RGB_TRAITS(hsv_to_rgb, 3, 3, 2) + OPENCV_CUDA_IMPLEMENT_HSV2RGB_TRAITS(hsv_to_rgba, 3, 4, 2) + OPENCV_CUDA_IMPLEMENT_HSV2RGB_TRAITS(hsv4_to_rgb, 4, 3, 2) + OPENCV_CUDA_IMPLEMENT_HSV2RGB_TRAITS(hsv4_to_rgba, 4, 4, 2) + OPENCV_CUDA_IMPLEMENT_HSV2RGB_TRAITS(hsv_to_bgr, 3, 3, 0) + OPENCV_CUDA_IMPLEMENT_HSV2RGB_TRAITS(hsv_to_bgra, 3, 4, 0) + OPENCV_CUDA_IMPLEMENT_HSV2RGB_TRAITS(hsv4_to_bgr, 4, 3, 0) + OPENCV_CUDA_IMPLEMENT_HSV2RGB_TRAITS(hsv4_to_bgra, 4, 4, 0) + + #undef OPENCV_CUDA_IMPLEMENT_HSV2RGB_TRAITS + + OPENCV_CUDA_IMPLEMENT_RGB2HLS_TRAITS(rgb_to_hls, 3, 3, 2) + OPENCV_CUDA_IMPLEMENT_RGB2HLS_TRAITS(rgba_to_hls, 4, 3, 2) + OPENCV_CUDA_IMPLEMENT_RGB2HLS_TRAITS(rgb_to_hls4, 3, 4, 2) + OPENCV_CUDA_IMPLEMENT_RGB2HLS_TRAITS(rgba_to_hls4, 4, 4, 2) + OPENCV_CUDA_IMPLEMENT_RGB2HLS_TRAITS(bgr_to_hls, 3, 3, 0) + OPENCV_CUDA_IMPLEMENT_RGB2HLS_TRAITS(bgra_to_hls, 4, 3, 0) + OPENCV_CUDA_IMPLEMENT_RGB2HLS_TRAITS(bgr_to_hls4, 3, 4, 0) + OPENCV_CUDA_IMPLEMENT_RGB2HLS_TRAITS(bgra_to_hls4, 4, 4, 0) + + #undef OPENCV_CUDA_IMPLEMENT_RGB2HLS_TRAITS + + OPENCV_CUDA_IMPLEMENT_HLS2RGB_TRAITS(hls_to_rgb, 3, 3, 2) + OPENCV_CUDA_IMPLEMENT_HLS2RGB_TRAITS(hls_to_rgba, 3, 4, 2) + OPENCV_CUDA_IMPLEMENT_HLS2RGB_TRAITS(hls4_to_rgb, 4, 3, 2) + OPENCV_CUDA_IMPLEMENT_HLS2RGB_TRAITS(hls4_to_rgba, 4, 4, 2) + OPENCV_CUDA_IMPLEMENT_HLS2RGB_TRAITS(hls_to_bgr, 3, 3, 0) + OPENCV_CUDA_IMPLEMENT_HLS2RGB_TRAITS(hls_to_bgra, 3, 4, 0) + OPENCV_CUDA_IMPLEMENT_HLS2RGB_TRAITS(hls4_to_bgr, 4, 3, 0) + OPENCV_CUDA_IMPLEMENT_HLS2RGB_TRAITS(hls4_to_bgra, 4, 4, 0) + + #undef OPENCV_CUDA_IMPLEMENT_HLS2RGB_TRAITS + + OPENCV_CUDA_IMPLEMENT_RGB2Lab_TRAITS(rgb_to_lab, 3, 3, true, 2) + OPENCV_CUDA_IMPLEMENT_RGB2Lab_TRAITS(rgba_to_lab, 4, 3, true, 2) + OPENCV_CUDA_IMPLEMENT_RGB2Lab_TRAITS(rgb_to_lab4, 3, 4, true, 2) + OPENCV_CUDA_IMPLEMENT_RGB2Lab_TRAITS(rgba_to_lab4, 4, 4, true, 2) + OPENCV_CUDA_IMPLEMENT_RGB2Lab_TRAITS(bgr_to_lab, 3, 3, true, 0) + OPENCV_CUDA_IMPLEMENT_RGB2Lab_TRAITS(bgra_to_lab, 4, 3, true, 0) + OPENCV_CUDA_IMPLEMENT_RGB2Lab_TRAITS(bgr_to_lab4, 3, 4, true, 0) + OPENCV_CUDA_IMPLEMENT_RGB2Lab_TRAITS(bgra_to_lab4, 4, 4, true, 0) + + OPENCV_CUDA_IMPLEMENT_RGB2Lab_TRAITS(lrgb_to_lab, 3, 3, false, 2) + OPENCV_CUDA_IMPLEMENT_RGB2Lab_TRAITS(lrgba_to_lab, 4, 3, false, 2) + OPENCV_CUDA_IMPLEMENT_RGB2Lab_TRAITS(lrgb_to_lab4, 3, 4, false, 2) + OPENCV_CUDA_IMPLEMENT_RGB2Lab_TRAITS(lrgba_to_lab4, 4, 4, false, 2) + OPENCV_CUDA_IMPLEMENT_RGB2Lab_TRAITS(lbgr_to_lab, 3, 3, false, 0) + OPENCV_CUDA_IMPLEMENT_RGB2Lab_TRAITS(lbgra_to_lab, 4, 3, false, 0) + OPENCV_CUDA_IMPLEMENT_RGB2Lab_TRAITS(lbgr_to_lab4, 3, 4, false, 0) + OPENCV_CUDA_IMPLEMENT_RGB2Lab_TRAITS(lbgra_to_lab4, 4, 4, false, 0) + + #undef OPENCV_CUDA_IMPLEMENT_RGB2Lab_TRAITS + + OPENCV_CUDA_IMPLEMENT_Lab2RGB_TRAITS(lab_to_rgb, 3, 3, true, 2) + OPENCV_CUDA_IMPLEMENT_Lab2RGB_TRAITS(lab4_to_rgb, 4, 3, true, 2) + OPENCV_CUDA_IMPLEMENT_Lab2RGB_TRAITS(lab_to_rgba, 3, 4, true, 2) + OPENCV_CUDA_IMPLEMENT_Lab2RGB_TRAITS(lab4_to_rgba, 4, 4, true, 2) + OPENCV_CUDA_IMPLEMENT_Lab2RGB_TRAITS(lab_to_bgr, 3, 3, true, 0) + OPENCV_CUDA_IMPLEMENT_Lab2RGB_TRAITS(lab4_to_bgr, 4, 3, true, 0) + OPENCV_CUDA_IMPLEMENT_Lab2RGB_TRAITS(lab_to_bgra, 3, 4, true, 0) + OPENCV_CUDA_IMPLEMENT_Lab2RGB_TRAITS(lab4_to_bgra, 4, 4, true, 0) + + OPENCV_CUDA_IMPLEMENT_Lab2RGB_TRAITS(lab_to_lrgb, 3, 3, false, 2) + OPENCV_CUDA_IMPLEMENT_Lab2RGB_TRAITS(lab4_to_lrgb, 4, 3, false, 2) + OPENCV_CUDA_IMPLEMENT_Lab2RGB_TRAITS(lab_to_lrgba, 3, 4, false, 2) + OPENCV_CUDA_IMPLEMENT_Lab2RGB_TRAITS(lab4_to_lrgba, 4, 4, false, 2) + OPENCV_CUDA_IMPLEMENT_Lab2RGB_TRAITS(lab_to_lbgr, 3, 3, false, 0) + OPENCV_CUDA_IMPLEMENT_Lab2RGB_TRAITS(lab4_to_lbgr, 4, 3, false, 0) + OPENCV_CUDA_IMPLEMENT_Lab2RGB_TRAITS(lab_to_lbgra, 3, 4, false, 0) + OPENCV_CUDA_IMPLEMENT_Lab2RGB_TRAITS(lab4_to_lbgra, 4, 4, false, 0) + + #undef OPENCV_CUDA_IMPLEMENT_Lab2RGB_TRAITS + + OPENCV_CUDA_IMPLEMENT_RGB2Luv_TRAITS(rgb_to_luv, 3, 3, true, 2) + OPENCV_CUDA_IMPLEMENT_RGB2Luv_TRAITS(rgba_to_luv, 4, 3, true, 2) + OPENCV_CUDA_IMPLEMENT_RGB2Luv_TRAITS(rgb_to_luv4, 3, 4, true, 2) + OPENCV_CUDA_IMPLEMENT_RGB2Luv_TRAITS(rgba_to_luv4, 4, 4, true, 2) + OPENCV_CUDA_IMPLEMENT_RGB2Luv_TRAITS(bgr_to_luv, 3, 3, true, 0) + OPENCV_CUDA_IMPLEMENT_RGB2Luv_TRAITS(bgra_to_luv, 4, 3, true, 0) + OPENCV_CUDA_IMPLEMENT_RGB2Luv_TRAITS(bgr_to_luv4, 3, 4, true, 0) + OPENCV_CUDA_IMPLEMENT_RGB2Luv_TRAITS(bgra_to_luv4, 4, 4, true, 0) + + OPENCV_CUDA_IMPLEMENT_RGB2Luv_TRAITS(lrgb_to_luv, 3, 3, false, 2) + OPENCV_CUDA_IMPLEMENT_RGB2Luv_TRAITS(lrgba_to_luv, 4, 3, false, 2) + OPENCV_CUDA_IMPLEMENT_RGB2Luv_TRAITS(lrgb_to_luv4, 3, 4, false, 2) + OPENCV_CUDA_IMPLEMENT_RGB2Luv_TRAITS(lrgba_to_luv4, 4, 4, false, 2) + OPENCV_CUDA_IMPLEMENT_RGB2Luv_TRAITS(lbgr_to_luv, 3, 3, false, 0) + OPENCV_CUDA_IMPLEMENT_RGB2Luv_TRAITS(lbgra_to_luv, 4, 3, false, 0) + OPENCV_CUDA_IMPLEMENT_RGB2Luv_TRAITS(lbgr_to_luv4, 3, 4, false, 0) + OPENCV_CUDA_IMPLEMENT_RGB2Luv_TRAITS(lbgra_to_luv4, 4, 4, false, 0) + + #undef OPENCV_CUDA_IMPLEMENT_RGB2Luv_TRAITS + + OPENCV_CUDA_IMPLEMENT_Luv2RGB_TRAITS(luv_to_rgb, 3, 3, true, 2) + OPENCV_CUDA_IMPLEMENT_Luv2RGB_TRAITS(luv4_to_rgb, 4, 3, true, 2) + OPENCV_CUDA_IMPLEMENT_Luv2RGB_TRAITS(luv_to_rgba, 3, 4, true, 2) + OPENCV_CUDA_IMPLEMENT_Luv2RGB_TRAITS(luv4_to_rgba, 4, 4, true, 2) + OPENCV_CUDA_IMPLEMENT_Luv2RGB_TRAITS(luv_to_bgr, 3, 3, true, 0) + OPENCV_CUDA_IMPLEMENT_Luv2RGB_TRAITS(luv4_to_bgr, 4, 3, true, 0) + OPENCV_CUDA_IMPLEMENT_Luv2RGB_TRAITS(luv_to_bgra, 3, 4, true, 0) + OPENCV_CUDA_IMPLEMENT_Luv2RGB_TRAITS(luv4_to_bgra, 4, 4, true, 0) + + OPENCV_CUDA_IMPLEMENT_Luv2RGB_TRAITS(luv_to_lrgb, 3, 3, false, 2) + OPENCV_CUDA_IMPLEMENT_Luv2RGB_TRAITS(luv4_to_lrgb, 4, 3, false, 2) + OPENCV_CUDA_IMPLEMENT_Luv2RGB_TRAITS(luv_to_lrgba, 3, 4, false, 2) + OPENCV_CUDA_IMPLEMENT_Luv2RGB_TRAITS(luv4_to_lrgba, 4, 4, false, 2) + OPENCV_CUDA_IMPLEMENT_Luv2RGB_TRAITS(luv_to_lbgr, 3, 3, false, 0) + OPENCV_CUDA_IMPLEMENT_Luv2RGB_TRAITS(luv4_to_lbgr, 4, 3, false, 0) + OPENCV_CUDA_IMPLEMENT_Luv2RGB_TRAITS(luv_to_lbgra, 3, 4, false, 0) + OPENCV_CUDA_IMPLEMENT_Luv2RGB_TRAITS(luv4_to_lbgra, 4, 4, false, 0) + + #undef OPENCV_CUDA_IMPLEMENT_Luv2RGB_TRAITS +}}} // namespace cv { namespace cuda { namespace cudev + +//! @endcond + +#endif // OPENCV_CUDA_COLOR_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/common.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/common.hpp new file mode 100644 index 0000000..80b2ff0 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/common.hpp @@ -0,0 +1,123 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_COMMON_HPP +#define OPENCV_CUDA_COMMON_HPP + +#include +#include "opencv2/core/cuda_types.hpp" +#include "opencv2/core/cvdef.h" +#include "opencv2/core/base.hpp" + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +#ifndef CV_PI_F + #ifndef CV_PI + #define CV_PI_F 3.14159265f + #else + #define CV_PI_F ((float)CV_PI) + #endif +#endif + +namespace cv { namespace cuda { + static inline void checkCudaError(cudaError_t err, const char* file, const int line, const char* func) + { + if (cudaSuccess != err) + cv::error(cv::Error::GpuApiCallError, cudaGetErrorString(err), func, file, line); + } +}} + +#ifndef cudaSafeCall + #define cudaSafeCall(expr) cv::cuda::checkCudaError(expr, __FILE__, __LINE__, CV_Func) +#endif + +namespace cv { namespace cuda +{ + template static inline bool isAligned(const T* ptr, size_t size) + { + return reinterpret_cast(ptr) % size == 0; + } + + static inline bool isAligned(size_t step, size_t size) + { + return step % size == 0; + } +}} + +namespace cv { namespace cuda +{ + namespace device + { + __host__ __device__ __forceinline__ int divUp(int total, int grain) + { + return (total + grain - 1) / grain; + } + + template inline void bindTexture(const textureReference* tex, const PtrStepSz& img) + { + cudaChannelFormatDesc desc = cudaCreateChannelDesc(); + cudaSafeCall( cudaBindTexture2D(0, tex, img.ptr(), &desc, img.cols, img.rows, img.step) ); + } + + template inline void createTextureObjectPitch2D(cudaTextureObject_t* tex, PtrStepSz& img, const cudaTextureDesc& texDesc) + { + cudaResourceDesc resDesc; + memset(&resDesc, 0, sizeof(resDesc)); + resDesc.resType = cudaResourceTypePitch2D; + resDesc.res.pitch2D.devPtr = static_cast(img.ptr()); + resDesc.res.pitch2D.height = img.rows; + resDesc.res.pitch2D.width = img.cols; + resDesc.res.pitch2D.pitchInBytes = img.step; + resDesc.res.pitch2D.desc = cudaCreateChannelDesc(); + + cudaSafeCall( cudaCreateTextureObject(tex, &resDesc, &texDesc, NULL) ); + } + } +}} + +//! @endcond + +#endif // OPENCV_CUDA_COMMON_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/datamov_utils.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/datamov_utils.hpp new file mode 100644 index 0000000..6820d0f --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/datamov_utils.hpp @@ -0,0 +1,113 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_DATAMOV_UTILS_HPP +#define OPENCV_CUDA_DATAMOV_UTILS_HPP + +#include "common.hpp" + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 200 + + // for Fermi memory space is detected automatically + template struct ForceGlob + { + __device__ __forceinline__ static void Load(const T* ptr, int offset, T& val) { val = ptr[offset]; } + }; + + #else // __CUDA_ARCH__ >= 200 + + #if defined(_WIN64) || defined(__LP64__) + // 64-bit register modifier for inlined asm + #define OPENCV_CUDA_ASM_PTR "l" + #else + // 32-bit register modifier for inlined asm + #define OPENCV_CUDA_ASM_PTR "r" + #endif + + template struct ForceGlob; + + #define OPENCV_CUDA_DEFINE_FORCE_GLOB(base_type, ptx_type, reg_mod) \ + template <> struct ForceGlob \ + { \ + __device__ __forceinline__ static void Load(const base_type* ptr, int offset, base_type& val) \ + { \ + asm("ld.global."#ptx_type" %0, [%1];" : "="#reg_mod(val) : OPENCV_CUDA_ASM_PTR(ptr + offset)); \ + } \ + }; + + #define OPENCV_CUDA_DEFINE_FORCE_GLOB_B(base_type, ptx_type) \ + template <> struct ForceGlob \ + { \ + __device__ __forceinline__ static void Load(const base_type* ptr, int offset, base_type& val) \ + { \ + asm("ld.global."#ptx_type" %0, [%1];" : "=r"(*reinterpret_cast(&val)) : OPENCV_CUDA_ASM_PTR(ptr + offset)); \ + } \ + }; + + OPENCV_CUDA_DEFINE_FORCE_GLOB_B(uchar, u8) + OPENCV_CUDA_DEFINE_FORCE_GLOB_B(schar, s8) + OPENCV_CUDA_DEFINE_FORCE_GLOB_B(char, b8) + OPENCV_CUDA_DEFINE_FORCE_GLOB (ushort, u16, h) + OPENCV_CUDA_DEFINE_FORCE_GLOB (short, s16, h) + OPENCV_CUDA_DEFINE_FORCE_GLOB (uint, u32, r) + OPENCV_CUDA_DEFINE_FORCE_GLOB (int, s32, r) + OPENCV_CUDA_DEFINE_FORCE_GLOB (float, f32, f) + OPENCV_CUDA_DEFINE_FORCE_GLOB (double, f64, d) + + #undef OPENCV_CUDA_DEFINE_FORCE_GLOB + #undef OPENCV_CUDA_DEFINE_FORCE_GLOB_B + #undef OPENCV_CUDA_ASM_PTR + + #endif // __CUDA_ARCH__ >= 200 +}}} // namespace cv { namespace cuda { namespace cudev + +//! @endcond + +#endif // OPENCV_CUDA_DATAMOV_UTILS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/color_detail.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/color_detail.hpp new file mode 100644 index 0000000..f4b4796 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/color_detail.hpp @@ -0,0 +1,2018 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_COLOR_DETAIL_HPP +#define OPENCV_CUDA_COLOR_DETAIL_HPP + +#include "../common.hpp" +#include "../vec_traits.hpp" +#include "../saturate_cast.hpp" +#include "../limits.hpp" +#include "../functional.hpp" + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + #ifndef CV_DESCALE + #define CV_DESCALE(x, n) (((x) + (1 << ((n)-1))) >> (n)) + #endif + + namespace color_detail + { + template struct ColorChannel + { + typedef float worktype_f; + static __device__ __forceinline__ T max() { return numeric_limits::max(); } + static __device__ __forceinline__ T half() { return (T)(max()/2 + 1); } + }; + + template<> struct ColorChannel + { + typedef float worktype_f; + static __device__ __forceinline__ float max() { return 1.f; } + static __device__ __forceinline__ float half() { return 0.5f; } + }; + + template static __device__ __forceinline__ void setAlpha(typename TypeVec::vec_type& vec, T val) + { + } + + template static __device__ __forceinline__ void setAlpha(typename TypeVec::vec_type& vec, T val) + { + vec.w = val; + } + + template static __device__ __forceinline__ T getAlpha(const typename TypeVec::vec_type& vec) + { + return ColorChannel::max(); + } + + template static __device__ __forceinline__ T getAlpha(const typename TypeVec::vec_type& vec) + { + return vec.w; + } + + //constants for conversion from/to RGB and Gray, YUV, YCrCb according to BT.601 + constexpr float B2YF = 0.114f; + constexpr float G2YF = 0.587f; + constexpr float R2YF = 0.299f; + + //to YCbCr + constexpr float YCBF = 0.564f; // == 1/2/(1-B2YF) + constexpr float YCRF = 0.713f; // == 1/2/(1-R2YF) + const int YCBI = 9241; // == YCBF*16384 + const int YCRI = 11682; // == YCRF*16384 + //to YUV + constexpr float B2UF = 0.492f; + constexpr float R2VF = 0.877f; + const int B2UI = 8061; // == B2UF*16384 + const int R2VI = 14369; // == R2VF*16384 + //from YUV + constexpr float U2BF = 2.032f; + constexpr float U2GF = -0.395f; + constexpr float V2GF = -0.581f; + constexpr float V2RF = 1.140f; + const int U2BI = 33292; + const int U2GI = -6472; + const int V2GI = -9519; + const int V2RI = 18678; + //from YCrCb + constexpr float CB2BF = 1.773f; + constexpr float CB2GF = -0.344f; + constexpr float CR2GF = -0.714f; + constexpr float CR2RF = 1.403f; + const int CB2BI = 29049; + const int CB2GI = -5636; + const int CR2GI = -11698; + const int CR2RI = 22987; + + enum + { + yuv_shift = 14, + xyz_shift = 12, + gray_shift = 15, + R2Y = 4899, + G2Y = 9617, + B2Y = 1868, + RY15 = 9798, // == R2YF*32768 + 0.5 + GY15 = 19235, // == G2YF*32768 + 0.5 + BY15 = 3735, // == B2YF*32768 + 0.5 + BLOCK_SIZE = 256 + }; + } + +////////////////// Various 3/4-channel to 3/4-channel RGB transformations ///////////////// + + namespace color_detail + { + template struct RGB2RGB + : unary_function::vec_type, typename TypeVec::vec_type> + { + __device__ typename TypeVec::vec_type operator()(const typename TypeVec::vec_type& src) const + { + typename TypeVec::vec_type dst; + + dst.x = (&src.x)[bidx]; + dst.y = src.y; + dst.z = (&src.x)[bidx^2]; + setAlpha(dst, getAlpha(src)); + + return dst; + } + + __host__ __device__ __forceinline__ RGB2RGB() {} + __host__ __device__ __forceinline__ RGB2RGB(const RGB2RGB&) {} + }; + + template <> struct RGB2RGB : unary_function + { + __device__ uint operator()(uint src) const + { + uint dst = 0; + + dst |= (0xffu & (src >> 16)); + dst |= (0xffu & (src >> 8)) << 8; + dst |= (0xffu & (src)) << 16; + dst |= (0xffu & (src >> 24)) << 24; + + return dst; + } + + __host__ __device__ __forceinline__ RGB2RGB() {} + __host__ __device__ __forceinline__ RGB2RGB(const RGB2RGB&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_RGB2RGB_TRAITS(name, scn, dcn, bidx) \ + template struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::RGB2RGB functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + +/////////// Transforming 16-bit (565 or 555) RGB to/from 24/32-bit (888[8]) RGB ////////// + + namespace color_detail + { + template struct RGB2RGB5x5Converter; + template struct RGB2RGB5x5Converter<6, bidx> + { + static __device__ __forceinline__ ushort cvt(const uchar3& src) + { + return (ushort)(((&src.x)[bidx] >> 3) | ((src.y & ~3) << 3) | (((&src.x)[bidx^2] & ~7) << 8)); + } + + static __device__ __forceinline__ ushort cvt(uint src) + { + uint b = 0xffu & (src >> (bidx * 8)); + uint g = 0xffu & (src >> 8); + uint r = 0xffu & (src >> ((bidx ^ 2) * 8)); + return (ushort)((b >> 3) | ((g & ~3) << 3) | ((r & ~7) << 8)); + } + }; + + template struct RGB2RGB5x5Converter<5, bidx> + { + static __device__ __forceinline__ ushort cvt(const uchar3& src) + { + return (ushort)(((&src.x)[bidx] >> 3) | ((src.y & ~7) << 2) | (((&src.x)[bidx^2] & ~7) << 7)); + } + + static __device__ __forceinline__ ushort cvt(uint src) + { + uint b = 0xffu & (src >> (bidx * 8)); + uint g = 0xffu & (src >> 8); + uint r = 0xffu & (src >> ((bidx ^ 2) * 8)); + uint a = 0xffu & (src >> 24); + return (ushort)((b >> 3) | ((g & ~7) << 2) | ((r & ~7) << 7) | (a * 0x8000)); + } + }; + + template struct RGB2RGB5x5; + + template struct RGB2RGB5x5<3, bidx,green_bits> : unary_function + { + __device__ __forceinline__ ushort operator()(const uchar3& src) const + { + return RGB2RGB5x5Converter::cvt(src); + } + + __host__ __device__ __forceinline__ RGB2RGB5x5() {} + __host__ __device__ __forceinline__ RGB2RGB5x5(const RGB2RGB5x5&) {} + }; + + template struct RGB2RGB5x5<4, bidx,green_bits> : unary_function + { + __device__ __forceinline__ ushort operator()(uint src) const + { + return RGB2RGB5x5Converter::cvt(src); + } + + __host__ __device__ __forceinline__ RGB2RGB5x5() {} + __host__ __device__ __forceinline__ RGB2RGB5x5(const RGB2RGB5x5&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_RGB2RGB5x5_TRAITS(name, scn, bidx, green_bits) \ + struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::RGB2RGB5x5 functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + + namespace color_detail + { + template struct RGB5x52RGBConverter; + + template struct RGB5x52RGBConverter<5, bidx> + { + static __device__ __forceinline__ void cvt(uint src, uchar3& dst) + { + (&dst.x)[bidx] = src << 3; + dst.y = (src >> 2) & ~7; + (&dst.x)[bidx ^ 2] = (src >> 7) & ~7; + } + + static __device__ __forceinline__ void cvt(uint src, uint& dst) + { + dst = 0; + + dst |= (0xffu & (src << 3)) << (bidx * 8); + dst |= (0xffu & ((src >> 2) & ~7)) << 8; + dst |= (0xffu & ((src >> 7) & ~7)) << ((bidx ^ 2) * 8); + dst |= ((src & 0x8000) * 0xffu) << 24; + } + }; + + template struct RGB5x52RGBConverter<6, bidx> + { + static __device__ __forceinline__ void cvt(uint src, uchar3& dst) + { + (&dst.x)[bidx] = src << 3; + dst.y = (src >> 3) & ~3; + (&dst.x)[bidx ^ 2] = (src >> 8) & ~7; + } + + static __device__ __forceinline__ void cvt(uint src, uint& dst) + { + dst = 0xffu << 24; + + dst |= (0xffu & (src << 3)) << (bidx * 8); + dst |= (0xffu &((src >> 3) & ~3)) << 8; + dst |= (0xffu & ((src >> 8) & ~7)) << ((bidx ^ 2) * 8); + } + }; + + template struct RGB5x52RGB; + + template struct RGB5x52RGB<3, bidx, green_bits> : unary_function + { + __device__ __forceinline__ uchar3 operator()(ushort src) const + { + uchar3 dst; + RGB5x52RGBConverter::cvt(src, dst); + return dst; + } + __host__ __device__ __forceinline__ RGB5x52RGB() {} + __host__ __device__ __forceinline__ RGB5x52RGB(const RGB5x52RGB&) {} + + }; + + template struct RGB5x52RGB<4, bidx, green_bits> : unary_function + { + __device__ __forceinline__ uint operator()(ushort src) const + { + uint dst; + RGB5x52RGBConverter::cvt(src, dst); + return dst; + } + __host__ __device__ __forceinline__ RGB5x52RGB() {} + __host__ __device__ __forceinline__ RGB5x52RGB(const RGB5x52RGB&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_RGB5x52RGB_TRAITS(name, dcn, bidx, green_bits) \ + struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::RGB5x52RGB functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + +///////////////////////////////// Grayscale to Color //////////////////////////////// + + namespace color_detail + { + template struct Gray2RGB : unary_function::vec_type> + { + __device__ __forceinline__ typename TypeVec::vec_type operator()(T src) const + { + typename TypeVec::vec_type dst; + + dst.z = dst.y = dst.x = src; + setAlpha(dst, ColorChannel::max()); + + return dst; + } + __host__ __device__ __forceinline__ Gray2RGB() {} + __host__ __device__ __forceinline__ Gray2RGB(const Gray2RGB&) {} + }; + + template <> struct Gray2RGB : unary_function + { + __device__ __forceinline__ uint operator()(uint src) const + { + uint dst = 0xffu << 24; + + dst |= src; + dst |= src << 8; + dst |= src << 16; + + return dst; + } + __host__ __device__ __forceinline__ Gray2RGB() {} + __host__ __device__ __forceinline__ Gray2RGB(const Gray2RGB&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_GRAY2RGB_TRAITS(name, dcn) \ + template struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::Gray2RGB functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + + namespace color_detail + { + template struct Gray2RGB5x5Converter; + template<> struct Gray2RGB5x5Converter<6> + { + static __device__ __forceinline__ ushort cvt(uint t) + { + return (ushort)((t >> 3) | ((t & ~3) << 3) | ((t & ~7) << 8)); + } + }; + + template<> struct Gray2RGB5x5Converter<5> + { + static __device__ __forceinline__ ushort cvt(uint t) + { + t >>= 3; + return (ushort)(t | (t << 5) | (t << 10)); + } + }; + + template struct Gray2RGB5x5 : unary_function + { + __device__ __forceinline__ ushort operator()(uint src) const + { + return Gray2RGB5x5Converter::cvt(src); + } + + __host__ __device__ __forceinline__ Gray2RGB5x5() {} + __host__ __device__ __forceinline__ Gray2RGB5x5(const Gray2RGB5x5&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_GRAY2RGB5x5_TRAITS(name, green_bits) \ + struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::Gray2RGB5x5 functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + +///////////////////////////////// Color to Grayscale //////////////////////////////// + + namespace color_detail + { + template struct RGB5x52GrayConverter; + template <> struct RGB5x52GrayConverter<6> + { + static __device__ __forceinline__ uchar cvt(uint t) + { + return (uchar)CV_DESCALE(((t << 3) & 0xf8) * BY15 + ((t >> 3) & 0xfc) * GY15 + ((t >> 8) & 0xf8) * RY15, gray_shift); + } + }; + + template <> struct RGB5x52GrayConverter<5> + { + static __device__ __forceinline__ uchar cvt(uint t) + { + return (uchar)CV_DESCALE(((t << 3) & 0xf8) * BY15 + ((t >> 2) & 0xf8) * GY15 + ((t >> 7) & 0xf8) * RY15, gray_shift); + } + }; + + template struct RGB5x52Gray : unary_function + { + __device__ __forceinline__ uchar operator()(uint src) const + { + return RGB5x52GrayConverter::cvt(src); + } + __host__ __device__ __forceinline__ RGB5x52Gray() {} + __host__ __device__ __forceinline__ RGB5x52Gray(const RGB5x52Gray&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_RGB5x52GRAY_TRAITS(name, green_bits) \ + struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::RGB5x52Gray functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + + namespace color_detail + { + template static __device__ __forceinline__ T RGB2GrayConvert(const T* src) + { + return (T)CV_DESCALE((unsigned)(src[bidx] * BY15 + src[1] * GY15 + src[bidx^2] * RY15), gray_shift); + } + + template static __device__ __forceinline__ uchar RGB2GrayConvert(uint src) + { + uint b = 0xffu & (src >> (bidx * 8)); + uint g = 0xffu & (src >> 8); + uint r = 0xffu & (src >> ((bidx ^ 2) * 8)); + return CV_DESCALE((uint)(b * BY15 + g * GY15 + r * RY15), gray_shift); + } + + template static __device__ __forceinline__ float RGB2GrayConvert(const float* src) + { + return src[bidx] * B2YF + src[1] * G2YF + src[bidx^2] * R2YF; + } + + template struct RGB2Gray : unary_function::vec_type, T> + { + __device__ __forceinline__ T operator()(const typename TypeVec::vec_type& src) const + { + return RGB2GrayConvert(&src.x); + } + __host__ __device__ __forceinline__ RGB2Gray() {} + __host__ __device__ __forceinline__ RGB2Gray(const RGB2Gray&) {} + }; + + template struct RGB2Gray : unary_function + { + __device__ __forceinline__ uchar operator()(uint src) const + { + return RGB2GrayConvert(src); + } + __host__ __device__ __forceinline__ RGB2Gray() {} + __host__ __device__ __forceinline__ RGB2Gray(const RGB2Gray&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_RGB2GRAY_TRAITS(name, scn, bidx) \ + template struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::RGB2Gray functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + +///////////////////////////////////// RGB <-> YUV ////////////////////////////////////// + + namespace color_detail + { + __constant__ float c_RGB2YUVCoeffs_f[5] = { B2YF, G2YF, R2YF, B2UF, R2VF }; + __constant__ int c_RGB2YUVCoeffs_i[5] = { B2Y, G2Y, R2Y, B2UI, R2VI }; + + template static __device__ void RGB2YUVConvert(const T* src, D& dst) + { + const int delta = ColorChannel::half() * (1 << yuv_shift); + + const int Y = CV_DESCALE(src[0] * c_RGB2YUVCoeffs_i[bidx^2] + src[1] * c_RGB2YUVCoeffs_i[1] + src[2] * c_RGB2YUVCoeffs_i[bidx], yuv_shift); + const int Cr = CV_DESCALE((src[bidx^2] - Y) * c_RGB2YUVCoeffs_i[3] + delta, yuv_shift); + const int Cb = CV_DESCALE((src[bidx] - Y) * c_RGB2YUVCoeffs_i[4] + delta, yuv_shift); + + dst.x = saturate_cast(Y); + dst.y = saturate_cast(Cr); + dst.z = saturate_cast(Cb); + } + + template static __device__ __forceinline__ void RGB2YUVConvert(const float* src, D& dst) + { + dst.x = src[0] * c_RGB2YUVCoeffs_f[bidx^2] + src[1] * c_RGB2YUVCoeffs_f[1] + src[2] * c_RGB2YUVCoeffs_f[bidx]; + dst.y = (src[bidx^2] - dst.x) * c_RGB2YUVCoeffs_f[3] + ColorChannel::half(); + dst.z = (src[bidx] - dst.x) * c_RGB2YUVCoeffs_f[4] + ColorChannel::half(); + } + + template struct RGB2YUV + : unary_function::vec_type, typename TypeVec::vec_type> + { + __device__ __forceinline__ typename TypeVec::vec_type operator ()(const typename TypeVec::vec_type& src) const + { + typename TypeVec::vec_type dst; + RGB2YUVConvert(&src.x, dst); + return dst; + } + __host__ __device__ __forceinline__ RGB2YUV() {} + __host__ __device__ __forceinline__ RGB2YUV(const RGB2YUV&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_RGB2YUV_TRAITS(name, scn, dcn, bidx) \ + template struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::RGB2YUV functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + + namespace color_detail + { + __constant__ float c_YUV2RGBCoeffs_f[5] = { U2BF, U2GF, V2GF, V2RF }; + __constant__ int c_YUV2RGBCoeffs_i[5] = { U2BI, U2GI, V2GI, V2RI }; + + template static __device__ void YUV2RGBConvert(const T& src, D* dst) + { + const int b = src.x + CV_DESCALE((src.z - ColorChannel::half()) * c_YUV2RGBCoeffs_i[3], yuv_shift); + + const int g = src.x + CV_DESCALE((src.z - ColorChannel::half()) * c_YUV2RGBCoeffs_i[2] + + (src.y - ColorChannel::half()) * c_YUV2RGBCoeffs_i[1], yuv_shift); + + const int r = src.x + CV_DESCALE((src.y - ColorChannel::half()) * c_YUV2RGBCoeffs_i[0], yuv_shift); + + dst[bidx] = saturate_cast(b); + dst[1] = saturate_cast(g); + dst[bidx^2] = saturate_cast(r); + } + + template static __device__ uint YUV2RGBConvert(uint src) + { + const int x = 0xff & (src); + const int y = 0xff & (src >> 8); + const int z = 0xff & (src >> 16); + + const int b = x + CV_DESCALE((z - ColorChannel::half()) * c_YUV2RGBCoeffs_i[3], yuv_shift); + + const int g = x + CV_DESCALE((z - ColorChannel::half()) * c_YUV2RGBCoeffs_i[2] + + (y - ColorChannel::half()) * c_YUV2RGBCoeffs_i[1], yuv_shift); + + const int r = x + CV_DESCALE((y - ColorChannel::half()) * c_YUV2RGBCoeffs_i[0], yuv_shift); + + uint dst = 0xffu << 24; + + dst |= saturate_cast(b) << (bidx * 8); + dst |= saturate_cast(g) << 8; + dst |= saturate_cast(r) << ((bidx ^ 2) * 8); + + return dst; + } + + template static __device__ __forceinline__ void YUV2RGBConvert(const T& src, float* dst) + { + dst[bidx] = src.x + (src.z - ColorChannel::half()) * c_YUV2RGBCoeffs_f[3]; + + dst[1] = src.x + (src.z - ColorChannel::half()) * c_YUV2RGBCoeffs_f[2] + + (src.y - ColorChannel::half()) * c_YUV2RGBCoeffs_f[1]; + + dst[bidx^2] = src.x + (src.y - ColorChannel::half()) * c_YUV2RGBCoeffs_f[0]; + } + + template struct YUV2RGB + : unary_function::vec_type, typename TypeVec::vec_type> + { + __device__ __forceinline__ typename TypeVec::vec_type operator ()(const typename TypeVec::vec_type& src) const + { + typename TypeVec::vec_type dst; + + YUV2RGBConvert(src, &dst.x); + setAlpha(dst, ColorChannel::max()); + + return dst; + } + __host__ __device__ __forceinline__ YUV2RGB() {} + __host__ __device__ __forceinline__ YUV2RGB(const YUV2RGB&) {} + }; + + template struct YUV2RGB : unary_function + { + __device__ __forceinline__ uint operator ()(uint src) const + { + return YUV2RGBConvert(src); + } + __host__ __device__ __forceinline__ YUV2RGB() {} + __host__ __device__ __forceinline__ YUV2RGB(const YUV2RGB&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_YUV2RGB_TRAITS(name, scn, dcn, bidx) \ + template struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::YUV2RGB functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + +///////////////////////////////////// RGB <-> YCrCb ////////////////////////////////////// + + namespace color_detail + { + __constant__ float c_RGB2YCrCbCoeffs_f[5] = {R2YF, G2YF, B2YF, YCRF, YCBF}; + __constant__ int c_RGB2YCrCbCoeffs_i[5] = {R2Y, G2Y, B2Y, YCRI, YCBI}; + + template static __device__ void RGB2YCrCbConvert(const T* src, D& dst) + { + const int delta = ColorChannel::half() * (1 << yuv_shift); + + const int Y = CV_DESCALE(src[0] * c_RGB2YCrCbCoeffs_i[bidx^2] + src[1] * c_RGB2YCrCbCoeffs_i[1] + src[2] * c_RGB2YCrCbCoeffs_i[bidx], yuv_shift); + const int Cr = CV_DESCALE((src[bidx^2] - Y) * c_RGB2YCrCbCoeffs_i[3] + delta, yuv_shift); + const int Cb = CV_DESCALE((src[bidx] - Y) * c_RGB2YCrCbCoeffs_i[4] + delta, yuv_shift); + + dst.x = saturate_cast(Y); + dst.y = saturate_cast(Cr); + dst.z = saturate_cast(Cb); + } + + template static __device__ uint RGB2YCrCbConvert(uint src) + { + const int delta = ColorChannel::half() * (1 << yuv_shift); + + const int Y = CV_DESCALE((0xffu & src) * c_RGB2YCrCbCoeffs_i[bidx^2] + (0xffu & (src >> 8)) * c_RGB2YCrCbCoeffs_i[1] + (0xffu & (src >> 16)) * c_RGB2YCrCbCoeffs_i[bidx], yuv_shift); + const int Cr = CV_DESCALE(((0xffu & (src >> ((bidx ^ 2) * 8))) - Y) * c_RGB2YCrCbCoeffs_i[3] + delta, yuv_shift); + const int Cb = CV_DESCALE(((0xffu & (src >> (bidx * 8))) - Y) * c_RGB2YCrCbCoeffs_i[4] + delta, yuv_shift); + + uint dst = 0; + + dst |= saturate_cast(Y); + dst |= saturate_cast(Cr) << 8; + dst |= saturate_cast(Cb) << 16; + + return dst; + } + + template static __device__ __forceinline__ void RGB2YCrCbConvert(const float* src, D& dst) + { + dst.x = src[0] * c_RGB2YCrCbCoeffs_f[bidx^2] + src[1] * c_RGB2YCrCbCoeffs_f[1] + src[2] * c_RGB2YCrCbCoeffs_f[bidx]; + dst.y = (src[bidx^2] - dst.x) * c_RGB2YCrCbCoeffs_f[3] + ColorChannel::half(); + dst.z = (src[bidx] - dst.x) * c_RGB2YCrCbCoeffs_f[4] + ColorChannel::half(); + } + + template struct RGB2YCrCb + : unary_function::vec_type, typename TypeVec::vec_type> + { + __device__ __forceinline__ typename TypeVec::vec_type operator ()(const typename TypeVec::vec_type& src) const + { + typename TypeVec::vec_type dst; + RGB2YCrCbConvert(&src.x, dst); + return dst; + } + __host__ __device__ __forceinline__ RGB2YCrCb() {} + __host__ __device__ __forceinline__ RGB2YCrCb(const RGB2YCrCb&) {} + }; + + template struct RGB2YCrCb : unary_function + { + __device__ __forceinline__ uint operator ()(uint src) const + { + return RGB2YCrCbConvert(src); + } + + __host__ __device__ __forceinline__ RGB2YCrCb() {} + __host__ __device__ __forceinline__ RGB2YCrCb(const RGB2YCrCb&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_RGB2YCrCb_TRAITS(name, scn, dcn, bidx) \ + template struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::RGB2YCrCb functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + + namespace color_detail + { + __constant__ float c_YCrCb2RGBCoeffs_f[5] = {CR2RF, CR2GF, CB2GF, CB2BF}; + __constant__ int c_YCrCb2RGBCoeffs_i[5] = {CR2RI, CR2GI, CB2GI, CB2BI}; + + template static __device__ void YCrCb2RGBConvert(const T& src, D* dst) + { + const int b = src.x + CV_DESCALE((src.z - ColorChannel::half()) * c_YCrCb2RGBCoeffs_i[3], yuv_shift); + const int g = src.x + CV_DESCALE((src.z - ColorChannel::half()) * c_YCrCb2RGBCoeffs_i[2] + (src.y - ColorChannel::half()) * c_YCrCb2RGBCoeffs_i[1], yuv_shift); + const int r = src.x + CV_DESCALE((src.y - ColorChannel::half()) * c_YCrCb2RGBCoeffs_i[0], yuv_shift); + + dst[bidx] = saturate_cast(b); + dst[1] = saturate_cast(g); + dst[bidx^2] = saturate_cast(r); + } + + template static __device__ uint YCrCb2RGBConvert(uint src) + { + const int x = 0xff & (src); + const int y = 0xff & (src >> 8); + const int z = 0xff & (src >> 16); + + const int b = x + CV_DESCALE((z - ColorChannel::half()) * c_YCrCb2RGBCoeffs_i[3], yuv_shift); + const int g = x + CV_DESCALE((z - ColorChannel::half()) * c_YCrCb2RGBCoeffs_i[2] + (y - ColorChannel::half()) * c_YCrCb2RGBCoeffs_i[1], yuv_shift); + const int r = x + CV_DESCALE((y - ColorChannel::half()) * c_YCrCb2RGBCoeffs_i[0], yuv_shift); + + uint dst = 0xffu << 24; + + dst |= saturate_cast(b) << (bidx * 8); + dst |= saturate_cast(g) << 8; + dst |= saturate_cast(r) << ((bidx ^ 2) * 8); + + return dst; + } + + template __device__ __forceinline__ void YCrCb2RGBConvert(const T& src, float* dst) + { + dst[bidx] = src.x + (src.z - ColorChannel::half()) * c_YCrCb2RGBCoeffs_f[3]; + dst[1] = src.x + (src.z - ColorChannel::half()) * c_YCrCb2RGBCoeffs_f[2] + (src.y - ColorChannel::half()) * c_YCrCb2RGBCoeffs_f[1]; + dst[bidx^2] = src.x + (src.y - ColorChannel::half()) * c_YCrCb2RGBCoeffs_f[0]; + } + + template struct YCrCb2RGB + : unary_function::vec_type, typename TypeVec::vec_type> + { + __device__ __forceinline__ typename TypeVec::vec_type operator ()(const typename TypeVec::vec_type& src) const + { + typename TypeVec::vec_type dst; + + YCrCb2RGBConvert(src, &dst.x); + setAlpha(dst, ColorChannel::max()); + + return dst; + } + __host__ __device__ __forceinline__ YCrCb2RGB() {} + __host__ __device__ __forceinline__ YCrCb2RGB(const YCrCb2RGB&) {} + }; + + template struct YCrCb2RGB : unary_function + { + __device__ __forceinline__ uint operator ()(uint src) const + { + return YCrCb2RGBConvert(src); + } + __host__ __device__ __forceinline__ YCrCb2RGB() {} + __host__ __device__ __forceinline__ YCrCb2RGB(const YCrCb2RGB&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_YCrCb2RGB_TRAITS(name, scn, dcn, bidx) \ + template struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::YCrCb2RGB functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + +////////////////////////////////////// RGB <-> XYZ /////////////////////////////////////// + + namespace color_detail + { + __constant__ float c_RGB2XYZ_D65f[9] = { 0.412453f, 0.357580f, 0.180423f, 0.212671f, 0.715160f, 0.072169f, 0.019334f, 0.119193f, 0.950227f }; + __constant__ int c_RGB2XYZ_D65i[9] = { 1689, 1465, 739, 871, 2929, 296, 79, 488, 3892 }; + + template static __device__ __forceinline__ void RGB2XYZConvert(const T* src, D& dst) + { + dst.z = saturate_cast(CV_DESCALE(src[bidx^2] * c_RGB2XYZ_D65i[6] + src[1] * c_RGB2XYZ_D65i[7] + src[bidx] * c_RGB2XYZ_D65i[8], xyz_shift)); + dst.x = saturate_cast(CV_DESCALE(src[bidx^2] * c_RGB2XYZ_D65i[0] + src[1] * c_RGB2XYZ_D65i[1] + src[bidx] * c_RGB2XYZ_D65i[2], xyz_shift)); + dst.y = saturate_cast(CV_DESCALE(src[bidx^2] * c_RGB2XYZ_D65i[3] + src[1] * c_RGB2XYZ_D65i[4] + src[bidx] * c_RGB2XYZ_D65i[5], xyz_shift)); + } + + template static __device__ __forceinline__ uint RGB2XYZConvert(uint src) + { + const uint b = 0xffu & (src >> (bidx * 8)); + const uint g = 0xffu & (src >> 8); + const uint r = 0xffu & (src >> ((bidx ^ 2) * 8)); + + const uint x = saturate_cast(CV_DESCALE(r * c_RGB2XYZ_D65i[0] + g * c_RGB2XYZ_D65i[1] + b * c_RGB2XYZ_D65i[2], xyz_shift)); + const uint y = saturate_cast(CV_DESCALE(r * c_RGB2XYZ_D65i[3] + g * c_RGB2XYZ_D65i[4] + b * c_RGB2XYZ_D65i[5], xyz_shift)); + const uint z = saturate_cast(CV_DESCALE(r * c_RGB2XYZ_D65i[6] + g * c_RGB2XYZ_D65i[7] + b * c_RGB2XYZ_D65i[8], xyz_shift)); + + uint dst = 0; + + dst |= x; + dst |= y << 8; + dst |= z << 16; + + return dst; + } + + template static __device__ __forceinline__ void RGB2XYZConvert(const float* src, D& dst) + { + dst.x = src[bidx^2] * c_RGB2XYZ_D65f[0] + src[1] * c_RGB2XYZ_D65f[1] + src[bidx] * c_RGB2XYZ_D65f[2]; + dst.y = src[bidx^2] * c_RGB2XYZ_D65f[3] + src[1] * c_RGB2XYZ_D65f[4] + src[bidx] * c_RGB2XYZ_D65f[5]; + dst.z = src[bidx^2] * c_RGB2XYZ_D65f[6] + src[1] * c_RGB2XYZ_D65f[7] + src[bidx] * c_RGB2XYZ_D65f[8]; + } + + template struct RGB2XYZ + : unary_function::vec_type, typename TypeVec::vec_type> + { + __device__ __forceinline__ typename TypeVec::vec_type operator()(const typename TypeVec::vec_type& src) const + { + typename TypeVec::vec_type dst; + + RGB2XYZConvert(&src.x, dst); + + return dst; + } + __host__ __device__ __forceinline__ RGB2XYZ() {} + __host__ __device__ __forceinline__ RGB2XYZ(const RGB2XYZ&) {} + }; + + template struct RGB2XYZ : unary_function + { + __device__ __forceinline__ uint operator()(uint src) const + { + return RGB2XYZConvert(src); + } + __host__ __device__ __forceinline__ RGB2XYZ() {} + __host__ __device__ __forceinline__ RGB2XYZ(const RGB2XYZ&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_RGB2XYZ_TRAITS(name, scn, dcn, bidx) \ + template struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::RGB2XYZ functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + + namespace color_detail + { + __constant__ float c_XYZ2sRGB_D65f[9] = { 3.240479f, -1.53715f, -0.498535f, -0.969256f, 1.875991f, 0.041556f, 0.055648f, -0.204043f, 1.057311f }; + __constant__ int c_XYZ2sRGB_D65i[9] = { 13273, -6296, -2042, -3970, 7684, 170, 228, -836, 4331 }; + + template static __device__ __forceinline__ void XYZ2RGBConvert(const T& src, D* dst) + { + dst[bidx^2] = saturate_cast(CV_DESCALE(src.x * c_XYZ2sRGB_D65i[0] + src.y * c_XYZ2sRGB_D65i[1] + src.z * c_XYZ2sRGB_D65i[2], xyz_shift)); + dst[1] = saturate_cast(CV_DESCALE(src.x * c_XYZ2sRGB_D65i[3] + src.y * c_XYZ2sRGB_D65i[4] + src.z * c_XYZ2sRGB_D65i[5], xyz_shift)); + dst[bidx] = saturate_cast(CV_DESCALE(src.x * c_XYZ2sRGB_D65i[6] + src.y * c_XYZ2sRGB_D65i[7] + src.z * c_XYZ2sRGB_D65i[8], xyz_shift)); + } + + template static __device__ __forceinline__ uint XYZ2RGBConvert(uint src) + { + const int x = 0xff & src; + const int y = 0xff & (src >> 8); + const int z = 0xff & (src >> 16); + + const uint r = saturate_cast(CV_DESCALE(x * c_XYZ2sRGB_D65i[0] + y * c_XYZ2sRGB_D65i[1] + z * c_XYZ2sRGB_D65i[2], xyz_shift)); + const uint g = saturate_cast(CV_DESCALE(x * c_XYZ2sRGB_D65i[3] + y * c_XYZ2sRGB_D65i[4] + z * c_XYZ2sRGB_D65i[5], xyz_shift)); + const uint b = saturate_cast(CV_DESCALE(x * c_XYZ2sRGB_D65i[6] + y * c_XYZ2sRGB_D65i[7] + z * c_XYZ2sRGB_D65i[8], xyz_shift)); + + uint dst = 0xffu << 24; + + dst |= b << (bidx * 8); + dst |= g << 8; + dst |= r << ((bidx ^ 2) * 8); + + return dst; + } + + template static __device__ __forceinline__ void XYZ2RGBConvert(const T& src, float* dst) + { + dst[bidx^2] = src.x * c_XYZ2sRGB_D65f[0] + src.y * c_XYZ2sRGB_D65f[1] + src.z * c_XYZ2sRGB_D65f[2]; + dst[1] = src.x * c_XYZ2sRGB_D65f[3] + src.y * c_XYZ2sRGB_D65f[4] + src.z * c_XYZ2sRGB_D65f[5]; + dst[bidx] = src.x * c_XYZ2sRGB_D65f[6] + src.y * c_XYZ2sRGB_D65f[7] + src.z * c_XYZ2sRGB_D65f[8]; + } + + template struct XYZ2RGB + : unary_function::vec_type, typename TypeVec::vec_type> + { + __device__ __forceinline__ typename TypeVec::vec_type operator()(const typename TypeVec::vec_type& src) const + { + typename TypeVec::vec_type dst; + + XYZ2RGBConvert(src, &dst.x); + setAlpha(dst, ColorChannel::max()); + + return dst; + } + __host__ __device__ __forceinline__ XYZ2RGB() {} + __host__ __device__ __forceinline__ XYZ2RGB(const XYZ2RGB&) {} + }; + + template struct XYZ2RGB : unary_function + { + __device__ __forceinline__ uint operator()(uint src) const + { + return XYZ2RGBConvert(src); + } + __host__ __device__ __forceinline__ XYZ2RGB() {} + __host__ __device__ __forceinline__ XYZ2RGB(const XYZ2RGB&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_XYZ2RGB_TRAITS(name, scn, dcn, bidx) \ + template struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::XYZ2RGB functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + +////////////////////////////////////// RGB <-> HSV /////////////////////////////////////// + + namespace color_detail + { + __constant__ int c_HsvDivTable [256] = {0, 1044480, 522240, 348160, 261120, 208896, 174080, 149211, 130560, 116053, 104448, 94953, 87040, 80345, 74606, 69632, 65280, 61440, 58027, 54973, 52224, 49737, 47476, 45412, 43520, 41779, 40172, 38684, 37303, 36017, 34816, 33693, 32640, 31651, 30720, 29842, 29013, 28229, 27486, 26782, 26112, 25475, 24869, 24290, 23738, 23211, 22706, 22223, 21760, 21316, 20890, 20480, 20086, 19707, 19342, 18991, 18651, 18324, 18008, 17703, 17408, 17123, 16846, 16579, 16320, 16069, 15825, 15589, 15360, 15137, 14921, 14711, 14507, 14308, 14115, 13926, 13743, 13565, 13391, 13221, 13056, 12895, 12738, 12584, 12434, 12288, 12145, 12006, 11869, 11736, 11605, 11478, 11353, 11231, 11111, 10995, 10880, 10768, 10658, 10550, 10445, 10341, 10240, 10141, 10043, 9947, 9854, 9761, 9671, 9582, 9495, 9410, 9326, 9243, 9162, 9082, 9004, 8927, 8852, 8777, 8704, 8632, 8561, 8492, 8423, 8356, 8290, 8224, 8160, 8097, 8034, 7973, 7913, 7853, 7795, 7737, 7680, 7624, 7569, 7514, 7461, 7408, 7355, 7304, 7253, 7203, 7154, 7105, 7057, 7010, 6963, 6917, 6872, 6827, 6782, 6739, 6695, 6653, 6611, 6569, 6528, 6487, 6447, 6408, 6369, 6330, 6292, 6254, 6217, 6180, 6144, 6108, 6073, 6037, 6003, 5968, 5935, 5901, 5868, 5835, 5803, 5771, 5739, 5708, 5677, 5646, 5615, 5585, 5556, 5526, 5497, 5468, 5440, 5412, 5384, 5356, 5329, 5302, 5275, 5249, 5222, 5196, 5171, 5145, 5120, 5095, 5070, 5046, 5022, 4998, 4974, 4950, 4927, 4904, 4881, 4858, 4836, 4813, 4791, 4769, 4748, 4726, 4705, 4684, 4663, 4642, 4622, 4601, 4581, 4561, 4541, 4522, 4502, 4483, 4464, 4445, 4426, 4407, 4389, 4370, 4352, 4334, 4316, 4298, 4281, 4263, 4246, 4229, 4212, 4195, 4178, 4161, 4145, 4128, 4112, 4096}; + __constant__ int c_HsvDivTable180[256] = {0, 122880, 61440, 40960, 30720, 24576, 20480, 17554, 15360, 13653, 12288, 11171, 10240, 9452, 8777, 8192, 7680, 7228, 6827, 6467, 6144, 5851, 5585, 5343, 5120, 4915, 4726, 4551, 4389, 4237, 4096, 3964, 3840, 3724, 3614, 3511, 3413, 3321, 3234, 3151, 3072, 2997, 2926, 2858, 2793, 2731, 2671, 2614, 2560, 2508, 2458, 2409, 2363, 2318, 2276, 2234, 2194, 2156, 2119, 2083, 2048, 2014, 1982, 1950, 1920, 1890, 1862, 1834, 1807, 1781, 1755, 1731, 1707, 1683, 1661, 1638, 1617, 1596, 1575, 1555, 1536, 1517, 1499, 1480, 1463, 1446, 1429, 1412, 1396, 1381, 1365, 1350, 1336, 1321, 1307, 1293, 1280, 1267, 1254, 1241, 1229, 1217, 1205, 1193, 1182, 1170, 1159, 1148, 1138, 1127, 1117, 1107, 1097, 1087, 1078, 1069, 1059, 1050, 1041, 1033, 1024, 1016, 1007, 999, 991, 983, 975, 968, 960, 953, 945, 938, 931, 924, 917, 910, 904, 897, 890, 884, 878, 871, 865, 859, 853, 847, 842, 836, 830, 825, 819, 814, 808, 803, 798, 793, 788, 783, 778, 773, 768, 763, 759, 754, 749, 745, 740, 736, 731, 727, 723, 719, 714, 710, 706, 702, 698, 694, 690, 686, 683, 679, 675, 671, 668, 664, 661, 657, 654, 650, 647, 643, 640, 637, 633, 630, 627, 624, 621, 617, 614, 611, 608, 605, 602, 599, 597, 594, 591, 588, 585, 582, 580, 577, 574, 572, 569, 566, 564, 561, 559, 556, 554, 551, 549, 546, 544, 541, 539, 537, 534, 532, 530, 527, 525, 523, 521, 518, 516, 514, 512, 510, 508, 506, 504, 502, 500, 497, 495, 493, 492, 490, 488, 486, 484, 482}; + __constant__ int c_HsvDivTable256[256] = {0, 174763, 87381, 58254, 43691, 34953, 29127, 24966, 21845, 19418, 17476, 15888, 14564, 13443, 12483, 11651, 10923, 10280, 9709, 9198, 8738, 8322, 7944, 7598, 7282, 6991, 6722, 6473, 6242, 6026, 5825, 5638, 5461, 5296, 5140, 4993, 4855, 4723, 4599, 4481, 4369, 4263, 4161, 4064, 3972, 3884, 3799, 3718, 3641, 3567, 3495, 3427, 3361, 3297, 3236, 3178, 3121, 3066, 3013, 2962, 2913, 2865, 2819, 2774, 2731, 2689, 2648, 2608, 2570, 2533, 2497, 2461, 2427, 2394, 2362, 2330, 2300, 2270, 2241, 2212, 2185, 2158, 2131, 2106, 2081, 2056, 2032, 2009, 1986, 1964, 1942, 1920, 1900, 1879, 1859, 1840, 1820, 1802, 1783, 1765, 1748, 1730, 1713, 1697, 1680, 1664, 1649, 1633, 1618, 1603, 1589, 1574, 1560, 1547, 1533, 1520, 1507, 1494, 1481, 1469, 1456, 1444, 1432, 1421, 1409, 1398, 1387, 1376, 1365, 1355, 1344, 1334, 1324, 1314, 1304, 1295, 1285, 1276, 1266, 1257, 1248, 1239, 1231, 1222, 1214, 1205, 1197, 1189, 1181, 1173, 1165, 1157, 1150, 1142, 1135, 1128, 1120, 1113, 1106, 1099, 1092, 1085, 1079, 1072, 1066, 1059, 1053, 1046, 1040, 1034, 1028, 1022, 1016, 1010, 1004, 999, 993, 987, 982, 976, 971, 966, 960, 955, 950, 945, 940, 935, 930, 925, 920, 915, 910, 906, 901, 896, 892, 887, 883, 878, 874, 869, 865, 861, 857, 853, 848, 844, 840, 836, 832, 828, 824, 820, 817, 813, 809, 805, 802, 798, 794, 791, 787, 784, 780, 777, 773, 770, 767, 763, 760, 757, 753, 750, 747, 744, 741, 737, 734, 731, 728, 725, 722, 719, 716, 713, 710, 708, 705, 702, 699, 696, 694, 691, 688, 685}; + + template static __device__ void RGB2HSVConvert(const uchar* src, D& dst) + { + const int hsv_shift = 12; + const int* hdiv_table = hr == 180 ? c_HsvDivTable180 : c_HsvDivTable256; + + int b = src[bidx], g = src[1], r = src[bidx^2]; + int h, s, v = b; + int vmin = b, diff; + int vr, vg; + + v = ::max(v, g); + v = ::max(v, r); + vmin = ::min(vmin, g); + vmin = ::min(vmin, r); + + diff = v - vmin; + vr = (v == r) * -1; + vg = (v == g) * -1; + + s = (diff * c_HsvDivTable[v] + (1 << (hsv_shift-1))) >> hsv_shift; + h = (vr & (g - b)) + (~vr & ((vg & (b - r + 2 * diff)) + ((~vg) & (r - g + 4 * diff)))); + h = (h * hdiv_table[diff] + (1 << (hsv_shift-1))) >> hsv_shift; + h += (h < 0) * hr; + + dst.x = saturate_cast(h); + dst.y = (uchar)s; + dst.z = (uchar)v; + } + + template static __device__ uint RGB2HSVConvert(uint src) + { + const int hsv_shift = 12; + const int* hdiv_table = hr == 180 ? c_HsvDivTable180 : c_HsvDivTable256; + + const int b = 0xff & (src >> (bidx * 8)); + const int g = 0xff & (src >> 8); + const int r = 0xff & (src >> ((bidx ^ 2) * 8)); + + int h, s, v = b; + int vmin = b, diff; + int vr, vg; + + v = ::max(v, g); + v = ::max(v, r); + vmin = ::min(vmin, g); + vmin = ::min(vmin, r); + + diff = v - vmin; + vr = (v == r) * -1; + vg = (v == g) * -1; + + s = (diff * c_HsvDivTable[v] + (1 << (hsv_shift-1))) >> hsv_shift; + h = (vr & (g - b)) + (~vr & ((vg & (b - r + 2 * diff)) + ((~vg) & (r - g + 4 * diff)))); + h = (h * hdiv_table[diff] + (1 << (hsv_shift-1))) >> hsv_shift; + h += (h < 0) * hr; + + uint dst = 0; + + dst |= saturate_cast(h); + dst |= (0xffu & s) << 8; + dst |= (0xffu & v) << 16; + + return dst; + } + + template static __device__ void RGB2HSVConvert(const float* src, D& dst) + { + const float hscale = hr * (1.f / 360.f); + + float b = src[bidx], g = src[1], r = src[bidx^2]; + float h, s, v; + + float vmin, diff; + + v = vmin = r; + v = fmax(v, g); + v = fmax(v, b); + vmin = fmin(vmin, g); + vmin = fmin(vmin, b); + + diff = v - vmin; + s = diff / (float)(::fabs(v) + numeric_limits::epsilon()); + diff = (float)(60. / (diff + numeric_limits::epsilon())); + + h = (v == r) * (g - b) * diff; + h += (v != r && v == g) * ((b - r) * diff + 120.f); + h += (v != r && v != g) * ((r - g) * diff + 240.f); + h += (h < 0) * 360.f; + + dst.x = h * hscale; + dst.y = s; + dst.z = v; + } + + template struct RGB2HSV + : unary_function::vec_type, typename TypeVec::vec_type> + { + __device__ __forceinline__ typename TypeVec::vec_type operator()(const typename TypeVec::vec_type& src) const + { + typename TypeVec::vec_type dst; + + RGB2HSVConvert(&src.x, dst); + + return dst; + } + __host__ __device__ __forceinline__ RGB2HSV() {} + __host__ __device__ __forceinline__ RGB2HSV(const RGB2HSV&) {} + }; + + template struct RGB2HSV : unary_function + { + __device__ __forceinline__ uint operator()(uint src) const + { + return RGB2HSVConvert(src); + } + __host__ __device__ __forceinline__ RGB2HSV() {} + __host__ __device__ __forceinline__ RGB2HSV(const RGB2HSV&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_RGB2HSV_TRAITS(name, scn, dcn, bidx) \ + template struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::RGB2HSV functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; \ + template struct name ## _full_traits \ + { \ + typedef ::cv::cuda::device::color_detail::RGB2HSV functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; \ + template <> struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::RGB2HSV functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; \ + template <> struct name ## _full_traits \ + { \ + typedef ::cv::cuda::device::color_detail::RGB2HSV functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + + namespace color_detail + { + __constant__ int c_HsvSectorData[6][3] = { {1,3,0}, {1,0,2}, {3,0,1}, {0,2,1}, {0,1,3}, {2,1,0} }; + + template static __device__ void HSV2RGBConvert(const T& src, float* dst) + { + const float hscale = 6.f / hr; + + float h = src.x, s = src.y, v = src.z; + float b = v, g = v, r = v; + + if (s != 0) + { + h *= hscale; + + if( h < 0 ) + do h += 6; while( h < 0 ); + else if( h >= 6 ) + do h -= 6; while( h >= 6 ); + + int sector = __float2int_rd(h); + h -= sector; + + if ( (unsigned)sector >= 6u ) + { + sector = 0; + h = 0.f; + } + + float tab[4]; + tab[0] = v; + tab[1] = v * (1.f - s); + tab[2] = v * (1.f - s * h); + tab[3] = v * (1.f - s * (1.f - h)); + + b = tab[c_HsvSectorData[sector][0]]; + g = tab[c_HsvSectorData[sector][1]]; + r = tab[c_HsvSectorData[sector][2]]; + } + + dst[bidx] = b; + dst[1] = g; + dst[bidx^2] = r; + } + + template static __device__ void HSV2RGBConvert(const T& src, uchar* dst) + { + float3 buf; + + buf.x = src.x; + buf.y = src.y * (1.f / 255.f); + buf.z = src.z * (1.f / 255.f); + + HSV2RGBConvert(buf, &buf.x); + + dst[0] = saturate_cast(buf.x * 255.f); + dst[1] = saturate_cast(buf.y * 255.f); + dst[2] = saturate_cast(buf.z * 255.f); + } + + template static __device__ uint HSV2RGBConvert(uint src) + { + float3 buf; + + buf.x = src & 0xff; + buf.y = ((src >> 8) & 0xff) * (1.f/255.f); + buf.z = ((src >> 16) & 0xff) * (1.f/255.f); + + HSV2RGBConvert(buf, &buf.x); + + uint dst = 0xffu << 24; + + dst |= saturate_cast(buf.x * 255.f); + dst |= saturate_cast(buf.y * 255.f) << 8; + dst |= saturate_cast(buf.z * 255.f) << 16; + + return dst; + } + + template struct HSV2RGB + : unary_function::vec_type, typename TypeVec::vec_type> + { + __device__ __forceinline__ typename TypeVec::vec_type operator()(const typename TypeVec::vec_type& src) const + { + typename TypeVec::vec_type dst; + + HSV2RGBConvert(src, &dst.x); + setAlpha(dst, ColorChannel::max()); + + return dst; + } + __host__ __device__ __forceinline__ HSV2RGB() {} + __host__ __device__ __forceinline__ HSV2RGB(const HSV2RGB&) {} + }; + + template struct HSV2RGB : unary_function + { + __device__ __forceinline__ uint operator()(uint src) const + { + return HSV2RGBConvert(src); + } + __host__ __device__ __forceinline__ HSV2RGB() {} + __host__ __device__ __forceinline__ HSV2RGB(const HSV2RGB&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_HSV2RGB_TRAITS(name, scn, dcn, bidx) \ + template struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::HSV2RGB functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; \ + template struct name ## _full_traits \ + { \ + typedef ::cv::cuda::device::color_detail::HSV2RGB functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; \ + template <> struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::HSV2RGB functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; \ + template <> struct name ## _full_traits \ + { \ + typedef ::cv::cuda::device::color_detail::HSV2RGB functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + +/////////////////////////////////////// RGB <-> HLS //////////////////////////////////////// + + namespace color_detail + { + template static __device__ void RGB2HLSConvert(const float* src, D& dst) + { + const float hscale = hr * (1.f / 360.f); + + float b = src[bidx], g = src[1], r = src[bidx^2]; + float h = 0.f, s = 0.f, l; + float vmin, vmax, diff; + + vmax = vmin = r; + vmax = fmax(vmax, g); + vmax = fmax(vmax, b); + vmin = fmin(vmin, g); + vmin = fmin(vmin, b); + + diff = vmax - vmin; + l = (vmax + vmin) * 0.5f; + + if (diff > numeric_limits::epsilon()) + { + s = (l < 0.5f) * diff / (vmax + vmin); + s += (l >= 0.5f) * diff / (2.0f - vmax - vmin); + + diff = 60.f / diff; + + h = (vmax == r) * (g - b) * diff; + h += (vmax != r && vmax == g) * ((b - r) * diff + 120.f); + h += (vmax != r && vmax != g) * ((r - g) * diff + 240.f); + h += (h < 0.f) * 360.f; + } + + dst.x = h * hscale; + dst.y = l; + dst.z = s; + } + + template static __device__ void RGB2HLSConvert(const uchar* src, D& dst) + { + float3 buf; + + buf.x = src[0] * (1.f / 255.f); + buf.y = src[1] * (1.f / 255.f); + buf.z = src[2] * (1.f / 255.f); + + RGB2HLSConvert(&buf.x, buf); + + dst.x = saturate_cast(buf.x); + dst.y = saturate_cast(buf.y*255.f); + dst.z = saturate_cast(buf.z*255.f); + } + + template static __device__ uint RGB2HLSConvert(uint src) + { + float3 buf; + + buf.x = (0xff & src) * (1.f / 255.f); + buf.y = (0xff & (src >> 8)) * (1.f / 255.f); + buf.z = (0xff & (src >> 16)) * (1.f / 255.f); + + RGB2HLSConvert(&buf.x, buf); + + uint dst = 0xffu << 24; + + dst |= saturate_cast(buf.x); + dst |= saturate_cast(buf.y * 255.f) << 8; + dst |= saturate_cast(buf.z * 255.f) << 16; + + return dst; + } + + template struct RGB2HLS + : unary_function::vec_type, typename TypeVec::vec_type> + { + __device__ __forceinline__ typename TypeVec::vec_type operator()(const typename TypeVec::vec_type& src) const + { + typename TypeVec::vec_type dst; + + RGB2HLSConvert(&src.x, dst); + + return dst; + } + __host__ __device__ __forceinline__ RGB2HLS() {} + __host__ __device__ __forceinline__ RGB2HLS(const RGB2HLS&) {} + }; + + template struct RGB2HLS : unary_function + { + __device__ __forceinline__ uint operator()(uint src) const + { + return RGB2HLSConvert(src); + } + __host__ __device__ __forceinline__ RGB2HLS() {} + __host__ __device__ __forceinline__ RGB2HLS(const RGB2HLS&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_RGB2HLS_TRAITS(name, scn, dcn, bidx) \ + template struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::RGB2HLS functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; \ + template struct name ## _full_traits \ + { \ + typedef ::cv::cuda::device::color_detail::RGB2HLS functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; \ + template <> struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::RGB2HLS functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; \ + template <> struct name ## _full_traits \ + { \ + typedef ::cv::cuda::device::color_detail::RGB2HLS functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + + namespace color_detail + { + __constant__ int c_HlsSectorData[6][3] = { {1,3,0}, {1,0,2}, {3,0,1}, {0,2,1}, {0,1,3}, {2,1,0} }; + + template static __device__ void HLS2RGBConvert(const T& src, float* dst) + { + const float hscale = 6.0f / hr; + + float h = src.x, l = src.y, s = src.z; + float b = l, g = l, r = l; + + if (s != 0) + { + float p2 = (l <= 0.5f) * l * (1 + s); + p2 += (l > 0.5f) * (l + s - l * s); + float p1 = 2 * l - p2; + + h *= hscale; + + if( h < 0 ) + do h += 6; while( h < 0 ); + else if( h >= 6 ) + do h -= 6; while( h >= 6 ); + + int sector; + sector = __float2int_rd(h); + + h -= sector; + + float tab[4]; + tab[0] = p2; + tab[1] = p1; + tab[2] = p1 + (p2 - p1) * (1 - h); + tab[3] = p1 + (p2 - p1) * h; + + b = tab[c_HlsSectorData[sector][0]]; + g = tab[c_HlsSectorData[sector][1]]; + r = tab[c_HlsSectorData[sector][2]]; + } + + dst[bidx] = b; + dst[1] = g; + dst[bidx^2] = r; + } + + template static __device__ void HLS2RGBConvert(const T& src, uchar* dst) + { + float3 buf; + + buf.x = src.x; + buf.y = src.y * (1.f / 255.f); + buf.z = src.z * (1.f / 255.f); + + HLS2RGBConvert(buf, &buf.x); + + dst[0] = saturate_cast(buf.x * 255.f); + dst[1] = saturate_cast(buf.y * 255.f); + dst[2] = saturate_cast(buf.z * 255.f); + } + + template static __device__ uint HLS2RGBConvert(uint src) + { + float3 buf; + + buf.x = 0xff & src; + buf.y = (0xff & (src >> 8)) * (1.f / 255.f); + buf.z = (0xff & (src >> 16)) * (1.f / 255.f); + + HLS2RGBConvert(buf, &buf.x); + + uint dst = 0xffu << 24; + + dst |= saturate_cast(buf.x * 255.f); + dst |= saturate_cast(buf.y * 255.f) << 8; + dst |= saturate_cast(buf.z * 255.f) << 16; + + return dst; + } + + template struct HLS2RGB + : unary_function::vec_type, typename TypeVec::vec_type> + { + __device__ __forceinline__ typename TypeVec::vec_type operator()(const typename TypeVec::vec_type& src) const + { + typename TypeVec::vec_type dst; + + HLS2RGBConvert(src, &dst.x); + setAlpha(dst, ColorChannel::max()); + + return dst; + } + __host__ __device__ __forceinline__ HLS2RGB() {} + __host__ __device__ __forceinline__ HLS2RGB(const HLS2RGB&) {} + }; + + template struct HLS2RGB : unary_function + { + __device__ __forceinline__ uint operator()(uint src) const + { + return HLS2RGBConvert(src); + } + __host__ __device__ __forceinline__ HLS2RGB() {} + __host__ __device__ __forceinline__ HLS2RGB(const HLS2RGB&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_HLS2RGB_TRAITS(name, scn, dcn, bidx) \ + template struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::HLS2RGB functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; \ + template struct name ## _full_traits \ + { \ + typedef ::cv::cuda::device::color_detail::HLS2RGB functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; \ + template <> struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::HLS2RGB functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; \ + template <> struct name ## _full_traits \ + { \ + typedef ::cv::cuda::device::color_detail::HLS2RGB functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + +///////////////////////////////////// RGB <-> Lab ///////////////////////////////////// + + namespace color_detail + { + enum + { + LAB_CBRT_TAB_SIZE = 1024, + GAMMA_TAB_SIZE = 1024, + lab_shift = xyz_shift, + gamma_shift = 3, + lab_shift2 = (lab_shift + gamma_shift), + LAB_CBRT_TAB_SIZE_B = (256 * 3 / 2 * (1 << gamma_shift)) + }; + + __constant__ ushort c_sRGBGammaTab_b[] = {0,1,1,2,2,3,4,4,5,6,6,7,8,8,9,10,11,11,12,13,14,15,16,17,19,20,21,22,24,25,26,28,29,31,33,34,36,38,40,41,43,45,47,49,51,54,56,58,60,63,65,68,70,73,75,78,81,83,86,89,92,95,98,101,105,108,111,115,118,121,125,129,132,136,140,144,147,151,155,160,164,168,172,176,181,185,190,194,199,204,209,213,218,223,228,233,239,244,249,255,260,265,271,277,282,288,294,300,306,312,318,324,331,337,343,350,356,363,370,376,383,390,397,404,411,418,426,433,440,448,455,463,471,478,486,494,502,510,518,527,535,543,552,560,569,578,586,595,604,613,622,631,641,650,659,669,678,688,698,707,717,727,737,747,757,768,778,788,799,809,820,831,842,852,863,875,886,897,908,920,931,943,954,966,978,990,1002,1014,1026,1038,1050,1063,1075,1088,1101,1113,1126,1139,1152,1165,1178,1192,1205,1218,1232,1245,1259,1273,1287,1301,1315,1329,1343,1357,1372,1386,1401,1415,1430,1445,1460,1475,1490,1505,1521,1536,1551,1567,1583,1598,1614,1630,1646,1662,1678,1695,1711,1728,1744,1761,1778,1794,1811,1828,1846,1863,1880,1897,1915,1933,1950,1968,1986,2004,2022,2040}; + + __device__ __forceinline__ int LabCbrt_b(int i) + { + float x = i * (1.f / (255.f * (1 << gamma_shift))); + return (1 << lab_shift2) * (x < 0.008856f ? x * 7.787f + 0.13793103448275862f : ::cbrtf(x)); + } + + template + __device__ __forceinline__ void RGB2LabConvert_b(const T& src, D& dst) + { + const int Lscale = (116 * 255 + 50) / 100; + const int Lshift = -((16 * 255 * (1 << lab_shift2) + 50) / 100); + + int B = blueIdx == 0 ? src.x : src.z; + int G = src.y; + int R = blueIdx == 0 ? src.z : src.x; + + if (srgb) + { + B = c_sRGBGammaTab_b[B]; + G = c_sRGBGammaTab_b[G]; + R = c_sRGBGammaTab_b[R]; + } + else + { + B <<= 3; + G <<= 3; + R <<= 3; + } + + int fX = LabCbrt_b(CV_DESCALE(B * 778 + G * 1541 + R * 1777, lab_shift)); + int fY = LabCbrt_b(CV_DESCALE(B * 296 + G * 2929 + R * 871, lab_shift)); + int fZ = LabCbrt_b(CV_DESCALE(B * 3575 + G * 448 + R * 73, lab_shift)); + + int L = CV_DESCALE(Lscale * fY + Lshift, lab_shift2); + int a = CV_DESCALE(500 * (fX - fY) + 128 * (1 << lab_shift2), lab_shift2); + int b = CV_DESCALE(200 * (fY - fZ) + 128 * (1 << lab_shift2), lab_shift2); + + dst.x = saturate_cast(L); + dst.y = saturate_cast(a); + dst.z = saturate_cast(b); + } + + __device__ __forceinline__ float splineInterpolate(float x, const float* tab, int n) + { + int ix = ::min(::max(int(x), 0), n-1); + x -= ix; + tab += ix * 4; + return ((tab[3] * x + tab[2]) * x + tab[1]) * x + tab[0]; + } + + __constant__ float c_sRGBGammaTab[] = {0,7.55853e-05,0.,-7.51331e-13,7.55853e-05,7.55853e-05,-2.25399e-12,3.75665e-12,0.000151171,7.55853e-05,9.01597e-12,-6.99932e-12,0.000226756,7.55853e-05,-1.1982e-11,2.41277e-12,0.000302341,7.55853e-05,-4.74369e-12,1.19001e-11,0.000377927,7.55853e-05,3.09568e-11,-2.09095e-11,0.000453512,7.55853e-05,-3.17718e-11,1.35303e-11,0.000529097,7.55853e-05,8.81905e-12,-4.10782e-12,0.000604683,7.55853e-05,-3.50439e-12,2.90097e-12,0.000680268,7.55853e-05,5.19852e-12,-7.49607e-12,0.000755853,7.55853e-05,-1.72897e-11,2.70833e-11,0.000831439,7.55854e-05,6.39602e-11,-4.26295e-11,0.000907024,7.55854e-05,-6.39282e-11,2.70193e-11,0.000982609,7.55853e-05,1.71298e-11,-7.24017e-12,0.00105819,7.55853e-05,-4.59077e-12,1.94137e-12,0.00113378,7.55853e-05,1.23333e-12,-5.25291e-13,0.00120937,7.55853e-05,-3.42545e-13,1.59799e-13,0.00128495,7.55853e-05,1.36852e-13,-1.13904e-13,0.00136054,7.55853e-05,-2.04861e-13,2.95818e-13,0.00143612,7.55853e-05,6.82594e-13,-1.06937e-12,0.00151171,7.55853e-05,-2.52551e-12,3.98166e-12,0.00158729,7.55853e-05,9.41946e-12,-1.48573e-11,0.00166288,7.55853e-05,-3.51523e-11,5.54474e-11,0.00173846,7.55854e-05,1.3119e-10,-9.0517e-11,0.00181405,7.55854e-05,-1.40361e-10,7.37899e-11,0.00188963,7.55853e-05,8.10085e-11,-8.82272e-11,0.00196522,7.55852e-05,-1.83673e-10,1.62704e-10,0.0020408,7.55853e-05,3.04438e-10,-2.13341e-10,0.00211639,7.55853e-05,-3.35586e-10,2.25e-10,0.00219197,7.55853e-05,3.39414e-10,-2.20997e-10,0.00226756,7.55853e-05,-3.23576e-10,1.93326e-10,0.00234315,7.55853e-05,2.564e-10,-8.66446e-11,0.00241873,7.55855e-05,-3.53328e-12,-7.9578e-11,0.00249432,7.55853e-05,-2.42267e-10,1.72126e-10,0.0025699,7.55853e-05,2.74111e-10,-1.43265e-10,0.00264549,7.55854e-05,-1.55683e-10,-6.47292e-11,0.00272107,7.55849e-05,-3.4987e-10,8.67842e-10,0.00279666,7.55868e-05,2.25366e-09,-3.8723e-09,0.00287224,7.55797e-05,-9.36325e-09,1.5087e-08,0.00294783,7.56063e-05,3.58978e-08,-5.69415e-08,0.00302341,7.55072e-05,-1.34927e-07,2.13144e-07,0.003099,7.58768e-05,5.04507e-07,1.38713e-07,0.00317552,7.7302e-05,9.20646e-07,-1.55186e-07,0.00325359,7.86777e-05,4.55087e-07,4.26813e-08,0.00333276,7.97159e-05,5.83131e-07,-1.06495e-08,0.00341305,8.08502e-05,5.51182e-07,3.87467e-09,0.00349446,8.19642e-05,5.62806e-07,-1.92586e-10,0.00357698,8.30892e-05,5.62228e-07,1.0866e-09,0.00366063,8.4217e-05,5.65488e-07,5.02818e-10,0.00374542,8.53494e-05,5.66997e-07,8.60211e-10,0.00383133,8.6486e-05,5.69577e-07,7.13044e-10,0.00391839,8.76273e-05,5.71716e-07,4.78527e-10,0.00400659,8.87722e-05,5.73152e-07,1.09818e-09,0.00409594,8.99218e-05,5.76447e-07,2.50964e-10,0.00418644,9.10754e-05,5.772e-07,1.15762e-09,0.00427809,9.22333e-05,5.80672e-07,2.40865e-10,0.0043709,9.33954e-05,5.81395e-07,1.13854e-09,0.00446488,9.45616e-05,5.84811e-07,3.27267e-10,0.00456003,9.57322e-05,5.85792e-07,8.1197e-10,0.00465635,9.69062e-05,5.88228e-07,6.15823e-10,0.00475384,9.80845e-05,5.90076e-07,9.15747e-10,0.00485252,9.92674e-05,5.92823e-07,3.778e-10,0.00495238,0.000100454,5.93956e-07,8.32623e-10,0.00505343,0.000101645,5.96454e-07,4.82695e-10,0.00515567,0.000102839,5.97902e-07,9.61904e-10,0.00525911,0.000104038,6.00788e-07,3.26281e-10,0.00536375,0.00010524,6.01767e-07,9.926e-10,0.00546959,0.000106447,6.04745e-07,3.59933e-10,0.00557664,0.000107657,6.05824e-07,8.2728e-10,0.0056849,0.000108871,6.08306e-07,5.21898e-10,0.00579438,0.00011009,6.09872e-07,8.10492e-10,0.00590508,0.000111312,6.12303e-07,4.27046e-10,0.00601701,0.000112538,6.13585e-07,7.40878e-10,0.00613016,0.000113767,6.15807e-07,8.00469e-10,0.00624454,0.000115001,6.18209e-07,2.48178e-10,0.00636016,0.000116238,6.18953e-07,1.00073e-09,0.00647702,0.000117479,6.21955e-07,4.05654e-10,0.00659512,0.000118724,6.23172e-07,6.36192e-10,0.00671447,0.000119973,6.25081e-07,7.74927e-10,0.00683507,0.000121225,6.27406e-07,4.54975e-10,0.00695692,0.000122481,6.28771e-07,6.64841e-10,0.00708003,0.000123741,6.30765e-07,6.10972e-10,0.00720441,0.000125004,6.32598e-07,6.16543e-10,0.00733004,0.000126271,6.34448e-07,6.48204e-10,0.00745695,0.000127542,6.36392e-07,5.15835e-10,0.00758513,0.000128816,6.3794e-07,5.48103e-10,0.00771458,0.000130094,6.39584e-07,1.01706e-09,0.00784532,0.000131376,6.42635e-07,4.0283e-11,0.00797734,0.000132661,6.42756e-07,6.84471e-10,0.00811064,0.000133949,6.4481e-07,9.47144e-10,0.00824524,0.000135241,6.47651e-07,1.83472e-10,0.00838112,0.000136537,6.48201e-07,1.11296e-09,0.00851831,0.000137837,6.5154e-07,2.13163e-11,0.0086568,0.00013914,6.51604e-07,6.64462e-10,0.00879659,0.000140445,6.53598e-07,1.04613e-09,0.00893769,0.000141756,6.56736e-07,-1.92377e-10,0.0090801,0.000143069,6.56159e-07,1.58601e-09,0.00922383,0.000144386,6.60917e-07,-5.63754e-10,0.00936888,0.000145706,6.59226e-07,1.60033e-09,0.00951524,0.000147029,6.64027e-07,-2.49543e-10,0.00966294,0.000148356,6.63278e-07,1.26043e-09,0.00981196,0.000149687,6.67059e-07,-1.35572e-10,0.00996231,0.00015102,6.66653e-07,1.14458e-09,0.010114,0.000152357,6.70086e-07,2.13864e-10,0.010267,0.000153698,6.70728e-07,7.93856e-10,0.0104214,0.000155042,6.73109e-07,3.36077e-10,0.0105771,0.000156389,6.74118e-07,6.55765e-10,0.0107342,0.000157739,6.76085e-07,7.66211e-10,0.0108926,0.000159094,6.78384e-07,4.66116e-12,0.0110524,0.000160451,6.78398e-07,1.07775e-09,0.0112135,0.000161811,6.81631e-07,3.41023e-10,0.011376,0.000163175,6.82654e-07,3.5205e-10,0.0115398,0.000164541,6.8371e-07,1.04473e-09,0.0117051,0.000165912,6.86844e-07,1.25757e-10,0.0118717,0.000167286,6.87222e-07,3.14818e-10,0.0120396,0.000168661,6.88166e-07,1.40886e-09,0.012209,0.000170042,6.92393e-07,-3.62244e-10,0.0123797,0.000171425,6.91306e-07,9.71397e-10,0.0125518,0.000172811,6.9422e-07,2.02003e-10,0.0127253,0.0001742,6.94826e-07,1.01448e-09,0.0129002,0.000175593,6.97869e-07,3.96653e-10,0.0130765,0.00017699,6.99059e-07,1.92927e-10,0.0132542,0.000178388,6.99638e-07,6.94305e-10,0.0134333,0.00017979,7.01721e-07,7.55108e-10,0.0136138,0.000181195,7.03986e-07,1.05918e-11,0.0137957,0.000182603,7.04018e-07,1.06513e-09,0.013979,0.000184015,7.07214e-07,3.85512e-10,0.0141637,0.00018543,7.0837e-07,1.86769e-10,0.0143499,0.000186848,7.0893e-07,7.30116e-10,0.0145374,0.000188268,7.11121e-07,6.17983e-10,0.0147264,0.000189692,7.12975e-07,5.23282e-10,0.0149168,0.000191119,7.14545e-07,8.28398e-11,0.0151087,0.000192549,7.14793e-07,1.0081e-09,0.0153019,0.000193981,7.17817e-07,5.41244e-10,0.0154966,0.000195418,7.19441e-07,-3.7907e-10,0.0156928,0.000196856,7.18304e-07,1.90641e-09,0.0158903,0.000198298,7.24023e-07,-7.27387e-10,0.0160893,0.000199744,7.21841e-07,1.00317e-09,0.0162898,0.000201191,7.24851e-07,4.39949e-10,0.0164917,0.000202642,7.2617e-07,9.6234e-10,0.0166951,0.000204097,7.29057e-07,-5.64019e-10,0.0168999,0.000205554,7.27365e-07,1.29374e-09,0.0171062,0.000207012,7.31247e-07,9.77025e-10,0.017314,0.000208478,7.34178e-07,-1.47651e-09,0.0175232,0.000209942,7.29748e-07,3.06636e-09,0.0177338,0.00021141,7.38947e-07,-1.47573e-09,0.017946,0.000212884,7.3452e-07,9.7386e-10,0.0181596,0.000214356,7.37442e-07,1.30562e-09,0.0183747,0.000215835,7.41358e-07,-6.08376e-10,0.0185913,0.000217315,7.39533e-07,1.12785e-09,0.0188093,0.000218798,7.42917e-07,-1.77711e-10,0.0190289,0.000220283,7.42384e-07,1.44562e-09,0.0192499,0.000221772,7.46721e-07,-1.68825e-11,0.0194724,0.000223266,7.4667e-07,4.84533e-10,0.0196964,0.000224761,7.48124e-07,-5.85298e-11,0.0199219,0.000226257,7.47948e-07,1.61217e-09,0.0201489,0.000227757,7.52785e-07,-8.02136e-10,0.0203775,0.00022926,7.50378e-07,1.59637e-09,0.0206075,0.000230766,7.55167e-07,4.47168e-12,0.020839,0.000232276,7.55181e-07,2.48387e-10,0.021072,0.000233787,7.55926e-07,8.6474e-10,0.0213066,0.000235302,7.5852e-07,1.78299e-11,0.0215426,0.000236819,7.58573e-07,9.26567e-10,0.0217802,0.000238339,7.61353e-07,1.34529e-12,0.0220193,0.000239862,7.61357e-07,9.30659e-10,0.0222599,0.000241387,7.64149e-07,1.34529e-12,0.0225021,0.000242915,7.64153e-07,9.26567e-10,0.0227458,0.000244447,7.66933e-07,1.76215e-11,0.022991,0.00024598,7.66986e-07,8.65536e-10,0.0232377,0.000247517,7.69582e-07,2.45677e-10,0.023486,0.000249057,7.70319e-07,1.44193e-11,0.0237358,0.000250598,7.70363e-07,1.55918e-09,0.0239872,0.000252143,7.7504e-07,-6.63173e-10,0.0242401,0.000253691,7.73051e-07,1.09357e-09,0.0244946,0.000255241,7.76331e-07,1.41919e-11,0.0247506,0.000256793,7.76374e-07,7.12248e-10,0.0250082,0.000258348,7.78511e-07,8.62049e-10,0.0252673,0.000259908,7.81097e-07,-4.35061e-10,0.025528,0.000261469,7.79792e-07,8.7825e-10,0.0257902,0.000263031,7.82426e-07,6.47181e-10,0.0260541,0.000264598,7.84368e-07,2.58448e-10,0.0263194,0.000266167,7.85143e-07,1.81558e-10,0.0265864,0.000267738,7.85688e-07,8.78041e-10,0.0268549,0.000269312,7.88322e-07,3.15102e-11,0.027125,0.000270889,7.88417e-07,8.58525e-10,0.0273967,0.000272468,7.90992e-07,2.59812e-10,0.02767,0.000274051,7.91772e-07,-3.5224e-11,0.0279448,0.000275634,7.91666e-07,1.74377e-09,0.0282212,0.000277223,7.96897e-07,-1.35196e-09,0.0284992,0.000278813,7.92841e-07,1.80141e-09,0.0287788,0.000280404,7.98246e-07,-2.65629e-10,0.0290601,0.000281999,7.97449e-07,1.12374e-09,0.0293428,0.000283598,8.0082e-07,-5.04106e-10,0.0296272,0.000285198,7.99308e-07,8.92764e-10,0.0299132,0.000286799,8.01986e-07,6.58379e-10,0.0302008,0.000288405,8.03961e-07,1.98971e-10,0.0304901,0.000290014,8.04558e-07,4.08382e-10,0.0307809,0.000291624,8.05783e-07,3.01839e-11,0.0310733,0.000293236,8.05874e-07,1.33343e-09,0.0313673,0.000294851,8.09874e-07,2.2419e-10,0.031663,0.000296472,8.10547e-07,-3.67606e-10,0.0319603,0.000298092,8.09444e-07,1.24624e-09,0.0322592,0.000299714,8.13182e-07,-8.92025e-10,0.0325597,0.000301338,8.10506e-07,2.32183e-09,0.0328619,0.000302966,8.17472e-07,-9.44719e-10,0.0331657,0.000304598,8.14638e-07,1.45703e-09,0.0334711,0.000306232,8.19009e-07,-1.15805e-09,0.0337781,0.000307866,8.15535e-07,3.17507e-09,0.0340868,0.000309507,8.2506e-07,-4.09161e-09,0.0343971,0.000311145,8.12785e-07,5.74079e-09,0.0347091,0.000312788,8.30007e-07,-3.97034e-09,0.0350227,0.000314436,8.18096e-07,2.68985e-09,0.035338,0.00031608,8.26166e-07,6.61676e-10,0.0356549,0.000317734,8.28151e-07,-1.61123e-09,0.0359734,0.000319386,8.23317e-07,2.05786e-09,0.0362936,0.000321038,8.29491e-07,8.30388e-10,0.0366155,0.0003227,8.31982e-07,-1.65424e-09,0.036939,0.000324359,8.27019e-07,2.06129e-09,0.0372642,0.000326019,8.33203e-07,8.59719e-10,0.0375911,0.000327688,8.35782e-07,-1.77488e-09,0.0379196,0.000329354,8.30458e-07,2.51464e-09,0.0382498,0.000331023,8.38002e-07,-8.33135e-10,0.0385817,0.000332696,8.35502e-07,8.17825e-10,0.0389152,0.00033437,8.37956e-07,1.28718e-09,0.0392504,0.00033605,8.41817e-07,-2.2413e-09,0.0395873,0.000337727,8.35093e-07,3.95265e-09,0.0399258,0.000339409,8.46951e-07,-2.39332e-09,0.0402661,0.000341095,8.39771e-07,1.89533e-09,0.040608,0.000342781,8.45457e-07,-1.46271e-09,0.0409517,0.000344467,8.41069e-07,3.95554e-09,0.041297,0.000346161,8.52936e-07,-3.18369e-09,0.041644,0.000347857,8.43385e-07,1.32873e-09,0.0419927,0.000349548,8.47371e-07,1.59402e-09,0.0423431,0.000351248,8.52153e-07,-2.54336e-10,0.0426952,0.000352951,8.5139e-07,-5.76676e-10,0.043049,0.000354652,8.4966e-07,2.56114e-09,0.0434045,0.000356359,8.57343e-07,-2.21744e-09,0.0437617,0.000358067,8.50691e-07,2.58344e-09,0.0441206,0.000359776,8.58441e-07,-6.65826e-10,0.0444813,0.000361491,8.56444e-07,7.99218e-11,0.0448436,0.000363204,8.56684e-07,3.46063e-10,0.0452077,0.000364919,8.57722e-07,2.26116e-09,0.0455734,0.000366641,8.64505e-07,-1.94005e-09,0.045941,0.000368364,8.58685e-07,1.77384e-09,0.0463102,0.000370087,8.64007e-07,-1.43005e-09,0.0466811,0.000371811,8.59717e-07,3.94634e-09,0.0470538,0.000373542,8.71556e-07,-3.17946e-09,0.0474282,0.000375276,8.62017e-07,1.32104e-09,0.0478043,0.000377003,8.6598e-07,1.62045e-09,0.0481822,0.00037874,8.70842e-07,-3.52297e-10,0.0485618,0.000380481,8.69785e-07,-2.11211e-10,0.0489432,0.00038222,8.69151e-07,1.19716e-09,0.0493263,0.000383962,8.72743e-07,-8.52026e-10,0.0497111,0.000385705,8.70187e-07,2.21092e-09,0.0500977,0.000387452,8.76819e-07,-5.41339e-10,0.050486,0.000389204,8.75195e-07,-4.5361e-11,0.0508761,0.000390954,8.75059e-07,7.22669e-10,0.0512679,0.000392706,8.77227e-07,8.79936e-10,0.0516615,0.000394463,8.79867e-07,-5.17048e-10,0.0520568,0.000396222,8.78316e-07,1.18833e-09,0.0524539,0.000397982,8.81881e-07,-5.11022e-10,0.0528528,0.000399744,8.80348e-07,8.55683e-10,0.0532534,0.000401507,8.82915e-07,8.13562e-10,0.0536558,0.000403276,8.85356e-07,-3.84603e-10,0.05406,0.000405045,8.84202e-07,7.24962e-10,0.0544659,0.000406816,8.86377e-07,1.20986e-09,0.0548736,0.000408592,8.90006e-07,-1.83896e-09,0.0552831,0.000410367,8.84489e-07,2.42071e-09,0.0556944,0.000412143,8.91751e-07,-3.93413e-10,0.0561074,0.000413925,8.90571e-07,-8.46967e-10,0.0565222,0.000415704,8.8803e-07,3.78122e-09,0.0569388,0.000417491,8.99374e-07,-3.1021e-09,0.0573572,0.000419281,8.90068e-07,1.17658e-09,0.0577774,0.000421064,8.93597e-07,2.12117e-09,0.0581993,0.000422858,8.99961e-07,-2.21068e-09,0.0586231,0.000424651,8.93329e-07,2.9961e-09,0.0590486,0.000426447,9.02317e-07,-2.32311e-09,0.059476,0.000428244,8.95348e-07,2.57122e-09,0.0599051,0.000430043,9.03062e-07,-5.11098e-10,0.0603361,0.000431847,9.01528e-07,-5.27166e-10,0.0607688,0.000433649,8.99947e-07,2.61984e-09,0.0612034,0.000435457,9.07806e-07,-2.50141e-09,0.0616397,0.000437265,9.00302e-07,3.66045e-09,0.0620779,0.000439076,9.11283e-07,-4.68977e-09,0.0625179,0.000440885,8.97214e-07,7.64783e-09,0.0629597,0.000442702,9.20158e-07,-7.27499e-09,0.0634033,0.000444521,8.98333e-07,6.55113e-09,0.0638487,0.000446337,9.17986e-07,-4.02844e-09,0.0642959,0.000448161,9.05901e-07,2.11196e-09,0.064745,0.000449979,9.12236e-07,3.03125e-09,0.0651959,0.000451813,9.2133e-07,-6.78648e-09,0.0656486,0.000453635,9.00971e-07,9.21375e-09,0.0661032,0.000455464,9.28612e-07,-7.71684e-09,0.0665596,0.000457299,9.05462e-07,6.7522e-09,0.0670178,0.00045913,9.25718e-07,-4.3907e-09,0.0674778,0.000460968,9.12546e-07,3.36e-09,0.0679397,0.000462803,9.22626e-07,-1.59876e-09,0.0684034,0.000464644,9.1783e-07,3.0351e-09,0.068869,0.000466488,9.26935e-07,-3.09101e-09,0.0693364,0.000468333,9.17662e-07,1.8785e-09,0.0698057,0.000470174,9.23298e-07,3.02733e-09,0.0702768,0.00047203,9.3238e-07,-6.53722e-09,0.0707497,0.000473875,9.12768e-07,8.22054e-09,0.0712245,0.000475725,9.37429e-07,-3.99325e-09,0.0717012,0.000477588,9.2545e-07,3.01839e-10,0.0721797,0.00047944,9.26355e-07,2.78597e-09,0.0726601,0.000481301,9.34713e-07,-3.99507e-09,0.0731423,0.000483158,9.22728e-07,5.7435e-09,0.0736264,0.000485021,9.39958e-07,-4.07776e-09,0.0741123,0.000486888,9.27725e-07,3.11695e-09,0.0746002,0.000488753,9.37076e-07,-9.39394e-10,0.0750898,0.000490625,9.34258e-07,6.4055e-10,0.0755814,0.000492495,9.3618e-07,-1.62265e-09,0.0760748,0.000494363,9.31312e-07,5.84995e-09,0.0765701,0.000496243,9.48861e-07,-6.87601e-09,0.0770673,0.00049812,9.28233e-07,6.75296e-09,0.0775664,0.000499997,9.48492e-07,-5.23467e-09,0.0780673,0.000501878,9.32788e-07,6.73523e-09,0.0785701,0.000503764,9.52994e-07,-6.80514e-09,0.0790748,0.000505649,9.32578e-07,5.5842e-09,0.0795814,0.000507531,9.49331e-07,-6.30583e-10,0.0800899,0.000509428,9.47439e-07,-3.0618e-09,0.0806003,0.000511314,9.38254e-07,5.4273e-09,0.0811125,0.000513206,9.54536e-07,-3.74627e-09,0.0816267,0.000515104,9.43297e-07,2.10713e-09,0.0821427,0.000516997,9.49618e-07,2.76839e-09,0.0826607,0.000518905,9.57924e-07,-5.73006e-09,0.0831805,0.000520803,9.40733e-07,5.25072e-09,0.0837023,0.0005227,9.56486e-07,-3.71718e-10,0.084226,0.000524612,9.5537e-07,-3.76404e-09,0.0847515,0.000526512,9.44078e-07,7.97735e-09,0.085279,0.000528424,9.6801e-07,-5.79367e-09,0.0858084,0.000530343,9.50629e-07,2.96268e-10,0.0863397,0.000532245,9.51518e-07,4.6086e-09,0.0868729,0.000534162,9.65344e-07,-3.82947e-09,0.087408,0.000536081,9.53856e-07,3.25861e-09,0.087945,0.000537998,9.63631e-07,-1.7543e-09,0.088484,0.00053992,9.58368e-07,3.75849e-09,0.0890249,0.000541848,9.69644e-07,-5.82891e-09,0.0895677,0.00054377,9.52157e-07,4.65593e-09,0.0901124,0.000545688,9.66125e-07,2.10643e-09,0.0906591,0.000547627,9.72444e-07,-5.63099e-09,0.0912077,0.000549555,9.55551e-07,5.51627e-09,0.0917582,0.000551483,9.721e-07,-1.53292e-09,0.0923106,0.000553422,9.67501e-07,6.15311e-10,0.092865,0.000555359,9.69347e-07,-9.28291e-10,0.0934213,0.000557295,9.66562e-07,3.09774e-09,0.0939796,0.000559237,9.75856e-07,-4.01186e-09,0.0945398,0.000561177,9.6382e-07,5.49892e-09,0.095102,0.000563121,9.80317e-07,-3.08258e-09,0.0956661,0.000565073,9.71069e-07,-6.19176e-10,0.0962321,0.000567013,9.69212e-07,5.55932e-09,0.0968001,0.000568968,9.8589e-07,-6.71704e-09,0.09737,0.00057092,9.65738e-07,6.40762e-09,0.0979419,0.00057287,9.84961e-07,-4.0122e-09,0.0985158,0.000574828,9.72925e-07,2.19059e-09,0.0990916,0.000576781,9.79496e-07,2.70048e-09,0.0996693,0.000578748,9.87598e-07,-5.54193e-09,0.100249,0.000580706,9.70972e-07,4.56597e-09,0.100831,0.000582662,9.8467e-07,2.17923e-09,0.101414,0.000584638,9.91208e-07,-5.83232e-09,0.102,0.000586603,9.73711e-07,6.24884e-09,0.102588,0.000588569,9.92457e-07,-4.26178e-09,0.103177,0.000590541,9.79672e-07,3.34781e-09,0.103769,0.00059251,9.89715e-07,-1.67904e-09,0.104362,0.000594485,9.84678e-07,3.36839e-09,0.104958,0.000596464,9.94783e-07,-4.34397e-09,0.105555,0.000598441,9.81751e-07,6.55696e-09,0.106155,0.000600424,1.00142e-06,-6.98272e-09,0.106756,0.000602406,9.80474e-07,6.4728e-09,0.107359,0.000604386,9.99893e-07,-4.00742e-09,0.107965,0.000606374,9.8787e-07,2.10654e-09,0.108572,0.000608356,9.9419e-07,3.0318e-09,0.109181,0.000610353,1.00329e-06,-6.7832e-09,0.109793,0.00061234,9.82936e-07,9.1998e-09,0.110406,0.000614333,1.01054e-06,-7.6642e-09,0.111021,0.000616331,9.87543e-07,6.55579e-09,0.111639,0.000618326,1.00721e-06,-3.65791e-09,0.112258,0.000620329,9.96236e-07,6.25467e-10,0.112879,0.000622324,9.98113e-07,1.15593e-09,0.113503,0.000624323,1.00158e-06,2.20158e-09,0.114128,0.000626333,1.00819e-06,-2.51191e-09,0.114755,0.000628342,1.00065e-06,3.95517e-10,0.115385,0.000630345,1.00184e-06,9.29807e-10,0.116016,0.000632351,1.00463e-06,3.33599e-09,0.116649,0.00063437,1.01463e-06,-6.82329e-09,0.117285,0.000636379,9.94163e-07,9.05595e-09,0.117922,0.000638395,1.02133e-06,-7.04862e-09,0.118562,0.000640416,1.00019e-06,4.23737e-09,0.119203,0.000642429,1.0129e-06,-2.45033e-09,0.119847,0.000644448,1.00555e-06,5.56395e-09,0.120492,0.000646475,1.02224e-06,-4.9043e-09,0.121139,0.000648505,1.00753e-06,-8.47952e-10,0.121789,0.000650518,1.00498e-06,8.29622e-09,0.122441,0.000652553,1.02987e-06,-9.98538e-09,0.123094,0.000654582,9.99914e-07,9.2936e-09,0.12375,0.00065661,1.02779e-06,-4.83707e-09,0.124407,0.000658651,1.01328e-06,2.60411e-09,0.125067,0.000660685,1.0211e-06,-5.57945e-09,0.125729,0.000662711,1.00436e-06,1.22631e-08,0.126392,0.000664756,1.04115e-06,-1.36704e-08,0.127058,0.000666798,1.00014e-06,1.26161e-08,0.127726,0.000668836,1.03798e-06,-6.99155e-09,0.128396,0.000670891,1.01701e-06,4.48836e-10,0.129068,0.000672926,1.01836e-06,5.19606e-09,0.129742,0.000674978,1.03394e-06,-6.3319e-09,0.130418,0.000677027,1.01495e-06,5.2305e-09,0.131096,0.000679073,1.03064e-06,3.11123e-10,0.131776,0.000681135,1.03157e-06,-6.47511e-09,0.132458,0.000683179,1.01215e-06,1.06882e-08,0.133142,0.000685235,1.04421e-06,-6.47519e-09,0.133829,0.000687304,1.02479e-06,3.11237e-10,0.134517,0.000689355,1.02572e-06,5.23035e-09,0.135207,0.000691422,1.04141e-06,-6.3316e-09,0.1359,0.000693486,1.02242e-06,5.19484e-09,0.136594,0.000695546,1.038e-06,4.53497e-10,0.137291,0.000697623,1.03936e-06,-7.00891e-09,0.137989,0.000699681,1.01834e-06,1.2681e-08,0.13869,0.000701756,1.05638e-06,-1.39128e-08,0.139393,0.000703827,1.01464e-06,1.31679e-08,0.140098,0.000705896,1.05414e-06,-8.95659e-09,0.140805,0.000707977,1.02727e-06,7.75742e-09,0.141514,0.000710055,1.05055e-06,-7.17182e-09,0.142225,0.000712135,1.02903e-06,6.02862e-09,0.142938,0.000714211,1.04712e-06,-2.04163e-09,0.143653,0.000716299,1.04099e-06,2.13792e-09,0.144371,0.000718387,1.04741e-06,-6.51009e-09,0.14509,0.000720462,1.02787e-06,9.00123e-09,0.145812,0.000722545,1.05488e-06,3.07523e-10,0.146535,0.000724656,1.0558e-06,-1.02312e-08,0.147261,0.000726737,1.02511e-06,1.0815e-08,0.147989,0.000728819,1.05755e-06,-3.22681e-09,0.148719,0.000730925,1.04787e-06,2.09244e-09,0.14945,0.000733027,1.05415e-06,-5.143e-09,0.150185,0.00073512,1.03872e-06,3.57844e-09,0.150921,0.000737208,1.04946e-06,5.73027e-09,0.151659,0.000739324,1.06665e-06,-1.15983e-08,0.152399,0.000741423,1.03185e-06,1.08605e-08,0.153142,0.000743519,1.06443e-06,-2.04106e-09,0.153886,0.000745642,1.05831e-06,-2.69642e-09,0.154633,0.00074775,1.05022e-06,-2.07425e-09,0.155382,0.000749844,1.044e-06,1.09934e-08,0.156133,0.000751965,1.07698e-06,-1.20972e-08,0.156886,0.000754083,1.04069e-06,7.59288e-09,0.157641,0.000756187,1.06347e-06,-3.37305e-09,0.158398,0.000758304,1.05335e-06,5.89921e-09,0.159158,0.000760428,1.07104e-06,-5.32248e-09,0.159919,0.000762554,1.05508e-06,4.8927e-10,0.160683,0.000764666,1.05654e-06,3.36547e-09,0.161448,0.000766789,1.06664e-06,9.50081e-10,0.162216,0.000768925,1.06949e-06,-7.16568e-09,0.162986,0.000771043,1.04799e-06,1.28114e-08,0.163758,0.000773177,1.08643e-06,-1.42774e-08,0.164533,0.000775307,1.0436e-06,1.44956e-08,0.165309,0.000777438,1.08708e-06,-1.39025e-08,0.166087,0.00077957,1.04538e-06,1.13118e-08,0.166868,0.000781695,1.07931e-06,-1.54224e-09,0.167651,0.000783849,1.07468e-06,-5.14312e-09,0.168436,0.000785983,1.05925e-06,7.21381e-09,0.169223,0.000788123,1.0809e-06,-8.81096e-09,0.170012,0.000790259,1.05446e-06,1.31289e-08,0.170803,0.000792407,1.09385e-06,-1.39022e-08,0.171597,0.000794553,1.05214e-06,1.26775e-08,0.172392,0.000796695,1.09018e-06,-7.00557e-09,0.17319,0.000798855,1.06916e-06,4.43796e-10,0.17399,0.000800994,1.07049e-06,5.23031e-09,0.174792,0.000803151,1.08618e-06,-6.46397e-09,0.175596,0.000805304,1.06679e-06,5.72444e-09,0.176403,0.000807455,1.08396e-06,-1.53254e-09,0.177211,0.000809618,1.07937e-06,4.05673e-10,0.178022,0.000811778,1.08058e-06,-9.01916e-11,0.178835,0.000813939,1.08031e-06,-4.49821e-11,0.17965,0.000816099,1.08018e-06,2.70234e-10,0.180467,0.00081826,1.08099e-06,-1.03603e-09,0.181286,0.000820419,1.07788e-06,3.87392e-09,0.182108,0.000822587,1.0895e-06,4.41522e-10,0.182932,0.000824767,1.09083e-06,-5.63997e-09,0.183758,0.000826932,1.07391e-06,7.21707e-09,0.184586,0.000829101,1.09556e-06,-8.32718e-09,0.185416,0.000831267,1.07058e-06,1.11907e-08,0.186248,0.000833442,1.10415e-06,-6.63336e-09,0.187083,0.00083563,1.08425e-06,4.41484e-10,0.187919,0.0008378,1.08557e-06,4.86754e-09,0.188758,0.000839986,1.10017e-06,-5.01041e-09,0.189599,0.000842171,1.08514e-06,2.72811e-10,0.190443,0.000844342,1.08596e-06,3.91916e-09,0.191288,0.000846526,1.09772e-06,-1.04819e-09,0.192136,0.000848718,1.09457e-06,2.73531e-10,0.192985,0.000850908,1.0954e-06,-4.58916e-11,0.193837,0.000853099,1.09526e-06,-9.01158e-11,0.194692,0.000855289,1.09499e-06,4.06506e-10,0.195548,0.00085748,1.09621e-06,-1.53595e-09,0.196407,0.000859668,1.0916e-06,5.73717e-09,0.197267,0.000861869,1.10881e-06,-6.51164e-09,0.19813,0.000864067,1.08928e-06,5.40831e-09,0.198995,0.000866261,1.1055e-06,-2.20401e-10,0.199863,0.000868472,1.10484e-06,-4.52652e-09,0.200732,0.000870668,1.09126e-06,3.42508e-09,0.201604,0.000872861,1.10153e-06,5.72762e-09,0.202478,0.000875081,1.11872e-06,-1.14344e-08,0.203354,0.000877284,1.08441e-06,1.02076e-08,0.204233,0.000879484,1.11504e-06,4.06355e-10,0.205113,0.000881715,1.11626e-06,-1.18329e-08,0.205996,0.000883912,1.08076e-06,1.71227e-08,0.206881,0.000886125,1.13213e-06,-1.19546e-08,0.207768,0.000888353,1.09626e-06,8.93465e-10,0.208658,0.000890548,1.09894e-06,8.38062e-09,0.209549,0.000892771,1.12408e-06,-4.61353e-09,0.210443,0.000895006,1.11024e-06,-4.82756e-09,0.211339,0.000897212,1.09576e-06,9.02245e-09,0.212238,0.00089943,1.12283e-06,-1.45997e-09,0.213138,0.000901672,1.11845e-06,-3.18255e-09,0.214041,0.000903899,1.1089e-06,-7.11073e-10,0.214946,0.000906115,1.10677e-06,6.02692e-09,0.215853,0.000908346,1.12485e-06,-8.49548e-09,0.216763,0.00091057,1.09936e-06,1.30537e-08,0.217675,0.000912808,1.13852e-06,-1.3917e-08,0.218588,0.000915044,1.09677e-06,1.28121e-08,0.219505,0.000917276,1.13521e-06,-7.5288e-09,0.220423,0.000919523,1.11262e-06,2.40205e-09,0.221344,0.000921756,1.11983e-06,-2.07941e-09,0.222267,0.000923989,1.11359e-06,5.91551e-09,0.223192,0.000926234,1.13134e-06,-6.68149e-09,0.224119,0.000928477,1.11129e-06,5.90929e-09,0.225049,0.000930717,1.12902e-06,-2.05436e-09,0.22598,0.000932969,1.12286e-06,2.30807e-09,0.226915,0.000935222,1.12978e-06,-7.17796e-09,0.227851,0.00093746,1.10825e-06,1.15028e-08,0.228789,0.000939711,1.14276e-06,-9.03083e-09,0.22973,0.000941969,1.11566e-06,9.71932e-09,0.230673,0.00094423,1.14482e-06,-1.49452e-08,0.231619,0.000946474,1.09998e-06,2.02591e-08,0.232566,0.000948735,1.16076e-06,-2.13879e-08,0.233516,0.000950993,1.0966e-06,2.05888e-08,0.234468,0.000953247,1.15837e-06,-1.62642e-08,0.235423,0.000955515,1.10957e-06,1.46658e-08,0.236379,0.000957779,1.15357e-06,-1.25966e-08,0.237338,0.000960048,1.11578e-06,5.91793e-09,0.238299,0.000962297,1.13353e-06,3.82602e-09,0.239263,0.000964576,1.14501e-06,-6.3208e-09,0.240229,0.000966847,1.12605e-06,6.55613e-09,0.241197,0.000969119,1.14572e-06,-5.00268e-09,0.242167,0.000971395,1.13071e-06,-1.44659e-09,0.243139,0.000973652,1.12637e-06,1.07891e-08,0.244114,0.000975937,1.15874e-06,-1.19073e-08,0.245091,0.000978219,1.12302e-06,7.03782e-09,0.246071,0.000980486,1.14413e-06,-1.34276e-09,0.247052,0.00098277,1.1401e-06,-1.66669e-09,0.248036,0.000985046,1.1351e-06,8.00935e-09,0.249022,0.00098734,1.15913e-06,-1.54694e-08,0.250011,0.000989612,1.11272e-06,2.4066e-08,0.251002,0.000991909,1.18492e-06,-2.11901e-08,0.251995,0.000994215,1.12135e-06,1.08973e-09,0.25299,0.000996461,1.12462e-06,1.68311e-08,0.253988,0.000998761,1.17511e-06,-8.8094e-09,0.254987,0.00100109,1.14868e-06,-1.13958e-08,0.25599,0.00100335,1.1145e-06,2.45902e-08,0.256994,0.00100565,1.18827e-06,-2.73603e-08,0.258001,0.00100795,1.10618e-06,2.52464e-08,0.25901,0.00101023,1.18192e-06,-1.40207e-08,0.260021,0.00101256,1.13986e-06,1.03387e-09,0.261035,0.00101484,1.14296e-06,9.8853e-09,0.262051,0.00101715,1.17262e-06,-1.07726e-08,0.263069,0.00101947,1.1403e-06,3.40272e-09,0.26409,0.00102176,1.15051e-06,-2.83827e-09,0.265113,0.00102405,1.142e-06,7.95039e-09,0.266138,0.00102636,1.16585e-06,8.39047e-10,0.267166,0.00102869,1.16836e-06,-1.13066e-08,0.268196,0.00103099,1.13444e-06,1.4585e-08,0.269228,0.00103331,1.1782e-06,-1.72314e-08,0.270262,0.00103561,1.1265e-06,2.45382e-08,0.271299,0.00103794,1.20012e-06,-2.13166e-08,0.272338,0.00104028,1.13617e-06,1.12364e-09,0.273379,0.00104255,1.13954e-06,1.68221e-08,0.274423,0.00104488,1.19001e-06,-8.80736e-09,0.275469,0.00104723,1.16358e-06,-1.13948e-08,0.276518,0.00104953,1.1294e-06,2.45839e-08,0.277568,0.00105186,1.20315e-06,-2.73361e-08,0.278621,0.00105418,1.12114e-06,2.51559e-08,0.279677,0.0010565,1.19661e-06,-1.36832e-08,0.280734,0.00105885,1.15556e-06,-2.25706e-10,0.281794,0.00106116,1.15488e-06,1.45862e-08,0.282857,0.00106352,1.19864e-06,-2.83167e-08,0.283921,0.00106583,1.11369e-06,3.90759e-08,0.284988,0.00106817,1.23092e-06,-3.85801e-08,0.286058,0.00107052,1.11518e-06,2.58375e-08,0.287129,0.00107283,1.19269e-06,-5.16498e-09,0.288203,0.0010752,1.1772e-06,-5.17768e-09,0.28928,0.00107754,1.16167e-06,-3.92671e-09,0.290358,0.00107985,1.14988e-06,2.08846e-08,0.29144,0.00108221,1.21254e-06,-2.00072e-08,0.292523,0.00108458,1.15252e-06,-4.60659e-10,0.293609,0.00108688,1.15114e-06,2.18499e-08,0.294697,0.00108925,1.21669e-06,-2.73343e-08,0.295787,0.0010916,1.13468e-06,2.78826e-08,0.29688,0.00109395,1.21833e-06,-2.45915e-08,0.297975,0.00109632,1.14456e-06,1.08787e-08,0.299073,0.00109864,1.17719e-06,1.08788e-08,0.300172,0.00110102,1.20983e-06,-2.45915e-08,0.301275,0.00110337,1.13605e-06,2.78828e-08,0.302379,0.00110573,1.2197e-06,-2.73348e-08,0.303486,0.00110808,1.1377e-06,2.18518e-08,0.304595,0.00111042,1.20325e-06,-4.67556e-10,0.305707,0.00111283,1.20185e-06,-1.99816e-08,0.306821,0.00111517,1.14191e-06,2.07891e-08,0.307937,0.00111752,1.20427e-06,-3.57026e-09,0.309056,0.00111992,1.19356e-06,-6.50797e-09,0.310177,0.00112228,1.17404e-06,-2.00165e-10,0.3113,0.00112463,1.17344e-06,7.30874e-09,0.312426,0.001127,1.19536e-06,7.67424e-10,0.313554,0.00112939,1.19767e-06,-1.03784e-08,0.314685,0.00113176,1.16653e-06,1.09437e-08,0.315818,0.00113412,1.19936e-06,-3.59406e-09,0.316953,0.00113651,1.18858e-06,3.43251e-09,0.318091,0.0011389,1.19888e-06,-1.0136e-08,0.319231,0.00114127,1.16847e-06,7.30915e-09,0.320374,0.00114363,1.1904e-06,1.07018e-08,0.321518,0.00114604,1.2225e-06,-2.03137e-08,0.322666,0.00114842,1.16156e-06,1.09484e-08,0.323815,0.00115078,1.19441e-06,6.32224e-09,0.324967,0.00115319,1.21337e-06,-6.43509e-09,0.326122,0.00115559,1.19407e-06,-1.03842e-08,0.327278,0.00115795,1.16291e-06,1.81697e-08,0.328438,0.00116033,1.21742e-06,-2.6901e-09,0.329599,0.00116276,1.20935e-06,-7.40939e-09,0.330763,0.00116515,1.18713e-06,2.52533e-09,0.331929,0.00116754,1.1947e-06,-2.69191e-09,0.333098,0.00116992,1.18663e-06,8.24218e-09,0.334269,0.00117232,1.21135e-06,-4.74377e-10,0.335443,0.00117474,1.20993e-06,-6.34471e-09,0.336619,0.00117714,1.1909e-06,-3.94922e-09,0.337797,0.00117951,1.17905e-06,2.21417e-08,0.338978,0.00118193,1.24547e-06,-2.50128e-08,0.340161,0.00118435,1.17043e-06,1.8305e-08,0.341346,0.00118674,1.22535e-06,-1.84048e-08,0.342534,0.00118914,1.17013e-06,2.55121e-08,0.343725,0.00119156,1.24667e-06,-2.40389e-08,0.344917,0.00119398,1.17455e-06,1.10389e-08,0.346113,0.00119636,1.20767e-06,9.68574e-09,0.34731,0.0011988,1.23673e-06,-1.99797e-08,0.34851,0.00120122,1.17679e-06,1.06284e-08,0.349713,0.0012036,1.20867e-06,7.26868e-09,0.350917,0.00120604,1.23048e-06,-9.90072e-09,0.352125,0.00120847,1.20078e-06,2.53177e-09,0.353334,0.00121088,1.20837e-06,-2.26199e-10,0.354546,0.0012133,1.20769e-06,-1.62705e-09,0.355761,0.00121571,1.20281e-06,6.73435e-09,0.356978,0.00121813,1.22302e-06,4.49207e-09,0.358197,0.00122059,1.23649e-06,-2.47027e-08,0.359419,0.00122299,1.16238e-06,3.47142e-08,0.360643,0.00122542,1.26653e-06,-2.47472e-08,0.36187,0.00122788,1.19229e-06,4.66965e-09,0.363099,0.00123028,1.20629e-06,6.06872e-09,0.36433,0.00123271,1.2245e-06,8.57729e-10,0.365564,0.00123516,1.22707e-06,-9.49952e-09,0.366801,0.00123759,1.19858e-06,7.33792e-09,0.36804,0.00124001,1.22059e-06,9.95025e-09,0.369281,0.00124248,1.25044e-06,-1.73366e-08,0.370525,0.00124493,1.19843e-06,-2.08464e-10,0.371771,0.00124732,1.1978e-06,1.81704e-08,0.373019,0.00124977,1.25232e-06,-1.28683e-08,0.37427,0.00125224,1.21371e-06,3.50042e-09,0.375524,0.00125468,1.22421e-06,-1.1335e-09,0.37678,0.00125712,1.22081e-06,1.03345e-09,0.378038,0.00125957,1.22391e-06,-3.00023e-09,0.379299,0.00126201,1.21491e-06,1.09676e-08,0.380562,0.00126447,1.24781e-06,-1.10676e-08,0.381828,0.00126693,1.21461e-06,3.50042e-09,0.383096,0.00126937,1.22511e-06,-2.93403e-09,0.384366,0.00127181,1.21631e-06,8.23574e-09,0.385639,0.00127427,1.24102e-06,-2.06607e-10,0.386915,0.00127675,1.2404e-06,-7.40935e-09,0.388193,0.00127921,1.21817e-06,4.1761e-11,0.389473,0.00128165,1.21829e-06,7.24223e-09,0.390756,0.0012841,1.24002e-06,7.91564e-10,0.392042,0.00128659,1.2424e-06,-1.04086e-08,0.393329,0.00128904,1.21117e-06,1.10405e-08,0.39462,0.0012915,1.24429e-06,-3.951e-09,0.395912,0.00129397,1.23244e-06,4.7634e-09,0.397208,0.00129645,1.24673e-06,-1.51025e-08,0.398505,0.0012989,1.20142e-06,2.58443e-08,0.399805,0.00130138,1.27895e-06,-2.86702e-08,0.401108,0.00130385,1.19294e-06,2.92318e-08,0.402413,0.00130632,1.28064e-06,-2.86524e-08,0.403721,0.0013088,1.19468e-06,2.57731e-08,0.405031,0.00131127,1.272e-06,-1.48355e-08,0.406343,0.00131377,1.2275e-06,3.76652e-09,0.407658,0.00131623,1.23879e-06,-2.30784e-10,0.408976,0.00131871,1.2381e-06,-2.84331e-09,0.410296,0.00132118,1.22957e-06,1.16041e-08,0.411618,0.00132367,1.26438e-06,-1.37708e-08,0.412943,0.00132616,1.22307e-06,1.36768e-08,0.41427,0.00132865,1.2641e-06,-1.1134e-08,0.4156,0.00133114,1.2307e-06,1.05714e-09,0.416933,0.00133361,1.23387e-06,6.90538e-09,0.418267,0.00133609,1.25459e-06,1.12372e-09,0.419605,0.00133861,1.25796e-06,-1.14002e-08,0.420945,0.00134109,1.22376e-06,1.46747e-08,0.422287,0.00134358,1.26778e-06,-1.7496e-08,0.423632,0.00134606,1.21529e-06,2.5507e-08,0.424979,0.00134857,1.29182e-06,-2.49272e-08,0.426329,0.00135108,1.21703e-06,1.45972e-08,0.427681,0.00135356,1.26083e-06,-3.65935e-09,0.429036,0.00135607,1.24985e-06,4.00178e-11,0.430393,0.00135857,1.24997e-06,3.49917e-09,0.431753,0.00136108,1.26047e-06,-1.40366e-08,0.433116,0.00136356,1.21836e-06,2.28448e-08,0.43448,0.00136606,1.28689e-06,-1.77378e-08,0.435848,0.00136858,1.23368e-06,1.83043e-08,0.437218,0.0013711,1.28859e-06,-2.56769e-08,0.43859,0.0013736,1.21156e-06,2.47987e-08,0.439965,0.0013761,1.28595e-06,-1.39133e-08,0.441342,0.00137863,1.24421e-06,1.05202e-09,0.442722,0.00138112,1.24737e-06,9.70507e-09,0.444104,0.00138365,1.27649e-06,-1.00698e-08,0.445489,0.00138617,1.24628e-06,7.72123e-10,0.446877,0.00138867,1.24859e-06,6.98132e-09,0.448267,0.00139118,1.26954e-06,1.10477e-09,0.449659,0.00139373,1.27285e-06,-1.14003e-08,0.451054,0.00139624,1.23865e-06,1.4694e-08,0.452452,0.00139876,1.28273e-06,-1.75734e-08,0.453852,0.00140127,1.23001e-06,2.5797e-08,0.455254,0.00140381,1.3074e-06,-2.60097e-08,0.456659,0.00140635,1.22937e-06,1.86371e-08,0.458067,0.00140886,1.28529e-06,-1.8736e-08,0.459477,0.00141137,1.22908e-06,2.65048e-08,0.46089,0.00141391,1.30859e-06,-2.76784e-08,0.462305,0.00141645,1.22556e-06,2.46043e-08,0.463722,0.00141897,1.29937e-06,-1.11341e-08,0.465143,0.00142154,1.26597e-06,-9.87033e-09,0.466565,0.00142404,1.23636e-06,2.08131e-08,0.467991,0.00142657,1.2988e-06,-1.37773e-08,0.469419,0.00142913,1.25746e-06,4.49378e-09,0.470849,0.00143166,1.27094e-06,-4.19781e-09,0.472282,0.00143419,1.25835e-06,1.22975e-08,0.473717,0.00143674,1.29524e-06,-1.51902e-08,0.475155,0.00143929,1.24967e-06,1.86608e-08,0.476596,0.00144184,1.30566e-06,-2.96506e-08,0.478039,0.00144436,1.2167e-06,4.03368e-08,0.479485,0.00144692,1.33771e-06,-4.22896e-08,0.480933,0.00144947,1.21085e-06,3.94148e-08,0.482384,0.00145201,1.32909e-06,-2.59626e-08,0.483837,0.00145459,1.2512e-06,4.83124e-09,0.485293,0.0014571,1.2657e-06,6.63757e-09,0.486751,0.00145966,1.28561e-06,-1.57911e-09,0.488212,0.00146222,1.28087e-06,-3.21468e-10,0.489676,0.00146478,1.27991e-06,2.86517e-09,0.491142,0.00146735,1.2885e-06,-1.11392e-08,0.49261,0.00146989,1.25508e-06,1.18893e-08,0.494081,0.00147244,1.29075e-06,-6.61574e-09,0.495555,0.001475,1.27091e-06,1.45736e-08,0.497031,0.00147759,1.31463e-06,-2.18759e-08,0.49851,0.00148015,1.249e-06,1.33252e-08,0.499992,0.00148269,1.28897e-06,-1.62277e-09,0.501476,0.00148526,1.28411e-06,-6.83421e-09,0.502962,0.00148781,1.2636e-06,2.89596e-08,0.504451,0.00149042,1.35048e-06,-4.93997e-08,0.505943,0.00149298,1.20228e-06,4.94299e-08,0.507437,0.00149553,1.35057e-06,-2.91107e-08,0.508934,0.00149814,1.26324e-06,7.40848e-09,0.510434,0.00150069,1.28547e-06,-5.23187e-10,0.511936,0.00150326,1.2839e-06,-5.31585e-09,0.51344,0.00150581,1.26795e-06,2.17866e-08,0.514947,0.00150841,1.33331e-06,-2.22257e-08,0.516457,0.00151101,1.26663e-06,7.51178e-09,0.517969,0.00151357,1.28917e-06,-7.82128e-09,0.519484,0.00151613,1.2657e-06,2.37733e-08,0.521002,0.00151873,1.33702e-06,-2.76674e-08,0.522522,0.00152132,1.25402e-06,2.72917e-08,0.524044,0.00152391,1.3359e-06,-2.18949e-08,0.525569,0.00152652,1.27021e-06,6.83372e-10,0.527097,0.00152906,1.27226e-06,1.91613e-08,0.528628,0.00153166,1.32974e-06,-1.77241e-08,0.53016,0.00153427,1.27657e-06,-7.86963e-09,0.531696,0.0015368,1.25296e-06,4.92027e-08,0.533234,0.00153945,1.40057e-06,-6.9732e-08,0.534775,0.00154204,1.19138e-06,5.09114e-08,0.536318,0.00154458,1.34411e-06,-1.4704e-08,0.537864,0.00154722,1.3e-06,7.9048e-09,0.539413,0.00154984,1.32371e-06,-1.69152e-08,0.540964,0.00155244,1.27297e-06,1.51355e-10,0.542517,0.00155499,1.27342e-06,1.63099e-08,0.544074,0.00155758,1.32235e-06,-5.78647e-09,0.545633,0.00156021,1.30499e-06,6.83599e-09,0.547194,0.00156284,1.3255e-06,-2.15575e-08,0.548758,0.00156543,1.26083e-06,1.97892e-08,0.550325,0.00156801,1.32019e-06,2.00525e-09,0.551894,0.00157065,1.32621e-06,-2.78103e-08,0.553466,0.00157322,1.24278e-06,4.96314e-08,0.555041,0.00157586,1.39167e-06,-5.1506e-08,0.556618,0.00157849,1.23716e-06,3.71835e-08,0.558198,0.00158107,1.34871e-06,-3.76233e-08,0.55978,0.00158366,1.23584e-06,5.37052e-08,0.561365,0.00158629,1.39695e-06,-5.79884e-08,0.562953,0.00158891,1.22299e-06,5.90392e-08,0.564543,0.00159153,1.4001e-06,-5.89592e-08,0.566136,0.00159416,1.22323e-06,5.7588e-08,0.567731,0.00159678,1.39599e-06,-5.21835e-08,0.569329,0.00159941,1.23944e-06,3.19369e-08,0.57093,0.00160199,1.33525e-06,-1.59594e-08,0.572533,0.00160461,1.28737e-06,3.19006e-08,0.574139,0.00160728,1.38307e-06,-5.20383e-08,0.575748,0.00160989,1.22696e-06,5.70431e-08,0.577359,0.00161251,1.39809e-06,-5.69247e-08,0.578973,0.00161514,1.22731e-06,5.14463e-08,0.580589,0.00161775,1.38165e-06,-2.9651e-08,0.582208,0.00162042,1.2927e-06,7.55339e-09,0.58383,0.00162303,1.31536e-06,-5.62636e-10,0.585455,0.00162566,1.31367e-06,-5.30281e-09,0.587081,0.00162827,1.29776e-06,2.17738e-08,0.588711,0.00163093,1.36309e-06,-2.21875e-08,0.590343,0.00163359,1.29652e-06,7.37164e-09,0.591978,0.00163621,1.31864e-06,-7.29907e-09,0.593616,0.00163882,1.29674e-06,2.18247e-08,0.595256,0.00164148,1.36221e-06,-2.03952e-08,0.596899,0.00164414,1.30103e-06,1.51241e-10,0.598544,0.00164675,1.30148e-06,1.97902e-08,0.600192,0.00164941,1.36085e-06,-1.97074e-08,0.601843,0.00165207,1.30173e-06,-5.65175e-10,0.603496,0.00165467,1.30004e-06,2.1968e-08,0.605152,0.00165734,1.36594e-06,-2.77024e-08,0.606811,0.00165999,1.28283e-06,2.92369e-08,0.608472,0.00166264,1.37054e-06,-2.96407e-08,0.610136,0.00166529,1.28162e-06,2.97215e-08,0.611803,0.00166795,1.37079e-06,-2.96408e-08,0.613472,0.0016706,1.28186e-06,2.92371e-08,0.615144,0.00167325,1.36957e-06,-2.77031e-08,0.616819,0.00167591,1.28647e-06,2.19708e-08,0.618496,0.00167855,1.35238e-06,-5.75407e-10,0.620176,0.00168125,1.35065e-06,-1.9669e-08,0.621858,0.00168389,1.29164e-06,1.96468e-08,0.623544,0.00168653,1.35058e-06,6.86403e-10,0.625232,0.00168924,1.35264e-06,-2.23924e-08,0.626922,0.00169187,1.28547e-06,2.92788e-08,0.628615,0.00169453,1.3733e-06,-3.51181e-08,0.630311,0.00169717,1.26795e-06,5.15889e-08,0.63201,0.00169987,1.42272e-06,-5.2028e-08,0.633711,0.00170255,1.26663e-06,3.73139e-08,0.635415,0.0017052,1.37857e-06,-3.76227e-08,0.637121,0.00170784,1.2657e-06,5.35722e-08,0.63883,0.00171054,1.42642e-06,-5.74567e-08,0.640542,0.00171322,1.25405e-06,5.70456e-08,0.642257,0.0017159,1.42519e-06,-5.15163e-08,0.643974,0.00171859,1.27064e-06,2.98103e-08,0.645694,0.00172122,1.36007e-06,-8.12016e-09,0.647417,0.00172392,1.33571e-06,2.67039e-09,0.649142,0.0017266,1.34372e-06,-2.56152e-09,0.65087,0.00172928,1.33604e-06,7.57571e-09,0.6526,0.00173197,1.35876e-06,-2.77413e-08,0.654334,0.00173461,1.27554e-06,4.3785e-08,0.65607,0.00173729,1.40689e-06,-2.81896e-08,0.657808,0.00174002,1.32233e-06,9.36893e-09,0.65955,0.00174269,1.35043e-06,-9.28617e-09,0.661294,0.00174536,1.32257e-06,2.77757e-08,0.66304,0.00174809,1.4059e-06,-4.2212e-08,0.66479,0.00175078,1.27926e-06,2.1863e-08,0.666542,0.0017534,1.34485e-06,1.43648e-08,0.668297,0.00175613,1.38795e-06,-1.97177e-08,0.670054,0.00175885,1.3288e-06,4.90115e-09,0.671814,0.00176152,1.3435e-06,1.13232e-10,0.673577,0.00176421,1.34384e-06,-5.3542e-09,0.675343,0.00176688,1.32778e-06,2.13035e-08,0.677111,0.0017696,1.39169e-06,-2.02553e-08,0.678882,0.00177232,1.33092e-06,1.13005e-10,0.680656,0.00177499,1.33126e-06,1.98031e-08,0.682432,0.00177771,1.39067e-06,-1.97211e-08,0.684211,0.00178043,1.33151e-06,-5.2349e-10,0.685993,0.00178309,1.32994e-06,2.18151e-08,0.687777,0.00178582,1.39538e-06,-2.71325e-08,0.689564,0.00178853,1.31398e-06,2.71101e-08,0.691354,0.00179124,1.39531e-06,-2.17035e-08,0.693147,0.00179396,1.3302e-06,9.92865e-11,0.694942,0.00179662,1.3305e-06,2.13063e-08,0.69674,0.00179935,1.39442e-06,-2.57198e-08,0.698541,0.00180206,1.31726e-06,2.19682e-08,0.700344,0.00180476,1.38317e-06,-2.54852e-09,0.70215,0.00180752,1.37552e-06,-1.17741e-08,0.703959,0.00181023,1.3402e-06,-9.95999e-09,0.705771,0.00181288,1.31032e-06,5.16141e-08,0.707585,0.00181566,1.46516e-06,-7.72869e-08,0.709402,0.00181836,1.2333e-06,7.87197e-08,0.711222,0.00182106,1.46946e-06,-5.87781e-08,0.713044,0.00182382,1.29312e-06,3.71834e-08,0.714869,0.00182652,1.40467e-06,-3.03511e-08,0.716697,0.00182924,1.31362e-06,2.46161e-08,0.718528,0.00183194,1.38747e-06,-8.5087e-09,0.720361,0.00183469,1.36194e-06,9.41892e-09,0.722197,0.00183744,1.3902e-06,-2.91671e-08,0.724036,0.00184014,1.3027e-06,4.76448e-08,0.725878,0.00184288,1.44563e-06,-4.22028e-08,0.727722,0.00184565,1.31902e-06,1.95682e-09,0.729569,0.00184829,1.3249e-06,3.43754e-08,0.731419,0.00185104,1.42802e-06,-2.0249e-08,0.733271,0.00185384,1.36727e-06,-1.29838e-08,0.735126,0.00185654,1.32832e-06,1.25794e-08,0.736984,0.00185923,1.36606e-06,2.22711e-08,0.738845,0.00186203,1.43287e-06,-4.20594e-08,0.740708,0.00186477,1.3067e-06,2.67571e-08,0.742574,0.00186746,1.38697e-06,-5.36424e-09,0.744443,0.00187022,1.37087e-06,-5.30023e-09,0.746315,0.00187295,1.35497e-06,2.65653e-08,0.748189,0.00187574,1.43467e-06,-4.13564e-08,0.750066,0.00187848,1.3106e-06,1.9651e-08,0.751946,0.00188116,1.36955e-06,2.23572e-08,0.753828,0.00188397,1.43663e-06,-4.9475e-08,0.755714,0.00188669,1.2882e-06,5.63335e-08,0.757602,0.00188944,1.4572e-06,-5.66499e-08,0.759493,0.00189218,1.28725e-06,5.10567e-08,0.761386,0.00189491,1.44042e-06,-2.83677e-08,0.763283,0.00189771,1.35532e-06,2.80962e-09,0.765182,0.00190042,1.36375e-06,1.71293e-08,0.767083,0.0019032,1.41513e-06,-1.17221e-08,0.768988,0.001906,1.37997e-06,-2.98453e-08,0.770895,0.00190867,1.29043e-06,7.14987e-08,0.772805,0.00191146,1.50493e-06,-7.73354e-08,0.774718,0.00191424,1.27292e-06,5.90292e-08,0.776634,0.00191697,1.45001e-06,-3.9572e-08,0.778552,0.00191975,1.33129e-06,3.9654e-08,0.780473,0.00192253,1.45026e-06,-5.94395e-08,0.782397,0.00192525,1.27194e-06,7.88945e-08,0.784324,0.00192803,1.50862e-06,-7.73249e-08,0.786253,0.00193082,1.27665e-06,5.15913e-08,0.788185,0.00193352,1.43142e-06,-9.83099e-09,0.79012,0.00193636,1.40193e-06,-1.22672e-08,0.792058,0.00193912,1.36513e-06,-7.05275e-10,0.793999,0.00194185,1.36301e-06,1.50883e-08,0.795942,0.00194462,1.40828e-06,-4.33147e-11,0.797888,0.00194744,1.40815e-06,-1.49151e-08,0.799837,0.00195021,1.3634e-06,9.93244e-11,0.801788,0.00195294,1.3637e-06,1.45179e-08,0.803743,0.00195571,1.40725e-06,1.43363e-09,0.8057,0.00195853,1.41155e-06,-2.02525e-08,0.80766,0.00196129,1.35079e-06,1.99718e-08,0.809622,0.00196405,1.41071e-06,-3.01649e-11,0.811588,0.00196687,1.41062e-06,-1.9851e-08,0.813556,0.00196964,1.35107e-06,1.98296e-08,0.815527,0.0019724,1.41056e-06,1.37485e-10,0.817501,0.00197522,1.41097e-06,-2.03796e-08,0.819477,0.00197798,1.34983e-06,2.17763e-08,0.821457,0.00198074,1.41516e-06,-7.12085e-09,0.823439,0.00198355,1.3938e-06,6.70707e-09,0.825424,0.00198636,1.41392e-06,-1.97074e-08,0.827412,0.00198913,1.35479e-06,1.25179e-08,0.829402,0.00199188,1.39235e-06,2.92405e-08,0.831396,0.00199475,1.48007e-06,-6.98755e-08,0.833392,0.0019975,1.27044e-06,7.14477e-08,0.835391,0.00200026,1.48479e-06,-3.71014e-08,0.837392,0.00200311,1.37348e-06,1.73533e-08,0.839397,0.00200591,1.42554e-06,-3.23118e-08,0.841404,0.00200867,1.32861e-06,5.2289e-08,0.843414,0.00201148,1.48547e-06,-5.76348e-08,0.845427,0.00201428,1.31257e-06,5.9041e-08,0.847443,0.00201708,1.48969e-06,-5.93197e-08,0.849461,0.00201988,1.31173e-06,5.90289e-08,0.851482,0.00202268,1.48882e-06,-5.75864e-08,0.853507,0.00202549,1.31606e-06,5.21075e-08,0.855533,0.00202828,1.47238e-06,-3.16344e-08,0.857563,0.00203113,1.37748e-06,1.48257e-08,0.859596,0.00203393,1.42196e-06,-2.76684e-08,0.861631,0.00203669,1.33895e-06,3.62433e-08,0.863669,0.00203947,1.44768e-06,1.90463e-09,0.86571,0.00204237,1.45339e-06,-4.38617e-08,0.867754,0.00204515,1.32181e-06,5.43328e-08,0.8698,0.00204796,1.48481e-06,-5.42603e-08,0.87185,0.00205076,1.32203e-06,4.34989e-08,0.873902,0.00205354,1.45252e-06,-5.26029e-10,0.875957,0.00205644,1.45095e-06,-4.13949e-08,0.878015,0.00205922,1.32676e-06,4.68962e-08,0.880075,0.00206201,1.46745e-06,-2.69807e-08,0.882139,0.00206487,1.38651e-06,1.42181e-09,0.884205,0.00206764,1.39077e-06,2.12935e-08,0.886274,0.00207049,1.45465e-06,-2.69912e-08,0.888346,0.00207332,1.37368e-06,2.70664e-08,0.890421,0.00207615,1.45488e-06,-2.16698e-08,0.892498,0.00207899,1.38987e-06,8.14756e-12,0.894579,0.00208177,1.38989e-06,2.16371e-08,0.896662,0.00208462,1.45481e-06,-2.6952e-08,0.898748,0.00208744,1.37395e-06,2.65663e-08,0.900837,0.00209027,1.45365e-06,-1.97084e-08,0.902928,0.00209312,1.39452e-06,-7.33731e-09,0.905023,0.00209589,1.37251e-06,4.90578e-08,0.90712,0.00209878,1.51968e-06,-6.96845e-08,0.90922,0.00210161,1.31063e-06,5.08664e-08,0.911323,0.00210438,1.46323e-06,-1.45717e-08,0.913429,0.00210727,1.41952e-06,7.42038e-09,0.915538,0.00211013,1.44178e-06,-1.51097e-08,0.917649,0.00211297,1.39645e-06,-6.58618e-09,0.919764,0.00211574,1.37669e-06,4.14545e-08,0.921881,0.00211862,1.50105e-06,-4.00222e-08,0.924001,0.0021215,1.38099e-06,-5.7518e-10,0.926124,0.00212426,1.37926e-06,4.23229e-08,0.92825,0.00212714,1.50623e-06,-4.9507e-08,0.930378,0.00213001,1.35771e-06,3.64958e-08,0.93251,0.00213283,1.4672e-06,-3.68713e-08,0.934644,0.00213566,1.35658e-06,5.13848e-08,0.936781,0.00213852,1.51074e-06,-4.94585e-08,0.938921,0.0021414,1.36236e-06,2.72399e-08,0.941064,0.0021442,1.44408e-06,1.0372e-10,0.943209,0.00214709,1.44439e-06,-2.76547e-08,0.945358,0.0021499,1.36143e-06,5.09106e-08,0.947509,0.00215277,1.51416e-06,-5.67784e-08,0.949663,0.00215563,1.34382e-06,5.69935e-08,0.95182,0.00215849,1.5148e-06,-5.19861e-08,0.95398,0.00216136,1.35885e-06,3.17417e-08,0.956143,0.00216418,1.45407e-06,-1.53758e-08,0.958309,0.00216704,1.40794e-06,2.97615e-08,0.960477,0.00216994,1.49723e-06,-4.40657e-08,0.962649,0.00217281,1.36503e-06,2.72919e-08,0.964823,0.00217562,1.44691e-06,-5.49729e-09,0.967,0.0021785,1.43041e-06,-5.30273e-09,0.96918,0.00218134,1.41451e-06,2.67084e-08,0.971363,0.00218425,1.49463e-06,-4.19265e-08,0.973548,0.00218711,1.36885e-06,2.17881e-08,0.975737,0.00218992,1.43422e-06,1.43789e-08,0.977928,0.00219283,1.47735e-06,-1.96989e-08,0.980122,0.00219572,1.41826e-06,4.81221e-09,0.98232,0.00219857,1.43269e-06,4.50048e-10,0.98452,0.00220144,1.43404e-06,-6.61237e-09,0.986722,0.00220429,1.41421e-06,2.59993e-08,0.988928,0.0022072,1.4922e-06,-3.77803e-08,0.991137,0.00221007,1.37886e-06,5.9127e-09,0.993348,0.00221284,1.3966e-06,1.33339e-07,0.995563,0.00221604,1.79662e-06,-5.98872e-07,0.99778,0.00222015,0.,0.}; + + template + __device__ __forceinline__ void RGB2LabConvert_f(const T& src, D& dst) + { + const float _1_3 = 1.0f / 3.0f; + const float _a = 16.0f / 116.0f; + + float B = blueIdx == 0 ? src.x : src.z; + float G = src.y; + float R = blueIdx == 0 ? src.z : src.x; + + if (srgb) + { + B = splineInterpolate(B * GAMMA_TAB_SIZE, c_sRGBGammaTab, GAMMA_TAB_SIZE); + G = splineInterpolate(G * GAMMA_TAB_SIZE, c_sRGBGammaTab, GAMMA_TAB_SIZE); + R = splineInterpolate(R * GAMMA_TAB_SIZE, c_sRGBGammaTab, GAMMA_TAB_SIZE); + } + + float X = B * 0.189828f + G * 0.376219f + R * 0.433953f; + float Y = B * 0.072169f + G * 0.715160f + R * 0.212671f; + float Z = B * 0.872766f + G * 0.109477f + R * 0.017758f; + + float FX = X > 0.008856f ? ::powf(X, _1_3) : (7.787f * X + _a); + float FY = Y > 0.008856f ? ::powf(Y, _1_3) : (7.787f * Y + _a); + float FZ = Z > 0.008856f ? ::powf(Z, _1_3) : (7.787f * Z + _a); + + float L = Y > 0.008856f ? (116.f * FY - 16.f) : (903.3f * Y); + float a = 500.f * (FX - FY); + float b = 200.f * (FY - FZ); + + dst.x = L; + dst.y = a; + dst.z = b; + } + + template struct RGB2Lab; + template + struct RGB2Lab + : unary_function::vec_type, typename TypeVec::vec_type> + { + __device__ __forceinline__ typename TypeVec::vec_type operator ()(const typename TypeVec::vec_type& src) const + { + typename TypeVec::vec_type dst; + + RGB2LabConvert_b(src, dst); + + return dst; + } + __host__ __device__ __forceinline__ RGB2Lab() {} + __host__ __device__ __forceinline__ RGB2Lab(const RGB2Lab&) {} + }; + template + struct RGB2Lab + : unary_function::vec_type, typename TypeVec::vec_type> + { + __device__ __forceinline__ typename TypeVec::vec_type operator ()(const typename TypeVec::vec_type& src) const + { + typename TypeVec::vec_type dst; + + RGB2LabConvert_f(src, dst); + + return dst; + } + __host__ __device__ __forceinline__ RGB2Lab() {} + __host__ __device__ __forceinline__ RGB2Lab(const RGB2Lab&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_RGB2Lab_TRAITS(name, scn, dcn, srgb, blueIdx) \ + template struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::RGB2Lab functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + + namespace color_detail + { + __constant__ float c_sRGBInvGammaTab[] = {0,0.0126255,0.,-8.33961e-06,0.0126172,0.0126005,-2.50188e-05,4.1698e-05,0.0252344,0.0126756,0.000100075,-0.000158451,0.0378516,0.0124004,-0.000375277,-0.000207393,0.0496693,0.0110276,-0.000997456,0.00016837,0.0598678,0.00953783,-0.000492346,2.07235e-05,0.068934,0.00861531,-0.000430176,3.62876e-05,0.0771554,0.00786382,-0.000321313,1.87625e-05,0.0847167,0.00727748,-0.000265025,1.53594e-05,0.0917445,0.00679351,-0.000218947,1.10545e-05,0.0983301,0.00638877,-0.000185784,8.66984e-06,0.104542,0.00604322,-0.000159774,6.82996e-06,0.110432,0.00574416,-0.000139284,5.51008e-06,0.116042,0.00548212,-0.000122754,4.52322e-06,0.121406,0.00525018,-0.000109184,3.75557e-06,0.126551,0.00504308,-9.79177e-05,3.17134e-06,0.131499,0.00485676,-8.84037e-05,2.68469e-06,0.13627,0.004688,-8.03496e-05,2.31725e-06,0.14088,0.00453426,-7.33978e-05,2.00868e-06,0.145343,0.00439349,-6.73718e-05,1.74775e-06,0.149671,0.00426399,-6.21286e-05,1.53547e-06,0.153875,0.00414434,-5.75222e-05,1.364e-06,0.157963,0.00403338,-5.34301e-05,1.20416e-06,0.161944,0.00393014,-4.98177e-05,1.09114e-06,0.165825,0.00383377,-4.65443e-05,9.57987e-07,0.169613,0.00374356,-4.36703e-05,8.88359e-07,0.173314,0.00365888,-4.10052e-05,7.7849e-07,0.176933,0.00357921,-3.86697e-05,7.36254e-07,0.180474,0.00350408,-3.6461e-05,6.42534e-07,0.183942,0.00343308,-3.45334e-05,6.12614e-07,0.187342,0.00336586,-3.26955e-05,5.42894e-07,0.190675,0.00330209,-3.10669e-05,5.08967e-07,0.193947,0.00324149,-2.954e-05,4.75977e-07,0.197159,0.00318383,-2.8112e-05,4.18343e-07,0.200315,0.00312887,-2.6857e-05,4.13651e-07,0.203418,0.00307639,-2.5616e-05,3.70847e-07,0.206469,0.00302627,-2.45035e-05,3.3813e-07,0.209471,0.00297828,-2.34891e-05,3.32999e-07,0.212426,0.0029323,-2.24901e-05,2.96826e-07,0.215336,0.00288821,-2.15996e-05,2.82736e-07,0.218203,0.00284586,-2.07514e-05,2.70961e-07,0.221029,0.00280517,-1.99385e-05,2.42744e-07,0.223814,0.00276602,-1.92103e-05,2.33277e-07,0.226561,0.0027283,-1.85105e-05,2.2486e-07,0.229271,0.00269195,-1.78359e-05,2.08383e-07,0.231945,0.00265691,-1.72108e-05,1.93305e-07,0.234585,0.00262307,-1.66308e-05,1.80687e-07,0.237192,0.00259035,-1.60888e-05,1.86632e-07,0.239766,0.00255873,-1.55289e-05,1.60569e-07,0.24231,0.00252815,-1.50472e-05,1.54566e-07,0.244823,0.00249852,-1.45835e-05,1.59939e-07,0.247307,0.00246983,-1.41037e-05,1.29549e-07,0.249763,0.00244202,-1.3715e-05,1.41429e-07,0.252191,0.00241501,-1.32907e-05,1.39198e-07,0.254593,0.00238885,-1.28731e-05,1.06444e-07,0.256969,0.00236342,-1.25538e-05,1.2048e-07,0.25932,0.00233867,-1.21924e-05,1.26892e-07,0.261647,0.00231467,-1.18117e-05,8.72084e-08,0.26395,0.00229131,-1.15501e-05,1.20323e-07,0.26623,0.00226857,-1.11891e-05,8.71514e-08,0.268487,0.00224645,-1.09276e-05,9.73165e-08,0.270723,0.00222489,-1.06357e-05,8.98259e-08,0.272937,0.00220389,-1.03662e-05,7.98218e-08,0.275131,0.00218339,-1.01267e-05,9.75254e-08,0.277304,0.00216343,-9.83416e-06,6.65195e-08,0.279458,0.00214396,-9.63461e-06,8.34313e-08,0.281592,0.00212494,-9.38431e-06,7.65919e-08,0.283708,0.00210641,-9.15454e-06,5.7236e-08,0.285805,0.00208827,-8.98283e-06,8.18939e-08,0.287885,0.00207055,-8.73715e-06,6.2224e-08,0.289946,0.00205326,-8.55047e-06,5.66388e-08,0.291991,0.00203633,-8.38056e-06,6.88491e-08,0.294019,0.00201978,-8.17401e-06,5.53955e-08,0.296031,0.00200359,-8.00782e-06,6.71971e-08,0.298027,0.00198778,-7.80623e-06,3.34439e-08,0.300007,0.00197227,-7.7059e-06,6.7248e-08,0.301971,0.00195706,-7.50416e-06,5.51915e-08,0.303921,0.00194221,-7.33858e-06,3.98124e-08,0.305856,0.00192766,-7.21915e-06,5.37795e-08,0.307776,0.00191338,-7.05781e-06,4.30919e-08,0.309683,0.00189939,-6.92853e-06,4.20744e-08,0.311575,0.00188566,-6.80231e-06,5.68321e-08,0.313454,0.00187223,-6.63181e-06,2.86195e-08,0.31532,0.00185905,-6.54595e-06,3.73075e-08,0.317172,0.00184607,-6.43403e-06,6.05684e-08,0.319012,0.00183338,-6.25233e-06,1.84426e-08,0.320839,0.00182094,-6.197e-06,4.44757e-08,0.322654,0.00180867,-6.06357e-06,4.20729e-08,0.324456,0.00179667,-5.93735e-06,2.56511e-08,0.326247,0.00178488,-5.8604e-06,3.41368e-08,0.328026,0.00177326,-5.75799e-06,4.64177e-08,0.329794,0.00176188,-5.61874e-06,1.86107e-08,0.33155,0.0017507,-5.5629e-06,2.81511e-08,0.333295,0.00173966,-5.47845e-06,4.75987e-08,0.335029,0.00172884,-5.33565e-06,1.98726e-08,0.336753,0.00171823,-5.27604e-06,2.19226e-08,0.338466,0.00170775,-5.21027e-06,4.14483e-08,0.340169,0.00169745,-5.08592e-06,2.09017e-08,0.341861,0.00168734,-5.02322e-06,2.39561e-08,0.343543,0.00167737,-4.95135e-06,3.22852e-08,0.345216,0.00166756,-4.85449e-06,2.57173e-08,0.346878,0.00165793,-4.77734e-06,1.38569e-08,0.348532,0.00164841,-4.73577e-06,3.80634e-08,0.350175,0.00163906,-4.62158e-06,1.27043e-08,0.35181,0.00162985,-4.58347e-06,3.03279e-08,0.353435,0.00162078,-4.49249e-06,1.49961e-08,0.355051,0.00161184,-4.4475e-06,2.88977e-08,0.356659,0.00160303,-4.3608e-06,1.84241e-08,0.358257,0.00159436,-4.30553e-06,1.6616e-08,0.359848,0.0015858,-4.25568e-06,3.43218e-08,0.361429,0.00157739,-4.15272e-06,-4.89172e-09,0.363002,0.00156907,-4.16739e-06,4.48498e-08,0.364567,0.00156087,-4.03284e-06,4.30676e-09,0.366124,0.00155282,-4.01992e-06,2.73303e-08,0.367673,0.00154486,-3.93793e-06,5.58036e-09,0.369214,0.001537,-3.92119e-06,3.97554e-08,0.370747,0.00152928,-3.80193e-06,-1.55904e-08,0.372272,0.00152163,-3.8487e-06,5.24081e-08,0.37379,0.00151409,-3.69147e-06,-1.52272e-08,0.375301,0.00150666,-3.73715e-06,3.83028e-08,0.376804,0.0014993,-3.62225e-06,1.10278e-08,0.378299,0.00149209,-3.58916e-06,6.99326e-09,0.379788,0.00148493,-3.56818e-06,2.06038e-08,0.381269,0.00147786,-3.50637e-06,2.98009e-08,0.382744,0.00147093,-3.41697e-06,-2.05978e-08,0.384211,0.00146404,-3.47876e-06,5.25899e-08,0.385672,0.00145724,-3.32099e-06,-1.09471e-08,0.387126,0.00145056,-3.35383e-06,2.10009e-08,0.388573,0.00144392,-3.29083e-06,1.63501e-08,0.390014,0.00143739,-3.24178e-06,3.00641e-09,0.391448,0.00143091,-3.23276e-06,3.12282e-08,0.392875,0.00142454,-3.13908e-06,-8.70932e-09,0.394297,0.00141824,-3.16521e-06,3.34114e-08,0.395712,0.00141201,-3.06497e-06,-5.72754e-09,0.397121,0.00140586,-3.08215e-06,1.9301e-08,0.398524,0.00139975,-3.02425e-06,1.7931e-08,0.39992,0.00139376,-2.97046e-06,-1.61822e-09,0.401311,0.00138781,-2.97531e-06,1.83442e-08,0.402696,0.00138192,-2.92028e-06,1.76485e-08,0.404075,0.00137613,-2.86733e-06,4.68617e-10,0.405448,0.00137039,-2.86593e-06,1.02794e-08,0.406816,0.00136469,-2.83509e-06,1.80179e-08,0.408178,0.00135908,-2.78104e-06,7.05594e-09,0.409534,0.00135354,-2.75987e-06,1.33633e-08,0.410885,0.00134806,-2.71978e-06,-9.04568e-10,0.41223,0.00134261,-2.72249e-06,2.0057e-08,0.41357,0.00133723,-2.66232e-06,1.00841e-08,0.414905,0.00133194,-2.63207e-06,-7.88835e-10,0.416234,0.00132667,-2.63444e-06,2.28734e-08,0.417558,0.00132147,-2.56582e-06,-1.29785e-09,0.418877,0.00131633,-2.56971e-06,1.21205e-08,0.420191,0.00131123,-2.53335e-06,1.24202e-08,0.421499,0.0013062,-2.49609e-06,-2.19681e-09,0.422803,0.0013012,-2.50268e-06,2.61696e-08,0.424102,0.00129628,-2.42417e-06,-1.30747e-08,0.425396,0.00129139,-2.46339e-06,2.6129e-08,0.426685,0.00128654,-2.38501e-06,-2.03454e-09,0.427969,0.00128176,-2.39111e-06,1.18115e-08,0.429248,0.00127702,-2.35567e-06,1.43932e-08,0.430523,0.00127235,-2.31249e-06,-9.77965e-09,0.431793,0.00126769,-2.34183e-06,2.47253e-08,0.433058,0.00126308,-2.26766e-06,2.85278e-10,0.434319,0.00125855,-2.2668e-06,3.93614e-09,0.435575,0.00125403,-2.25499e-06,1.37722e-08,0.436827,0.00124956,-2.21368e-06,5.79803e-10,0.438074,0.00124513,-2.21194e-06,1.37112e-08,0.439317,0.00124075,-2.1708e-06,4.17973e-09,0.440556,0.00123642,-2.15826e-06,-6.27703e-10,0.44179,0.0012321,-2.16015e-06,2.81332e-08,0.44302,0.00122787,-2.07575e-06,-2.24985e-08,0.444246,0.00122365,-2.14324e-06,3.20586e-08,0.445467,0.00121946,-2.04707e-06,-1.6329e-08,0.446685,0.00121532,-2.09605e-06,3.32573e-08,0.447898,0.00121122,-1.99628e-06,-2.72927e-08,0.449107,0.00120715,-2.07816e-06,4.6111e-08,0.450312,0.00120313,-1.93983e-06,-3.79416e-08,0.451514,0.00119914,-2.05365e-06,4.60507e-08,0.452711,0.00119517,-1.9155e-06,-2.7052e-08,0.453904,0.00119126,-1.99666e-06,3.23551e-08,0.455093,0.00118736,-1.89959e-06,-1.29613e-08,0.456279,0.00118352,-1.93848e-06,1.94905e-08,0.45746,0.0011797,-1.88e-06,-5.39588e-09,0.458638,0.00117593,-1.89619e-06,2.09282e-09,0.459812,0.00117214,-1.88991e-06,2.68267e-08,0.460982,0.00116844,-1.80943e-06,-1.99925e-08,0.462149,0.00116476,-1.86941e-06,2.3341e-08,0.463312,0.00116109,-1.79939e-06,-1.37674e-08,0.464471,0.00115745,-1.84069e-06,3.17287e-08,0.465627,0.00115387,-1.7455e-06,-2.37407e-08,0.466779,0.00115031,-1.81673e-06,3.34315e-08,0.467927,0.00114677,-1.71643e-06,-2.05786e-08,0.469073,0.00114328,-1.77817e-06,1.90802e-08,0.470214,0.00113978,-1.72093e-06,3.86247e-09,0.471352,0.00113635,-1.70934e-06,-4.72759e-09,0.472487,0.00113292,-1.72352e-06,1.50478e-08,0.473618,0.00112951,-1.67838e-06,4.14108e-09,0.474746,0.00112617,-1.66595e-06,-1.80986e-09,0.47587,0.00112283,-1.67138e-06,3.09816e-09,0.476991,0.0011195,-1.66209e-06,1.92198e-08,0.478109,0.00111623,-1.60443e-06,-2.03726e-08,0.479224,0.00111296,-1.66555e-06,3.2468e-08,0.480335,0.00110973,-1.56814e-06,-2.00922e-08,0.481443,0.00110653,-1.62842e-06,1.80983e-08,0.482548,0.00110333,-1.57413e-06,7.30362e-09,0.48365,0.0011002,-1.55221e-06,-1.75107e-08,0.484749,0.00109705,-1.60475e-06,3.29373e-08,0.485844,0.00109393,-1.50594e-06,-2.48315e-08,0.486937,0.00109085,-1.58043e-06,3.65865e-08,0.488026,0.0010878,-1.47067e-06,-3.21078e-08,0.489112,0.00108476,-1.56699e-06,3.22397e-08,0.490195,0.00108172,-1.47027e-06,-7.44391e-09,0.491276,0.00107876,-1.49261e-06,-2.46428e-09,0.492353,0.00107577,-1.5e-06,1.73011e-08,0.493427,0.00107282,-1.4481e-06,-7.13552e-09,0.494499,0.0010699,-1.4695e-06,1.1241e-08,0.495567,0.001067,-1.43578e-06,-8.02637e-09,0.496633,0.0010641,-1.45986e-06,2.08645e-08,0.497695,0.00106124,-1.39726e-06,-1.58271e-08,0.498755,0.0010584,-1.44475e-06,1.26415e-08,0.499812,0.00105555,-1.40682e-06,2.48655e-08,0.500866,0.00105281,-1.33222e-06,-5.24988e-08,0.501918,0.00104999,-1.48972e-06,6.59206e-08,0.502966,0.00104721,-1.29196e-06,-3.237e-08,0.504012,0.00104453,-1.38907e-06,3.95479e-09,0.505055,0.00104176,-1.3772e-06,1.65509e-08,0.506096,0.00103905,-1.32755e-06,-1.05539e-08,0.507133,0.00103637,-1.35921e-06,2.56648e-08,0.508168,0.00103373,-1.28222e-06,-3.25007e-08,0.509201,0.00103106,-1.37972e-06,4.47336e-08,0.51023,0.00102844,-1.24552e-06,-2.72245e-08,0.511258,0.00102587,-1.32719e-06,4.55952e-09,0.512282,0.00102323,-1.31352e-06,8.98645e-09,0.513304,0.00102063,-1.28656e-06,1.90992e-08,0.514323,0.00101811,-1.22926e-06,-2.57786e-08,0.51534,0.00101557,-1.30659e-06,2.44104e-08,0.516355,0.00101303,-1.23336e-06,-1.22581e-08,0.517366,0.00101053,-1.27014e-06,2.4622e-08,0.518376,0.00100806,-1.19627e-06,-2.66253e-08,0.519383,0.00100559,-1.27615e-06,2.22744e-08,0.520387,0.00100311,-1.20932e-06,-2.8679e-09,0.521389,0.00100068,-1.21793e-06,-1.08029e-08,0.522388,0.000998211,-1.25034e-06,4.60795e-08,0.523385,0.000995849,-1.1121e-06,-5.4306e-08,0.52438,0.000993462,-1.27502e-06,5.19354e-08,0.525372,0.000991067,-1.11921e-06,-3.42262e-08,0.526362,0.000988726,-1.22189e-06,2.53646e-08,0.52735,0.000986359,-1.14579e-06,-7.62782e-09,0.528335,0.000984044,-1.16868e-06,5.14668e-09,0.529318,0.000981722,-1.15324e-06,-1.29589e-08,0.530298,0.000979377,-1.19211e-06,4.66888e-08,0.531276,0.000977133,-1.05205e-06,-5.45868e-08,0.532252,0.000974865,-1.21581e-06,5.24495e-08,0.533226,0.000972591,-1.05846e-06,-3.60019e-08,0.534198,0.000970366,-1.16647e-06,3.19537e-08,0.535167,0.000968129,-1.07061e-06,-3.2208e-08,0.536134,0.000965891,-1.16723e-06,3.72738e-08,0.537099,0.000963668,-1.05541e-06,2.32205e-09,0.538061,0.000961564,-1.04844e-06,-4.65618e-08,0.539022,0.000959328,-1.18813e-06,6.47159e-08,0.53998,0.000957146,-9.93979e-07,-3.3488e-08,0.540936,0.000955057,-1.09444e-06,9.63166e-09,0.54189,0.000952897,-1.06555e-06,-5.03871e-09,0.542842,0.000950751,-1.08066e-06,1.05232e-08,0.543792,0.000948621,-1.04909e-06,2.25503e-08,0.544739,0.000946591,-9.81444e-07,-4.11195e-08,0.545685,0.000944504,-1.1048e-06,2.27182e-08,0.546628,0.000942363,-1.03665e-06,9.85146e-09,0.54757,0.000940319,-1.00709e-06,-2.51938e-09,0.548509,0.000938297,-1.01465e-06,2.25858e-10,0.549446,0.000936269,-1.01397e-06,1.61598e-09,0.550381,0.000934246,-1.00913e-06,-6.68983e-09,0.551315,0.000932207,-1.0292e-06,2.51434e-08,0.552246,0.000930224,-9.53765e-07,-3.42793e-08,0.553175,0.000928214,-1.0566e-06,5.23688e-08,0.554102,0.000926258,-8.99497e-07,-5.59865e-08,0.555028,0.000924291,-1.06746e-06,5.23679e-08,0.555951,0.000922313,-9.10352e-07,-3.42763e-08,0.556872,0.00092039,-1.01318e-06,2.51326e-08,0.557792,0.000918439,-9.37783e-07,-6.64954e-09,0.558709,0.000916543,-9.57732e-07,1.46554e-09,0.559625,0.000914632,-9.53335e-07,7.87281e-10,0.560538,0.000912728,-9.50973e-07,-4.61466e-09,0.56145,0.000910812,-9.64817e-07,1.76713e-08,0.56236,0.000908935,-9.11804e-07,-6.46564e-09,0.563268,0.000907092,-9.312e-07,8.19121e-09,0.564174,0.000905255,-9.06627e-07,-2.62992e-08,0.565078,0.000903362,-9.85524e-07,3.74007e-08,0.565981,0.000901504,-8.73322e-07,-4.0942e-09,0.566882,0.000899745,-8.85605e-07,-2.1024e-08,0.56778,0.00089791,-9.48677e-07,2.85854e-08,0.568677,0.000896099,-8.62921e-07,-3.3713e-08,0.569573,0.000894272,-9.64059e-07,4.6662e-08,0.570466,0.000892484,-8.24073e-07,-3.37258e-08,0.571358,0.000890734,-9.25251e-07,2.86365e-08,0.572247,0.00088897,-8.39341e-07,-2.12155e-08,0.573135,0.000887227,-9.02988e-07,-3.37913e-09,0.574022,0.000885411,-9.13125e-07,3.47319e-08,0.574906,0.000883689,-8.08929e-07,-1.63394e-08,0.575789,0.000882022,-8.57947e-07,-2.8979e-08,0.57667,0.00088022,-9.44885e-07,7.26509e-08,0.57755,0.000878548,-7.26932e-07,-8.28106e-08,0.578427,0.000876845,-9.75364e-07,7.97774e-08,0.579303,0.000875134,-7.36032e-07,-5.74849e-08,0.580178,0.00087349,-9.08486e-07,3.09529e-08,0.58105,0.000871765,-8.15628e-07,-6.72206e-09,0.581921,0.000870114,-8.35794e-07,-4.06451e-09,0.582791,0.00086843,-8.47987e-07,2.29799e-08,0.583658,0.000866803,-7.79048e-07,-2.82503e-08,0.584524,0.00086516,-8.63799e-07,3.04167e-08,0.585388,0.000863524,-7.72548e-07,-3.38119e-08,0.586251,0.000861877,-8.73984e-07,4.52264e-08,0.587112,0.000860265,-7.38305e-07,-2.78842e-08,0.587972,0.000858705,-8.21958e-07,6.70567e-09,0.58883,0.000857081,-8.01841e-07,1.06161e-09,0.589686,0.000855481,-7.98656e-07,-1.09521e-08,0.590541,0.00085385,-8.31512e-07,4.27468e-08,0.591394,0.000852316,-7.03272e-07,-4.08257e-08,0.592245,0.000850787,-8.25749e-07,1.34677e-09,0.593095,0.000849139,-8.21709e-07,3.54387e-08,0.593944,0.000847602,-7.15393e-07,-2.38924e-08,0.59479,0.0008461,-7.8707e-07,5.26143e-10,0.595636,0.000844527,-7.85491e-07,2.17879e-08,0.596479,0.000843021,-7.20127e-07,-2.80733e-08,0.597322,0.000841497,-8.04347e-07,3.09005e-08,0.598162,0.000839981,-7.11646e-07,-3.5924e-08,0.599002,0.00083845,-8.19418e-07,5.3191e-08,0.599839,0.000836971,-6.59845e-07,-5.76307e-08,0.600676,0.000835478,-8.32737e-07,5.81227e-08,0.60151,0.000833987,-6.58369e-07,-5.56507e-08,0.602344,0.000832503,-8.25321e-07,4.52706e-08,0.603175,0.000830988,-6.89509e-07,-6.22236e-09,0.604006,0.000829591,-7.08176e-07,-2.03811e-08,0.604834,0.000828113,-7.6932e-07,2.8142e-08,0.605662,0.000826659,-6.84894e-07,-3.25822e-08,0.606488,0.000825191,-7.8264e-07,4.25823e-08,0.607312,0.000823754,-6.54893e-07,-1.85376e-08,0.608135,0.000822389,-7.10506e-07,-2.80365e-08,0.608957,0.000820883,-7.94616e-07,7.1079e-08,0.609777,0.000819507,-5.81379e-07,-7.74655e-08,0.610596,0.000818112,-8.13775e-07,5.9969e-08,0.611413,0.000816665,-6.33868e-07,-4.32013e-08,0.612229,0.000815267,-7.63472e-07,5.32313e-08,0.613044,0.0008139,-6.03778e-07,-5.05148e-08,0.613857,0.000812541,-7.55323e-07,2.96187e-08,0.614669,0.000811119,-6.66466e-07,-8.35545e-09,0.615479,0.000809761,-6.91533e-07,3.80301e-09,0.616288,0.00080839,-6.80124e-07,-6.85666e-09,0.617096,0.000807009,-7.00694e-07,2.36237e-08,0.617903,0.000805678,-6.29822e-07,-2.80336e-08,0.618708,0.000804334,-7.13923e-07,2.8906e-08,0.619511,0.000802993,-6.27205e-07,-2.79859e-08,0.620314,0.000801655,-7.11163e-07,2.34329e-08,0.621114,0.000800303,-6.40864e-07,-6.14108e-09,0.621914,0.000799003,-6.59287e-07,1.13151e-09,0.622712,0.000797688,-6.55893e-07,1.61507e-09,0.62351,0.000796381,-6.51048e-07,-7.59186e-09,0.624305,0.000795056,-6.73823e-07,2.87524e-08,0.6251,0.000793794,-5.87566e-07,-4.7813e-08,0.625893,0.000792476,-7.31005e-07,4.32901e-08,0.626685,0.000791144,-6.01135e-07,-6.13814e-09,0.627475,0.000789923,-6.19549e-07,-1.87376e-08,0.628264,0.000788628,-6.75762e-07,2.14837e-08,0.629052,0.000787341,-6.11311e-07,-7.59265e-09,0.629839,0.000786095,-6.34089e-07,8.88692e-09,0.630625,0.000784854,-6.07428e-07,-2.7955e-08,0.631409,0.000783555,-6.91293e-07,4.33285e-08,0.632192,0.000782302,-5.61307e-07,-2.61497e-08,0.632973,0.000781101,-6.39757e-07,1.6658e-09,0.633754,0.000779827,-6.34759e-07,1.94866e-08,0.634533,0.000778616,-5.76299e-07,-2.00076e-08,0.635311,0.000777403,-6.36322e-07,9.39091e-10,0.636088,0.000776133,-6.33505e-07,1.62512e-08,0.636863,0.000774915,-5.84751e-07,-6.33937e-09,0.637638,0.000773726,-6.03769e-07,9.10609e-09,0.638411,0.000772546,-5.76451e-07,-3.00849e-08,0.639183,0.000771303,-6.66706e-07,5.1629e-08,0.639953,0.000770125,-5.11819e-07,-5.7222e-08,0.640723,0.000768929,-6.83485e-07,5.80497e-08,0.641491,0.000767736,-5.09336e-07,-5.57674e-08,0.642259,0.000766551,-6.76638e-07,4.58105e-08,0.643024,0.000765335,-5.39206e-07,-8.26541e-09,0.643789,0.000764231,-5.64002e-07,-1.27488e-08,0.644553,0.000763065,-6.02249e-07,-3.44168e-10,0.645315,0.00076186,-6.03281e-07,1.41254e-08,0.646077,0.000760695,-5.60905e-07,3.44727e-09,0.646837,0.000759584,-5.50563e-07,-2.79144e-08,0.647596,0.000758399,-6.34307e-07,4.86057e-08,0.648354,0.000757276,-4.88489e-07,-4.72989e-08,0.64911,0.000756158,-6.30386e-07,2.13807e-08,0.649866,0.000754961,-5.66244e-07,2.13808e-08,0.65062,0.000753893,-5.02102e-07,-4.7299e-08,0.651374,0.000752746,-6.43999e-07,4.86059e-08,0.652126,0.000751604,-4.98181e-07,-2.79154e-08,0.652877,0.000750524,-5.81927e-07,3.45089e-09,0.653627,0.000749371,-5.71575e-07,1.41119e-08,0.654376,0.00074827,-5.29239e-07,-2.93748e-10,0.655123,0.00074721,-5.3012e-07,-1.29368e-08,0.65587,0.000746111,-5.68931e-07,-7.56355e-09,0.656616,0.000744951,-5.91621e-07,4.3191e-08,0.65736,0.000743897,-4.62048e-07,-4.59911e-08,0.658103,0.000742835,-6.00022e-07,2.15642e-08,0.658846,0.0007417,-5.35329e-07,1.93389e-08,0.659587,0.000740687,-4.77312e-07,-3.93152e-08,0.660327,0.000739615,-5.95258e-07,1.87126e-08,0.661066,0.00073848,-5.3912e-07,2.40695e-08,0.661804,0.000737474,-4.66912e-07,-5.53859e-08,0.662541,0.000736374,-6.33069e-07,7.82648e-08,0.663277,0.000735343,-3.98275e-07,-7.88593e-08,0.664012,0.00073431,-6.34853e-07,5.83585e-08,0.664745,0.000733215,-4.59777e-07,-3.53656e-08,0.665478,0.000732189,-5.65874e-07,2.34994e-08,0.66621,0.000731128,-4.95376e-07,9.72743e-10,0.66694,0.00073014,-4.92458e-07,-2.73903e-08,0.66767,0.000729073,-5.74629e-07,4.89839e-08,0.668398,0.000728071,-4.27677e-07,-4.93359e-08,0.669126,0.000727068,-5.75685e-07,2.91504e-08,0.669853,0.000726004,-4.88234e-07,-7.66109e-09,0.670578,0.000725004,-5.11217e-07,1.49392e-09,0.671303,0.000723986,-5.06735e-07,1.68533e-09,0.672026,0.000722978,-5.01679e-07,-8.23525e-09,0.672749,0.00072195,-5.26385e-07,3.12556e-08,0.67347,0.000720991,-4.32618e-07,-5.71825e-08,0.674191,0.000719954,-6.04166e-07,7.8265e-08,0.67491,0.00071898,-3.69371e-07,-7.70634e-08,0.675628,0.00071801,-6.00561e-07,5.11747e-08,0.676346,0.000716963,-4.47037e-07,-8.42615e-09,0.677062,0.000716044,-4.72315e-07,-1.747e-08,0.677778,0.000715046,-5.24725e-07,1.87015e-08,0.678493,0.000714053,-4.68621e-07,2.26856e-09,0.679206,0.000713123,-4.61815e-07,-2.77758e-08,0.679919,0.000712116,-5.45142e-07,4.92298e-08,0.68063,0.000711173,-3.97453e-07,-4.99339e-08,0.681341,0.000710228,-5.47255e-07,3.12967e-08,0.682051,0.000709228,-4.53365e-07,-1.56481e-08,0.68276,0.000708274,-5.00309e-07,3.12958e-08,0.683467,0.000707367,-4.06422e-07,-4.99303e-08,0.684174,0.000706405,-5.56213e-07,4.9216e-08,0.68488,0.00070544,-4.08565e-07,-2.77245e-08,0.685585,0.00070454,-4.91738e-07,2.07748e-09,0.686289,0.000703562,-4.85506e-07,1.94146e-08,0.686992,0.00070265,-4.27262e-07,-2.01314e-08,0.687695,0.000701735,-4.87656e-07,1.50616e-09,0.688396,0.000700764,-4.83137e-07,1.41067e-08,0.689096,0.00069984,-4.40817e-07,1.67168e-09,0.689795,0.000698963,-4.35802e-07,-2.07934e-08,0.690494,0.000698029,-4.98182e-07,2.18972e-08,0.691192,0.000697099,-4.32491e-07,-7.19092e-09,0.691888,0.000696212,-4.54064e-07,6.86642e-09,0.692584,0.000695325,-4.33464e-07,-2.02747e-08,0.693279,0.000694397,-4.94288e-07,1.46279e-08,0.693973,0.000693452,-4.50405e-07,2.13678e-08,0.694666,0.000692616,-3.86301e-07,-4.04945e-08,0.695358,0.000691721,-5.07785e-07,2.14009e-08,0.696049,0.00069077,-4.43582e-07,1.44955e-08,0.69674,0.000689926,-4.00096e-07,-1.97783e-08,0.697429,0.000689067,-4.5943e-07,5.01296e-09,0.698118,0.000688163,-4.44392e-07,-2.73521e-10,0.698805,0.000687273,-4.45212e-07,-3.91893e-09,0.699492,0.000686371,-4.56969e-07,1.59493e-08,0.700178,0.000685505,-4.09121e-07,-2.73351e-10,0.700863,0.000684686,-4.09941e-07,-1.4856e-08,0.701548,0.000683822,-4.54509e-07,9.25979e-11,0.702231,0.000682913,-4.54231e-07,1.44855e-08,0.702913,0.000682048,-4.10775e-07,1.56992e-09,0.703595,0.000681231,-4.06065e-07,-2.07652e-08,0.704276,0.000680357,-4.68361e-07,2.18864e-08,0.704956,0.000679486,-4.02701e-07,-7.17595e-09,0.705635,0.000678659,-4.24229e-07,6.81748e-09,0.706313,0.000677831,-4.03777e-07,-2.0094e-08,0.70699,0.000676963,-4.64059e-07,1.39538e-08,0.707667,0.000676077,-4.22197e-07,2.38835e-08,0.708343,0.000675304,-3.50547e-07,-4.98831e-08,0.709018,0.000674453,-5.00196e-07,5.64395e-08,0.709692,0.000673622,-3.30878e-07,-5.66657e-08,0.710365,0.00067279,-5.00875e-07,5.1014e-08,0.711037,0.000671942,-3.47833e-07,-2.81809e-08,0.711709,0.000671161,-4.32376e-07,2.10513e-09,0.712379,0.000670303,-4.2606e-07,1.97604e-08,0.713049,0.00066951,-3.66779e-07,-2.15422e-08,0.713718,0.000668712,-4.31406e-07,6.8038e-09,0.714387,0.000667869,-4.10994e-07,-5.67295e-09,0.715054,0.00066703,-4.28013e-07,1.5888e-08,0.715721,0.000666222,-3.80349e-07,1.72576e-09,0.716387,0.000665467,-3.75172e-07,-2.27911e-08,0.717052,0.000664648,-4.43545e-07,2.9834e-08,0.717716,0.00066385,-3.54043e-07,-3.69401e-08,0.718379,0.000663031,-4.64864e-07,5.83219e-08,0.719042,0.000662277,-2.89898e-07,-7.71382e-08,0.719704,0.000661465,-5.21313e-07,7.14171e-08,0.720365,0.000660637,-3.07061e-07,-2.97161e-08,0.721025,0.000659934,-3.96209e-07,-1.21575e-08,0.721685,0.000659105,-4.32682e-07,1.87412e-08,0.722343,0.000658296,-3.76458e-07,-3.2029e-09,0.723001,0.000657533,-3.86067e-07,-5.9296e-09,0.723659,0.000656743,-4.03856e-07,2.69213e-08,0.724315,0.000656016,-3.23092e-07,-4.21511e-08,0.724971,0.000655244,-4.49545e-07,2.24737e-08,0.725625,0.000654412,-3.82124e-07,1.18611e-08,0.726279,0.000653683,-3.46541e-07,-1.03132e-08,0.726933,0.000652959,-3.7748e-07,-3.02128e-08,0.727585,0.000652114,-4.68119e-07,7.15597e-08,0.728237,0.000651392,-2.5344e-07,-7.72119e-08,0.728888,0.000650654,-4.85075e-07,5.8474e-08,0.729538,0.000649859,-3.09654e-07,-3.74746e-08,0.730188,0.000649127,-4.22077e-07,3.18197e-08,0.730837,0.000648379,-3.26618e-07,-3.01997e-08,0.731485,0.000647635,-4.17217e-07,2.93747e-08,0.732132,0.000646888,-3.29093e-07,-2.76943e-08,0.732778,0.000646147,-4.12176e-07,2.17979e-08,0.733424,0.000645388,-3.46783e-07,1.07292e-10,0.734069,0.000644695,-3.46461e-07,-2.22271e-08,0.734713,0.000643935,-4.13142e-07,2.91963e-08,0.735357,0.000643197,-3.25553e-07,-3.49536e-08,0.736,0.000642441,-4.30414e-07,5.10133e-08,0.736642,0.000641733,-2.77374e-07,-4.98904e-08,0.737283,0.000641028,-4.27045e-07,2.93392e-08,0.737924,0.000640262,-3.39028e-07,-7.86156e-09,0.738564,0.000639561,-3.62612e-07,2.10703e-09,0.739203,0.000638842,-3.56291e-07,-5.6653e-10,0.739842,0.000638128,-3.57991e-07,1.59086e-10,0.740479,0.000637412,-3.57513e-07,-6.98321e-11,0.741116,0.000636697,-3.57723e-07,1.20214e-10,0.741753,0.000635982,-3.57362e-07,-4.10987e-10,0.742388,0.000635266,-3.58595e-07,1.5237e-09,0.743023,0.000634553,-3.54024e-07,-5.68376e-09,0.743657,0.000633828,-3.71075e-07,2.12113e-08,0.744291,0.00063315,-3.07441e-07,-1.95569e-08,0.744924,0.000632476,-3.66112e-07,-2.58816e-09,0.745556,0.000631736,-3.73877e-07,2.99096e-08,0.746187,0.000631078,-2.84148e-07,-5.74454e-08,0.746818,0.000630337,-4.56484e-07,8.06629e-08,0.747448,0.000629666,-2.14496e-07,-8.63922e-08,0.748077,0.000628978,-4.73672e-07,8.60918e-08,0.748706,0.000628289,-2.15397e-07,-7.91613e-08,0.749334,0.000627621,-4.5288e-07,5.17393e-08,0.749961,0.00062687,-2.97663e-07,-8.58662e-09,0.750588,0.000626249,-3.23422e-07,-1.73928e-08,0.751214,0.00062555,-3.75601e-07,1.85532e-08,0.751839,0.000624855,-3.19941e-07,2.78479e-09,0.752463,0.000624223,-3.11587e-07,-2.96923e-08,0.753087,0.000623511,-4.00664e-07,5.63799e-08,0.75371,0.000622879,-2.31524e-07,-7.66179e-08,0.754333,0.000622186,-4.61378e-07,7.12778e-08,0.754955,0.000621477,-2.47545e-07,-2.96794e-08,0.755576,0.000620893,-3.36583e-07,-1.21648e-08,0.756196,0.000620183,-3.73077e-07,1.87339e-08,0.756816,0.000619493,-3.16875e-07,-3.16622e-09,0.757435,0.00061885,-3.26374e-07,-6.0691e-09,0.758054,0.000618179,-3.44581e-07,2.74426e-08,0.758672,0.000617572,-2.62254e-07,-4.40968e-08,0.759289,0.000616915,-3.94544e-07,2.97352e-08,0.759906,0.000616215,-3.05338e-07,-1.52393e-08,0.760522,0.000615559,-3.51056e-07,3.12221e-08,0.761137,0.000614951,-2.5739e-07,-5.00443e-08,0.761751,0.000614286,-4.07523e-07,4.9746e-08,0.762365,0.00061362,-2.58285e-07,-2.97303e-08,0.762979,0.000613014,-3.47476e-07,9.57079e-09,0.763591,0.000612348,-3.18764e-07,-8.55287e-09,0.764203,0.000611685,-3.44422e-07,2.46407e-08,0.764815,0.00061107,-2.705e-07,-3.04053e-08,0.765426,0.000610437,-3.61716e-07,3.73759e-08,0.766036,0.000609826,-2.49589e-07,-5.94935e-08,0.766645,0.000609149,-4.28069e-07,8.13889e-08,0.767254,0.000608537,-1.83902e-07,-8.72483e-08,0.767862,0.000607907,-4.45647e-07,8.87901e-08,0.76847,0.000607282,-1.79277e-07,-8.90983e-08,0.769077,0.000606656,-4.46572e-07,8.87892e-08,0.769683,0.000606029,-1.80204e-07,-8.72446e-08,0.770289,0.000605407,-4.41938e-07,8.13752e-08,0.770894,0.000604768,-1.97812e-07,-5.94423e-08,0.771498,0.000604194,-3.76139e-07,3.71848e-08,0.772102,0.000603553,-2.64585e-07,-2.96922e-08,0.772705,0.000602935,-3.53661e-07,2.19793e-08,0.773308,0.000602293,-2.87723e-07,1.37955e-09,0.77391,0.000601722,-2.83585e-07,-2.74976e-08,0.774512,0.000601072,-3.66077e-07,4.9006e-08,0.775112,0.000600487,-2.19059e-07,-4.93171e-08,0.775712,0.000599901,-3.67011e-07,2.90531e-08,0.776312,0.000599254,-2.79851e-07,-7.29081e-09,0.776911,0.000598673,-3.01724e-07,1.10077e-10,0.777509,0.00059807,-3.01393e-07,6.85053e-09,0.778107,0.000597487,-2.80842e-07,-2.75123e-08,0.778704,0.000596843,-3.63379e-07,4.35939e-08,0.779301,0.000596247,-2.32597e-07,-2.7654e-08,0.779897,0.000595699,-3.15559e-07,7.41741e-09,0.780492,0.00059509,-2.93307e-07,-2.01562e-09,0.781087,0.000594497,-2.99354e-07,6.45059e-10,0.781681,0.000593901,-2.97418e-07,-5.64635e-10,0.782275,0.000593304,-2.99112e-07,1.61347e-09,0.782868,0.000592711,-2.94272e-07,-5.88926e-09,0.78346,0.000592105,-3.1194e-07,2.19436e-08,0.784052,0.000591546,-2.46109e-07,-2.22805e-08,0.784643,0.000590987,-3.1295e-07,7.57368e-09,0.785234,0.000590384,-2.90229e-07,-8.01428e-09,0.785824,0.00058978,-3.14272e-07,2.44834e-08,0.786414,0.000589225,-2.40822e-07,-3.03148e-08,0.787003,0.000588652,-3.31766e-07,3.7171e-08,0.787591,0.0005881,-2.20253e-07,-5.87646e-08,0.788179,0.000587483,-3.96547e-07,7.86782e-08,0.788766,0.000586926,-1.60512e-07,-7.71342e-08,0.789353,0.000586374,-3.91915e-07,5.10444e-08,0.789939,0.000585743,-2.38782e-07,-7.83422e-09,0.790524,0.000585242,-2.62284e-07,-1.97076e-08,0.791109,0.000584658,-3.21407e-07,2.70598e-08,0.791693,0.000584097,-2.40228e-07,-2.89269e-08,0.792277,0.000583529,-3.27008e-07,2.90431e-08,0.792861,0.000582963,-2.39879e-07,-2.76409e-08,0.793443,0.0005824,-3.22802e-07,2.1916e-08,0.794025,0.00058182,-2.57054e-07,-4.18368e-10,0.794607,0.000581305,-2.58309e-07,-2.02425e-08,0.795188,0.000580727,-3.19036e-07,2.17838e-08,0.795768,0.000580155,-2.53685e-07,-7.28814e-09,0.796348,0.000579625,-2.75549e-07,7.36871e-09,0.796928,0.000579096,-2.53443e-07,-2.21867e-08,0.797506,0.000578523,-3.20003e-07,2.17736e-08,0.798085,0.000577948,-2.54683e-07,-5.30296e-09,0.798662,0.000577423,-2.70592e-07,-5.61698e-10,0.799239,0.00057688,-2.72277e-07,7.54977e-09,0.799816,0.000576358,-2.49627e-07,-2.96374e-08,0.800392,0.00057577,-3.38539e-07,5.1395e-08,0.800968,0.000575247,-1.84354e-07,-5.67335e-08,0.801543,0.000574708,-3.54555e-07,5.63297e-08,0.802117,0.000574168,-1.85566e-07,-4.93759e-08,0.802691,0.000573649,-3.33693e-07,2.19646e-08,0.803264,0.000573047,-2.678e-07,2.1122e-08,0.803837,0.000572575,-2.04433e-07,-4.68482e-08,0.804409,0.000572026,-3.44978e-07,4.70613e-08,0.804981,0.000571477,-2.03794e-07,-2.21877e-08,0.805552,0.000571003,-2.70357e-07,-1.79153e-08,0.806123,0.000570408,-3.24103e-07,3.42443e-08,0.806693,0.000569863,-2.2137e-07,1.47556e-10,0.807263,0.000569421,-2.20928e-07,-3.48345e-08,0.807832,0.000568874,-3.25431e-07,1.99812e-08,0.808401,0.000568283,-2.65487e-07,1.45143e-08,0.808969,0.000567796,-2.21945e-07,-1.84338e-08,0.809536,0.000567297,-2.77246e-07,-3.83608e-10,0.810103,0.000566741,-2.78397e-07,1.99683e-08,0.81067,0.000566244,-2.18492e-07,-1.98848e-08,0.811236,0.000565747,-2.78146e-07,-3.38976e-11,0.811801,0.000565191,-2.78248e-07,2.00204e-08,0.812366,0.000564695,-2.18187e-07,-2.04429e-08,0.812931,0.000564197,-2.79516e-07,2.1467e-09,0.813495,0.000563644,-2.73076e-07,1.18561e-08,0.814058,0.000563134,-2.37507e-07,1.00334e-08,0.814621,0.000562689,-2.07407e-07,-5.19898e-08,0.815183,0.000562118,-3.63376e-07,7.87163e-08,0.815745,0.000561627,-1.27227e-07,-8.40616e-08,0.816306,0.000561121,-3.79412e-07,7.87163e-08,0.816867,0.000560598,-1.43263e-07,-5.19898e-08,0.817428,0.000560156,-2.99233e-07,1.00335e-08,0.817988,0.000559587,-2.69132e-07,1.18559e-08,0.818547,0.000559085,-2.33564e-07,2.14764e-09,0.819106,0.000558624,-2.27122e-07,-2.04464e-08,0.819664,0.000558108,-2.88461e-07,2.00334e-08,0.820222,0.000557591,-2.28361e-07,-8.24277e-11,0.820779,0.000557135,-2.28608e-07,-1.97037e-08,0.821336,0.000556618,-2.87719e-07,1.92925e-08,0.821893,0.000556101,-2.29841e-07,2.13831e-09,0.822448,0.000555647,-2.23427e-07,-2.78458e-08,0.823004,0.000555117,-3.06964e-07,4.96402e-08,0.823559,0.000554652,-1.58043e-07,-5.15058e-08,0.824113,0.000554181,-3.12561e-07,3.71737e-08,0.824667,0.000553668,-2.0104e-07,-3.75844e-08,0.82522,0.000553153,-3.13793e-07,5.35592e-08,0.825773,0.000552686,-1.53115e-07,-5.74431e-08,0.826326,0.000552207,-3.25444e-07,5.7004e-08,0.826878,0.000551728,-1.54433e-07,-5.13635e-08,0.827429,0.000551265,-3.08523e-07,2.92406e-08,0.82798,0.000550735,-2.20801e-07,-5.99424e-09,0.828531,0.000550276,-2.38784e-07,-5.26363e-09,0.829081,0.000549782,-2.54575e-07,2.70488e-08,0.82963,0.000549354,-1.73429e-07,-4.33268e-08,0.83018,0.000548878,-3.03409e-07,2.7049e-08,0.830728,0.000548352,-2.22262e-07,-5.26461e-09,0.831276,0.000547892,-2.38056e-07,-5.99057e-09,0.831824,0.000547397,-2.56027e-07,2.92269e-08,0.832371,0.000546973,-1.68347e-07,-5.13125e-08,0.832918,0.000546482,-3.22284e-07,5.68139e-08,0.833464,0.000546008,-1.51843e-07,-5.67336e-08,0.83401,0.000545534,-3.22043e-07,5.09113e-08,0.834555,0.000545043,-1.6931e-07,-2.77022e-08,0.8351,0.000544621,-2.52416e-07,2.92924e-10,0.835644,0.000544117,-2.51537e-07,2.65305e-08,0.836188,0.000543694,-1.71946e-07,-4.68105e-08,0.836732,0.00054321,-3.12377e-07,4.15021e-08,0.837275,0.000542709,-1.87871e-07,1.13355e-11,0.837817,0.000542334,-1.87837e-07,-4.15474e-08,0.838359,0.000541833,-3.12479e-07,4.69691e-08,0.838901,0.000541349,-1.71572e-07,-2.71196e-08,0.839442,0.000540925,-2.52931e-07,1.90462e-09,0.839983,0.000540425,-2.47217e-07,1.95011e-08,0.840523,0.000539989,-1.88713e-07,-2.03045e-08,0.841063,0.00053955,-2.49627e-07,2.11216e-09,0.841602,0.000539057,-2.4329e-07,1.18558e-08,0.842141,0.000538606,-2.07723e-07,1.00691e-08,0.842679,0.000538221,-1.77516e-07,-5.21324e-08,0.843217,0.00053771,-3.33913e-07,7.92513e-08,0.843755,0.00053728,-9.6159e-08,-8.60587e-08,0.844292,0.000536829,-3.54335e-07,8.61696e-08,0.844828,0.000536379,-9.58263e-08,-7.98057e-08,0.845364,0.000535948,-3.35243e-07,5.42394e-08,0.8459,0.00053544,-1.72525e-07,-1.79426e-08,0.846435,0.000535041,-2.26353e-07,1.75308e-08,0.84697,0.000534641,-1.73761e-07,-5.21806e-08,0.847505,0.000534137,-3.30302e-07,7.19824e-08,0.848038,0.000533692,-1.14355e-07,-5.69349e-08,0.848572,0.000533293,-2.8516e-07,3.65479e-08,0.849105,0.000532832,-1.75516e-07,-2.96519e-08,0.849638,0.000532392,-2.64472e-07,2.2455e-08,0.85017,0.000531931,-1.97107e-07,-5.63451e-10,0.850702,0.000531535,-1.98797e-07,-2.02011e-08,0.851233,0.000531077,-2.59401e-07,2.17634e-08,0.851764,0.000530623,-1.94111e-07,-7.24794e-09,0.852294,0.000530213,-2.15854e-07,7.22832e-09,0.852824,0.000529803,-1.94169e-07,-2.16653e-08,0.853354,0.00052935,-2.59165e-07,1.98283e-08,0.853883,0.000528891,-1.9968e-07,1.95678e-09,0.854412,0.000528497,-1.9381e-07,-2.76554e-08,0.85494,0.000528027,-2.76776e-07,4.90603e-08,0.855468,0.00052762,-1.29596e-07,-4.93764e-08,0.855995,0.000527213,-2.77725e-07,2.92361e-08,0.856522,0.000526745,-1.90016e-07,-7.96341e-09,0.857049,0.000526341,-2.13907e-07,2.61752e-09,0.857575,0.000525922,-2.06054e-07,-2.50665e-09,0.8581,0.000525502,-2.13574e-07,7.40906e-09,0.858626,0.000525097,-1.91347e-07,-2.71296e-08,0.859151,0.000524633,-2.72736e-07,4.15048e-08,0.859675,0.000524212,-1.48221e-07,-1.96802e-08,0.860199,0.000523856,-2.07262e-07,-2.23886e-08,0.860723,0.000523375,-2.74428e-07,4.96299e-08,0.861246,0.000522975,-1.25538e-07,-5.69216e-08,0.861769,0.000522553,-2.96303e-07,5.88473e-08,0.862291,0.000522137,-1.19761e-07,-5.92584e-08,0.862813,0.00052172,-2.97536e-07,5.8977e-08,0.863334,0.000521301,-1.20605e-07,-5.74403e-08,0.863855,0.000520888,-2.92926e-07,5.15751e-08,0.864376,0.000520457,-1.38201e-07,-2.96506e-08,0.864896,0.000520091,-2.27153e-07,7.42277e-09,0.865416,0.000519659,-2.04885e-07,-4.05057e-11,0.865936,0.00051925,-2.05006e-07,-7.26074e-09,0.866455,0.000518818,-2.26788e-07,2.90835e-08,0.866973,0.000518451,-1.39538e-07,-4.94686e-08,0.867492,0.000518024,-2.87944e-07,4.95814e-08,0.868009,0.000517597,-1.39199e-07,-2.96479e-08,0.868527,0.000517229,-2.28143e-07,9.40539e-09,0.869044,0.000516801,-1.99927e-07,-7.9737e-09,0.86956,0.000516378,-2.23848e-07,2.24894e-08,0.870077,0.000515997,-1.5638e-07,-2.23793e-08,0.870592,0.000515617,-2.23517e-07,7.42302e-09,0.871108,0.000515193,-2.01248e-07,-7.31283e-09,0.871623,0.000514768,-2.23187e-07,2.18283e-08,0.872137,0.000514387,-1.57702e-07,-2.03959e-08,0.872652,0.000514011,-2.1889e-07,1.50711e-10,0.873165,0.000513573,-2.18437e-07,1.97931e-08,0.873679,0.000513196,-1.59058e-07,-1.97183e-08,0.874192,0.000512819,-2.18213e-07,-5.24324e-10,0.874704,0.000512381,-2.19786e-07,2.18156e-08,0.875217,0.000512007,-1.54339e-07,-2.71336e-08,0.875728,0.000511616,-2.3574e-07,2.71141e-08,0.87624,0.000511226,-1.54398e-07,-2.17182e-08,0.876751,0.000510852,-2.19552e-07,1.54131e-10,0.877262,0.000510414,-2.1909e-07,2.11017e-08,0.877772,0.000510039,-1.55785e-07,-2.49562e-08,0.878282,0.000509652,-2.30654e-07,1.91183e-08,0.878791,0.000509248,-1.73299e-07,8.08751e-09,0.8793,0.000508926,-1.49036e-07,-5.14684e-08,0.879809,0.000508474,-3.03441e-07,7.85766e-08,0.880317,0.000508103,-6.77112e-08,-8.40242e-08,0.880825,0.000507715,-3.19784e-07,7.87063e-08,0.881333,0.000507312,-8.36649e-08,-5.19871e-08,0.88184,0.000506988,-2.39626e-07,1.00327e-08,0.882346,0.000506539,-2.09528e-07,1.18562e-08,0.882853,0.000506156,-1.73959e-07,2.14703e-09,0.883359,0.000505814,-1.67518e-07,-2.04444e-08,0.883864,0.000505418,-2.28851e-07,2.00258e-08,0.88437,0.00050502,-1.68774e-07,-5.42855e-11,0.884874,0.000504682,-1.68937e-07,-1.98087e-08,0.885379,0.000504285,-2.28363e-07,1.96842e-08,0.885883,0.000503887,-1.6931e-07,6.76342e-10,0.886387,0.000503551,-1.67281e-07,-2.23896e-08,0.88689,0.000503149,-2.3445e-07,2.92774e-08,0.887393,0.000502768,-1.46618e-07,-3.51152e-08,0.887896,0.00050237,-2.51963e-07,5.15787e-08,0.888398,0.00050202,-9.72271e-08,-5.19903e-08,0.8889,0.00050167,-2.53198e-07,3.71732e-08,0.889401,0.000501275,-1.41678e-07,-3.70978e-08,0.889902,0.00050088,-2.52972e-07,5.16132e-08,0.890403,0.000500529,-9.81321e-08,-5.01459e-08,0.890903,0.000500183,-2.4857e-07,2.9761e-08,0.891403,0.000499775,-1.59287e-07,-9.29351e-09,0.891903,0.000499428,-1.87167e-07,7.41301e-09,0.892402,0.000499076,-1.64928e-07,-2.03585e-08,0.892901,0.000498685,-2.26004e-07,1.44165e-08,0.893399,0.000498276,-1.82754e-07,2.22974e-08,0.893898,0.000497978,-1.15862e-07,-4.40013e-08,0.894395,0.000497614,-2.47866e-07,3.44985e-08,0.894893,0.000497222,-1.44371e-07,-3.43882e-08,0.89539,0.00049683,-2.47535e-07,4.34497e-08,0.895886,0.000496465,-1.17186e-07,-2.02012e-08,0.896383,0.00049617,-1.7779e-07,-2.22497e-08,0.896879,0.000495748,-2.44539e-07,4.95952e-08,0.897374,0.000495408,-9.57532e-08,-5.69217e-08,0.89787,0.000495045,-2.66518e-07,5.88823e-08,0.898364,0.000494689,-8.98713e-08,-5.93983e-08,0.898859,0.000494331,-2.68066e-07,5.95017e-08,0.899353,0.000493973,-8.95613e-08,-5.9399e-08,0.899847,0.000493616,-2.67758e-07,5.8885e-08,0.90034,0.000493257,-9.11033e-08,-5.69317e-08,0.900833,0.000492904,-2.61898e-07,4.96326e-08,0.901326,0.000492529,-1.13001e-07,-2.23893e-08,0.901819,0.000492236,-1.80169e-07,-1.968e-08,0.902311,0.000491817,-2.39209e-07,4.15047e-08,0.902802,0.000491463,-1.14694e-07,-2.71296e-08,0.903293,0.000491152,-1.96083e-07,7.409e-09,0.903784,0.000490782,-1.73856e-07,-2.50645e-09,0.904275,0.000490427,-1.81376e-07,2.61679e-09,0.904765,0.000490072,-1.73525e-07,-7.96072e-09,0.905255,0.000489701,-1.97407e-07,2.92261e-08,0.905745,0.000489394,-1.09729e-07,-4.93389e-08,0.906234,0.000489027,-2.57746e-07,4.89204e-08,0.906723,0.000488658,-1.10985e-07,-2.71333e-08,0.907211,0.000488354,-1.92385e-07,8.30861e-12,0.907699,0.00048797,-1.9236e-07,2.71001e-08,0.908187,0.000487666,-1.1106e-07,-4.88041e-08,0.908675,0.000487298,-2.57472e-07,4.89069e-08,0.909162,0.000486929,-1.10751e-07,-2.76143e-08,0.909649,0.000486625,-1.93594e-07,1.9457e-09,0.910135,0.000486244,-1.87757e-07,1.98315e-08,0.910621,0.000485928,-1.28262e-07,-2.16671e-08,0.911107,0.000485606,-1.93264e-07,7.23216e-09,0.911592,0.000485241,-1.71567e-07,-7.26152e-09,0.912077,0.000484877,-1.93352e-07,2.18139e-08,0.912562,0.000484555,-1.2791e-07,-2.03895e-08,0.913047,0.000484238,-1.89078e-07,1.39494e-10,0.913531,0.000483861,-1.8866e-07,1.98315e-08,0.914014,0.000483543,-1.29165e-07,-1.98609e-08,0.914498,0.000483225,-1.88748e-07,7.39912e-12,0.914981,0.000482847,-1.88726e-07,1.98313e-08,0.915463,0.000482529,-1.29232e-07,-1.9728e-08,0.915946,0.000482212,-1.88416e-07,-5.24035e-10,0.916428,0.000481833,-1.89988e-07,2.18241e-08,0.916909,0.000481519,-1.24516e-07,-2.71679e-08,0.917391,0.000481188,-2.06019e-07,2.72427e-08,0.917872,0.000480858,-1.24291e-07,-2.21985e-08,0.918353,0.000480543,-1.90886e-07,1.94644e-09,0.918833,0.000480167,-1.85047e-07,1.44127e-08,0.919313,0.00047984,-1.41809e-07,7.39438e-12,0.919793,0.000479556,-1.41787e-07,-1.44423e-08,0.920272,0.000479229,-1.85114e-07,-1.84291e-09,0.920751,0.000478854,-1.90642e-07,2.18139e-08,0.92123,0.000478538,-1.25201e-07,-2.58081e-08,0.921708,0.00047821,-2.02625e-07,2.18139e-08,0.922186,0.00047787,-1.37183e-07,-1.84291e-09,0.922664,0.00047759,-1.42712e-07,-1.44423e-08,0.923141,0.000477262,-1.86039e-07,7.34701e-12,0.923618,0.00047689,-1.86017e-07,1.44129e-08,0.924095,0.000476561,-1.42778e-07,1.94572e-09,0.924572,0.000476281,-1.36941e-07,-2.21958e-08,0.925048,0.000475941,-2.03528e-07,2.72327e-08,0.925523,0.000475615,-1.2183e-07,-2.71304e-08,0.925999,0.00047529,-2.03221e-07,2.16843e-08,0.926474,0.000474949,-1.38168e-07,-2.16005e-12,0.926949,0.000474672,-1.38175e-07,-2.16756e-08,0.927423,0.000474331,-2.03202e-07,2.71001e-08,0.927897,0.000474006,-1.21902e-07,-2.71201e-08,0.928371,0.000473681,-2.03262e-07,2.17757e-08,0.928845,0.00047334,-1.37935e-07,-3.78028e-10,0.929318,0.000473063,-1.39069e-07,-2.02636e-08,0.929791,0.000472724,-1.9986e-07,2.18276e-08,0.930263,0.000472389,-1.34377e-07,-7.44231e-09,0.930736,0.000472098,-1.56704e-07,7.94165e-09,0.931208,0.000471809,-1.32879e-07,-2.43243e-08,0.931679,0.00047147,-2.05851e-07,2.97508e-08,0.932151,0.000471148,-1.16599e-07,-3.50742e-08,0.932622,0.000470809,-2.21822e-07,5.09414e-08,0.933092,0.000470518,-6.89976e-08,-4.94821e-08,0.933563,0.000470232,-2.17444e-07,2.77775e-08,0.934033,0.00046988,-1.34111e-07,-2.02351e-09,0.934502,0.000469606,-1.40182e-07,-1.96835e-08,0.934972,0.000469267,-1.99232e-07,2.11529e-08,0.935441,0.000468932,-1.35774e-07,-5.32332e-09,0.93591,0.000468644,-1.51743e-07,1.40413e-10,0.936378,0.000468341,-1.51322e-07,4.76166e-09,0.936846,0.000468053,-1.37037e-07,-1.9187e-08,0.937314,0.000467721,-1.94598e-07,1.23819e-08,0.937782,0.000467369,-1.57453e-07,2.92642e-08,0.938249,0.000467142,-6.96601e-08,-6.98342e-08,0.938716,0.000466793,-2.79163e-07,7.12586e-08,0.939183,0.000466449,-6.53869e-08,-3.63863e-08,0.939649,0.000466209,-1.74546e-07,1.46818e-08,0.940115,0.000465904,-1.305e-07,-2.2341e-08,0.940581,0.000465576,-1.97523e-07,1.50774e-08,0.941046,0.000465226,-1.52291e-07,2.16359e-08,0.941511,0.000464986,-8.73832e-08,-4.20162e-08,0.941976,0.000464685,-2.13432e-07,2.72198e-08,0.942441,0.00046434,-1.31773e-07,-7.2581e-09,0.942905,0.000464055,-1.53547e-07,1.81263e-09,0.943369,0.000463753,-1.48109e-07,7.58386e-12,0.943832,0.000463457,-1.48086e-07,-1.84298e-09,0.944296,0.000463155,-1.53615e-07,7.36433e-09,0.944759,0.00046287,-1.31522e-07,-2.76143e-08,0.945221,0.000462524,-2.14365e-07,4.34883e-08,0.945684,0.000462226,-8.39003e-08,-2.71297e-08,0.946146,0.000461977,-1.65289e-07,5.42595e-09,0.946608,0.000461662,-1.49012e-07,5.42593e-09,0.947069,0.000461381,-1.32734e-07,-2.71297e-08,0.94753,0.000461034,-2.14123e-07,4.34881e-08,0.947991,0.000460736,-8.36585e-08,-2.76134e-08,0.948452,0.000460486,-1.66499e-07,7.36083e-09,0.948912,0.000460175,-1.44416e-07,-1.82993e-09,0.949372,0.000459881,-1.49906e-07,-4.11073e-11,0.949832,0.000459581,-1.50029e-07,1.99434e-09,0.950291,0.000459287,-1.44046e-07,-7.93627e-09,0.950751,0.000458975,-1.67855e-07,2.97507e-08,0.951209,0.000458728,-7.86029e-08,-5.1462e-08,0.951668,0.000458417,-2.32989e-07,5.6888e-08,0.952126,0.000458121,-6.2325e-08,-5.68806e-08,0.952584,0.000457826,-2.32967e-07,5.14251e-08,0.953042,0.000457514,-7.86914e-08,-2.96107e-08,0.953499,0.000457268,-1.67523e-07,7.41296e-09,0.953956,0.000456955,-1.45285e-07,-4.11262e-11,0.954413,0.000456665,-1.45408e-07,-7.24847e-09,0.95487,0.000456352,-1.67153e-07,2.9035e-08,0.955326,0.000456105,-8.00484e-08,-4.92869e-08,0.955782,0.000455797,-2.27909e-07,4.89032e-08,0.956238,0.000455488,-8.11994e-08,-2.71166e-08,0.956693,0.000455244,-1.62549e-07,-4.13678e-11,0.957148,0.000454919,-1.62673e-07,2.72821e-08,0.957603,0.000454675,-8.0827e-08,-4.94824e-08,0.958057,0.000454365,-2.29274e-07,5.14382e-08,0.958512,0.000454061,-7.49597e-08,-3.7061e-08,0.958965,0.0004538,-1.86143e-07,3.72013e-08,0.959419,0.000453539,-7.45389e-08,-5.21396e-08,0.959873,0.000453234,-2.30958e-07,5.21476e-08,0.960326,0.000452928,-7.45146e-08,-3.72416e-08,0.960778,0.000452667,-1.8624e-07,3.72143e-08,0.961231,0.000452407,-7.45967e-08,-5.20109e-08,0.961683,0.000452101,-2.30629e-07,5.16199e-08,0.962135,0.000451795,-7.57696e-08,-3.52595e-08,0.962587,0.000451538,-1.81548e-07,2.98133e-08,0.963038,0.000451264,-9.2108e-08,-2.43892e-08,0.963489,0.000451007,-1.65276e-07,8.13892e-09,0.96394,0.000450701,-1.40859e-07,-8.16647e-09,0.964391,0.000450394,-1.65358e-07,2.45269e-08,0.964841,0.000450137,-9.17775e-08,-3.03367e-08,0.965291,0.000449863,-1.82787e-07,3.7215e-08,0.965741,0.000449609,-7.11424e-08,-5.89188e-08,0.96619,0.00044929,-2.47899e-07,7.92509e-08,0.966639,0.000449032,-1.01462e-08,-7.92707e-08,0.967088,0.000448773,-2.47958e-07,5.90181e-08,0.967537,0.000448455,-7.0904e-08,-3.75925e-08,0.967985,0.0004482,-1.83681e-07,3.17471e-08,0.968433,0.000447928,-8.84401e-08,-2.97913e-08,0.968881,0.000447662,-1.77814e-07,2.78133e-08,0.969329,0.000447389,-9.4374e-08,-2.18572e-08,0.969776,0.000447135,-1.59946e-07,1.10134e-11,0.970223,0.000446815,-1.59913e-07,2.18132e-08,0.97067,0.000446561,-9.44732e-08,-2.76591e-08,0.971116,0.000446289,-1.7745e-07,2.92185e-08,0.971562,0.000446022,-8.97948e-08,-2.96104e-08,0.972008,0.000445753,-1.78626e-07,2.96185e-08,0.972454,0.000445485,-8.97706e-08,-2.92588e-08,0.972899,0.000445218,-1.77547e-07,2.78123e-08,0.973344,0.000444946,-9.41103e-08,-2.23856e-08,0.973789,0.000444691,-1.61267e-07,2.12559e-09,0.974233,0.000444374,-1.5489e-07,1.38833e-08,0.974678,0.000444106,-1.13241e-07,1.94591e-09,0.975122,0.000443886,-1.07403e-07,-2.16669e-08,0.975565,0.000443606,-1.72404e-07,2.5117e-08,0.976009,0.000443336,-9.70526e-08,-1.91963e-08,0.976452,0.000443085,-1.54642e-07,-7.93627e-09,0.976895,0.000442752,-1.7845e-07,5.09414e-08,0.977338,0.000442548,-2.56262e-08,-7.66201e-08,0.97778,0.000442266,-2.55486e-07,7.67249e-08,0.978222,0.000441986,-2.53118e-08,-5.14655e-08,0.978664,0.000441781,-1.79708e-07,9.92773e-09,0.979106,0.000441451,-1.49925e-07,1.17546e-08,0.979547,0.000441186,-1.14661e-07,2.65868e-09,0.979988,0.000440965,-1.06685e-07,-2.23893e-08,0.980429,0.000440684,-1.73853e-07,2.72939e-08,0.980869,0.000440419,-9.19716e-08,-2.71816e-08,0.98131,0.000440153,-1.73516e-07,2.18278e-08,0.98175,0.000439872,-1.08033e-07,-5.24833e-10,0.982189,0.000439654,-1.09607e-07,-1.97284e-08,0.982629,0.000439376,-1.68793e-07,1.98339e-08,0.983068,0.000439097,-1.09291e-07,-2.62901e-12,0.983507,0.000438879,-1.09299e-07,-1.98234e-08,0.983946,0.000438601,-1.68769e-07,1.96916e-08,0.984384,0.000438322,-1.09694e-07,6.6157e-10,0.984823,0.000438105,-1.0771e-07,-2.23379e-08,0.985261,0.000437823,-1.74723e-07,2.90855e-08,0.985698,0.00043756,-8.74669e-08,-3.43992e-08,0.986136,0.000437282,-1.90665e-07,4.89068e-08,0.986573,0.000437048,-4.39442e-08,-4.20188e-08,0.98701,0.000436834,-1.7e-07,-4.11073e-11,0.987446,0.000436494,-1.70124e-07,4.21832e-08,0.987883,0.00043628,-4.35742e-08,-4.94824e-08,0.988319,0.000436044,-1.92021e-07,3.6537e-08,0.988755,0.00043577,-8.24102e-08,-3.70611e-08,0.989191,0.000435494,-1.93593e-07,5.21026e-08,0.989626,0.000435263,-3.72855e-08,-5.21402e-08,0.990061,0.000435032,-1.93706e-07,3.7249e-08,0.990496,0.000434756,-8.19592e-08,-3.72512e-08,0.990931,0.000434481,-1.93713e-07,5.21511e-08,0.991365,0.00043425,-3.72595e-08,-5.21439e-08,0.991799,0.000434019,-1.93691e-07,3.72152e-08,0.992233,0.000433743,-8.20456e-08,-3.71123e-08,0.992667,0.000433468,-1.93382e-07,5.16292e-08,0.9931,0.000433236,-3.84947e-08,-5.01953e-08,0.993533,0.000433008,-1.89081e-07,2.99427e-08,0.993966,0.00043272,-9.92525e-08,-9.9708e-09,0.994399,0.000432491,-1.29165e-07,9.94051e-09,0.994831,0.000432263,-9.93434e-08,-2.97912e-08,0.995263,0.000431975,-1.88717e-07,4.96198e-08,0.995695,0.000431746,-3.98578e-08,-4.94785e-08,0.996127,0.000431518,-1.88293e-07,2.9085e-08,0.996558,0.000431229,-1.01038e-07,-7.25675e-09,0.996989,0.000431005,-1.22809e-07,-5.79945e-11,0.99742,0.000430759,-1.22983e-07,7.48873e-09,0.997851,0.000430536,-1.00516e-07,-2.98969e-08,0.998281,0.000430245,-1.90207e-07,5.24942e-08,0.998711,0.000430022,-3.27246e-08,-6.08706e-08,0.999141,0.000429774,-2.15336e-07,7.17788e-08,0.999571,0.000429392,0.,0.}; + + template + __device__ __forceinline__ void Lab2RGBConvert_f(const T& src, D& dst) + { + const float lThresh = 0.008856f * 903.3f; + const float fThresh = 7.787f * 0.008856f + 16.0f / 116.0f; + + float Y, fy; + + if (src.x <= lThresh) + { + Y = src.x / 903.3f; + fy = 7.787f * Y + 16.0f / 116.0f; + } + else + { + fy = (src.x + 16.0f) / 116.0f; + Y = fy * fy * fy; + } + + float X = src.y / 500.0f + fy; + float Z = fy - src.z / 200.0f; + + if (X <= fThresh) + X = (X - 16.0f / 116.0f) / 7.787f; + else + X = X * X * X; + + if (Z <= fThresh) + Z = (Z - 16.0f / 116.0f) / 7.787f; + else + Z = Z * Z * Z; + + float B = 0.052891f * X - 0.204043f * Y + 1.151152f * Z; + float G = -0.921235f * X + 1.875991f * Y + 0.045244f * Z; + float R = 3.079933f * X - 1.537150f * Y - 0.542782f * Z; + + if (srgb) + { + B = splineInterpolate(B * GAMMA_TAB_SIZE, c_sRGBInvGammaTab, GAMMA_TAB_SIZE); + G = splineInterpolate(G * GAMMA_TAB_SIZE, c_sRGBInvGammaTab, GAMMA_TAB_SIZE); + R = splineInterpolate(R * GAMMA_TAB_SIZE, c_sRGBInvGammaTab, GAMMA_TAB_SIZE); + } + + dst.x = blueIdx == 0 ? B : R; + dst.y = G; + dst.z = blueIdx == 0 ? R : B; + setAlpha(dst, ColorChannel::max()); + } + + template + __device__ __forceinline__ void Lab2RGBConvert_b(const T& src, D& dst) + { + float3 srcf, dstf; + + srcf.x = src.x * (100.f / 255.f); + srcf.y = src.y - 128; + srcf.z = src.z - 128; + + Lab2RGBConvert_f(srcf, dstf); + + dst.x = saturate_cast(dstf.x * 255.f); + dst.y = saturate_cast(dstf.y * 255.f); + dst.z = saturate_cast(dstf.z * 255.f); + setAlpha(dst, ColorChannel::max()); + } + + template struct Lab2RGB; + template + struct Lab2RGB + : unary_function::vec_type, typename TypeVec::vec_type> + { + __device__ __forceinline__ typename TypeVec::vec_type operator ()(const typename TypeVec::vec_type& src) const + { + typename TypeVec::vec_type dst; + + Lab2RGBConvert_b(src, dst); + + return dst; + } + __host__ __device__ __forceinline__ Lab2RGB() {} + __host__ __device__ __forceinline__ Lab2RGB(const Lab2RGB&) {} + }; + template + struct Lab2RGB + : unary_function::vec_type, typename TypeVec::vec_type> + { + __device__ __forceinline__ typename TypeVec::vec_type operator ()(const typename TypeVec::vec_type& src) const + { + typename TypeVec::vec_type dst; + + Lab2RGBConvert_f(src, dst); + + return dst; + } + __host__ __device__ __forceinline__ Lab2RGB() {} + __host__ __device__ __forceinline__ Lab2RGB(const Lab2RGB&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_Lab2RGB_TRAITS(name, scn, dcn, srgb, blueIdx) \ + template struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::Lab2RGB functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + +///////////////////////////////////// RGB <-> Luv ///////////////////////////////////// + + namespace color_detail + { + __constant__ float c_LabCbrtTab[] = {0.137931,0.0114066,0.,1.18859e-07,0.149338,0.011407,3.56578e-07,-5.79396e-07,0.160745,0.0114059,-1.38161e-06,2.16892e-06,0.172151,0.0114097,5.12516e-06,-8.0814e-06,0.183558,0.0113957,-1.9119e-05,3.01567e-05,0.194965,0.0114479,7.13509e-05,-0.000112545,0.206371,0.011253,-0.000266285,-0.000106493,0.217252,0.0104009,-0.000585765,7.32149e-05,0.22714,0.00944906,-0.00036612,1.21917e-05,0.236235,0.0087534,-0.000329545,2.01753e-05,0.244679,0.00815483,-0.000269019,1.24435e-05,0.252577,0.00765412,-0.000231689,1.05618e-05,0.26001,0.00722243,-0.000200003,8.26662e-06,0.267041,0.00684723,-0.000175203,6.76746e-06,0.27372,0.00651712,-0.000154901,5.61192e-06,0.280088,0.00622416,-0.000138065,4.67009e-06,0.286179,0.00596204,-0.000124055,3.99012e-06,0.292021,0.0057259,-0.000112085,3.36032e-06,0.297638,0.00551181,-0.000102004,2.95338e-06,0.30305,0.00531666,-9.31435e-05,2.52875e-06,0.308277,0.00513796,-8.55572e-05,2.22022e-06,0.313331,0.00497351,-7.88966e-05,1.97163e-06,0.318228,0.00482163,-7.29817e-05,1.7248e-06,0.322978,0.00468084,-6.78073e-05,1.55998e-06,0.327593,0.0045499,-6.31274e-05,1.36343e-06,0.332081,0.00442774,-5.90371e-05,1.27136e-06,0.336451,0.00431348,-5.5223e-05,1.09111e-06,0.34071,0.00420631,-5.19496e-05,1.0399e-06,0.344866,0.00410553,-4.88299e-05,9.18347e-07,0.348923,0.00401062,-4.60749e-05,8.29942e-07,0.352889,0.00392096,-4.35851e-05,7.98478e-07,0.356767,0.00383619,-4.11896e-05,6.84917e-07,0.360562,0.00375586,-3.91349e-05,6.63976e-07,0.36428,0.00367959,-3.7143e-05,5.93086e-07,0.367923,0.00360708,-3.53637e-05,5.6976e-07,0.371495,0.00353806,-3.36544e-05,4.95533e-07,0.375,0.00347224,-3.21678e-05,4.87951e-07,0.378441,0.00340937,-3.0704e-05,4.4349e-07,0.38182,0.00334929,-2.93735e-05,4.20297e-07,0.38514,0.0032918,-2.81126e-05,3.7872e-07,0.388404,0.00323671,-2.69764e-05,3.596e-07,0.391614,0.00318384,-2.58976e-05,3.5845e-07,0.394772,0.00313312,-2.48223e-05,2.92765e-07,0.397881,0.00308435,-2.3944e-05,3.18232e-07,0.400942,0.00303742,-2.29893e-05,2.82046e-07,0.403957,0.00299229,-2.21432e-05,2.52315e-07,0.406927,0.00294876,-2.13862e-05,2.58416e-07,0.409855,0.00290676,-2.0611e-05,2.33939e-07,0.412741,0.00286624,-1.99092e-05,2.36342e-07,0.415587,0.00282713,-1.92001e-05,1.916e-07,0.418396,0.00278931,-1.86253e-05,2.1915e-07,0.421167,0.00275271,-1.79679e-05,1.83498e-07,0.423901,0.00271733,-1.74174e-05,1.79343e-07,0.426602,0.00268303,-1.68794e-05,1.72013e-07,0.429268,0.00264979,-1.63633e-05,1.75686e-07,0.431901,0.00261759,-1.58363e-05,1.3852e-07,0.434503,0.00258633,-1.54207e-05,1.64304e-07,0.437074,0.00255598,-1.49278e-05,1.28136e-07,0.439616,0.00252651,-1.45434e-05,1.57618e-07,0.442128,0.0024979,-1.40705e-05,1.0566e-07,0.444612,0.00247007,-1.37535e-05,1.34998e-07,0.447068,0.00244297,-1.33485e-05,1.29207e-07,0.449498,0.00241666,-1.29609e-05,9.32347e-08,0.451902,0.00239102,-1.26812e-05,1.23703e-07,0.45428,0.00236603,-1.23101e-05,9.74072e-08,0.456634,0.0023417,-1.20179e-05,1.12518e-07,0.458964,0.002318,-1.16803e-05,7.83681e-08,0.46127,0.00229488,-1.14452e-05,1.10452e-07,0.463554,0.00227232,-1.11139e-05,7.58719e-08,0.465815,0.00225032,-1.08863e-05,9.2699e-08,0.468055,0.00222882,-1.06082e-05,8.97738e-08,0.470273,0.00220788,-1.03388e-05,5.4845e-08,0.47247,0.00218736,-1.01743e-05,1.0808e-07,0.474648,0.00216734,-9.85007e-06,4.9277e-08,0.476805,0.00214779,-9.70224e-06,8.22408e-08,0.478943,0.00212863,-9.45551e-06,6.87942e-08,0.481063,0.00210993,-9.24913e-06,5.98144e-08,0.483163,0.00209161,-9.06969e-06,7.93789e-08,0.485246,0.00207371,-8.83155e-06,3.99032e-08,0.487311,0.00205616,-8.71184e-06,8.88325e-08,0.489358,0.002039,-8.44534e-06,2.20004e-08,0.491389,0.00202218,-8.37934e-06,9.13872e-08,0.493403,0.0020057,-8.10518e-06,2.96829e-08,0.495401,0.00198957,-8.01613e-06,5.81028e-08,0.497382,0.00197372,-7.84183e-06,6.5731e-08,0.499348,0.00195823,-7.64463e-06,3.66019e-08,0.501299,0.00194305,-7.53483e-06,2.62811e-08,0.503234,0.00192806,-7.45598e-06,9.66907e-08,0.505155,0.00191344,-7.16591e-06,4.18928e-09,0.507061,0.00189912,-7.15334e-06,6.53665e-08,0.508953,0.00188501,-6.95724e-06,3.23686e-08,0.510831,0.00187119,-6.86014e-06,4.35774e-08,0.512696,0.0018576,-6.72941e-06,3.17406e-08,0.514547,0.00184424,-6.63418e-06,6.78785e-08,0.516384,0.00183117,-6.43055e-06,-5.23126e-09,0.518209,0.0018183,-6.44624e-06,7.22562e-08,0.520021,0.00180562,-6.22947e-06,1.42292e-08,0.52182,0.0017932,-6.18679e-06,4.9641e-08,0.523607,0.00178098,-6.03786e-06,2.56259e-08,0.525382,0.00176898,-5.96099e-06,2.66696e-08,0.527145,0.00175714,-5.88098e-06,4.65094e-08,0.528897,0.00174552,-5.74145e-06,2.57114e-08,0.530637,0.00173411,-5.66431e-06,2.94588e-08,0.532365,0.00172287,-5.57594e-06,3.52667e-08,0.534082,0.00171182,-5.47014e-06,8.28868e-09,0.535789,0.00170091,-5.44527e-06,5.07871e-08,0.537484,0.00169017,-5.29291e-06,2.69817e-08,0.539169,0.00167967,-5.21197e-06,2.01009e-08,0.540844,0.0016693,-5.15166e-06,1.18237e-08,0.542508,0.00165903,-5.11619e-06,5.18135e-08,0.544162,0.00164896,-4.96075e-06,1.9341e-08,0.545806,0.00163909,-4.90273e-06,-9.96867e-09,0.54744,0.00162926,-4.93263e-06,8.01382e-08,0.549064,0.00161963,-4.69222e-06,-1.25601e-08,0.550679,0.00161021,-4.7299e-06,2.97067e-08,0.552285,0.00160084,-4.64078e-06,1.29426e-08,0.553881,0.0015916,-4.60195e-06,3.77327e-08,0.555468,0.00158251,-4.48875e-06,1.49412e-08,0.557046,0.00157357,-4.44393e-06,2.17118e-08,0.558615,0.00156475,-4.3788e-06,1.74206e-08,0.560176,0.00155605,-4.32653e-06,2.78152e-08,0.561727,0.00154748,-4.24309e-06,-9.47239e-09,0.563271,0.00153896,-4.27151e-06,6.9679e-08,0.564805,0.00153063,-4.06247e-06,-3.08246e-08,0.566332,0.00152241,-4.15494e-06,5.36188e-08,0.56785,0.00151426,-3.99409e-06,-4.83594e-09,0.56936,0.00150626,-4.00859e-06,2.53293e-08,0.570863,0.00149832,-3.93261e-06,2.27286e-08,0.572357,0.00149052,-3.86442e-06,2.96541e-09,0.573844,0.0014828,-3.85552e-06,2.50147e-08,0.575323,0.00147516,-3.78048e-06,1.61842e-08,0.576794,0.00146765,-3.73193e-06,2.94582e-08,0.578258,0.00146028,-3.64355e-06,-1.48076e-08,0.579715,0.00145295,-3.68798e-06,2.97724e-08,0.581164,0.00144566,-3.59866e-06,1.49272e-08,0.582606,0.00143851,-3.55388e-06,2.97285e-08,0.584041,0.00143149,-3.46469e-06,-1.46323e-08,0.585469,0.00142451,-3.50859e-06,2.88004e-08,0.58689,0.00141758,-3.42219e-06,1.864e-08,0.588304,0.00141079,-3.36627e-06,1.58482e-08,0.589712,0.00140411,-3.31872e-06,-2.24279e-08,0.591112,0.00139741,-3.38601e-06,7.38639e-08,0.592507,0.00139085,-3.16441e-06,-3.46088e-08,0.593894,0.00138442,-3.26824e-06,4.96675e-09,0.595275,0.0013779,-3.25334e-06,7.4346e-08,0.59665,0.00137162,-3.0303e-06,-6.39319e-08,0.598019,0.00136536,-3.2221e-06,6.21725e-08,0.599381,0.00135911,-3.03558e-06,-5.94423e-09,0.600737,0.00135302,-3.05341e-06,2.12091e-08,0.602087,0.00134697,-2.98979e-06,-1.92876e-08,0.603431,0.00134094,-3.04765e-06,5.5941e-08,0.604769,0.00133501,-2.87983e-06,-2.56622e-08,0.606101,0.00132917,-2.95681e-06,4.67078e-08,0.607427,0.0013234,-2.81669e-06,-4.19592e-08,0.608748,0.00131764,-2.94257e-06,6.15243e-08,0.610062,0.00131194,-2.75799e-06,-2.53244e-08,0.611372,0.00130635,-2.83397e-06,3.97739e-08,0.612675,0.0013008,-2.71465e-06,-1.45618e-08,0.613973,0.00129533,-2.75833e-06,1.84733e-08,0.615266,0.00128986,-2.70291e-06,2.73606e-10,0.616553,0.00128446,-2.70209e-06,4.00367e-08,0.617835,0.00127918,-2.58198e-06,-4.12113e-08,0.619111,0.00127389,-2.70561e-06,6.52039e-08,0.620383,0.00126867,-2.51e-06,-4.07901e-08,0.621649,0.00126353,-2.63237e-06,3.83516e-08,0.62291,0.00125838,-2.51732e-06,6.59315e-09,0.624166,0.00125337,-2.49754e-06,-5.11939e-09,0.625416,0.00124836,-2.5129e-06,1.38846e-08,0.626662,0.00124337,-2.47124e-06,9.18514e-09,0.627903,0.00123846,-2.44369e-06,8.97952e-09,0.629139,0.0012336,-2.41675e-06,1.45012e-08,0.63037,0.00122881,-2.37325e-06,-7.37949e-09,0.631597,0.00122404,-2.39538e-06,1.50169e-08,0.632818,0.00121929,-2.35033e-06,6.91648e-09,0.634035,0.00121461,-2.32958e-06,1.69219e-08,0.635248,0.00121,-2.27882e-06,-1.49997e-08,0.636455,0.0012054,-2.32382e-06,4.30769e-08,0.637659,0.00120088,-2.19459e-06,-3.80986e-08,0.638857,0.00119638,-2.30888e-06,4.97134e-08,0.640051,0.00119191,-2.15974e-06,-4.15463e-08,0.641241,0.00118747,-2.28438e-06,5.68667e-08,0.642426,0.00118307,-2.11378e-06,-7.10641e-09,0.643607,0.00117882,-2.1351e-06,-2.8441e-08,0.644784,0.00117446,-2.22042e-06,6.12658e-08,0.645956,0.00117021,-2.03663e-06,-3.78083e-08,0.647124,0.00116602,-2.15005e-06,3.03627e-08,0.648288,0.00116181,-2.05896e-06,-2.40379e-08,0.649448,0.00115762,-2.13108e-06,6.57887e-08,0.650603,0.00115356,-1.93371e-06,-6.03028e-08,0.651755,0.00114951,-2.11462e-06,5.62134e-08,0.652902,0.00114545,-1.94598e-06,-4.53417e-08,0.654046,0.00114142,-2.082e-06,6.55489e-08,0.655185,0.00113745,-1.88536e-06,-3.80396e-08,0.656321,0.00113357,-1.99948e-06,2.70049e-08,0.657452,0.00112965,-1.91846e-06,-1.03755e-08,0.65858,0.00112578,-1.94959e-06,1.44973e-08,0.659704,0.00112192,-1.9061e-06,1.1991e-08,0.660824,0.00111815,-1.87012e-06,-2.85634e-09,0.66194,0.0011144,-1.87869e-06,-5.65782e-10,0.663053,0.00111064,-1.88039e-06,5.11947e-09,0.664162,0.0011069,-1.86503e-06,3.96924e-08,0.665267,0.00110328,-1.74595e-06,-4.46795e-08,0.666368,0.00109966,-1.87999e-06,1.98161e-08,0.667466,0.00109596,-1.82054e-06,2.502e-08,0.66856,0.00109239,-1.74548e-06,-6.86593e-10,0.669651,0.0010889,-1.74754e-06,-2.22739e-08,0.670738,0.00108534,-1.81437e-06,3.01776e-08,0.671821,0.0010818,-1.72383e-06,2.07732e-08,0.672902,0.00107841,-1.66151e-06,-5.36658e-08,0.673978,0.00107493,-1.82251e-06,7.46802e-08,0.675051,0.00107151,-1.59847e-06,-6.62411e-08,0.676121,0.00106811,-1.79719e-06,7.10748e-08,0.677188,0.00106473,-1.58397e-06,-3.92441e-08,0.678251,0.00106145,-1.7017e-06,2.62973e-08,0.679311,0.00105812,-1.62281e-06,-6.34035e-09,0.680367,0.00105486,-1.64183e-06,-9.36249e-10,0.68142,0.00105157,-1.64464e-06,1.00854e-08,0.68247,0.00104831,-1.61438e-06,2.01995e-08,0.683517,0.00104514,-1.55378e-06,-3.1279e-08,0.68456,0.00104194,-1.64762e-06,4.53114e-08,0.685601,0.00103878,-1.51169e-06,-3.07573e-08,0.686638,0.00103567,-1.60396e-06,1.81133e-08,0.687672,0.00103251,-1.54962e-06,1.79085e-08,0.688703,0.00102947,-1.49589e-06,-3.01428e-08,0.689731,0.00102639,-1.58632e-06,4.30583e-08,0.690756,0.00102334,-1.45715e-06,-2.28814e-08,0.691778,0.00102036,-1.52579e-06,-1.11373e-08,0.692797,0.00101727,-1.5592e-06,6.74305e-08,0.693812,0.00101436,-1.35691e-06,-7.97709e-08,0.694825,0.0010114,-1.59622e-06,7.28391e-08,0.695835,0.00100843,-1.37771e-06,-3.27715e-08,0.696842,0.00100558,-1.47602e-06,-1.35807e-09,0.697846,0.00100262,-1.48009e-06,3.82037e-08,0.698847,0.000999775,-1.36548e-06,-3.22474e-08,0.699846,0.000996948,-1.46223e-06,3.11809e-08,0.700841,0.000994117,-1.36868e-06,-3.28714e-08,0.701834,0.000991281,-1.4673e-06,4.07001e-08,0.702824,0.000988468,-1.3452e-06,-1.07197e-08,0.703811,0.000985746,-1.37736e-06,2.17866e-09,0.704795,0.000982998,-1.37082e-06,2.00521e-09,0.705777,0.000980262,-1.3648e-06,-1.01996e-08,0.706756,0.000977502,-1.3954e-06,3.87931e-08,0.707732,0.000974827,-1.27902e-06,-2.57632e-08,0.708706,0.000972192,-1.35631e-06,4.65513e-09,0.709676,0.000969493,-1.34235e-06,7.14257e-09,0.710645,0.00096683,-1.32092e-06,2.63791e-08,0.71161,0.000964267,-1.24178e-06,-5.30543e-08,0.712573,0.000961625,-1.40095e-06,6.66289e-08,0.713533,0.000959023,-1.20106e-06,-3.46474e-08,0.714491,0.000956517,-1.305e-06,1.23559e-08,0.715446,0.000953944,-1.26793e-06,-1.47763e-08,0.716399,0.000951364,-1.31226e-06,4.67494e-08,0.717349,0.000948879,-1.17201e-06,-5.3012e-08,0.718297,0.000946376,-1.33105e-06,4.60894e-08,0.719242,0.000943852,-1.19278e-06,-1.21366e-08,0.720185,0.00094143,-1.22919e-06,2.45673e-09,0.721125,0.000938979,-1.22182e-06,2.30966e-09,0.722063,0.000936543,-1.21489e-06,-1.16954e-08,0.722998,0.000934078,-1.24998e-06,4.44718e-08,0.723931,0.000931711,-1.11656e-06,-4.69823e-08,0.724861,0.000929337,-1.25751e-06,2.4248e-08,0.725789,0.000926895,-1.18477e-06,9.5949e-09,0.726715,0.000924554,-1.15598e-06,-3.02286e-09,0.727638,0.000922233,-1.16505e-06,2.49649e-09,0.72856,0.00091991,-1.15756e-06,-6.96321e-09,0.729478,0.000917575,-1.17845e-06,2.53564e-08,0.730395,0.000915294,-1.10238e-06,-3.48578e-08,0.731309,0.000912984,-1.20695e-06,5.44704e-08,0.732221,0.000910734,-1.04354e-06,-6.38144e-08,0.73313,0.000908455,-1.23499e-06,8.15781e-08,0.734038,0.00090623,-9.90253e-07,-8.3684e-08,0.734943,0.000903999,-1.2413e-06,7.43441e-08,0.735846,0.000901739,-1.01827e-06,-3.48787e-08,0.736746,0.000899598,-1.12291e-06,5.56596e-09,0.737645,0.000897369,-1.10621e-06,1.26148e-08,0.738541,0.000895194,-1.06837e-06,3.57935e-09,0.739435,0.000893068,-1.05763e-06,-2.69322e-08,0.740327,0.000890872,-1.13842e-06,4.45448e-08,0.741217,0.000888729,-1.00479e-06,-3.20376e-08,0.742105,0.000886623,-1.1009e-06,2.40011e-08,0.74299,0.000884493,-1.0289e-06,-4.36209e-09,0.743874,0.000882422,-1.04199e-06,-6.55268e-09,0.744755,0.000880319,-1.06164e-06,3.05728e-08,0.745634,0.000878287,-9.69926e-07,-5.61338e-08,0.746512,0.000876179,-1.13833e-06,7.4753e-08,0.747387,0.000874127,-9.14068e-07,-6.40644e-08,0.74826,0.000872106,-1.10626e-06,6.22955e-08,0.749131,0.000870081,-9.19375e-07,-6.59083e-08,0.75,0.000868044,-1.1171e-06,8.21284e-08,0.750867,0.000866056,-8.70714e-07,-8.37915e-08,0.751732,0.000864064,-1.12209e-06,7.42237e-08,0.752595,0.000862042,-8.99418e-07,-3.42894e-08,0.753456,0.00086014,-1.00229e-06,3.32955e-09,0.754315,0.000858146,-9.92297e-07,2.09712e-08,0.755173,0.000856224,-9.29384e-07,-2.76096e-08,0.756028,0.000854282,-1.01221e-06,2.98627e-08,0.756881,0.000852348,-9.22625e-07,-3.22365e-08,0.757733,0.000850406,-1.01933e-06,3.94786e-08,0.758582,0.000848485,-9.00898e-07,-6.46833e-09,0.75943,0.000846664,-9.20303e-07,-1.36052e-08,0.760275,0.000844783,-9.61119e-07,1.28447e-09,0.761119,0.000842864,-9.57266e-07,8.4674e-09,0.761961,0.000840975,-9.31864e-07,2.44506e-08,0.762801,0.000839185,-8.58512e-07,-4.6665e-08,0.763639,0.000837328,-9.98507e-07,4.30001e-08,0.764476,0.00083546,-8.69507e-07,-6.12609e-09,0.76531,0.000833703,-8.87885e-07,-1.84959e-08,0.766143,0.000831871,-9.43372e-07,2.05052e-08,0.766974,0.000830046,-8.81857e-07,-3.92026e-09,0.767803,0.000828271,-8.93618e-07,-4.82426e-09,0.768631,0.000826469,-9.0809e-07,2.32172e-08,0.769456,0.000824722,-8.38439e-07,-2.84401e-08,0.77028,0.00082296,-9.23759e-07,3.09386e-08,0.771102,0.000821205,-8.30943e-07,-3.57099e-08,0.771922,0.000819436,-9.38073e-07,5.22963e-08,0.772741,0.000817717,-7.81184e-07,-5.42658e-08,0.773558,0.000815992,-9.43981e-07,4.55579e-08,0.774373,0.000814241,-8.07308e-07,-8.75656e-09,0.775186,0.0008126,-8.33578e-07,-1.05315e-08,0.775998,0.000810901,-8.65172e-07,-8.72188e-09,0.776808,0.000809145,-8.91338e-07,4.54191e-08,0.777616,0.000807498,-7.5508e-07,-5.37454e-08,0.778423,0.000805827,-9.16317e-07,5.03532e-08,0.779228,0.000804145,-7.65257e-07,-2.84584e-08,0.780031,0.000802529,-8.50632e-07,3.87579e-09,0.780833,0.00080084,-8.39005e-07,1.29552e-08,0.781633,0.0007992,-8.00139e-07,3.90804e-09,0.782432,0.000797612,-7.88415e-07,-2.85874e-08,0.783228,0.000795949,-8.74177e-07,5.0837e-08,0.784023,0.000794353,-7.21666e-07,-5.55513e-08,0.784817,0.000792743,-8.8832e-07,5.21587e-08,0.785609,0.000791123,-7.31844e-07,-3.38744e-08,0.786399,0.000789558,-8.33467e-07,2.37342e-08,0.787188,0.000787962,-7.62264e-07,-1.45775e-09,0.787975,0.000786433,-7.66638e-07,-1.79034e-08,0.788761,0.000784846,-8.20348e-07,1.34665e-08,0.789545,0.000783246,-7.79948e-07,2.3642e-08,0.790327,0.000781757,-7.09022e-07,-4.84297e-08,0.791108,0.000780194,-8.54311e-07,5.08674e-08,0.791888,0.000778638,-7.01709e-07,-3.58303e-08,0.792666,0.000777127,-8.092e-07,3.28493e-08,0.793442,0.000775607,-7.10652e-07,-3.59624e-08,0.794217,0.000774078,-8.1854e-07,5.13959e-08,0.79499,0.000772595,-6.64352e-07,-5.04121e-08,0.795762,0.000771115,-8.15588e-07,3.10431e-08,0.796532,0.000769577,-7.22459e-07,-1.41557e-08,0.797301,0.00076809,-7.64926e-07,2.55795e-08,0.798069,0.000766636,-6.88187e-07,-2.85578e-08,0.798835,0.000765174,-7.73861e-07,2.90472e-08,0.799599,0.000763714,-6.86719e-07,-2.80262e-08,0.800362,0.000762256,-7.70798e-07,2.34531e-08,0.801123,0.000760785,-7.00438e-07,-6.18144e-09,0.801884,0.000759366,-7.18983e-07,1.27263e-09,0.802642,0.000757931,-7.15165e-07,1.09101e-09,0.803399,0.000756504,-7.11892e-07,-5.63675e-09,0.804155,0.000755064,-7.28802e-07,2.14559e-08,0.80491,0.00075367,-6.64434e-07,-2.05821e-08,0.805663,0.00075228,-7.26181e-07,1.26812e-09,0.806414,0.000750831,-7.22377e-07,1.55097e-08,0.807164,0.000749433,-6.75848e-07,-3.70216e-09,0.807913,0.00074807,-6.86954e-07,-7.0105e-10,0.80866,0.000746694,-6.89057e-07,6.5063e-09,0.809406,0.000745336,-6.69538e-07,-2.53242e-08,0.810151,0.000743921,-7.45511e-07,3.51858e-08,0.810894,0.000742535,-6.39953e-07,3.79034e-09,0.811636,0.000741267,-6.28582e-07,-5.03471e-08,0.812377,0.000739858,-7.79624e-07,7.83886e-08,0.813116,0.000738534,-5.44458e-07,-8.43935e-08,0.813854,0.000737192,-7.97638e-07,8.03714e-08,0.81459,0.000735838,-5.56524e-07,-5.82784e-08,0.815325,0.00073455,-7.31359e-07,3.35329e-08,0.816059,0.000733188,-6.3076e-07,-1.62486e-08,0.816792,0.000731878,-6.79506e-07,3.14614e-08,0.817523,0.000730613,-5.85122e-07,-4.99925e-08,0.818253,0.000729293,-7.35099e-07,4.92994e-08,0.818982,0.000727971,-5.87201e-07,-2.79959e-08,0.819709,0.000726712,-6.71189e-07,3.07959e-09,0.820435,0.000725379,-6.6195e-07,1.56777e-08,0.82116,0.000724102,-6.14917e-07,-6.18564e-09,0.821883,0.000722854,-6.33474e-07,9.06488e-09,0.822606,0.000721614,-6.06279e-07,-3.00739e-08,0.823327,0.000720311,-6.96501e-07,5.16262e-08,0.824046,0.000719073,-5.41623e-07,-5.72214e-08,0.824765,0.000717818,-7.13287e-07,5.80503e-08,0.825482,0.000716566,-5.39136e-07,-5.57703e-08,0.826198,0.00071532,-7.06447e-07,4.58215e-08,0.826912,0.000714045,-5.68983e-07,-8.30636e-09,0.827626,0.000712882,-5.93902e-07,-1.25961e-08,0.828338,0.000711656,-6.3169e-07,-9.13985e-10,0.829049,0.00071039,-6.34432e-07,1.62519e-08,0.829759,0.00070917,-5.85676e-07,-4.48904e-09,0.830468,0.000707985,-5.99143e-07,1.70418e-09,0.831175,0.000706792,-5.9403e-07,-2.32768e-09,0.831881,0.000705597,-6.01014e-07,7.60648e-09,0.832586,0.000704418,-5.78194e-07,-2.80982e-08,0.83329,0.000703177,-6.62489e-07,4.51817e-08,0.833993,0.000701988,-5.26944e-07,-3.34192e-08,0.834694,0.000700834,-6.27201e-07,2.88904e-08,0.835394,0.000699666,-5.4053e-07,-2.25378e-08,0.836093,0.000698517,-6.08143e-07,1.65589e-09,0.836791,0.000697306,-6.03176e-07,1.59142e-08,0.837488,0.000696147,-5.55433e-07,-5.70801e-09,0.838184,0.000695019,-5.72557e-07,6.91792e-09,0.838878,0.000693895,-5.51803e-07,-2.19637e-08,0.839571,0.000692725,-6.17694e-07,2.13321e-08,0.840263,0.000691554,-5.53698e-07,-3.75996e-09,0.840954,0.000690435,-5.64978e-07,-6.29219e-09,0.841644,0.000689287,-5.83855e-07,2.89287e-08,0.842333,0.000688206,-4.97068e-07,-4.98181e-08,0.843021,0.000687062,-6.46523e-07,5.11344e-08,0.843707,0.000685922,-4.9312e-07,-3.55102e-08,0.844393,0.00068483,-5.9965e-07,3.13019e-08,0.845077,0.000683724,-5.05745e-07,-3.00925e-08,0.84576,0.000682622,-5.96022e-07,2.94636e-08,0.846442,0.000681519,-5.07631e-07,-2.81572e-08,0.847123,0.000680419,-5.92103e-07,2.35606e-08,0.847803,0.000679306,-5.21421e-07,-6.48045e-09,0.848482,0.000678243,-5.40863e-07,2.36124e-09,0.849159,0.000677169,-5.33779e-07,-2.96461e-09,0.849836,0.000676092,-5.42673e-07,9.49728e-09,0.850512,0.000675035,-5.14181e-07,-3.50245e-08,0.851186,0.000673902,-6.19254e-07,7.09959e-08,0.851859,0.000672876,-4.06267e-07,-7.01453e-08,0.852532,0.000671853,-6.16703e-07,3.07714e-08,0.853203,0.000670712,-5.24388e-07,6.66423e-09,0.853873,0.000669684,-5.04396e-07,2.17629e-09,0.854542,0.000668681,-4.97867e-07,-1.53693e-08,0.855211,0.000667639,-5.43975e-07,-3.03752e-10,0.855878,0.000666551,-5.44886e-07,1.65844e-08,0.856544,0.000665511,-4.95133e-07,-6.42907e-09,0.857209,0.000664501,-5.1442e-07,9.13195e-09,0.857873,0.0006635,-4.87024e-07,-3.00987e-08,0.858536,0.000662435,-5.7732e-07,5.16584e-08,0.859198,0.000661436,-4.22345e-07,-5.73255e-08,0.859859,0.000660419,-5.94322e-07,5.84343e-08,0.860518,0.000659406,-4.19019e-07,-5.72022e-08,0.861177,0.000658396,-5.90626e-07,5.11653e-08,0.861835,0.000657368,-4.3713e-07,-2.82495e-08,0.862492,0.000656409,-5.21878e-07,2.22788e-09,0.863148,0.000655372,-5.15195e-07,1.9338e-08,0.863803,0.0006544,-4.5718e-07,-1.99754e-08,0.864457,0.000653425,-5.17107e-07,9.59024e-10,0.86511,0.000652394,-5.1423e-07,1.61393e-08,0.865762,0.000651414,-4.65812e-07,-5.91149e-09,0.866413,0.000650465,-4.83546e-07,7.50665e-09,0.867063,0.00064952,-4.61026e-07,-2.4115e-08,0.867712,0.000648526,-5.33371e-07,2.93486e-08,0.86836,0.000647547,-4.45325e-07,-3.36748e-08,0.869007,0.000646555,-5.4635e-07,4.57461e-08,0.869653,0.0006456,-4.09112e-07,-3.01002e-08,0.870298,0.000644691,-4.99412e-07,1.50501e-08,0.870942,0.000643738,-4.54262e-07,-3.01002e-08,0.871585,0.000642739,-5.44563e-07,4.57461e-08,0.872228,0.000641787,-4.07324e-07,-3.36748e-08,0.872869,0.000640871,-5.08349e-07,2.93486e-08,0.873509,0.000639943,-4.20303e-07,-2.4115e-08,0.874149,0.00063903,-4.92648e-07,7.50655e-09,0.874787,0.000638067,-4.70128e-07,-5.91126e-09,0.875425,0.000637109,-4.87862e-07,1.61385e-08,0.876062,0.000636182,-4.39447e-07,9.61961e-10,0.876697,0.000635306,-4.36561e-07,-1.99863e-08,0.877332,0.000634373,-4.9652e-07,1.93785e-08,0.877966,0.000633438,-4.38384e-07,2.07697e-09,0.878599,0.000632567,-4.32153e-07,-2.76864e-08,0.879231,0.00063162,-5.15212e-07,4.90641e-08,0.879862,0.000630737,-3.6802e-07,-4.93606e-08,0.880493,0.000629852,-5.16102e-07,2.9169e-08,0.881122,0.000628908,-4.28595e-07,-7.71083e-09,0.881751,0.000628027,-4.51727e-07,1.6744e-09,0.882378,0.000627129,-4.46704e-07,1.01317e-09,0.883005,0.000626239,-4.43665e-07,-5.72703e-09,0.883631,0.000625334,-4.60846e-07,2.1895e-08,0.884255,0.000624478,-3.95161e-07,-2.22481e-08,0.88488,0.000623621,-4.61905e-07,7.4928e-09,0.885503,0.00062272,-4.39427e-07,-7.72306e-09,0.886125,0.000621818,-4.62596e-07,2.33995e-08,0.886746,0.000620963,-3.92398e-07,-2.62704e-08,0.887367,0.000620099,-4.71209e-07,2.20775e-08,0.887987,0.000619223,-4.04976e-07,-2.43496e-09,0.888605,0.000618406,-4.12281e-07,-1.23377e-08,0.889223,0.000617544,-4.49294e-07,-7.81876e-09,0.88984,0.000616622,-4.72751e-07,4.36128e-08,0.890457,0.000615807,-3.41912e-07,-4.7423e-08,0.891072,0.000614981,-4.84181e-07,2.68698e-08,0.891687,0.000614093,-4.03572e-07,-4.51384e-10,0.8923,0.000613285,-4.04926e-07,-2.50643e-08,0.892913,0.0006124,-4.80119e-07,4.11038e-08,0.893525,0.000611563,-3.56808e-07,-2.01414e-08,0.894136,0.000610789,-4.17232e-07,-2.01426e-08,0.894747,0.000609894,-4.7766e-07,4.11073e-08,0.895356,0.000609062,-3.54338e-07,-2.50773e-08,0.895965,0.000608278,-4.2957e-07,-4.02954e-10,0.896573,0.000607418,-4.30779e-07,2.66891e-08,0.89718,0.000606636,-3.50711e-07,-4.67489e-08,0.897786,0.000605795,-4.90958e-07,4.10972e-08,0.898391,0.000604936,-3.67666e-07,1.56948e-09,0.898996,0.000604205,-3.62958e-07,-4.73751e-08,0.8996,0.000603337,-5.05083e-07,6.87214e-08,0.900202,0.000602533,-2.98919e-07,-4.86966e-08,0.900805,0.000601789,-4.45009e-07,6.85589e-09,0.901406,0.00060092,-4.24441e-07,2.1273e-08,0.902007,0.000600135,-3.60622e-07,-3.23434e-08,0.902606,0.000599317,-4.57652e-07,4.84959e-08,0.903205,0.000598547,-3.12164e-07,-4.24309e-08,0.903803,0.000597795,-4.39457e-07,2.01844e-09,0.904401,0.000596922,-4.33402e-07,3.43571e-08,0.904997,0.000596159,-3.30331e-07,-2.02374e-08,0.905593,0.000595437,-3.91043e-07,-1.30123e-08,0.906188,0.000594616,-4.3008e-07,1.26819e-08,0.906782,0.000593794,-3.92034e-07,2.18894e-08,0.907376,0.000593076,-3.26366e-07,-4.06349e-08,0.907968,0.000592301,-4.4827e-07,2.1441e-08,0.90856,0.000591469,-3.83947e-07,1.44754e-08,0.909151,0.000590744,-3.40521e-07,-1.97379e-08,0.909742,0.000590004,-3.99735e-07,4.87161e-09,0.910331,0.000589219,-3.8512e-07,2.51532e-10,0.91092,0.00058845,-3.84366e-07,-5.87776e-09,0.911508,0.000587663,-4.01999e-07,2.32595e-08,0.912096,0.000586929,-3.3222e-07,-2.75554e-08,0.912682,0.000586182,-4.14887e-07,2.73573e-08,0.913268,0.000585434,-3.32815e-07,-2.22692e-08,0.913853,0.000584702,-3.99622e-07,2.11486e-09,0.914437,0.000583909,-3.93278e-07,1.38098e-08,0.915021,0.000583164,-3.51848e-07,2.25042e-09,0.915604,0.000582467,-3.45097e-07,-2.28115e-08,0.916186,0.000581708,-4.13531e-07,2.93911e-08,0.916767,0.000580969,-3.25358e-07,-3.51481e-08,0.917348,0.000580213,-4.30803e-07,5.15967e-08,0.917928,0.000579506,-2.76012e-07,-5.20296e-08,0.918507,0.000578798,-4.32101e-07,3.73124e-08,0.919085,0.000578046,-3.20164e-07,-3.76154e-08,0.919663,0.000577293,-4.3301e-07,5.35447e-08,0.92024,0.000576587,-2.72376e-07,-5.7354e-08,0.920816,0.000575871,-4.44438e-07,5.66621e-08,0.921391,0.000575152,-2.74452e-07,-5.00851e-08,0.921966,0.000574453,-4.24707e-07,2.4469e-08,0.92254,0.000573677,-3.513e-07,1.18138e-08,0.923114,0.000573009,-3.15859e-07,-1.21195e-08,0.923686,0.000572341,-3.52217e-07,-2.29403e-08,0.924258,0.000571568,-4.21038e-07,4.4276e-08,0.924829,0.000570859,-2.8821e-07,-3.49546e-08,0.9254,0.000570178,-3.93074e-07,3.59377e-08,0.92597,0.000569499,-2.85261e-07,-4.91915e-08,0.926539,0.000568781,-4.32835e-07,4.16189e-08,0.927107,0.00056804,-3.07979e-07,1.92523e-09,0.927675,0.00056743,-3.02203e-07,-4.93198e-08,0.928242,0.000566678,-4.50162e-07,7.61447e-08,0.928809,0.000566006,-2.21728e-07,-7.6445e-08,0.929374,0.000565333,-4.51063e-07,5.08216e-08,0.929939,0.000564583,-2.98599e-07,-7.63212e-09,0.930503,0.000563963,-3.21495e-07,-2.02931e-08,0.931067,0.000563259,-3.82374e-07,2.92001e-08,0.93163,0.000562582,-2.94774e-07,-3.69025e-08,0.932192,0.000561882,-4.05482e-07,5.88053e-08,0.932754,0.000561247,-2.29066e-07,-7.91094e-08,0.933315,0.000560552,-4.66394e-07,7.88184e-08,0.933875,0.000559856,-2.29939e-07,-5.73501e-08,0.934434,0.000559224,-4.01989e-07,3.13727e-08,0.934993,0.000558514,-3.07871e-07,-8.53611e-09,0.935551,0.000557873,-3.33479e-07,2.77175e-09,0.936109,0.000557214,-3.25164e-07,-2.55091e-09,0.936666,0.000556556,-3.32817e-07,7.43188e-09,0.937222,0.000555913,-3.10521e-07,-2.71766e-08,0.937778,0.00055521,-3.92051e-07,4.167e-08,0.938333,0.000554551,-2.67041e-07,-2.02941e-08,0.938887,0.000553956,-3.27923e-07,-2.00984e-08,0.93944,0.00055324,-3.88218e-07,4.10828e-08,0.939993,0.000552587,-2.6497e-07,-2.50237e-08,0.940546,0.000551982,-3.40041e-07,-5.92583e-10,0.941097,0.0005513,-3.41819e-07,2.7394e-08,0.941648,0.000550698,-2.59637e-07,-4.93788e-08,0.942199,0.000550031,-4.07773e-07,5.09119e-08,0.942748,0.000549368,-2.55038e-07,-3.50595e-08,0.943297,0.000548753,-3.60216e-07,2.97214e-08,0.943846,0.000548122,-2.71052e-07,-2.42215e-08,0.944394,0.000547507,-3.43716e-07,7.55985e-09,0.944941,0.000546842,-3.21037e-07,-6.01796e-09,0.945487,0.000546182,-3.3909e-07,1.65119e-08,0.946033,0.000545553,-2.89555e-07,-4.2498e-10,0.946578,0.000544973,-2.9083e-07,-1.4812e-08,0.947123,0.000544347,-3.35266e-07,6.83068e-11,0.947667,0.000543676,-3.35061e-07,1.45388e-08,0.94821,0.00054305,-2.91444e-07,1.38123e-09,0.948753,0.000542471,-2.87301e-07,-2.00637e-08,0.949295,0.000541836,-3.47492e-07,1.92688e-08,0.949837,0.000541199,-2.89685e-07,2.59298e-09,0.950378,0.000540628,-2.81906e-07,-2.96407e-08,0.950918,0.000539975,-3.70829e-07,5.63652e-08,0.951458,0.000539402,-2.01733e-07,-7.66107e-08,0.951997,0.000538769,-4.31565e-07,7.12638e-08,0.952535,0.00053812,-2.17774e-07,-2.96305e-08,0.953073,0.000537595,-3.06665e-07,-1.23464e-08,0.95361,0.000536945,-3.43704e-07,1.94114e-08,0.954147,0.000536316,-2.8547e-07,-5.69451e-09,0.954683,0.000535728,-3.02554e-07,3.36666e-09,0.955219,0.000535133,-2.92454e-07,-7.77208e-09,0.955753,0.000534525,-3.1577e-07,2.77216e-08,0.956288,0.000533976,-2.32605e-07,-4.35097e-08,0.956821,0.00053338,-3.63134e-07,2.7108e-08,0.957354,0.000532735,-2.8181e-07,-5.31772e-09,0.957887,0.000532156,-2.97764e-07,-5.83718e-09,0.958419,0.000531543,-3.15275e-07,2.86664e-08,0.95895,0.000530998,-2.29276e-07,-4.9224e-08,0.959481,0.000530392,-3.76948e-07,4.90201e-08,0.960011,0.000529785,-2.29887e-07,-2.76471e-08,0.96054,0.000529243,-3.12829e-07,1.96385e-09,0.961069,0.000528623,-3.06937e-07,1.97917e-08,0.961598,0.000528068,-2.47562e-07,-2.15261e-08,0.962125,0.000527508,-3.1214e-07,6.70795e-09,0.962653,0.000526904,-2.92016e-07,-5.30573e-09,0.963179,0.000526304,-3.07934e-07,1.4515e-08,0.963705,0.000525732,-2.64389e-07,6.85048e-09,0.964231,0.000525224,-2.43837e-07,-4.19169e-08,0.964756,0.00052461,-3.69588e-07,4.1608e-08,0.96528,0.000523996,-2.44764e-07,-5.30598e-09,0.965804,0.000523491,-2.60682e-07,-2.03841e-08,0.966327,0.000522908,-3.21834e-07,2.72378e-08,0.966849,0.000522346,-2.40121e-07,-2.89625e-08,0.967371,0.000521779,-3.27008e-07,2.90075e-08,0.967893,0.000521212,-2.39986e-07,-2.74629e-08,0.968414,0.00052065,-3.22374e-07,2.12396e-08,0.968934,0.000520069,-2.58656e-07,2.10922e-09,0.969454,0.000519558,-2.52328e-07,-2.96765e-08,0.969973,0.000518964,-3.41357e-07,5.6992e-08,0.970492,0.000518452,-1.70382e-07,-7.90821e-08,0.97101,0.000517874,-4.07628e-07,8.05224e-08,0.971528,0.000517301,-1.66061e-07,-6.41937e-08,0.972045,0.000516776,-3.58642e-07,5.70429e-08,0.972561,0.00051623,-1.87513e-07,-4.47686e-08,0.973077,0.00051572,-3.21819e-07,2.82237e-09,0.973593,0.000515085,-3.13352e-07,3.34792e-08,0.974108,0.000514559,-2.12914e-07,-1.75298e-08,0.974622,0.000514081,-2.65503e-07,-2.29648e-08,0.975136,0.000513481,-3.34398e-07,4.97843e-08,0.975649,0.000512961,-1.85045e-07,-5.6963e-08,0.976162,0.00051242,-3.55934e-07,5.88585e-08,0.976674,0.000511885,-1.79359e-07,-5.92616e-08,0.977185,0.000511348,-3.57143e-07,5.89785e-08,0.977696,0.000510811,-1.80208e-07,-5.74433e-08,0.978207,0.000510278,-3.52538e-07,5.15854e-08,0.978717,0.000509728,-1.97781e-07,-2.9689e-08,0.979226,0.000509243,-2.86848e-07,7.56591e-09,0.979735,0.000508692,-2.64151e-07,-5.74649e-10,0.980244,0.000508162,-2.65875e-07,-5.26732e-09,0.980752,0.000507615,-2.81677e-07,2.16439e-08,0.981259,0.000507116,-2.16745e-07,-2.17037e-08,0.981766,0.000506618,-2.81856e-07,5.56636e-09,0.982272,0.000506071,-2.65157e-07,-5.61689e-10,0.982778,0.000505539,-2.66842e-07,-3.31963e-09,0.983283,0.000504995,-2.76801e-07,1.38402e-08,0.983788,0.000504483,-2.3528e-07,7.56339e-09,0.984292,0.000504035,-2.1259e-07,-4.40938e-08,0.984796,0.000503478,-3.44871e-07,4.96026e-08,0.985299,0.000502937,-1.96064e-07,-3.51071e-08,0.985802,0.000502439,-3.01385e-07,3.12212e-08,0.986304,0.00050193,-2.07721e-07,-3.0173e-08,0.986806,0.000501424,-2.9824e-07,2.9866e-08,0.987307,0.000500917,-2.08642e-07,-2.96865e-08,0.987808,0.000500411,-2.97702e-07,2.92753e-08,0.988308,0.000499903,-2.09876e-07,-2.78101e-08,0.988807,0.0004994,-2.93306e-07,2.23604e-08,0.989307,0.000498881,-2.26225e-07,-2.02681e-09,0.989805,0.000498422,-2.32305e-07,-1.42531e-08,0.990303,0.000497915,-2.75065e-07,-5.65232e-10,0.990801,0.000497363,-2.76761e-07,1.65141e-08,0.991298,0.000496859,-2.27218e-07,-5.88639e-09,0.991795,0.000496387,-2.44878e-07,7.0315e-09,0.992291,0.000495918,-2.23783e-07,-2.22396e-08,0.992787,0.000495404,-2.90502e-07,2.23224e-08,0.993282,0.00049489,-2.23535e-07,-7.44543e-09,0.993776,0.000494421,-2.45871e-07,7.45924e-09,0.994271,0.000493951,-2.23493e-07,-2.23915e-08,0.994764,0.000493437,-2.90668e-07,2.25021e-08,0.995257,0.000492923,-2.23161e-07,-8.01218e-09,0.99575,0.000492453,-2.47198e-07,9.54669e-09,0.996242,0.000491987,-2.18558e-07,-3.01746e-08,0.996734,0.000491459,-3.09082e-07,5.1547e-08,0.997225,0.000490996,-1.54441e-07,-5.68039e-08,0.997716,0.000490517,-3.24853e-07,5.64594e-08,0.998206,0.000490036,-1.55474e-07,-4.98245e-08,0.998696,0.000489576,-3.04948e-07,2.36292e-08,0.999186,0.000489037,-2.3406e-07,1.49121e-08,0.999674,0.000488613,-1.89324e-07,-2.3673e-08,1.00016,0.000488164,-2.60343e-07,2.01754e-08,1.00065,0.000487704,-1.99816e-07,-5.70288e-08,1.00114,0.000487133,-3.70903e-07,8.87303e-08,1.00162,0.000486657,-1.04712e-07,-5.94737e-08,1.00211,0.000486269,-2.83133e-07,2.99553e-08,1.0026,0.000485793,-1.93267e-07,-6.03474e-08,1.00308,0.000485225,-3.74309e-07,9.2225e-08,1.00357,0.000484754,-9.76345e-08,-7.0134e-08,1.00405,0.000484348,-3.08036e-07,6.91016e-08,1.00454,0.000483939,-1.00731e-07,-8.70633e-08,1.00502,0.000483476,-3.61921e-07,4.07328e-08,1.0055,0.000482875,-2.39723e-07,4.33413e-08,1.00599,0.000482525,-1.09699e-07,-9.48886e-08,1.00647,0.000482021,-3.94365e-07,9.77947e-08,1.00695,0.000481526,-1.00981e-07,-5.78713e-08,1.00743,0.00048115,-2.74595e-07,1.44814e-08,1.00791,0.000480645,-2.31151e-07,-5.42665e-11,1.00839,0.000480182,-2.31314e-07,-1.42643e-08,1.00887,0.000479677,-2.74106e-07,5.71115e-08,1.00935,0.0004793,-1.02772e-07,-9.49724e-08,1.00983,0.000478809,-3.87689e-07,8.43596e-08,1.01031,0.000478287,-1.3461e-07,-4.04755e-09,1.01079,0.000478006,-1.46753e-07,-6.81694e-08,1.01127,0.000477508,-3.51261e-07,3.83067e-08,1.01174,0.00047692,-2.36341e-07,3.41521e-08,1.01222,0.00047655,-1.33885e-07,-5.57058e-08,1.0127,0.000476115,-3.01002e-07,6.94616e-08,1.01317,0.000475721,-9.26174e-08,-1.02931e-07,1.01365,0.000475227,-4.01412e-07,1.03846e-07,1.01412,0.000474736,-8.98751e-08,-7.40321e-08,1.0146,0.000474334,-3.11971e-07,7.30735e-08,1.01507,0.00047393,-9.27508e-08,-9.90527e-08,1.01554,0.000473447,-3.89909e-07,8.47188e-08,1.01602,0.000472921,-1.35753e-07,-1.40381e-09,1.01649,0.000472645,-1.39964e-07,-7.91035e-08,1.01696,0.000472128,-3.77275e-07,7.93993e-08,1.01744,0.000471612,-1.39077e-07,-7.52607e-11,1.01791,0.000471334,-1.39302e-07,-7.90983e-08,1.01838,0.000470818,-3.76597e-07,7.80499e-08,1.01885,0.000470299,-1.42448e-07,5.31733e-09,1.01932,0.00047003,-1.26496e-07,-9.93193e-08,1.01979,0.000469479,-4.24453e-07,1.53541e-07,1.02026,0.00046909,3.617e-08,-1.57217e-07,1.02073,0.000468691,-4.35482e-07,1.177e-07,1.02119,0.000468173,-8.23808e-08,-7.51659e-08,1.02166,0.000467783,-3.07878e-07,6.37538e-08,1.02213,0.000467358,-1.16617e-07,-6.064e-08,1.0226,0.000466943,-2.98537e-07,5.9597e-08,1.02306,0.000466525,-1.19746e-07,-5.85386e-08,1.02353,0.00046611,-2.95362e-07,5.53482e-08,1.024,0.000465685,-1.29317e-07,-4.36449e-08,1.02446,0.000465296,-2.60252e-07,2.20268e-11,1.02493,0.000464775,-2.60186e-07,4.35568e-08,1.02539,0.000464386,-1.29516e-07,-5.50398e-08,1.02586,0.000463961,-2.94635e-07,5.73932e-08,1.02632,0.000463544,-1.22456e-07,-5.53236e-08,1.02678,0.000463133,-2.88426e-07,4.46921e-08,1.02725,0.000462691,-1.5435e-07,-4.23534e-09,1.02771,0.000462369,-1.67056e-07,-2.77507e-08,1.02817,0.000461952,-2.50308e-07,-3.97101e-09,1.02863,0.000461439,-2.62221e-07,4.36348e-08,1.02909,0.000461046,-1.31317e-07,-5.13589e-08,1.02955,0.000460629,-2.85394e-07,4.25913e-08,1.03001,0.000460186,-1.5762e-07,2.0285e-10,1.03047,0.000459871,-1.57011e-07,-4.34027e-08,1.03093,0.000459427,-2.87219e-07,5.41987e-08,1.03139,0.000459015,-1.24623e-07,-5.4183e-08,1.03185,0.000458604,-2.87172e-07,4.33239e-08,1.03231,0.000458159,-1.572e-07,9.65817e-11,1.03277,0.000457845,-1.56911e-07,-4.37103e-08,1.03323,0.0004574,-2.88041e-07,5.55351e-08,1.03368,0.000456991,-1.21436e-07,-5.9221e-08,1.03414,0.00045657,-2.99099e-07,6.21394e-08,1.0346,0.000456158,-1.1268e-07,-7.01275e-08,1.03505,0.000455723,-3.23063e-07,9.91614e-08,1.03551,0.000455374,-2.55788e-08,-8.80996e-08,1.03596,0.000455058,-2.89878e-07,1.48184e-08,1.03642,0.000454523,-2.45422e-07,2.88258e-08,1.03687,0.000454119,-1.58945e-07,-1.09125e-08,1.03733,0.000453768,-1.91682e-07,1.48241e-08,1.03778,0.000453429,-1.4721e-07,-4.83838e-08,1.03823,0.00045299,-2.92361e-07,5.95019e-08,1.03869,0.000452584,-1.13856e-07,-7.04146e-08,1.03914,0.000452145,-3.25099e-07,1.02947e-07,1.03959,0.000451803,-1.62583e-08,-1.02955e-07,1.04004,0.000451462,-3.25123e-07,7.04544e-08,1.04049,0.000451023,-1.1376e-07,-5.96534e-08,1.04094,0.000450616,-2.9272e-07,4.89499e-08,1.04139,0.000450178,-1.45871e-07,-1.69369e-08,1.04184,0.000449835,-1.96681e-07,1.87977e-08,1.04229,0.000449498,-1.40288e-07,-5.82539e-08,1.04274,0.000449043,-3.1505e-07,9.50087e-08,1.04319,0.000448698,-3.00238e-08,-8.33623e-08,1.04364,0.000448388,-2.80111e-07,2.20363e-11,1.04409,0.000447828,-2.80045e-07,8.32742e-08,1.04454,0.000447517,-3.02221e-08,-9.47002e-08,1.04498,0.000447173,-3.14323e-07,5.7108e-08,1.04543,0.000446716,-1.42999e-07,-1.45225e-08,1.04588,0.000446386,-1.86566e-07,9.82022e-10,1.04632,0.000446016,-1.8362e-07,1.05944e-08,1.04677,0.00044568,-1.51837e-07,-4.33597e-08,1.04721,0.000445247,-2.81916e-07,4.36352e-08,1.04766,0.000444814,-1.51011e-07,-1.19717e-08,1.0481,0.000444476,-1.86926e-07,4.25158e-09,1.04855,0.000444115,-1.74171e-07,-5.03461e-09,1.04899,0.000443751,-1.89275e-07,1.58868e-08,1.04944,0.00044342,-1.41614e-07,-5.85127e-08,1.04988,0.000442961,-3.17152e-07,9.89548e-08,1.05032,0.000442624,-2.0288e-08,-9.88878e-08,1.05076,0.000442287,-3.16951e-07,5.81779e-08,1.05121,0.000441827,-1.42418e-07,-1.46144e-08,1.05165,0.000441499,-1.86261e-07,2.79892e-10,1.05209,0.000441127,-1.85421e-07,1.34949e-08,1.05253,0.000440797,-1.44937e-07,-5.42594e-08,1.05297,0.000440344,-3.07715e-07,8.43335e-08,1.05341,0.000439982,-5.47146e-08,-4.46558e-08,1.05385,0.000439738,-1.88682e-07,-2.49193e-08,1.05429,0.000439286,-2.6344e-07,2.5124e-08,1.05473,0.000438835,-1.88068e-07,4.36328e-08,1.05517,0.000438589,-5.71699e-08,-8.04459e-08,1.05561,0.000438234,-2.98508e-07,3.97324e-08,1.05605,0.000437756,-1.79311e-07,4.07258e-08,1.05648,0.000437519,-5.71332e-08,-8.34263e-08,1.05692,0.000437155,-3.07412e-07,5.45608e-08,1.05736,0.000436704,-1.4373e-07,-1.56078e-08,1.05779,0.000436369,-1.90553e-07,7.87043e-09,1.05823,0.000436012,-1.66942e-07,-1.58739e-08,1.05867,0.00043563,-2.14563e-07,5.56251e-08,1.0591,0.000435368,-4.76881e-08,-8.74172e-08,1.05954,0.000435011,-3.0994e-07,5.56251e-08,1.05997,0.000434558,-1.43064e-07,-1.58739e-08,1.06041,0.000434224,-1.90686e-07,7.87042e-09,1.06084,0.000433866,-1.67075e-07,-1.56078e-08,1.06127,0.000433485,-2.13898e-07,5.45609e-08,1.06171,0.000433221,-5.02157e-08,-8.34263e-08,1.06214,0.00043287,-3.00495e-07,4.07258e-08,1.06257,0.000432391,-1.78317e-07,3.97325e-08,1.063,0.000432154,-5.91198e-08,-8.04464e-08,1.06344,0.000431794,-3.00459e-07,4.36347e-08,1.06387,0.000431324,-1.69555e-07,2.5117e-08,1.0643,0.000431061,-9.42041e-08,-2.48934e-08,1.06473,0.000430798,-1.68884e-07,-4.47527e-08,1.06516,0.000430326,-3.03142e-07,8.46951e-08,1.06559,0.000429973,-4.90573e-08,-5.56089e-08,1.06602,0.000429708,-2.15884e-07,1.85314e-08,1.06645,0.000429332,-1.6029e-07,-1.85166e-08,1.06688,0.000428956,-2.1584e-07,5.5535e-08,1.06731,0.000428691,-4.92347e-08,-8.44142e-08,1.06774,0.000428339,-3.02477e-07,4.37032e-08,1.06816,0.000427865,-1.71368e-07,2.88107e-08,1.06859,0.000427609,-8.49356e-08,-3.97367e-08,1.06902,0.00042732,-2.04146e-07,1.09267e-08,1.06945,0.000426945,-1.71365e-07,-3.97023e-09,1.06987,0.00042659,-1.83276e-07,4.9542e-09,1.0703,0.000426238,-1.68414e-07,-1.58466e-08,1.07073,0.000425854,-2.15953e-07,5.84321e-08,1.07115,0.000425597,-4.0657e-08,-9.86725e-08,1.07158,0.00042522,-3.36674e-07,9.78392e-08,1.072,0.00042484,-4.31568e-08,-5.42658e-08,1.07243,0.000424591,-2.05954e-07,1.45377e-11,1.07285,0.000424179,-2.0591e-07,5.42076e-08,1.07328,0.00042393,-4.32877e-08,-9.76357e-08,1.0737,0.00042355,-3.36195e-07,9.79165e-08,1.07412,0.000423172,-4.24451e-08,-5.56118e-08,1.07455,0.00042292,-2.09281e-07,5.32143e-09,1.07497,0.000422518,-1.93316e-07,3.43261e-08,1.07539,0.000422234,-9.0338e-08,-2.34165e-08,1.07581,0.000421983,-1.60588e-07,-5.98692e-08,1.07623,0.000421482,-3.40195e-07,1.43684e-07,1.07666,0.000421233,9.08574e-08,-1.5724e-07,1.07708,0.000420943,-3.80862e-07,1.27647e-07,1.0775,0.000420564,2.0791e-09,-1.1493e-07,1.07792,0.000420223,-3.4271e-07,9.36534e-08,1.07834,0.000419819,-6.17499e-08,-2.12653e-08,1.07876,0.000419632,-1.25546e-07,-8.59219e-09,1.07918,0.000419355,-1.51322e-07,-6.35752e-08,1.0796,0.000418861,-3.42048e-07,1.43684e-07,1.08002,0.000418608,8.90034e-08,-1.53532e-07,1.08043,0.000418326,-3.71593e-07,1.12817e-07,1.08085,0.000417921,-3.31414e-08,-5.93184e-08,1.08127,0.000417677,-2.11097e-07,5.24697e-09,1.08169,0.00041727,-1.95356e-07,3.83305e-08,1.0821,0.000416995,-8.03642e-08,-3.93597e-08,1.08252,0.000416716,-1.98443e-07,-1.0094e-10,1.08294,0.000416319,-1.98746e-07,3.97635e-08,1.08335,0.00041604,-7.94557e-08,-3.97437e-08,1.08377,0.000415762,-1.98687e-07,1.94215e-12,1.08419,0.000415365,-1.98681e-07,3.97359e-08,1.0846,0.000415087,-7.94732e-08,-3.97362e-08,1.08502,0.000414809,-1.98682e-07,-4.31063e-13,1.08543,0.000414411,-1.98683e-07,3.97379e-08,1.08584,0.000414133,-7.94694e-08,-3.97418e-08,1.08626,0.000413855,-1.98695e-07,2.00563e-11,1.08667,0.000413458,-1.98635e-07,3.96616e-08,1.08709,0.000413179,-7.965e-08,-3.9457e-08,1.0875,0.000412902,-1.98021e-07,-1.04281e-09,1.08791,0.000412502,-2.01149e-07,4.36282e-08,1.08832,0.000412231,-7.02648e-08,-5.42608e-08,1.08874,0.000411928,-2.33047e-07,5.42057e-08,1.08915,0.000411624,-7.04301e-08,-4.33527e-08,1.08956,0.000411353,-2.00488e-07,-4.07378e-12,1.08997,0.000410952,-2.005e-07,4.3369e-08,1.09038,0.000410681,-7.03934e-08,-5.42627e-08,1.09079,0.000410378,-2.33182e-07,5.44726e-08,1.0912,0.000410075,-6.97637e-08,-4.44186e-08,1.09161,0.000409802,-2.03019e-07,3.99235e-09,1.09202,0.000409408,-1.91042e-07,2.84491e-08,1.09243,0.000409111,-1.05695e-07,1.42043e-09,1.09284,0.000408904,-1.01434e-07,-3.41308e-08,1.09325,0.000408599,-2.03826e-07,1.58937e-08,1.09366,0.000408239,-1.56145e-07,-2.94438e-08,1.09406,0.000407838,-2.44476e-07,1.01881e-07,1.09447,0.000407655,6.11676e-08,-1.39663e-07,1.09488,0.000407358,-3.57822e-07,9.91432e-08,1.09529,0.00040694,-6.03921e-08,-1.84912e-08,1.09569,0.000406764,-1.15866e-07,-2.51785e-08,1.0961,0.000406457,-1.91401e-07,-4.03115e-12,1.09651,0.000406074,-1.91413e-07,2.51947e-08,1.09691,0.000405767,-1.15829e-07,1.84346e-08,1.09732,0.00040559,-6.05254e-08,-9.89332e-08,1.09772,0.000405172,-3.57325e-07,1.3888e-07,1.09813,0.000404874,5.93136e-08,-9.8957e-08,1.09853,0.000404696,-2.37557e-07,1.853e-08,1.09894,0.000404277,-1.81968e-07,2.48372e-08,1.09934,0.000403987,-1.07456e-07,1.33047e-09,1.09975,0.000403776,-1.03465e-07,-3.01591e-08,1.10015,0.000403479,-1.93942e-07,9.66054e-11,1.10055,0.000403091,-1.93652e-07,2.97727e-08,1.10096,0.000402793,-1.04334e-07,2.19273e-11,1.10136,0.000402585,-1.04268e-07,-2.98604e-08,1.10176,0.000402287,-1.93849e-07,2.10325e-10,1.10216,0.0004019,-1.93218e-07,2.90191e-08,1.10256,0.0004016,-1.06161e-07,2.92264e-09,1.10297,0.000401397,-9.73931e-08,-4.07096e-08,1.10337,0.00040108,-2.19522e-07,4.07067e-08,1.10377,0.000400763,-9.7402e-08,-2.90783e-09,1.10417,0.000400559,-1.06126e-07,-2.90754e-08,1.10457,0.00040026,-1.93352e-07,9.00021e-14,1.10497,0.000399873,-1.93351e-07,2.9075e-08,1.10537,0.000399574,-1.06126e-07,2.90902e-09,1.10577,0.00039937,-9.73992e-08,-4.07111e-08,1.10617,0.000399053,-2.19533e-07,4.07262e-08,1.10657,0.000398736,-9.73541e-08,-2.98424e-09,1.10697,0.000398533,-1.06307e-07,-2.87892e-08,1.10736,0.000398234,-1.92674e-07,-1.06824e-09,1.10776,0.000397845,-1.95879e-07,3.30622e-08,1.10816,0.000397552,-9.66926e-08,-1.19712e-08,1.10856,0.000397323,-1.32606e-07,1.48225e-08,1.10895,0.000397102,-8.81387e-08,-4.73187e-08,1.10935,0.000396784,-2.30095e-07,5.52429e-08,1.10975,0.00039649,-6.4366e-08,-5.44437e-08,1.11014,0.000396198,-2.27697e-07,4.33226e-08,1.11054,0.000395872,-9.77293e-08,3.62656e-10,1.11094,0.000395678,-9.66414e-08,-4.47732e-08,1.11133,0.00039535,-2.30961e-07,5.95208e-08,1.11173,0.000395067,-5.23985e-08,-7.41008e-08,1.11212,0.00039474,-2.74701e-07,1.17673e-07,1.11252,0.000394543,7.83181e-08,-1.58172e-07,1.11291,0.000394225,-3.96199e-07,1.57389e-07,1.1133,0.000393905,7.59679e-08,-1.13756e-07,1.1137,0.000393716,-2.653e-07,5.92165e-08,1.11409,0.000393363,-8.76507e-08,-3.90074e-09,1.11449,0.000393176,-9.93529e-08,-4.36136e-08,1.11488,0.000392846,-2.30194e-07,5.91457e-08,1.11527,0.000392563,-5.27564e-08,-7.376e-08,1.11566,0.000392237,-2.74037e-07,1.16685e-07,1.11606,0.000392039,7.60189e-08,-1.54562e-07,1.11645,0.000391727,-3.87667e-07,1.43935e-07,1.11684,0.000391384,4.4137e-08,-6.35487e-08,1.11723,0.000391281,-1.46509e-07,-8.94896e-09,1.11762,0.000390961,-1.73356e-07,-1.98647e-08,1.11801,0.000390555,-2.3295e-07,8.8408e-08,1.1184,0.000390354,3.22736e-08,-9.53486e-08,1.11879,0.000390133,-2.53772e-07,5.45677e-08,1.11918,0.000389789,-9.0069e-08,-3.71296e-09,1.11957,0.000389598,-1.01208e-07,-3.97159e-08,1.11996,0.000389276,-2.20355e-07,4.33671e-08,1.12035,0.000388966,-9.02542e-08,-1.45431e-08,1.12074,0.000388741,-1.33883e-07,1.48052e-08,1.12113,0.000388518,-8.94678e-08,-4.46778e-08,1.12152,0.000388205,-2.23501e-07,4.46966e-08,1.12191,0.000387892,-8.94114e-08,-1.48992e-08,1.12229,0.000387669,-1.34109e-07,1.49003e-08,1.12268,0.000387445,-8.94082e-08,-4.47019e-08,1.12307,0.000387132,-2.23514e-07,4.4698e-08,1.12345,0.000386819,-8.942e-08,-1.48806e-08,1.12384,0.000386596,-1.34062e-07,1.48245e-08,1.12423,0.000386372,-8.95885e-08,-4.44172e-08,1.12461,0.00038606,-2.2284e-07,4.36351e-08,1.125,0.000385745,-9.19348e-08,-1.09139e-08,1.12539,0.000385528,-1.24677e-07,2.05584e-11,1.12577,0.000385279,-1.24615e-07,1.08317e-08,1.12616,0.000385062,-9.21198e-08,-4.33473e-08,1.12654,0.000384748,-2.22162e-07,4.33481e-08,1.12693,0.000384434,-9.21174e-08,-1.08356e-08,1.12731,0.000384217,-1.24624e-07,-5.50907e-12,1.12769,0.000383968,-1.24641e-07,1.08577e-08,1.12808,0.000383751,-9.20679e-08,-4.34252e-08,1.12846,0.000383437,-2.22343e-07,4.36337e-08,1.12884,0.000383123,-9.14422e-08,-1.19005e-08,1.12923,0.000382904,-1.27144e-07,3.96813e-09,1.12961,0.000382662,-1.15239e-07,-3.97207e-09,1.12999,0.000382419,-1.27155e-07,1.19201e-08,1.13038,0.000382201,-9.1395e-08,-4.37085e-08,1.13076,0.000381887,-2.2252e-07,4.37046e-08,1.13114,0.000381573,-9.14068e-08,-1.19005e-08,1.13152,0.000381355,-1.27108e-07,3.89734e-09,1.1319,0.000381112,-1.15416e-07,-3.68887e-09,1.13228,0.00038087,-1.26483e-07,1.08582e-08,1.13266,0.00038065,-9.39083e-08,-3.97438e-08,1.13304,0.000380343,-2.1314e-07,2.89076e-08,1.13342,0.000380003,-1.26417e-07,4.33225e-08,1.1338,0.00037988,3.55072e-09,-8.29883e-08,1.13418,0.000379638,-2.45414e-07,5.0212e-08,1.13456,0.000379298,-9.47781e-08,1.34964e-09,1.13494,0.000379113,-9.07292e-08,-5.56105e-08,1.13532,0.000378764,-2.57561e-07,1.01883e-07,1.1357,0.000378555,4.80889e-08,-1.13504e-07,1.13608,0.000378311,-2.92423e-07,1.13713e-07,1.13646,0.000378067,4.87176e-08,-1.02931e-07,1.13683,0.000377856,-2.60076e-07,5.95923e-08,1.13721,0.000377514,-8.12988e-08,-1.62288e-08,1.13759,0.000377303,-1.29985e-07,5.32278e-09,1.13797,0.000377059,-1.14017e-07,-5.06237e-09,1.13834,0.000376816,-1.29204e-07,1.49267e-08,1.13872,0.000376602,-8.44237e-08,-5.46444e-08,1.1391,0.000376269,-2.48357e-07,8.44417e-08,1.13947,0.000376026,4.96815e-09,-4.47039e-08,1.13985,0.000375902,-1.29143e-07,-2.48355e-08,1.14023,0.000375569,-2.0365e-07,2.48368e-08,1.1406,0.000375236,-1.2914e-07,4.46977e-08,1.14098,0.000375112,4.95341e-09,-8.44184e-08,1.14135,0.000374869,-2.48302e-07,5.45572e-08,1.14173,0.000374536,-8.463e-08,-1.46013e-08,1.1421,0.000374323,-1.28434e-07,3.8478e-09,1.14247,0.000374077,-1.1689e-07,-7.89941e-10,1.14285,0.000373841,-1.1926e-07,-6.88042e-10,1.14322,0.0003736,-1.21324e-07,3.54213e-09,1.1436,0.000373368,-1.10698e-07,-1.34805e-08,1.14397,0.000373107,-1.51139e-07,5.03798e-08,1.14434,0.000372767,0.,0.}; + + template + __device__ __forceinline__ void RGB2LuvConvert_f(const T& src, D& dst) + { + const float _d = 1.f / (0.950456f + 15 + 1.088754f * 3); + const float _un = 13 * (4 * 0.950456f * _d); + const float _vn = 13 * (9 * _d); + + float B = blueIdx == 0 ? src.x : src.z; + float G = src.y; + float R = blueIdx == 0 ? src.z : src.x; + + if (srgb) + { + B = splineInterpolate(B * GAMMA_TAB_SIZE, c_sRGBGammaTab, GAMMA_TAB_SIZE); + G = splineInterpolate(G * GAMMA_TAB_SIZE, c_sRGBGammaTab, GAMMA_TAB_SIZE); + R = splineInterpolate(R * GAMMA_TAB_SIZE, c_sRGBGammaTab, GAMMA_TAB_SIZE); + } + + float X = R * 0.412453f + G * 0.357580f + B * 0.180423f; + float Y = R * 0.212671f + G * 0.715160f + B * 0.072169f; + float Z = R * 0.019334f + G * 0.119193f + B * 0.950227f; + + float L = splineInterpolate(Y * (LAB_CBRT_TAB_SIZE / 1.5f), c_LabCbrtTab, LAB_CBRT_TAB_SIZE); + L = 116.f * L - 16.f; + + const float d = (4 * 13) / ::fmaxf(X + 15 * Y + 3 * Z, numeric_limits::epsilon()); + float u = L * (X * d - _un); + float v = L * ((9 * 0.25f) * Y * d - _vn); + + dst.x = L; + dst.y = u; + dst.z = v; + } + + template + __device__ __forceinline__ void RGB2LuvConvert_b(const T& src, D& dst) + { + float3 srcf, dstf; + + srcf.x = src.x * (1.f / 255.f); + srcf.y = src.y * (1.f / 255.f); + srcf.z = src.z * (1.f / 255.f); + + RGB2LuvConvert_f(srcf, dstf); + + dst.x = saturate_cast(dstf.x * 2.55f); + dst.y = saturate_cast(dstf.y * 0.72033898305084743f + 96.525423728813564f); + dst.z = saturate_cast(dstf.z * 0.9732824427480916f + 136.259541984732824f); + } + + template struct RGB2Luv; + template + struct RGB2Luv + : unary_function::vec_type, typename TypeVec::vec_type> + { + __device__ __forceinline__ typename TypeVec::vec_type operator ()(const typename TypeVec::vec_type& src) const + { + typename TypeVec::vec_type dst; + + RGB2LuvConvert_b(src, dst); + + return dst; + } + __host__ __device__ __forceinline__ RGB2Luv() {} + __host__ __device__ __forceinline__ RGB2Luv(const RGB2Luv&) {} + }; + template + struct RGB2Luv + : unary_function::vec_type, typename TypeVec::vec_type> + { + __device__ __forceinline__ typename TypeVec::vec_type operator ()(const typename TypeVec::vec_type& src) const + { + typename TypeVec::vec_type dst; + + RGB2LuvConvert_f(src, dst); + + return dst; + } + __host__ __device__ __forceinline__ RGB2Luv() {} + __host__ __device__ __forceinline__ RGB2Luv(const RGB2Luv&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_RGB2Luv_TRAITS(name, scn, dcn, srgb, blueIdx) \ + template struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::RGB2Luv functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + + namespace color_detail + { + template + __device__ __forceinline__ void Luv2RGBConvert_f(const T& src, D& dst) + { + const float _d = 1.f / (0.950456f + 15 + 1.088754f * 3); + const float _un = 4 * 0.950456f * _d; + const float _vn = 9 * _d; + + float L = src.x; + float u = src.y; + float v = src.z; + + float Y = (L + 16.f) * (1.f / 116.f); + Y = Y * Y * Y; + + float d = (1.f / 13.f) / L; + u = u * d + _un; + v = v * d + _vn; + + float iv = 1.f / v; + float X = 2.25f * u * Y * iv; + float Z = (12 - 3 * u - 20 * v) * Y * 0.25f * iv; + + float B = 0.055648f * X - 0.204043f * Y + 1.057311f * Z; + float G = -0.969256f * X + 1.875991f * Y + 0.041556f * Z; + float R = 3.240479f * X - 1.537150f * Y - 0.498535f * Z; + + if (srgb) + { + B = splineInterpolate(B * GAMMA_TAB_SIZE, c_sRGBInvGammaTab, GAMMA_TAB_SIZE); + G = splineInterpolate(G * GAMMA_TAB_SIZE, c_sRGBInvGammaTab, GAMMA_TAB_SIZE); + R = splineInterpolate(R * GAMMA_TAB_SIZE, c_sRGBInvGammaTab, GAMMA_TAB_SIZE); + } + + dst.x = blueIdx == 0 ? B : R; + dst.y = G; + dst.z = blueIdx == 0 ? R : B; + setAlpha(dst, ColorChannel::max()); + } + + template + __device__ __forceinline__ void Luv2RGBConvert_b(const T& src, D& dst) + { + float3 srcf, dstf; + + srcf.x = src.x * (100.f / 255.f); + srcf.y = src.y * 1.388235294117647f - 134.f; + srcf.z = src.z * 1.027450980392157f - 140.f; + + Luv2RGBConvert_f(srcf, dstf); + + dst.x = saturate_cast(dstf.x * 255.f); + dst.y = saturate_cast(dstf.y * 255.f); + dst.z = saturate_cast(dstf.z * 255.f); + setAlpha(dst, ColorChannel::max()); + } + + template struct Luv2RGB; + template + struct Luv2RGB + : unary_function::vec_type, typename TypeVec::vec_type> + { + __device__ __forceinline__ typename TypeVec::vec_type operator ()(const typename TypeVec::vec_type& src) const + { + typename TypeVec::vec_type dst; + + Luv2RGBConvert_b(src, dst); + + return dst; + } + __host__ __device__ __forceinline__ Luv2RGB() {} + __host__ __device__ __forceinline__ Luv2RGB(const Luv2RGB&) {} + }; + template + struct Luv2RGB + : unary_function::vec_type, typename TypeVec::vec_type> + { + __device__ __forceinline__ typename TypeVec::vec_type operator ()(const typename TypeVec::vec_type& src) const + { + typename TypeVec::vec_type dst; + + Luv2RGBConvert_f(src, dst); + + return dst; + } + __host__ __device__ __forceinline__ Luv2RGB() {} + __host__ __device__ __forceinline__ Luv2RGB(const Luv2RGB&) {} + }; + } + +#define OPENCV_CUDA_IMPLEMENT_Luv2RGB_TRAITS(name, scn, dcn, srgb, blueIdx) \ + template struct name ## _traits \ + { \ + typedef ::cv::cuda::device::color_detail::Luv2RGB functor_type; \ + static __host__ __device__ __forceinline__ functor_type create_functor() \ + { \ + return functor_type(); \ + } \ + }; + + #undef CV_DESCALE + +}}} // namespace cv { namespace cuda { namespace cudev + +//! @endcond + +#endif // OPENCV_CUDA_COLOR_DETAIL_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/reduce.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/reduce.hpp new file mode 100644 index 0000000..8af20b0 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/reduce.hpp @@ -0,0 +1,365 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_REDUCE_DETAIL_HPP +#define OPENCV_CUDA_REDUCE_DETAIL_HPP + +#include +#include "../warp.hpp" +#include "../warp_shuffle.hpp" + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + namespace reduce_detail + { + template struct GetType; + template struct GetType + { + typedef T type; + }; + template struct GetType + { + typedef T type; + }; + template struct GetType + { + typedef T type; + }; + + template + struct For + { + template + static __device__ void loadToSmem(const PointerTuple& smem, const ValTuple& val, unsigned int tid) + { + thrust::get(smem)[tid] = thrust::get(val); + + For::loadToSmem(smem, val, tid); + } + template + static __device__ void loadFromSmem(const PointerTuple& smem, const ValTuple& val, unsigned int tid) + { + thrust::get(val) = thrust::get(smem)[tid]; + + For::loadFromSmem(smem, val, tid); + } + + template + static __device__ void merge(const PointerTuple& smem, const ValTuple& val, unsigned int tid, unsigned int delta, const OpTuple& op) + { + typename GetType::type>::type reg = thrust::get(smem)[tid + delta]; + thrust::get(smem)[tid] = thrust::get(val) = thrust::get(op)(thrust::get(val), reg); + + For::merge(smem, val, tid, delta, op); + } + template + static __device__ void mergeShfl(const ValTuple& val, unsigned int delta, unsigned int width, const OpTuple& op) + { + typename GetType::type>::type reg = shfl_down(thrust::get(val), delta, width); + thrust::get(val) = thrust::get(op)(thrust::get(val), reg); + + For::mergeShfl(val, delta, width, op); + } + }; + template + struct For + { + template + static __device__ void loadToSmem(const PointerTuple&, const ValTuple&, unsigned int) + { + } + template + static __device__ void loadFromSmem(const PointerTuple&, const ValTuple&, unsigned int) + { + } + + template + static __device__ void merge(const PointerTuple&, const ValTuple&, unsigned int, unsigned int, const OpTuple&) + { + } + template + static __device__ void mergeShfl(const ValTuple&, unsigned int, unsigned int, const OpTuple&) + { + } + }; + + template + __device__ __forceinline__ void loadToSmem(volatile T* smem, T& val, unsigned int tid) + { + smem[tid] = val; + } + template + __device__ __forceinline__ void loadFromSmem(volatile T* smem, T& val, unsigned int tid) + { + val = smem[tid]; + } + template + __device__ __forceinline__ void loadToSmem(const thrust::tuple& smem, + const thrust::tuple& val, + unsigned int tid) + { + For<0, thrust::tuple_size >::value>::loadToSmem(smem, val, tid); + } + template + __device__ __forceinline__ void loadFromSmem(const thrust::tuple& smem, + const thrust::tuple& val, + unsigned int tid) + { + For<0, thrust::tuple_size >::value>::loadFromSmem(smem, val, tid); + } + + template + __device__ __forceinline__ void merge(volatile T* smem, T& val, unsigned int tid, unsigned int delta, const Op& op) + { + T reg = smem[tid + delta]; + smem[tid] = val = op(val, reg); + } + template + __device__ __forceinline__ void mergeShfl(T& val, unsigned int delta, unsigned int width, const Op& op) + { + T reg = shfl_down(val, delta, width); + val = op(val, reg); + } + template + __device__ __forceinline__ void merge(const thrust::tuple& smem, + const thrust::tuple& val, + unsigned int tid, + unsigned int delta, + const thrust::tuple& op) + { + For<0, thrust::tuple_size >::value>::merge(smem, val, tid, delta, op); + } + template + __device__ __forceinline__ void mergeShfl(const thrust::tuple& val, + unsigned int delta, + unsigned int width, + const thrust::tuple& op) + { + For<0, thrust::tuple_size >::value>::mergeShfl(val, delta, width, op); + } + + template struct Generic + { + template + static __device__ void reduce(Pointer smem, Reference val, unsigned int tid, Op op) + { + loadToSmem(smem, val, tid); + if (N >= 32) + __syncthreads(); + + if (N >= 2048) + { + if (tid < 1024) + merge(smem, val, tid, 1024, op); + + __syncthreads(); + } + if (N >= 1024) + { + if (tid < 512) + merge(smem, val, tid, 512, op); + + __syncthreads(); + } + if (N >= 512) + { + if (tid < 256) + merge(smem, val, tid, 256, op); + + __syncthreads(); + } + if (N >= 256) + { + if (tid < 128) + merge(smem, val, tid, 128, op); + + __syncthreads(); + } + if (N >= 128) + { + if (tid < 64) + merge(smem, val, tid, 64, op); + + __syncthreads(); + } + if (N >= 64) + { + if (tid < 32) + merge(smem, val, tid, 32, op); + } + + if (tid < 16) + { + merge(smem, val, tid, 16, op); + merge(smem, val, tid, 8, op); + merge(smem, val, tid, 4, op); + merge(smem, val, tid, 2, op); + merge(smem, val, tid, 1, op); + } + } + }; + + template + struct Unroll + { + static __device__ void loopShfl(Reference val, Op op, unsigned int N) + { + mergeShfl(val, I, N, op); + Unroll::loopShfl(val, op, N); + } + static __device__ void loop(Pointer smem, Reference val, unsigned int tid, Op op) + { + merge(smem, val, tid, I, op); + Unroll::loop(smem, val, tid, op); + } + }; + template + struct Unroll<0, Pointer, Reference, Op> + { + static __device__ void loopShfl(Reference, Op, unsigned int) + { + } + static __device__ void loop(Pointer, Reference, unsigned int, Op) + { + } + }; + + template struct WarpOptimized + { + template + static __device__ void reduce(Pointer smem, Reference val, unsigned int tid, Op op) + { + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 + CV_UNUSED(smem); + CV_UNUSED(tid); + + Unroll::loopShfl(val, op, N); + #else + loadToSmem(smem, val, tid); + + if (tid < N / 2) + Unroll::loop(smem, val, tid, op); + #endif + } + }; + + template struct GenericOptimized32 + { + enum { M = N / 32 }; + + template + static __device__ void reduce(Pointer smem, Reference val, unsigned int tid, Op op) + { + const unsigned int laneId = Warp::laneId(); + + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 + Unroll<16, Pointer, Reference, Op>::loopShfl(val, op, warpSize); + + if (laneId == 0) + loadToSmem(smem, val, tid / 32); + #else + loadToSmem(smem, val, tid); + + if (laneId < 16) + Unroll<16, Pointer, Reference, Op>::loop(smem, val, tid, op); + + __syncthreads(); + + if (laneId == 0) + loadToSmem(smem, val, tid / 32); + #endif + + __syncthreads(); + + loadFromSmem(smem, val, tid); + + if (tid < 32) + { + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 + Unroll::loopShfl(val, op, M); + #else + Unroll::loop(smem, val, tid, op); + #endif + } + } + }; + + template struct StaticIf; + template struct StaticIf + { + typedef T1 type; + }; + template struct StaticIf + { + typedef T2 type; + }; + + template struct IsPowerOf2 + { + enum { value = ((N != 0) && !(N & (N - 1))) }; + }; + + template struct Dispatcher + { + typedef typename StaticIf< + (N <= 32) && IsPowerOf2::value, + WarpOptimized, + typename StaticIf< + (N <= 1024) && IsPowerOf2::value, + GenericOptimized32, + Generic + >::type + >::type reductor; + }; + } +}}} + +//! @endcond + +#endif // OPENCV_CUDA_REDUCE_DETAIL_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/reduce_key_val.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/reduce_key_val.hpp new file mode 100644 index 0000000..df37c17 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/reduce_key_val.hpp @@ -0,0 +1,502 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_PRED_VAL_REDUCE_DETAIL_HPP +#define OPENCV_CUDA_PRED_VAL_REDUCE_DETAIL_HPP + +#include +#include "../warp.hpp" +#include "../warp_shuffle.hpp" + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + namespace reduce_key_val_detail + { + template struct GetType; + template struct GetType + { + typedef T type; + }; + template struct GetType + { + typedef T type; + }; + template struct GetType + { + typedef T type; + }; + + template + struct For + { + template + static __device__ void loadToSmem(const PointerTuple& smem, const ReferenceTuple& data, unsigned int tid) + { + thrust::get(smem)[tid] = thrust::get(data); + + For::loadToSmem(smem, data, tid); + } + template + static __device__ void loadFromSmem(const PointerTuple& smem, const ReferenceTuple& data, unsigned int tid) + { + thrust::get(data) = thrust::get(smem)[tid]; + + For::loadFromSmem(smem, data, tid); + } + + template + static __device__ void copyShfl(const ReferenceTuple& val, unsigned int delta, int width) + { + thrust::get(val) = shfl_down(thrust::get(val), delta, width); + + For::copyShfl(val, delta, width); + } + template + static __device__ void copy(const PointerTuple& svals, const ReferenceTuple& val, unsigned int tid, unsigned int delta) + { + thrust::get(svals)[tid] = thrust::get(val) = thrust::get(svals)[tid + delta]; + + For::copy(svals, val, tid, delta); + } + + template + static __device__ void mergeShfl(const KeyReferenceTuple& key, const ValReferenceTuple& val, const CmpTuple& cmp, unsigned int delta, int width) + { + typename GetType::type>::type reg = shfl_down(thrust::get(key), delta, width); + + if (thrust::get(cmp)(reg, thrust::get(key))) + { + thrust::get(key) = reg; + thrust::get(val) = shfl_down(thrust::get(val), delta, width); + } + + For::mergeShfl(key, val, cmp, delta, width); + } + template + static __device__ void merge(const KeyPointerTuple& skeys, const KeyReferenceTuple& key, + const ValPointerTuple& svals, const ValReferenceTuple& val, + const CmpTuple& cmp, + unsigned int tid, unsigned int delta) + { + typename GetType::type>::type reg = thrust::get(skeys)[tid + delta]; + + if (thrust::get(cmp)(reg, thrust::get(key))) + { + thrust::get(skeys)[tid] = thrust::get(key) = reg; + thrust::get(svals)[tid] = thrust::get(val) = thrust::get(svals)[tid + delta]; + } + + For::merge(skeys, key, svals, val, cmp, tid, delta); + } + }; + template + struct For + { + template + static __device__ void loadToSmem(const PointerTuple&, const ReferenceTuple&, unsigned int) + { + } + template + static __device__ void loadFromSmem(const PointerTuple&, const ReferenceTuple&, unsigned int) + { + } + + template + static __device__ void copyShfl(const ReferenceTuple&, unsigned int, int) + { + } + template + static __device__ void copy(const PointerTuple&, const ReferenceTuple&, unsigned int, unsigned int) + { + } + + template + static __device__ void mergeShfl(const KeyReferenceTuple&, const ValReferenceTuple&, const CmpTuple&, unsigned int, int) + { + } + template + static __device__ void merge(const KeyPointerTuple&, const KeyReferenceTuple&, + const ValPointerTuple&, const ValReferenceTuple&, + const CmpTuple&, + unsigned int, unsigned int) + { + } + }; + + ////////////////////////////////////////////////////// + // loadToSmem + + template + __device__ __forceinline__ void loadToSmem(volatile T* smem, T& data, unsigned int tid) + { + smem[tid] = data; + } + template + __device__ __forceinline__ void loadFromSmem(volatile T* smem, T& data, unsigned int tid) + { + data = smem[tid]; + } + template + __device__ __forceinline__ void loadToSmem(const thrust::tuple& smem, + const thrust::tuple& data, + unsigned int tid) + { + For<0, thrust::tuple_size >::value>::loadToSmem(smem, data, tid); + } + template + __device__ __forceinline__ void loadFromSmem(const thrust::tuple& smem, + const thrust::tuple& data, + unsigned int tid) + { + For<0, thrust::tuple_size >::value>::loadFromSmem(smem, data, tid); + } + + ////////////////////////////////////////////////////// + // copyVals + + template + __device__ __forceinline__ void copyValsShfl(V& val, unsigned int delta, int width) + { + val = shfl_down(val, delta, width); + } + template + __device__ __forceinline__ void copyVals(volatile V* svals, V& val, unsigned int tid, unsigned int delta) + { + svals[tid] = val = svals[tid + delta]; + } + template + __device__ __forceinline__ void copyValsShfl(const thrust::tuple& val, + unsigned int delta, + int width) + { + For<0, thrust::tuple_size >::value>::copyShfl(val, delta, width); + } + template + __device__ __forceinline__ void copyVals(const thrust::tuple& svals, + const thrust::tuple& val, + unsigned int tid, unsigned int delta) + { + For<0, thrust::tuple_size >::value>::copy(svals, val, tid, delta); + } + + ////////////////////////////////////////////////////// + // merge + + template + __device__ __forceinline__ void mergeShfl(K& key, V& val, const Cmp& cmp, unsigned int delta, int width) + { + K reg = shfl_down(key, delta, width); + + if (cmp(reg, key)) + { + key = reg; + copyValsShfl(val, delta, width); + } + } + template + __device__ __forceinline__ void merge(volatile K* skeys, K& key, volatile V* svals, V& val, const Cmp& cmp, unsigned int tid, unsigned int delta) + { + K reg = skeys[tid + delta]; + + if (cmp(reg, key)) + { + skeys[tid] = key = reg; + copyVals(svals, val, tid, delta); + } + } + template + __device__ __forceinline__ void mergeShfl(K& key, + const thrust::tuple& val, + const Cmp& cmp, + unsigned int delta, int width) + { + K reg = shfl_down(key, delta, width); + + if (cmp(reg, key)) + { + key = reg; + copyValsShfl(val, delta, width); + } + } + template + __device__ __forceinline__ void merge(volatile K* skeys, K& key, + const thrust::tuple& svals, + const thrust::tuple& val, + const Cmp& cmp, unsigned int tid, unsigned int delta) + { + K reg = skeys[tid + delta]; + + if (cmp(reg, key)) + { + skeys[tid] = key = reg; + copyVals(svals, val, tid, delta); + } + } + template + __device__ __forceinline__ void mergeShfl(const thrust::tuple& key, + const thrust::tuple& val, + const thrust::tuple& cmp, + unsigned int delta, int width) + { + For<0, thrust::tuple_size >::value>::mergeShfl(key, val, cmp, delta, width); + } + template + __device__ __forceinline__ void merge(const thrust::tuple& skeys, + const thrust::tuple& key, + const thrust::tuple& svals, + const thrust::tuple& val, + const thrust::tuple& cmp, + unsigned int tid, unsigned int delta) + { + For<0, thrust::tuple_size >::value>::merge(skeys, key, svals, val, cmp, tid, delta); + } + + ////////////////////////////////////////////////////// + // Generic + + template struct Generic + { + template + static __device__ void reduce(KP skeys, KR key, VP svals, VR val, unsigned int tid, Cmp cmp) + { + loadToSmem(skeys, key, tid); + loadValsToSmem(svals, val, tid); + if (N >= 32) + __syncthreads(); + + if (N >= 2048) + { + if (tid < 1024) + merge(skeys, key, svals, val, cmp, tid, 1024); + + __syncthreads(); + } + if (N >= 1024) + { + if (tid < 512) + merge(skeys, key, svals, val, cmp, tid, 512); + + __syncthreads(); + } + if (N >= 512) + { + if (tid < 256) + merge(skeys, key, svals, val, cmp, tid, 256); + + __syncthreads(); + } + if (N >= 256) + { + if (tid < 128) + merge(skeys, key, svals, val, cmp, tid, 128); + + __syncthreads(); + } + if (N >= 128) + { + if (tid < 64) + merge(skeys, key, svals, val, cmp, tid, 64); + + __syncthreads(); + } + if (N >= 64) + { + if (tid < 32) + merge(skeys, key, svals, val, cmp, tid, 32); + } + + if (tid < 16) + { + merge(skeys, key, svals, val, cmp, tid, 16); + merge(skeys, key, svals, val, cmp, tid, 8); + merge(skeys, key, svals, val, cmp, tid, 4); + merge(skeys, key, svals, val, cmp, tid, 2); + merge(skeys, key, svals, val, cmp, tid, 1); + } + } + }; + + template + struct Unroll + { + static __device__ void loopShfl(KR key, VR val, Cmp cmp, unsigned int N) + { + mergeShfl(key, val, cmp, I, N); + Unroll::loopShfl(key, val, cmp, N); + } + static __device__ void loop(KP skeys, KR key, VP svals, VR val, unsigned int tid, Cmp cmp) + { + merge(skeys, key, svals, val, cmp, tid, I); + Unroll::loop(skeys, key, svals, val, tid, cmp); + } + }; + template + struct Unroll<0, KP, KR, VP, VR, Cmp> + { + static __device__ void loopShfl(KR, VR, Cmp, unsigned int) + { + } + static __device__ void loop(KP, KR, VP, VR, unsigned int, Cmp) + { + } + }; + + template struct WarpOptimized + { + template + static __device__ void reduce(KP skeys, KR key, VP svals, VR val, unsigned int tid, Cmp cmp) + { + #if 0 // __CUDA_ARCH__ >= 300 + CV_UNUSED(skeys); + CV_UNUSED(svals); + CV_UNUSED(tid); + + Unroll::loopShfl(key, val, cmp, N); + #else + loadToSmem(skeys, key, tid); + loadToSmem(svals, val, tid); + + if (tid < N / 2) + Unroll::loop(skeys, key, svals, val, tid, cmp); + #endif + } + }; + + template struct GenericOptimized32 + { + enum { M = N / 32 }; + + template + static __device__ void reduce(KP skeys, KR key, VP svals, VR val, unsigned int tid, Cmp cmp) + { + const unsigned int laneId = Warp::laneId(); + + #if 0 // __CUDA_ARCH__ >= 300 + Unroll<16, KP, KR, VP, VR, Cmp>::loopShfl(key, val, cmp, warpSize); + + if (laneId == 0) + { + loadToSmem(skeys, key, tid / 32); + loadToSmem(svals, val, tid / 32); + } + #else + loadToSmem(skeys, key, tid); + loadToSmem(svals, val, tid); + + if (laneId < 16) + Unroll<16, KP, KR, VP, VR, Cmp>::loop(skeys, key, svals, val, tid, cmp); + + __syncthreads(); + + if (laneId == 0) + { + loadToSmem(skeys, key, tid / 32); + loadToSmem(svals, val, tid / 32); + } + #endif + + __syncthreads(); + + loadFromSmem(skeys, key, tid); + + if (tid < 32) + { + #if 0 // __CUDA_ARCH__ >= 300 + loadFromSmem(svals, val, tid); + + Unroll::loopShfl(key, val, cmp, M); + #else + Unroll::loop(skeys, key, svals, val, tid, cmp); + #endif + } + } + }; + + template struct StaticIf; + template struct StaticIf + { + typedef T1 type; + }; + template struct StaticIf + { + typedef T2 type; + }; + + template struct IsPowerOf2 + { + enum { value = ((N != 0) && !(N & (N - 1))) }; + }; + + template struct Dispatcher + { + typedef typename StaticIf< + (N <= 32) && IsPowerOf2::value, + WarpOptimized, + typename StaticIf< + (N <= 1024) && IsPowerOf2::value, + GenericOptimized32, + Generic + >::type + >::type reductor; + }; + } +}}} + +//! @endcond + +#endif // OPENCV_CUDA_PRED_VAL_REDUCE_DETAIL_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/transform_detail.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/transform_detail.hpp new file mode 100644 index 0000000..1919848 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/transform_detail.hpp @@ -0,0 +1,392 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_TRANSFORM_DETAIL_HPP +#define OPENCV_CUDA_TRANSFORM_DETAIL_HPP + +#include "../common.hpp" +#include "../vec_traits.hpp" +#include "../functional.hpp" + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + namespace transform_detail + { + //! Read Write Traits + + template struct UnaryReadWriteTraits + { + typedef typename TypeVec::vec_type read_type; + typedef typename TypeVec::vec_type write_type; + }; + + template struct BinaryReadWriteTraits + { + typedef typename TypeVec::vec_type read_type1; + typedef typename TypeVec::vec_type read_type2; + typedef typename TypeVec::vec_type write_type; + }; + + //! Transform kernels + + template struct OpUnroller; + template <> struct OpUnroller<1> + { + template + static __device__ __forceinline__ void unroll(const T& src, D& dst, const Mask& mask, UnOp& op, int x_shifted, int y) + { + if (mask(y, x_shifted)) + dst.x = op(src.x); + } + + template + static __device__ __forceinline__ void unroll(const T1& src1, const T2& src2, D& dst, const Mask& mask, BinOp& op, int x_shifted, int y) + { + if (mask(y, x_shifted)) + dst.x = op(src1.x, src2.x); + } + }; + template <> struct OpUnroller<2> + { + template + static __device__ __forceinline__ void unroll(const T& src, D& dst, const Mask& mask, UnOp& op, int x_shifted, int y) + { + if (mask(y, x_shifted)) + dst.x = op(src.x); + if (mask(y, x_shifted + 1)) + dst.y = op(src.y); + } + + template + static __device__ __forceinline__ void unroll(const T1& src1, const T2& src2, D& dst, const Mask& mask, BinOp& op, int x_shifted, int y) + { + if (mask(y, x_shifted)) + dst.x = op(src1.x, src2.x); + if (mask(y, x_shifted + 1)) + dst.y = op(src1.y, src2.y); + } + }; + template <> struct OpUnroller<3> + { + template + static __device__ __forceinline__ void unroll(const T& src, D& dst, const Mask& mask, const UnOp& op, int x_shifted, int y) + { + if (mask(y, x_shifted)) + dst.x = op(src.x); + if (mask(y, x_shifted + 1)) + dst.y = op(src.y); + if (mask(y, x_shifted + 2)) + dst.z = op(src.z); + } + + template + static __device__ __forceinline__ void unroll(const T1& src1, const T2& src2, D& dst, const Mask& mask, const BinOp& op, int x_shifted, int y) + { + if (mask(y, x_shifted)) + dst.x = op(src1.x, src2.x); + if (mask(y, x_shifted + 1)) + dst.y = op(src1.y, src2.y); + if (mask(y, x_shifted + 2)) + dst.z = op(src1.z, src2.z); + } + }; + template <> struct OpUnroller<4> + { + template + static __device__ __forceinline__ void unroll(const T& src, D& dst, const Mask& mask, const UnOp& op, int x_shifted, int y) + { + if (mask(y, x_shifted)) + dst.x = op(src.x); + if (mask(y, x_shifted + 1)) + dst.y = op(src.y); + if (mask(y, x_shifted + 2)) + dst.z = op(src.z); + if (mask(y, x_shifted + 3)) + dst.w = op(src.w); + } + + template + static __device__ __forceinline__ void unroll(const T1& src1, const T2& src2, D& dst, const Mask& mask, const BinOp& op, int x_shifted, int y) + { + if (mask(y, x_shifted)) + dst.x = op(src1.x, src2.x); + if (mask(y, x_shifted + 1)) + dst.y = op(src1.y, src2.y); + if (mask(y, x_shifted + 2)) + dst.z = op(src1.z, src2.z); + if (mask(y, x_shifted + 3)) + dst.w = op(src1.w, src2.w); + } + }; + template <> struct OpUnroller<8> + { + template + static __device__ __forceinline__ void unroll(const T& src, D& dst, const Mask& mask, const UnOp& op, int x_shifted, int y) + { + if (mask(y, x_shifted)) + dst.a0 = op(src.a0); + if (mask(y, x_shifted + 1)) + dst.a1 = op(src.a1); + if (mask(y, x_shifted + 2)) + dst.a2 = op(src.a2); + if (mask(y, x_shifted + 3)) + dst.a3 = op(src.a3); + if (mask(y, x_shifted + 4)) + dst.a4 = op(src.a4); + if (mask(y, x_shifted + 5)) + dst.a5 = op(src.a5); + if (mask(y, x_shifted + 6)) + dst.a6 = op(src.a6); + if (mask(y, x_shifted + 7)) + dst.a7 = op(src.a7); + } + + template + static __device__ __forceinline__ void unroll(const T1& src1, const T2& src2, D& dst, const Mask& mask, const BinOp& op, int x_shifted, int y) + { + if (mask(y, x_shifted)) + dst.a0 = op(src1.a0, src2.a0); + if (mask(y, x_shifted + 1)) + dst.a1 = op(src1.a1, src2.a1); + if (mask(y, x_shifted + 2)) + dst.a2 = op(src1.a2, src2.a2); + if (mask(y, x_shifted + 3)) + dst.a3 = op(src1.a3, src2.a3); + if (mask(y, x_shifted + 4)) + dst.a4 = op(src1.a4, src2.a4); + if (mask(y, x_shifted + 5)) + dst.a5 = op(src1.a5, src2.a5); + if (mask(y, x_shifted + 6)) + dst.a6 = op(src1.a6, src2.a6); + if (mask(y, x_shifted + 7)) + dst.a7 = op(src1.a7, src2.a7); + } + }; + + template + static __global__ void transformSmart(const PtrStepSz src_, PtrStep dst_, const Mask mask, const UnOp op) + { + typedef TransformFunctorTraits ft; + typedef typename UnaryReadWriteTraits::read_type read_type; + typedef typename UnaryReadWriteTraits::write_type write_type; + + const int x = threadIdx.x + blockIdx.x * blockDim.x; + const int y = threadIdx.y + blockIdx.y * blockDim.y; + const int x_shifted = x * ft::smart_shift; + + if (y < src_.rows) + { + const T* src = src_.ptr(y); + D* dst = dst_.ptr(y); + + if (x_shifted + ft::smart_shift - 1 < src_.cols) + { + const read_type src_n_el = ((const read_type*)src)[x]; + OpUnroller::unroll(src_n_el, ((write_type*)dst)[x], mask, op, x_shifted, y); + } + else + { + for (int real_x = x_shifted; real_x < src_.cols; ++real_x) + { + if (mask(y, real_x)) + dst[real_x] = op(src[real_x]); + } + } + } + } + + template + __global__ static void transformSimple(const PtrStepSz src, PtrStep dst, const Mask mask, const UnOp op) + { + const int x = blockDim.x * blockIdx.x + threadIdx.x; + const int y = blockDim.y * blockIdx.y + threadIdx.y; + + if (x < src.cols && y < src.rows && mask(y, x)) + { + dst.ptr(y)[x] = op(src.ptr(y)[x]); + } + } + + template + static __global__ void transformSmart(const PtrStepSz src1_, const PtrStep src2_, PtrStep dst_, + const Mask mask, const BinOp op) + { + typedef TransformFunctorTraits ft; + typedef typename BinaryReadWriteTraits::read_type1 read_type1; + typedef typename BinaryReadWriteTraits::read_type2 read_type2; + typedef typename BinaryReadWriteTraits::write_type write_type; + + const int x = threadIdx.x + blockIdx.x * blockDim.x; + const int y = threadIdx.y + blockIdx.y * blockDim.y; + const int x_shifted = x * ft::smart_shift; + + if (y < src1_.rows) + { + const T1* src1 = src1_.ptr(y); + const T2* src2 = src2_.ptr(y); + D* dst = dst_.ptr(y); + + if (x_shifted + ft::smart_shift - 1 < src1_.cols) + { + const read_type1 src1_n_el = ((const read_type1*)src1)[x]; + const read_type2 src2_n_el = ((const read_type2*)src2)[x]; + + OpUnroller::unroll(src1_n_el, src2_n_el, ((write_type*)dst)[x], mask, op, x_shifted, y); + } + else + { + for (int real_x = x_shifted; real_x < src1_.cols; ++real_x) + { + if (mask(y, real_x)) + dst[real_x] = op(src1[real_x], src2[real_x]); + } + } + } + } + + template + static __global__ void transformSimple(const PtrStepSz src1, const PtrStep src2, PtrStep dst, + const Mask mask, const BinOp op) + { + const int x = blockDim.x * blockIdx.x + threadIdx.x; + const int y = blockDim.y * blockIdx.y + threadIdx.y; + + if (x < src1.cols && y < src1.rows && mask(y, x)) + { + const T1 src1_data = src1.ptr(y)[x]; + const T2 src2_data = src2.ptr(y)[x]; + dst.ptr(y)[x] = op(src1_data, src2_data); + } + } + + template struct TransformDispatcher; + template<> struct TransformDispatcher + { + template + static void call(PtrStepSz src, PtrStepSz dst, UnOp op, Mask mask, cudaStream_t stream) + { + typedef TransformFunctorTraits ft; + + const dim3 threads(ft::simple_block_dim_x, ft::simple_block_dim_y, 1); + const dim3 grid(divUp(src.cols, threads.x), divUp(src.rows, threads.y), 1); + + transformSimple<<>>(src, dst, mask, op); + cudaSafeCall( cudaGetLastError() ); + + if (stream == 0) + cudaSafeCall( cudaDeviceSynchronize() ); + } + + template + static void call(PtrStepSz src1, PtrStepSz src2, PtrStepSz dst, BinOp op, Mask mask, cudaStream_t stream) + { + typedef TransformFunctorTraits ft; + + const dim3 threads(ft::simple_block_dim_x, ft::simple_block_dim_y, 1); + const dim3 grid(divUp(src1.cols, threads.x), divUp(src1.rows, threads.y), 1); + + transformSimple<<>>(src1, src2, dst, mask, op); + cudaSafeCall( cudaGetLastError() ); + + if (stream == 0) + cudaSafeCall( cudaDeviceSynchronize() ); + } + }; + template<> struct TransformDispatcher + { + template + static void call(PtrStepSz src, PtrStepSz dst, UnOp op, Mask mask, cudaStream_t stream) + { + typedef TransformFunctorTraits ft; + + CV_StaticAssert(ft::smart_shift != 1, ""); + + if (!isAligned(src.data, ft::smart_shift * sizeof(T)) || !isAligned(src.step, ft::smart_shift * sizeof(T)) || + !isAligned(dst.data, ft::smart_shift * sizeof(D)) || !isAligned(dst.step, ft::smart_shift * sizeof(D))) + { + TransformDispatcher::call(src, dst, op, mask, stream); + return; + } + + const dim3 threads(ft::smart_block_dim_x, ft::smart_block_dim_y, 1); + const dim3 grid(divUp(src.cols, threads.x * ft::smart_shift), divUp(src.rows, threads.y), 1); + + transformSmart<<>>(src, dst, mask, op); + cudaSafeCall( cudaGetLastError() ); + + if (stream == 0) + cudaSafeCall( cudaDeviceSynchronize() ); + } + + template + static void call(PtrStepSz src1, PtrStepSz src2, PtrStepSz dst, BinOp op, Mask mask, cudaStream_t stream) + { + typedef TransformFunctorTraits ft; + + CV_StaticAssert(ft::smart_shift != 1, ""); + + if (!isAligned(src1.data, ft::smart_shift * sizeof(T1)) || !isAligned(src1.step, ft::smart_shift * sizeof(T1)) || + !isAligned(src2.data, ft::smart_shift * sizeof(T2)) || !isAligned(src2.step, ft::smart_shift * sizeof(T2)) || + !isAligned(dst.data, ft::smart_shift * sizeof(D)) || !isAligned(dst.step, ft::smart_shift * sizeof(D))) + { + TransformDispatcher::call(src1, src2, dst, op, mask, stream); + return; + } + + const dim3 threads(ft::smart_block_dim_x, ft::smart_block_dim_y, 1); + const dim3 grid(divUp(src1.cols, threads.x * ft::smart_shift), divUp(src1.rows, threads.y), 1); + + transformSmart<<>>(src1, src2, dst, mask, op); + cudaSafeCall( cudaGetLastError() ); + + if (stream == 0) + cudaSafeCall( cudaDeviceSynchronize() ); + } + }; + } // namespace transform_detail +}}} // namespace cv { namespace cuda { namespace cudev + +//! @endcond + +#endif // OPENCV_CUDA_TRANSFORM_DETAIL_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/type_traits_detail.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/type_traits_detail.hpp new file mode 100644 index 0000000..a78bd2c --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/type_traits_detail.hpp @@ -0,0 +1,191 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_TYPE_TRAITS_DETAIL_HPP +#define OPENCV_CUDA_TYPE_TRAITS_DETAIL_HPP + +#include "../common.hpp" +#include "../vec_traits.hpp" + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + namespace type_traits_detail + { + template struct Select { typedef T1 type; }; + template struct Select { typedef T2 type; }; + + template struct IsSignedIntergral { enum {value = 0}; }; + template <> struct IsSignedIntergral { enum {value = 1}; }; + template <> struct IsSignedIntergral { enum {value = 1}; }; + template <> struct IsSignedIntergral { enum {value = 1}; }; + template <> struct IsSignedIntergral { enum {value = 1}; }; + template <> struct IsSignedIntergral { enum {value = 1}; }; + template <> struct IsSignedIntergral { enum {value = 1}; }; + + template struct IsUnsignedIntegral { enum {value = 0}; }; + template <> struct IsUnsignedIntegral { enum {value = 1}; }; + template <> struct IsUnsignedIntegral { enum {value = 1}; }; + template <> struct IsUnsignedIntegral { enum {value = 1}; }; + template <> struct IsUnsignedIntegral { enum {value = 1}; }; + template <> struct IsUnsignedIntegral { enum {value = 1}; }; + template <> struct IsUnsignedIntegral { enum {value = 1}; }; + + template struct IsIntegral { enum {value = IsSignedIntergral::value || IsUnsignedIntegral::value}; }; + template <> struct IsIntegral { enum {value = 1}; }; + template <> struct IsIntegral { enum {value = 1}; }; + + template struct IsFloat { enum {value = 0}; }; + template <> struct IsFloat { enum {value = 1}; }; + template <> struct IsFloat { enum {value = 1}; }; + + template struct IsVec { enum {value = 0}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + template <> struct IsVec { enum {value = 1}; }; + + template struct AddParameterType { typedef const U& type; }; + template struct AddParameterType { typedef U& type; }; + template <> struct AddParameterType { typedef void type; }; + + template struct ReferenceTraits + { + enum { value = false }; + typedef U type; + }; + template struct ReferenceTraits + { + enum { value = true }; + typedef U type; + }; + + template struct PointerTraits + { + enum { value = false }; + typedef void type; + }; + template struct PointerTraits + { + enum { value = true }; + typedef U type; + }; + template struct PointerTraits + { + enum { value = true }; + typedef U type; + }; + + template struct UnConst + { + typedef U type; + enum { value = 0 }; + }; + template struct UnConst + { + typedef U type; + enum { value = 1 }; + }; + template struct UnConst + { + typedef U& type; + enum { value = 1 }; + }; + + template struct UnVolatile + { + typedef U type; + enum { value = 0 }; + }; + template struct UnVolatile + { + typedef U type; + enum { value = 1 }; + }; + template struct UnVolatile + { + typedef U& type; + enum { value = 1 }; + }; + } // namespace type_traits_detail +}}} // namespace cv { namespace cuda { namespace cudev + +//! @endcond + +#endif // OPENCV_CUDA_TYPE_TRAITS_DETAIL_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/vec_distance_detail.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/vec_distance_detail.hpp new file mode 100644 index 0000000..8283a99 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/detail/vec_distance_detail.hpp @@ -0,0 +1,121 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_VEC_DISTANCE_DETAIL_HPP +#define OPENCV_CUDA_VEC_DISTANCE_DETAIL_HPP + +#include "../datamov_utils.hpp" + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + namespace vec_distance_detail + { + template struct UnrollVecDiffCached + { + template + static __device__ void calcCheck(const T1* vecCached, const T2* vecGlob, int len, Dist& dist, int ind) + { + if (ind < len) + { + T1 val1 = *vecCached++; + + T2 val2; + ForceGlob::Load(vecGlob, ind, val2); + + dist.reduceIter(val1, val2); + + UnrollVecDiffCached::calcCheck(vecCached, vecGlob, len, dist, ind + THREAD_DIM); + } + } + + template + static __device__ void calcWithoutCheck(const T1* vecCached, const T2* vecGlob, Dist& dist) + { + T1 val1 = *vecCached++; + + T2 val2; + ForceGlob::Load(vecGlob, 0, val2); + vecGlob += THREAD_DIM; + + dist.reduceIter(val1, val2); + + UnrollVecDiffCached::calcWithoutCheck(vecCached, vecGlob, dist); + } + }; + template struct UnrollVecDiffCached + { + template + static __device__ __forceinline__ void calcCheck(const T1*, const T2*, int, Dist&, int) + { + } + + template + static __device__ __forceinline__ void calcWithoutCheck(const T1*, const T2*, Dist&) + { + } + }; + + template struct VecDiffCachedCalculator; + template struct VecDiffCachedCalculator + { + template + static __device__ __forceinline__ void calc(const T1* vecCached, const T2* vecGlob, int len, Dist& dist, int tid) + { + UnrollVecDiffCached::calcCheck(vecCached, vecGlob, len, dist, tid); + } + }; + template struct VecDiffCachedCalculator + { + template + static __device__ __forceinline__ void calc(const T1* vecCached, const T2* vecGlob, int len, Dist& dist, int tid) + { + UnrollVecDiffCached::calcWithoutCheck(vecCached, vecGlob + tid, dist); + } + }; + } // namespace vec_distance_detail +}}} // namespace cv { namespace cuda { namespace cudev + +//! @endcond + +#endif // OPENCV_CUDA_VEC_DISTANCE_DETAIL_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/dynamic_smem.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/dynamic_smem.hpp new file mode 100644 index 0000000..42570c6 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/dynamic_smem.hpp @@ -0,0 +1,88 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_DYNAMIC_SMEM_HPP +#define OPENCV_CUDA_DYNAMIC_SMEM_HPP + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + template struct DynamicSharedMem + { + __device__ __forceinline__ operator T*() + { + extern __shared__ int __smem[]; + return (T*)__smem; + } + + __device__ __forceinline__ operator const T*() const + { + extern __shared__ int __smem[]; + return (T*)__smem; + } + }; + + // specialize for double to avoid unaligned memory access compile errors + template<> struct DynamicSharedMem + { + __device__ __forceinline__ operator double*() + { + extern __shared__ double __smem_d[]; + return (double*)__smem_d; + } + + __device__ __forceinline__ operator const double*() const + { + extern __shared__ double __smem_d[]; + return (double*)__smem_d; + } + }; +}}} + +//! @endcond + +#endif // OPENCV_CUDA_DYNAMIC_SMEM_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/emulation.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/emulation.hpp new file mode 100644 index 0000000..17dc117 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/emulation.hpp @@ -0,0 +1,269 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_EMULATION_HPP_ +#define OPENCV_CUDA_EMULATION_HPP_ + +#include "common.hpp" +#include "warp_reduce.hpp" + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + struct Emulation + { + + static __device__ __forceinline__ int syncthreadsOr(int pred) + { +#if defined (__CUDA_ARCH__) && (__CUDA_ARCH__ < 200) + // just campilation stab + return 0; +#else + return __syncthreads_or(pred); +#endif + } + + template + static __forceinline__ __device__ int Ballot(int predicate) + { +#if defined (__CUDA_ARCH__) && (__CUDA_ARCH__ >= 200) + return __ballot(predicate); +#else + __shared__ volatile int cta_buffer[CTA_SIZE]; + + int tid = threadIdx.x; + cta_buffer[tid] = predicate ? (1 << (tid & 31)) : 0; + return warp_reduce(cta_buffer); +#endif + } + + struct smem + { + enum { TAG_MASK = (1U << ( (sizeof(unsigned int) << 3) - 5U)) - 1U }; + + template + static __device__ __forceinline__ T atomicInc(T* address, T val) + { +#if defined (__CUDA_ARCH__) && (__CUDA_ARCH__ < 120) + T count; + unsigned int tag = threadIdx.x << ( (sizeof(unsigned int) << 3) - 5U); + do + { + count = *address & TAG_MASK; + count = tag | (count + 1); + *address = count; + } while (*address != count); + + return (count & TAG_MASK) - 1; +#else + return ::atomicInc(address, val); +#endif + } + + template + static __device__ __forceinline__ T atomicAdd(T* address, T val) + { +#if defined (__CUDA_ARCH__) && (__CUDA_ARCH__ < 120) + T count; + unsigned int tag = threadIdx.x << ( (sizeof(unsigned int) << 3) - 5U); + do + { + count = *address & TAG_MASK; + count = tag | (count + val); + *address = count; + } while (*address != count); + + return (count & TAG_MASK) - val; +#else + return ::atomicAdd(address, val); +#endif + } + + template + static __device__ __forceinline__ T atomicMin(T* address, T val) + { +#if defined (__CUDA_ARCH__) && (__CUDA_ARCH__ < 120) + T count = ::min(*address, val); + do + { + *address = count; + } while (*address > count); + + return count; +#else + return ::atomicMin(address, val); +#endif + } + }; // struct cmem + + struct glob + { + static __device__ __forceinline__ int atomicAdd(int* address, int val) + { + return ::atomicAdd(address, val); + } + static __device__ __forceinline__ unsigned int atomicAdd(unsigned int* address, unsigned int val) + { + return ::atomicAdd(address, val); + } + static __device__ __forceinline__ float atomicAdd(float* address, float val) + { + #if __CUDA_ARCH__ >= 200 + return ::atomicAdd(address, val); + #else + int* address_as_i = (int*) address; + int old = *address_as_i, assumed; + do { + assumed = old; + old = ::atomicCAS(address_as_i, assumed, + __float_as_int(val + __int_as_float(assumed))); + } while (assumed != old); + return __int_as_float(old); + #endif + } + static __device__ __forceinline__ double atomicAdd(double* address, double val) + { + #if __CUDA_ARCH__ >= 130 + unsigned long long int* address_as_ull = (unsigned long long int*) address; + unsigned long long int old = *address_as_ull, assumed; + do { + assumed = old; + old = ::atomicCAS(address_as_ull, assumed, + __double_as_longlong(val + __longlong_as_double(assumed))); + } while (assumed != old); + return __longlong_as_double(old); + #else + CV_UNUSED(address); + CV_UNUSED(val); + return 0.0; + #endif + } + + static __device__ __forceinline__ int atomicMin(int* address, int val) + { + return ::atomicMin(address, val); + } + static __device__ __forceinline__ float atomicMin(float* address, float val) + { + #if __CUDA_ARCH__ >= 120 + int* address_as_i = (int*) address; + int old = *address_as_i, assumed; + do { + assumed = old; + old = ::atomicCAS(address_as_i, assumed, + __float_as_int(::fminf(val, __int_as_float(assumed)))); + } while (assumed != old); + return __int_as_float(old); + #else + CV_UNUSED(address); + CV_UNUSED(val); + return 0.0f; + #endif + } + static __device__ __forceinline__ double atomicMin(double* address, double val) + { + #if __CUDA_ARCH__ >= 130 + unsigned long long int* address_as_ull = (unsigned long long int*) address; + unsigned long long int old = *address_as_ull, assumed; + do { + assumed = old; + old = ::atomicCAS(address_as_ull, assumed, + __double_as_longlong(::fmin(val, __longlong_as_double(assumed)))); + } while (assumed != old); + return __longlong_as_double(old); + #else + CV_UNUSED(address); + CV_UNUSED(val); + return 0.0; + #endif + } + + static __device__ __forceinline__ int atomicMax(int* address, int val) + { + return ::atomicMax(address, val); + } + static __device__ __forceinline__ float atomicMax(float* address, float val) + { + #if __CUDA_ARCH__ >= 120 + int* address_as_i = (int*) address; + int old = *address_as_i, assumed; + do { + assumed = old; + old = ::atomicCAS(address_as_i, assumed, + __float_as_int(::fmaxf(val, __int_as_float(assumed)))); + } while (assumed != old); + return __int_as_float(old); + #else + CV_UNUSED(address); + CV_UNUSED(val); + return 0.0f; + #endif + } + static __device__ __forceinline__ double atomicMax(double* address, double val) + { + #if __CUDA_ARCH__ >= 130 + unsigned long long int* address_as_ull = (unsigned long long int*) address; + unsigned long long int old = *address_as_ull, assumed; + do { + assumed = old; + old = ::atomicCAS(address_as_ull, assumed, + __double_as_longlong(::fmax(val, __longlong_as_double(assumed)))); + } while (assumed != old); + return __longlong_as_double(old); + #else + CV_UNUSED(address); + CV_UNUSED(val); + return 0.0; + #endif + } + }; + }; //struct Emulation +}}} // namespace cv { namespace cuda { namespace cudev + +//! @endcond + +#endif /* OPENCV_CUDA_EMULATION_HPP_ */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/filters.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/filters.hpp new file mode 100644 index 0000000..bf3147e --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/filters.hpp @@ -0,0 +1,293 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_FILTERS_HPP +#define OPENCV_CUDA_FILTERS_HPP + +#include "saturate_cast.hpp" +#include "vec_traits.hpp" +#include "vec_math.hpp" +#include "type_traits.hpp" +#include "nppdefs.h" + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + template struct PointFilter + { + typedef typename Ptr2D::elem_type elem_type; + typedef float index_type; + + explicit __host__ __device__ __forceinline__ PointFilter(const Ptr2D& src_, float fx = 0.f, float fy = 0.f) + : src(src_) + { + CV_UNUSED(fx); + CV_UNUSED(fy); + } + + __device__ __forceinline__ elem_type operator ()(float y, float x) const + { + return src(__float2int_rz(y), __float2int_rz(x)); + } + + Ptr2D src; + }; + + template struct LinearFilter + { + typedef typename Ptr2D::elem_type elem_type; + typedef float index_type; + + explicit __host__ __device__ __forceinline__ LinearFilter(const Ptr2D& src_, float fx = 0.f, float fy = 0.f) + : src(src_) + { + CV_UNUSED(fx); + CV_UNUSED(fy); + } + __device__ __forceinline__ elem_type operator ()(float y, float x) const + { + typedef typename TypeVec::cn>::vec_type work_type; + + work_type out = VecTraits::all(0); + + const int x1 = __float2int_rd(x); + const int y1 = __float2int_rd(y); + if (x1 <= NPP_MIN_32S || x1 >= NPP_MAX_32S || y1 <= NPP_MIN_32S || y1 >= NPP_MAX_32S) + { + elem_type src_reg = src(y1, x1); + out = out + src_reg * 1.0f; + return saturate_cast(out); + } + const int x2 = x1 + 1; + const int y2 = y1 + 1; + + elem_type src_reg = src(y1, x1); + out = out + src_reg * ((x2 - x) * (y2 - y)); + + src_reg = src(y1, x2); + out = out + src_reg * ((x - x1) * (y2 - y)); + + src_reg = src(y2, x1); + out = out + src_reg * ((x2 - x) * (y - y1)); + + src_reg = src(y2, x2); + out = out + src_reg * ((x - x1) * (y - y1)); + + return saturate_cast(out); + } + + Ptr2D src; + }; + + template struct CubicFilter + { + typedef typename Ptr2D::elem_type elem_type; + typedef float index_type; + typedef typename TypeVec::cn>::vec_type work_type; + + explicit __host__ __device__ __forceinline__ CubicFilter(const Ptr2D& src_, float fx = 0.f, float fy = 0.f) + : src(src_) + { + CV_UNUSED(fx); + CV_UNUSED(fy); + } + + static __device__ __forceinline__ float bicubicCoeff(float x_) + { + float x = fabsf(x_); + if (x <= 1.0f) + { + return x * x * (1.5f * x - 2.5f) + 1.0f; + } + else if (x < 2.0f) + { + return x * (x * (-0.5f * x + 2.5f) - 4.0f) + 2.0f; + } + else + { + return 0.0f; + } + } + + __device__ elem_type operator ()(float y, float x) const + { + const float xmin = ::ceilf(x - 2.0f); + const float xmax = ::floorf(x + 2.0f); + + const float ymin = ::ceilf(y - 2.0f); + const float ymax = ::floorf(y + 2.0f); + + work_type sum = VecTraits::all(0); + float wsum = 0.0f; + + for (float cy = ymin; cy <= ymax; cy += 1.0f) + { + for (float cx = xmin; cx <= xmax; cx += 1.0f) + { + const float w = bicubicCoeff(x - cx) * bicubicCoeff(y - cy); + sum = sum + w * src(__float2int_rd(cy), __float2int_rd(cx)); + wsum += w; + } + } + + work_type res = (!wsum)? VecTraits::all(0) : sum / wsum; + + return saturate_cast(res); + } + + Ptr2D src; + }; + // for integer scaling + template struct IntegerAreaFilter + { + typedef typename Ptr2D::elem_type elem_type; + typedef float index_type; + + explicit __host__ __device__ __forceinline__ IntegerAreaFilter(const Ptr2D& src_, float scale_x_, float scale_y_) + : src(src_), scale_x(scale_x_), scale_y(scale_y_), scale(1.f / (scale_x * scale_y)) {} + + __device__ __forceinline__ elem_type operator ()(float y, float x) const + { + float fsx1 = x * scale_x; + float fsx2 = fsx1 + scale_x; + + int sx1 = __float2int_ru(fsx1); + int sx2 = __float2int_rd(fsx2); + + float fsy1 = y * scale_y; + float fsy2 = fsy1 + scale_y; + + int sy1 = __float2int_ru(fsy1); + int sy2 = __float2int_rd(fsy2); + + typedef typename TypeVec::cn>::vec_type work_type; + work_type out = VecTraits::all(0.f); + + for(int dy = sy1; dy < sy2; ++dy) + for(int dx = sx1; dx < sx2; ++dx) + { + out = out + src(dy, dx) * scale; + } + + return saturate_cast(out); + } + + Ptr2D src; + float scale_x, scale_y ,scale; + }; + + template struct AreaFilter + { + typedef typename Ptr2D::elem_type elem_type; + typedef float index_type; + + explicit __host__ __device__ __forceinline__ AreaFilter(const Ptr2D& src_, float scale_x_, float scale_y_) + : src(src_), scale_x(scale_x_), scale_y(scale_y_){} + + __device__ __forceinline__ elem_type operator ()(float y, float x) const + { + float fsx1 = x * scale_x; + float fsx2 = fsx1 + scale_x; + + int sx1 = __float2int_ru(fsx1); + int sx2 = __float2int_rd(fsx2); + + float fsy1 = y * scale_y; + float fsy2 = fsy1 + scale_y; + + int sy1 = __float2int_ru(fsy1); + int sy2 = __float2int_rd(fsy2); + + float scale = 1.f / (fminf(scale_x, src.width - fsx1) * fminf(scale_y, src.height - fsy1)); + + typedef typename TypeVec::cn>::vec_type work_type; + work_type out = VecTraits::all(0.f); + + for (int dy = sy1; dy < sy2; ++dy) + { + for (int dx = sx1; dx < sx2; ++dx) + out = out + src(dy, dx) * scale; + + if (sx1 > fsx1) + out = out + src(dy, (sx1 -1) ) * ((sx1 - fsx1) * scale); + + if (sx2 < fsx2) + out = out + src(dy, sx2) * ((fsx2 -sx2) * scale); + } + + if (sy1 > fsy1) + for (int dx = sx1; dx < sx2; ++dx) + out = out + src( (sy1 - 1) , dx) * ((sy1 -fsy1) * scale); + + if (sy2 < fsy2) + for (int dx = sx1; dx < sx2; ++dx) + out = out + src(sy2, dx) * ((fsy2 -sy2) * scale); + + if ((sy1 > fsy1) && (sx1 > fsx1)) + out = out + src( (sy1 - 1) , (sx1 - 1)) * ((sy1 -fsy1) * (sx1 -fsx1) * scale); + + if ((sy1 > fsy1) && (sx2 < fsx2)) + out = out + src( (sy1 - 1) , sx2) * ((sy1 -fsy1) * (fsx2 -sx2) * scale); + + if ((sy2 < fsy2) && (sx2 < fsx2)) + out = out + src(sy2, sx2) * ((fsy2 -sy2) * (fsx2 -sx2) * scale); + + if ((sy2 < fsy2) && (sx1 > fsx1)) + out = out + src(sy2, (sx1 - 1)) * ((fsy2 -sy2) * (sx1 -fsx1) * scale); + + return saturate_cast(out); + } + + Ptr2D src; + float scale_x, scale_y; + int width, haight; + }; +}}} // namespace cv { namespace cuda { namespace cudev + +//! @endcond + +#endif // OPENCV_CUDA_FILTERS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/funcattrib.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/funcattrib.hpp new file mode 100644 index 0000000..f582080 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/funcattrib.hpp @@ -0,0 +1,79 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_DEVICE_FUNCATTRIB_HPP +#define OPENCV_CUDA_DEVICE_FUNCATTRIB_HPP + +#include + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + template + void printFuncAttrib(Func& func) + { + + cudaFuncAttributes attrs; + cudaFuncGetAttributes(&attrs, func); + + printf("=== Function stats ===\n"); + printf("Name: \n"); + printf("sharedSizeBytes = %d\n", attrs.sharedSizeBytes); + printf("constSizeBytes = %d\n", attrs.constSizeBytes); + printf("localSizeBytes = %d\n", attrs.localSizeBytes); + printf("maxThreadsPerBlock = %d\n", attrs.maxThreadsPerBlock); + printf("numRegs = %d\n", attrs.numRegs); + printf("ptxVersion = %d\n", attrs.ptxVersion); + printf("binaryVersion = %d\n", attrs.binaryVersion); + printf("\n"); + fflush(stdout); + } +}}} // namespace cv { namespace cuda { namespace cudev + +//! @endcond + +#endif /* OPENCV_CUDA_DEVICE_FUNCATTRIB_HPP */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/functional.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/functional.hpp new file mode 100644 index 0000000..9f53d87 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/functional.hpp @@ -0,0 +1,805 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_FUNCTIONAL_HPP +#define OPENCV_CUDA_FUNCTIONAL_HPP + +#include +#include "saturate_cast.hpp" +#include "vec_traits.hpp" +#include "type_traits.hpp" + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + // Function Objects + template struct unary_function + { + typedef Argument argument_type; + typedef Result result_type; + }; + template struct binary_function + { + typedef Argument1 first_argument_type; + typedef Argument2 second_argument_type; + typedef Result result_type; + }; + + // Arithmetic Operations + template struct plus : binary_function + { + __device__ __forceinline__ T operator ()(typename TypeTraits::ParameterType a, + typename TypeTraits::ParameterType b) const + { + return a + b; + } + __host__ __device__ __forceinline__ plus() {} + __host__ __device__ __forceinline__ plus(const plus&) {} + }; + + template struct minus : binary_function + { + __device__ __forceinline__ T operator ()(typename TypeTraits::ParameterType a, + typename TypeTraits::ParameterType b) const + { + return a - b; + } + __host__ __device__ __forceinline__ minus() {} + __host__ __device__ __forceinline__ minus(const minus&) {} + }; + + template struct multiplies : binary_function + { + __device__ __forceinline__ T operator ()(typename TypeTraits::ParameterType a, + typename TypeTraits::ParameterType b) const + { + return a * b; + } + __host__ __device__ __forceinline__ multiplies() {} + __host__ __device__ __forceinline__ multiplies(const multiplies&) {} + }; + + template struct divides : binary_function + { + __device__ __forceinline__ T operator ()(typename TypeTraits::ParameterType a, + typename TypeTraits::ParameterType b) const + { + return a / b; + } + __host__ __device__ __forceinline__ divides() {} + __host__ __device__ __forceinline__ divides(const divides&) {} + }; + + template struct modulus : binary_function + { + __device__ __forceinline__ T operator ()(typename TypeTraits::ParameterType a, + typename TypeTraits::ParameterType b) const + { + return a % b; + } + __host__ __device__ __forceinline__ modulus() {} + __host__ __device__ __forceinline__ modulus(const modulus&) {} + }; + + template struct negate : unary_function + { + __device__ __forceinline__ T operator ()(typename TypeTraits::ParameterType a) const + { + return -a; + } + __host__ __device__ __forceinline__ negate() {} + __host__ __device__ __forceinline__ negate(const negate&) {} + }; + + // Comparison Operations + template struct equal_to : binary_function + { + __device__ __forceinline__ bool operator ()(typename TypeTraits::ParameterType a, + typename TypeTraits::ParameterType b) const + { + return a == b; + } + __host__ __device__ __forceinline__ equal_to() {} + __host__ __device__ __forceinline__ equal_to(const equal_to&) {} + }; + + template struct not_equal_to : binary_function + { + __device__ __forceinline__ bool operator ()(typename TypeTraits::ParameterType a, + typename TypeTraits::ParameterType b) const + { + return a != b; + } + __host__ __device__ __forceinline__ not_equal_to() {} + __host__ __device__ __forceinline__ not_equal_to(const not_equal_to&) {} + }; + + template struct greater : binary_function + { + __device__ __forceinline__ bool operator ()(typename TypeTraits::ParameterType a, + typename TypeTraits::ParameterType b) const + { + return a > b; + } + __host__ __device__ __forceinline__ greater() {} + __host__ __device__ __forceinline__ greater(const greater&) {} + }; + + template struct less : binary_function + { + __device__ __forceinline__ bool operator ()(typename TypeTraits::ParameterType a, + typename TypeTraits::ParameterType b) const + { + return a < b; + } + __host__ __device__ __forceinline__ less() {} + __host__ __device__ __forceinline__ less(const less&) {} + }; + + template struct greater_equal : binary_function + { + __device__ __forceinline__ bool operator ()(typename TypeTraits::ParameterType a, + typename TypeTraits::ParameterType b) const + { + return a >= b; + } + __host__ __device__ __forceinline__ greater_equal() {} + __host__ __device__ __forceinline__ greater_equal(const greater_equal&) {} + }; + + template struct less_equal : binary_function + { + __device__ __forceinline__ bool operator ()(typename TypeTraits::ParameterType a, + typename TypeTraits::ParameterType b) const + { + return a <= b; + } + __host__ __device__ __forceinline__ less_equal() {} + __host__ __device__ __forceinline__ less_equal(const less_equal&) {} + }; + + // Logical Operations + template struct logical_and : binary_function + { + __device__ __forceinline__ bool operator ()(typename TypeTraits::ParameterType a, + typename TypeTraits::ParameterType b) const + { + return a && b; + } + __host__ __device__ __forceinline__ logical_and() {} + __host__ __device__ __forceinline__ logical_and(const logical_and&) {} + }; + + template struct logical_or : binary_function + { + __device__ __forceinline__ bool operator ()(typename TypeTraits::ParameterType a, + typename TypeTraits::ParameterType b) const + { + return a || b; + } + __host__ __device__ __forceinline__ logical_or() {} + __host__ __device__ __forceinline__ logical_or(const logical_or&) {} + }; + + template struct logical_not : unary_function + { + __device__ __forceinline__ bool operator ()(typename TypeTraits::ParameterType a) const + { + return !a; + } + __host__ __device__ __forceinline__ logical_not() {} + __host__ __device__ __forceinline__ logical_not(const logical_not&) {} + }; + + // Bitwise Operations + template struct bit_and : binary_function + { + __device__ __forceinline__ T operator ()(typename TypeTraits::ParameterType a, + typename TypeTraits::ParameterType b) const + { + return a & b; + } + __host__ __device__ __forceinline__ bit_and() {} + __host__ __device__ __forceinline__ bit_and(const bit_and&) {} + }; + + template struct bit_or : binary_function + { + __device__ __forceinline__ T operator ()(typename TypeTraits::ParameterType a, + typename TypeTraits::ParameterType b) const + { + return a | b; + } + __host__ __device__ __forceinline__ bit_or() {} + __host__ __device__ __forceinline__ bit_or(const bit_or&) {} + }; + + template struct bit_xor : binary_function + { + __device__ __forceinline__ T operator ()(typename TypeTraits::ParameterType a, + typename TypeTraits::ParameterType b) const + { + return a ^ b; + } + __host__ __device__ __forceinline__ bit_xor() {} + __host__ __device__ __forceinline__ bit_xor(const bit_xor&) {} + }; + + template struct bit_not : unary_function + { + __device__ __forceinline__ T operator ()(typename TypeTraits::ParameterType v) const + { + return ~v; + } + __host__ __device__ __forceinline__ bit_not() {} + __host__ __device__ __forceinline__ bit_not(const bit_not&) {} + }; + + // Generalized Identity Operations + template struct identity : unary_function + { + __device__ __forceinline__ typename TypeTraits::ParameterType operator()(typename TypeTraits::ParameterType x) const + { + return x; + } + __host__ __device__ __forceinline__ identity() {} + __host__ __device__ __forceinline__ identity(const identity&) {} + }; + + template struct project1st : binary_function + { + __device__ __forceinline__ typename TypeTraits::ParameterType operator()(typename TypeTraits::ParameterType lhs, typename TypeTraits::ParameterType rhs) const + { + return lhs; + } + __host__ __device__ __forceinline__ project1st() {} + __host__ __device__ __forceinline__ project1st(const project1st&) {} + }; + + template struct project2nd : binary_function + { + __device__ __forceinline__ typename TypeTraits::ParameterType operator()(typename TypeTraits::ParameterType lhs, typename TypeTraits::ParameterType rhs) const + { + return rhs; + } + __host__ __device__ __forceinline__ project2nd() {} + __host__ __device__ __forceinline__ project2nd(const project2nd&) {} + }; + + // Min/Max Operations + +#define OPENCV_CUDA_IMPLEMENT_MINMAX(name, type, op) \ + template <> struct name : binary_function \ + { \ + __device__ __forceinline__ type operator()(type lhs, type rhs) const {return op(lhs, rhs);} \ + __host__ __device__ __forceinline__ name() {}\ + __host__ __device__ __forceinline__ name(const name&) {}\ + }; + + template struct maximum : binary_function + { + __device__ __forceinline__ T operator()(typename TypeTraits::ParameterType lhs, typename TypeTraits::ParameterType rhs) const + { + return max(lhs, rhs); + } + __host__ __device__ __forceinline__ maximum() {} + __host__ __device__ __forceinline__ maximum(const maximum&) {} + }; + + OPENCV_CUDA_IMPLEMENT_MINMAX(maximum, uchar, ::max) + OPENCV_CUDA_IMPLEMENT_MINMAX(maximum, schar, ::max) + OPENCV_CUDA_IMPLEMENT_MINMAX(maximum, char, ::max) + OPENCV_CUDA_IMPLEMENT_MINMAX(maximum, ushort, ::max) + OPENCV_CUDA_IMPLEMENT_MINMAX(maximum, short, ::max) + OPENCV_CUDA_IMPLEMENT_MINMAX(maximum, int, ::max) + OPENCV_CUDA_IMPLEMENT_MINMAX(maximum, uint, ::max) + OPENCV_CUDA_IMPLEMENT_MINMAX(maximum, float, ::fmax) + OPENCV_CUDA_IMPLEMENT_MINMAX(maximum, double, ::fmax) + + template struct minimum : binary_function + { + __device__ __forceinline__ T operator()(typename TypeTraits::ParameterType lhs, typename TypeTraits::ParameterType rhs) const + { + return min(lhs, rhs); + } + __host__ __device__ __forceinline__ minimum() {} + __host__ __device__ __forceinline__ minimum(const minimum&) {} + }; + + OPENCV_CUDA_IMPLEMENT_MINMAX(minimum, uchar, ::min) + OPENCV_CUDA_IMPLEMENT_MINMAX(minimum, schar, ::min) + OPENCV_CUDA_IMPLEMENT_MINMAX(minimum, char, ::min) + OPENCV_CUDA_IMPLEMENT_MINMAX(minimum, ushort, ::min) + OPENCV_CUDA_IMPLEMENT_MINMAX(minimum, short, ::min) + OPENCV_CUDA_IMPLEMENT_MINMAX(minimum, int, ::min) + OPENCV_CUDA_IMPLEMENT_MINMAX(minimum, uint, ::min) + OPENCV_CUDA_IMPLEMENT_MINMAX(minimum, float, ::fmin) + OPENCV_CUDA_IMPLEMENT_MINMAX(minimum, double, ::fmin) + +#undef OPENCV_CUDA_IMPLEMENT_MINMAX + + // Math functions + + template struct abs_func : unary_function + { + __device__ __forceinline__ T operator ()(typename TypeTraits::ParameterType x) const + { + return abs(x); + } + + __host__ __device__ __forceinline__ abs_func() {} + __host__ __device__ __forceinline__ abs_func(const abs_func&) {} + }; + template <> struct abs_func : unary_function + { + __device__ __forceinline__ unsigned char operator ()(unsigned char x) const + { + return x; + } + + __host__ __device__ __forceinline__ abs_func() {} + __host__ __device__ __forceinline__ abs_func(const abs_func&) {} + }; + template <> struct abs_func : unary_function + { + __device__ __forceinline__ signed char operator ()(signed char x) const + { + return ::abs((int)x); + } + + __host__ __device__ __forceinline__ abs_func() {} + __host__ __device__ __forceinline__ abs_func(const abs_func&) {} + }; + template <> struct abs_func : unary_function + { + __device__ __forceinline__ char operator ()(char x) const + { + return ::abs((int)x); + } + + __host__ __device__ __forceinline__ abs_func() {} + __host__ __device__ __forceinline__ abs_func(const abs_func&) {} + }; + template <> struct abs_func : unary_function + { + __device__ __forceinline__ unsigned short operator ()(unsigned short x) const + { + return x; + } + + __host__ __device__ __forceinline__ abs_func() {} + __host__ __device__ __forceinline__ abs_func(const abs_func&) {} + }; + template <> struct abs_func : unary_function + { + __device__ __forceinline__ short operator ()(short x) const + { + return ::abs((int)x); + } + + __host__ __device__ __forceinline__ abs_func() {} + __host__ __device__ __forceinline__ abs_func(const abs_func&) {} + }; + template <> struct abs_func : unary_function + { + __device__ __forceinline__ unsigned int operator ()(unsigned int x) const + { + return x; + } + + __host__ __device__ __forceinline__ abs_func() {} + __host__ __device__ __forceinline__ abs_func(const abs_func&) {} + }; + template <> struct abs_func : unary_function + { + __device__ __forceinline__ int operator ()(int x) const + { + return ::abs(x); + } + + __host__ __device__ __forceinline__ abs_func() {} + __host__ __device__ __forceinline__ abs_func(const abs_func&) {} + }; + template <> struct abs_func : unary_function + { + __device__ __forceinline__ float operator ()(float x) const + { + return ::fabsf(x); + } + + __host__ __device__ __forceinline__ abs_func() {} + __host__ __device__ __forceinline__ abs_func(const abs_func&) {} + }; + template <> struct abs_func : unary_function + { + __device__ __forceinline__ double operator ()(double x) const + { + return ::fabs(x); + } + + __host__ __device__ __forceinline__ abs_func() {} + __host__ __device__ __forceinline__ abs_func(const abs_func&) {} + }; + +#define OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR(name, func) \ + template struct name ## _func : unary_function \ + { \ + __device__ __forceinline__ float operator ()(typename TypeTraits::ParameterType v) const \ + { \ + return func ## f(v); \ + } \ + __host__ __device__ __forceinline__ name ## _func() {} \ + __host__ __device__ __forceinline__ name ## _func(const name ## _func&) {} \ + }; \ + template <> struct name ## _func : unary_function \ + { \ + __device__ __forceinline__ double operator ()(double v) const \ + { \ + return func(v); \ + } \ + __host__ __device__ __forceinline__ name ## _func() {} \ + __host__ __device__ __forceinline__ name ## _func(const name ## _func&) {} \ + }; + +#define OPENCV_CUDA_IMPLEMENT_BIN_FUNCTOR(name, func) \ + template struct name ## _func : binary_function \ + { \ + __device__ __forceinline__ float operator ()(typename TypeTraits::ParameterType v1, typename TypeTraits::ParameterType v2) const \ + { \ + return func ## f(v1, v2); \ + } \ + __host__ __device__ __forceinline__ name ## _func() {} \ + __host__ __device__ __forceinline__ name ## _func(const name ## _func&) {} \ + }; \ + template <> struct name ## _func : binary_function \ + { \ + __device__ __forceinline__ double operator ()(double v1, double v2) const \ + { \ + return func(v1, v2); \ + } \ + __host__ __device__ __forceinline__ name ## _func() {} \ + __host__ __device__ __forceinline__ name ## _func(const name ## _func&) {} \ + }; + + OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR(sqrt, ::sqrt) + OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR(exp, ::exp) + OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR(exp2, ::exp2) + OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR(exp10, ::exp10) + OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR(log, ::log) + OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR(log2, ::log2) + OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR(log10, ::log10) + OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR(sin, ::sin) + OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR(cos, ::cos) + OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR(tan, ::tan) + OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR(asin, ::asin) + OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR(acos, ::acos) + OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR(atan, ::atan) + OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR(sinh, ::sinh) + OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR(cosh, ::cosh) + OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR(tanh, ::tanh) + OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR(asinh, ::asinh) + OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR(acosh, ::acosh) + OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR(atanh, ::atanh) + + OPENCV_CUDA_IMPLEMENT_BIN_FUNCTOR(hypot, ::hypot) + OPENCV_CUDA_IMPLEMENT_BIN_FUNCTOR(atan2, ::atan2) + OPENCV_CUDA_IMPLEMENT_BIN_FUNCTOR(pow, ::pow) + + #undef OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR + #undef OPENCV_CUDA_IMPLEMENT_UN_FUNCTOR_NO_DOUBLE + #undef OPENCV_CUDA_IMPLEMENT_BIN_FUNCTOR + + template struct hypot_sqr_func : binary_function + { + __device__ __forceinline__ T operator ()(typename TypeTraits::ParameterType src1, typename TypeTraits::ParameterType src2) const + { + return src1 * src1 + src2 * src2; + } + __host__ __device__ __forceinline__ hypot_sqr_func() {} + __host__ __device__ __forceinline__ hypot_sqr_func(const hypot_sqr_func&) {} + }; + + // Saturate Cast Functor + template struct saturate_cast_func : unary_function + { + __device__ __forceinline__ D operator ()(typename TypeTraits::ParameterType v) const + { + return saturate_cast(v); + } + __host__ __device__ __forceinline__ saturate_cast_func() {} + __host__ __device__ __forceinline__ saturate_cast_func(const saturate_cast_func&) {} + }; + + // Threshold Functors + template struct thresh_binary_func : unary_function + { + __host__ __device__ __forceinline__ thresh_binary_func(T thresh_, T maxVal_) : thresh(thresh_), maxVal(maxVal_) {} + + __device__ __forceinline__ T operator()(typename TypeTraits::ParameterType src) const + { + return (src > thresh) * maxVal; + } + + __host__ __device__ __forceinline__ thresh_binary_func() {} + __host__ __device__ __forceinline__ thresh_binary_func(const thresh_binary_func& other) + : thresh(other.thresh), maxVal(other.maxVal) {} + + T thresh; + T maxVal; + }; + + template struct thresh_binary_inv_func : unary_function + { + __host__ __device__ __forceinline__ thresh_binary_inv_func(T thresh_, T maxVal_) : thresh(thresh_), maxVal(maxVal_) {} + + __device__ __forceinline__ T operator()(typename TypeTraits::ParameterType src) const + { + return (src <= thresh) * maxVal; + } + + __host__ __device__ __forceinline__ thresh_binary_inv_func() {} + __host__ __device__ __forceinline__ thresh_binary_inv_func(const thresh_binary_inv_func& other) + : thresh(other.thresh), maxVal(other.maxVal) {} + + T thresh; + T maxVal; + }; + + template struct thresh_trunc_func : unary_function + { + explicit __host__ __device__ __forceinline__ thresh_trunc_func(T thresh_, T maxVal_ = 0) : thresh(thresh_) {CV_UNUSED(maxVal_);} + + __device__ __forceinline__ T operator()(typename TypeTraits::ParameterType src) const + { + return minimum()(src, thresh); + } + + __host__ __device__ __forceinline__ thresh_trunc_func() {} + __host__ __device__ __forceinline__ thresh_trunc_func(const thresh_trunc_func& other) + : thresh(other.thresh) {} + + T thresh; + }; + + template struct thresh_to_zero_func : unary_function + { + explicit __host__ __device__ __forceinline__ thresh_to_zero_func(T thresh_, T maxVal_ = 0) : thresh(thresh_) {CV_UNUSED(maxVal_);} + + __device__ __forceinline__ T operator()(typename TypeTraits::ParameterType src) const + { + return (src > thresh) * src; + } + + __host__ __device__ __forceinline__ thresh_to_zero_func() {} + __host__ __device__ __forceinline__ thresh_to_zero_func(const thresh_to_zero_func& other) + : thresh(other.thresh) {} + + T thresh; + }; + + template struct thresh_to_zero_inv_func : unary_function + { + explicit __host__ __device__ __forceinline__ thresh_to_zero_inv_func(T thresh_, T maxVal_ = 0) : thresh(thresh_) {CV_UNUSED(maxVal_);} + + __device__ __forceinline__ T operator()(typename TypeTraits::ParameterType src) const + { + return (src <= thresh) * src; + } + + __host__ __device__ __forceinline__ thresh_to_zero_inv_func() {} + __host__ __device__ __forceinline__ thresh_to_zero_inv_func(const thresh_to_zero_inv_func& other) + : thresh(other.thresh) {} + + T thresh; + }; + + // Function Object Adaptors + template struct unary_negate : unary_function + { + explicit __host__ __device__ __forceinline__ unary_negate(const Predicate& p) : pred(p) {} + + __device__ __forceinline__ bool operator()(typename TypeTraits::ParameterType x) const + { + return !pred(x); + } + + __host__ __device__ __forceinline__ unary_negate() {} + __host__ __device__ __forceinline__ unary_negate(const unary_negate& other) : pred(other.pred) {} + + Predicate pred; + }; + + template __host__ __device__ __forceinline__ unary_negate not1(const Predicate& pred) + { + return unary_negate(pred); + } + + template struct binary_negate : binary_function + { + explicit __host__ __device__ __forceinline__ binary_negate(const Predicate& p) : pred(p) {} + + __device__ __forceinline__ bool operator()(typename TypeTraits::ParameterType x, + typename TypeTraits::ParameterType y) const + { + return !pred(x,y); + } + + __host__ __device__ __forceinline__ binary_negate() {} + __host__ __device__ __forceinline__ binary_negate(const binary_negate& other) : pred(other.pred) {} + + Predicate pred; + }; + + template __host__ __device__ __forceinline__ binary_negate not2(const BinaryPredicate& pred) + { + return binary_negate(pred); + } + + template struct binder1st : unary_function + { + __host__ __device__ __forceinline__ binder1st(const Op& op_, const typename Op::first_argument_type& arg1_) : op(op_), arg1(arg1_) {} + + __device__ __forceinline__ typename Op::result_type operator ()(typename TypeTraits::ParameterType a) const + { + return op(arg1, a); + } + + __host__ __device__ __forceinline__ binder1st() {} + __host__ __device__ __forceinline__ binder1st(const binder1st& other) : op(other.op), arg1(other.arg1) {} + + Op op; + typename Op::first_argument_type arg1; + }; + + template __host__ __device__ __forceinline__ binder1st bind1st(const Op& op, const T& x) + { + return binder1st(op, typename Op::first_argument_type(x)); + } + + template struct binder2nd : unary_function + { + __host__ __device__ __forceinline__ binder2nd(const Op& op_, const typename Op::second_argument_type& arg2_) : op(op_), arg2(arg2_) {} + + __forceinline__ __device__ typename Op::result_type operator ()(typename TypeTraits::ParameterType a) const + { + return op(a, arg2); + } + + __host__ __device__ __forceinline__ binder2nd() {} + __host__ __device__ __forceinline__ binder2nd(const binder2nd& other) : op(other.op), arg2(other.arg2) {} + + Op op; + typename Op::second_argument_type arg2; + }; + + template __host__ __device__ __forceinline__ binder2nd bind2nd(const Op& op, const T& x) + { + return binder2nd(op, typename Op::second_argument_type(x)); + } + + // Functor Traits + template struct IsUnaryFunction + { + typedef char Yes; + struct No {Yes a[2];}; + + template static Yes check(unary_function); + static No check(...); + + static F makeF(); + + enum { value = (sizeof(check(makeF())) == sizeof(Yes)) }; + }; + + template struct IsBinaryFunction + { + typedef char Yes; + struct No {Yes a[2];}; + + template static Yes check(binary_function); + static No check(...); + + static F makeF(); + + enum { value = (sizeof(check(makeF())) == sizeof(Yes)) }; + }; + + namespace functional_detail + { + template struct UnOpShift { enum { shift = 1 }; }; + template struct UnOpShift { enum { shift = 4 }; }; + template struct UnOpShift { enum { shift = 2 }; }; + + template struct DefaultUnaryShift + { + enum { shift = UnOpShift::shift }; + }; + + template struct BinOpShift { enum { shift = 1 }; }; + template struct BinOpShift { enum { shift = 4 }; }; + template struct BinOpShift { enum { shift = 2 }; }; + + template struct DefaultBinaryShift + { + enum { shift = BinOpShift::shift }; + }; + + template ::value> struct ShiftDispatcher; + template struct ShiftDispatcher + { + enum { shift = DefaultUnaryShift::shift }; + }; + template struct ShiftDispatcher + { + enum { shift = DefaultBinaryShift::shift }; + }; + } + + template struct DefaultTransformShift + { + enum { shift = functional_detail::ShiftDispatcher::shift }; + }; + + template struct DefaultTransformFunctorTraits + { + enum { simple_block_dim_x = 16 }; + enum { simple_block_dim_y = 16 }; + + enum { smart_block_dim_x = 16 }; + enum { smart_block_dim_y = 16 }; + enum { smart_shift = DefaultTransformShift::shift }; + }; + + template struct TransformFunctorTraits : DefaultTransformFunctorTraits {}; + +#define OPENCV_CUDA_TRANSFORM_FUNCTOR_TRAITS(type) \ + template <> struct TransformFunctorTraits< type > : DefaultTransformFunctorTraits< type > +}}} // namespace cv { namespace cuda { namespace cudev + +//! @endcond + +#endif // OPENCV_CUDA_FUNCTIONAL_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/limits.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/limits.hpp new file mode 100644 index 0000000..7e15ed6 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/limits.hpp @@ -0,0 +1,128 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_LIMITS_HPP +#define OPENCV_CUDA_LIMITS_HPP + +#include +#include +#include "common.hpp" + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ +template struct numeric_limits; + +template <> struct numeric_limits +{ + __device__ __forceinline__ static bool min() { return false; } + __device__ __forceinline__ static bool max() { return true; } + static const bool is_signed = false; +}; + +template <> struct numeric_limits +{ + __device__ __forceinline__ static signed char min() { return SCHAR_MIN; } + __device__ __forceinline__ static signed char max() { return SCHAR_MAX; } + static const bool is_signed = true; +}; + +template <> struct numeric_limits +{ + __device__ __forceinline__ static unsigned char min() { return 0; } + __device__ __forceinline__ static unsigned char max() { return UCHAR_MAX; } + static const bool is_signed = false; +}; + +template <> struct numeric_limits +{ + __device__ __forceinline__ static short min() { return SHRT_MIN; } + __device__ __forceinline__ static short max() { return SHRT_MAX; } + static const bool is_signed = true; +}; + +template <> struct numeric_limits +{ + __device__ __forceinline__ static unsigned short min() { return 0; } + __device__ __forceinline__ static unsigned short max() { return USHRT_MAX; } + static const bool is_signed = false; +}; + +template <> struct numeric_limits +{ + __device__ __forceinline__ static int min() { return INT_MIN; } + __device__ __forceinline__ static int max() { return INT_MAX; } + static const bool is_signed = true; +}; + +template <> struct numeric_limits +{ + __device__ __forceinline__ static unsigned int min() { return 0; } + __device__ __forceinline__ static unsigned int max() { return UINT_MAX; } + static const bool is_signed = false; +}; + +template <> struct numeric_limits +{ + __device__ __forceinline__ static float min() { return FLT_MIN; } + __device__ __forceinline__ static float max() { return FLT_MAX; } + __device__ __forceinline__ static float epsilon() { return FLT_EPSILON; } + static const bool is_signed = true; +}; + +template <> struct numeric_limits +{ + __device__ __forceinline__ static double min() { return DBL_MIN; } + __device__ __forceinline__ static double max() { return DBL_MAX; } + __device__ __forceinline__ static double epsilon() { return DBL_EPSILON; } + static const bool is_signed = true; +}; +}}} // namespace cv { namespace cuda { namespace cudev { + +//! @endcond + +#endif // OPENCV_CUDA_LIMITS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/reduce.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/reduce.hpp new file mode 100644 index 0000000..5de3650 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/reduce.hpp @@ -0,0 +1,209 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_REDUCE_HPP +#define OPENCV_CUDA_REDUCE_HPP + +#ifndef THRUST_DEBUG // eliminate -Wundef warning +#define THRUST_DEBUG 0 +#endif + +#include +#include "detail/reduce.hpp" +#include "detail/reduce_key_val.hpp" + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + template + __device__ __forceinline__ void reduce(volatile T* smem, T& val, unsigned int tid, const Op& op) + { + reduce_detail::Dispatcher::reductor::template reduce(smem, val, tid, op); + } + template + __device__ __forceinline__ void reduce(const thrust::tuple& smem, + const thrust::tuple& val, + unsigned int tid, + const thrust::tuple& op) + { + reduce_detail::Dispatcher::reductor::template reduce< + const thrust::tuple&, + const thrust::tuple&, + const thrust::tuple&>(smem, val, tid, op); + } + + template + __device__ __forceinline__ void reduceKeyVal(volatile K* skeys, K& key, volatile V* svals, V& val, unsigned int tid, const Cmp& cmp) + { + reduce_key_val_detail::Dispatcher::reductor::template reduce(skeys, key, svals, val, tid, cmp); + } + template + __device__ __forceinline__ void reduceKeyVal(volatile K* skeys, K& key, + const thrust::tuple& svals, + const thrust::tuple& val, + unsigned int tid, const Cmp& cmp) + { + reduce_key_val_detail::Dispatcher::reductor::template reduce&, + const thrust::tuple&, + const Cmp&>(skeys, key, svals, val, tid, cmp); + } + template + __device__ __forceinline__ void reduceKeyVal(const thrust::tuple& skeys, + const thrust::tuple& key, + const thrust::tuple& svals, + const thrust::tuple& val, + unsigned int tid, + const thrust::tuple& cmp) + { + reduce_key_val_detail::Dispatcher::reductor::template reduce< + const thrust::tuple&, + const thrust::tuple&, + const thrust::tuple&, + const thrust::tuple&, + const thrust::tuple& + >(skeys, key, svals, val, tid, cmp); + } + + // smem_tuple + + template + __device__ __forceinline__ + thrust::tuple + smem_tuple(T0* t0) + { + return thrust::make_tuple((volatile T0*) t0); + } + + template + __device__ __forceinline__ + thrust::tuple + smem_tuple(T0* t0, T1* t1) + { + return thrust::make_tuple((volatile T0*) t0, (volatile T1*) t1); + } + + template + __device__ __forceinline__ + thrust::tuple + smem_tuple(T0* t0, T1* t1, T2* t2) + { + return thrust::make_tuple((volatile T0*) t0, (volatile T1*) t1, (volatile T2*) t2); + } + + template + __device__ __forceinline__ + thrust::tuple + smem_tuple(T0* t0, T1* t1, T2* t2, T3* t3) + { + return thrust::make_tuple((volatile T0*) t0, (volatile T1*) t1, (volatile T2*) t2, (volatile T3*) t3); + } + + template + __device__ __forceinline__ + thrust::tuple + smem_tuple(T0* t0, T1* t1, T2* t2, T3* t3, T4* t4) + { + return thrust::make_tuple((volatile T0*) t0, (volatile T1*) t1, (volatile T2*) t2, (volatile T3*) t3, (volatile T4*) t4); + } + + template + __device__ __forceinline__ + thrust::tuple + smem_tuple(T0* t0, T1* t1, T2* t2, T3* t3, T4* t4, T5* t5) + { + return thrust::make_tuple((volatile T0*) t0, (volatile T1*) t1, (volatile T2*) t2, (volatile T3*) t3, (volatile T4*) t4, (volatile T5*) t5); + } + + template + __device__ __forceinline__ + thrust::tuple + smem_tuple(T0* t0, T1* t1, T2* t2, T3* t3, T4* t4, T5* t5, T6* t6) + { + return thrust::make_tuple((volatile T0*) t0, (volatile T1*) t1, (volatile T2*) t2, (volatile T3*) t3, (volatile T4*) t4, (volatile T5*) t5, (volatile T6*) t6); + } + + template + __device__ __forceinline__ + thrust::tuple + smem_tuple(T0* t0, T1* t1, T2* t2, T3* t3, T4* t4, T5* t5, T6* t6, T7* t7) + { + return thrust::make_tuple((volatile T0*) t0, (volatile T1*) t1, (volatile T2*) t2, (volatile T3*) t3, (volatile T4*) t4, (volatile T5*) t5, (volatile T6*) t6, (volatile T7*) t7); + } + + template + __device__ __forceinline__ + thrust::tuple + smem_tuple(T0* t0, T1* t1, T2* t2, T3* t3, T4* t4, T5* t5, T6* t6, T7* t7, T8* t8) + { + return thrust::make_tuple((volatile T0*) t0, (volatile T1*) t1, (volatile T2*) t2, (volatile T3*) t3, (volatile T4*) t4, (volatile T5*) t5, (volatile T6*) t6, (volatile T7*) t7, (volatile T8*) t8); + } + + template + __device__ __forceinline__ + thrust::tuple + smem_tuple(T0* t0, T1* t1, T2* t2, T3* t3, T4* t4, T5* t5, T6* t6, T7* t7, T8* t8, T9* t9) + { + return thrust::make_tuple((volatile T0*) t0, (volatile T1*) t1, (volatile T2*) t2, (volatile T3*) t3, (volatile T4*) t4, (volatile T5*) t5, (volatile T6*) t6, (volatile T7*) t7, (volatile T8*) t8, (volatile T9*) t9); + } +}}} + +//! @endcond + +#endif // OPENCV_CUDA_REDUCE_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/saturate_cast.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/saturate_cast.hpp new file mode 100644 index 0000000..c3a3d1c --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/saturate_cast.hpp @@ -0,0 +1,292 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_SATURATE_CAST_HPP +#define OPENCV_CUDA_SATURATE_CAST_HPP + +#include "common.hpp" + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + template __device__ __forceinline__ _Tp saturate_cast(uchar v) { return _Tp(v); } + template __device__ __forceinline__ _Tp saturate_cast(schar v) { return _Tp(v); } + template __device__ __forceinline__ _Tp saturate_cast(ushort v) { return _Tp(v); } + template __device__ __forceinline__ _Tp saturate_cast(short v) { return _Tp(v); } + template __device__ __forceinline__ _Tp saturate_cast(uint v) { return _Tp(v); } + template __device__ __forceinline__ _Tp saturate_cast(int v) { return _Tp(v); } + template __device__ __forceinline__ _Tp saturate_cast(float v) { return _Tp(v); } + template __device__ __forceinline__ _Tp saturate_cast(double v) { return _Tp(v); } + + template<> __device__ __forceinline__ uchar saturate_cast(schar v) + { + uint res = 0; + int vi = v; + asm("cvt.sat.u8.s8 %0, %1;" : "=r"(res) : "r"(vi)); + return res; + } + template<> __device__ __forceinline__ uchar saturate_cast(short v) + { + uint res = 0; + asm("cvt.sat.u8.s16 %0, %1;" : "=r"(res) : "h"(v)); + return res; + } + template<> __device__ __forceinline__ uchar saturate_cast(ushort v) + { + uint res = 0; + asm("cvt.sat.u8.u16 %0, %1;" : "=r"(res) : "h"(v)); + return res; + } + template<> __device__ __forceinline__ uchar saturate_cast(int v) + { + uint res = 0; + asm("cvt.sat.u8.s32 %0, %1;" : "=r"(res) : "r"(v)); + return res; + } + template<> __device__ __forceinline__ uchar saturate_cast(uint v) + { + uint res = 0; + asm("cvt.sat.u8.u32 %0, %1;" : "=r"(res) : "r"(v)); + return res; + } + template<> __device__ __forceinline__ uchar saturate_cast(float v) + { + uint res = 0; + asm("cvt.rni.sat.u8.f32 %0, %1;" : "=r"(res) : "f"(v)); + return res; + } + template<> __device__ __forceinline__ uchar saturate_cast(double v) + { + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 130 + uint res = 0; + asm("cvt.rni.sat.u8.f64 %0, %1;" : "=r"(res) : "d"(v)); + return res; + #else + return saturate_cast((float)v); + #endif + } + + template<> __device__ __forceinline__ schar saturate_cast(uchar v) + { + uint res = 0; + uint vi = v; + asm("cvt.sat.s8.u8 %0, %1;" : "=r"(res) : "r"(vi)); + return res; + } + template<> __device__ __forceinline__ schar saturate_cast(short v) + { + uint res = 0; + asm("cvt.sat.s8.s16 %0, %1;" : "=r"(res) : "h"(v)); + return res; + } + template<> __device__ __forceinline__ schar saturate_cast(ushort v) + { + uint res = 0; + asm("cvt.sat.s8.u16 %0, %1;" : "=r"(res) : "h"(v)); + return res; + } + template<> __device__ __forceinline__ schar saturate_cast(int v) + { + uint res = 0; + asm("cvt.sat.s8.s32 %0, %1;" : "=r"(res) : "r"(v)); + return res; + } + template<> __device__ __forceinline__ schar saturate_cast(uint v) + { + uint res = 0; + asm("cvt.sat.s8.u32 %0, %1;" : "=r"(res) : "r"(v)); + return res; + } + template<> __device__ __forceinline__ schar saturate_cast(float v) + { + uint res = 0; + asm("cvt.rni.sat.s8.f32 %0, %1;" : "=r"(res) : "f"(v)); + return res; + } + template<> __device__ __forceinline__ schar saturate_cast(double v) + { + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 130 + uint res = 0; + asm("cvt.rni.sat.s8.f64 %0, %1;" : "=r"(res) : "d"(v)); + return res; + #else + return saturate_cast((float)v); + #endif + } + + template<> __device__ __forceinline__ ushort saturate_cast(schar v) + { + ushort res = 0; + int vi = v; + asm("cvt.sat.u16.s8 %0, %1;" : "=h"(res) : "r"(vi)); + return res; + } + template<> __device__ __forceinline__ ushort saturate_cast(short v) + { + ushort res = 0; + asm("cvt.sat.u16.s16 %0, %1;" : "=h"(res) : "h"(v)); + return res; + } + template<> __device__ __forceinline__ ushort saturate_cast(int v) + { + ushort res = 0; + asm("cvt.sat.u16.s32 %0, %1;" : "=h"(res) : "r"(v)); + return res; + } + template<> __device__ __forceinline__ ushort saturate_cast(uint v) + { + ushort res = 0; + asm("cvt.sat.u16.u32 %0, %1;" : "=h"(res) : "r"(v)); + return res; + } + template<> __device__ __forceinline__ ushort saturate_cast(float v) + { + ushort res = 0; + asm("cvt.rni.sat.u16.f32 %0, %1;" : "=h"(res) : "f"(v)); + return res; + } + template<> __device__ __forceinline__ ushort saturate_cast(double v) + { + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 130 + ushort res = 0; + asm("cvt.rni.sat.u16.f64 %0, %1;" : "=h"(res) : "d"(v)); + return res; + #else + return saturate_cast((float)v); + #endif + } + + template<> __device__ __forceinline__ short saturate_cast(ushort v) + { + short res = 0; + asm("cvt.sat.s16.u16 %0, %1;" : "=h"(res) : "h"(v)); + return res; + } + template<> __device__ __forceinline__ short saturate_cast(int v) + { + short res = 0; + asm("cvt.sat.s16.s32 %0, %1;" : "=h"(res) : "r"(v)); + return res; + } + template<> __device__ __forceinline__ short saturate_cast(uint v) + { + short res = 0; + asm("cvt.sat.s16.u32 %0, %1;" : "=h"(res) : "r"(v)); + return res; + } + template<> __device__ __forceinline__ short saturate_cast(float v) + { + short res = 0; + asm("cvt.rni.sat.s16.f32 %0, %1;" : "=h"(res) : "f"(v)); + return res; + } + template<> __device__ __forceinline__ short saturate_cast(double v) + { + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 130 + short res = 0; + asm("cvt.rni.sat.s16.f64 %0, %1;" : "=h"(res) : "d"(v)); + return res; + #else + return saturate_cast((float)v); + #endif + } + + template<> __device__ __forceinline__ int saturate_cast(uint v) + { + int res = 0; + asm("cvt.sat.s32.u32 %0, %1;" : "=r"(res) : "r"(v)); + return res; + } + template<> __device__ __forceinline__ int saturate_cast(float v) + { + return __float2int_rn(v); + } + template<> __device__ __forceinline__ int saturate_cast(double v) + { + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 130 + return __double2int_rn(v); + #else + return saturate_cast((float)v); + #endif + } + + template<> __device__ __forceinline__ uint saturate_cast(schar v) + { + uint res = 0; + int vi = v; + asm("cvt.sat.u32.s8 %0, %1;" : "=r"(res) : "r"(vi)); + return res; + } + template<> __device__ __forceinline__ uint saturate_cast(short v) + { + uint res = 0; + asm("cvt.sat.u32.s16 %0, %1;" : "=r"(res) : "h"(v)); + return res; + } + template<> __device__ __forceinline__ uint saturate_cast(int v) + { + uint res = 0; + asm("cvt.sat.u32.s32 %0, %1;" : "=r"(res) : "r"(v)); + return res; + } + template<> __device__ __forceinline__ uint saturate_cast(float v) + { + return __float2uint_rn(v); + } + template<> __device__ __forceinline__ uint saturate_cast(double v) + { + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 130 + return __double2uint_rn(v); + #else + return saturate_cast((float)v); + #endif + } +}}} + +//! @endcond + +#endif /* OPENCV_CUDA_SATURATE_CAST_HPP */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/scan.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/scan.hpp new file mode 100644 index 0000000..e128fb0 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/scan.hpp @@ -0,0 +1,258 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_SCAN_HPP +#define OPENCV_CUDA_SCAN_HPP + +#include "opencv2/core/cuda/common.hpp" +#include "opencv2/core/cuda/utility.hpp" +#include "opencv2/core/cuda/warp.hpp" +#include "opencv2/core/cuda/warp_shuffle.hpp" + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + enum ScanKind { EXCLUSIVE = 0, INCLUSIVE = 1 }; + + template struct WarpScan + { + __device__ __forceinline__ WarpScan() {} + __device__ __forceinline__ WarpScan(const WarpScan& other) { CV_UNUSED(other); } + + __device__ __forceinline__ T operator()( volatile T *ptr , const unsigned int idx) + { + const unsigned int lane = idx & 31; + F op; + + if ( lane >= 1) ptr [idx ] = op(ptr [idx - 1], ptr [idx]); + if ( lane >= 2) ptr [idx ] = op(ptr [idx - 2], ptr [idx]); + if ( lane >= 4) ptr [idx ] = op(ptr [idx - 4], ptr [idx]); + if ( lane >= 8) ptr [idx ] = op(ptr [idx - 8], ptr [idx]); + if ( lane >= 16) ptr [idx ] = op(ptr [idx - 16], ptr [idx]); + + if( Kind == INCLUSIVE ) + return ptr [idx]; + else + return (lane > 0) ? ptr [idx - 1] : 0; + } + + __device__ __forceinline__ unsigned int index(const unsigned int tid) + { + return tid; + } + + __device__ __forceinline__ void init(volatile T *ptr){} + + static const int warp_offset = 0; + + typedef WarpScan merge; + }; + + template struct WarpScanNoComp + { + __device__ __forceinline__ WarpScanNoComp() {} + __device__ __forceinline__ WarpScanNoComp(const WarpScanNoComp& other) { CV_UNUSED(other); } + + __device__ __forceinline__ T operator()( volatile T *ptr , const unsigned int idx) + { + const unsigned int lane = threadIdx.x & 31; + F op; + + ptr [idx ] = op(ptr [idx - 1], ptr [idx]); + ptr [idx ] = op(ptr [idx - 2], ptr [idx]); + ptr [idx ] = op(ptr [idx - 4], ptr [idx]); + ptr [idx ] = op(ptr [idx - 8], ptr [idx]); + ptr [idx ] = op(ptr [idx - 16], ptr [idx]); + + if( Kind == INCLUSIVE ) + return ptr [idx]; + else + return (lane > 0) ? ptr [idx - 1] : 0; + } + + __device__ __forceinline__ unsigned int index(const unsigned int tid) + { + return (tid >> warp_log) * warp_smem_stride + 16 + (tid & warp_mask); + } + + __device__ __forceinline__ void init(volatile T *ptr) + { + ptr[threadIdx.x] = 0; + } + + static const int warp_smem_stride = 32 + 16 + 1; + static const int warp_offset = 16; + static const int warp_log = 5; + static const int warp_mask = 31; + + typedef WarpScanNoComp merge; + }; + + template struct BlockScan + { + __device__ __forceinline__ BlockScan() {} + __device__ __forceinline__ BlockScan(const BlockScan& other) { CV_UNUSED(other); } + + __device__ __forceinline__ T operator()(volatile T *ptr) + { + const unsigned int tid = threadIdx.x; + const unsigned int lane = tid & warp_mask; + const unsigned int warp = tid >> warp_log; + + Sc scan; + typename Sc::merge merge_scan; + const unsigned int idx = scan.index(tid); + + T val = scan(ptr, idx); + __syncthreads (); + + if( warp == 0) + scan.init(ptr); + __syncthreads (); + + if( lane == 31 ) + ptr [scan.warp_offset + warp ] = (Kind == INCLUSIVE) ? val : ptr [idx]; + __syncthreads (); + + if( warp == 0 ) + merge_scan(ptr, idx); + __syncthreads(); + + if ( warp > 0) + val = ptr [scan.warp_offset + warp - 1] + val; + __syncthreads (); + + ptr[idx] = val; + __syncthreads (); + + return val ; + } + + static const int warp_log = 5; + static const int warp_mask = 31; + }; + + template + __device__ T warpScanInclusive(T idata, volatile T* s_Data, unsigned int tid) + { + #if __CUDA_ARCH__ >= 300 + const unsigned int laneId = cv::cuda::device::Warp::laneId(); + + // scan on shuffl functions + #pragma unroll + for (int i = 1; i <= (OPENCV_CUDA_WARP_SIZE / 2); i *= 2) + { + const T n = cv::cuda::device::shfl_up(idata, i); + if (laneId >= i) + idata += n; + } + + return idata; + #else + unsigned int pos = 2 * tid - (tid & (OPENCV_CUDA_WARP_SIZE - 1)); + s_Data[pos] = 0; + pos += OPENCV_CUDA_WARP_SIZE; + s_Data[pos] = idata; + + s_Data[pos] += s_Data[pos - 1]; + s_Data[pos] += s_Data[pos - 2]; + s_Data[pos] += s_Data[pos - 4]; + s_Data[pos] += s_Data[pos - 8]; + s_Data[pos] += s_Data[pos - 16]; + + return s_Data[pos]; + #endif + } + + template + __device__ __forceinline__ T warpScanExclusive(T idata, volatile T* s_Data, unsigned int tid) + { + return warpScanInclusive(idata, s_Data, tid) - idata; + } + + template + __device__ T blockScanInclusive(T idata, volatile T* s_Data, unsigned int tid) + { + if (tiNumScanThreads > OPENCV_CUDA_WARP_SIZE) + { + //Bottom-level inclusive warp scan + T warpResult = warpScanInclusive(idata, s_Data, tid); + + //Save top elements of each warp for exclusive warp scan + //sync to wait for warp scans to complete (because s_Data is being overwritten) + __syncthreads(); + if ((tid & (OPENCV_CUDA_WARP_SIZE - 1)) == (OPENCV_CUDA_WARP_SIZE - 1)) + { + s_Data[tid >> OPENCV_CUDA_LOG_WARP_SIZE] = warpResult; + } + + //wait for warp scans to complete + __syncthreads(); + + if (tid < (tiNumScanThreads / OPENCV_CUDA_WARP_SIZE) ) + { + //grab top warp elements + T val = s_Data[tid]; + //calculate exclusive scan and write back to shared memory + s_Data[tid] = warpScanExclusive(val, s_Data, tid); + } + + //return updated warp scans with exclusive scan results + __syncthreads(); + + return warpResult + s_Data[tid >> OPENCV_CUDA_LOG_WARP_SIZE]; + } + else + { + return warpScanInclusive(idata, s_Data, tid); + } + } +}}} + +//! @endcond + +#endif // OPENCV_CUDA_SCAN_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/simd_functions.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/simd_functions.hpp new file mode 100644 index 0000000..3d8c2e0 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/simd_functions.hpp @@ -0,0 +1,869 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +/* + * Copyright (c) 2013 NVIDIA Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted 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 NVIDIA Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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. + */ + +#ifndef OPENCV_CUDA_SIMD_FUNCTIONS_HPP +#define OPENCV_CUDA_SIMD_FUNCTIONS_HPP + +#include "common.hpp" + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + // 2 + + static __device__ __forceinline__ unsigned int vadd2(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vadd2.u32.u32.u32.sat %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #elif __CUDA_ARCH__ >= 200 + asm("vadd.u32.u32.u32.sat %0.h0, %1.h0, %2.h0, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + asm("vadd.u32.u32.u32.sat %0.h1, %1.h1, %2.h1, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + unsigned int s; + s = a ^ b; // sum bits + r = a + b; // actual sum + s = s ^ r; // determine carry-ins for each bit position + s = s & 0x00010000; // carry-in to high word (= carry-out from low word) + r = r - s; // subtract out carry-out from low word + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vsub2(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vsub2.u32.u32.u32.sat %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #elif __CUDA_ARCH__ >= 200 + asm("vsub.u32.u32.u32.sat %0.h0, %1.h0, %2.h0, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + asm("vsub.u32.u32.u32.sat %0.h1, %1.h1, %2.h1, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + unsigned int s; + s = a ^ b; // sum bits + r = a - b; // actual sum + s = s ^ r; // determine carry-ins for each bit position + s = s & 0x00010000; // borrow to high word + r = r + s; // compensate for borrow from low word + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vabsdiff2(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vabsdiff2.u32.u32.u32.sat %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #elif __CUDA_ARCH__ >= 200 + asm("vabsdiff.u32.u32.u32.sat %0.h0, %1.h0, %2.h0, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + asm("vabsdiff.u32.u32.u32.sat %0.h1, %1.h1, %2.h1, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + unsigned int s, t, u, v; + s = a & 0x0000ffff; // extract low halfword + r = b & 0x0000ffff; // extract low halfword + u = ::max(r, s); // maximum of low halfwords + v = ::min(r, s); // minimum of low halfwords + s = a & 0xffff0000; // extract high halfword + r = b & 0xffff0000; // extract high halfword + t = ::max(r, s); // maximum of high halfwords + s = ::min(r, s); // minimum of high halfwords + r = u | t; // maximum of both halfwords + s = v | s; // minimum of both halfwords + r = r - s; // |a - b| = max(a,b) - min(a,b); + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vavg2(unsigned int a, unsigned int b) + { + unsigned int r, s; + + // HAKMEM #23: a + b = 2 * (a & b) + (a ^ b) ==> + // (a + b) / 2 = (a & b) + ((a ^ b) >> 1) + s = a ^ b; + r = a & b; + s = s & 0xfffefffe; // ensure shift doesn't cross halfword boundaries + s = s >> 1; + s = r + s; + + return s; + } + + static __device__ __forceinline__ unsigned int vavrg2(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vavrg2.u32.u32.u32 %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + // HAKMEM #23: a + b = 2 * (a | b) - (a ^ b) ==> + // (a + b + 1) / 2 = (a | b) - ((a ^ b) >> 1) + unsigned int s; + s = a ^ b; + r = a | b; + s = s & 0xfffefffe; // ensure shift doesn't cross half-word boundaries + s = s >> 1; + r = r - s; + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vseteq2(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vset2.u32.u32.eq %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + // inspired by Alan Mycroft's null-byte detection algorithm: + // null_byte(x) = ((x - 0x01010101) & (~x & 0x80808080)) + unsigned int c; + r = a ^ b; // 0x0000 if a == b + c = r | 0x80008000; // set msbs, to catch carry out + r = r ^ c; // extract msbs, msb = 1 if r < 0x8000 + c = c - 0x00010001; // msb = 0, if r was 0x0000 or 0x8000 + c = r & ~c; // msb = 1, if r was 0x0000 + r = c >> 15; // convert to bool + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vcmpeq2(unsigned int a, unsigned int b) + { + unsigned int r, c; + + #if __CUDA_ARCH__ >= 300 + r = vseteq2(a, b); + c = r << 16; // convert bool + r = c - r; // into mask + #else + // inspired by Alan Mycroft's null-byte detection algorithm: + // null_byte(x) = ((x - 0x01010101) & (~x & 0x80808080)) + r = a ^ b; // 0x0000 if a == b + c = r | 0x80008000; // set msbs, to catch carry out + r = r ^ c; // extract msbs, msb = 1 if r < 0x8000 + c = c - 0x00010001; // msb = 0, if r was 0x0000 or 0x8000 + c = r & ~c; // msb = 1, if r was 0x0000 + r = c >> 15; // convert + r = c - r; // msbs to + r = c | r; // mask + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vsetge2(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vset2.u32.u32.ge %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + unsigned int c; + asm("not.b32 %0, %0;" : "+r"(b)); + c = vavrg2(a, b); // (a + ~b + 1) / 2 = (a - b) / 2 + c = c & 0x80008000; // msb = carry-outs + r = c >> 15; // convert to bool + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vcmpge2(unsigned int a, unsigned int b) + { + unsigned int r, c; + + #if __CUDA_ARCH__ >= 300 + r = vsetge2(a, b); + c = r << 16; // convert bool + r = c - r; // into mask + #else + asm("not.b32 %0, %0;" : "+r"(b)); + c = vavrg2(a, b); // (a + ~b + 1) / 2 = (a - b) / 2 + c = c & 0x80008000; // msb = carry-outs + r = c >> 15; // convert + r = c - r; // msbs to + r = c | r; // mask + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vsetgt2(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vset2.u32.u32.gt %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + unsigned int c; + asm("not.b32 %0, %0;" : "+r"(b)); + c = vavg2(a, b); // (a + ~b) / 2 = (a - b) / 2 [rounded down] + c = c & 0x80008000; // msbs = carry-outs + r = c >> 15; // convert to bool + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vcmpgt2(unsigned int a, unsigned int b) + { + unsigned int r, c; + + #if __CUDA_ARCH__ >= 300 + r = vsetgt2(a, b); + c = r << 16; // convert bool + r = c - r; // into mask + #else + asm("not.b32 %0, %0;" : "+r"(b)); + c = vavg2(a, b); // (a + ~b) / 2 = (a - b) / 2 [rounded down] + c = c & 0x80008000; // msbs = carry-outs + r = c >> 15; // convert + r = c - r; // msbs to + r = c | r; // mask + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vsetle2(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vset2.u32.u32.le %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + unsigned int c; + asm("not.b32 %0, %0;" : "+r"(a)); + c = vavrg2(a, b); // (b + ~a + 1) / 2 = (b - a) / 2 + c = c & 0x80008000; // msb = carry-outs + r = c >> 15; // convert to bool + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vcmple2(unsigned int a, unsigned int b) + { + unsigned int r, c; + + #if __CUDA_ARCH__ >= 300 + r = vsetle2(a, b); + c = r << 16; // convert bool + r = c - r; // into mask + #else + asm("not.b32 %0, %0;" : "+r"(a)); + c = vavrg2(a, b); // (b + ~a + 1) / 2 = (b - a) / 2 + c = c & 0x80008000; // msb = carry-outs + r = c >> 15; // convert + r = c - r; // msbs to + r = c | r; // mask + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vsetlt2(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vset2.u32.u32.lt %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + unsigned int c; + asm("not.b32 %0, %0;" : "+r"(a)); + c = vavg2(a, b); // (b + ~a) / 2 = (b - a) / 2 [rounded down] + c = c & 0x80008000; // msb = carry-outs + r = c >> 15; // convert to bool + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vcmplt2(unsigned int a, unsigned int b) + { + unsigned int r, c; + + #if __CUDA_ARCH__ >= 300 + r = vsetlt2(a, b); + c = r << 16; // convert bool + r = c - r; // into mask + #else + asm("not.b32 %0, %0;" : "+r"(a)); + c = vavg2(a, b); // (b + ~a) / 2 = (b - a) / 2 [rounded down] + c = c & 0x80008000; // msb = carry-outs + r = c >> 15; // convert + r = c - r; // msbs to + r = c | r; // mask + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vsetne2(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm ("vset2.u32.u32.ne %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + // inspired by Alan Mycroft's null-byte detection algorithm: + // null_byte(x) = ((x - 0x01010101) & (~x & 0x80808080)) + unsigned int c; + r = a ^ b; // 0x0000 if a == b + c = r | 0x80008000; // set msbs, to catch carry out + c = c - 0x00010001; // msb = 0, if r was 0x0000 or 0x8000 + c = r | c; // msb = 1, if r was not 0x0000 + c = c & 0x80008000; // extract msbs + r = c >> 15; // convert to bool + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vcmpne2(unsigned int a, unsigned int b) + { + unsigned int r, c; + + #if __CUDA_ARCH__ >= 300 + r = vsetne2(a, b); + c = r << 16; // convert bool + r = c - r; // into mask + #else + // inspired by Alan Mycroft's null-byte detection algorithm: + // null_byte(x) = ((x - 0x01010101) & (~x & 0x80808080)) + r = a ^ b; // 0x0000 if a == b + c = r | 0x80008000; // set msbs, to catch carry out + c = c - 0x00010001; // msb = 0, if r was 0x0000 or 0x8000 + c = r | c; // msb = 1, if r was not 0x0000 + c = c & 0x80008000; // extract msbs + r = c >> 15; // convert + r = c - r; // msbs to + r = c | r; // mask + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vmax2(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vmax2.u32.u32.u32 %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #elif __CUDA_ARCH__ >= 200 + asm("vmax.u32.u32.u32 %0.h0, %1.h0, %2.h0, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + asm("vmax.u32.u32.u32 %0.h1, %1.h1, %2.h1, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + unsigned int s, t, u; + r = a & 0x0000ffff; // extract low halfword + s = b & 0x0000ffff; // extract low halfword + t = ::max(r, s); // maximum of low halfwords + r = a & 0xffff0000; // extract high halfword + s = b & 0xffff0000; // extract high halfword + u = ::max(r, s); // maximum of high halfwords + r = t | u; // combine halfword maximums + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vmin2(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vmin2.u32.u32.u32 %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #elif __CUDA_ARCH__ >= 200 + asm("vmin.u32.u32.u32 %0.h0, %1.h0, %2.h0, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + asm("vmin.u32.u32.u32 %0.h1, %1.h1, %2.h1, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + unsigned int s, t, u; + r = a & 0x0000ffff; // extract low halfword + s = b & 0x0000ffff; // extract low halfword + t = ::min(r, s); // minimum of low halfwords + r = a & 0xffff0000; // extract high halfword + s = b & 0xffff0000; // extract high halfword + u = ::min(r, s); // minimum of high halfwords + r = t | u; // combine halfword minimums + #endif + + return r; + } + + // 4 + + static __device__ __forceinline__ unsigned int vadd4(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vadd4.u32.u32.u32.sat %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #elif __CUDA_ARCH__ >= 200 + asm("vadd.u32.u32.u32.sat %0.b0, %1.b0, %2.b0, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + asm("vadd.u32.u32.u32.sat %0.b1, %1.b1, %2.b1, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + asm("vadd.u32.u32.u32.sat %0.b2, %1.b2, %2.b2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + asm("vadd.u32.u32.u32.sat %0.b3, %1.b3, %2.b3, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + unsigned int s, t; + s = a ^ b; // sum bits + r = a & 0x7f7f7f7f; // clear msbs + t = b & 0x7f7f7f7f; // clear msbs + s = s & 0x80808080; // msb sum bits + r = r + t; // add without msbs, record carry-out in msbs + r = r ^ s; // sum of msb sum and carry-in bits, w/o carry-out + #endif /* __CUDA_ARCH__ >= 300 */ + + return r; + } + + static __device__ __forceinline__ unsigned int vsub4(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vsub4.u32.u32.u32.sat %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #elif __CUDA_ARCH__ >= 200 + asm("vsub.u32.u32.u32.sat %0.b0, %1.b0, %2.b0, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + asm("vsub.u32.u32.u32.sat %0.b1, %1.b1, %2.b1, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + asm("vsub.u32.u32.u32.sat %0.b2, %1.b2, %2.b2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + asm("vsub.u32.u32.u32.sat %0.b3, %1.b3, %2.b3, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + unsigned int s, t; + s = a ^ ~b; // inverted sum bits + r = a | 0x80808080; // set msbs + t = b & 0x7f7f7f7f; // clear msbs + s = s & 0x80808080; // inverted msb sum bits + r = r - t; // subtract w/o msbs, record inverted borrows in msb + r = r ^ s; // combine inverted msb sum bits and borrows + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vavg4(unsigned int a, unsigned int b) + { + unsigned int r, s; + + // HAKMEM #23: a + b = 2 * (a & b) + (a ^ b) ==> + // (a + b) / 2 = (a & b) + ((a ^ b) >> 1) + s = a ^ b; + r = a & b; + s = s & 0xfefefefe; // ensure following shift doesn't cross byte boundaries + s = s >> 1; + s = r + s; + + return s; + } + + static __device__ __forceinline__ unsigned int vavrg4(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vavrg4.u32.u32.u32 %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + // HAKMEM #23: a + b = 2 * (a | b) - (a ^ b) ==> + // (a + b + 1) / 2 = (a | b) - ((a ^ b) >> 1) + unsigned int c; + c = a ^ b; + r = a | b; + c = c & 0xfefefefe; // ensure following shift doesn't cross byte boundaries + c = c >> 1; + r = r - c; + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vseteq4(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vset4.u32.u32.eq %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + // inspired by Alan Mycroft's null-byte detection algorithm: + // null_byte(x) = ((x - 0x01010101) & (~x & 0x80808080)) + unsigned int c; + r = a ^ b; // 0x00 if a == b + c = r | 0x80808080; // set msbs, to catch carry out + r = r ^ c; // extract msbs, msb = 1 if r < 0x80 + c = c - 0x01010101; // msb = 0, if r was 0x00 or 0x80 + c = r & ~c; // msb = 1, if r was 0x00 + r = c >> 7; // convert to bool + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vcmpeq4(unsigned int a, unsigned int b) + { + unsigned int r, t; + + #if __CUDA_ARCH__ >= 300 + r = vseteq4(a, b); + t = r << 8; // convert bool + r = t - r; // to mask + #else + // inspired by Alan Mycroft's null-byte detection algorithm: + // null_byte(x) = ((x - 0x01010101) & (~x & 0x80808080)) + t = a ^ b; // 0x00 if a == b + r = t | 0x80808080; // set msbs, to catch carry out + t = t ^ r; // extract msbs, msb = 1 if t < 0x80 + r = r - 0x01010101; // msb = 0, if t was 0x00 or 0x80 + r = t & ~r; // msb = 1, if t was 0x00 + t = r >> 7; // build mask + t = r - t; // from + r = t | r; // msbs + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vsetle4(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vset4.u32.u32.le %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + unsigned int c; + asm("not.b32 %0, %0;" : "+r"(a)); + c = vavrg4(a, b); // (b + ~a + 1) / 2 = (b - a) / 2 + c = c & 0x80808080; // msb = carry-outs + r = c >> 7; // convert to bool + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vcmple4(unsigned int a, unsigned int b) + { + unsigned int r, c; + + #if __CUDA_ARCH__ >= 300 + r = vsetle4(a, b); + c = r << 8; // convert bool + r = c - r; // to mask + #else + asm("not.b32 %0, %0;" : "+r"(a)); + c = vavrg4(a, b); // (b + ~a + 1) / 2 = (b - a) / 2 + c = c & 0x80808080; // msbs = carry-outs + r = c >> 7; // convert + r = c - r; // msbs to + r = c | r; // mask + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vsetlt4(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vset4.u32.u32.lt %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + unsigned int c; + asm("not.b32 %0, %0;" : "+r"(a)); + c = vavg4(a, b); // (b + ~a) / 2 = (b - a) / 2 [rounded down] + c = c & 0x80808080; // msb = carry-outs + r = c >> 7; // convert to bool + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vcmplt4(unsigned int a, unsigned int b) + { + unsigned int r, c; + + #if __CUDA_ARCH__ >= 300 + r = vsetlt4(a, b); + c = r << 8; // convert bool + r = c - r; // to mask + #else + asm("not.b32 %0, %0;" : "+r"(a)); + c = vavg4(a, b); // (b + ~a) / 2 = (b - a) / 2 [rounded down] + c = c & 0x80808080; // msbs = carry-outs + r = c >> 7; // convert + r = c - r; // msbs to + r = c | r; // mask + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vsetge4(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vset4.u32.u32.ge %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + unsigned int c; + asm("not.b32 %0, %0;" : "+r"(b)); + c = vavrg4(a, b); // (a + ~b + 1) / 2 = (a - b) / 2 + c = c & 0x80808080; // msb = carry-outs + r = c >> 7; // convert to bool + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vcmpge4(unsigned int a, unsigned int b) + { + unsigned int r, s; + + #if __CUDA_ARCH__ >= 300 + r = vsetge4(a, b); + s = r << 8; // convert bool + r = s - r; // to mask + #else + asm ("not.b32 %0,%0;" : "+r"(b)); + r = vavrg4 (a, b); // (a + ~b + 1) / 2 = (a - b) / 2 + r = r & 0x80808080; // msb = carry-outs + s = r >> 7; // build mask + s = r - s; // from + r = s | r; // msbs + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vsetgt4(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vset4.u32.u32.gt %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + unsigned int c; + asm("not.b32 %0, %0;" : "+r"(b)); + c = vavg4(a, b); // (a + ~b) / 2 = (a - b) / 2 [rounded down] + c = c & 0x80808080; // msb = carry-outs + r = c >> 7; // convert to bool + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vcmpgt4(unsigned int a, unsigned int b) + { + unsigned int r, c; + + #if __CUDA_ARCH__ >= 300 + r = vsetgt4(a, b); + c = r << 8; // convert bool + r = c - r; // to mask + #else + asm("not.b32 %0, %0;" : "+r"(b)); + c = vavg4(a, b); // (a + ~b) / 2 = (a - b) / 2 [rounded down] + c = c & 0x80808080; // msb = carry-outs + r = c >> 7; // convert + r = c - r; // msbs to + r = c | r; // mask + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vsetne4(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vset4.u32.u32.ne %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + // inspired by Alan Mycroft's null-byte detection algorithm: + // null_byte(x) = ((x - 0x01010101) & (~x & 0x80808080)) + unsigned int c; + r = a ^ b; // 0x00 if a == b + c = r | 0x80808080; // set msbs, to catch carry out + c = c - 0x01010101; // msb = 0, if r was 0x00 or 0x80 + c = r | c; // msb = 1, if r was not 0x00 + c = c & 0x80808080; // extract msbs + r = c >> 7; // convert to bool + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vcmpne4(unsigned int a, unsigned int b) + { + unsigned int r, c; + + #if __CUDA_ARCH__ >= 300 + r = vsetne4(a, b); + c = r << 8; // convert bool + r = c - r; // to mask + #else + // inspired by Alan Mycroft's null-byte detection algorithm: + // null_byte(x) = ((x - 0x01010101) & (~x & 0x80808080)) + r = a ^ b; // 0x00 if a == b + c = r | 0x80808080; // set msbs, to catch carry out + c = c - 0x01010101; // msb = 0, if r was 0x00 or 0x80 + c = r | c; // msb = 1, if r was not 0x00 + c = c & 0x80808080; // extract msbs + r = c >> 7; // convert + r = c - r; // msbs to + r = c | r; // mask + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vabsdiff4(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vabsdiff4.u32.u32.u32.sat %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #elif __CUDA_ARCH__ >= 200 + asm("vabsdiff.u32.u32.u32.sat %0.b0, %1.b0, %2.b0, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + asm("vabsdiff.u32.u32.u32.sat %0.b1, %1.b1, %2.b1, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + asm("vabsdiff.u32.u32.u32.sat %0.b2, %1.b2, %2.b2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + asm("vabsdiff.u32.u32.u32.sat %0.b3, %1.b3, %2.b3, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + unsigned int s; + s = vcmpge4(a, b); // mask = 0xff if a >= b + r = a ^ b; // + s = (r & s) ^ b; // select a when a >= b, else select b => max(a,b) + r = s ^ r; // select a when b >= a, else select b => min(a,b) + r = s - r; // |a - b| = max(a,b) - min(a,b); + #endif + + return r; + } + + static __device__ __forceinline__ unsigned int vmax4(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vmax4.u32.u32.u32 %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #elif __CUDA_ARCH__ >= 200 + asm("vmax.u32.u32.u32 %0.b0, %1.b0, %2.b0, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + asm("vmax.u32.u32.u32 %0.b1, %1.b1, %2.b1, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + asm("vmax.u32.u32.u32 %0.b2, %1.b2, %2.b2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + asm("vmax.u32.u32.u32 %0.b3, %1.b3, %2.b3, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + unsigned int s; + s = vcmpge4(a, b); // mask = 0xff if a >= b + r = a & s; // select a when b >= a + s = b & ~s; // select b when b < a + r = r | s; // combine byte selections + #endif + + return r; // byte-wise unsigned maximum + } + + static __device__ __forceinline__ unsigned int vmin4(unsigned int a, unsigned int b) + { + unsigned int r = 0; + + #if __CUDA_ARCH__ >= 300 + asm("vmin4.u32.u32.u32 %0, %1, %2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #elif __CUDA_ARCH__ >= 200 + asm("vmin.u32.u32.u32 %0.b0, %1.b0, %2.b0, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + asm("vmin.u32.u32.u32 %0.b1, %1.b1, %2.b1, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + asm("vmin.u32.u32.u32 %0.b2, %1.b2, %2.b2, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + asm("vmin.u32.u32.u32 %0.b3, %1.b3, %2.b3, %3;" : "=r"(r) : "r"(a), "r"(b), "r"(r)); + #else + unsigned int s; + s = vcmpge4(b, a); // mask = 0xff if a >= b + r = a & s; // select a when b >= a + s = b & ~s; // select b when b < a + r = r | s; // combine byte selections + #endif + + return r; + } +}}} + +//! @endcond + +#endif // OPENCV_CUDA_SIMD_FUNCTIONS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/transform.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/transform.hpp new file mode 100644 index 0000000..42aa6ea --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/transform.hpp @@ -0,0 +1,75 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_TRANSFORM_HPP +#define OPENCV_CUDA_TRANSFORM_HPP + +#include "common.hpp" +#include "utility.hpp" +#include "detail/transform_detail.hpp" + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + template + static inline void transform(PtrStepSz src, PtrStepSz dst, UnOp op, const Mask& mask, cudaStream_t stream) + { + typedef TransformFunctorTraits ft; + transform_detail::TransformDispatcher::cn == 1 && VecTraits::cn == 1 && ft::smart_shift != 1>::call(src, dst, op, mask, stream); + } + + template + static inline void transform(PtrStepSz src1, PtrStepSz src2, PtrStepSz dst, BinOp op, const Mask& mask, cudaStream_t stream) + { + typedef TransformFunctorTraits ft; + transform_detail::TransformDispatcher::cn == 1 && VecTraits::cn == 1 && VecTraits::cn == 1 && ft::smart_shift != 1>::call(src1, src2, dst, op, mask, stream); + } +}}} + +//! @endcond + +#endif // OPENCV_CUDA_TRANSFORM_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/type_traits.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/type_traits.hpp new file mode 100644 index 0000000..8b7a3fd --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/type_traits.hpp @@ -0,0 +1,90 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_TYPE_TRAITS_HPP +#define OPENCV_CUDA_TYPE_TRAITS_HPP + +#include "detail/type_traits_detail.hpp" + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + template struct IsSimpleParameter + { + enum {value = type_traits_detail::IsIntegral::value || type_traits_detail::IsFloat::value || + type_traits_detail::PointerTraits::type>::value}; + }; + + template struct TypeTraits + { + typedef typename type_traits_detail::UnConst::type NonConstType; + typedef typename type_traits_detail::UnVolatile::type NonVolatileType; + typedef typename type_traits_detail::UnVolatile::type>::type UnqualifiedType; + typedef typename type_traits_detail::PointerTraits::type PointeeType; + typedef typename type_traits_detail::ReferenceTraits::type ReferredType; + + enum { isConst = type_traits_detail::UnConst::value }; + enum { isVolatile = type_traits_detail::UnVolatile::value }; + + enum { isReference = type_traits_detail::ReferenceTraits::value }; + enum { isPointer = type_traits_detail::PointerTraits::type>::value }; + + enum { isUnsignedInt = type_traits_detail::IsUnsignedIntegral::value }; + enum { isSignedInt = type_traits_detail::IsSignedIntergral::value }; + enum { isIntegral = type_traits_detail::IsIntegral::value }; + enum { isFloat = type_traits_detail::IsFloat::value }; + enum { isArith = isIntegral || isFloat }; + enum { isVec = type_traits_detail::IsVec::value }; + + typedef typename type_traits_detail::Select::value, + T, typename type_traits_detail::AddParameterType::type>::type ParameterType; + }; +}}} + +//! @endcond + +#endif // OPENCV_CUDA_TYPE_TRAITS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/utility.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/utility.hpp new file mode 100644 index 0000000..7f5db48 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/utility.hpp @@ -0,0 +1,230 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_UTILITY_HPP +#define OPENCV_CUDA_UTILITY_HPP + +#include "saturate_cast.hpp" +#include "datamov_utils.hpp" + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + struct CV_EXPORTS ThrustAllocator + { + typedef uchar value_type; + virtual ~ThrustAllocator(); + virtual __device__ __host__ uchar* allocate(size_t numBytes) = 0; + virtual __device__ __host__ void deallocate(uchar* ptr, size_t numBytes) = 0; + static ThrustAllocator& getAllocator(); + static void setAllocator(ThrustAllocator* allocator); + }; + #define OPENCV_CUDA_LOG_WARP_SIZE (5) + #define OPENCV_CUDA_WARP_SIZE (1 << OPENCV_CUDA_LOG_WARP_SIZE) + #define OPENCV_CUDA_LOG_MEM_BANKS ((__CUDA_ARCH__ >= 200) ? 5 : 4) // 32 banks on fermi, 16 on tesla + #define OPENCV_CUDA_MEM_BANKS (1 << OPENCV_CUDA_LOG_MEM_BANKS) + + /////////////////////////////////////////////////////////////////////////////// + // swap + + template void __device__ __host__ __forceinline__ swap(T& a, T& b) + { + const T temp = a; + a = b; + b = temp; + } + + /////////////////////////////////////////////////////////////////////////////// + // Mask Reader + + struct SingleMask + { + explicit __host__ __device__ __forceinline__ SingleMask(PtrStepb mask_) : mask(mask_) {} + __host__ __device__ __forceinline__ SingleMask(const SingleMask& mask_): mask(mask_.mask){} + + __device__ __forceinline__ bool operator()(int y, int x) const + { + return mask.ptr(y)[x] != 0; + } + + PtrStepb mask; + }; + + struct SingleMaskChannels + { + __host__ __device__ __forceinline__ SingleMaskChannels(PtrStepb mask_, int channels_) + : mask(mask_), channels(channels_) {} + __host__ __device__ __forceinline__ SingleMaskChannels(const SingleMaskChannels& mask_) + :mask(mask_.mask), channels(mask_.channels){} + + __device__ __forceinline__ bool operator()(int y, int x) const + { + return mask.ptr(y)[x / channels] != 0; + } + + PtrStepb mask; + int channels; + }; + + struct MaskCollection + { + explicit __host__ __device__ __forceinline__ MaskCollection(PtrStepb* maskCollection_) + : maskCollection(maskCollection_) {} + + __device__ __forceinline__ MaskCollection(const MaskCollection& masks_) + : maskCollection(masks_.maskCollection), curMask(masks_.curMask){} + + __device__ __forceinline__ void next() + { + curMask = *maskCollection++; + } + __device__ __forceinline__ void setMask(int z) + { + curMask = maskCollection[z]; + } + + __device__ __forceinline__ bool operator()(int y, int x) const + { + uchar val; + return curMask.data == 0 || (ForceGlob::Load(curMask.ptr(y), x, val), (val != 0)); + } + + const PtrStepb* maskCollection; + PtrStepb curMask; + }; + + struct WithOutMask + { + __host__ __device__ __forceinline__ WithOutMask(){} + __host__ __device__ __forceinline__ WithOutMask(const WithOutMask&){} + + __device__ __forceinline__ void next() const + { + } + __device__ __forceinline__ void setMask(int) const + { + } + + __device__ __forceinline__ bool operator()(int, int) const + { + return true; + } + + __device__ __forceinline__ bool operator()(int, int, int) const + { + return true; + } + + static __device__ __forceinline__ bool check(int, int) + { + return true; + } + + static __device__ __forceinline__ bool check(int, int, int) + { + return true; + } + }; + + /////////////////////////////////////////////////////////////////////////////// + // Solve linear system + + // solve 2x2 linear system Ax=b + template __device__ __forceinline__ bool solve2x2(const T A[2][2], const T b[2], T x[2]) + { + T det = A[0][0] * A[1][1] - A[1][0] * A[0][1]; + + if (det != 0) + { + double invdet = 1.0 / det; + + x[0] = saturate_cast(invdet * (b[0] * A[1][1] - b[1] * A[0][1])); + + x[1] = saturate_cast(invdet * (A[0][0] * b[1] - A[1][0] * b[0])); + + return true; + } + + return false; + } + + // solve 3x3 linear system Ax=b + template __device__ __forceinline__ bool solve3x3(const T A[3][3], const T b[3], T x[3]) + { + T det = A[0][0] * (A[1][1] * A[2][2] - A[1][2] * A[2][1]) + - A[0][1] * (A[1][0] * A[2][2] - A[1][2] * A[2][0]) + + A[0][2] * (A[1][0] * A[2][1] - A[1][1] * A[2][0]); + + if (det != 0) + { + double invdet = 1.0 / det; + + x[0] = saturate_cast(invdet * + (b[0] * (A[1][1] * A[2][2] - A[1][2] * A[2][1]) - + A[0][1] * (b[1] * A[2][2] - A[1][2] * b[2] ) + + A[0][2] * (b[1] * A[2][1] - A[1][1] * b[2] ))); + + x[1] = saturate_cast(invdet * + (A[0][0] * (b[1] * A[2][2] - A[1][2] * b[2] ) - + b[0] * (A[1][0] * A[2][2] - A[1][2] * A[2][0]) + + A[0][2] * (A[1][0] * b[2] - b[1] * A[2][0]))); + + x[2] = saturate_cast(invdet * + (A[0][0] * (A[1][1] * b[2] - b[1] * A[2][1]) - + A[0][1] * (A[1][0] * b[2] - b[1] * A[2][0]) + + b[0] * (A[1][0] * A[2][1] - A[1][1] * A[2][0]))); + + return true; + } + + return false; + } +}}} // namespace cv { namespace cuda { namespace cudev + +//! @endcond + +#endif // OPENCV_CUDA_UTILITY_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/vec_distance.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/vec_distance.hpp new file mode 100644 index 0000000..ef6e510 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/vec_distance.hpp @@ -0,0 +1,232 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_VEC_DISTANCE_HPP +#define OPENCV_CUDA_VEC_DISTANCE_HPP + +#include "reduce.hpp" +#include "functional.hpp" +#include "detail/vec_distance_detail.hpp" + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + template struct L1Dist + { + typedef int value_type; + typedef int result_type; + + __device__ __forceinline__ L1Dist() : mySum(0) {} + + __device__ __forceinline__ void reduceIter(int val1, int val2) + { + mySum = __sad(val1, val2, mySum); + } + + template __device__ __forceinline__ void reduceAll(int* smem, int tid) + { + reduce(smem, mySum, tid, plus()); + } + + __device__ __forceinline__ operator int() const + { + return mySum; + } + + int mySum; + }; + template <> struct L1Dist + { + typedef float value_type; + typedef float result_type; + + __device__ __forceinline__ L1Dist() : mySum(0.0f) {} + + __device__ __forceinline__ void reduceIter(float val1, float val2) + { + mySum += ::fabs(val1 - val2); + } + + template __device__ __forceinline__ void reduceAll(float* smem, int tid) + { + reduce(smem, mySum, tid, plus()); + } + + __device__ __forceinline__ operator float() const + { + return mySum; + } + + float mySum; + }; + + struct L2Dist + { + typedef float value_type; + typedef float result_type; + + __device__ __forceinline__ L2Dist() : mySum(0.0f) {} + + __device__ __forceinline__ void reduceIter(float val1, float val2) + { + float reg = val1 - val2; + mySum += reg * reg; + } + + template __device__ __forceinline__ void reduceAll(float* smem, int tid) + { + reduce(smem, mySum, tid, plus()); + } + + __device__ __forceinline__ operator float() const + { + return sqrtf(mySum); + } + + float mySum; + }; + + struct HammingDist + { + typedef int value_type; + typedef int result_type; + + __device__ __forceinline__ HammingDist() : mySum(0) {} + + __device__ __forceinline__ void reduceIter(int val1, int val2) + { + mySum += __popc(val1 ^ val2); + } + + template __device__ __forceinline__ void reduceAll(int* smem, int tid) + { + reduce(smem, mySum, tid, plus()); + } + + __device__ __forceinline__ operator int() const + { + return mySum; + } + + int mySum; + }; + + // calc distance between two vectors in global memory + template + __device__ void calcVecDiffGlobal(const T1* vec1, const T2* vec2, int len, Dist& dist, typename Dist::result_type* smem, int tid) + { + for (int i = tid; i < len; i += THREAD_DIM) + { + T1 val1; + ForceGlob::Load(vec1, i, val1); + + T2 val2; + ForceGlob::Load(vec2, i, val2); + + dist.reduceIter(val1, val2); + } + + dist.reduceAll(smem, tid); + } + + // calc distance between two vectors, first vector is cached in register or shared memory, second vector is in global memory + template + __device__ __forceinline__ void calcVecDiffCached(const T1* vecCached, const T2* vecGlob, int len, Dist& dist, typename Dist::result_type* smem, int tid) + { + vec_distance_detail::VecDiffCachedCalculator::calc(vecCached, vecGlob, len, dist, tid); + + dist.reduceAll(smem, tid); + } + + // calc distance between two vectors in global memory + template struct VecDiffGlobal + { + explicit __device__ __forceinline__ VecDiffGlobal(const T1* vec1_, int = 0, void* = 0, int = 0, int = 0) + { + vec1 = vec1_; + } + + template + __device__ __forceinline__ void calc(const T2* vec2, int len, Dist& dist, typename Dist::result_type* smem, int tid) const + { + calcVecDiffGlobal(vec1, vec2, len, dist, smem, tid); + } + + const T1* vec1; + }; + + // calc distance between two vectors, first vector is cached in register memory, second vector is in global memory + template struct VecDiffCachedRegister + { + template __device__ __forceinline__ VecDiffCachedRegister(const T1* vec1, int len, U* smem, int glob_tid, int tid) + { + if (glob_tid < len) + smem[glob_tid] = vec1[glob_tid]; + __syncthreads(); + + U* vec1ValsPtr = vec1Vals; + + #pragma unroll + for (int i = tid; i < MAX_LEN; i += THREAD_DIM) + *vec1ValsPtr++ = smem[i]; + + __syncthreads(); + } + + template + __device__ __forceinline__ void calc(const T2* vec2, int len, Dist& dist, typename Dist::result_type* smem, int tid) const + { + calcVecDiffCached(vec1Vals, vec2, len, dist, smem, tid); + } + + U vec1Vals[MAX_LEN / THREAD_DIM]; + }; +}}} // namespace cv { namespace cuda { namespace cudev + +//! @endcond + +#endif // OPENCV_CUDA_VEC_DISTANCE_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/vec_math.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/vec_math.hpp new file mode 100644 index 0000000..80b1303 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/vec_math.hpp @@ -0,0 +1,923 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_VECMATH_HPP +#define OPENCV_CUDA_VECMATH_HPP + +#include "vec_traits.hpp" +#include "saturate_cast.hpp" + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + +// saturate_cast + +namespace vec_math_detail +{ + template struct SatCastHelper; + template struct SatCastHelper<1, VecD> + { + template static __device__ __forceinline__ VecD cast(const VecS& v) + { + typedef typename VecTraits::elem_type D; + return VecTraits::make(saturate_cast(v.x)); + } + }; + template struct SatCastHelper<2, VecD> + { + template static __device__ __forceinline__ VecD cast(const VecS& v) + { + typedef typename VecTraits::elem_type D; + return VecTraits::make(saturate_cast(v.x), saturate_cast(v.y)); + } + }; + template struct SatCastHelper<3, VecD> + { + template static __device__ __forceinline__ VecD cast(const VecS& v) + { + typedef typename VecTraits::elem_type D; + return VecTraits::make(saturate_cast(v.x), saturate_cast(v.y), saturate_cast(v.z)); + } + }; + template struct SatCastHelper<4, VecD> + { + template static __device__ __forceinline__ VecD cast(const VecS& v) + { + typedef typename VecTraits::elem_type D; + return VecTraits::make(saturate_cast(v.x), saturate_cast(v.y), saturate_cast(v.z), saturate_cast(v.w)); + } + }; + + template static __device__ __forceinline__ VecD saturate_cast_helper(const VecS& v) + { + return SatCastHelper::cn, VecD>::cast(v); + } +} + +template static __device__ __forceinline__ T saturate_cast(const uchar1& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const char1& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const ushort1& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const short1& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const uint1& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const int1& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const float1& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const double1& v) {return vec_math_detail::saturate_cast_helper(v);} + +template static __device__ __forceinline__ T saturate_cast(const uchar2& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const char2& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const ushort2& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const short2& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const uint2& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const int2& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const float2& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const double2& v) {return vec_math_detail::saturate_cast_helper(v);} + +template static __device__ __forceinline__ T saturate_cast(const uchar3& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const char3& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const ushort3& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const short3& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const uint3& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const int3& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const float3& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const double3& v) {return vec_math_detail::saturate_cast_helper(v);} + +template static __device__ __forceinline__ T saturate_cast(const uchar4& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const char4& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const ushort4& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const short4& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const uint4& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const int4& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const float4& v) {return vec_math_detail::saturate_cast_helper(v);} +template static __device__ __forceinline__ T saturate_cast(const double4& v) {return vec_math_detail::saturate_cast_helper(v);} + +// unary operators + +#define CV_CUDEV_IMPLEMENT_VEC_UNARY_OP(op, input_type, output_type) \ + __device__ __forceinline__ output_type ## 1 operator op(const input_type ## 1 & a) \ + { \ + return VecTraits::make(op (a.x)); \ + } \ + __device__ __forceinline__ output_type ## 2 operator op(const input_type ## 2 & a) \ + { \ + return VecTraits::make(op (a.x), op (a.y)); \ + } \ + __device__ __forceinline__ output_type ## 3 operator op(const input_type ## 3 & a) \ + { \ + return VecTraits::make(op (a.x), op (a.y), op (a.z)); \ + } \ + __device__ __forceinline__ output_type ## 4 operator op(const input_type ## 4 & a) \ + { \ + return VecTraits::make(op (a.x), op (a.y), op (a.z), op (a.w)); \ + } + +CV_CUDEV_IMPLEMENT_VEC_UNARY_OP(-, char, char) +CV_CUDEV_IMPLEMENT_VEC_UNARY_OP(-, short, short) +CV_CUDEV_IMPLEMENT_VEC_UNARY_OP(-, int, int) +CV_CUDEV_IMPLEMENT_VEC_UNARY_OP(-, float, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_OP(-, double, double) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_OP(!, uchar, uchar) +CV_CUDEV_IMPLEMENT_VEC_UNARY_OP(!, char, uchar) +CV_CUDEV_IMPLEMENT_VEC_UNARY_OP(!, ushort, uchar) +CV_CUDEV_IMPLEMENT_VEC_UNARY_OP(!, short, uchar) +CV_CUDEV_IMPLEMENT_VEC_UNARY_OP(!, int, uchar) +CV_CUDEV_IMPLEMENT_VEC_UNARY_OP(!, uint, uchar) +CV_CUDEV_IMPLEMENT_VEC_UNARY_OP(!, float, uchar) +CV_CUDEV_IMPLEMENT_VEC_UNARY_OP(!, double, uchar) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_OP(~, uchar, uchar) +CV_CUDEV_IMPLEMENT_VEC_UNARY_OP(~, char, char) +CV_CUDEV_IMPLEMENT_VEC_UNARY_OP(~, ushort, ushort) +CV_CUDEV_IMPLEMENT_VEC_UNARY_OP(~, short, short) +CV_CUDEV_IMPLEMENT_VEC_UNARY_OP(~, int, int) +CV_CUDEV_IMPLEMENT_VEC_UNARY_OP(~, uint, uint) + +#undef CV_CUDEV_IMPLEMENT_VEC_UNARY_OP + +// unary functions + +#define CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(func_name, func, input_type, output_type) \ + __device__ __forceinline__ output_type ## 1 func_name(const input_type ## 1 & a) \ + { \ + return VecTraits::make(func (a.x)); \ + } \ + __device__ __forceinline__ output_type ## 2 func_name(const input_type ## 2 & a) \ + { \ + return VecTraits::make(func (a.x), func (a.y)); \ + } \ + __device__ __forceinline__ output_type ## 3 func_name(const input_type ## 3 & a) \ + { \ + return VecTraits::make(func (a.x), func (a.y), func (a.z)); \ + } \ + __device__ __forceinline__ output_type ## 4 func_name(const input_type ## 4 & a) \ + { \ + return VecTraits::make(func (a.x), func (a.y), func (a.z), func (a.w)); \ + } + +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(abs, ::fabsf, float, float) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sqrt, ::sqrtf, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sqrt, ::sqrtf, char, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sqrt, ::sqrtf, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sqrt, ::sqrtf, short, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sqrt, ::sqrtf, int, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sqrt, ::sqrtf, uint, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sqrt, ::sqrtf, float, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sqrt, ::sqrt, double, double) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp, ::expf, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp, ::expf, char, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp, ::expf, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp, ::expf, short, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp, ::expf, int, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp, ::expf, uint, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp, ::expf, float, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp, ::exp, double, double) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp2, ::exp2f, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp2, ::exp2f, char, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp2, ::exp2f, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp2, ::exp2f, short, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp2, ::exp2f, int, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp2, ::exp2f, uint, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp2, ::exp2f, float, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp2, ::exp2, double, double) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp10, ::exp10f, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp10, ::exp10f, char, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp10, ::exp10f, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp10, ::exp10f, short, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp10, ::exp10f, int, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp10, ::exp10f, uint, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp10, ::exp10f, float, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(exp10, ::exp10, double, double) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log, ::logf, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log, ::logf, char, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log, ::logf, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log, ::logf, short, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log, ::logf, int, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log, ::logf, uint, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log, ::logf, float, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log, ::log, double, double) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log2, ::log2f, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log2, ::log2f, char, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log2, ::log2f, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log2, ::log2f, short, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log2, ::log2f, int, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log2, ::log2f, uint, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log2, ::log2f, float, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log2, ::log2, double, double) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log10, ::log10f, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log10, ::log10f, char, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log10, ::log10f, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log10, ::log10f, short, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log10, ::log10f, int, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log10, ::log10f, uint, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log10, ::log10f, float, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(log10, ::log10, double, double) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sin, ::sinf, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sin, ::sinf, char, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sin, ::sinf, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sin, ::sinf, short, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sin, ::sinf, int, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sin, ::sinf, uint, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sin, ::sinf, float, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sin, ::sin, double, double) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(cos, ::cosf, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(cos, ::cosf, char, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(cos, ::cosf, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(cos, ::cosf, short, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(cos, ::cosf, int, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(cos, ::cosf, uint, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(cos, ::cosf, float, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(cos, ::cos, double, double) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(tan, ::tanf, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(tan, ::tanf, char, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(tan, ::tanf, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(tan, ::tanf, short, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(tan, ::tanf, int, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(tan, ::tanf, uint, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(tan, ::tanf, float, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(tan, ::tan, double, double) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(asin, ::asinf, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(asin, ::asinf, char, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(asin, ::asinf, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(asin, ::asinf, short, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(asin, ::asinf, int, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(asin, ::asinf, uint, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(asin, ::asinf, float, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(asin, ::asin, double, double) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(acos, ::acosf, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(acos, ::acosf, char, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(acos, ::acosf, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(acos, ::acosf, short, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(acos, ::acosf, int, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(acos, ::acosf, uint, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(acos, ::acosf, float, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(acos, ::acos, double, double) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(atan, ::atanf, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(atan, ::atanf, char, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(atan, ::atanf, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(atan, ::atanf, short, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(atan, ::atanf, int, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(atan, ::atanf, uint, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(atan, ::atanf, float, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(atan, ::atan, double, double) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sinh, ::sinhf, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sinh, ::sinhf, char, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sinh, ::sinhf, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sinh, ::sinhf, short, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sinh, ::sinhf, int, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sinh, ::sinhf, uint, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sinh, ::sinhf, float, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(sinh, ::sinh, double, double) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(cosh, ::coshf, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(cosh, ::coshf, char, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(cosh, ::coshf, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(cosh, ::coshf, short, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(cosh, ::coshf, int, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(cosh, ::coshf, uint, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(cosh, ::coshf, float, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(cosh, ::cosh, double, double) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(tanh, ::tanhf, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(tanh, ::tanhf, char, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(tanh, ::tanhf, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(tanh, ::tanhf, short, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(tanh, ::tanhf, int, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(tanh, ::tanhf, uint, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(tanh, ::tanhf, float, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(tanh, ::tanh, double, double) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(asinh, ::asinhf, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(asinh, ::asinhf, char, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(asinh, ::asinhf, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(asinh, ::asinhf, short, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(asinh, ::asinhf, int, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(asinh, ::asinhf, uint, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(asinh, ::asinhf, float, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(asinh, ::asinh, double, double) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(acosh, ::acoshf, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(acosh, ::acoshf, char, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(acosh, ::acoshf, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(acosh, ::acoshf, short, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(acosh, ::acoshf, int, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(acosh, ::acoshf, uint, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(acosh, ::acoshf, float, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(acosh, ::acosh, double, double) + +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(atanh, ::atanhf, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(atanh, ::atanhf, char, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(atanh, ::atanhf, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(atanh, ::atanhf, short, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(atanh, ::atanhf, int, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(atanh, ::atanhf, uint, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(atanh, ::atanhf, float, float) +CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC(atanh, ::atanh, double, double) + +#undef CV_CUDEV_IMPLEMENT_VEC_UNARY_FUNC + +// binary operators (vec & vec) + +#define CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(op, input_type, output_type) \ + __device__ __forceinline__ output_type ## 1 operator op(const input_type ## 1 & a, const input_type ## 1 & b) \ + { \ + return VecTraits::make(a.x op b.x); \ + } \ + __device__ __forceinline__ output_type ## 2 operator op(const input_type ## 2 & a, const input_type ## 2 & b) \ + { \ + return VecTraits::make(a.x op b.x, a.y op b.y); \ + } \ + __device__ __forceinline__ output_type ## 3 operator op(const input_type ## 3 & a, const input_type ## 3 & b) \ + { \ + return VecTraits::make(a.x op b.x, a.y op b.y, a.z op b.z); \ + } \ + __device__ __forceinline__ output_type ## 4 operator op(const input_type ## 4 & a, const input_type ## 4 & b) \ + { \ + return VecTraits::make(a.x op b.x, a.y op b.y, a.z op b.z, a.w op b.w); \ + } + +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(+, uchar, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(+, char, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(+, ushort, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(+, short, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(+, int, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(+, uint, uint) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(+, float, float) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(+, double, double) + +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(-, uchar, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(-, char, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(-, ushort, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(-, short, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(-, int, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(-, uint, uint) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(-, float, float) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(-, double, double) + +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(*, uchar, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(*, char, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(*, ushort, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(*, short, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(*, int, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(*, uint, uint) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(*, float, float) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(*, double, double) + +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(/, uchar, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(/, char, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(/, ushort, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(/, short, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(/, int, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(/, uint, uint) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(/, float, float) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(/, double, double) + +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(==, uchar, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(==, char, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(==, ushort, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(==, short, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(==, int, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(==, uint, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(==, float, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(==, double, uchar) + +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(!=, uchar, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(!=, char, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(!=, ushort, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(!=, short, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(!=, int, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(!=, uint, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(!=, float, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(!=, double, uchar) + +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(>, uchar, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(>, char, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(>, ushort, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(>, short, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(>, int, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(>, uint, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(>, float, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(>, double, uchar) + +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(<, uchar, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(<, char, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(<, ushort, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(<, short, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(<, int, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(<, uint, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(<, float, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(<, double, uchar) + +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(>=, uchar, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(>=, char, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(>=, ushort, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(>=, short, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(>=, int, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(>=, uint, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(>=, float, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(>=, double, uchar) + +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(<=, uchar, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(<=, char, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(<=, ushort, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(<=, short, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(<=, int, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(<=, uint, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(<=, float, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(<=, double, uchar) + +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(&&, uchar, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(&&, char, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(&&, ushort, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(&&, short, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(&&, int, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(&&, uint, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(&&, float, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(&&, double, uchar) + +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(||, uchar, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(||, char, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(||, ushort, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(||, short, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(||, int, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(||, uint, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(||, float, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(||, double, uchar) + +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(&, uchar, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(&, char, char) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(&, ushort, ushort) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(&, short, short) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(&, int, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(&, uint, uint) + +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(|, uchar, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(|, char, char) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(|, ushort, ushort) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(|, short, short) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(|, int, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(|, uint, uint) + +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(^, uchar, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(^, char, char) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(^, ushort, ushort) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(^, short, short) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(^, int, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_OP(^, uint, uint) + +#undef CV_CUDEV_IMPLEMENT_VEC_BINARY_OP + +// binary operators (vec & scalar) + +#define CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(op, input_type, scalar_type, output_type) \ + __device__ __forceinline__ output_type ## 1 operator op(const input_type ## 1 & a, scalar_type s) \ + { \ + return VecTraits::make(a.x op s); \ + } \ + __device__ __forceinline__ output_type ## 1 operator op(scalar_type s, const input_type ## 1 & b) \ + { \ + return VecTraits::make(s op b.x); \ + } \ + __device__ __forceinline__ output_type ## 2 operator op(const input_type ## 2 & a, scalar_type s) \ + { \ + return VecTraits::make(a.x op s, a.y op s); \ + } \ + __device__ __forceinline__ output_type ## 2 operator op(scalar_type s, const input_type ## 2 & b) \ + { \ + return VecTraits::make(s op b.x, s op b.y); \ + } \ + __device__ __forceinline__ output_type ## 3 operator op(const input_type ## 3 & a, scalar_type s) \ + { \ + return VecTraits::make(a.x op s, a.y op s, a.z op s); \ + } \ + __device__ __forceinline__ output_type ## 3 operator op(scalar_type s, const input_type ## 3 & b) \ + { \ + return VecTraits::make(s op b.x, s op b.y, s op b.z); \ + } \ + __device__ __forceinline__ output_type ## 4 operator op(const input_type ## 4 & a, scalar_type s) \ + { \ + return VecTraits::make(a.x op s, a.y op s, a.z op s, a.w op s); \ + } \ + __device__ __forceinline__ output_type ## 4 operator op(scalar_type s, const input_type ## 4 & b) \ + { \ + return VecTraits::make(s op b.x, s op b.y, s op b.z, s op b.w); \ + } + +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, uchar, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, uchar, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, uchar, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, char, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, char, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, char, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, ushort, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, ushort, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, ushort, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, short, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, short, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, short, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, int, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, int, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, int, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, uint, uint, uint) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, uint, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, uint, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, float, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, float, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(+, double, double, double) + +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, uchar, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, uchar, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, uchar, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, char, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, char, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, char, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, ushort, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, ushort, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, ushort, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, short, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, short, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, short, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, int, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, int, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, int, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, uint, uint, uint) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, uint, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, uint, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, float, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, float, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(-, double, double, double) + +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, uchar, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, uchar, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, uchar, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, char, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, char, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, char, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, ushort, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, ushort, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, ushort, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, short, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, short, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, short, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, int, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, int, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, int, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, uint, uint, uint) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, uint, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, uint, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, float, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, float, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(*, double, double, double) + +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, uchar, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, uchar, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, uchar, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, char, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, char, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, char, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, ushort, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, ushort, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, ushort, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, short, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, short, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, short, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, int, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, int, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, int, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, uint, uint, uint) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, uint, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, uint, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, float, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, float, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(/, double, double, double) + +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(==, uchar, uchar, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(==, char, char, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(==, ushort, ushort, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(==, short, short, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(==, int, int, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(==, uint, uint, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(==, float, float, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(==, double, double, uchar) + +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(!=, uchar, uchar, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(!=, char, char, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(!=, ushort, ushort, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(!=, short, short, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(!=, int, int, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(!=, uint, uint, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(!=, float, float, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(!=, double, double, uchar) + +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(>, uchar, uchar, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(>, char, char, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(>, ushort, ushort, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(>, short, short, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(>, int, int, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(>, uint, uint, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(>, float, float, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(>, double, double, uchar) + +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(<, uchar, uchar, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(<, char, char, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(<, ushort, ushort, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(<, short, short, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(<, int, int, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(<, uint, uint, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(<, float, float, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(<, double, double, uchar) + +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(>=, uchar, uchar, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(>=, char, char, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(>=, ushort, ushort, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(>=, short, short, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(>=, int, int, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(>=, uint, uint, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(>=, float, float, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(>=, double, double, uchar) + +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(<=, uchar, uchar, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(<=, char, char, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(<=, ushort, ushort, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(<=, short, short, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(<=, int, int, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(<=, uint, uint, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(<=, float, float, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(<=, double, double, uchar) + +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(&&, uchar, uchar, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(&&, char, char, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(&&, ushort, ushort, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(&&, short, short, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(&&, int, int, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(&&, uint, uint, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(&&, float, float, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(&&, double, double, uchar) + +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(||, uchar, uchar, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(||, char, char, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(||, ushort, ushort, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(||, short, short, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(||, int, int, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(||, uint, uint, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(||, float, float, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(||, double, double, uchar) + +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(&, uchar, uchar, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(&, char, char, char) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(&, ushort, ushort, ushort) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(&, short, short, short) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(&, int, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(&, uint, uint, uint) + +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(|, uchar, uchar, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(|, char, char, char) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(|, ushort, ushort, ushort) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(|, short, short, short) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(|, int, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(|, uint, uint, uint) + +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(^, uchar, uchar, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(^, char, char, char) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(^, ushort, ushort, ushort) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(^, short, short, short) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(^, int, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP(^, uint, uint, uint) + +#undef CV_CUDEV_IMPLEMENT_SCALAR_BINARY_OP + +// binary function (vec & vec) + +#define CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(func_name, func, input_type, output_type) \ + __device__ __forceinline__ output_type ## 1 func_name(const input_type ## 1 & a, const input_type ## 1 & b) \ + { \ + return VecTraits::make(func (a.x, b.x)); \ + } \ + __device__ __forceinline__ output_type ## 2 func_name(const input_type ## 2 & a, const input_type ## 2 & b) \ + { \ + return VecTraits::make(func (a.x, b.x), func (a.y, b.y)); \ + } \ + __device__ __forceinline__ output_type ## 3 func_name(const input_type ## 3 & a, const input_type ## 3 & b) \ + { \ + return VecTraits::make(func (a.x, b.x), func (a.y, b.y), func (a.z, b.z)); \ + } \ + __device__ __forceinline__ output_type ## 4 func_name(const input_type ## 4 & a, const input_type ## 4 & b) \ + { \ + return VecTraits::make(func (a.x, b.x), func (a.y, b.y), func (a.z, b.z), func (a.w, b.w)); \ + } + +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(max, ::max, uchar, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(max, ::max, char, char) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(max, ::max, ushort, ushort) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(max, ::max, short, short) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(max, ::max, uint, uint) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(max, ::max, int, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(max, ::fmaxf, float, float) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(max, ::fmax, double, double) + +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(min, ::min, uchar, uchar) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(min, ::min, char, char) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(min, ::min, ushort, ushort) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(min, ::min, short, short) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(min, ::min, uint, uint) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(min, ::min, int, int) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(min, ::fminf, float, float) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(min, ::fmin, double, double) + +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(hypot, ::hypotf, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(hypot, ::hypotf, char, float) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(hypot, ::hypotf, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(hypot, ::hypotf, short, float) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(hypot, ::hypotf, uint, float) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(hypot, ::hypotf, int, float) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(hypot, ::hypotf, float, float) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(hypot, ::hypot, double, double) + +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(atan2, ::atan2f, uchar, float) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(atan2, ::atan2f, char, float) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(atan2, ::atan2f, ushort, float) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(atan2, ::atan2f, short, float) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(atan2, ::atan2f, uint, float) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(atan2, ::atan2f, int, float) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(atan2, ::atan2f, float, float) +CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC(atan2, ::atan2, double, double) + +#undef CV_CUDEV_IMPLEMENT_VEC_BINARY_FUNC + +// binary function (vec & scalar) + +#define CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(func_name, func, input_type, scalar_type, output_type) \ + __device__ __forceinline__ output_type ## 1 func_name(const input_type ## 1 & a, scalar_type s) \ + { \ + return VecTraits::make(func ((output_type) a.x, (output_type) s)); \ + } \ + __device__ __forceinline__ output_type ## 1 func_name(scalar_type s, const input_type ## 1 & b) \ + { \ + return VecTraits::make(func ((output_type) s, (output_type) b.x)); \ + } \ + __device__ __forceinline__ output_type ## 2 func_name(const input_type ## 2 & a, scalar_type s) \ + { \ + return VecTraits::make(func ((output_type) a.x, (output_type) s), func ((output_type) a.y, (output_type) s)); \ + } \ + __device__ __forceinline__ output_type ## 2 func_name(scalar_type s, const input_type ## 2 & b) \ + { \ + return VecTraits::make(func ((output_type) s, (output_type) b.x), func ((output_type) s, (output_type) b.y)); \ + } \ + __device__ __forceinline__ output_type ## 3 func_name(const input_type ## 3 & a, scalar_type s) \ + { \ + return VecTraits::make(func ((output_type) a.x, (output_type) s), func ((output_type) a.y, (output_type) s), func ((output_type) a.z, (output_type) s)); \ + } \ + __device__ __forceinline__ output_type ## 3 func_name(scalar_type s, const input_type ## 3 & b) \ + { \ + return VecTraits::make(func ((output_type) s, (output_type) b.x), func ((output_type) s, (output_type) b.y), func ((output_type) s, (output_type) b.z)); \ + } \ + __device__ __forceinline__ output_type ## 4 func_name(const input_type ## 4 & a, scalar_type s) \ + { \ + return VecTraits::make(func ((output_type) a.x, (output_type) s), func ((output_type) a.y, (output_type) s), func ((output_type) a.z, (output_type) s), func ((output_type) a.w, (output_type) s)); \ + } \ + __device__ __forceinline__ output_type ## 4 func_name(scalar_type s, const input_type ## 4 & b) \ + { \ + return VecTraits::make(func ((output_type) s, (output_type) b.x), func ((output_type) s, (output_type) b.y), func ((output_type) s, (output_type) b.z), func ((output_type) s, (output_type) b.w)); \ + } + +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::max, uchar, uchar, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::fmaxf, uchar, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::fmax, uchar, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::max, char, char, char) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::fmaxf, char, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::fmax, char, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::max, ushort, ushort, ushort) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::fmaxf, ushort, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::fmax, ushort, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::max, short, short, short) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::fmaxf, short, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::fmax, short, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::max, uint, uint, uint) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::fmaxf, uint, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::fmax, uint, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::max, int, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::fmaxf, int, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::fmax, int, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::fmaxf, float, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::fmax, float, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(max, ::fmax, double, double, double) + +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::min, uchar, uchar, uchar) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::fminf, uchar, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::fmin, uchar, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::min, char, char, char) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::fminf, char, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::fmin, char, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::min, ushort, ushort, ushort) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::fminf, ushort, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::fmin, ushort, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::min, short, short, short) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::fminf, short, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::fmin, short, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::min, uint, uint, uint) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::fminf, uint, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::fmin, uint, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::min, int, int, int) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::fminf, int, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::fmin, int, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::fminf, float, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::fmin, float, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(min, ::fmin, double, double, double) + +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(hypot, ::hypotf, uchar, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(hypot, ::hypot, uchar, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(hypot, ::hypotf, char, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(hypot, ::hypot, char, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(hypot, ::hypotf, ushort, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(hypot, ::hypot, ushort, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(hypot, ::hypotf, short, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(hypot, ::hypot, short, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(hypot, ::hypotf, uint, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(hypot, ::hypot, uint, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(hypot, ::hypotf, int, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(hypot, ::hypot, int, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(hypot, ::hypotf, float, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(hypot, ::hypot, float, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(hypot, ::hypot, double, double, double) + +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(atan2, ::atan2f, uchar, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(atan2, ::atan2, uchar, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(atan2, ::atan2f, char, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(atan2, ::atan2, char, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(atan2, ::atan2f, ushort, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(atan2, ::atan2, ushort, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(atan2, ::atan2f, short, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(atan2, ::atan2, short, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(atan2, ::atan2f, uint, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(atan2, ::atan2, uint, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(atan2, ::atan2f, int, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(atan2, ::atan2, int, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(atan2, ::atan2f, float, float, float) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(atan2, ::atan2, float, double, double) +CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(atan2, ::atan2, double, double, double) + +#undef CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC + +}}} // namespace cv { namespace cuda { namespace device + +//! @endcond + +#endif // OPENCV_CUDA_VECMATH_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/vec_traits.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/vec_traits.hpp new file mode 100644 index 0000000..b5ff281 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/vec_traits.hpp @@ -0,0 +1,288 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_VEC_TRAITS_HPP +#define OPENCV_CUDA_VEC_TRAITS_HPP + +#include "common.hpp" + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + template struct TypeVec; + + struct __align__(8) uchar8 + { + uchar a0, a1, a2, a3, a4, a5, a6, a7; + }; + static __host__ __device__ __forceinline__ uchar8 make_uchar8(uchar a0, uchar a1, uchar a2, uchar a3, uchar a4, uchar a5, uchar a6, uchar a7) + { + uchar8 val = {a0, a1, a2, a3, a4, a5, a6, a7}; + return val; + } + struct __align__(8) char8 + { + schar a0, a1, a2, a3, a4, a5, a6, a7; + }; + static __host__ __device__ __forceinline__ char8 make_char8(schar a0, schar a1, schar a2, schar a3, schar a4, schar a5, schar a6, schar a7) + { + char8 val = {a0, a1, a2, a3, a4, a5, a6, a7}; + return val; + } + struct __align__(16) ushort8 + { + ushort a0, a1, a2, a3, a4, a5, a6, a7; + }; + static __host__ __device__ __forceinline__ ushort8 make_ushort8(ushort a0, ushort a1, ushort a2, ushort a3, ushort a4, ushort a5, ushort a6, ushort a7) + { + ushort8 val = {a0, a1, a2, a3, a4, a5, a6, a7}; + return val; + } + struct __align__(16) short8 + { + short a0, a1, a2, a3, a4, a5, a6, a7; + }; + static __host__ __device__ __forceinline__ short8 make_short8(short a0, short a1, short a2, short a3, short a4, short a5, short a6, short a7) + { + short8 val = {a0, a1, a2, a3, a4, a5, a6, a7}; + return val; + } + struct __align__(32) uint8 + { + uint a0, a1, a2, a3, a4, a5, a6, a7; + }; + static __host__ __device__ __forceinline__ uint8 make_uint8(uint a0, uint a1, uint a2, uint a3, uint a4, uint a5, uint a6, uint a7) + { + uint8 val = {a0, a1, a2, a3, a4, a5, a6, a7}; + return val; + } + struct __align__(32) int8 + { + int a0, a1, a2, a3, a4, a5, a6, a7; + }; + static __host__ __device__ __forceinline__ int8 make_int8(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7) + { + int8 val = {a0, a1, a2, a3, a4, a5, a6, a7}; + return val; + } + struct __align__(32) float8 + { + float a0, a1, a2, a3, a4, a5, a6, a7; + }; + static __host__ __device__ __forceinline__ float8 make_float8(float a0, float a1, float a2, float a3, float a4, float a5, float a6, float a7) + { + float8 val = {a0, a1, a2, a3, a4, a5, a6, a7}; + return val; + } + struct double8 + { + double a0, a1, a2, a3, a4, a5, a6, a7; + }; + static __host__ __device__ __forceinline__ double8 make_double8(double a0, double a1, double a2, double a3, double a4, double a5, double a6, double a7) + { + double8 val = {a0, a1, a2, a3, a4, a5, a6, a7}; + return val; + } + +#define OPENCV_CUDA_IMPLEMENT_TYPE_VEC(type) \ + template<> struct TypeVec { typedef type vec_type; }; \ + template<> struct TypeVec { typedef type ## 1 vec_type; }; \ + template<> struct TypeVec { typedef type ## 2 vec_type; }; \ + template<> struct TypeVec { typedef type ## 2 vec_type; }; \ + template<> struct TypeVec { typedef type ## 3 vec_type; }; \ + template<> struct TypeVec { typedef type ## 3 vec_type; }; \ + template<> struct TypeVec { typedef type ## 4 vec_type; }; \ + template<> struct TypeVec { typedef type ## 4 vec_type; }; \ + template<> struct TypeVec { typedef type ## 8 vec_type; }; \ + template<> struct TypeVec { typedef type ## 8 vec_type; }; + + OPENCV_CUDA_IMPLEMENT_TYPE_VEC(uchar) + OPENCV_CUDA_IMPLEMENT_TYPE_VEC(char) + OPENCV_CUDA_IMPLEMENT_TYPE_VEC(ushort) + OPENCV_CUDA_IMPLEMENT_TYPE_VEC(short) + OPENCV_CUDA_IMPLEMENT_TYPE_VEC(int) + OPENCV_CUDA_IMPLEMENT_TYPE_VEC(uint) + OPENCV_CUDA_IMPLEMENT_TYPE_VEC(float) + OPENCV_CUDA_IMPLEMENT_TYPE_VEC(double) + + #undef OPENCV_CUDA_IMPLEMENT_TYPE_VEC + + template<> struct TypeVec { typedef schar vec_type; }; + template<> struct TypeVec { typedef char2 vec_type; }; + template<> struct TypeVec { typedef char3 vec_type; }; + template<> struct TypeVec { typedef char4 vec_type; }; + template<> struct TypeVec { typedef char8 vec_type; }; + + template<> struct TypeVec { typedef uchar vec_type; }; + template<> struct TypeVec { typedef uchar2 vec_type; }; + template<> struct TypeVec { typedef uchar3 vec_type; }; + template<> struct TypeVec { typedef uchar4 vec_type; }; + template<> struct TypeVec { typedef uchar8 vec_type; }; + + template struct VecTraits; + +#define OPENCV_CUDA_IMPLEMENT_VEC_TRAITS(type) \ + template<> struct VecTraits \ + { \ + typedef type elem_type; \ + enum {cn=1}; \ + static __device__ __host__ __forceinline__ type all(type v) {return v;} \ + static __device__ __host__ __forceinline__ type make(type x) {return x;} \ + static __device__ __host__ __forceinline__ type make(const type* v) {return *v;} \ + }; \ + template<> struct VecTraits \ + { \ + typedef type elem_type; \ + enum {cn=1}; \ + static __device__ __host__ __forceinline__ type ## 1 all(type v) {return make_ ## type ## 1(v);} \ + static __device__ __host__ __forceinline__ type ## 1 make(type x) {return make_ ## type ## 1(x);} \ + static __device__ __host__ __forceinline__ type ## 1 make(const type* v) {return make_ ## type ## 1(*v);} \ + }; \ + template<> struct VecTraits \ + { \ + typedef type elem_type; \ + enum {cn=2}; \ + static __device__ __host__ __forceinline__ type ## 2 all(type v) {return make_ ## type ## 2(v, v);} \ + static __device__ __host__ __forceinline__ type ## 2 make(type x, type y) {return make_ ## type ## 2(x, y);} \ + static __device__ __host__ __forceinline__ type ## 2 make(const type* v) {return make_ ## type ## 2(v[0], v[1]);} \ + }; \ + template<> struct VecTraits \ + { \ + typedef type elem_type; \ + enum {cn=3}; \ + static __device__ __host__ __forceinline__ type ## 3 all(type v) {return make_ ## type ## 3(v, v, v);} \ + static __device__ __host__ __forceinline__ type ## 3 make(type x, type y, type z) {return make_ ## type ## 3(x, y, z);} \ + static __device__ __host__ __forceinline__ type ## 3 make(const type* v) {return make_ ## type ## 3(v[0], v[1], v[2]);} \ + }; \ + template<> struct VecTraits \ + { \ + typedef type elem_type; \ + enum {cn=4}; \ + static __device__ __host__ __forceinline__ type ## 4 all(type v) {return make_ ## type ## 4(v, v, v, v);} \ + static __device__ __host__ __forceinline__ type ## 4 make(type x, type y, type z, type w) {return make_ ## type ## 4(x, y, z, w);} \ + static __device__ __host__ __forceinline__ type ## 4 make(const type* v) {return make_ ## type ## 4(v[0], v[1], v[2], v[3]);} \ + }; \ + template<> struct VecTraits \ + { \ + typedef type elem_type; \ + enum {cn=8}; \ + static __device__ __host__ __forceinline__ type ## 8 all(type v) {return make_ ## type ## 8(v, v, v, v, v, v, v, v);} \ + static __device__ __host__ __forceinline__ type ## 8 make(type a0, type a1, type a2, type a3, type a4, type a5, type a6, type a7) {return make_ ## type ## 8(a0, a1, a2, a3, a4, a5, a6, a7);} \ + static __device__ __host__ __forceinline__ type ## 8 make(const type* v) {return make_ ## type ## 8(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);} \ + }; + + OPENCV_CUDA_IMPLEMENT_VEC_TRAITS(uchar) + OPENCV_CUDA_IMPLEMENT_VEC_TRAITS(ushort) + OPENCV_CUDA_IMPLEMENT_VEC_TRAITS(short) + OPENCV_CUDA_IMPLEMENT_VEC_TRAITS(int) + OPENCV_CUDA_IMPLEMENT_VEC_TRAITS(uint) + OPENCV_CUDA_IMPLEMENT_VEC_TRAITS(float) + OPENCV_CUDA_IMPLEMENT_VEC_TRAITS(double) + + #undef OPENCV_CUDA_IMPLEMENT_VEC_TRAITS + + template<> struct VecTraits + { + typedef char elem_type; + enum {cn=1}; + static __device__ __host__ __forceinline__ char all(char v) {return v;} + static __device__ __host__ __forceinline__ char make(char x) {return x;} + static __device__ __host__ __forceinline__ char make(const char* x) {return *x;} + }; + template<> struct VecTraits + { + typedef schar elem_type; + enum {cn=1}; + static __device__ __host__ __forceinline__ schar all(schar v) {return v;} + static __device__ __host__ __forceinline__ schar make(schar x) {return x;} + static __device__ __host__ __forceinline__ schar make(const schar* x) {return *x;} + }; + template<> struct VecTraits + { + typedef schar elem_type; + enum {cn=1}; + static __device__ __host__ __forceinline__ char1 all(schar v) {return make_char1(v);} + static __device__ __host__ __forceinline__ char1 make(schar x) {return make_char1(x);} + static __device__ __host__ __forceinline__ char1 make(const schar* v) {return make_char1(v[0]);} + }; + template<> struct VecTraits + { + typedef schar elem_type; + enum {cn=2}; + static __device__ __host__ __forceinline__ char2 all(schar v) {return make_char2(v, v);} + static __device__ __host__ __forceinline__ char2 make(schar x, schar y) {return make_char2(x, y);} + static __device__ __host__ __forceinline__ char2 make(const schar* v) {return make_char2(v[0], v[1]);} + }; + template<> struct VecTraits + { + typedef schar elem_type; + enum {cn=3}; + static __device__ __host__ __forceinline__ char3 all(schar v) {return make_char3(v, v, v);} + static __device__ __host__ __forceinline__ char3 make(schar x, schar y, schar z) {return make_char3(x, y, z);} + static __device__ __host__ __forceinline__ char3 make(const schar* v) {return make_char3(v[0], v[1], v[2]);} + }; + template<> struct VecTraits + { + typedef schar elem_type; + enum {cn=4}; + static __device__ __host__ __forceinline__ char4 all(schar v) {return make_char4(v, v, v, v);} + static __device__ __host__ __forceinline__ char4 make(schar x, schar y, schar z, schar w) {return make_char4(x, y, z, w);} + static __device__ __host__ __forceinline__ char4 make(const schar* v) {return make_char4(v[0], v[1], v[2], v[3]);} + }; + template<> struct VecTraits + { + typedef schar elem_type; + enum {cn=8}; + static __device__ __host__ __forceinline__ char8 all(schar v) {return make_char8(v, v, v, v, v, v, v, v);} + static __device__ __host__ __forceinline__ char8 make(schar a0, schar a1, schar a2, schar a3, schar a4, schar a5, schar a6, schar a7) {return make_char8(a0, a1, a2, a3, a4, a5, a6, a7);} + static __device__ __host__ __forceinline__ char8 make(const schar* v) {return make_char8(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);} + }; +}}} // namespace cv { namespace cuda { namespace cudev + +//! @endcond + +#endif // OPENCV_CUDA_VEC_TRAITS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/warp.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/warp.hpp new file mode 100644 index 0000000..8af7e6a --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/warp.hpp @@ -0,0 +1,139 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_DEVICE_WARP_HPP +#define OPENCV_CUDA_DEVICE_WARP_HPP + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + struct Warp + { + enum + { + LOG_WARP_SIZE = 5, + WARP_SIZE = 1 << LOG_WARP_SIZE, + STRIDE = WARP_SIZE + }; + + /** \brief Returns the warp lane ID of the calling thread. */ + static __device__ __forceinline__ unsigned int laneId() + { + unsigned int ret; + asm("mov.u32 %0, %%laneid;" : "=r"(ret) ); + return ret; + } + + template + static __device__ __forceinline__ void fill(It beg, It end, const T& value) + { + for(It t = beg + laneId(); t < end; t += STRIDE) + *t = value; + } + + template + static __device__ __forceinline__ OutIt copy(InIt beg, InIt end, OutIt out) + { + for(InIt t = beg + laneId(); t < end; t += STRIDE, out += STRIDE) + *out = *t; + return out; + } + + template + static __device__ __forceinline__ OutIt transform(InIt beg, InIt end, OutIt out, UnOp op) + { + for(InIt t = beg + laneId(); t < end; t += STRIDE, out += STRIDE) + *out = op(*t); + return out; + } + + template + static __device__ __forceinline__ OutIt transform(InIt1 beg1, InIt1 end1, InIt2 beg2, OutIt out, BinOp op) + { + unsigned int lane = laneId(); + + InIt1 t1 = beg1 + lane; + InIt2 t2 = beg2 + lane; + for(; t1 < end1; t1 += STRIDE, t2 += STRIDE, out += STRIDE) + *out = op(*t1, *t2); + return out; + } + + template + static __device__ __forceinline__ T reduce(volatile T *ptr, BinOp op) + { + const unsigned int lane = laneId(); + + if (lane < 16) + { + T partial = ptr[lane]; + + ptr[lane] = partial = op(partial, ptr[lane + 16]); + ptr[lane] = partial = op(partial, ptr[lane + 8]); + ptr[lane] = partial = op(partial, ptr[lane + 4]); + ptr[lane] = partial = op(partial, ptr[lane + 2]); + ptr[lane] = partial = op(partial, ptr[lane + 1]); + } + + return *ptr; + } + + template + static __device__ __forceinline__ void yota(OutIt beg, OutIt end, T value) + { + unsigned int lane = laneId(); + value += lane; + + for(OutIt t = beg + lane; t < end; t += STRIDE, value += STRIDE) + *t = value; + } + }; +}}} // namespace cv { namespace cuda { namespace cudev + +//! @endcond + +#endif /* OPENCV_CUDA_DEVICE_WARP_HPP */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/warp_reduce.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/warp_reduce.hpp new file mode 100644 index 0000000..530303d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/warp_reduce.hpp @@ -0,0 +1,76 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_WARP_REDUCE_HPP__ +#define OPENCV_CUDA_WARP_REDUCE_HPP__ + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ + template + __device__ __forceinline__ T warp_reduce(volatile T *ptr , const unsigned int tid = threadIdx.x) + { + const unsigned int lane = tid & 31; // index of thread in warp (0..31) + + if (lane < 16) + { + T partial = ptr[tid]; + + ptr[tid] = partial = partial + ptr[tid + 16]; + ptr[tid] = partial = partial + ptr[tid + 8]; + ptr[tid] = partial = partial + ptr[tid + 4]; + ptr[tid] = partial = partial + ptr[tid + 2]; + ptr[tid] = partial = partial + ptr[tid + 1]; + } + + return ptr[tid - lane]; + } +}}} // namespace cv { namespace cuda { namespace cudev { + +//! @endcond + +#endif /* OPENCV_CUDA_WARP_REDUCE_HPP__ */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/warp_shuffle.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/warp_shuffle.hpp new file mode 100644 index 0000000..0da54ae --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda/warp_shuffle.hpp @@ -0,0 +1,162 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CUDA_WARP_SHUFFLE_HPP +#define OPENCV_CUDA_WARP_SHUFFLE_HPP + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +namespace cv { namespace cuda { namespace device +{ +#if __CUDACC_VER_MAJOR__ >= 9 +# define __shfl(x, y, z) __shfl_sync(0xFFFFFFFFU, x, y, z) +# define __shfl_up(x, y, z) __shfl_up_sync(0xFFFFFFFFU, x, y, z) +# define __shfl_down(x, y, z) __shfl_down_sync(0xFFFFFFFFU, x, y, z) +#endif + template + __device__ __forceinline__ T shfl(T val, int srcLane, int width = warpSize) + { + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 + return __shfl(val, srcLane, width); + #else + return T(); + #endif + } + __device__ __forceinline__ unsigned int shfl(unsigned int val, int srcLane, int width = warpSize) + { + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 + return (unsigned int) __shfl((int) val, srcLane, width); + #else + return 0; + #endif + } + __device__ __forceinline__ double shfl(double val, int srcLane, int width = warpSize) + { + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 + int lo = __double2loint(val); + int hi = __double2hiint(val); + + lo = __shfl(lo, srcLane, width); + hi = __shfl(hi, srcLane, width); + + return __hiloint2double(hi, lo); + #else + return 0.0; + #endif + } + + template + __device__ __forceinline__ T shfl_down(T val, unsigned int delta, int width = warpSize) + { + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 + return __shfl_down(val, delta, width); + #else + return T(); + #endif + } + __device__ __forceinline__ unsigned int shfl_down(unsigned int val, unsigned int delta, int width = warpSize) + { + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 + return (unsigned int) __shfl_down((int) val, delta, width); + #else + return 0; + #endif + } + __device__ __forceinline__ double shfl_down(double val, unsigned int delta, int width = warpSize) + { + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 + int lo = __double2loint(val); + int hi = __double2hiint(val); + + lo = __shfl_down(lo, delta, width); + hi = __shfl_down(hi, delta, width); + + return __hiloint2double(hi, lo); + #else + return 0.0; + #endif + } + + template + __device__ __forceinline__ T shfl_up(T val, unsigned int delta, int width = warpSize) + { + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 + return __shfl_up(val, delta, width); + #else + return T(); + #endif + } + __device__ __forceinline__ unsigned int shfl_up(unsigned int val, unsigned int delta, int width = warpSize) + { + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 + return (unsigned int) __shfl_up((int) val, delta, width); + #else + return 0; + #endif + } + __device__ __forceinline__ double shfl_up(double val, unsigned int delta, int width = warpSize) + { + #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300 + int lo = __double2loint(val); + int hi = __double2hiint(val); + + lo = __shfl_up(lo, delta, width); + hi = __shfl_up(hi, delta, width); + + return __hiloint2double(hi, lo); + #else + return 0.0; + #endif + } +}}} + +# undef __shfl +# undef __shfl_up +# undef __shfl_down + +//! @endcond + +#endif // OPENCV_CUDA_WARP_SHUFFLE_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda_stream_accessor.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda_stream_accessor.hpp new file mode 100644 index 0000000..deaf356 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda_stream_accessor.hpp @@ -0,0 +1,86 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_CUDA_STREAM_ACCESSOR_HPP +#define OPENCV_CORE_CUDA_STREAM_ACCESSOR_HPP + +#ifndef __cplusplus +# error cuda_stream_accessor.hpp header must be compiled as C++ +#endif + +/** @file cuda_stream_accessor.hpp + * This is only header file that depends on CUDA Runtime API. All other headers are independent. + */ + +#include +#include "opencv2/core/cuda.hpp" + +namespace cv +{ + namespace cuda + { + +//! @addtogroup cudacore_struct +//! @{ + + /** @brief Class that enables getting cudaStream_t from cuda::Stream + */ + struct StreamAccessor + { + CV_EXPORTS static cudaStream_t getStream(const Stream& stream); + CV_EXPORTS static Stream wrapStream(cudaStream_t stream); + }; + + /** @brief Class that enables getting cudaEvent_t from cuda::Event + */ + struct EventAccessor + { + CV_EXPORTS static cudaEvent_t getEvent(const Event& event); + CV_EXPORTS static Event wrapEvent(cudaEvent_t event); + }; + +//! @} + + } +} + +#endif /* OPENCV_CORE_CUDA_STREAM_ACCESSOR_HPP */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda_types.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda_types.hpp new file mode 100644 index 0000000..b33f061 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cuda_types.hpp @@ -0,0 +1,144 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_CUDA_TYPES_HPP +#define OPENCV_CORE_CUDA_TYPES_HPP + +#ifndef __cplusplus +# error cuda_types.hpp header must be compiled as C++ +#endif + +#if defined(__OPENCV_BUILD) && defined(__clang__) +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif +#if defined(__OPENCV_BUILD) && defined(__GNUC__) && __GNUC__ >= 5 +#pragma GCC diagnostic ignored "-Wsuggest-override" +#endif + +/** @file + * @deprecated Use @ref cudev instead. + */ + +//! @cond IGNORED + +#ifdef __CUDACC__ + #define __CV_CUDA_HOST_DEVICE__ __host__ __device__ __forceinline__ +#else + #define __CV_CUDA_HOST_DEVICE__ +#endif + +namespace cv +{ + namespace cuda + { + + // Simple lightweight structures that encapsulates information about an image on device. + // It is intended to pass to nvcc-compiled code. GpuMat depends on headers that nvcc can't compile + + template struct DevPtr + { + typedef T elem_type; + typedef int index_type; + + enum { elem_size = sizeof(elem_type) }; + + T* data; + + __CV_CUDA_HOST_DEVICE__ DevPtr() : data(0) {} + __CV_CUDA_HOST_DEVICE__ DevPtr(T* data_) : data(data_) {} + + __CV_CUDA_HOST_DEVICE__ size_t elemSize() const { return elem_size; } + __CV_CUDA_HOST_DEVICE__ operator T*() { return data; } + __CV_CUDA_HOST_DEVICE__ operator const T*() const { return data; } + }; + + template struct PtrSz : public DevPtr + { + __CV_CUDA_HOST_DEVICE__ PtrSz() : size(0) {} + __CV_CUDA_HOST_DEVICE__ PtrSz(T* data_, size_t size_) : DevPtr(data_), size(size_) {} + + size_t size; + }; + + template struct PtrStep : public DevPtr + { + __CV_CUDA_HOST_DEVICE__ PtrStep() : step(0) {} + __CV_CUDA_HOST_DEVICE__ PtrStep(T* data_, size_t step_) : DevPtr(data_), step(step_) {} + + size_t step; + + __CV_CUDA_HOST_DEVICE__ T* ptr(int y = 0) { return ( T*)( ( char*)(((DevPtr*)this)->data) + y * step); } + __CV_CUDA_HOST_DEVICE__ const T* ptr(int y = 0) const { return (const T*)( (const char*)(((DevPtr*)this)->data) + y * step); } + + __CV_CUDA_HOST_DEVICE__ T& operator ()(int y, int x) { return ptr(y)[x]; } + __CV_CUDA_HOST_DEVICE__ const T& operator ()(int y, int x) const { return ptr(y)[x]; } + }; + + template struct PtrStepSz : public PtrStep + { + __CV_CUDA_HOST_DEVICE__ PtrStepSz() : cols(0), rows(0) {} + __CV_CUDA_HOST_DEVICE__ PtrStepSz(int rows_, int cols_, T* data_, size_t step_) + : PtrStep(data_, step_), cols(cols_), rows(rows_) {} + + template + explicit PtrStepSz(const PtrStepSz& d) : PtrStep((T*)d.data, d.step), cols(d.cols), rows(d.rows){} + + int cols; + int rows; + }; + + typedef PtrStepSz PtrStepSzb; + typedef PtrStepSz PtrStepSzus; + typedef PtrStepSz PtrStepSzf; + typedef PtrStepSz PtrStepSzi; + + typedef PtrStep PtrStepb; + typedef PtrStep PtrStepus; + typedef PtrStep PtrStepf; + typedef PtrStep PtrStepi; + + } +} + +//! @endcond + +#endif /* OPENCV_CORE_CUDA_TYPES_HPP */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cv_cpu_dispatch.h b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cv_cpu_dispatch.h new file mode 100644 index 0000000..ab5a67d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cv_cpu_dispatch.h @@ -0,0 +1,368 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#if defined __OPENCV_BUILD \ + +#include "cv_cpu_config.h" +#include "cv_cpu_helper.h" + +#ifdef CV_CPU_DISPATCH_MODE +#define CV_CPU_OPTIMIZATION_NAMESPACE __CV_CAT(opt_, CV_CPU_DISPATCH_MODE) +#define CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN namespace __CV_CAT(opt_, CV_CPU_DISPATCH_MODE) { +#define CV_CPU_OPTIMIZATION_NAMESPACE_END } +#else +#define CV_CPU_OPTIMIZATION_NAMESPACE cpu_baseline +#define CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN namespace cpu_baseline { +#define CV_CPU_OPTIMIZATION_NAMESPACE_END } +#define CV_CPU_BASELINE_MODE 1 +#endif + + +#define __CV_CPU_DISPATCH_CHAIN_END(fn, args, mode, ...) /* done */ +#define __CV_CPU_DISPATCH(fn, args, mode, ...) __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) +#define __CV_CPU_DISPATCH_EXPAND(fn, args, ...) __CV_EXPAND(__CV_CPU_DISPATCH(fn, args, __VA_ARGS__)) +#define CV_CPU_DISPATCH(fn, args, ...) __CV_CPU_DISPATCH_EXPAND(fn, args, __VA_ARGS__, END) // expand macros + + +#if defined CV_ENABLE_INTRINSICS \ + && !defined CV_DISABLE_OPTIMIZATION \ + && !defined __CUDACC__ /* do not include SSE/AVX/NEON headers for NVCC compiler */ \ + +#ifdef CV_CPU_COMPILE_SSE2 +# include +# define CV_MMX 1 +# define CV_SSE 1 +# define CV_SSE2 1 +#endif +#ifdef CV_CPU_COMPILE_SSE3 +# include +# define CV_SSE3 1 +#endif +#ifdef CV_CPU_COMPILE_SSSE3 +# include +# define CV_SSSE3 1 +#endif +#ifdef CV_CPU_COMPILE_SSE4_1 +# include +# define CV_SSE4_1 1 +#endif +#ifdef CV_CPU_COMPILE_SSE4_2 +# include +# define CV_SSE4_2 1 +#endif +#ifdef CV_CPU_COMPILE_POPCNT +# ifdef _MSC_VER +# include +# if defined(_M_X64) +# define CV_POPCNT_U64 (int)_mm_popcnt_u64 +# endif +# define CV_POPCNT_U32 _mm_popcnt_u32 +# else +# include +# if defined(__x86_64__) +# define CV_POPCNT_U64 __builtin_popcountll +# endif +# define CV_POPCNT_U32 __builtin_popcount +# endif +# define CV_POPCNT 1 +#endif +#ifdef CV_CPU_COMPILE_AVX +# include +# define CV_AVX 1 +#endif +#ifdef CV_CPU_COMPILE_FP16 +# if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARM64) +# include +# else +# include +# endif +# define CV_FP16 1 +#endif +#ifdef CV_CPU_COMPILE_AVX2 +# include +# define CV_AVX2 1 +#endif +#ifdef CV_CPU_COMPILE_AVX_512F +# include +# define CV_AVX_512F 1 +#endif +#ifdef CV_CPU_COMPILE_AVX512_COMMON +# define CV_AVX512_COMMON 1 +# define CV_AVX_512CD 1 +#endif +#ifdef CV_CPU_COMPILE_AVX512_KNL +# define CV_AVX512_KNL 1 +# define CV_AVX_512ER 1 +# define CV_AVX_512PF 1 +#endif +#ifdef CV_CPU_COMPILE_AVX512_KNM +# define CV_AVX512_KNM 1 +# define CV_AVX_5124FMAPS 1 +# define CV_AVX_5124VNNIW 1 +# define CV_AVX_512VPOPCNTDQ 1 +#endif +#ifdef CV_CPU_COMPILE_AVX512_SKX +# define CV_AVX512_SKX 1 +# define CV_AVX_512VL 1 +# define CV_AVX_512BW 1 +# define CV_AVX_512DQ 1 +#endif +#ifdef CV_CPU_COMPILE_AVX512_CNL +# define CV_AVX512_CNL 1 +# define CV_AVX_512IFMA 1 +# define CV_AVX_512VBMI 1 +#endif +#ifdef CV_CPU_COMPILE_AVX512_CLX +# define CV_AVX512_CLX 1 +# define CV_AVX_512VNNI 1 +#endif +#ifdef CV_CPU_COMPILE_AVX512_ICL +# define CV_AVX512_ICL 1 +# undef CV_AVX_512IFMA +# define CV_AVX_512IFMA 1 +# undef CV_AVX_512VBMI +# define CV_AVX_512VBMI 1 +# undef CV_AVX_512VNNI +# define CV_AVX_512VNNI 1 +# define CV_AVX_512VBMI2 1 +# define CV_AVX_512BITALG 1 +# define CV_AVX_512VPOPCNTDQ 1 +#endif +#ifdef CV_CPU_COMPILE_FMA3 +# define CV_FMA3 1 +#endif + +#if defined _WIN32 && (defined(_M_ARM) || defined(_M_ARM64)) && (defined(CV_CPU_COMPILE_NEON) || !defined(_MSC_VER)) +# include +# include +# define CV_NEON 1 +#elif defined(__ARM_NEON__) || (defined (__ARM_NEON) && defined(__aarch64__)) +# include +# define CV_NEON 1 +#endif + +#if defined(__riscv) && defined(__riscv_vector) && defined(__riscv_vector_071) +# include +# define CV_RVV071 1 +#endif + +#if defined(__ARM_NEON__) || defined(__aarch64__) +# include +#endif + +#ifdef CV_CPU_COMPILE_VSX +# include +# undef vector +# undef pixel +# undef bool +# define CV_VSX 1 +#endif + +#ifdef CV_CPU_COMPILE_VSX3 +# define CV_VSX3 1 +#endif + +#ifdef CV_CPU_COMPILE_MSA +# include "hal/msa_macros.h" +# define CV_MSA 1 +#endif + +#ifdef __EMSCRIPTEN__ +# define CV_WASM_SIMD 1 +# include +#endif + +#if defined CV_CPU_COMPILE_RVV +# define CV_RVV 1 +# include +#endif + +#endif // CV_ENABLE_INTRINSICS && !CV_DISABLE_OPTIMIZATION && !__CUDACC__ + +#if defined CV_CPU_COMPILE_AVX && !defined CV_CPU_BASELINE_COMPILE_AVX +struct VZeroUpperGuard { +#ifdef __GNUC__ + __attribute__((always_inline)) +#endif + inline VZeroUpperGuard() { _mm256_zeroupper(); } +#ifdef __GNUC__ + __attribute__((always_inline)) +#endif + inline ~VZeroUpperGuard() { _mm256_zeroupper(); } +}; +#define __CV_AVX_GUARD VZeroUpperGuard __vzeroupper_guard; CV_UNUSED(__vzeroupper_guard); +#endif + +#ifdef __CV_AVX_GUARD +#define CV_AVX_GUARD __CV_AVX_GUARD +#else +#define CV_AVX_GUARD +#endif + +#endif // __OPENCV_BUILD + + + +#if !defined __OPENCV_BUILD /* Compatibility code */ \ + && !defined __CUDACC__ /* do not include SSE/AVX/NEON headers for NVCC compiler */ +#if defined __SSE2__ || defined _M_X64 || (defined _M_IX86_FP && _M_IX86_FP >= 2) +# include +# define CV_MMX 1 +# define CV_SSE 1 +# define CV_SSE2 1 +#elif defined _WIN32 && (defined(_M_ARM) || defined(_M_ARM64)) && (defined(CV_CPU_COMPILE_NEON) || !defined(_MSC_VER)) +# include +# include +# define CV_NEON 1 +#elif defined(__ARM_NEON__) || (defined (__ARM_NEON) && defined(__aarch64__)) +# include +# define CV_NEON 1 +#elif defined(__VSX__) && defined(__PPC64__) && defined(__LITTLE_ENDIAN__) +# include +# undef vector +# undef pixel +# undef bool +# define CV_VSX 1 +#endif + +#ifdef __F16C__ +# include +# define CV_FP16 1 +#endif + +#endif // !__OPENCV_BUILD && !__CUDACC (Compatibility code) + + + +#ifndef CV_MMX +# define CV_MMX 0 +#endif +#ifndef CV_SSE +# define CV_SSE 0 +#endif +#ifndef CV_SSE2 +# define CV_SSE2 0 +#endif +#ifndef CV_SSE3 +# define CV_SSE3 0 +#endif +#ifndef CV_SSSE3 +# define CV_SSSE3 0 +#endif +#ifndef CV_SSE4_1 +# define CV_SSE4_1 0 +#endif +#ifndef CV_SSE4_2 +# define CV_SSE4_2 0 +#endif +#ifndef CV_POPCNT +# define CV_POPCNT 0 +#endif +#ifndef CV_AVX +# define CV_AVX 0 +#endif +#ifndef CV_FP16 +# define CV_FP16 0 +#endif +#ifndef CV_AVX2 +# define CV_AVX2 0 +#endif +#ifndef CV_FMA3 +# define CV_FMA3 0 +#endif +#ifndef CV_AVX_512F +# define CV_AVX_512F 0 +#endif +#ifndef CV_AVX_512BW +# define CV_AVX_512BW 0 +#endif +#ifndef CV_AVX_512CD +# define CV_AVX_512CD 0 +#endif +#ifndef CV_AVX_512DQ +# define CV_AVX_512DQ 0 +#endif +#ifndef CV_AVX_512ER +# define CV_AVX_512ER 0 +#endif +#ifndef CV_AVX_512IFMA +# define CV_AVX_512IFMA 0 +#endif +#define CV_AVX_512IFMA512 CV_AVX_512IFMA // deprecated +#ifndef CV_AVX_512PF +# define CV_AVX_512PF 0 +#endif +#ifndef CV_AVX_512VBMI +# define CV_AVX_512VBMI 0 +#endif +#ifndef CV_AVX_512VL +# define CV_AVX_512VL 0 +#endif +#ifndef CV_AVX_5124FMAPS +# define CV_AVX_5124FMAPS 0 +#endif +#ifndef CV_AVX_5124VNNIW +# define CV_AVX_5124VNNIW 0 +#endif +#ifndef CV_AVX_512VPOPCNTDQ +# define CV_AVX_512VPOPCNTDQ 0 +#endif +#ifndef CV_AVX_512VNNI +# define CV_AVX_512VNNI 0 +#endif +#ifndef CV_AVX_512VBMI2 +# define CV_AVX_512VBMI2 0 +#endif +#ifndef CV_AVX_512BITALG +# define CV_AVX_512BITALG 0 +#endif +#ifndef CV_AVX512_COMMON +# define CV_AVX512_COMMON 0 +#endif +#ifndef CV_AVX512_KNL +# define CV_AVX512_KNL 0 +#endif +#ifndef CV_AVX512_KNM +# define CV_AVX512_KNM 0 +#endif +#ifndef CV_AVX512_SKX +# define CV_AVX512_SKX 0 +#endif +#ifndef CV_AVX512_CNL +# define CV_AVX512_CNL 0 +#endif +#ifndef CV_AVX512_CLX +# define CV_AVX512_CLX 0 +#endif +#ifndef CV_AVX512_ICL +# define CV_AVX512_ICL 0 +#endif + +#ifndef CV_NEON +# define CV_NEON 0 +#endif + +#ifndef CV_RVV071 +# define CV_RVV071 0 +#endif + +#ifndef CV_VSX +# define CV_VSX 0 +#endif + +#ifndef CV_VSX3 +# define CV_VSX3 0 +#endif + +#ifndef CV_MSA +# define CV_MSA 0 +#endif + +#ifndef CV_WASM_SIMD +# define CV_WASM_SIMD 0 +#endif + +#ifndef CV_RVV +# define CV_RVV 0 +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cv_cpu_helper.h b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cv_cpu_helper.h new file mode 100644 index 0000000..39ae0b9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cv_cpu_helper.h @@ -0,0 +1,508 @@ +// AUTOGENERATED, DO NOT EDIT + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSE +# define CV_TRY_SSE 1 +# define CV_CPU_FORCE_SSE 1 +# define CV_CPU_HAS_SUPPORT_SSE 1 +# define CV_CPU_CALL_SSE(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_SSE_(fn, args) return (opt_SSE::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSE +# define CV_TRY_SSE 1 +# define CV_CPU_FORCE_SSE 0 +# define CV_CPU_HAS_SUPPORT_SSE (cv::checkHardwareSupport(CV_CPU_SSE)) +# define CV_CPU_CALL_SSE(fn, args) if (CV_CPU_HAS_SUPPORT_SSE) return (opt_SSE::fn args) +# define CV_CPU_CALL_SSE_(fn, args) if (CV_CPU_HAS_SUPPORT_SSE) return (opt_SSE::fn args) +#else +# define CV_TRY_SSE 0 +# define CV_CPU_FORCE_SSE 0 +# define CV_CPU_HAS_SUPPORT_SSE 0 +# define CV_CPU_CALL_SSE(fn, args) +# define CV_CPU_CALL_SSE_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_SSE(fn, args, mode, ...) CV_CPU_CALL_SSE(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSE2 +# define CV_TRY_SSE2 1 +# define CV_CPU_FORCE_SSE2 1 +# define CV_CPU_HAS_SUPPORT_SSE2 1 +# define CV_CPU_CALL_SSE2(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_SSE2_(fn, args) return (opt_SSE2::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSE2 +# define CV_TRY_SSE2 1 +# define CV_CPU_FORCE_SSE2 0 +# define CV_CPU_HAS_SUPPORT_SSE2 (cv::checkHardwareSupport(CV_CPU_SSE2)) +# define CV_CPU_CALL_SSE2(fn, args) if (CV_CPU_HAS_SUPPORT_SSE2) return (opt_SSE2::fn args) +# define CV_CPU_CALL_SSE2_(fn, args) if (CV_CPU_HAS_SUPPORT_SSE2) return (opt_SSE2::fn args) +#else +# define CV_TRY_SSE2 0 +# define CV_CPU_FORCE_SSE2 0 +# define CV_CPU_HAS_SUPPORT_SSE2 0 +# define CV_CPU_CALL_SSE2(fn, args) +# define CV_CPU_CALL_SSE2_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_SSE2(fn, args, mode, ...) CV_CPU_CALL_SSE2(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSE3 +# define CV_TRY_SSE3 1 +# define CV_CPU_FORCE_SSE3 1 +# define CV_CPU_HAS_SUPPORT_SSE3 1 +# define CV_CPU_CALL_SSE3(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_SSE3_(fn, args) return (opt_SSE3::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSE3 +# define CV_TRY_SSE3 1 +# define CV_CPU_FORCE_SSE3 0 +# define CV_CPU_HAS_SUPPORT_SSE3 (cv::checkHardwareSupport(CV_CPU_SSE3)) +# define CV_CPU_CALL_SSE3(fn, args) if (CV_CPU_HAS_SUPPORT_SSE3) return (opt_SSE3::fn args) +# define CV_CPU_CALL_SSE3_(fn, args) if (CV_CPU_HAS_SUPPORT_SSE3) return (opt_SSE3::fn args) +#else +# define CV_TRY_SSE3 0 +# define CV_CPU_FORCE_SSE3 0 +# define CV_CPU_HAS_SUPPORT_SSE3 0 +# define CV_CPU_CALL_SSE3(fn, args) +# define CV_CPU_CALL_SSE3_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_SSE3(fn, args, mode, ...) CV_CPU_CALL_SSE3(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSSE3 +# define CV_TRY_SSSE3 1 +# define CV_CPU_FORCE_SSSE3 1 +# define CV_CPU_HAS_SUPPORT_SSSE3 1 +# define CV_CPU_CALL_SSSE3(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_SSSE3_(fn, args) return (opt_SSSE3::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSSE3 +# define CV_TRY_SSSE3 1 +# define CV_CPU_FORCE_SSSE3 0 +# define CV_CPU_HAS_SUPPORT_SSSE3 (cv::checkHardwareSupport(CV_CPU_SSSE3)) +# define CV_CPU_CALL_SSSE3(fn, args) if (CV_CPU_HAS_SUPPORT_SSSE3) return (opt_SSSE3::fn args) +# define CV_CPU_CALL_SSSE3_(fn, args) if (CV_CPU_HAS_SUPPORT_SSSE3) return (opt_SSSE3::fn args) +#else +# define CV_TRY_SSSE3 0 +# define CV_CPU_FORCE_SSSE3 0 +# define CV_CPU_HAS_SUPPORT_SSSE3 0 +# define CV_CPU_CALL_SSSE3(fn, args) +# define CV_CPU_CALL_SSSE3_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_SSSE3(fn, args, mode, ...) CV_CPU_CALL_SSSE3(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSE4_1 +# define CV_TRY_SSE4_1 1 +# define CV_CPU_FORCE_SSE4_1 1 +# define CV_CPU_HAS_SUPPORT_SSE4_1 1 +# define CV_CPU_CALL_SSE4_1(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_SSE4_1_(fn, args) return (opt_SSE4_1::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSE4_1 +# define CV_TRY_SSE4_1 1 +# define CV_CPU_FORCE_SSE4_1 0 +# define CV_CPU_HAS_SUPPORT_SSE4_1 (cv::checkHardwareSupport(CV_CPU_SSE4_1)) +# define CV_CPU_CALL_SSE4_1(fn, args) if (CV_CPU_HAS_SUPPORT_SSE4_1) return (opt_SSE4_1::fn args) +# define CV_CPU_CALL_SSE4_1_(fn, args) if (CV_CPU_HAS_SUPPORT_SSE4_1) return (opt_SSE4_1::fn args) +#else +# define CV_TRY_SSE4_1 0 +# define CV_CPU_FORCE_SSE4_1 0 +# define CV_CPU_HAS_SUPPORT_SSE4_1 0 +# define CV_CPU_CALL_SSE4_1(fn, args) +# define CV_CPU_CALL_SSE4_1_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_SSE4_1(fn, args, mode, ...) CV_CPU_CALL_SSE4_1(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SSE4_2 +# define CV_TRY_SSE4_2 1 +# define CV_CPU_FORCE_SSE4_2 1 +# define CV_CPU_HAS_SUPPORT_SSE4_2 1 +# define CV_CPU_CALL_SSE4_2(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_SSE4_2_(fn, args) return (opt_SSE4_2::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SSE4_2 +# define CV_TRY_SSE4_2 1 +# define CV_CPU_FORCE_SSE4_2 0 +# define CV_CPU_HAS_SUPPORT_SSE4_2 (cv::checkHardwareSupport(CV_CPU_SSE4_2)) +# define CV_CPU_CALL_SSE4_2(fn, args) if (CV_CPU_HAS_SUPPORT_SSE4_2) return (opt_SSE4_2::fn args) +# define CV_CPU_CALL_SSE4_2_(fn, args) if (CV_CPU_HAS_SUPPORT_SSE4_2) return (opt_SSE4_2::fn args) +#else +# define CV_TRY_SSE4_2 0 +# define CV_CPU_FORCE_SSE4_2 0 +# define CV_CPU_HAS_SUPPORT_SSE4_2 0 +# define CV_CPU_CALL_SSE4_2(fn, args) +# define CV_CPU_CALL_SSE4_2_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_SSE4_2(fn, args, mode, ...) CV_CPU_CALL_SSE4_2(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_POPCNT +# define CV_TRY_POPCNT 1 +# define CV_CPU_FORCE_POPCNT 1 +# define CV_CPU_HAS_SUPPORT_POPCNT 1 +# define CV_CPU_CALL_POPCNT(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_POPCNT_(fn, args) return (opt_POPCNT::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_POPCNT +# define CV_TRY_POPCNT 1 +# define CV_CPU_FORCE_POPCNT 0 +# define CV_CPU_HAS_SUPPORT_POPCNT (cv::checkHardwareSupport(CV_CPU_POPCNT)) +# define CV_CPU_CALL_POPCNT(fn, args) if (CV_CPU_HAS_SUPPORT_POPCNT) return (opt_POPCNT::fn args) +# define CV_CPU_CALL_POPCNT_(fn, args) if (CV_CPU_HAS_SUPPORT_POPCNT) return (opt_POPCNT::fn args) +#else +# define CV_TRY_POPCNT 0 +# define CV_CPU_FORCE_POPCNT 0 +# define CV_CPU_HAS_SUPPORT_POPCNT 0 +# define CV_CPU_CALL_POPCNT(fn, args) +# define CV_CPU_CALL_POPCNT_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_POPCNT(fn, args, mode, ...) CV_CPU_CALL_POPCNT(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_AVX +# define CV_TRY_AVX 1 +# define CV_CPU_FORCE_AVX 1 +# define CV_CPU_HAS_SUPPORT_AVX 1 +# define CV_CPU_CALL_AVX(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_AVX_(fn, args) return (opt_AVX::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_AVX +# define CV_TRY_AVX 1 +# define CV_CPU_FORCE_AVX 0 +# define CV_CPU_HAS_SUPPORT_AVX (cv::checkHardwareSupport(CV_CPU_AVX)) +# define CV_CPU_CALL_AVX(fn, args) if (CV_CPU_HAS_SUPPORT_AVX) return (opt_AVX::fn args) +# define CV_CPU_CALL_AVX_(fn, args) if (CV_CPU_HAS_SUPPORT_AVX) return (opt_AVX::fn args) +#else +# define CV_TRY_AVX 0 +# define CV_CPU_FORCE_AVX 0 +# define CV_CPU_HAS_SUPPORT_AVX 0 +# define CV_CPU_CALL_AVX(fn, args) +# define CV_CPU_CALL_AVX_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX(fn, args, mode, ...) CV_CPU_CALL_AVX(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_FP16 +# define CV_TRY_FP16 1 +# define CV_CPU_FORCE_FP16 1 +# define CV_CPU_HAS_SUPPORT_FP16 1 +# define CV_CPU_CALL_FP16(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_FP16_(fn, args) return (opt_FP16::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_FP16 +# define CV_TRY_FP16 1 +# define CV_CPU_FORCE_FP16 0 +# define CV_CPU_HAS_SUPPORT_FP16 (cv::checkHardwareSupport(CV_CPU_FP16)) +# define CV_CPU_CALL_FP16(fn, args) if (CV_CPU_HAS_SUPPORT_FP16) return (opt_FP16::fn args) +# define CV_CPU_CALL_FP16_(fn, args) if (CV_CPU_HAS_SUPPORT_FP16) return (opt_FP16::fn args) +#else +# define CV_TRY_FP16 0 +# define CV_CPU_FORCE_FP16 0 +# define CV_CPU_HAS_SUPPORT_FP16 0 +# define CV_CPU_CALL_FP16(fn, args) +# define CV_CPU_CALL_FP16_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_FP16(fn, args, mode, ...) CV_CPU_CALL_FP16(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_AVX2 +# define CV_TRY_AVX2 1 +# define CV_CPU_FORCE_AVX2 1 +# define CV_CPU_HAS_SUPPORT_AVX2 1 +# define CV_CPU_CALL_AVX2(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_AVX2_(fn, args) return (opt_AVX2::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_AVX2 +# define CV_TRY_AVX2 1 +# define CV_CPU_FORCE_AVX2 0 +# define CV_CPU_HAS_SUPPORT_AVX2 (cv::checkHardwareSupport(CV_CPU_AVX2)) +# define CV_CPU_CALL_AVX2(fn, args) if (CV_CPU_HAS_SUPPORT_AVX2) return (opt_AVX2::fn args) +# define CV_CPU_CALL_AVX2_(fn, args) if (CV_CPU_HAS_SUPPORT_AVX2) return (opt_AVX2::fn args) +#else +# define CV_TRY_AVX2 0 +# define CV_CPU_FORCE_AVX2 0 +# define CV_CPU_HAS_SUPPORT_AVX2 0 +# define CV_CPU_CALL_AVX2(fn, args) +# define CV_CPU_CALL_AVX2_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX2(fn, args, mode, ...) CV_CPU_CALL_AVX2(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_FMA3 +# define CV_TRY_FMA3 1 +# define CV_CPU_FORCE_FMA3 1 +# define CV_CPU_HAS_SUPPORT_FMA3 1 +# define CV_CPU_CALL_FMA3(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_FMA3_(fn, args) return (opt_FMA3::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_FMA3 +# define CV_TRY_FMA3 1 +# define CV_CPU_FORCE_FMA3 0 +# define CV_CPU_HAS_SUPPORT_FMA3 (cv::checkHardwareSupport(CV_CPU_FMA3)) +# define CV_CPU_CALL_FMA3(fn, args) if (CV_CPU_HAS_SUPPORT_FMA3) return (opt_FMA3::fn args) +# define CV_CPU_CALL_FMA3_(fn, args) if (CV_CPU_HAS_SUPPORT_FMA3) return (opt_FMA3::fn args) +#else +# define CV_TRY_FMA3 0 +# define CV_CPU_FORCE_FMA3 0 +# define CV_CPU_HAS_SUPPORT_FMA3 0 +# define CV_CPU_CALL_FMA3(fn, args) +# define CV_CPU_CALL_FMA3_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_FMA3(fn, args, mode, ...) CV_CPU_CALL_FMA3(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_AVX_512F +# define CV_TRY_AVX_512F 1 +# define CV_CPU_FORCE_AVX_512F 1 +# define CV_CPU_HAS_SUPPORT_AVX_512F 1 +# define CV_CPU_CALL_AVX_512F(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_AVX_512F_(fn, args) return (opt_AVX_512F::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_AVX_512F +# define CV_TRY_AVX_512F 1 +# define CV_CPU_FORCE_AVX_512F 0 +# define CV_CPU_HAS_SUPPORT_AVX_512F (cv::checkHardwareSupport(CV_CPU_AVX_512F)) +# define CV_CPU_CALL_AVX_512F(fn, args) if (CV_CPU_HAS_SUPPORT_AVX_512F) return (opt_AVX_512F::fn args) +# define CV_CPU_CALL_AVX_512F_(fn, args) if (CV_CPU_HAS_SUPPORT_AVX_512F) return (opt_AVX_512F::fn args) +#else +# define CV_TRY_AVX_512F 0 +# define CV_CPU_FORCE_AVX_512F 0 +# define CV_CPU_HAS_SUPPORT_AVX_512F 0 +# define CV_CPU_CALL_AVX_512F(fn, args) +# define CV_CPU_CALL_AVX_512F_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX_512F(fn, args, mode, ...) CV_CPU_CALL_AVX_512F(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_AVX512_COMMON +# define CV_TRY_AVX512_COMMON 1 +# define CV_CPU_FORCE_AVX512_COMMON 1 +# define CV_CPU_HAS_SUPPORT_AVX512_COMMON 1 +# define CV_CPU_CALL_AVX512_COMMON(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_AVX512_COMMON_(fn, args) return (opt_AVX512_COMMON::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_AVX512_COMMON +# define CV_TRY_AVX512_COMMON 1 +# define CV_CPU_FORCE_AVX512_COMMON 0 +# define CV_CPU_HAS_SUPPORT_AVX512_COMMON (cv::checkHardwareSupport(CV_CPU_AVX512_COMMON)) +# define CV_CPU_CALL_AVX512_COMMON(fn, args) if (CV_CPU_HAS_SUPPORT_AVX512_COMMON) return (opt_AVX512_COMMON::fn args) +# define CV_CPU_CALL_AVX512_COMMON_(fn, args) if (CV_CPU_HAS_SUPPORT_AVX512_COMMON) return (opt_AVX512_COMMON::fn args) +#else +# define CV_TRY_AVX512_COMMON 0 +# define CV_CPU_FORCE_AVX512_COMMON 0 +# define CV_CPU_HAS_SUPPORT_AVX512_COMMON 0 +# define CV_CPU_CALL_AVX512_COMMON(fn, args) +# define CV_CPU_CALL_AVX512_COMMON_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX512_COMMON(fn, args, mode, ...) CV_CPU_CALL_AVX512_COMMON(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_AVX512_KNL +# define CV_TRY_AVX512_KNL 1 +# define CV_CPU_FORCE_AVX512_KNL 1 +# define CV_CPU_HAS_SUPPORT_AVX512_KNL 1 +# define CV_CPU_CALL_AVX512_KNL(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_AVX512_KNL_(fn, args) return (opt_AVX512_KNL::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_AVX512_KNL +# define CV_TRY_AVX512_KNL 1 +# define CV_CPU_FORCE_AVX512_KNL 0 +# define CV_CPU_HAS_SUPPORT_AVX512_KNL (cv::checkHardwareSupport(CV_CPU_AVX512_KNL)) +# define CV_CPU_CALL_AVX512_KNL(fn, args) if (CV_CPU_HAS_SUPPORT_AVX512_KNL) return (opt_AVX512_KNL::fn args) +# define CV_CPU_CALL_AVX512_KNL_(fn, args) if (CV_CPU_HAS_SUPPORT_AVX512_KNL) return (opt_AVX512_KNL::fn args) +#else +# define CV_TRY_AVX512_KNL 0 +# define CV_CPU_FORCE_AVX512_KNL 0 +# define CV_CPU_HAS_SUPPORT_AVX512_KNL 0 +# define CV_CPU_CALL_AVX512_KNL(fn, args) +# define CV_CPU_CALL_AVX512_KNL_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX512_KNL(fn, args, mode, ...) CV_CPU_CALL_AVX512_KNL(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_AVX512_KNM +# define CV_TRY_AVX512_KNM 1 +# define CV_CPU_FORCE_AVX512_KNM 1 +# define CV_CPU_HAS_SUPPORT_AVX512_KNM 1 +# define CV_CPU_CALL_AVX512_KNM(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_AVX512_KNM_(fn, args) return (opt_AVX512_KNM::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_AVX512_KNM +# define CV_TRY_AVX512_KNM 1 +# define CV_CPU_FORCE_AVX512_KNM 0 +# define CV_CPU_HAS_SUPPORT_AVX512_KNM (cv::checkHardwareSupport(CV_CPU_AVX512_KNM)) +# define CV_CPU_CALL_AVX512_KNM(fn, args) if (CV_CPU_HAS_SUPPORT_AVX512_KNM) return (opt_AVX512_KNM::fn args) +# define CV_CPU_CALL_AVX512_KNM_(fn, args) if (CV_CPU_HAS_SUPPORT_AVX512_KNM) return (opt_AVX512_KNM::fn args) +#else +# define CV_TRY_AVX512_KNM 0 +# define CV_CPU_FORCE_AVX512_KNM 0 +# define CV_CPU_HAS_SUPPORT_AVX512_KNM 0 +# define CV_CPU_CALL_AVX512_KNM(fn, args) +# define CV_CPU_CALL_AVX512_KNM_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX512_KNM(fn, args, mode, ...) CV_CPU_CALL_AVX512_KNM(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_AVX512_SKX +# define CV_TRY_AVX512_SKX 1 +# define CV_CPU_FORCE_AVX512_SKX 1 +# define CV_CPU_HAS_SUPPORT_AVX512_SKX 1 +# define CV_CPU_CALL_AVX512_SKX(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_AVX512_SKX_(fn, args) return (opt_AVX512_SKX::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_AVX512_SKX +# define CV_TRY_AVX512_SKX 1 +# define CV_CPU_FORCE_AVX512_SKX 0 +# define CV_CPU_HAS_SUPPORT_AVX512_SKX (cv::checkHardwareSupport(CV_CPU_AVX512_SKX)) +# define CV_CPU_CALL_AVX512_SKX(fn, args) if (CV_CPU_HAS_SUPPORT_AVX512_SKX) return (opt_AVX512_SKX::fn args) +# define CV_CPU_CALL_AVX512_SKX_(fn, args) if (CV_CPU_HAS_SUPPORT_AVX512_SKX) return (opt_AVX512_SKX::fn args) +#else +# define CV_TRY_AVX512_SKX 0 +# define CV_CPU_FORCE_AVX512_SKX 0 +# define CV_CPU_HAS_SUPPORT_AVX512_SKX 0 +# define CV_CPU_CALL_AVX512_SKX(fn, args) +# define CV_CPU_CALL_AVX512_SKX_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX512_SKX(fn, args, mode, ...) CV_CPU_CALL_AVX512_SKX(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_AVX512_CNL +# define CV_TRY_AVX512_CNL 1 +# define CV_CPU_FORCE_AVX512_CNL 1 +# define CV_CPU_HAS_SUPPORT_AVX512_CNL 1 +# define CV_CPU_CALL_AVX512_CNL(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_AVX512_CNL_(fn, args) return (opt_AVX512_CNL::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_AVX512_CNL +# define CV_TRY_AVX512_CNL 1 +# define CV_CPU_FORCE_AVX512_CNL 0 +# define CV_CPU_HAS_SUPPORT_AVX512_CNL (cv::checkHardwareSupport(CV_CPU_AVX512_CNL)) +# define CV_CPU_CALL_AVX512_CNL(fn, args) if (CV_CPU_HAS_SUPPORT_AVX512_CNL) return (opt_AVX512_CNL::fn args) +# define CV_CPU_CALL_AVX512_CNL_(fn, args) if (CV_CPU_HAS_SUPPORT_AVX512_CNL) return (opt_AVX512_CNL::fn args) +#else +# define CV_TRY_AVX512_CNL 0 +# define CV_CPU_FORCE_AVX512_CNL 0 +# define CV_CPU_HAS_SUPPORT_AVX512_CNL 0 +# define CV_CPU_CALL_AVX512_CNL(fn, args) +# define CV_CPU_CALL_AVX512_CNL_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX512_CNL(fn, args, mode, ...) CV_CPU_CALL_AVX512_CNL(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_AVX512_CLX +# define CV_TRY_AVX512_CLX 1 +# define CV_CPU_FORCE_AVX512_CLX 1 +# define CV_CPU_HAS_SUPPORT_AVX512_CLX 1 +# define CV_CPU_CALL_AVX512_CLX(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_AVX512_CLX_(fn, args) return (opt_AVX512_CLX::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_AVX512_CLX +# define CV_TRY_AVX512_CLX 1 +# define CV_CPU_FORCE_AVX512_CLX 0 +# define CV_CPU_HAS_SUPPORT_AVX512_CLX (cv::checkHardwareSupport(CV_CPU_AVX512_CLX)) +# define CV_CPU_CALL_AVX512_CLX(fn, args) if (CV_CPU_HAS_SUPPORT_AVX512_CLX) return (opt_AVX512_CLX::fn args) +# define CV_CPU_CALL_AVX512_CLX_(fn, args) if (CV_CPU_HAS_SUPPORT_AVX512_CLX) return (opt_AVX512_CLX::fn args) +#else +# define CV_TRY_AVX512_CLX 0 +# define CV_CPU_FORCE_AVX512_CLX 0 +# define CV_CPU_HAS_SUPPORT_AVX512_CLX 0 +# define CV_CPU_CALL_AVX512_CLX(fn, args) +# define CV_CPU_CALL_AVX512_CLX_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX512_CLX(fn, args, mode, ...) CV_CPU_CALL_AVX512_CLX(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_AVX512_ICL +# define CV_TRY_AVX512_ICL 1 +# define CV_CPU_FORCE_AVX512_ICL 1 +# define CV_CPU_HAS_SUPPORT_AVX512_ICL 1 +# define CV_CPU_CALL_AVX512_ICL(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_AVX512_ICL_(fn, args) return (opt_AVX512_ICL::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_AVX512_ICL +# define CV_TRY_AVX512_ICL 1 +# define CV_CPU_FORCE_AVX512_ICL 0 +# define CV_CPU_HAS_SUPPORT_AVX512_ICL (cv::checkHardwareSupport(CV_CPU_AVX512_ICL)) +# define CV_CPU_CALL_AVX512_ICL(fn, args) if (CV_CPU_HAS_SUPPORT_AVX512_ICL) return (opt_AVX512_ICL::fn args) +# define CV_CPU_CALL_AVX512_ICL_(fn, args) if (CV_CPU_HAS_SUPPORT_AVX512_ICL) return (opt_AVX512_ICL::fn args) +#else +# define CV_TRY_AVX512_ICL 0 +# define CV_CPU_FORCE_AVX512_ICL 0 +# define CV_CPU_HAS_SUPPORT_AVX512_ICL 0 +# define CV_CPU_CALL_AVX512_ICL(fn, args) +# define CV_CPU_CALL_AVX512_ICL_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX512_ICL(fn, args, mode, ...) CV_CPU_CALL_AVX512_ICL(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_NEON +# define CV_TRY_NEON 1 +# define CV_CPU_FORCE_NEON 1 +# define CV_CPU_HAS_SUPPORT_NEON 1 +# define CV_CPU_CALL_NEON(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_NEON_(fn, args) return (opt_NEON::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_NEON +# define CV_TRY_NEON 1 +# define CV_CPU_FORCE_NEON 0 +# define CV_CPU_HAS_SUPPORT_NEON (cv::checkHardwareSupport(CV_CPU_NEON)) +# define CV_CPU_CALL_NEON(fn, args) if (CV_CPU_HAS_SUPPORT_NEON) return (opt_NEON::fn args) +# define CV_CPU_CALL_NEON_(fn, args) if (CV_CPU_HAS_SUPPORT_NEON) return (opt_NEON::fn args) +#else +# define CV_TRY_NEON 0 +# define CV_CPU_FORCE_NEON 0 +# define CV_CPU_HAS_SUPPORT_NEON 0 +# define CV_CPU_CALL_NEON(fn, args) +# define CV_CPU_CALL_NEON_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_NEON(fn, args, mode, ...) CV_CPU_CALL_NEON(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_MSA +# define CV_TRY_MSA 1 +# define CV_CPU_FORCE_MSA 1 +# define CV_CPU_HAS_SUPPORT_MSA 1 +# define CV_CPU_CALL_MSA(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_MSA_(fn, args) return (opt_MSA::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_MSA +# define CV_TRY_MSA 1 +# define CV_CPU_FORCE_MSA 0 +# define CV_CPU_HAS_SUPPORT_MSA (cv::checkHardwareSupport(CV_CPU_MSA)) +# define CV_CPU_CALL_MSA(fn, args) if (CV_CPU_HAS_SUPPORT_MSA) return (opt_MSA::fn args) +# define CV_CPU_CALL_MSA_(fn, args) if (CV_CPU_HAS_SUPPORT_MSA) return (opt_MSA::fn args) +#else +# define CV_TRY_MSA 0 +# define CV_CPU_FORCE_MSA 0 +# define CV_CPU_HAS_SUPPORT_MSA 0 +# define CV_CPU_CALL_MSA(fn, args) +# define CV_CPU_CALL_MSA_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_MSA(fn, args, mode, ...) CV_CPU_CALL_MSA(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_VSX +# define CV_TRY_VSX 1 +# define CV_CPU_FORCE_VSX 1 +# define CV_CPU_HAS_SUPPORT_VSX 1 +# define CV_CPU_CALL_VSX(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_VSX_(fn, args) return (opt_VSX::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_VSX +# define CV_TRY_VSX 1 +# define CV_CPU_FORCE_VSX 0 +# define CV_CPU_HAS_SUPPORT_VSX (cv::checkHardwareSupport(CV_CPU_VSX)) +# define CV_CPU_CALL_VSX(fn, args) if (CV_CPU_HAS_SUPPORT_VSX) return (opt_VSX::fn args) +# define CV_CPU_CALL_VSX_(fn, args) if (CV_CPU_HAS_SUPPORT_VSX) return (opt_VSX::fn args) +#else +# define CV_TRY_VSX 0 +# define CV_CPU_FORCE_VSX 0 +# define CV_CPU_HAS_SUPPORT_VSX 0 +# define CV_CPU_CALL_VSX(fn, args) +# define CV_CPU_CALL_VSX_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_VSX(fn, args, mode, ...) CV_CPU_CALL_VSX(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_VSX3 +# define CV_TRY_VSX3 1 +# define CV_CPU_FORCE_VSX3 1 +# define CV_CPU_HAS_SUPPORT_VSX3 1 +# define CV_CPU_CALL_VSX3(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_VSX3_(fn, args) return (opt_VSX3::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_VSX3 +# define CV_TRY_VSX3 1 +# define CV_CPU_FORCE_VSX3 0 +# define CV_CPU_HAS_SUPPORT_VSX3 (cv::checkHardwareSupport(CV_CPU_VSX3)) +# define CV_CPU_CALL_VSX3(fn, args) if (CV_CPU_HAS_SUPPORT_VSX3) return (opt_VSX3::fn args) +# define CV_CPU_CALL_VSX3_(fn, args) if (CV_CPU_HAS_SUPPORT_VSX3) return (opt_VSX3::fn args) +#else +# define CV_TRY_VSX3 0 +# define CV_CPU_FORCE_VSX3 0 +# define CV_CPU_HAS_SUPPORT_VSX3 0 +# define CV_CPU_CALL_VSX3(fn, args) +# define CV_CPU_CALL_VSX3_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_VSX3(fn, args, mode, ...) CV_CPU_CALL_VSX3(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_RVV +# define CV_TRY_RVV 1 +# define CV_CPU_FORCE_RVV 1 +# define CV_CPU_HAS_SUPPORT_RVV 1 +# define CV_CPU_CALL_RVV(fn, args) return (cpu_baseline::fn args) +# define CV_CPU_CALL_RVV_(fn, args) return (opt_RVV::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_RVV +# define CV_TRY_RVV 1 +# define CV_CPU_FORCE_RVV 0 +# define CV_CPU_HAS_SUPPORT_RVV (cv::checkHardwareSupport(CV_CPU_RVV)) +# define CV_CPU_CALL_RVV(fn, args) if (CV_CPU_HAS_SUPPORT_RVV) return (opt_RVV::fn args) +# define CV_CPU_CALL_RVV_(fn, args) if (CV_CPU_HAS_SUPPORT_RVV) return (opt_RVV::fn args) +#else +# define CV_TRY_RVV 0 +# define CV_CPU_FORCE_RVV 0 +# define CV_CPU_HAS_SUPPORT_RVV 0 +# define CV_CPU_CALL_RVV(fn, args) +# define CV_CPU_CALL_RVV_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_RVV(fn, args, mode, ...) CV_CPU_CALL_RVV(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__)) + +#define CV_CPU_CALL_BASELINE(fn, args) return (cpu_baseline::fn args) +#define __CV_CPU_DISPATCH_CHAIN_BASELINE(fn, args, mode, ...) CV_CPU_CALL_BASELINE(fn, args) /* last in sequence */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cvdef.h b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cvdef.h new file mode 100644 index 0000000..f785f32 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cvdef.h @@ -0,0 +1,967 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_CVDEF_H +#define OPENCV_CORE_CVDEF_H + +#include "opencv2/core/version.hpp" + +//! @addtogroup core_utils +//! @{ + +#ifdef OPENCV_INCLUDE_PORT_FILE // User-provided header file with custom platform configuration +#include OPENCV_INCLUDE_PORT_FILE +#endif + +#if !defined CV_DOXYGEN && !defined CV_IGNORE_DEBUG_BUILD_GUARD +#if (defined(_MSC_VER) && (defined(DEBUG) || defined(_DEBUG))) || \ + (defined(_GLIBCXX_DEBUG) || defined(_GLIBCXX_DEBUG_PEDANTIC)) +// Guard to prevent using of binary incompatible binaries / runtimes +// https://github.com/opencv/opencv/pull/9161 +#define CV__DEBUG_NS_BEGIN namespace debug_build_guard { +#define CV__DEBUG_NS_END } +namespace cv { namespace debug_build_guard { } using namespace debug_build_guard; } +#endif +#endif + +#ifndef CV__DEBUG_NS_BEGIN +#define CV__DEBUG_NS_BEGIN +#define CV__DEBUG_NS_END +#endif + + +#ifdef __OPENCV_BUILD +#include "cvconfig.h" +#endif + +#ifndef __CV_EXPAND +#define __CV_EXPAND(x) x +#endif + +#ifndef __CV_CAT +#define __CV_CAT__(x, y) x ## y +#define __CV_CAT_(x, y) __CV_CAT__(x, y) +#define __CV_CAT(x, y) __CV_CAT_(x, y) +#endif + +#define __CV_VA_NUM_ARGS_HELPER(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N +#define __CV_VA_NUM_ARGS(...) __CV_EXPAND(__CV_VA_NUM_ARGS_HELPER(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) + +#ifdef CV_Func +// keep current value (through OpenCV port file) +#elif defined __GNUC__ || (defined (__cpluscplus) && (__cpluscplus >= 201103)) +#define CV_Func __func__ +#elif defined __clang__ && (__clang_minor__ * 100 + __clang_major__ >= 305) +#define CV_Func __func__ +#elif defined(__STDC_VERSION__) && (__STDC_VERSION >= 199901) +#define CV_Func __func__ +#elif defined _MSC_VER +#define CV_Func __FUNCTION__ +#elif defined(__INTEL_COMPILER) && (_INTEL_COMPILER >= 600) +#define CV_Func __FUNCTION__ +#elif defined __IBMCPP__ && __IBMCPP__ >=500 +#define CV_Func __FUNCTION__ +#elif defined __BORLAND__ && (__BORLANDC__ >= 0x550) +#define CV_Func __FUNC__ +#else +#define CV_Func "" +#endif + +//! @cond IGNORED + +//////////////// static assert ///////////////// +#define CVAUX_CONCAT_EXP(a, b) a##b +#define CVAUX_CONCAT(a, b) CVAUX_CONCAT_EXP(a,b) + +#if defined(__clang__) +# ifndef __has_extension +# define __has_extension __has_feature /* compatibility, for older versions of clang */ +# endif +# if __has_extension(cxx_static_assert) +# define CV_StaticAssert(condition, reason) static_assert((condition), reason " " #condition) +# elif __has_extension(c_static_assert) +# define CV_StaticAssert(condition, reason) _Static_assert((condition), reason " " #condition) +# endif +#elif defined(__GNUC__) +# if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L) +# define CV_StaticAssert(condition, reason) static_assert((condition), reason " " #condition) +# endif +#elif defined(_MSC_VER) +# if _MSC_VER >= 1600 /* MSVC 10 */ +# define CV_StaticAssert(condition, reason) static_assert((condition), reason " " #condition) +# endif +#endif +#ifndef CV_StaticAssert +# if !defined(__clang__) && defined(__GNUC__) && (__GNUC__*100 + __GNUC_MINOR__ > 302) +# define CV_StaticAssert(condition, reason) ({ extern int __attribute__((error("CV_StaticAssert: " reason " " #condition))) CV_StaticAssert(); ((condition) ? 0 : CV_StaticAssert()); }) +# else +namespace cv { + template struct CV_StaticAssert_failed; + template <> struct CV_StaticAssert_failed { enum { val = 1 }; }; + template struct CV_StaticAssert_test {}; +} +# define CV_StaticAssert(condition, reason)\ + typedef cv::CV_StaticAssert_test< sizeof(cv::CV_StaticAssert_failed< static_cast(condition) >) > CVAUX_CONCAT(CV_StaticAssert_failed_at_, __LINE__) +# endif +#endif + +// Suppress warning "-Wdeprecated-declarations" / C4996 +#if defined(_MSC_VER) + #define CV_DO_PRAGMA(x) __pragma(x) +#elif defined(__GNUC__) + #define CV_DO_PRAGMA(x) _Pragma (#x) +#else + #define CV_DO_PRAGMA(x) +#endif + +#ifdef _MSC_VER +#define CV_SUPPRESS_DEPRECATED_START \ + CV_DO_PRAGMA(warning(push)) \ + CV_DO_PRAGMA(warning(disable: 4996)) +#define CV_SUPPRESS_DEPRECATED_END CV_DO_PRAGMA(warning(pop)) +#elif defined (__clang__) || ((__GNUC__) && (__GNUC__*100 + __GNUC_MINOR__ > 405)) +#define CV_SUPPRESS_DEPRECATED_START \ + CV_DO_PRAGMA(GCC diagnostic push) \ + CV_DO_PRAGMA(GCC diagnostic ignored "-Wdeprecated-declarations") +#define CV_SUPPRESS_DEPRECATED_END CV_DO_PRAGMA(GCC diagnostic pop) +#else +#define CV_SUPPRESS_DEPRECATED_START +#define CV_SUPPRESS_DEPRECATED_END +#endif + +#define CV_UNUSED(name) (void)name + +//! @endcond + +// undef problematic defines sometimes defined by system headers (windows.h in particular) +#undef small +#undef min +#undef max +#undef abs +#undef Complex + +#if defined __cplusplus +#include +#else +#include +#endif + +#include "opencv2/core/hal/interface.h" + +#if defined __ICL +# define CV_ICC __ICL +#elif defined __ICC +# define CV_ICC __ICC +#elif defined __ECL +# define CV_ICC __ECL +#elif defined __ECC +# define CV_ICC __ECC +#elif defined __INTEL_COMPILER +# define CV_ICC __INTEL_COMPILER +#endif + +#ifndef CV_INLINE +# if defined __cplusplus +# define CV_INLINE static inline +# elif defined _MSC_VER +# define CV_INLINE __inline +# else +# define CV_INLINE static +# endif +#endif + +#ifndef CV_ALWAYS_INLINE +#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#define CV_ALWAYS_INLINE inline __attribute__((always_inline)) +#elif defined(_MSC_VER) +#define CV_ALWAYS_INLINE __forceinline +#else +#define CV_ALWAYS_INLINE inline +#endif +#endif + +#if defined CV_DISABLE_OPTIMIZATION || (defined CV_ICC && !defined CV_ENABLE_UNROLLED) +# define CV_ENABLE_UNROLLED 0 +#else +# define CV_ENABLE_UNROLLED 1 +#endif + +#ifdef __GNUC__ +# define CV_DECL_ALIGNED(x) __attribute__ ((aligned (x))) +#elif defined _MSC_VER +# define CV_DECL_ALIGNED(x) __declspec(align(x)) +#else +# define CV_DECL_ALIGNED(x) +#endif + +/* CPU features and intrinsics support */ +#define CV_CPU_NONE 0 +#define CV_CPU_MMX 1 +#define CV_CPU_SSE 2 +#define CV_CPU_SSE2 3 +#define CV_CPU_SSE3 4 +#define CV_CPU_SSSE3 5 +#define CV_CPU_SSE4_1 6 +#define CV_CPU_SSE4_2 7 +#define CV_CPU_POPCNT 8 +#define CV_CPU_FP16 9 +#define CV_CPU_AVX 10 +#define CV_CPU_AVX2 11 +#define CV_CPU_FMA3 12 + +#define CV_CPU_AVX_512F 13 +#define CV_CPU_AVX_512BW 14 +#define CV_CPU_AVX_512CD 15 +#define CV_CPU_AVX_512DQ 16 +#define CV_CPU_AVX_512ER 17 +#define CV_CPU_AVX_512IFMA512 18 // deprecated +#define CV_CPU_AVX_512IFMA 18 +#define CV_CPU_AVX_512PF 19 +#define CV_CPU_AVX_512VBMI 20 +#define CV_CPU_AVX_512VL 21 +#define CV_CPU_AVX_512VBMI2 22 +#define CV_CPU_AVX_512VNNI 23 +#define CV_CPU_AVX_512BITALG 24 +#define CV_CPU_AVX_512VPOPCNTDQ 25 +#define CV_CPU_AVX_5124VNNIW 26 +#define CV_CPU_AVX_5124FMAPS 27 + +#define CV_CPU_NEON 100 + +#define CV_CPU_MSA 150 + +#define CV_CPU_RISCVV 170 + +#define CV_CPU_VSX 200 +#define CV_CPU_VSX3 201 + +#define CV_CPU_RVV 210 + +// CPU features groups +#define CV_CPU_AVX512_SKX 256 +#define CV_CPU_AVX512_COMMON 257 +#define CV_CPU_AVX512_KNL 258 +#define CV_CPU_AVX512_KNM 259 +#define CV_CPU_AVX512_CNL 260 +#define CV_CPU_AVX512_CLX 261 +#define CV_CPU_AVX512_ICL 262 + +// when adding to this list remember to update the following enum +#define CV_HARDWARE_MAX_FEATURE 512 + +/** @brief Available CPU features. +*/ +enum CpuFeatures { + CPU_MMX = 1, + CPU_SSE = 2, + CPU_SSE2 = 3, + CPU_SSE3 = 4, + CPU_SSSE3 = 5, + CPU_SSE4_1 = 6, + CPU_SSE4_2 = 7, + CPU_POPCNT = 8, + CPU_FP16 = 9, + CPU_AVX = 10, + CPU_AVX2 = 11, + CPU_FMA3 = 12, + + CPU_AVX_512F = 13, + CPU_AVX_512BW = 14, + CPU_AVX_512CD = 15, + CPU_AVX_512DQ = 16, + CPU_AVX_512ER = 17, + CPU_AVX_512IFMA512 = 18, // deprecated + CPU_AVX_512IFMA = 18, + CPU_AVX_512PF = 19, + CPU_AVX_512VBMI = 20, + CPU_AVX_512VL = 21, + CPU_AVX_512VBMI2 = 22, + CPU_AVX_512VNNI = 23, + CPU_AVX_512BITALG = 24, + CPU_AVX_512VPOPCNTDQ= 25, + CPU_AVX_5124VNNIW = 26, + CPU_AVX_5124FMAPS = 27, + + CPU_NEON = 100, + + CPU_MSA = 150, + + CPU_RISCVV = 170, + + CPU_VSX = 200, + CPU_VSX3 = 201, + + CPU_RVV = 210, + + CPU_AVX512_SKX = 256, //!< Skylake-X with AVX-512F/CD/BW/DQ/VL + CPU_AVX512_COMMON = 257, //!< Common instructions AVX-512F/CD for all CPUs that support AVX-512 + CPU_AVX512_KNL = 258, //!< Knights Landing with AVX-512F/CD/ER/PF + CPU_AVX512_KNM = 259, //!< Knights Mill with AVX-512F/CD/ER/PF/4FMAPS/4VNNIW/VPOPCNTDQ + CPU_AVX512_CNL = 260, //!< Cannon Lake with AVX-512F/CD/BW/DQ/VL/IFMA/VBMI + CPU_AVX512_CLX = 261, //!< Cascade Lake with AVX-512F/CD/BW/DQ/VL/VNNI + CPU_AVX512_ICL = 262, //!< Ice Lake with AVX-512F/CD/BW/DQ/VL/IFMA/VBMI/VNNI/VBMI2/BITALG/VPOPCNTDQ + + CPU_MAX_FEATURE = 512 // see CV_HARDWARE_MAX_FEATURE +}; + + +#include "cv_cpu_dispatch.h" + +#if !defined(CV_STRONG_ALIGNMENT) && defined(__arm__) && !(defined(__aarch64__) || defined(_M_ARM64)) +// int*, int64* should be propertly aligned pointers on ARMv7 +#define CV_STRONG_ALIGNMENT 1 +#endif +#if !defined(CV_STRONG_ALIGNMENT) +#define CV_STRONG_ALIGNMENT 0 +#endif + +/* fundamental constants */ +#define CV_PI 3.1415926535897932384626433832795 +#define CV_2PI 6.283185307179586476925286766559 +#define CV_LOG2 0.69314718055994530941723212145818 + +#if defined __ARM_FP16_FORMAT_IEEE \ + && !defined __CUDACC__ +# define CV_FP16_TYPE 1 +#else +# define CV_FP16_TYPE 0 +#endif + +typedef union Cv16suf +{ + short i; + ushort u; +#if CV_FP16_TYPE + __fp16 h; +#endif +} +Cv16suf; + +typedef union Cv32suf +{ + int i; + unsigned u; + float f; +} +Cv32suf; + +typedef union Cv64suf +{ + int64 i; + uint64 u; + double f; +} +Cv64suf; + +#ifndef OPENCV_ABI_COMPATIBILITY +#define OPENCV_ABI_COMPATIBILITY 400 +#endif + +#ifdef __OPENCV_BUILD +# define DISABLE_OPENCV_3_COMPATIBILITY +# define OPENCV_DISABLE_DEPRECATED_COMPATIBILITY +#endif + +#ifndef CV_EXPORTS +# if (defined _WIN32 || defined WINCE || defined __CYGWIN__) && defined(CVAPI_EXPORTS) +# define CV_EXPORTS __declspec(dllexport) +# elif defined __GNUC__ && __GNUC__ >= 4 && (defined(CVAPI_EXPORTS) || defined(__APPLE__)) +# define CV_EXPORTS __attribute__ ((visibility ("default"))) +# endif +#endif + +#ifndef CV_EXPORTS +# define CV_EXPORTS +#endif + +#ifdef _MSC_VER +# define CV_EXPORTS_TEMPLATE +#else +# define CV_EXPORTS_TEMPLATE CV_EXPORTS +#endif + +#ifndef CV_DEPRECATED +# if defined(__GNUC__) +# define CV_DEPRECATED __attribute__ ((deprecated)) +# elif defined(_MSC_VER) +# define CV_DEPRECATED __declspec(deprecated) +# else +# define CV_DEPRECATED +# endif +#endif + +#ifndef CV_DEPRECATED_EXTERNAL +# if defined(__OPENCV_BUILD) +# define CV_DEPRECATED_EXTERNAL /* nothing */ +# else +# define CV_DEPRECATED_EXTERNAL CV_DEPRECATED +# endif +#endif + + +#ifndef CV_EXTERN_C +# ifdef __cplusplus +# define CV_EXTERN_C extern "C" +# else +# define CV_EXTERN_C +# endif +#endif + +/* special informative macros for wrapper generators */ +#define CV_EXPORTS_W CV_EXPORTS +#define CV_EXPORTS_W_SIMPLE CV_EXPORTS +#define CV_EXPORTS_AS(synonym) CV_EXPORTS +#define CV_EXPORTS_W_MAP CV_EXPORTS +#define CV_IN_OUT +#define CV_OUT +#define CV_PROP +#define CV_PROP_RW +#define CV_WRAP +#define CV_WRAP_AS(synonym) +#define CV_WRAP_MAPPABLE(mappable) +#define CV_WRAP_PHANTOM(phantom_header) +#define CV_WRAP_DEFAULT(val) + +/****************************************************************************************\ +* Matrix type (Mat) * +\****************************************************************************************/ + +#define CV_MAT_CN_MASK ((CV_CN_MAX - 1) << CV_CN_SHIFT) +#define CV_MAT_CN(flags) ((((flags) & CV_MAT_CN_MASK) >> CV_CN_SHIFT) + 1) +#define CV_MAT_TYPE_MASK (CV_DEPTH_MAX*CV_CN_MAX - 1) +#define CV_MAT_TYPE(flags) ((flags) & CV_MAT_TYPE_MASK) +#define CV_MAT_CONT_FLAG_SHIFT 14 +#define CV_MAT_CONT_FLAG (1 << CV_MAT_CONT_FLAG_SHIFT) +#define CV_IS_MAT_CONT(flags) ((flags) & CV_MAT_CONT_FLAG) +#define CV_IS_CONT_MAT CV_IS_MAT_CONT +#define CV_SUBMAT_FLAG_SHIFT 15 +#define CV_SUBMAT_FLAG (1 << CV_SUBMAT_FLAG_SHIFT) +#define CV_IS_SUBMAT(flags) ((flags) & CV_MAT_SUBMAT_FLAG) + +/** Size of each channel item, + 0x28442211 = 0010 1000 0100 0100 0010 0010 0001 0001 ~ array of sizeof(arr_type_elem) */ +#define CV_ELEM_SIZE1(type) ((0x28442211 >> CV_MAT_DEPTH(type)*4) & 15) + +#define CV_ELEM_SIZE(type) (CV_MAT_CN(type)*CV_ELEM_SIZE1(type)) + +#ifndef MIN +# define MIN(a,b) ((a) > (b) ? (b) : (a)) +#endif + +#ifndef MAX +# define MAX(a,b) ((a) < (b) ? (b) : (a)) +#endif + +///////////////////////////////////////// Enum operators /////////////////////////////////////// + +/** + +Provides compatibility operators for both classical and C++11 enum classes, +as well as exposing the C++11 enum class members for backwards compatibility + +@code + // Provides operators required for flag enums + CV_ENUM_FLAGS(AccessFlag) + + // Exposes the listed members of the enum class AccessFlag to the current namespace + CV_ENUM_CLASS_EXPOSE(AccessFlag, ACCESS_READ [, ACCESS_WRITE [, ...] ]); +@endcode +*/ + +#define __CV_ENUM_CLASS_EXPOSE_1(EnumType, MEMBER_CONST) \ +static const EnumType MEMBER_CONST = EnumType::MEMBER_CONST; \ + +#define __CV_ENUM_CLASS_EXPOSE_2(EnumType, MEMBER_CONST, ...) \ +__CV_ENUM_CLASS_EXPOSE_1(EnumType, MEMBER_CONST); \ +__CV_EXPAND(__CV_ENUM_CLASS_EXPOSE_1(EnumType, __VA_ARGS__)); \ + +#define __CV_ENUM_CLASS_EXPOSE_3(EnumType, MEMBER_CONST, ...) \ +__CV_ENUM_CLASS_EXPOSE_1(EnumType, MEMBER_CONST); \ +__CV_EXPAND(__CV_ENUM_CLASS_EXPOSE_2(EnumType, __VA_ARGS__)); \ + +#define __CV_ENUM_CLASS_EXPOSE_4(EnumType, MEMBER_CONST, ...) \ +__CV_ENUM_CLASS_EXPOSE_1(EnumType, MEMBER_CONST); \ +__CV_EXPAND(__CV_ENUM_CLASS_EXPOSE_3(EnumType, __VA_ARGS__)); \ + +#define __CV_ENUM_CLASS_EXPOSE_5(EnumType, MEMBER_CONST, ...) \ +__CV_ENUM_CLASS_EXPOSE_1(EnumType, MEMBER_CONST); \ +__CV_EXPAND(__CV_ENUM_CLASS_EXPOSE_4(EnumType, __VA_ARGS__)); \ + +#define __CV_ENUM_CLASS_EXPOSE_6(EnumType, MEMBER_CONST, ...) \ +__CV_ENUM_CLASS_EXPOSE_1(EnumType, MEMBER_CONST); \ +__CV_EXPAND(__CV_ENUM_CLASS_EXPOSE_5(EnumType, __VA_ARGS__)); \ + +#define __CV_ENUM_CLASS_EXPOSE_7(EnumType, MEMBER_CONST, ...) \ +__CV_ENUM_CLASS_EXPOSE_1(EnumType, MEMBER_CONST); \ +__CV_EXPAND(__CV_ENUM_CLASS_EXPOSE_6(EnumType, __VA_ARGS__)); \ + +#define __CV_ENUM_CLASS_EXPOSE_8(EnumType, MEMBER_CONST, ...) \ +__CV_ENUM_CLASS_EXPOSE_1(EnumType, MEMBER_CONST); \ +__CV_EXPAND(__CV_ENUM_CLASS_EXPOSE_7(EnumType, __VA_ARGS__)); \ + +#define __CV_ENUM_CLASS_EXPOSE_9(EnumType, MEMBER_CONST, ...) \ +__CV_ENUM_CLASS_EXPOSE_1(EnumType, MEMBER_CONST); \ +__CV_EXPAND(__CV_ENUM_CLASS_EXPOSE_8(EnumType, __VA_ARGS__)); \ + +#define __CV_ENUM_FLAGS_LOGICAL_NOT(EnumType) \ +static inline bool operator!(const EnumType& val) \ +{ \ + typedef std::underlying_type::type UnderlyingType; \ + return !static_cast(val); \ +} \ + +#define __CV_ENUM_FLAGS_LOGICAL_NOT_EQ(Arg1Type, Arg2Type) \ +static inline bool operator!=(const Arg1Type& a, const Arg2Type& b) \ +{ \ + return static_cast(a) != static_cast(b); \ +} \ + +#define __CV_ENUM_FLAGS_LOGICAL_EQ(Arg1Type, Arg2Type) \ +static inline bool operator==(const Arg1Type& a, const Arg2Type& b) \ +{ \ + return static_cast(a) == static_cast(b); \ +} \ + +#define __CV_ENUM_FLAGS_BITWISE_NOT(EnumType) \ +static inline EnumType operator~(const EnumType& val) \ +{ \ + typedef std::underlying_type::type UnderlyingType; \ + return static_cast(~static_cast(val)); \ +} \ + +#define __CV_ENUM_FLAGS_BITWISE_OR(EnumType, Arg1Type, Arg2Type) \ +static inline EnumType operator|(const Arg1Type& a, const Arg2Type& b) \ +{ \ + typedef std::underlying_type::type UnderlyingType; \ + return static_cast(static_cast(a) | static_cast(b)); \ +} \ + +#define __CV_ENUM_FLAGS_BITWISE_AND(EnumType, Arg1Type, Arg2Type) \ +static inline EnumType operator&(const Arg1Type& a, const Arg2Type& b) \ +{ \ + typedef std::underlying_type::type UnderlyingType; \ + return static_cast(static_cast(a) & static_cast(b)); \ +} \ + +#define __CV_ENUM_FLAGS_BITWISE_XOR(EnumType, Arg1Type, Arg2Type) \ +static inline EnumType operator^(const Arg1Type& a, const Arg2Type& b) \ +{ \ + typedef std::underlying_type::type UnderlyingType; \ + return static_cast(static_cast(a) ^ static_cast(b)); \ +} \ + +#define __CV_ENUM_FLAGS_BITWISE_OR_EQ(EnumType, Arg1Type) \ +static inline EnumType& operator|=(EnumType& _this, const Arg1Type& val) \ +{ \ + _this = static_cast(static_cast(_this) | static_cast(val)); \ + return _this; \ +} \ + +#define __CV_ENUM_FLAGS_BITWISE_AND_EQ(EnumType, Arg1Type) \ +static inline EnumType& operator&=(EnumType& _this, const Arg1Type& val) \ +{ \ + _this = static_cast(static_cast(_this) & static_cast(val)); \ + return _this; \ +} \ + +#define __CV_ENUM_FLAGS_BITWISE_XOR_EQ(EnumType, Arg1Type) \ +static inline EnumType& operator^=(EnumType& _this, const Arg1Type& val) \ +{ \ + _this = static_cast(static_cast(_this) ^ static_cast(val)); \ + return _this; \ +} \ + +#define CV_ENUM_CLASS_EXPOSE(EnumType, ...) \ +__CV_EXPAND(__CV_CAT(__CV_ENUM_CLASS_EXPOSE_, __CV_VA_NUM_ARGS(__VA_ARGS__))(EnumType, __VA_ARGS__)); \ + +#define CV_ENUM_FLAGS(EnumType) \ +__CV_ENUM_FLAGS_LOGICAL_NOT (EnumType) \ +__CV_ENUM_FLAGS_LOGICAL_EQ (EnumType, int) \ +__CV_ENUM_FLAGS_LOGICAL_NOT_EQ (EnumType, int) \ + \ +__CV_ENUM_FLAGS_BITWISE_NOT (EnumType) \ +__CV_ENUM_FLAGS_BITWISE_OR (EnumType, EnumType, EnumType) \ +__CV_ENUM_FLAGS_BITWISE_AND (EnumType, EnumType, EnumType) \ +__CV_ENUM_FLAGS_BITWISE_XOR (EnumType, EnumType, EnumType) \ + \ +__CV_ENUM_FLAGS_BITWISE_OR_EQ (EnumType, EnumType) \ +__CV_ENUM_FLAGS_BITWISE_AND_EQ (EnumType, EnumType) \ +__CV_ENUM_FLAGS_BITWISE_XOR_EQ (EnumType, EnumType) \ + +/****************************************************************************************\ +* static analysys * +\****************************************************************************************/ + +// In practice, some macro are not processed correctly (noreturn is not detected). +// We need to use simplified definition for them. +#ifndef CV_STATIC_ANALYSIS +# if defined(__KLOCWORK__) || defined(__clang_analyzer__) || defined(__COVERITY__) +# define CV_STATIC_ANALYSIS 1 +# endif +#else +# if defined(CV_STATIC_ANALYSIS) && !(__CV_CAT(1, CV_STATIC_ANALYSIS) == 1) // defined and not empty +# if 0 == CV_STATIC_ANALYSIS +# undef CV_STATIC_ANALYSIS +# endif +# endif +#endif + +/****************************************************************************************\ +* Thread sanitizer * +\****************************************************************************************/ +#ifndef CV_THREAD_SANITIZER +# if defined(__has_feature) +# if __has_feature(thread_sanitizer) +# define CV_THREAD_SANITIZER +# endif +# endif +#endif + +/****************************************************************************************\ +* exchange-add operation for atomic operations on reference counters * +\****************************************************************************************/ + +#ifdef CV_XADD + // allow to use user-defined macro +#elif defined __GNUC__ || defined __clang__ +# if defined __clang__ && __clang_major__ >= 3 && !defined __ANDROID__ && !defined __EMSCRIPTEN__ && !defined(__CUDACC__) && !defined __INTEL_COMPILER +# ifdef __ATOMIC_ACQ_REL +# define CV_XADD(addr, delta) __c11_atomic_fetch_add((_Atomic(int)*)(addr), delta, __ATOMIC_ACQ_REL) +# else +# define CV_XADD(addr, delta) __atomic_fetch_add((_Atomic(int)*)(addr), delta, 4) +# endif +# else +# if defined __ATOMIC_ACQ_REL && !defined __clang__ + // version for gcc >= 4.7 +# define CV_XADD(addr, delta) (int)__atomic_fetch_add((unsigned*)(addr), (unsigned)(delta), __ATOMIC_ACQ_REL) +# else +# define CV_XADD(addr, delta) (int)__sync_fetch_and_add((unsigned*)(addr), (unsigned)(delta)) +# endif +# endif +#elif defined _MSC_VER && !defined RC_INVOKED +# include +# define CV_XADD(addr, delta) (int)_InterlockedExchangeAdd((long volatile*)addr, delta) +#else + #ifdef OPENCV_FORCE_UNSAFE_XADD + CV_INLINE int CV_XADD(int* addr, int delta) { int tmp = *addr; *addr += delta; return tmp; } + #else + #error "OpenCV: can't define safe CV_XADD macro for current platform (unsupported). Define CV_XADD macro through custom port header (see OPENCV_INCLUDE_PORT_FILE)" + #endif +#endif + + +/****************************************************************************************\ +* CV_NORETURN attribute * +\****************************************************************************************/ + +#ifndef CV_NORETURN +# if defined(__GNUC__) +# define CV_NORETURN __attribute__((__noreturn__)) +# elif defined(_MSC_VER) && (_MSC_VER >= 1300) +# define CV_NORETURN __declspec(noreturn) +# else +# define CV_NORETURN /* nothing by default */ +# endif +#endif + +/****************************************************************************************\ +* CV_NODISCARD_STD attribute (C++17) * +* encourages the compiler to issue a warning if the return value is discarded * +\****************************************************************************************/ +#ifndef CV_NODISCARD_STD +# ifndef __has_cpp_attribute +// workaround preprocessor non-compliance https://reviews.llvm.org/D57851 +# define __has_cpp_attribute(__x) 0 +# endif +# if __has_cpp_attribute(nodiscard) +# define CV_NODISCARD_STD [[nodiscard]] +# elif __cplusplus >= 201703L +// available when compiler is C++17 compliant +# define CV_NODISCARD_STD [[nodiscard]] +# elif defined(__INTEL_COMPILER) + // see above, available when C++17 is enabled +# elif defined(_MSC_VER) && _MSC_VER >= 1911 && _MSVC_LANG >= 201703L +// available with VS2017 v15.3+ with /std:c++17 or higher; works on functions and classes +# define CV_NODISCARD_STD [[nodiscard]] +# elif defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 700) && (__cplusplus >= 201103L) +// available with GCC 7.0+; works on functions, works or silently fails on classes +# define CV_NODISCARD_STD [[nodiscard]] +# elif defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 408) && (__cplusplus >= 201103L) +// available with GCC 4.8+ but it usually does nothing and can fail noisily -- therefore not used +// define CV_NODISCARD_STD [[gnu::warn_unused_result]] +# endif +#endif +#ifndef CV_NODISCARD_STD +# define CV_NODISCARD_STD /* nothing by default */ +#endif + + +/****************************************************************************************\ +* CV_NODISCARD attribute (deprecated, GCC only) * +* DONT USE: use instead the standard CV_NODISCARD_STD macro above * +* this legacy method silently fails to issue warning until some version * +* after gcc 6.3.0. Yet with gcc 7+ you can use the above standard method * +* which makes this method useless. Don't use it. * +* @deprecated use instead CV_NODISCARD_STD * +\****************************************************************************************/ +#ifndef CV_NODISCARD +# if defined(__GNUC__) +# define CV_NODISCARD __attribute__((__warn_unused_result__)) +# elif defined(__clang__) && defined(__has_attribute) +# if __has_attribute(__warn_unused_result__) +# define CV_NODISCARD __attribute__((__warn_unused_result__)) +# endif +# endif +#endif +#ifndef CV_NODISCARD +# define CV_NODISCARD /* nothing by default */ +#endif + + +/****************************************************************************************\ +* C++ 11 * +\****************************************************************************************/ +#ifndef CV_CXX11 +# if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800) +# define CV_CXX11 1 +# endif +#else +# if CV_CXX11 == 0 +# undef CV_CXX11 +# endif +#endif +#ifndef CV_CXX11 +# error "OpenCV 4.x+ requires enabled C++11 support" +#endif + +#define CV_CXX_MOVE_SEMANTICS 1 +#define CV_CXX_MOVE(x) std::move(x) +#define CV_CXX_STD_ARRAY 1 +#include +#ifndef CV_OVERRIDE +# define CV_OVERRIDE override +#endif +#ifndef CV_FINAL +# define CV_FINAL final +#endif + +#ifndef CV_NOEXCEPT +# if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900/*MSVS 2015*/) +# define CV_NOEXCEPT noexcept +# endif +#endif +#ifndef CV_NOEXCEPT +# define CV_NOEXCEPT +#endif + +#ifndef CV_CONSTEXPR +# if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900/*MSVS 2015*/) +# define CV_CONSTEXPR constexpr +# endif +#endif +#ifndef CV_CONSTEXPR +# define CV_CONSTEXPR +#endif + +// Integer types portatibility +#ifdef OPENCV_STDINT_HEADER +#include OPENCV_STDINT_HEADER +#elif defined(__cplusplus) +#if defined(_MSC_VER) && _MSC_VER < 1600 /* MSVS 2010 */ +namespace cv { +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef signed short int16_t; +typedef unsigned short uint16_t; +typedef signed int int32_t; +typedef unsigned int uint32_t; +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; +} +#elif defined(_MSC_VER) || __cplusplus >= 201103L +#include +namespace cv { +using std::int8_t; +using std::uint8_t; +using std::int16_t; +using std::uint16_t; +using std::int32_t; +using std::uint32_t; +using std::int64_t; +using std::uint64_t; +} +#else +#include +namespace cv { +typedef ::int8_t int8_t; +typedef ::uint8_t uint8_t; +typedef ::int16_t int16_t; +typedef ::uint16_t uint16_t; +typedef ::int32_t int32_t; +typedef ::uint32_t uint32_t; +typedef ::int64_t int64_t; +typedef ::uint64_t uint64_t; +} +#endif +#else // pure C +#include +#endif + +#ifdef __cplusplus +namespace cv +{ + +class float16_t +{ +public: +#if CV_FP16_TYPE + + float16_t() : h(0) {} + explicit float16_t(float x) { h = (__fp16)x; } + operator float() const { return (float)h; } + static float16_t fromBits(ushort w) + { + Cv16suf u; + u.u = w; + float16_t result; + result.h = u.h; + return result; + } + static float16_t zero() + { + float16_t result; + result.h = (__fp16)0; + return result; + } + ushort bits() const + { + Cv16suf u; + u.h = h; + return u.u; + } +protected: + __fp16 h; + +#else + float16_t() : w(0) {} + explicit float16_t(float x) + { + #if CV_FP16 + __m128 v = _mm_load_ss(&x); + w = (ushort)_mm_cvtsi128_si32(_mm_cvtps_ph(v, 0)); + #else + Cv32suf in; + in.f = x; + unsigned sign = in.u & 0x80000000; + in.u ^= sign; + + if( in.u >= 0x47800000 ) + w = (ushort)(in.u > 0x7f800000 ? 0x7e00 : 0x7c00); + else + { + if (in.u < 0x38800000) + { + in.f += 0.5f; + w = (ushort)(in.u - 0x3f000000); + } + else + { + unsigned t = in.u + 0xc8000fff; + w = (ushort)((t + ((in.u >> 13) & 1)) >> 13); + } + } + + w = (ushort)(w | (sign >> 16)); + #endif + } + + operator float() const + { + #if CV_FP16 + float f; + _mm_store_ss(&f, _mm_cvtph_ps(_mm_cvtsi32_si128(w))); + return f; + #else + Cv32suf out; + + unsigned t = ((w & 0x7fff) << 13) + 0x38000000; + unsigned sign = (w & 0x8000) << 16; + unsigned e = w & 0x7c00; + + out.u = t + (1 << 23); + out.u = (e >= 0x7c00 ? t + 0x38000000 : + e == 0 ? (static_cast(out.f -= 6.103515625e-05f), out.u) : t) | sign; + return out.f; + #endif + } + + static float16_t fromBits(ushort b) + { + float16_t result; + result.w = b; + return result; + } + static float16_t zero() + { + float16_t result; + result.w = (ushort)0; + return result; + } + ushort bits() const { return w; } +protected: + ushort w; + +#endif +}; + +} +#endif + +//! @} + +#ifndef __cplusplus +#include "opencv2/core/fast_math.hpp" // define cvRound(double) +#endif + +#endif // OPENCV_CORE_CVDEF_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cvstd.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cvstd.hpp new file mode 100644 index 0000000..6ce9e4b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cvstd.hpp @@ -0,0 +1,190 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_CVSTD_HPP +#define OPENCV_CORE_CVSTD_HPP + +#ifndef __cplusplus +# error cvstd.hpp header must be compiled as C++ +#endif + +#include "opencv2/core/cvdef.h" +#include +#include +#include + +#include + +// import useful primitives from stl +# include +# include +# include //for abs(int) +# include + +namespace cv +{ + static inline uchar abs(uchar a) { return a; } + static inline ushort abs(ushort a) { return a; } + static inline unsigned abs(unsigned a) { return a; } + static inline uint64 abs(uint64 a) { return a; } + + using std::min; + using std::max; + using std::abs; + using std::swap; + using std::sqrt; + using std::exp; + using std::pow; + using std::log; +} + +#include "cvstd_wrapper.hpp" + +namespace cv { + +//! @addtogroup core_utils +//! @{ + +//////////////////////////// memory management functions //////////////////////////// + +/** @brief Allocates an aligned memory buffer. + +The function allocates the buffer of the specified size and returns it. When the buffer size is 16 +bytes or more, the returned buffer is aligned to 16 bytes. +@param bufSize Allocated buffer size. + */ +CV_EXPORTS void* fastMalloc(size_t bufSize); + +/** @brief Deallocates a memory buffer. + +The function deallocates the buffer allocated with fastMalloc . If NULL pointer is passed, the +function does nothing. C version of the function clears the pointer *pptr* to avoid problems with +double memory deallocation. +@param ptr Pointer to the allocated buffer. + */ +CV_EXPORTS void fastFree(void* ptr); + +/*! + The STL-compliant memory Allocator based on cv::fastMalloc() and cv::fastFree() +*/ +template class Allocator +{ +public: + typedef _Tp value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + template class rebind { typedef Allocator other; }; + + explicit Allocator() {} + ~Allocator() {} + explicit Allocator(Allocator const&) {} + template + explicit Allocator(Allocator const&) {} + + // address + pointer address(reference r) { return &r; } + const_pointer address(const_reference r) { return &r; } + + pointer allocate(size_type count, const void* =0) { return reinterpret_cast(fastMalloc(count * sizeof (_Tp))); } + void deallocate(pointer p, size_type) { fastFree(p); } + + void construct(pointer p, const _Tp& v) { new(static_cast(p)) _Tp(v); } + void destroy(pointer p) { p->~_Tp(); } + + size_type max_size() const { return cv::max(static_cast<_Tp>(-1)/sizeof(_Tp), 1); } +}; + +//! @} core_utils + +//! @endcond + +//! @addtogroup core_basic +//! @{ + +//////////////////////////////// string class //////////////////////////////// + +class CV_EXPORTS FileNode; //for string constructor from FileNode + +typedef std::string String; + +#ifndef OPENCV_DISABLE_STRING_LOWER_UPPER_CONVERSIONS + +//! @cond IGNORED +namespace details { +// std::tolower is int->int +static inline char char_tolower(char ch) +{ + return (char)std::tolower((int)ch); +} +// std::toupper is int->int +static inline char char_toupper(char ch) +{ + return (char)std::toupper((int)ch); +} +} // namespace details +//! @endcond + +static inline std::string toLowerCase(const std::string& str) +{ + std::string result(str); + std::transform(result.begin(), result.end(), result.begin(), details::char_tolower); + return result; +} + +static inline std::string toUpperCase(const std::string& str) +{ + std::string result(str); + std::transform(result.begin(), result.end(), result.begin(), details::char_toupper); + return result; +} + +#endif // OPENCV_DISABLE_STRING_LOWER_UPPER_CONVERSIONS + +//! @} core_basic +} // cv + +#endif //OPENCV_CORE_CVSTD_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cvstd.inl.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cvstd.inl.hpp new file mode 100644 index 0000000..37ad1e6 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cvstd.inl.hpp @@ -0,0 +1,197 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_CVSTDINL_HPP +#define OPENCV_CORE_CVSTDINL_HPP + +#include +#include +#include + +//! @cond IGNORED + +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable: 4127 ) +#endif + +namespace cv +{ + +template class DataType< std::complex<_Tp> > +{ +public: + typedef std::complex<_Tp> value_type; + typedef value_type work_type; + typedef _Tp channel_type; + + enum { generic_type = 0, + depth = DataType::depth, + channels = 2, + fmt = DataType::fmt + ((channels - 1) << 8), + type = CV_MAKETYPE(depth, channels) }; + + typedef Vec vec_type; +}; + +static inline +std::ostream& operator << (std::ostream& out, Ptr fmtd) +{ + fmtd->reset(); + for(const char* str = fmtd->next(); str; str = fmtd->next()) + out << str; + return out; +} + +static inline +std::ostream& operator << (std::ostream& out, const Mat& mtx) +{ + return out << Formatter::get()->format(mtx); +} + +static inline +std::ostream& operator << (std::ostream& out, const UMat& m) +{ + return out << m.getMat(ACCESS_READ); +} + +template static inline +std::ostream& operator << (std::ostream& out, const Complex<_Tp>& c) +{ + return out << "(" << c.re << "," << c.im << ")"; +} + +template static inline +std::ostream& operator << (std::ostream& out, const std::vector >& vec) +{ + return out << Formatter::get()->format(Mat(vec)); +} + + +template static inline +std::ostream& operator << (std::ostream& out, const std::vector >& vec) +{ + return out << Formatter::get()->format(Mat(vec)); +} + + +template static inline +std::ostream& operator << (std::ostream& out, const Matx<_Tp, m, n>& matx) +{ + return out << Formatter::get()->format(Mat(matx)); +} + +template static inline +std::ostream& operator << (std::ostream& out, const Point_<_Tp>& p) +{ + out << "[" << p.x << ", " << p.y << "]"; + return out; +} + +template static inline +std::ostream& operator << (std::ostream& out, const Point3_<_Tp>& p) +{ + out << "[" << p.x << ", " << p.y << ", " << p.z << "]"; + return out; +} + +template static inline +std::ostream& operator << (std::ostream& out, const Vec<_Tp, n>& vec) +{ + out << "["; + if (cv::traits::Depth<_Tp>::value <= CV_32S) + { + for (int i = 0; i < n - 1; ++i) { + out << (int)vec[i] << ", "; + } + out << (int)vec[n-1] << "]"; + } + else + { + for (int i = 0; i < n - 1; ++i) { + out << vec[i] << ", "; + } + out << vec[n-1] << "]"; + } + + return out; +} + +template static inline +std::ostream& operator << (std::ostream& out, const Size_<_Tp>& size) +{ + return out << "[" << size.width << " x " << size.height << "]"; +} + +template static inline +std::ostream& operator << (std::ostream& out, const Rect_<_Tp>& rect) +{ + return out << "[" << rect.width << " x " << rect.height << " from (" << rect.x << ", " << rect.y << ")]"; +} + +static inline std::ostream& operator << (std::ostream& out, const MatSize& msize) +{ + int i, dims = msize.dims(); + for( i = 0; i < dims; i++ ) + { + out << msize[i]; + if( i < dims-1 ) + out << " x "; + } + return out; +} + +static inline std::ostream &operator<< (std::ostream &s, cv::Range &r) +{ + return s << "[" << r.start << " : " << r.end << ")"; +} + +} // cv + +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + +//! @endcond + +#endif // OPENCV_CORE_CVSTDINL_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cvstd_wrapper.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cvstd_wrapper.hpp new file mode 100644 index 0000000..25e0041 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/cvstd_wrapper.hpp @@ -0,0 +1,154 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_CVSTD_WRAPPER_HPP +#define OPENCV_CORE_CVSTD_WRAPPER_HPP + +#include "opencv2/core/cvdef.h" + +#include +#include // std::shared_ptr +#include // std::enable_if + +namespace cv { + +using std::nullptr_t; + +//! @addtogroup core_basic +//! @{ + +#ifdef CV_DOXYGEN + +template using Ptr = std::shared_ptr<_Tp>; // In ideal world it should look like this, but we need some compatibility workarounds below + +template static inline +Ptr<_Tp> makePtr(const A1&... a1) { return std::make_shared<_Tp>(a1...); } + +#else // cv::Ptr with compatibility workarounds + +// It should be defined for C-API types only. +// C++ types should use regular "delete" operator. +template struct DefaultDeleter; +#if 0 +{ + void operator()(Y* p) const; +}; +#endif + +namespace sfinae { +template +struct has_parenthesis_operator +{ +private: + template + static CV_CONSTEXPR std::true_type has_parenthesis_operator_check(typename std::is_same().operator()(std::declval()...))>::type, Ret>::type*); + + template static CV_CONSTEXPR std::false_type has_parenthesis_operator_check(...); + + typedef decltype(has_parenthesis_operator_check(0)) type; + +public: +#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900/*MSVS 2015*/) + static CV_CONSTEXPR bool value = type::value; +#else + // support MSVS 2013 + static const int value = type::value; +#endif +}; +} // namespace sfinae + +template +struct has_custom_delete + : public std::false_type {}; + +// Force has_custom_delete to std::false_type when NVCC is compiling CUDA source files +#ifndef __CUDACC__ +template +struct has_custom_delete, void, T*>::value >::type > + : public std::true_type {}; +#endif + +template +struct Ptr : public std::shared_ptr +{ +#if 0 + using std::shared_ptr::shared_ptr; // GCC 5.x can't handle this +#else + inline Ptr() CV_NOEXCEPT : std::shared_ptr() {} + inline Ptr(nullptr_t) CV_NOEXCEPT : std::shared_ptr(nullptr) {} + template inline Ptr(Y* p, D d) : std::shared_ptr(p, d) {} + template inline Ptr(nullptr_t, D d) : std::shared_ptr(nullptr, d) {} + + template inline Ptr(const Ptr& r, T* ptr) CV_NOEXCEPT : std::shared_ptr(r, ptr) {} + + inline Ptr(const Ptr& o) CV_NOEXCEPT : std::shared_ptr(o) {} + inline Ptr(Ptr&& o) CV_NOEXCEPT : std::shared_ptr(std::move(o)) {} + + template inline Ptr(const Ptr& o) CV_NOEXCEPT : std::shared_ptr(o) {} + template inline Ptr(Ptr&& o) CV_NOEXCEPT : std::shared_ptr(std::move(o)) {} +#endif + inline Ptr(const std::shared_ptr& o) CV_NOEXCEPT : std::shared_ptr(o) {} + inline Ptr(std::shared_ptr&& o) CV_NOEXCEPT : std::shared_ptr(std::move(o)) {} + + // Overload with custom DefaultDeleter: Ptr(...) + template + inline Ptr(const std::true_type&, Y* ptr) : std::shared_ptr(ptr, DefaultDeleter()) {} + + // Overload without custom deleter: Ptr(...); + template + inline Ptr(const std::false_type&, Y* ptr) : std::shared_ptr(ptr) {} + + template + inline Ptr(Y* ptr) : Ptr(has_custom_delete(), ptr) {} + + // Overload with custom DefaultDeleter: Ptr(...) + template + inline void reset(const std::true_type&, Y* ptr) { std::shared_ptr::reset(ptr, DefaultDeleter()); } + + // Overload without custom deleter: Ptr(...); + template + inline void reset(const std::false_type&, Y* ptr) { std::shared_ptr::reset(ptr); } + + template + inline void reset(Y* ptr) { Ptr::reset(has_custom_delete(), ptr); } + + template + void reset(Y* ptr, Deleter d) { std::shared_ptr::reset(ptr, d); } + + void reset() CV_NOEXCEPT { std::shared_ptr::reset(); } + + Ptr& operator=(const Ptr& o) { std::shared_ptr::operator =(o); return *this; } + template inline Ptr& operator=(const Ptr& o) { std::shared_ptr::operator =(o); return *this; } + + T* operator->() const CV_NOEXCEPT { return std::shared_ptr::get();} + typename std::add_lvalue_reference::type operator*() const CV_NOEXCEPT { return *std::shared_ptr::get(); } + + // OpenCV 3.x methods (not a part of standard C++ library) + inline void release() { std::shared_ptr::reset(); } + inline operator T* () const { return std::shared_ptr::get(); } + inline bool empty() const { return std::shared_ptr::get() == nullptr; } + + template inline + Ptr staticCast() const CV_NOEXCEPT { return std::static_pointer_cast(*this); } + + template inline + Ptr constCast() const CV_NOEXCEPT { return std::const_pointer_cast(*this); } + + template inline + Ptr dynamicCast() const CV_NOEXCEPT { return std::dynamic_pointer_cast(*this); } +}; + +template static inline +Ptr<_Tp> makePtr(const A1&... a1) +{ + static_assert( !has_custom_delete<_Tp>::value, "Can't use this makePtr with custom DefaultDeleter"); + return (Ptr<_Tp>)std::make_shared<_Tp>(a1...); +} + +#endif // CV_DOXYGEN + +//! @} core_basic +} // cv + +#endif //OPENCV_CORE_CVSTD_WRAPPER_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/detail/async_promise.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/detail/async_promise.hpp new file mode 100644 index 0000000..6eb3fb5 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/detail/async_promise.hpp @@ -0,0 +1,71 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_ASYNC_PROMISE_HPP +#define OPENCV_CORE_ASYNC_PROMISE_HPP + +#include "../async.hpp" + +#include "exception_ptr.hpp" + +namespace cv { + +/** @addtogroup core_async +@{ +*/ + + +/** @brief Provides result of asynchronous operations + +*/ +class CV_EXPORTS AsyncPromise +{ +public: + ~AsyncPromise() CV_NOEXCEPT; + AsyncPromise() CV_NOEXCEPT; + explicit AsyncPromise(const AsyncPromise& o) CV_NOEXCEPT; + AsyncPromise& operator=(const AsyncPromise& o) CV_NOEXCEPT; + void release() CV_NOEXCEPT; + + /** Returns associated AsyncArray + @note Can be called once + */ + AsyncArray getArrayResult(); + + /** Stores asynchronous result. + @param[in] value result + */ + void setValue(InputArray value); + + // TODO "move" setters + +#if CV__EXCEPTION_PTR + /** Stores exception. + @param[in] exception exception to be raised in AsyncArray + */ + void setException(std::exception_ptr exception); +#endif + + /** Stores exception. + @param[in] exception exception to be raised in AsyncArray + */ + void setException(const cv::Exception& exception); + +#ifdef CV_CXX11 + explicit AsyncPromise(AsyncPromise&& o) { p = o.p; o.p = NULL; } + AsyncPromise& operator=(AsyncPromise&& o) CV_NOEXCEPT { std::swap(p, o.p); return *this; } +#endif + + + // PImpl + typedef struct AsyncArray::Impl Impl; friend struct AsyncArray::Impl; + inline void* _getImpl() const CV_NOEXCEPT { return p; } +protected: + Impl* p; +}; + + +//! @} +} // namespace +#endif // OPENCV_CORE_ASYNC_PROMISE_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/detail/dispatch_helper.impl.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/detail/dispatch_helper.impl.hpp new file mode 100644 index 0000000..d6ec676 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/detail/dispatch_helper.impl.hpp @@ -0,0 +1,49 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_DETAIL_DISPATCH_HELPER_IMPL_HPP +#define OPENCV_CORE_DETAIL_DISPATCH_HELPER_IMPL_HPP + +//! @cond IGNORED + +namespace cv { +namespace detail { + +template class Functor, typename... Args> +static inline void depthDispatch(const int depth, Args&&... args) +{ + switch (depth) + { + case CV_8U: + Functor{}(std::forward(args)...); + break; + case CV_8S: + Functor{}(std::forward(args)...); + break; + case CV_16U: + Functor{}(std::forward(args)...); + break; + case CV_16S: + Functor{}(std::forward(args)...); + break; + case CV_32S: + Functor{}(std::forward(args)...); + break; + case CV_32F: + Functor{}(std::forward(args)...); + break; + case CV_64F: + Functor{}(std::forward(args)...); + break; + case CV_16F: + default: + CV_Error(cv::Error::BadDepth, "Unsupported matrix type."); + }; +} + +}} + +//! @endcond + +#endif //OPENCV_CORE_DETAIL_DISPATCH_HELPER_IMPL_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/detail/exception_ptr.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/detail/exception_ptr.hpp new file mode 100644 index 0000000..d98ffc4 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/detail/exception_ptr.hpp @@ -0,0 +1,27 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_DETAILS_EXCEPTION_PTR_H +#define OPENCV_CORE_DETAILS_EXCEPTION_PTR_H + +#ifndef CV__EXCEPTION_PTR +# if defined(__ANDROID__) && defined(ATOMIC_INT_LOCK_FREE) && ATOMIC_INT_LOCK_FREE < 2 +# define CV__EXCEPTION_PTR 0 // Not supported, details: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58938 +# elif defined(CV_CXX11) +# define CV__EXCEPTION_PTR 1 +# elif defined(_MSC_VER) +# define CV__EXCEPTION_PTR (_MSC_VER >= 1600) +# elif defined(__clang__) +# define CV__EXCEPTION_PTR 0 // C++11 only (see above) +# elif defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__) +# define CV__EXCEPTION_PTR (__GXX_EXPERIMENTAL_CXX0X__ > 0) +# endif +#endif +#ifndef CV__EXCEPTION_PTR +# define CV__EXCEPTION_PTR 0 +#elif CV__EXCEPTION_PTR +# include // std::exception_ptr +#endif + +#endif // OPENCV_CORE_DETAILS_EXCEPTION_PTR_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/directx.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/directx.hpp new file mode 100644 index 0000000..056a85a --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/directx.hpp @@ -0,0 +1,184 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 holders 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. +// +//M*/ + +#ifndef OPENCV_CORE_DIRECTX_HPP +#define OPENCV_CORE_DIRECTX_HPP + +#include "mat.hpp" +#include "ocl.hpp" + +#if !defined(__d3d11_h__) +struct ID3D11Device; +struct ID3D11Texture2D; +#endif + +#if !defined(__d3d10_h__) +struct ID3D10Device; +struct ID3D10Texture2D; +#endif + +#if !defined(_D3D9_H_) +struct IDirect3DDevice9; +struct IDirect3DDevice9Ex; +struct IDirect3DSurface9; +#endif + + +namespace cv { namespace directx { + +namespace ocl { +using namespace cv::ocl; + +//! @addtogroup core_directx +// This section describes OpenCL and DirectX interoperability. +// +// To enable DirectX support, configure OpenCV using CMake with WITH_DIRECTX=ON . Note, DirectX is +// supported only on Windows. +// +// To use OpenCL functionality you should first initialize OpenCL context from DirectX resource. +// +//! @{ + +// TODO static functions in the Context class +//! @brief Creates OpenCL context from D3D11 device +// +//! @param pD3D11Device - pointer to D3D11 device +//! @return Returns reference to OpenCL Context +CV_EXPORTS Context& initializeContextFromD3D11Device(ID3D11Device* pD3D11Device); + +//! @brief Creates OpenCL context from D3D10 device +// +//! @param pD3D10Device - pointer to D3D10 device +//! @return Returns reference to OpenCL Context +CV_EXPORTS Context& initializeContextFromD3D10Device(ID3D10Device* pD3D10Device); + +//! @brief Creates OpenCL context from Direct3DDevice9Ex device +// +//! @param pDirect3DDevice9Ex - pointer to Direct3DDevice9Ex device +//! @return Returns reference to OpenCL Context +CV_EXPORTS Context& initializeContextFromDirect3DDevice9Ex(IDirect3DDevice9Ex* pDirect3DDevice9Ex); + +//! @brief Creates OpenCL context from Direct3DDevice9 device +// +//! @param pDirect3DDevice9 - pointer to Direct3Device9 device +//! @return Returns reference to OpenCL Context +CV_EXPORTS Context& initializeContextFromDirect3DDevice9(IDirect3DDevice9* pDirect3DDevice9); + +//! @} + +} // namespace cv::directx::ocl + +//! @addtogroup core_directx +//! @{ + +//! @brief Converts InputArray to ID3D11Texture2D. If destination texture format is DXGI_FORMAT_NV12 then +//! input UMat expected to be in BGR format and data will be downsampled and color-converted to NV12. +// +//! @note Note: Destination texture must be allocated by application. Function does memory copy from src to +//! pD3D11Texture2D +// +//! @param src - source InputArray +//! @param pD3D11Texture2D - destination D3D11 texture +CV_EXPORTS void convertToD3D11Texture2D(InputArray src, ID3D11Texture2D* pD3D11Texture2D); + +//! @brief Converts ID3D11Texture2D to OutputArray. If input texture format is DXGI_FORMAT_NV12 then +//! data will be upsampled and color-converted to BGR format. +// +//! @note Note: Destination matrix will be re-allocated if it has not enough memory to match texture size. +//! function does memory copy from pD3D11Texture2D to dst +// +//! @param pD3D11Texture2D - source D3D11 texture +//! @param dst - destination OutputArray +CV_EXPORTS void convertFromD3D11Texture2D(ID3D11Texture2D* pD3D11Texture2D, OutputArray dst); + +//! @brief Converts InputArray to ID3D10Texture2D +// +//! @note Note: function does memory copy from src to +//! pD3D10Texture2D +// +//! @param src - source InputArray +//! @param pD3D10Texture2D - destination D3D10 texture +CV_EXPORTS void convertToD3D10Texture2D(InputArray src, ID3D10Texture2D* pD3D10Texture2D); + +//! @brief Converts ID3D10Texture2D to OutputArray +// +//! @note Note: function does memory copy from pD3D10Texture2D +//! to dst +// +//! @param pD3D10Texture2D - source D3D10 texture +//! @param dst - destination OutputArray +CV_EXPORTS void convertFromD3D10Texture2D(ID3D10Texture2D* pD3D10Texture2D, OutputArray dst); + +//! @brief Converts InputArray to IDirect3DSurface9 +// +//! @note Note: function does memory copy from src to +//! pDirect3DSurface9 +// +//! @param src - source InputArray +//! @param pDirect3DSurface9 - destination D3D10 texture +//! @param surfaceSharedHandle - shared handle +CV_EXPORTS void convertToDirect3DSurface9(InputArray src, IDirect3DSurface9* pDirect3DSurface9, void* surfaceSharedHandle = NULL); + +//! @brief Converts IDirect3DSurface9 to OutputArray +// +//! @note Note: function does memory copy from pDirect3DSurface9 +//! to dst +// +//! @param pDirect3DSurface9 - source D3D10 texture +//! @param dst - destination OutputArray +//! @param surfaceSharedHandle - shared handle +CV_EXPORTS void convertFromDirect3DSurface9(IDirect3DSurface9* pDirect3DSurface9, OutputArray dst, void* surfaceSharedHandle = NULL); + +//! @brief Get OpenCV type from DirectX type +//! @param iDXGI_FORMAT - enum DXGI_FORMAT for D3D10/D3D11 +//! @return OpenCV type or -1 if there is no equivalent +CV_EXPORTS int getTypeFromDXGI_FORMAT(const int iDXGI_FORMAT); // enum DXGI_FORMAT for D3D10/D3D11 + +//! @brief Get OpenCV type from DirectX type +//! @param iD3DFORMAT - enum D3DTYPE for D3D9 +//! @return OpenCV type or -1 if there is no equivalent +CV_EXPORTS int getTypeFromD3DFORMAT(const int iD3DFORMAT); // enum D3DTYPE for D3D9 + +//! @} + +} } // namespace cv::directx + +#endif // OPENCV_CORE_DIRECTX_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/dualquaternion.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/dualquaternion.hpp new file mode 100644 index 0000000..1f644e9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/dualquaternion.hpp @@ -0,0 +1,979 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2020, Huawei Technologies Co., Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Liangqian Kong +// Longbu Wang +#ifndef OPENCV_CORE_DUALQUATERNION_HPP +#define OPENCV_CORE_DUALQUATERNION_HPP + +#include +#include + +namespace cv{ +//! @addtogroup core +//! @{ + +template class DualQuat; +template std::ostream& operator<<(std::ostream&, const DualQuat<_Tp>&); + +/** + * Dual quaternions were introduced to describe rotation together with translation while ordinary + * quaternions can only describe rotation. It can be used for shortest path pose interpolation, + * local pose optimization or volumetric deformation. More details can be found + * - https://en.wikipedia.org/wiki/Dual_quaternion + * - ["A beginners guide to dual-quaternions: what they are, how they work, and how to use them for 3D character hierarchies", Ben Kenwright, 2012](https://borodust.org/public/shared/beginner_dual_quats.pdf) + * - ["Dual Quaternions", Yan-Bin Jia, 2013](http://web.cs.iastate.edu/~cs577/handouts/dual-quaternion.pdf) + * - ["Geometric Skinning with Approximate Dual Quaternion Blending", Kavan, 2008](https://www.cs.utah.edu/~ladislav/kavan08geometric/kavan08geometric) + * - http://rodolphe-vaillant.fr/?e=29 + * + * A unit dual quaternion can be classically represented as: + * \f[ + * \begin{equation} + * \begin{split} + * \sigma &= \left(r+\frac{\epsilon}{2}tr\right)\\ + * &= [w, x, y, z, w\_, x\_, y\_, z\_] + * \end{split} + * \end{equation} + * \f] + * where \f$r, t\f$ represents the rotation (ordinary unit quaternion) and translation (pure ordinary quaternion) respectively. + * + * A general dual quaternions which consist of two quaternions is usually represented in form of: + * \f[ + * \sigma = p + \epsilon q + * \f] + * where the introduced dual unit \f$\epsilon\f$ satisfies \f$\epsilon^2 = \epsilon^3 =...=0\f$, and \f$p, q\f$ are quaternions. + * + * Alternatively, dual quaternions can also be interpreted as four components which are all [dual numbers](https://www.cs.utah.edu/~ladislav/kavan08geometric/kavan08geometric): + * \f[ + * \sigma = \hat{q}_w + \hat{q}_xi + \hat{q}_yj + \hat{q}_zk + * \f] + * If we set \f$\hat{q}_x, \hat{q}_y\f$ and \f$\hat{q}_z\f$ equal to 0, a dual quaternion is transformed to a dual number. see normalize(). + * + * If you want to create a dual quaternion, you can use: + * + * ``` + * using namespace cv; + * double angle = CV_PI; + * + * // create from eight number + * DualQuatd dq1(1, 2, 3, 4, 5, 6, 7, 8); //p = [1,2,3,4]. q=[5,6,7,8] + * + * // create from Vec + * Vec v{1,2,3,4,5,6,7,8}; + * DualQuatd dq_v{v}; + * + * // create from two quaternion + * Quatd p(1, 2, 3, 4); + * Quatd q(5, 6, 7, 8); + * DualQuatd dq2 = DualQuatd::createFromQuat(p, q); + * + * // create from an angle, an axis and a translation + * Vec3d axis{0, 0, 1}; + * Vec3d trans{3, 4, 5}; + * DualQuatd dq3 = DualQuatd::createFromAngleAxisTrans(angle, axis, trans); + * + * // If you already have an instance of class Affine3, then you can use + * Affine3d R = dq3.toAffine3(); + * DualQuatd dq4 = DualQuatd::createFromAffine3(R); + * + * // or create directly by affine transformation matrix Rt + * // see createFromMat() in detail for the form of Rt + * Matx44d Rt = dq3.toMat(); + * DualQuatd dq5 = DualQuatd::createFromMat(Rt); + * + * // Any rotation + translation movement can + * // be expressed as a rotation + translation around the same line in space (expressed by Plucker + * // coords), and here's a way to represent it this way. + * Vec3d axis{1, 1, 1}; // axis will be normalized in createFromPitch + * Vec3d trans{3, 4 ,5}; + * axis = axis / std::sqrt(axis.dot(axis));// The formula for computing moment that I use below requires a normalized axis + * Vec3d moment = 1.0 / 2 * (trans.cross(axis) + axis.cross(trans.cross(axis)) * + * std::cos(rotation_angle / 2) / std::sin(rotation_angle / 2)); + * double d = trans.dot(qaxis); + * DualQuatd dq6 = DualQuatd::createFromPitch(angle, d, axis, moment); + * ``` + * + * A point \f$v=(x, y, z)\f$ in form of dual quaternion is \f$[1+\epsilon v]=[1,0,0,0,0,x,y,z]\f$. + * The transformation of a point \f$v_1\f$ to another point \f$v_2\f$ under the dual quaternion \f$\sigma\f$ is + * \f[ + * 1 + \epsilon v_2 = \sigma * (1 + \epsilon v_1) * \sigma^{\star} + * \f] + * where \f$\sigma^{\star}=p^*-\epsilon q^*.\f$ + * + * A line in the \f$Pl\ddot{u}cker\f$ coordinates \f$(\hat{l}, m)\f$ defined by the dual quaternion \f$l=\hat{l}+\epsilon m\f$. + * To transform a line, \f[l_2 = \sigma * l_1 * \sigma^*,\f] where \f$\sigma=r+\frac{\epsilon}{2}rt\f$ and + * \f$\sigma^*=p^*+\epsilon q^*\f$. + * + * To extract the Vec or Vec, see toVec(); + * + * To extract the affine transformation matrix, see toMat(); + * + * To extract the instance of Affine3, see toAffine3(); + * + * If two quaternions \f$q_0, q_1\f$ are needed to be interpolated, you can use sclerp() + * ``` + * DualQuatd::sclerp(q0, q1, t) + * ``` + * or dqblend(). + * ``` + * DualQuatd::dqblend(q0, q1, t) + * ``` + * With more than two dual quaternions to be blended, you can use generalize linear dual quaternion blending + * with the corresponding weights, i.e. gdqblend(). + * + */ +template +class CV_EXPORTS DualQuat{ + static_assert(std::is_floating_point<_Tp>::value, "Dual quaternion only make sense with type of float or double"); + using value_type = _Tp; + +public: + static constexpr _Tp CV_DUAL_QUAT_EPS = (_Tp)1.e-6; + + DualQuat(); + + /** + * @brief create from eight same type numbers. + */ + DualQuat(const _Tp w, const _Tp x, const _Tp y, const _Tp z, const _Tp w_, const _Tp x_, const _Tp y_, const _Tp z_); + + /** + * @brief create from a double or float vector. + */ + DualQuat(const Vec<_Tp, 8> &q); + + _Tp w, x, y, z, w_, x_, y_, z_; + + /** + * @brief create Dual Quaternion from two same type quaternions p and q. + * A Dual Quaternion \f$\sigma\f$ has the form: + * \f[\sigma = p + \epsilon q\f] + * where p and q are defined as follows: + * \f[\begin{equation} + * \begin{split} + * p &= w + x\boldsymbol{i} + y\boldsymbol{j} + z\boldsymbol{k}\\ + * q &= w\_ + x\_\boldsymbol{i} + y\_\boldsymbol{j} + z\_\boldsymbol{k}. + * \end{split} + * \end{equation} + * \f] + * The p and q are the real part and dual part respectively. + * @param realPart a quaternion, real part of dual quaternion. + * @param dualPart a quaternion, dual part of dual quaternion. + * @sa Quat + */ + static DualQuat<_Tp> createFromQuat(const Quat<_Tp> &realPart, const Quat<_Tp> &dualPart); + + /** + * @brief create a dual quaternion from a rotation angle \f$\theta\f$, a rotation axis + * \f$\boldsymbol{u}\f$ and a translation \f$\boldsymbol{t}\f$. + * It generates a dual quaternion \f$\sigma\f$ in the form of + * \f[\begin{equation} + * \begin{split} + * \sigma &= r + \frac{\epsilon}{2}\boldsymbol{t}r \\ + * &= [\cos(\frac{\theta}{2}), \boldsymbol{u}\sin(\frac{\theta}{2})] + * + \frac{\epsilon}{2}[0, \boldsymbol{t}][[\cos(\frac{\theta}{2}), + * \boldsymbol{u}\sin(\frac{\theta}{2})]]\\ + * &= \cos(\frac{\theta}{2}) + \boldsymbol{u}\sin(\frac{\theta}{2}) + * + \frac{\epsilon}{2}(-(\boldsymbol{t} \cdot \boldsymbol{u})\sin(\frac{\theta}{2}) + * + \boldsymbol{t}\cos(\frac{\theta}{2}) + \boldsymbol{u} \times \boldsymbol{t} \sin(\frac{\theta}{2})). + * \end{split} + * \end{equation}\f] + * @param angle rotation angle. + * @param axis rotation axis. + * @param translation a vector of length 3. + * @note Axis will be normalized in this function. And translation is applied + * after the rotation. Use @ref createFromQuat(r, r * t / 2) to create a dual quaternion + * which translation is applied before rotation. + * @sa Quat + */ + static DualQuat<_Tp> createFromAngleAxisTrans(const _Tp angle, const Vec<_Tp, 3> &axis, const Vec<_Tp, 3> &translation); + + /** + * @brief Transform this dual quaternion to an affine transformation matrix \f$M\f$. + * Dual quaternion consists of a rotation \f$r=[a,b,c,d]\f$ and a translation \f$t=[\Delta x,\Delta y,\Delta z]\f$. The + * affine transformation matrix \f$M\f$ has the form + * \f[ + * \begin{bmatrix} + * 1-2(e_2^2 +e_3^2) &2(e_1e_2-e_0e_3) &2(e_0e_2+e_1e_3) &\Delta x\\ + * 2(e_0e_3+e_1e_2) &1-2(e_1^2+e_3^2) &2(e_2e_3-e_0e_1) &\Delta y\\ + * 2(e_1e_3-e_0e_2) &2(e_0e_1+e_2e_3) &1-2(e_1^2-e_2^2) &\Delta z\\ + * 0&0&0&1 + * \end{bmatrix} + * \f] + * if A is a matrix consisting of n points to be transformed, this could be achieved by + * \f[ + * new\_A = M * A + * \f] + * where A has the form + * \f[ + * \begin{bmatrix} + * x_0& x_1& x_2&...&x_n\\ + * y_0& y_1& y_2&...&y_n\\ + * z_0& z_1& z_2&...&z_n\\ + * 1&1&1&...&1 + * \end{bmatrix} + * \f] + * where the same subscript represent the same point. The size of A should be \f$[4,n]\f$. + * and the same size for matrix new_A. + * @param _R 4x4 matrix that represents rotations and translation. + * @note Translation is applied after the rotation. Use createFromQuat(r, r * t / 2) to create + * a dual quaternion which translation is applied before rotation. + */ + static DualQuat<_Tp> createFromMat(InputArray _R); + + /** + * @brief create dual quaternion from an affine matrix. The definition of affine matrix can refer to createFromMat() + */ + static DualQuat<_Tp> createFromAffine3(const Affine3<_Tp> &R); + + /** + * @brief A dual quaternion is a vector in form of + * \f[ + * \begin{equation} + * \begin{split} + * \sigma &=\boldsymbol{p} + \epsilon \boldsymbol{q}\\ + * &= \cos\hat{\frac{\theta}{2}}+\overline{\hat{l}}\sin\frac{\hat{\theta}}{2} + * \end{split} + * \end{equation} + * \f] + * where \f$\hat{\theta}\f$ is dual angle and \f$\overline{\hat{l}}\f$ is dual axis: + * \f[ + * \hat{\theta}=\theta + \epsilon d,\\ + * \overline{\hat{l}}= \hat{l} +\epsilon m. + * \f] + * In this representation, \f$\theta\f$ is rotation angle and \f$(\hat{l},m)\f$ is the screw axis, d is the translation distance along the axis. + * + * @param angle rotation angle. + * @param d translation along the rotation axis. + * @param axis rotation axis represented by quaternion with w = 0. + * @param moment the moment of line, and it should be orthogonal to axis. + * @note Translation is applied after the rotation. Use createFromQuat(r, r * t / 2) to create + * a dual quaternion which translation is applied before rotation. + */ + static DualQuat<_Tp> createFromPitch(const _Tp angle, const _Tp d, const Vec<_Tp, 3> &axis, const Vec<_Tp, 3> &moment); + + /** + * @brief return a quaternion which represent the real part of dual quaternion. + * The definition of real part is in createFromQuat(). + * @sa createFromQuat, getDualPart + */ + Quat<_Tp> getRealPart() const; + + /** + * @brief return a quaternion which represent the dual part of dual quaternion. + * The definition of dual part is in createFromQuat(). + * @sa createFromQuat, getRealPart + */ + Quat<_Tp> getDualPart() const; + + /** + * @brief return the conjugate of a dual quaternion. + * \f[ + * \begin{equation} + * \begin{split} + * \sigma^* &= (p + \epsilon q)^* + * &= (p^* + \epsilon q^*) + * \end{split} + * \end{equation} + * \f] + * @param dq a dual quaternion. + */ + template + friend DualQuat conjugate(const DualQuat &dq); + + /** + * @brief return the conjugate of a dual quaternion. + * \f[ + * \begin{equation} + * \begin{split} + * \sigma^* &= (p + \epsilon q)^* + * &= (p^* + \epsilon q^*) + * \end{split} + * \end{equation} + * \f] + */ + DualQuat<_Tp> conjugate() const; + + /** + * @brief return the rotation in quaternion form. + */ + Quat<_Tp> getRotation(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const; + + /** + * @brief return the translation vector. + * The rotation \f$r\f$ in this dual quaternion \f$\sigma\f$ is applied before translation \f$t\f$. + * The dual quaternion \f$\sigma\f$ is defined as + * \f[\begin{equation} + * \begin{split} + * \sigma &= p + \epsilon q \\ + * &= r + \frac{\epsilon}{2}{t}r. + * \end{split} + * \end{equation}\f] + * Thus, the translation can be obtained as follows + * \f[t = 2qp^*.\f] + * @param assumeUnit if @ref QUAT_ASSUME_UNIT, this dual quaternion assume to be a unit dual quaternion + * and this function will save some computations. + * @note This dual quaternion's translation is applied after the rotation. + */ + Vec<_Tp, 3> getTranslation(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const; + + /** + * @brief return the norm \f$||\sigma||\f$ of dual quaternion \f$\sigma = p + \epsilon q\f$. + * \f[ + * \begin{equation} + * \begin{split} + * ||\sigma|| &= \sqrt{\sigma * \sigma^*} \\ + * &= ||p|| + \epsilon \frac{p \cdot q}{||p||}. + * \end{split} + * \end{equation} + * \f] + * Generally speaking, the norm of a not unit dual + * quaternion is a dual number. For convenience, we return it in the form of a dual quaternion + * , i.e. + * \f[ ||\sigma|| = [||p||, 0, 0, 0, \frac{p \cdot q}{||p||}, 0, 0, 0].\f] + * + * @note The data type of dual number is dual quaternion. + */ + DualQuat<_Tp> norm() const; + + /** + * @brief return a normalized dual quaternion. + * A dual quaternion can be expressed as + * \f[ + * \begin{equation} + * \begin{split} + * \sigma &= p + \epsilon q\\ + * &=||\sigma||\left(r+\frac{1}{2}tr\right) + * \end{split} + * \end{equation} + * \f] + * where \f$r, t\f$ represents the rotation (ordinary quaternion) and translation (pure ordinary quaternion) respectively, + * and \f$||\sigma||\f$ is the norm of dual quaternion(a dual number). + * A dual quaternion is unit if and only if + * \f[ + * ||p||=1, p \cdot q=0 + * \f] + * where \f$\cdot\f$ means dot product. + * The process of normalization is + * \f[ + * \sigma_{u}=\frac{\sigma}{||\sigma||} + * \f] + * Next, we simply proof \f$\sigma_u\f$ is a unit dual quaternion: + * \f[ + * \renewcommand{\Im}{\operatorname{Im}} + * \begin{equation} + * \begin{split} + * \sigma_{u}=\frac{\sigma}{||\sigma||}&=\frac{p + \epsilon q}{||p||+\epsilon\frac{p\cdot q}{||p||}}\\ + * &=\frac{p}{||p||}+\epsilon\left(\frac{q}{||p||}-p\frac{p\cdot q}{||p||^3}\right)\\ + * &=\frac{p}{||p||}+\epsilon\frac{1}{||p||^2}\left(qp^{*}-p\cdot q\right)\frac{p}{||p||}\\ + * &=\frac{p}{||p||}+\epsilon\frac{1}{||p||^2}\Im(qp^*)\frac{p}{||p||}.\\ + * \end{split} + * \end{equation} + * \f] + * As expected, the real part is a rotation and dual part is a pure quaternion. + */ + DualQuat<_Tp> normalize() const; + + /** + * @brief if \f$\sigma = p + \epsilon q\f$ is a dual quaternion, p is not zero, + * the inverse dual quaternion is + * \f[\sigma^{-1} = \frac{\sigma^*}{||\sigma||^2}, \f] + * or equivalentlly, + * \f[\sigma^{-1} = p^{-1} - \epsilon p^{-1}qp^{-1}.\f] + * @param dq a dual quaternion. + * @param assumeUnit if @ref QUAT_ASSUME_UNIT, dual quaternion dq assume to be a unit dual quaternion + * and this function will save some computations. + */ + template + friend DualQuat inv(const DualQuat &dq, QuatAssumeType assumeUnit); + + /** + * @brief if \f$\sigma = p + \epsilon q\f$ is a dual quaternion, p is not zero, + * the inverse dual quaternion is + * \f[\sigma^{-1} = \frac{\sigma^*}{||\sigma||^2}, \f] + * or equivalentlly, + * \f[\sigma^{-1} = p^{-1} - \epsilon p^{-1}qp^{-1}.\f] + * @param assumeUnit if @ref QUAT_ASSUME_UNIT, this dual quaternion assume to be a unit dual quaternion + * and this function will save some computations. + */ + DualQuat<_Tp> inv(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const; + + /** + * @brief return the dot product of two dual quaternion. + * @param p other dual quaternion. + */ + _Tp dot(DualQuat<_Tp> p) const; + + /** + ** @brief return the value of \f$p^t\f$ where p is a dual quaternion. + * This could be calculated as: + * \f[ + * p^t = \exp(t\ln p) + * \f] + * @param dq a dual quaternion. + * @param t index of power function. + * @param assumeUnit if @ref QUAT_ASSUME_UNIT, dual quaternion dq assume to be a unit dual quaternion + * and this function will save some computations. + */ + template + friend DualQuat power(const DualQuat &dq, const T t, QuatAssumeType assumeUnit); + + /** + ** @brief return the value of \f$p^t\f$ where p is a dual quaternion. + * This could be calculated as: + * \f[ + * p^t = \exp(t\ln p) + * \f] + * + * @param t index of power function. + * @param assumeUnit if @ref QUAT_ASSUME_UNIT, this dual quaternion assume to be a unit dual quaternion + * and this function will save some computations. + */ + DualQuat<_Tp> power(const _Tp t, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const; + + /** + * @brief return the value of \f$p^q\f$ where p and q are dual quaternions. + * This could be calculated as: + * \f[ + * p^q = \exp(q\ln p) + * \f] + * @param p a dual quaternion. + * @param q a dual quaternion. + * @param assumeUnit if @ref QUAT_ASSUME_UNIT, dual quaternion p assume to be a dual unit quaternion + * and this function will save some computations. + */ + template + friend DualQuat power(const DualQuat& p, const DualQuat& q, QuatAssumeType assumeUnit); + + /** + * @brief return the value of \f$p^q\f$ where p and q are dual quaternions. + * This could be calculated as: + * \f[ + * p^q = \exp(q\ln p) + * \f] + * + * @param q a dual quaternion + * @param assumeUnit if @ref QUAT_ASSUME_UNIT, this dual quaternion assume to be a dual unit quaternion + * and this function will save some computations. + */ + DualQuat<_Tp> power(const DualQuat<_Tp>& q, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const; + + /** + * @brief return the value of exponential function value + * @param dq a dual quaternion. + */ + template + friend DualQuat exp(const DualQuat &dq); + + /** + * @brief return the value of exponential function value + */ + DualQuat<_Tp> exp() const; + + /** + * @brief return the value of logarithm function value + * + * @param dq a dual quaternion. + * @param assumeUnit if @ref QUAT_ASSUME_UNIT, dual quaternion dq assume to be a unit dual quaternion + * and this function will save some computations. + */ + template + friend DualQuat log(const DualQuat &dq, QuatAssumeType assumeUnit); + + /** + * @brief return the value of logarithm function value + * @param assumeUnit if @ref QUAT_ASSUME_UNIT, this dual quaternion assume to be a unit dual quaternion + * and this function will save some computations. + */ + DualQuat<_Tp> log(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const; + + /** + * @brief Transform this dual quaternion to a vector. + */ + Vec<_Tp, 8> toVec() const; + + /** + * @brief Transform this dual quaternion to a affine transformation matrix + * the form of matrix, see createFromMat(). + */ + Matx<_Tp, 4, 4> toMat(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const; + + /** + * @brief Transform this dual quaternion to a instance of Affine3. + */ + Affine3<_Tp> toAffine3(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const; + + /** + * @brief The screw linear interpolation(ScLERP) is an extension of spherical linear interpolation of dual quaternion. + * If \f$\sigma_1\f$ and \f$\sigma_2\f$ are two dual quaternions representing the initial and final pose. + * The interpolation of ScLERP function can be defined as: + * \f[ + * ScLERP(t;\sigma_1,\sigma_2) = \sigma_1 * (\sigma_1^{-1} * \sigma_2)^t, t\in[0,1] + * \f] + * + * @param q1 a dual quaternion represents a initial pose. + * @param q2 a dual quaternion represents a final pose. + * @param t interpolation parameter + * @param directChange if true, it always return the shortest path. + * @param assumeUnit if @ref QUAT_ASSUME_UNIT, this dual quaternion assume to be a unit dual quaternion + * and this function will save some computations. + * + * For example + * ``` + * double angle1 = CV_PI / 2; + * Vec3d axis{0, 0, 1}; + * Vec3d t(0, 0, 3); + * DualQuatd initial = DualQuatd::createFromAngleAxisTrans(angle1, axis, t); + * double angle2 = CV_PI; + * DualQuatd final = DualQuatd::createFromAngleAxisTrans(angle2, axis, t); + * DualQuatd inter = DualQuatd::sclerp(initial, final, 0.5); + * ``` + */ + static DualQuat<_Tp> sclerp(const DualQuat<_Tp> &q1, const DualQuat<_Tp> &q2, const _Tp t, + bool directChange=true, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT); + /** + * @brief The method of Dual Quaternion linear Blending(DQB) is to compute a transformation between dual quaternion + * \f$q_1\f$ and \f$q_2\f$ and can be defined as: + * \f[ + * DQB(t;{\boldsymbol{q}}_1,{\boldsymbol{q}}_2)= + * \frac{(1-t){\boldsymbol{q}}_1+t{\boldsymbol{q}}_2}{||(1-t){\boldsymbol{q}}_1+t{\boldsymbol{q}}_2||}. + * \f] + * where \f$q_1\f$ and \f$q_2\f$ are unit dual quaternions representing the input transformations. + * If you want to use DQB that works for more than two rigid transformations, see @ref gdqblend + * + * @param q1 a unit dual quaternion representing the input transformations. + * @param q2 a unit dual quaternion representing the input transformations. + * @param t parameter \f$t\in[0,1]\f$. + * @param assumeUnit if @ref QUAT_ASSUME_UNIT, this dual quaternion assume to be a unit dual quaternion + * and this function will save some computations. + * + * @sa gdqblend + */ + static DualQuat<_Tp> dqblend(const DualQuat<_Tp> &q1, const DualQuat<_Tp> &q2, const _Tp t, + QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT); + + /** + * @brief The generalized Dual Quaternion linear Blending works for more than two rigid transformations. + * If these transformations are expressed as unit dual quaternions \f$q_1,...,q_n\f$ with convex weights + * \f$w = (w_1,...,w_n)\f$, the generalized DQB is simply + * \f[ + * gDQB(\boldsymbol{w};{\boldsymbol{q}}_1,...,{\boldsymbol{q}}_n)=\frac{w_1{\boldsymbol{q}}_1+...+w_n{\boldsymbol{q}}_n} + * {||w_1{\boldsymbol{q}}_1+...+w_n{\boldsymbol{q}}_n||}. + * \f] + * @param dualquat vector of dual quaternions + * @param weights vector of weights, the size of weights should be the same as dualquat, and the weights should + * satisfy \f$\sum_0^n w_{i} = 1\f$ and \f$w_i>0\f$. + * @param assumeUnit if @ref QUAT_ASSUME_UNIT, these dual quaternions assume to be unit quaternions + * and this function will save some computations. + * @note the type of weights' element should be the same as the date type of dual quaternion inside the dualquat. + */ + template + static DualQuat<_Tp> gdqblend(const Vec, cn> &dualquat, InputArray weights, + QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT); + + /** + * @brief The generalized Dual Quaternion linear Blending works for more than two rigid transformations. + * If these transformations are expressed as unit dual quaternions \f$q_1,...,q_n\f$ with convex weights + * \f$w = (w_1,...,w_n)\f$, the generalized DQB is simply + * \f[ + * gDQB(\boldsymbol{w};{\boldsymbol{q}}_1,...,{\boldsymbol{q}}_n)=\frac{w_1{\boldsymbol{q}}_1+...+w_n{\boldsymbol{q}}_n} + * {||w_1{\boldsymbol{q}}_1+...+w_n{\boldsymbol{q}}_n||}. + * \f] + * @param dualquat The dual quaternions which have 8 channels and 1 row or 1 col. + * @param weights vector of weights, the size of weights should be the same as dualquat, and the weights should + * satisfy \f$\sum_0^n w_{i} = 1\f$ and \f$w_i>0\f$. + * @param assumeUnit if @ref QUAT_ASSUME_UNIT, these dual quaternions assume to be unit quaternions + * and this function will save some computations. + * @note the type of weights' element should be the same as the date type of dual quaternion inside the dualquat. + */ + static DualQuat<_Tp> gdqblend(InputArray dualquat, InputArray weights, + QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT); + + /** + * @brief Return opposite dual quaternion \f$-p\f$ + * which satisfies \f$p + (-p) = 0.\f$ + * + * For example + * ``` + * DualQuatd q{1, 2, 3, 4, 5, 6, 7, 8}; + * std::cout << -q << std::endl; // [-1, -2, -3, -4, -5, -6, -7, -8] + * ``` + */ + DualQuat<_Tp> operator-() const; + + /** + * @brief return true if two dual quaternions p and q are nearly equal, i.e. when the absolute + * value of each \f$p_i\f$ and \f$q_i\f$ is less than CV_DUAL_QUAT_EPS. + */ + bool operator==(const DualQuat<_Tp>&) const; + + /** + * @brief Subtraction operator of two dual quaternions p and q. + * It returns a new dual quaternion that each value is the sum of \f$p_i\f$ and \f$-q_i\f$. + * + * For example + * ``` + * DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8}; + * DualQuatd q{5, 6, 7, 8, 9, 10, 11, 12}; + * std::cout << p - q << std::endl; //[-4, -4, -4, -4, 4, -4, -4, -4] + * ``` + */ + DualQuat<_Tp> operator-(const DualQuat<_Tp>&) const; + + /** + * @brief Subtraction assignment operator of two dual quaternions p and q. + * It subtracts right operand from the left operand and assign the result to left operand. + * + * For example + * ``` + * DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8}; + * DualQuatd q{5, 6, 7, 8, 9, 10, 11, 12}; + * p -= q; // equivalent to p = p - q + * std::cout << p << std::endl; //[-4, -4, -4, -4, 4, -4, -4, -4] + * + * ``` + */ + DualQuat<_Tp>& operator-=(const DualQuat<_Tp>&); + + /** + * @brief Addition operator of two dual quaternions p and q. + * It returns a new dual quaternion that each value is the sum of \f$p_i\f$ and \f$q_i\f$. + * + * For example + * ``` + * DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8}; + * DualQuatd q{5, 6, 7, 8, 9, 10, 11, 12}; + * std::cout << p + q << std::endl; //[6, 8, 10, 12, 14, 16, 18, 20] + * ``` + */ + DualQuat<_Tp> operator+(const DualQuat<_Tp>&) const; + + /** + * @brief Addition assignment operator of two dual quaternions p and q. + * It adds right operand to the left operand and assign the result to left operand. + * + * For example + * ``` + * DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8}; + * DualQuatd q{5, 6, 7, 8, 9, 10, 11, 12}; + * p += q; // equivalent to p = p + q + * std::cout << p << std::endl; //[6, 8, 10, 12, 14, 16, 18, 20] + * + * ``` + */ + DualQuat<_Tp>& operator+=(const DualQuat<_Tp>&); + + /** + * @brief Multiplication assignment operator of two quaternions. + * It multiplies right operand with the left operand and assign the result to left operand. + * + * Rule of dual quaternion multiplication: + * The dual quaternion can be written as an ordered pair of quaternions [A, B]. Thus + * \f[ + * \begin{equation} + * \begin{split} + * p * q &= [A, B][C, D]\\ + * &=[AC, AD + BC] + * \end{split} + * \end{equation} + * \f] + * + * For example + * ``` + * DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8}; + * DualQuatd q{5, 6, 7, 8, 9, 10, 11, 12}; + * p *= q; + * std::cout << p << std::endl; //[-60, 12, 30, 24, -216, 80, 124, 120] + * ``` + */ + DualQuat<_Tp>& operator*=(const DualQuat<_Tp>&); + + /** + * @brief Multiplication assignment operator of a quaternions and a scalar. + * It multiplies right operand with the left operand and assign the result to left operand. + * + * Rule of dual quaternion multiplication with a scalar: + * \f[ + * \begin{equation} + * \begin{split} + * p * s &= [w, x, y, z, w\_, x\_, y\_, z\_] * s\\ + * &=[w s, x s, y s, z s, w\_ \space s, x\_ \space s, y\_ \space s, z\_ \space s]. + * \end{split} + * \end{equation} + * \f] + * + * For example + * ``` + * DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8}; + * double s = 2.0; + * p *= s; + * std::cout << p << std::endl; //[2, 4, 6, 8, 10, 12, 14, 16] + * ``` + * @note the type of scalar should be equal to the dual quaternion. + */ + DualQuat<_Tp> operator*=(const _Tp s); + + + /** + * @brief Multiplication operator of two dual quaternions q and p. + * Multiplies values on either side of the operator. + * + * Rule of dual quaternion multiplication: + * The dual quaternion can be written as an ordered pair of quaternions [A, B]. Thus + * \f[ + * \begin{equation} + * \begin{split} + * p * q &= [A, B][C, D]\\ + * &=[AC, AD + BC] + * \end{split} + * \end{equation} + * \f] + * + * For example + * ``` + * DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8}; + * DualQuatd q{5, 6, 7, 8, 9, 10, 11, 12}; + * std::cout << p * q << std::endl; //[-60, 12, 30, 24, -216, 80, 124, 120] + * ``` + */ + DualQuat<_Tp> operator*(const DualQuat<_Tp>&) const; + + /** + * @brief Division operator of a dual quaternions and a scalar. + * It divides left operand with the right operand and assign the result to left operand. + * + * Rule of dual quaternion division with a scalar: + * \f[ + * \begin{equation} + * \begin{split} + * p / s &= [w, x, y, z, w\_, x\_, y\_, z\_] / s\\ + * &=[w/s, x/s, y/s, z/s, w\_/s, x\_/s, y\_/s, z\_/s]. + * \end{split} + * \end{equation} + * \f] + * + * For example + * ``` + * DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8}; + * double s = 2.0; + * p /= s; // equivalent to p = p / s + * std::cout << p << std::endl; //[0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4] + * ``` + * @note the type of scalar should be equal to this dual quaternion. + */ + DualQuat<_Tp> operator/(const _Tp s) const; + + /** + * @brief Division operator of two dual quaternions p and q. + * Divides left hand operand by right hand operand. + * + * Rule of dual quaternion division with a dual quaternion: + * \f[ + * \begin{equation} + * \begin{split} + * p / q &= p * q.inv()\\ + * \end{split} + * \end{equation} + * \f] + * + * For example + * ``` + * DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8}; + * DualQuatd q{5, 6, 7, 8, 9, 10, 11, 12}; + * std::cout << p / q << std::endl; // equivalent to p * q.inv() + * ``` + */ + DualQuat<_Tp> operator/(const DualQuat<_Tp>&) const; + + /** + * @brief Division assignment operator of two dual quaternions p and q; + * It divides left operand with the right operand and assign the result to left operand. + * + * Rule of dual quaternion division with a quaternion: + * \f[ + * \begin{equation} + * \begin{split} + * p / q&= p * q.inv()\\ + * \end{split} + * \end{equation} + * \f] + * + * For example + * ``` + * DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8}; + * DualQuatd q{5, 6, 7, 8, 9, 10, 11, 12}; + * p /= q; // equivalent to p = p * q.inv() + * std::cout << p << std::endl; + * ``` + */ + DualQuat<_Tp>& operator/=(const DualQuat<_Tp>&); + + /** + * @brief Division assignment operator of a dual quaternions and a scalar. + * It divides left operand with the right operand and assign the result to left operand. + * + * Rule of dual quaternion division with a scalar: + * \f[ + * \begin{equation} + * \begin{split} + * p / s &= [w, x, y, z, w\_, x\_, y\_ ,z\_] / s\\ + * &=[w / s, x / s, y / s, z / s, w\_ / \space s, x\_ / \space s, y\_ / \space s, z\_ / \space s]. + * \end{split} + * \end{equation} + * \f] + * + * For example + * ``` + * DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8}; + * double s = 2.0;; + * p /= s; // equivalent to p = p / s + * std::cout << p << std::endl; //[0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0] + * ``` + * @note the type of scalar should be equal to the dual quaternion. + */ + Quat<_Tp>& operator/=(const _Tp s); + + /** + * @brief Addition operator of a scalar and a dual quaternions. + * Adds right hand operand from left hand operand. + * + * For example + * ``` + * DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8}; + * double scalar = 2.0; + * std::cout << scalar + p << std::endl; //[3.0, 2, 3, 4, 5, 6, 7, 8] + * ``` + * @note the type of scalar should be equal to the dual quaternion. + */ + template + friend DualQuat cv::operator+(const T s, const DualQuat&); + + /** + * @brief Addition operator of a dual quaternions and a scalar. + * Adds right hand operand from left hand operand. + * + * For example + * ``` + * DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8}; + * double scalar = 2.0; + * std::cout << p + scalar << std::endl; //[3.0, 2, 3, 4, 5, 6, 7, 8] + * ``` + * @note the type of scalar should be equal to the dual quaternion. + */ + template + friend DualQuat cv::operator+(const DualQuat&, const T s); + + /** + * @brief Multiplication operator of a scalar and a dual quaternions. + * It multiplies right operand with the left operand and assign the result to left operand. + * + * Rule of dual quaternion multiplication with a scalar: + * \f[ + * \begin{equation} + * \begin{split} + * p * s &= [w, x, y, z, w\_, x\_, y\_, z\_] * s\\ + * &=[w s, x s, y s, z s, w\_ \space s, x\_ \space s, y\_ \space s, z\_ \space s]. + * \end{split} + * \end{equation} + * \f] + * + * For example + * ``` + * DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8}; + * double s = 2.0; + * std::cout << s * p << std::endl; //[2, 4, 6, 8, 10, 12, 14, 16] + * ``` + * @note the type of scalar should be equal to the dual quaternion. + */ + template + friend DualQuat cv::operator*(const T s, const DualQuat&); + + /** + * @brief Subtraction operator of a dual quaternion and a scalar. + * Subtracts right hand operand from left hand operand. + * + * For example + * ``` + * DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8}; + * double scalar = 2.0; + * std::cout << p - scalar << std::endl; //[-1, 2, 3, 4, 5, 6, 7, 8] + * ``` + * @note the type of scalar should be equal to the dual quaternion. + */ + template + friend DualQuat cv::operator-(const DualQuat&, const T s); + + /** + * @brief Subtraction operator of a scalar and a dual quaternions. + * Subtracts right hand operand from left hand operand. + * + * For example + * ``` + * DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8}; + * double scalar = 2.0; + * std::cout << scalar - p << std::endl; //[1.0, -2, -3, -4, -5, -6, -7, -8] + * ``` + * @note the type of scalar should be equal to the dual quaternion. + */ + template + friend DualQuat cv::operator-(const T s, const DualQuat&); + + /** + * @brief Multiplication operator of a dual quaternions and a scalar. + * It multiplies right operand with the left operand and assign the result to left operand. + * + * Rule of dual quaternion multiplication with a scalar: + * \f[ + * \begin{equation} + * \begin{split} + * p * s &= [w, x, y, z, w\_, x\_, y\_, z\_] * s\\ + * &=[w s, x s, y s, z s, w\_ \space s, x\_ \space s, y\_ \space s, z\_ \space s]. + * \end{split} + * \end{equation} + * \f] + * + * For example + * ``` + * DualQuatd p{1, 2, 3, 4, 5, 6, 7, 8}; + * double s = 2.0; + * std::cout << p * s << std::endl; //[2, 4, 6, 8, 10, 12, 14, 16] + * ``` + * @note the type of scalar should be equal to the dual quaternion. + */ + template + friend DualQuat cv::operator*(const DualQuat&, const T s); + + template + friend std::ostream& cv::operator<<(std::ostream&, const DualQuat&); + +}; + +using DualQuatd = DualQuat; +using DualQuatf = DualQuat; + +//! @} core +}//namespace + +#include "dualquaternion.inl.hpp" + +#endif /* OPENCV_CORE_QUATERNION_HPP */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/dualquaternion.inl.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/dualquaternion.inl.hpp new file mode 100644 index 0000000..6abb159 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/dualquaternion.inl.hpp @@ -0,0 +1,487 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2020, Huawei Technologies Co., Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Liangqian Kong +// Longbu Wang + +#ifndef OPENCV_CORE_DUALQUATERNION_INL_HPP +#define OPENCV_CORE_DUALQUATERNION_INL_HPP + +#ifndef OPENCV_CORE_DUALQUATERNION_HPP +#error This is not a standalone header. Include dualquaternion.hpp instead. +#endif + +/////////////////////////////////////////////////////////////////////////////////////// +//Implementation +namespace cv { + +template +DualQuat::DualQuat():w(0), x(0), y(0), z(0), w_(0), x_(0), y_(0), z_(0){}; + +template +DualQuat::DualQuat(const T vw, const T vx, const T vy, const T vz, const T _w, const T _x, const T _y, const T _z): + w(vw), x(vx), y(vy), z(vz), w_(_w), x_(_x), y_(_y), z_(_z){}; + +template +DualQuat::DualQuat(const Vec &q):w(q[0]), x(q[1]), y(q[2]), z(q[3]), + w_(q[4]), x_(q[5]), y_(q[6]), z_(q[7]){}; + +template +DualQuat DualQuat::createFromQuat(const Quat &realPart, const Quat &dualPart) +{ + T w = realPart.w; + T x = realPart.x; + T y = realPart.y; + T z = realPart.z; + T w_ = dualPart.w; + T x_ = dualPart.x; + T y_ = dualPart.y; + T z_ = dualPart.z; + return DualQuat(w, x, y, z, w_, x_, y_, z_); +} + +template +DualQuat DualQuat::createFromAngleAxisTrans(const T angle, const Vec &axis, const Vec &trans) +{ + Quat r = Quat::createFromAngleAxis(angle, axis); + Quat t{0, trans[0], trans[1], trans[2]}; + return createFromQuat(r, t * r * T(0.5)); +} + +template +DualQuat DualQuat::createFromMat(InputArray _R) +{ + CV_CheckTypeEQ(_R.type(), cv::traits::Type::value, ""); + if (_R.size() != Size(4, 4)) + { + CV_Error(Error::StsBadArg, "The input matrix must have 4 columns and 4 rows"); + } + Mat R = _R.getMat(); + Quat r = Quat::createFromRotMat(R.colRange(0, 3).rowRange(0, 3)); + Quat trans(0, R.at(0, 3), R.at(1, 3), R.at(2, 3)); + return createFromQuat(r, trans * r * T(0.5)); +} + +template +DualQuat DualQuat::createFromAffine3(const Affine3 &R) +{ + return createFromMat(R.matrix); +} + +template +DualQuat DualQuat::createFromPitch(const T angle, const T d, const Vec &axis, const Vec &moment) +{ + T half_angle = angle * T(0.5), half_d = d * T(0.5); + Quat qaxis = Quat(0, axis[0], axis[1], axis[2]).normalize(); + Quat qmoment = Quat(0, moment[0], moment[1], moment[2]); + qmoment -= qaxis * axis.dot(moment); + Quat dual = -half_d * std::sin(half_angle) + std::sin(half_angle) * qmoment + + half_d * std::cos(half_angle) * qaxis; + return createFromQuat(Quat::createFromAngleAxis(angle, axis), dual); +} + +template +inline bool DualQuat::operator==(const DualQuat &q) const +{ + return (abs(w - q.w) < CV_DUAL_QUAT_EPS && abs(x - q.x) < CV_DUAL_QUAT_EPS && + abs(y - q.y) < CV_DUAL_QUAT_EPS && abs(z - q.z) < CV_DUAL_QUAT_EPS && + abs(w_ - q.w_) < CV_DUAL_QUAT_EPS && abs(x_ - q.x_) < CV_DUAL_QUAT_EPS && + abs(y_ - q.y_) < CV_DUAL_QUAT_EPS && abs(z_ - q.z_) < CV_DUAL_QUAT_EPS); +} + +template +inline Quat DualQuat::getRealPart() const +{ + return Quat(w, x, y, z); +} + +template +inline Quat DualQuat::getDualPart() const +{ + return Quat(w_, x_, y_, z_); +} + +template +inline DualQuat conjugate(const DualQuat &dq) +{ + return dq.conjugate(); +} + +template +inline DualQuat DualQuat::conjugate() const +{ + return DualQuat(w, -x, -y, -z, w_, -x_, -y_, -z_); +} + +template +DualQuat DualQuat::norm() const +{ + Quat real = getRealPart(); + T realNorm = real.norm(); + Quat dual = getDualPart(); + if (realNorm < CV_DUAL_QUAT_EPS){ + return DualQuat(0, 0, 0, 0, 0, 0, 0, 0); + } + return DualQuat(realNorm, 0, 0, 0, real.dot(dual) / realNorm, 0, 0, 0); +} + +template +inline Quat DualQuat::getRotation(QuatAssumeType assumeUnit) const +{ + if (assumeUnit) + { + return getRealPart(); + } + return getRealPart().normalize(); +} + +template +inline Vec DualQuat::getTranslation(QuatAssumeType assumeUnit) const +{ + Quat trans = T(2.0) * (getDualPart() * getRealPart().inv(assumeUnit)); + return Vec{trans[1], trans[2], trans[3]}; +} + +template +DualQuat DualQuat::normalize() const +{ + Quat p = getRealPart(); + Quat q = getDualPart(); + T p_norm = p.norm(); + if (p_norm < CV_DUAL_QUAT_EPS) + { + CV_Error(Error::StsBadArg, "Cannot normalize this dual quaternion: the norm is too small."); + } + Quat p_nr = p / p_norm; + Quat q_nr = q / p_norm; + return createFromQuat(p_nr, q_nr - p_nr * p_nr.dot(q_nr)); +} + +template +inline T DualQuat::dot(DualQuat q) const +{ + return q.w * w + q.x * x + q.y * y + q.z * z + q.w_ * w_ + q.x_ * x_ + q.y_ * y_ + q.z_ * z_; +} + +template +inline DualQuat inv(const DualQuat &dq, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) +{ + return dq.inv(assumeUnit); +} + +template +inline DualQuat DualQuat::inv(QuatAssumeType assumeUnit) const +{ + Quat real = getRealPart(); + Quat dual = getDualPart(); + return createFromQuat(real.inv(assumeUnit), -real.inv(assumeUnit) * dual * real.inv(assumeUnit)); +} + +template +inline DualQuat DualQuat::operator-(const DualQuat &q) const +{ + return DualQuat(w - q.w, x - q.x, y - q.y, z - q.z, w_ - q.w_, x_ - q.x_, y_ - q.y_, z_ - q.z_); +} + +template +inline DualQuat DualQuat::operator-() const +{ + return DualQuat(-w, -x, -y, -z, -w_, -x_, -y_, -z_); +} + +template +inline DualQuat DualQuat::operator+(const DualQuat &q) const +{ + return DualQuat(w + q.w, x + q.x, y + q.y, z + q.z, w_ + q.w_, x_ + q.x_, y_ + q.y_, z_ + q.z_); +} + +template +inline DualQuat& DualQuat::operator+=(const DualQuat &q) +{ + *this = *this + q; + return *this; +} + +template +inline DualQuat DualQuat::operator*(const DualQuat &q) const +{ + Quat A = getRealPart(); + Quat B = getDualPart(); + Quat C = q.getRealPart(); + Quat D = q.getDualPart(); + return DualQuat::createFromQuat(A * C, A * D + B * C); +} + +template +inline DualQuat& DualQuat::operator*=(const DualQuat &q) +{ + *this = *this * q; + return *this; +} + +template +inline DualQuat operator+(const T a, const DualQuat &q) +{ + return DualQuat(a + q.w, q.x, q.y, q.z, q.w_, q.x_, q.y_, q.z_); +} + +template +inline DualQuat operator+(const DualQuat &q, const T a) +{ + return DualQuat(a + q.w, q.x, q.y, q.z, q.w_, q.x_, q.y_, q.z_); +} + +template +inline DualQuat operator-(const DualQuat &q, const T a) +{ + return DualQuat(q.w - a, q.x, q.y, q.z, q.w_, q.x_, q.y_, q.z_); +} + +template +inline DualQuat& DualQuat::operator-=(const DualQuat &q) +{ + *this = *this - q; + return *this; +} + +template +inline DualQuat operator-(const T a, const DualQuat &q) +{ + return DualQuat(a - q.w, -q.x, -q.y, -q.z, -q.w_, -q.x_, -q.y_, -q.z_); +} + +template +inline DualQuat operator*(const T a, const DualQuat &q) +{ + return DualQuat(q.w * a, q.x * a, q.y * a, q.z * a, q.w_ * a, q.x_ * a, q.y_ * a, q.z_ * a); +} + +template +inline DualQuat operator*(const DualQuat &q, const T a) +{ + return DualQuat(q.w * a, q.x * a, q.y * a, q.z * a, q.w_ * a, q.x_ * a, q.y_ * a, q.z_ * a); +} + +template +inline DualQuat DualQuat::operator/(const T a) const +{ + return DualQuat(w / a, x / a, y / a, z / a, w_ / a, x_ / a, y_ / a, z_ / a); +} + +template +inline DualQuat DualQuat::operator/(const DualQuat &q) const +{ + return *this * q.inv(); +} + +template +inline DualQuat& DualQuat::operator/=(const DualQuat &q) +{ + *this = *this / q; + return *this; +} + +template +std::ostream & operator<<(std::ostream &os, const DualQuat &q) +{ + os << "DualQuat " << Vec{q.w, q.x, q.y, q.z, q.w_, q.x_, q.y_, q.z_}; + return os; +} + +template +inline DualQuat exp(const DualQuat &dq) +{ + return dq.exp(); +} + +namespace detail { + +template +Matx<_Tp, 4, 4> jacob_exp(const Quat<_Tp> &q) +{ + _Tp nv = std::sqrt(q.x * q.x + q.y * q.y + q.z * q.z); + _Tp sinc_nv = abs(nv) < cv::DualQuat<_Tp>::CV_DUAL_QUAT_EPS ? _Tp(1.0) - nv * nv * _Tp(1.0/6.0) : std::sin(nv) / nv; + _Tp csiii_nv = abs(nv) < cv::DualQuat<_Tp>::CV_DUAL_QUAT_EPS ? -_Tp(1.0/3.0) : (std::cos(nv) - sinc_nv) / nv / nv; + Matx<_Tp, 4, 4> J_exp_quat { + std::cos(nv), -sinc_nv * q.x, -sinc_nv * q.y, -sinc_nv * q.z, + sinc_nv * q.x, csiii_nv * q.x * q.x + sinc_nv, csiii_nv * q.x * q.y, csiii_nv * q.x * q.z, + sinc_nv * q.y, csiii_nv * q.y * q.x, csiii_nv * q.y * q.y + sinc_nv, csiii_nv * q.y * q.z, + sinc_nv * q.z, csiii_nv * q.z * q.x, csiii_nv * q.z * q.y, csiii_nv * q.z * q.z + sinc_nv + }; + return std::exp(q.w) * J_exp_quat; +} + +} // namespace detail + +template +DualQuat DualQuat::exp() const +{ + Quat real = getRealPart(); + return createFromQuat(real.exp(), Quat(detail::jacob_exp(real) * getDualPart().toVec())); +} + +template +DualQuat log(const DualQuat &dq, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) +{ + return dq.log(assumeUnit); +} + +template +DualQuat DualQuat::log(QuatAssumeType assumeUnit) const +{ + Quat plog = getRealPart().log(assumeUnit); + Matx jacob = detail::jacob_exp(plog); + return createFromQuat(plog, Quat(jacob.inv() * getDualPart().toVec())); +} + +template +inline DualQuat power(const DualQuat &dq, const T t, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) +{ + return dq.power(t, assumeUnit); +} + +template +inline DualQuat DualQuat::power(const T t, QuatAssumeType assumeUnit) const +{ + return (t * log(assumeUnit)).exp(); +} + +template +inline DualQuat power(const DualQuat &p, const DualQuat &q, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) +{ + return p.power(q, assumeUnit); +} + +template +inline DualQuat DualQuat::power(const DualQuat &q, QuatAssumeType assumeUnit) const +{ + return (q * log(assumeUnit)).exp(); +} + +template +inline Vec DualQuat::toVec() const +{ + return Vec(w, x, y, z, w_, x_, y_, z_); +} + +template +Affine3 DualQuat::toAffine3(QuatAssumeType assumeUnit) const +{ + return Affine3(toMat(assumeUnit)); +} + +template +Matx DualQuat::toMat(QuatAssumeType assumeUnit) const +{ + Matx rot44 = getRotation(assumeUnit).toRotMat4x4(); + Vec translation = getTranslation(assumeUnit); + rot44(0, 3) = translation[0]; + rot44(1, 3) = translation[1]; + rot44(2, 3) = translation[2]; + return rot44; +} + +template +DualQuat DualQuat::sclerp(const DualQuat &q0, const DualQuat &q1, const T t, bool directChange, QuatAssumeType assumeUnit) +{ + DualQuat v0(q0), v1(q1); + if (!assumeUnit) + { + v0 = v0.normalize(); + v1 = v1.normalize(); + } + Quat v0Real = v0.getRealPart(); + Quat v1Real = v1.getRealPart(); + if (directChange && v1Real.dot(v0Real) < 0) + { + v0 = -v0; + } + DualQuat v0inv1 = v0.inv() * v1; + return v0 * v0inv1.power(t, QUAT_ASSUME_UNIT); +} + +template +DualQuat DualQuat::dqblend(const DualQuat &q1, const DualQuat &q2, const T t, QuatAssumeType assumeUnit) +{ + DualQuat v1(q1), v2(q2); + if (!assumeUnit) + { + v1 = v1.normalize(); + v2 = v2.normalize(); + } + if (v1.getRotation(assumeUnit).dot(v2.getRotation(assumeUnit)) < 0) + { + return ((1 - t) * v1 - t * v2).normalize(); + } + return ((1 - t) * v1 + t * v2).normalize(); +} + +template +DualQuat DualQuat::gdqblend(InputArray _dualquat, InputArray _weight, QuatAssumeType assumeUnit) +{ + CV_CheckTypeEQ(_weight.type(), cv::traits::Type::value, ""); + CV_CheckTypeEQ(_dualquat.type(), CV_MAKETYPE(CV_MAT_DEPTH(cv::traits::Type::value), 8), ""); + Size dq_s = _dualquat.size(); + if (dq_s != _weight.size() || (dq_s.height != 1 && dq_s.width != 1)) + { + CV_Error(Error::StsBadArg, "The size of weight must be the same as dualquat, both of them should be (1, n) or (n, 1)"); + } + Mat dualquat = _dualquat.getMat(), weight = _weight.getMat(); + const int cn = std::max(dq_s.width, dq_s.height); + if (!assumeUnit) + { + for (int i = 0; i < cn; ++i) + { + dualquat.at>(i) = DualQuat{dualquat.at>(i)}.normalize().toVec(); + } + } + Vec dq_blend = dualquat.at>(0) * weight.at(0); + Quat q0 = DualQuat {dualquat.at>(0)}.getRotation(assumeUnit); + for (int i = 1; i < cn; ++i) + { + T k = q0.dot(DualQuat{dualquat.at>(i)}.getRotation(assumeUnit)) < 0 ? -1: 1; + dq_blend = dq_blend + dualquat.at>(i) * k * weight.at(i); + } + return DualQuat{dq_blend}.normalize(); +} + +template +template +DualQuat DualQuat::gdqblend(const Vec, cn> &_dualquat, InputArray _weight, QuatAssumeType assumeUnit) +{ + Vec, cn> dualquat(_dualquat); + if (cn == 0) + { + return DualQuat(1, 0, 0, 0, 0, 0, 0, 0); + } + Mat dualquat_mat(cn, 1, CV_64FC(8)); + for (int i = 0; i < cn ; ++i) + { + dualquat_mat.at>(i) = dualquat[i].toVec(); + } + return gdqblend(dualquat_mat, _weight, assumeUnit); +} + +} //namespace cv + +#endif /*OPENCV_CORE_DUALQUATERNION_INL_HPP*/ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/eigen.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/eigen.hpp new file mode 100644 index 0000000..51f4147 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/eigen.hpp @@ -0,0 +1,402 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + + +#ifndef OPENCV_CORE_EIGEN_HPP +#define OPENCV_CORE_EIGEN_HPP + +#ifndef EIGEN_WORLD_VERSION +#error "Wrong usage of OpenCV's Eigen utility header. Include Eigen's headers first. See https://github.com/opencv/opencv/issues/17366" +#endif + +#include "opencv2/core.hpp" + +#if defined _MSC_VER && _MSC_VER >= 1200 +#define NOMINMAX // fix https://github.com/opencv/opencv/issues/17548 +#pragma warning( disable: 4714 ) //__forceinline is not inlined +#pragma warning( disable: 4127 ) //conditional expression is constant +#pragma warning( disable: 4244 ) //conversion from '__int64' to 'int', possible loss of data +#endif + +#if !defined(OPENCV_DISABLE_EIGEN_TENSOR_SUPPORT) +#if EIGEN_WORLD_VERSION == 3 && EIGEN_MAJOR_VERSION >= 3 \ + && defined(CV_CXX11) && defined(CV_CXX_STD_ARRAY) +#include +#define OPENCV_EIGEN_TENSOR_SUPPORT 1 +#endif // EIGEN_WORLD_VERSION == 3 && EIGEN_MAJOR_VERSION >= 3 +#endif // !defined(OPENCV_DISABLE_EIGEN_TENSOR_SUPPORT) + +namespace cv +{ + +/** @addtogroup core_eigen +These functions are provided for OpenCV-Eigen interoperability. They convert `Mat` +objects to corresponding `Eigen::Matrix` objects and vice-versa. Consult the [Eigen +documentation](https://eigen.tuxfamily.org/dox/group__TutorialMatrixClass.html) for +information about the `Matrix` template type. + +@note Using these functions requires the `Eigen/Dense` or similar header to be +included before this header. +*/ +//! @{ + +#if defined(OPENCV_EIGEN_TENSOR_SUPPORT) || defined(CV_DOXYGEN) +/** @brief Converts an Eigen::Tensor to a cv::Mat. + +The method converts an Eigen::Tensor with shape (H x W x C) to a cv::Mat where: + H = number of rows + W = number of columns + C = number of channels + +Usage: +\code +Eigen::Tensor a_tensor(...); +// populate tensor with values +Mat a_mat; +eigen2cv(a_tensor, a_mat); +\endcode +*/ +template static inline +void eigen2cv( const Eigen::Tensor<_Tp, 3, _layout> &src, OutputArray dst ) +{ + if( !(_layout & Eigen::RowMajorBit) ) + { + const std::array shuffle{2, 1, 0}; + Eigen::Tensor<_Tp, 3, !_layout> row_major_tensor = src.swap_layout().shuffle(shuffle); + Mat _src(src.dimension(0), src.dimension(1), CV_MAKETYPE(DataType<_Tp>::type, src.dimension(2)), row_major_tensor.data()); + _src.copyTo(dst); + } + else + { + Mat _src(src.dimension(0), src.dimension(1), CV_MAKETYPE(DataType<_Tp>::type, src.dimension(2)), (void *)src.data()); + _src.copyTo(dst); + } +} + +/** @brief Converts a cv::Mat to an Eigen::Tensor. + +The method converts a cv::Mat to an Eigen Tensor with shape (H x W x C) where: + H = number of rows + W = number of columns + C = number of channels + +Usage: +\code +Mat a_mat(...); +// populate Mat with values +Eigen::Tensor a_tensor(...); +cv2eigen(a_mat, a_tensor); +\endcode +*/ +template static inline +void cv2eigen( const Mat &src, Eigen::Tensor<_Tp, 3, _layout> &dst ) +{ + if( !(_layout & Eigen::RowMajorBit) ) + { + Eigen::Tensor<_Tp, 3, !_layout> row_major_tensor(src.rows, src.cols, src.channels()); + Mat _dst(src.rows, src.cols, CV_MAKETYPE(DataType<_Tp>::type, src.channels()), row_major_tensor.data()); + if (src.type() == _dst.type()) + src.copyTo(_dst); + else + src.convertTo(_dst, _dst.type()); + const std::array shuffle{2, 1, 0}; + dst = row_major_tensor.swap_layout().shuffle(shuffle); + } + else + { + dst.resize(src.rows, src.cols, src.channels()); + Mat _dst(src.rows, src.cols, CV_MAKETYPE(DataType<_Tp>::type, src.channels()), dst.data()); + if (src.type() == _dst.type()) + src.copyTo(_dst); + else + src.convertTo(_dst, _dst.type()); + } +} + +/** @brief Maps cv::Mat data to an Eigen::TensorMap. + +The method wraps an existing Mat data array with an Eigen TensorMap of shape (H x W x C) where: + H = number of rows + W = number of columns + C = number of channels + +Explicit instantiation of the return type is required. + +@note Caller should be aware of the lifetime of the cv::Mat instance and take appropriate safety measures. +The cv::Mat instance will retain ownership of the data and the Eigen::TensorMap will lose access when the cv::Mat data is deallocated. + +The example below initializes a cv::Mat and produces an Eigen::TensorMap: +\code +float arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; +Mat a_mat(2, 2, CV_32FC3, arr); +Eigen::TensorMap> a_tensormap = cv2eigen_tensormap(a_mat); +\endcode +*/ +template static inline +Eigen::TensorMap> cv2eigen_tensormap(InputArray src) +{ + Mat mat = src.getMat(); + CV_CheckTypeEQ(mat.type(), CV_MAKETYPE(traits::Type<_Tp>::value, mat.channels()), ""); + return Eigen::TensorMap>((_Tp *)mat.data, mat.rows, mat.cols, mat.channels()); +} +#endif // OPENCV_EIGEN_TENSOR_SUPPORT + +template static inline +void eigen2cv( const Eigen::Matrix<_Tp, _rows, _cols, _options, _maxRows, _maxCols>& src, OutputArray dst ) +{ + if( !(src.Flags & Eigen::RowMajorBit) ) + { + Mat _src(src.cols(), src.rows(), traits::Type<_Tp>::value, + (void*)src.data(), src.outerStride()*sizeof(_Tp)); + transpose(_src, dst); + } + else + { + Mat _src(src.rows(), src.cols(), traits::Type<_Tp>::value, + (void*)src.data(), src.outerStride()*sizeof(_Tp)); + _src.copyTo(dst); + } +} + +// Matx case +template static inline +void eigen2cv( const Eigen::Matrix<_Tp, _rows, _cols, _options, _maxRows, _maxCols>& src, + Matx<_Tp, _rows, _cols>& dst ) +{ + if( !(src.Flags & Eigen::RowMajorBit) ) + { + dst = Matx<_Tp, _cols, _rows>(static_cast(src.data())).t(); + } + else + { + dst = Matx<_Tp, _rows, _cols>(static_cast(src.data())); + } +} + +template static inline +void cv2eigen( const Mat& src, + Eigen::Matrix<_Tp, _rows, _cols, _options, _maxRows, _maxCols>& dst ) +{ + CV_DbgAssert(src.rows == _rows && src.cols == _cols); + if( !(dst.Flags & Eigen::RowMajorBit) ) + { + const Mat _dst(src.cols, src.rows, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); + if( src.type() == _dst.type() ) + transpose(src, _dst); + else if( src.cols == src.rows ) + { + src.convertTo(_dst, _dst.type()); + transpose(_dst, _dst); + } + else + Mat(src.t()).convertTo(_dst, _dst.type()); + } + else + { + const Mat _dst(src.rows, src.cols, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); + src.convertTo(_dst, _dst.type()); + } +} + +// Matx case +template static inline +void cv2eigen( const Matx<_Tp, _rows, _cols>& src, + Eigen::Matrix<_Tp, _rows, _cols, _options, _maxRows, _maxCols>& dst ) +{ + if( !(dst.Flags & Eigen::RowMajorBit) ) + { + const Mat _dst(_cols, _rows, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); + transpose(src, _dst); + } + else + { + const Mat _dst(_rows, _cols, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); + Mat(src).copyTo(_dst); + } +} + +template static inline +void cv2eigen( const Mat& src, + Eigen::Matrix<_Tp, Eigen::Dynamic, Eigen::Dynamic>& dst ) +{ + dst.resize(src.rows, src.cols); + if( !(dst.Flags & Eigen::RowMajorBit) ) + { + const Mat _dst(src.cols, src.rows, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); + if( src.type() == _dst.type() ) + transpose(src, _dst); + else if( src.cols == src.rows ) + { + src.convertTo(_dst, _dst.type()); + transpose(_dst, _dst); + } + else + Mat(src.t()).convertTo(_dst, _dst.type()); + } + else + { + const Mat _dst(src.rows, src.cols, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); + src.convertTo(_dst, _dst.type()); + } +} + +// Matx case +template static inline +void cv2eigen( const Matx<_Tp, _rows, _cols>& src, + Eigen::Matrix<_Tp, Eigen::Dynamic, Eigen::Dynamic>& dst ) +{ + dst.resize(_rows, _cols); + if( !(dst.Flags & Eigen::RowMajorBit) ) + { + const Mat _dst(_cols, _rows, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); + transpose(src, _dst); + } + else + { + const Mat _dst(_rows, _cols, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); + Mat(src).copyTo(_dst); + } +} + +template static inline +void cv2eigen( const Mat& src, + Eigen::Matrix<_Tp, Eigen::Dynamic, 1>& dst ) +{ + CV_Assert(src.cols == 1); + dst.resize(src.rows); + + if( !(dst.Flags & Eigen::RowMajorBit) ) + { + const Mat _dst(src.cols, src.rows, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); + if( src.type() == _dst.type() ) + transpose(src, _dst); + else + Mat(src.t()).convertTo(_dst, _dst.type()); + } + else + { + const Mat _dst(src.rows, src.cols, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); + src.convertTo(_dst, _dst.type()); + } +} + +// Matx case +template static inline +void cv2eigen( const Matx<_Tp, _rows, 1>& src, + Eigen::Matrix<_Tp, Eigen::Dynamic, 1>& dst ) +{ + dst.resize(_rows); + + if( !(dst.Flags & Eigen::RowMajorBit) ) + { + const Mat _dst(1, _rows, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); + transpose(src, _dst); + } + else + { + const Mat _dst(_rows, 1, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); + src.copyTo(_dst); + } +} + + +template static inline +void cv2eigen( const Mat& src, + Eigen::Matrix<_Tp, 1, Eigen::Dynamic>& dst ) +{ + CV_Assert(src.rows == 1); + dst.resize(src.cols); + if( !(dst.Flags & Eigen::RowMajorBit) ) + { + const Mat _dst(src.cols, src.rows, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); + if( src.type() == _dst.type() ) + transpose(src, _dst); + else + Mat(src.t()).convertTo(_dst, _dst.type()); + } + else + { + const Mat _dst(src.rows, src.cols, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); + src.convertTo(_dst, _dst.type()); + } +} + +//Matx +template static inline +void cv2eigen( const Matx<_Tp, 1, _cols>& src, + Eigen::Matrix<_Tp, 1, Eigen::Dynamic>& dst ) +{ + dst.resize(_cols); + if( !(dst.Flags & Eigen::RowMajorBit) ) + { + const Mat _dst(_cols, 1, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); + transpose(src, _dst); + } + else + { + const Mat _dst(1, _cols, traits::Type<_Tp>::value, + dst.data(), (size_t)(dst.outerStride()*sizeof(_Tp))); + Mat(src).copyTo(_dst); + } +} + +//! @} + +} // cv + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/fast_math.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/fast_math.hpp new file mode 100644 index 0000000..eb4fbe2 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/fast_math.hpp @@ -0,0 +1,411 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_FAST_MATH_HPP +#define OPENCV_CORE_FAST_MATH_HPP + +#include "opencv2/core/cvdef.h" + +//! @addtogroup core_utils +//! @{ + +/****************************************************************************************\ +* fast math * +\****************************************************************************************/ + +#ifdef __cplusplus +# include +#else +# ifdef __BORLANDC__ +# include +# else +# include +# endif +#endif + +#if defined(__CUDACC__) + // nothing, intrinsics/asm code is not supported +#else + #if ((defined _MSC_VER && defined _M_X64) \ + || (defined __GNUC__ && defined __x86_64__ && defined __SSE2__)) \ + && !defined(OPENCV_SKIP_INCLUDE_EMMINTRIN_H) + #include + #endif + + #if defined __PPC64__ && defined __GNUC__ && defined _ARCH_PWR8 \ + && !defined(OPENCV_SKIP_INCLUDE_ALTIVEC_H) + #include + #undef vector + #undef bool + #undef pixel + #endif + + #if defined(CV_INLINE_ROUND_FLT) + // user-specified version + // CV_INLINE_ROUND_DBL should be defined too + #elif defined __GNUC__ && defined __arm__ && (defined __ARM_PCS_VFP || defined __ARM_VFPV3__ || defined __ARM_NEON__) && !defined __SOFTFP__ + // 1. general scheme + #define ARM_ROUND(_value, _asm_string) \ + int res; \ + float temp; \ + CV_UNUSED(temp); \ + __asm__(_asm_string : [res] "=r" (res), [temp] "=w" (temp) : [value] "w" (_value)); \ + return res + // 2. version for double + #ifdef __clang__ + #define CV_INLINE_ROUND_DBL(value) ARM_ROUND(value, "vcvtr.s32.f64 %[temp], %[value] \n vmov %[res], %[temp]") + #else + #define CV_INLINE_ROUND_DBL(value) ARM_ROUND(value, "vcvtr.s32.f64 %[temp], %P[value] \n vmov %[res], %[temp]") + #endif + // 3. version for float + #define CV_INLINE_ROUND_FLT(value) ARM_ROUND(value, "vcvtr.s32.f32 %[temp], %[value]\n vmov %[res], %[temp]") + #elif defined __PPC64__ && defined __GNUC__ && defined _ARCH_PWR8 + // P8 and newer machines can convert fp32/64 to int quickly. + #define CV_INLINE_ROUND_DBL(value) \ + int out; \ + double temp; \ + __asm__( "fctiw %[temp],%[in]\n\tmfvsrwz %[out],%[temp]\n\t" : [out] "=r" (out), [temp] "=d" (temp) : [in] "d" ((double)(value)) : ); \ + return out; + + // FP32 also works with FP64 routine above + #define CV_INLINE_ROUND_FLT(value) CV_INLINE_ROUND_DBL(value) + #endif + + #ifdef CV_INLINE_ISINF_FLT + // user-specified version + // CV_INLINE_ISINF_DBL should be defined too + #elif defined __PPC64__ && defined _ARCH_PWR9 && defined(scalar_test_data_class) + #define CV_INLINE_ISINF_DBL(value) return scalar_test_data_class(value, 0x30); + #define CV_INLINE_ISINF_FLT(value) CV_INLINE_ISINF_DBL(value) + #endif + + #ifdef CV_INLINE_ISNAN_FLT + // user-specified version + // CV_INLINE_ISNAN_DBL should be defined too + #elif defined __PPC64__ && defined _ARCH_PWR9 && defined(scalar_test_data_class) + #define CV_INLINE_ISNAN_DBL(value) return scalar_test_data_class(value, 0x40); + #define CV_INLINE_ISNAN_FLT(value) CV_INLINE_ISNAN_DBL(value) + #endif + + #if !defined(OPENCV_USE_FASTMATH_BUILTINS) \ + && ( \ + defined(__x86_64__) || defined(__i686__) \ + || defined(__arm__) \ + || defined(__PPC64__) \ + ) + /* Let builtin C math functions when available. Dedicated hardware is available to + round and convert FP values. */ + #define OPENCV_USE_FASTMATH_BUILTINS 1 + #endif + + /* Enable builtin math functions if possible, desired, and available. + Note, not all math functions inline equally. E.g lrint will not inline + without the -fno-math-errno option. */ + #if defined(CV_ICC) + // nothing + #elif defined(OPENCV_USE_FASTMATH_BUILTINS) && OPENCV_USE_FASTMATH_BUILTINS + #if defined(__clang__) + #define CV__FASTMATH_ENABLE_CLANG_MATH_BUILTINS + #if !defined(CV_INLINE_ISNAN_DBL) && __has_builtin(__builtin_isnan) + #define CV_INLINE_ISNAN_DBL(value) return __builtin_isnan(value); + #endif + #if !defined(CV_INLINE_ISNAN_FLT) && __has_builtin(__builtin_isnan) + #define CV_INLINE_ISNAN_FLT(value) return __builtin_isnan(value); + #endif + #if !defined(CV_INLINE_ISINF_DBL) && __has_builtin(__builtin_isinf) + #define CV_INLINE_ISINF_DBL(value) return __builtin_isinf(value); + #endif + #if !defined(CV_INLINE_ISINF_FLT) && __has_builtin(__builtin_isinf) + #define CV_INLINE_ISINF_FLT(value) return __builtin_isinf(value); + #endif + #elif defined(__GNUC__) + #define CV__FASTMATH_ENABLE_GCC_MATH_BUILTINS + #if !defined(CV_INLINE_ISNAN_DBL) + #define CV_INLINE_ISNAN_DBL(value) return __builtin_isnan(value); + #endif + #if !defined(CV_INLINE_ISNAN_FLT) + #define CV_INLINE_ISNAN_FLT(value) return __builtin_isnanf(value); + #endif + #if !defined(CV_INLINE_ISINF_DBL) + #define CV_INLINE_ISINF_DBL(value) return __builtin_isinf(value); + #endif + #if !defined(CV_INLINE_ISINF_FLT) + #define CV_INLINE_ISINF_FLT(value) return __builtin_isinff(value); + #endif + #elif defined(_MSC_VER) + #if !defined(CV_INLINE_ISNAN_DBL) + #define CV_INLINE_ISNAN_DBL(value) return isnan(value); + #endif + #if !defined(CV_INLINE_ISNAN_FLT) + #define CV_INLINE_ISNAN_FLT(value) return isnan(value); + #endif + #if !defined(CV_INLINE_ISINF_DBL) + #define CV_INLINE_ISINF_DBL(value) return isinf(value); + #endif + #if !defined(CV_INLINE_ISINF_FLT) + #define CV_INLINE_ISINF_FLT(value) return isinf(value); + #endif + #endif + #endif + +#endif // defined(__CUDACC__) + +/** @brief Rounds floating-point number to the nearest integer + + @param value floating-point number. If the value is outside of INT_MIN ... INT_MAX range, the + result is not defined. + */ +CV_INLINE int +cvRound( double value ) +{ +#if defined CV_INLINE_ROUND_DBL + CV_INLINE_ROUND_DBL(value); +#elif ((defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__ \ + && defined __SSE2__ && !defined __APPLE__) || CV_SSE2) \ + && !defined(__CUDACC__) + __m128d t = _mm_set_sd( value ); + return _mm_cvtsd_si32(t); +#elif defined _MSC_VER && defined _M_IX86 + int t; + __asm + { + fld value; + fistp t; + } + return t; +#elif defined CV_ICC || defined __GNUC__ + return (int)(lrint(value)); +#else + /* it's ok if round does not comply with IEEE754 standard; + the tests should allow +/-1 difference when the tested functions use round */ + return (int)(value + (value >= 0 ? 0.5 : -0.5)); +#endif +} + + +/** @brief Rounds floating-point number to the nearest integer not larger than the original. + + The function computes an integer i such that: + \f[i \le \texttt{value} < i+1\f] + @param value floating-point number. If the value is outside of INT_MIN ... INT_MAX range, the + result is not defined. + */ +CV_INLINE int cvFloor( double value ) +{ +#if (defined CV__FASTMATH_ENABLE_GCC_MATH_BUILTINS || defined CV__FASTMATH_ENABLE_CLANG_MATH_BUILTINS) \ + && ( \ + defined(__PPC64__) \ + ) + return __builtin_floor(value); +#else + int i = (int)value; + return i - (i > value); +#endif +} + +/** @brief Rounds floating-point number to the nearest integer not smaller than the original. + + The function computes an integer i such that: + \f[i \le \texttt{value} < i+1\f] + @param value floating-point number. If the value is outside of INT_MIN ... INT_MAX range, the + result is not defined. + */ +CV_INLINE int cvCeil( double value ) +{ +#if (defined CV__FASTMATH_ENABLE_GCC_MATH_BUILTINS || defined CV__FASTMATH_ENABLE_CLANG_MATH_BUILTINS) \ + && ( \ + defined(__PPC64__) \ + ) + return __builtin_ceil(value); +#else + int i = (int)value; + return i + (i < value); +#endif +} + +/** @brief Determines if the argument is Not A Number. + + @param value The input floating-point value + + The function returns 1 if the argument is Not A Number (as defined by IEEE754 standard), 0 + otherwise. */ +CV_INLINE int cvIsNaN( double value ) +{ +#if defined CV_INLINE_ISNAN_DBL + CV_INLINE_ISNAN_DBL(value); +#else + Cv64suf ieee754; + ieee754.f = value; + return ((unsigned)(ieee754.u >> 32) & 0x7fffffff) + + ((unsigned)ieee754.u != 0) > 0x7ff00000; +#endif +} + +/** @brief Determines if the argument is Infinity. + + @param value The input floating-point value + + The function returns 1 if the argument is a plus or minus infinity (as defined by IEEE754 standard) + and 0 otherwise. */ +CV_INLINE int cvIsInf( double value ) +{ +#if defined CV_INLINE_ISINF_DBL + CV_INLINE_ISINF_DBL(value); +#elif defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__PPC64__) + Cv64suf ieee754; + ieee754.f = value; + return (ieee754.u & 0x7fffffff00000000) == + 0x7ff0000000000000; +#else + Cv64suf ieee754; + ieee754.f = value; + return ((unsigned)(ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 && + (unsigned)ieee754.u == 0; +#endif +} + +#ifdef __cplusplus + +/** @overload */ +CV_INLINE int cvRound(float value) +{ +#if defined CV_INLINE_ROUND_FLT + CV_INLINE_ROUND_FLT(value); +#elif ((defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__ \ + && defined __SSE2__ && !defined __APPLE__) || CV_SSE2) \ + && !defined(__CUDACC__) + __m128 t = _mm_set_ss( value ); + return _mm_cvtss_si32(t); +#elif defined _MSC_VER && defined _M_IX86 + int t; + __asm + { + fld value; + fistp t; + } + return t; +#elif defined CV_ICC || defined __GNUC__ + return (int)(lrintf(value)); +#else + /* it's ok if round does not comply with IEEE754 standard; + the tests should allow +/-1 difference when the tested functions use round */ + return (int)(value + (value >= 0 ? 0.5f : -0.5f)); +#endif +} + +/** @overload */ +CV_INLINE int cvRound( int value ) +{ + return value; +} + +/** @overload */ +CV_INLINE int cvFloor( float value ) +{ +#if (defined CV__FASTMATH_ENABLE_GCC_MATH_BUILTINS || defined CV__FASTMATH_ENABLE_CLANG_MATH_BUILTINS) \ + && ( \ + defined(__PPC64__) \ + ) + return __builtin_floorf(value); +#else + int i = (int)value; + return i - (i > value); +#endif +} + +/** @overload */ +CV_INLINE int cvFloor( int value ) +{ + return value; +} + +/** @overload */ +CV_INLINE int cvCeil( float value ) +{ +#if (defined CV__FASTMATH_ENABLE_GCC_MATH_BUILTINS || defined CV__FASTMATH_ENABLE_CLANG_MATH_BUILTINS) \ + && ( \ + defined(__PPC64__) \ + ) + return __builtin_ceilf(value); +#else + int i = (int)value; + return i + (i < value); +#endif +} + +/** @overload */ +CV_INLINE int cvCeil( int value ) +{ + return value; +} + +/** @overload */ +CV_INLINE int cvIsNaN( float value ) +{ +#if defined CV_INLINE_ISNAN_FLT + CV_INLINE_ISNAN_FLT(value); +#else + Cv32suf ieee754; + ieee754.f = value; + return (ieee754.u & 0x7fffffff) > 0x7f800000; +#endif +} + +/** @overload */ +CV_INLINE int cvIsInf( float value ) +{ +#if defined CV_INLINE_ISINF_FLT + CV_INLINE_ISINF_FLT(value); +#else + Cv32suf ieee754; + ieee754.f = value; + return (ieee754.u & 0x7fffffff) == 0x7f800000; +#endif +} + +#endif // __cplusplus + +//! @} core_utils + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/hal.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/hal.hpp new file mode 100644 index 0000000..0d68078 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/hal.hpp @@ -0,0 +1,256 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_HAL_HPP +#define OPENCV_HAL_HPP + +#include "opencv2/core/cvdef.h" +#include "opencv2/core/cvstd.hpp" +#include "opencv2/core/hal/interface.h" + +namespace cv { namespace hal { + +//! @addtogroup core_hal_functions +//! @{ + +CV_EXPORTS int normHamming(const uchar* a, int n); +CV_EXPORTS int normHamming(const uchar* a, const uchar* b, int n); + +CV_EXPORTS int normHamming(const uchar* a, int n, int cellSize); +CV_EXPORTS int normHamming(const uchar* a, const uchar* b, int n, int cellSize); + +CV_EXPORTS int LU32f(float* A, size_t astep, int m, float* b, size_t bstep, int n); +CV_EXPORTS int LU64f(double* A, size_t astep, int m, double* b, size_t bstep, int n); +CV_EXPORTS bool Cholesky32f(float* A, size_t astep, int m, float* b, size_t bstep, int n); +CV_EXPORTS bool Cholesky64f(double* A, size_t astep, int m, double* b, size_t bstep, int n); +CV_EXPORTS void SVD32f(float* At, size_t astep, float* W, float* U, size_t ustep, float* Vt, size_t vstep, int m, int n, int flags); +CV_EXPORTS void SVD64f(double* At, size_t astep, double* W, double* U, size_t ustep, double* Vt, size_t vstep, int m, int n, int flags); +CV_EXPORTS int QR32f(float* A, size_t astep, int m, int n, int k, float* b, size_t bstep, float* hFactors); +CV_EXPORTS int QR64f(double* A, size_t astep, int m, int n, int k, double* b, size_t bstep, double* hFactors); + +CV_EXPORTS void gemm32f(const float* src1, size_t src1_step, const float* src2, size_t src2_step, + float alpha, const float* src3, size_t src3_step, float beta, float* dst, size_t dst_step, + int m_a, int n_a, int n_d, int flags); +CV_EXPORTS void gemm64f(const double* src1, size_t src1_step, const double* src2, size_t src2_step, + double alpha, const double* src3, size_t src3_step, double beta, double* dst, size_t dst_step, + int m_a, int n_a, int n_d, int flags); +CV_EXPORTS void gemm32fc(const float* src1, size_t src1_step, const float* src2, size_t src2_step, + float alpha, const float* src3, size_t src3_step, float beta, float* dst, size_t dst_step, + int m_a, int n_a, int n_d, int flags); +CV_EXPORTS void gemm64fc(const double* src1, size_t src1_step, const double* src2, size_t src2_step, + double alpha, const double* src3, size_t src3_step, double beta, double* dst, size_t dst_step, + int m_a, int n_a, int n_d, int flags); + +CV_EXPORTS int normL1_(const uchar* a, const uchar* b, int n); +CV_EXPORTS float normL1_(const float* a, const float* b, int n); +CV_EXPORTS float normL2Sqr_(const float* a, const float* b, int n); + +CV_EXPORTS void exp32f(const float* src, float* dst, int n); +CV_EXPORTS void exp64f(const double* src, double* dst, int n); +CV_EXPORTS void log32f(const float* src, float* dst, int n); +CV_EXPORTS void log64f(const double* src, double* dst, int n); + +CV_EXPORTS void fastAtan32f(const float* y, const float* x, float* dst, int n, bool angleInDegrees); +CV_EXPORTS void fastAtan64f(const double* y, const double* x, double* dst, int n, bool angleInDegrees); +CV_EXPORTS void magnitude32f(const float* x, const float* y, float* dst, int n); +CV_EXPORTS void magnitude64f(const double* x, const double* y, double* dst, int n); +CV_EXPORTS void sqrt32f(const float* src, float* dst, int len); +CV_EXPORTS void sqrt64f(const double* src, double* dst, int len); +CV_EXPORTS void invSqrt32f(const float* src, float* dst, int len); +CV_EXPORTS void invSqrt64f(const double* src, double* dst, int len); + +CV_EXPORTS void split8u(const uchar* src, uchar** dst, int len, int cn ); +CV_EXPORTS void split16u(const ushort* src, ushort** dst, int len, int cn ); +CV_EXPORTS void split32s(const int* src, int** dst, int len, int cn ); +CV_EXPORTS void split64s(const int64* src, int64** dst, int len, int cn ); + +CV_EXPORTS void merge8u(const uchar** src, uchar* dst, int len, int cn ); +CV_EXPORTS void merge16u(const ushort** src, ushort* dst, int len, int cn ); +CV_EXPORTS void merge32s(const int** src, int* dst, int len, int cn ); +CV_EXPORTS void merge64s(const int64** src, int64* dst, int len, int cn ); + +CV_EXPORTS void add8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void add8s( const schar* src1, size_t step1, const schar* src2, size_t step2, schar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void add16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, ushort* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void add16s( const short* src1, size_t step1, const short* src2, size_t step2, short* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void add32s( const int* src1, size_t step1, const int* src2, size_t step2, int* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void add32f( const float* src1, size_t step1, const float* src2, size_t step2, float* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void add64f( const double* src1, size_t step1, const double* src2, size_t step2, double* dst, size_t step, int width, int height, void* ); + +CV_EXPORTS void sub8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void sub8s( const schar* src1, size_t step1, const schar* src2, size_t step2, schar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void sub16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, ushort* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void sub16s( const short* src1, size_t step1, const short* src2, size_t step2, short* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void sub32s( const int* src1, size_t step1, const int* src2, size_t step2, int* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void sub32f( const float* src1, size_t step1, const float* src2, size_t step2, float* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void sub64f( const double* src1, size_t step1, const double* src2, size_t step2, double* dst, size_t step, int width, int height, void* ); + +CV_EXPORTS void max8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void max8s( const schar* src1, size_t step1, const schar* src2, size_t step2, schar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void max16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, ushort* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void max16s( const short* src1, size_t step1, const short* src2, size_t step2, short* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void max32s( const int* src1, size_t step1, const int* src2, size_t step2, int* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void max32f( const float* src1, size_t step1, const float* src2, size_t step2, float* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void max64f( const double* src1, size_t step1, const double* src2, size_t step2, double* dst, size_t step, int width, int height, void* ); + +CV_EXPORTS void min8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void min8s( const schar* src1, size_t step1, const schar* src2, size_t step2, schar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void min16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, ushort* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void min16s( const short* src1, size_t step1, const short* src2, size_t step2, short* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void min32s( const int* src1, size_t step1, const int* src2, size_t step2, int* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void min32f( const float* src1, size_t step1, const float* src2, size_t step2, float* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void min64f( const double* src1, size_t step1, const double* src2, size_t step2, double* dst, size_t step, int width, int height, void* ); + +CV_EXPORTS void absdiff8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void absdiff8s( const schar* src1, size_t step1, const schar* src2, size_t step2, schar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void absdiff16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, ushort* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void absdiff16s( const short* src1, size_t step1, const short* src2, size_t step2, short* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void absdiff32s( const int* src1, size_t step1, const int* src2, size_t step2, int* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void absdiff32f( const float* src1, size_t step1, const float* src2, size_t step2, float* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void absdiff64f( const double* src1, size_t step1, const double* src2, size_t step2, double* dst, size_t step, int width, int height, void* ); + +CV_EXPORTS void and8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void or8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void xor8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* ); +CV_EXPORTS void not8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* ); + +CV_EXPORTS void cmp8u(const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* _cmpop); +CV_EXPORTS void cmp8s(const schar* src1, size_t step1, const schar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* _cmpop); +CV_EXPORTS void cmp16u(const ushort* src1, size_t step1, const ushort* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* _cmpop); +CV_EXPORTS void cmp16s(const short* src1, size_t step1, const short* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* _cmpop); +CV_EXPORTS void cmp32s(const int* src1, size_t step1, const int* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* _cmpop); +CV_EXPORTS void cmp32f(const float* src1, size_t step1, const float* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* _cmpop); +CV_EXPORTS void cmp64f(const double* src1, size_t step1, const double* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* _cmpop); + +CV_EXPORTS void mul8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void mul8s( const schar* src1, size_t step1, const schar* src2, size_t step2, schar* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void mul16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, ushort* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void mul16s( const short* src1, size_t step1, const short* src2, size_t step2, short* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void mul32s( const int* src1, size_t step1, const int* src2, size_t step2, int* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void mul32f( const float* src1, size_t step1, const float* src2, size_t step2, float* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void mul64f( const double* src1, size_t step1, const double* src2, size_t step2, double* dst, size_t step, int width, int height, void* scale); + +CV_EXPORTS void div8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void div8s( const schar* src1, size_t step1, const schar* src2, size_t step2, schar* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void div16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, ushort* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void div16s( const short* src1, size_t step1, const short* src2, size_t step2, short* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void div32s( const int* src1, size_t step1, const int* src2, size_t step2, int* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void div32f( const float* src1, size_t step1, const float* src2, size_t step2, float* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void div64f( const double* src1, size_t step1, const double* src2, size_t step2, double* dst, size_t step, int width, int height, void* scale); + +CV_EXPORTS void recip8u( const uchar *, size_t, const uchar * src2, size_t step2, uchar* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void recip8s( const schar *, size_t, const schar * src2, size_t step2, schar* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void recip16u( const ushort *, size_t, const ushort * src2, size_t step2, ushort* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void recip16s( const short *, size_t, const short * src2, size_t step2, short* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void recip32s( const int *, size_t, const int * src2, size_t step2, int* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void recip32f( const float *, size_t, const float * src2, size_t step2, float* dst, size_t step, int width, int height, void* scale); +CV_EXPORTS void recip64f( const double *, size_t, const double * src2, size_t step2, double* dst, size_t step, int width, int height, void* scale); + +CV_EXPORTS void addWeighted8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* _scalars ); +CV_EXPORTS void addWeighted8s( const schar* src1, size_t step1, const schar* src2, size_t step2, schar* dst, size_t step, int width, int height, void* scalars ); +CV_EXPORTS void addWeighted16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, ushort* dst, size_t step, int width, int height, void* scalars ); +CV_EXPORTS void addWeighted16s( const short* src1, size_t step1, const short* src2, size_t step2, short* dst, size_t step, int width, int height, void* scalars ); +CV_EXPORTS void addWeighted32s( const int* src1, size_t step1, const int* src2, size_t step2, int* dst, size_t step, int width, int height, void* scalars ); +CV_EXPORTS void addWeighted32f( const float* src1, size_t step1, const float* src2, size_t step2, float* dst, size_t step, int width, int height, void* scalars ); +CV_EXPORTS void addWeighted64f( const double* src1, size_t step1, const double* src2, size_t step2, double* dst, size_t step, int width, int height, void* scalars ); + +CV_EXPORTS void cvt16f32f( const float16_t* src, float* dst, int len ); +CV_EXPORTS void cvt32f16f( const float* src, float16_t* dst, int len ); + +CV_EXPORTS void addRNGBias32f( float* arr, const float* scaleBiasPairs, int len ); +CV_EXPORTS void addRNGBias64f( double* arr, const double* scaleBiasPairs, int len ); + +struct CV_EXPORTS DFT1D +{ + static Ptr create(int len, int count, int depth, int flags, bool * useBuffer = 0); + virtual void apply(const uchar *src, uchar *dst) = 0; + virtual ~DFT1D() {} +}; + +struct CV_EXPORTS DFT2D +{ + static Ptr create(int width, int height, int depth, + int src_channels, int dst_channels, + int flags, int nonzero_rows = 0); + virtual void apply(const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step) = 0; + virtual ~DFT2D() {} +}; + +struct CV_EXPORTS DCT2D +{ + static Ptr create(int width, int height, int depth, int flags); + virtual void apply(const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step) = 0; + virtual ~DCT2D() {} +}; + +//! @} core_hal + +//============================================================================= +// for binary compatibility with 3.0 + +//! @cond IGNORED + +CV_EXPORTS int LU(float* A, size_t astep, int m, float* b, size_t bstep, int n); +CV_EXPORTS int LU(double* A, size_t astep, int m, double* b, size_t bstep, int n); +CV_EXPORTS bool Cholesky(float* A, size_t astep, int m, float* b, size_t bstep, int n); +CV_EXPORTS bool Cholesky(double* A, size_t astep, int m, double* b, size_t bstep, int n); + +CV_EXPORTS void exp(const float* src, float* dst, int n); +CV_EXPORTS void exp(const double* src, double* dst, int n); +CV_EXPORTS void log(const float* src, float* dst, int n); +CV_EXPORTS void log(const double* src, double* dst, int n); + +CV_EXPORTS void fastAtan2(const float* y, const float* x, float* dst, int n, bool angleInDegrees); +CV_EXPORTS void magnitude(const float* x, const float* y, float* dst, int n); +CV_EXPORTS void magnitude(const double* x, const double* y, double* dst, int n); +CV_EXPORTS void sqrt(const float* src, float* dst, int len); +CV_EXPORTS void sqrt(const double* src, double* dst, int len); +CV_EXPORTS void invSqrt(const float* src, float* dst, int len); +CV_EXPORTS void invSqrt(const double* src, double* dst, int len); + +//! @endcond + +}} //cv::hal + +#endif //OPENCV_HAL_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/interface.h b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/interface.h new file mode 100644 index 0000000..6f0a83d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/interface.h @@ -0,0 +1,190 @@ +#ifndef OPENCV_CORE_HAL_INTERFACE_H +#define OPENCV_CORE_HAL_INTERFACE_H + +//! @addtogroup core_hal_interface +//! @{ + +//! @name Return codes +//! @{ +#define CV_HAL_ERROR_OK 0 +#define CV_HAL_ERROR_NOT_IMPLEMENTED 1 +#define CV_HAL_ERROR_UNKNOWN -1 +//! @} + +#ifdef __cplusplus +#include +#else +#include +#include +#endif + +//! @name Data types +//! primitive types +//! - schar - signed 1 byte integer +//! - uchar - unsigned 1 byte integer +//! - short - signed 2 byte integer +//! - ushort - unsigned 2 byte integer +//! - int - signed 4 byte integer +//! - uint - unsigned 4 byte integer +//! - int64 - signed 8 byte integer +//! - uint64 - unsigned 8 byte integer +//! @{ +#if !defined _MSC_VER && !defined __BORLANDC__ +# if defined __cplusplus && __cplusplus >= 201103L && !defined __APPLE__ +# include +# ifdef __NEWLIB__ + typedef unsigned int uint; +# else + typedef std::uint32_t uint; +# endif +# else +# include + typedef uint32_t uint; +# endif +#else + typedef unsigned uint; +#endif + +typedef signed char schar; + +#ifndef __IPL_H__ + typedef unsigned char uchar; + typedef unsigned short ushort; +#endif + +#if defined _MSC_VER || defined __BORLANDC__ + typedef __int64 int64; + typedef unsigned __int64 uint64; +# define CV_BIG_INT(n) n##I64 +# define CV_BIG_UINT(n) n##UI64 +#else + typedef int64_t int64; + typedef uint64_t uint64; +# define CV_BIG_INT(n) n##LL +# define CV_BIG_UINT(n) n##ULL +#endif + +#define CV_USRTYPE1 (void)"CV_USRTYPE1 support has been dropped in OpenCV 4.0" + +#define CV_CN_MAX 512 +#define CV_CN_SHIFT 3 +#define CV_DEPTH_MAX (1 << CV_CN_SHIFT) + +#define CV_8U 0 +#define CV_8S 1 +#define CV_16U 2 +#define CV_16S 3 +#define CV_32S 4 +#define CV_32F 5 +#define CV_64F 6 +#define CV_16F 7 + +#define CV_MAT_DEPTH_MASK (CV_DEPTH_MAX - 1) +#define CV_MAT_DEPTH(flags) ((flags) & CV_MAT_DEPTH_MASK) + +#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT)) +#define CV_MAKE_TYPE CV_MAKETYPE + +#define CV_8UC1 CV_MAKETYPE(CV_8U,1) +#define CV_8UC2 CV_MAKETYPE(CV_8U,2) +#define CV_8UC3 CV_MAKETYPE(CV_8U,3) +#define CV_8UC4 CV_MAKETYPE(CV_8U,4) +#define CV_8UC(n) CV_MAKETYPE(CV_8U,(n)) + +#define CV_8SC1 CV_MAKETYPE(CV_8S,1) +#define CV_8SC2 CV_MAKETYPE(CV_8S,2) +#define CV_8SC3 CV_MAKETYPE(CV_8S,3) +#define CV_8SC4 CV_MAKETYPE(CV_8S,4) +#define CV_8SC(n) CV_MAKETYPE(CV_8S,(n)) + +#define CV_16UC1 CV_MAKETYPE(CV_16U,1) +#define CV_16UC2 CV_MAKETYPE(CV_16U,2) +#define CV_16UC3 CV_MAKETYPE(CV_16U,3) +#define CV_16UC4 CV_MAKETYPE(CV_16U,4) +#define CV_16UC(n) CV_MAKETYPE(CV_16U,(n)) + +#define CV_16SC1 CV_MAKETYPE(CV_16S,1) +#define CV_16SC2 CV_MAKETYPE(CV_16S,2) +#define CV_16SC3 CV_MAKETYPE(CV_16S,3) +#define CV_16SC4 CV_MAKETYPE(CV_16S,4) +#define CV_16SC(n) CV_MAKETYPE(CV_16S,(n)) + +#define CV_32SC1 CV_MAKETYPE(CV_32S,1) +#define CV_32SC2 CV_MAKETYPE(CV_32S,2) +#define CV_32SC3 CV_MAKETYPE(CV_32S,3) +#define CV_32SC4 CV_MAKETYPE(CV_32S,4) +#define CV_32SC(n) CV_MAKETYPE(CV_32S,(n)) + +#define CV_32FC1 CV_MAKETYPE(CV_32F,1) +#define CV_32FC2 CV_MAKETYPE(CV_32F,2) +#define CV_32FC3 CV_MAKETYPE(CV_32F,3) +#define CV_32FC4 CV_MAKETYPE(CV_32F,4) +#define CV_32FC(n) CV_MAKETYPE(CV_32F,(n)) + +#define CV_64FC1 CV_MAKETYPE(CV_64F,1) +#define CV_64FC2 CV_MAKETYPE(CV_64F,2) +#define CV_64FC3 CV_MAKETYPE(CV_64F,3) +#define CV_64FC4 CV_MAKETYPE(CV_64F,4) +#define CV_64FC(n) CV_MAKETYPE(CV_64F,(n)) + +#define CV_16FC1 CV_MAKETYPE(CV_16F,1) +#define CV_16FC2 CV_MAKETYPE(CV_16F,2) +#define CV_16FC3 CV_MAKETYPE(CV_16F,3) +#define CV_16FC4 CV_MAKETYPE(CV_16F,4) +#define CV_16FC(n) CV_MAKETYPE(CV_16F,(n)) +//! @} + +//! @name Comparison operation +//! @sa cv::CmpTypes +//! @{ +#define CV_HAL_CMP_EQ 0 +#define CV_HAL_CMP_GT 1 +#define CV_HAL_CMP_GE 2 +#define CV_HAL_CMP_LT 3 +#define CV_HAL_CMP_LE 4 +#define CV_HAL_CMP_NE 5 +//! @} + +//! @name Border processing modes +//! @sa cv::BorderTypes +//! @{ +#define CV_HAL_BORDER_CONSTANT 0 +#define CV_HAL_BORDER_REPLICATE 1 +#define CV_HAL_BORDER_REFLECT 2 +#define CV_HAL_BORDER_WRAP 3 +#define CV_HAL_BORDER_REFLECT_101 4 +#define CV_HAL_BORDER_TRANSPARENT 5 +#define CV_HAL_BORDER_ISOLATED 16 +//! @} + +//! @name DFT flags +//! @{ +#define CV_HAL_DFT_INVERSE 1 +#define CV_HAL_DFT_SCALE 2 +#define CV_HAL_DFT_ROWS 4 +#define CV_HAL_DFT_COMPLEX_OUTPUT 16 +#define CV_HAL_DFT_REAL_OUTPUT 32 +#define CV_HAL_DFT_TWO_STAGE 64 +#define CV_HAL_DFT_STAGE_COLS 128 +#define CV_HAL_DFT_IS_CONTINUOUS 512 +#define CV_HAL_DFT_IS_INPLACE 1024 +//! @} + +//! @name SVD flags +//! @{ +#define CV_HAL_SVD_NO_UV 1 +#define CV_HAL_SVD_SHORT_UV 2 +#define CV_HAL_SVD_MODIFY_A 4 +#define CV_HAL_SVD_FULL_UV 8 +//! @} + +//! @name Gemm flags +//! @{ +#define CV_HAL_GEMM_1_T 1 +#define CV_HAL_GEMM_2_T 2 +#define CV_HAL_GEMM_3_T 4 +//! @} + +//! @} + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin.hpp new file mode 100644 index 0000000..ac331f2 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin.hpp @@ -0,0 +1,706 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_HAL_INTRIN_HPP +#define OPENCV_HAL_INTRIN_HPP + +#include +#include +#include +#include "opencv2/core/cvdef.h" + +#define OPENCV_HAL_ADD(a, b) ((a) + (b)) +#define OPENCV_HAL_AND(a, b) ((a) & (b)) +#define OPENCV_HAL_NOP(a) (a) +#define OPENCV_HAL_1ST(a, b) (a) + +namespace { +inline unsigned int trailingZeros32(unsigned int value) { +#if defined(_MSC_VER) +#if (_MSC_VER < 1700) || defined(_M_ARM) || defined(_M_ARM64) + unsigned long index = 0; + _BitScanForward(&index, value); + return (unsigned int)index; +#elif defined(__clang__) + // clang-cl doesn't export _tzcnt_u32 for non BMI systems + return value ? __builtin_ctz(value) : 32; +#else + return _tzcnt_u32(value); +#endif +#elif defined(__GNUC__) || defined(__GNUG__) + return __builtin_ctz(value); +#elif defined(__ICC) || defined(__INTEL_COMPILER) + return _bit_scan_forward(value); +#elif defined(__clang__) + return llvm.cttz.i32(value, true); +#else + static const int MultiplyDeBruijnBitPosition[32] = { + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 }; + return MultiplyDeBruijnBitPosition[((uint32_t)((value & -value) * 0x077CB531U)) >> 27]; +#endif +} +} + +// unlike HAL API, which is in cv::hal, +// we put intrinsics into cv namespace to make its +// access from within opencv code more accessible +namespace cv { + +namespace hal { + +enum StoreMode +{ + STORE_UNALIGNED = 0, + STORE_ALIGNED = 1, + STORE_ALIGNED_NOCACHE = 2 +}; + +} + +// TODO FIXIT: Don't use "God" traits. Split on separate cases. +template struct V_TypeTraits +{ +}; + +#define CV_INTRIN_DEF_TYPE_TRAITS(type, int_type_, uint_type_, abs_type_, w_type_, q_type_, sum_type_) \ + template<> struct V_TypeTraits \ + { \ + typedef type value_type; \ + typedef int_type_ int_type; \ + typedef abs_type_ abs_type; \ + typedef uint_type_ uint_type; \ + typedef w_type_ w_type; \ + typedef q_type_ q_type; \ + typedef sum_type_ sum_type; \ + \ + static inline int_type reinterpret_int(type x) \ + { \ + union { type l; int_type i; } v; \ + v.l = x; \ + return v.i; \ + } \ + \ + static inline type reinterpret_from_int(int_type x) \ + { \ + union { type l; int_type i; } v; \ + v.i = x; \ + return v.l; \ + } \ + } + +#define CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(type, int_type_, uint_type_, abs_type_, w_type_, sum_type_) \ + template<> struct V_TypeTraits \ + { \ + typedef type value_type; \ + typedef int_type_ int_type; \ + typedef abs_type_ abs_type; \ + typedef uint_type_ uint_type; \ + typedef w_type_ w_type; \ + typedef sum_type_ sum_type; \ + \ + static inline int_type reinterpret_int(type x) \ + { \ + union { type l; int_type i; } v; \ + v.l = x; \ + return v.i; \ + } \ + \ + static inline type reinterpret_from_int(int_type x) \ + { \ + union { type l; int_type i; } v; \ + v.i = x; \ + return v.l; \ + } \ + } + +CV_INTRIN_DEF_TYPE_TRAITS(uchar, schar, uchar, uchar, ushort, unsigned, unsigned); +CV_INTRIN_DEF_TYPE_TRAITS(schar, schar, uchar, uchar, short, int, int); +CV_INTRIN_DEF_TYPE_TRAITS(ushort, short, ushort, ushort, unsigned, uint64, unsigned); +CV_INTRIN_DEF_TYPE_TRAITS(short, short, ushort, ushort, int, int64, int); +CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(unsigned, int, unsigned, unsigned, uint64, unsigned); +CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(int, int, unsigned, unsigned, int64, int); +CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(float, int, unsigned, float, double, float); +CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(uint64, int64, uint64, uint64, void, uint64); +CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(int64, int64, uint64, uint64, void, int64); +CV_INTRIN_DEF_TYPE_TRAITS_NO_Q_TYPE(double, int64, uint64, double, void, double); + +#ifndef CV_DOXYGEN + +#ifndef CV_CPU_OPTIMIZATION_HAL_NAMESPACE +#ifdef CV_FORCE_SIMD128_CPP + #define CV_CPU_OPTIMIZATION_HAL_NAMESPACE hal_EMULATOR_CPP + #define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN namespace hal_EMULATOR_CPP { + #define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END } +#elif defined(CV_CPU_DISPATCH_MODE) + #define CV_CPU_OPTIMIZATION_HAL_NAMESPACE __CV_CAT(hal_, CV_CPU_DISPATCH_MODE) + #define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN namespace __CV_CAT(hal_, CV_CPU_DISPATCH_MODE) { + #define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END } +#else + #define CV_CPU_OPTIMIZATION_HAL_NAMESPACE hal_baseline + #define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN namespace hal_baseline { + #define CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END } +#endif +#endif // CV_CPU_OPTIMIZATION_HAL_NAMESPACE + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END +using namespace CV_CPU_OPTIMIZATION_HAL_NAMESPACE; +#endif +} + +#ifdef CV_DOXYGEN +# undef CV_AVX2 +# undef CV_SSE2 +# undef CV_NEON +# undef CV_VSX +# undef CV_FP16 +# undef CV_MSA +# undef CV_RVV +#endif + +#if (CV_SSE2 || CV_NEON || CV_VSX || CV_MSA || CV_WASM_SIMD || CV_RVV071 || CV_RVV) && !defined(CV_FORCE_SIMD128_CPP) +#define CV__SIMD_FORWARD 128 +#include "opencv2/core/hal/intrin_forward.hpp" +#endif + +#if CV_SSE2 && !defined(CV_FORCE_SIMD128_CPP) + +#include "opencv2/core/hal/intrin_sse_em.hpp" +#include "opencv2/core/hal/intrin_sse.hpp" + +#elif CV_NEON && !defined(CV_FORCE_SIMD128_CPP) + +#include "opencv2/core/hal/intrin_neon.hpp" + +#elif CV_RVV071 && !defined(CV_FORCE_SIMD128_CPP) +#define CV_SIMD128_CPP 0 +#include "opencv2/core/hal/intrin_rvv071.hpp" + +#elif CV_VSX && !defined(CV_FORCE_SIMD128_CPP) + +#include "opencv2/core/hal/intrin_vsx.hpp" + +#elif CV_MSA && !defined(CV_FORCE_SIMD128_CPP) + +#include "opencv2/core/hal/intrin_msa.hpp" + +#elif CV_WASM_SIMD && !defined(CV_FORCE_SIMD128_CPP) +#include "opencv2/core/hal/intrin_wasm.hpp" + +#elif CV_RVV && !defined(CV_FORCE_SIMD128_CPP) +#include "opencv2/core/hal/intrin_rvv.hpp" + +#else + +#include "opencv2/core/hal/intrin_cpp.hpp" + +#endif + +// AVX2 can be used together with SSE2, so +// we define those two sets of intrinsics at once. +// Most of the intrinsics do not conflict (the proper overloaded variant is +// resolved by the argument types, e.g. v_float32x4 ~ SSE2, v_float32x8 ~ AVX2), +// but some of AVX2 intrinsics get v256_ prefix instead of v_, e.g. v256_load() vs v_load(). +// Correspondingly, the wide intrinsics (which are mapped to the "widest" +// available instruction set) will get vx_ prefix +// (and will be mapped to v256_ counterparts) (e.g. vx_load() => v256_load()) +#if CV_AVX2 + +#define CV__SIMD_FORWARD 256 +#include "opencv2/core/hal/intrin_forward.hpp" +#include "opencv2/core/hal/intrin_avx.hpp" + +#endif + +// AVX512 can be used together with SSE2 and AVX2, so +// we define those sets of intrinsics at once. +// For some of AVX512 intrinsics get v512_ prefix instead of v_, e.g. v512_load() vs v_load(). +// Wide intrinsics will be mapped to v512_ counterparts in this case(e.g. vx_load() => v512_load()) +#if CV_AVX512_SKX + +#define CV__SIMD_FORWARD 512 +#include "opencv2/core/hal/intrin_forward.hpp" +#include "opencv2/core/hal/intrin_avx512.hpp" + +#endif + +//! @cond IGNORED + +namespace cv { + +#ifndef CV_DOXYGEN +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN +#endif + +#ifndef CV_SIMD128 +#define CV_SIMD128 0 +#endif + +#ifndef CV_SIMD128_CPP +#define CV_SIMD128_CPP 0 +#endif + +#ifndef CV_SIMD128_64F +#define CV_SIMD128_64F 0 +#endif + +#ifndef CV_SIMD256 +#define CV_SIMD256 0 +#endif + +#ifndef CV_SIMD256_64F +#define CV_SIMD256_64F 0 +#endif + +#ifndef CV_SIMD512 +#define CV_SIMD512 0 +#endif + +#ifndef CV_SIMD512_64F +#define CV_SIMD512_64F 0 +#endif + +#ifndef CV_SIMD128_FP16 +#define CV_SIMD128_FP16 0 +#endif + +#ifndef CV_SIMD256_FP16 +#define CV_SIMD256_FP16 0 +#endif + +#ifndef CV_SIMD512_FP16 +#define CV_SIMD512_FP16 0 +#endif + +//================================================================================================== + +template struct V_RegTraits +{ +}; + +#define CV_DEF_REG_TRAITS(prefix, _reg, lane_type, suffix, _u_reg, _w_reg, _q_reg, _int_reg, _round_reg) \ + template<> struct V_RegTraits<_reg> \ + { \ + typedef _reg reg; \ + typedef _u_reg u_reg; \ + typedef _w_reg w_reg; \ + typedef _q_reg q_reg; \ + typedef _int_reg int_reg; \ + typedef _round_reg round_reg; \ + } + +#if CV_SIMD128 || CV_SIMD128_CPP + CV_DEF_REG_TRAITS(v, v_uint8x16, uchar, u8, v_uint8x16, v_uint16x8, v_uint32x4, v_int8x16, void); + CV_DEF_REG_TRAITS(v, v_int8x16, schar, s8, v_uint8x16, v_int16x8, v_int32x4, v_int8x16, void); + CV_DEF_REG_TRAITS(v, v_uint16x8, ushort, u16, v_uint16x8, v_uint32x4, v_uint64x2, v_int16x8, void); + CV_DEF_REG_TRAITS(v, v_int16x8, short, s16, v_uint16x8, v_int32x4, v_int64x2, v_int16x8, void); + CV_DEF_REG_TRAITS(v, v_uint32x4, unsigned, u32, v_uint32x4, v_uint64x2, void, v_int32x4, void); + CV_DEF_REG_TRAITS(v, v_int32x4, int, s32, v_uint32x4, v_int64x2, void, v_int32x4, void); +#if CV_SIMD128_64F || CV_SIMD128_CPP + CV_DEF_REG_TRAITS(v, v_float32x4, float, f32, v_float32x4, v_float64x2, void, v_int32x4, v_int32x4); +#else + CV_DEF_REG_TRAITS(v, v_float32x4, float, f32, v_float32x4, void, void, v_int32x4, v_int32x4); +#endif + CV_DEF_REG_TRAITS(v, v_uint64x2, uint64, u64, v_uint64x2, void, void, v_int64x2, void); + CV_DEF_REG_TRAITS(v, v_int64x2, int64, s64, v_uint64x2, void, void, v_int64x2, void); +#if CV_SIMD128_64F + CV_DEF_REG_TRAITS(v, v_float64x2, double, f64, v_float64x2, void, void, v_int64x2, v_int32x4); +#endif +#endif + +#if CV_SIMD256 + CV_DEF_REG_TRAITS(v256, v_uint8x32, uchar, u8, v_uint8x32, v_uint16x16, v_uint32x8, v_int8x32, void); + CV_DEF_REG_TRAITS(v256, v_int8x32, schar, s8, v_uint8x32, v_int16x16, v_int32x8, v_int8x32, void); + CV_DEF_REG_TRAITS(v256, v_uint16x16, ushort, u16, v_uint16x16, v_uint32x8, v_uint64x4, v_int16x16, void); + CV_DEF_REG_TRAITS(v256, v_int16x16, short, s16, v_uint16x16, v_int32x8, v_int64x4, v_int16x16, void); + CV_DEF_REG_TRAITS(v256, v_uint32x8, unsigned, u32, v_uint32x8, v_uint64x4, void, v_int32x8, void); + CV_DEF_REG_TRAITS(v256, v_int32x8, int, s32, v_uint32x8, v_int64x4, void, v_int32x8, void); + CV_DEF_REG_TRAITS(v256, v_float32x8, float, f32, v_float32x8, v_float64x4, void, v_int32x8, v_int32x8); + CV_DEF_REG_TRAITS(v256, v_uint64x4, uint64, u64, v_uint64x4, void, void, v_int64x4, void); + CV_DEF_REG_TRAITS(v256, v_int64x4, int64, s64, v_uint64x4, void, void, v_int64x4, void); + CV_DEF_REG_TRAITS(v256, v_float64x4, double, f64, v_float64x4, void, void, v_int64x4, v_int32x8); +#endif + +#if CV_SIMD512 + CV_DEF_REG_TRAITS(v512, v_uint8x64, uchar, u8, v_uint8x64, v_uint16x32, v_uint32x16, v_int8x64, void); + CV_DEF_REG_TRAITS(v512, v_int8x64, schar, s8, v_uint8x64, v_int16x32, v_int32x16, v_int8x64, void); + CV_DEF_REG_TRAITS(v512, v_uint16x32, ushort, u16, v_uint16x32, v_uint32x16, v_uint64x8, v_int16x32, void); + CV_DEF_REG_TRAITS(v512, v_int16x32, short, s16, v_uint16x32, v_int32x16, v_int64x8, v_int16x32, void); + CV_DEF_REG_TRAITS(v512, v_uint32x16, unsigned, u32, v_uint32x16, v_uint64x8, void, v_int32x16, void); + CV_DEF_REG_TRAITS(v512, v_int32x16, int, s32, v_uint32x16, v_int64x8, void, v_int32x16, void); + CV_DEF_REG_TRAITS(v512, v_float32x16, float, f32, v_float32x16, v_float64x8, void, v_int32x16, v_int32x16); + CV_DEF_REG_TRAITS(v512, v_uint64x8, uint64, u64, v_uint64x8, void, void, v_int64x8, void); + CV_DEF_REG_TRAITS(v512, v_int64x8, int64, s64, v_uint64x8, void, void, v_int64x8, void); + CV_DEF_REG_TRAITS(v512, v_float64x8, double, f64, v_float64x8, void, void, v_int64x8, v_int32x16); +#endif +//! @endcond + +#if CV_SIMD512 && (!defined(CV__SIMD_FORCE_WIDTH) || CV__SIMD_FORCE_WIDTH == 512) +#define CV__SIMD_NAMESPACE simd512 +namespace CV__SIMD_NAMESPACE { + #define CV_SIMD 1 + #define CV_SIMD_64F CV_SIMD512_64F + #define CV_SIMD_FP16 CV_SIMD512_FP16 + #define CV_SIMD_WIDTH 64 +//! @addtogroup core_hal_intrin +//! @{ + //! @brief Maximum available vector register capacity 8-bit unsigned integer values + typedef v_uint8x64 v_uint8; + //! @brief Maximum available vector register capacity 8-bit signed integer values + typedef v_int8x64 v_int8; + //! @brief Maximum available vector register capacity 16-bit unsigned integer values + typedef v_uint16x32 v_uint16; + //! @brief Maximum available vector register capacity 16-bit signed integer values + typedef v_int16x32 v_int16; + //! @brief Maximum available vector register capacity 32-bit unsigned integer values + typedef v_uint32x16 v_uint32; + //! @brief Maximum available vector register capacity 32-bit signed integer values + typedef v_int32x16 v_int32; + //! @brief Maximum available vector register capacity 64-bit unsigned integer values + typedef v_uint64x8 v_uint64; + //! @brief Maximum available vector register capacity 64-bit signed integer values + typedef v_int64x8 v_int64; + //! @brief Maximum available vector register capacity 32-bit floating point values (single precision) + typedef v_float32x16 v_float32; + #if CV_SIMD512_64F + //! @brief Maximum available vector register capacity 64-bit floating point values (double precision) + typedef v_float64x8 v_float64; + #endif +//! @} + + #define VXPREFIX(func) v512##func +} // namespace +using namespace CV__SIMD_NAMESPACE; +#elif CV_SIMD256 && (!defined(CV__SIMD_FORCE_WIDTH) || CV__SIMD_FORCE_WIDTH == 256) +#define CV__SIMD_NAMESPACE simd256 +namespace CV__SIMD_NAMESPACE { + #define CV_SIMD 1 + #define CV_SIMD_64F CV_SIMD256_64F + #define CV_SIMD_FP16 CV_SIMD256_FP16 + #define CV_SIMD_WIDTH 32 +//! @addtogroup core_hal_intrin +//! @{ + //! @brief Maximum available vector register capacity 8-bit unsigned integer values + typedef v_uint8x32 v_uint8; + //! @brief Maximum available vector register capacity 8-bit signed integer values + typedef v_int8x32 v_int8; + //! @brief Maximum available vector register capacity 16-bit unsigned integer values + typedef v_uint16x16 v_uint16; + //! @brief Maximum available vector register capacity 16-bit signed integer values + typedef v_int16x16 v_int16; + //! @brief Maximum available vector register capacity 32-bit unsigned integer values + typedef v_uint32x8 v_uint32; + //! @brief Maximum available vector register capacity 32-bit signed integer values + typedef v_int32x8 v_int32; + //! @brief Maximum available vector register capacity 64-bit unsigned integer values + typedef v_uint64x4 v_uint64; + //! @brief Maximum available vector register capacity 64-bit signed integer values + typedef v_int64x4 v_int64; + //! @brief Maximum available vector register capacity 32-bit floating point values (single precision) + typedef v_float32x8 v_float32; + #if CV_SIMD256_64F + //! @brief Maximum available vector register capacity 64-bit floating point values (double precision) + typedef v_float64x4 v_float64; + #endif +//! @} + + #define VXPREFIX(func) v256##func +} // namespace +using namespace CV__SIMD_NAMESPACE; +#elif (CV_SIMD128 || CV_SIMD128_CPP) && (!defined(CV__SIMD_FORCE_WIDTH) || CV__SIMD_FORCE_WIDTH == 128) +#if defined CV_SIMD128_CPP +#define CV__SIMD_NAMESPACE simd128_cpp +#else +#define CV__SIMD_NAMESPACE simd128 +#endif +namespace CV__SIMD_NAMESPACE { + #define CV_SIMD CV_SIMD128 + #define CV_SIMD_64F CV_SIMD128_64F + #define CV_SIMD_WIDTH 16 +//! @addtogroup core_hal_intrin +//! @{ + //! @brief Maximum available vector register capacity 8-bit unsigned integer values + typedef v_uint8x16 v_uint8; + //! @brief Maximum available vector register capacity 8-bit signed integer values + typedef v_int8x16 v_int8; + //! @brief Maximum available vector register capacity 16-bit unsigned integer values + typedef v_uint16x8 v_uint16; + //! @brief Maximum available vector register capacity 16-bit signed integer values + typedef v_int16x8 v_int16; + //! @brief Maximum available vector register capacity 32-bit unsigned integer values + typedef v_uint32x4 v_uint32; + //! @brief Maximum available vector register capacity 32-bit signed integer values + typedef v_int32x4 v_int32; + //! @brief Maximum available vector register capacity 64-bit unsigned integer values + typedef v_uint64x2 v_uint64; + //! @brief Maximum available vector register capacity 64-bit signed integer values + typedef v_int64x2 v_int64; + //! @brief Maximum available vector register capacity 32-bit floating point values (single precision) + typedef v_float32x4 v_float32; + #if CV_SIMD128_64F + //! @brief Maximum available vector register capacity 64-bit floating point values (double precision) + typedef v_float64x2 v_float64; + #endif +//! @} + + #define VXPREFIX(func) v##func +} // namespace +using namespace CV__SIMD_NAMESPACE; +#endif + +namespace CV__SIMD_NAMESPACE { +//! @addtogroup core_hal_intrin +//! @{ + //! @name Wide init with value + //! @{ + //! @brief Create maximum available capacity vector with elements set to a specific value + inline v_uint8 vx_setall_u8(uchar v) { return VXPREFIX(_setall_u8)(v); } + inline v_int8 vx_setall_s8(schar v) { return VXPREFIX(_setall_s8)(v); } + inline v_uint16 vx_setall_u16(ushort v) { return VXPREFIX(_setall_u16)(v); } + inline v_int16 vx_setall_s16(short v) { return VXPREFIX(_setall_s16)(v); } + inline v_int32 vx_setall_s32(int v) { return VXPREFIX(_setall_s32)(v); } + inline v_uint32 vx_setall_u32(unsigned v) { return VXPREFIX(_setall_u32)(v); } + inline v_float32 vx_setall_f32(float v) { return VXPREFIX(_setall_f32)(v); } + inline v_int64 vx_setall_s64(int64 v) { return VXPREFIX(_setall_s64)(v); } + inline v_uint64 vx_setall_u64(uint64 v) { return VXPREFIX(_setall_u64)(v); } +#if CV_SIMD_64F + inline v_float64 vx_setall_f64(double v) { return VXPREFIX(_setall_f64)(v); } +#endif + //! @} + + //! @name Wide init with zero + //! @{ + //! @brief Create maximum available capacity vector with elements set to zero + inline v_uint8 vx_setzero_u8() { return VXPREFIX(_setzero_u8)(); } + inline v_int8 vx_setzero_s8() { return VXPREFIX(_setzero_s8)(); } + inline v_uint16 vx_setzero_u16() { return VXPREFIX(_setzero_u16)(); } + inline v_int16 vx_setzero_s16() { return VXPREFIX(_setzero_s16)(); } + inline v_int32 vx_setzero_s32() { return VXPREFIX(_setzero_s32)(); } + inline v_uint32 vx_setzero_u32() { return VXPREFIX(_setzero_u32)(); } + inline v_float32 vx_setzero_f32() { return VXPREFIX(_setzero_f32)(); } + inline v_int64 vx_setzero_s64() { return VXPREFIX(_setzero_s64)(); } + inline v_uint64 vx_setzero_u64() { return VXPREFIX(_setzero_u64)(); } +#if CV_SIMD_64F + inline v_float64 vx_setzero_f64() { return VXPREFIX(_setzero_f64)(); } +#endif + //! @} + + //! @name Wide load from memory + //! @{ + //! @brief Load maximum available capacity register contents from memory + inline v_uint8 vx_load(const uchar * ptr) { return VXPREFIX(_load)(ptr); } + inline v_int8 vx_load(const schar * ptr) { return VXPREFIX(_load)(ptr); } + inline v_uint16 vx_load(const ushort * ptr) { return VXPREFIX(_load)(ptr); } + inline v_int16 vx_load(const short * ptr) { return VXPREFIX(_load)(ptr); } + inline v_int32 vx_load(const int * ptr) { return VXPREFIX(_load)(ptr); } + inline v_uint32 vx_load(const unsigned * ptr) { return VXPREFIX(_load)(ptr); } + inline v_float32 vx_load(const float * ptr) { return VXPREFIX(_load)(ptr); } + inline v_int64 vx_load(const int64 * ptr) { return VXPREFIX(_load)(ptr); } + inline v_uint64 vx_load(const uint64 * ptr) { return VXPREFIX(_load)(ptr); } +#if CV_SIMD_64F + inline v_float64 vx_load(const double * ptr) { return VXPREFIX(_load)(ptr); } +#endif + //! @} + + //! @name Wide load from memory(aligned) + //! @{ + //! @brief Load maximum available capacity register contents from memory(aligned) + inline v_uint8 vx_load_aligned(const uchar * ptr) { return VXPREFIX(_load_aligned)(ptr); } + inline v_int8 vx_load_aligned(const schar * ptr) { return VXPREFIX(_load_aligned)(ptr); } + inline v_uint16 vx_load_aligned(const ushort * ptr) { return VXPREFIX(_load_aligned)(ptr); } + inline v_int16 vx_load_aligned(const short * ptr) { return VXPREFIX(_load_aligned)(ptr); } + inline v_int32 vx_load_aligned(const int * ptr) { return VXPREFIX(_load_aligned)(ptr); } + inline v_uint32 vx_load_aligned(const unsigned * ptr) { return VXPREFIX(_load_aligned)(ptr); } + inline v_float32 vx_load_aligned(const float * ptr) { return VXPREFIX(_load_aligned)(ptr); } + inline v_int64 vx_load_aligned(const int64 * ptr) { return VXPREFIX(_load_aligned)(ptr); } + inline v_uint64 vx_load_aligned(const uint64 * ptr) { return VXPREFIX(_load_aligned)(ptr); } +#if CV_SIMD_64F + inline v_float64 vx_load_aligned(const double * ptr) { return VXPREFIX(_load_aligned)(ptr); } +#endif + //! @} + + //! @name Wide load lower half from memory + //! @{ + //! @brief Load lower half of maximum available capacity register from memory + inline v_uint8 vx_load_low(const uchar * ptr) { return VXPREFIX(_load_low)(ptr); } + inline v_int8 vx_load_low(const schar * ptr) { return VXPREFIX(_load_low)(ptr); } + inline v_uint16 vx_load_low(const ushort * ptr) { return VXPREFIX(_load_low)(ptr); } + inline v_int16 vx_load_low(const short * ptr) { return VXPREFIX(_load_low)(ptr); } + inline v_int32 vx_load_low(const int * ptr) { return VXPREFIX(_load_low)(ptr); } + inline v_uint32 vx_load_low(const unsigned * ptr) { return VXPREFIX(_load_low)(ptr); } + inline v_float32 vx_load_low(const float * ptr) { return VXPREFIX(_load_low)(ptr); } + inline v_int64 vx_load_low(const int64 * ptr) { return VXPREFIX(_load_low)(ptr); } + inline v_uint64 vx_load_low(const uint64 * ptr) { return VXPREFIX(_load_low)(ptr); } +#if CV_SIMD_64F + inline v_float64 vx_load_low(const double * ptr) { return VXPREFIX(_load_low)(ptr); } +#endif + //! @} + + //! @name Wide load halfs from memory + //! @{ + //! @brief Load maximum available capacity register contents from two memory blocks + inline v_uint8 vx_load_halves(const uchar * ptr0, const uchar * ptr1) { return VXPREFIX(_load_halves)(ptr0, ptr1); } + inline v_int8 vx_load_halves(const schar * ptr0, const schar * ptr1) { return VXPREFIX(_load_halves)(ptr0, ptr1); } + inline v_uint16 vx_load_halves(const ushort * ptr0, const ushort * ptr1) { return VXPREFIX(_load_halves)(ptr0, ptr1); } + inline v_int16 vx_load_halves(const short * ptr0, const short * ptr1) { return VXPREFIX(_load_halves)(ptr0, ptr1); } + inline v_int32 vx_load_halves(const int * ptr0, const int * ptr1) { return VXPREFIX(_load_halves)(ptr0, ptr1); } + inline v_uint32 vx_load_halves(const unsigned * ptr0, const unsigned * ptr1) { return VXPREFIX(_load_halves)(ptr0, ptr1); } + inline v_float32 vx_load_halves(const float * ptr0, const float * ptr1) { return VXPREFIX(_load_halves)(ptr0, ptr1); } + inline v_int64 vx_load_halves(const int64 * ptr0, const int64 * ptr1) { return VXPREFIX(_load_halves)(ptr0, ptr1); } + inline v_uint64 vx_load_halves(const uint64 * ptr0, const uint64 * ptr1) { return VXPREFIX(_load_halves)(ptr0, ptr1); } +#if CV_SIMD_64F + inline v_float64 vx_load_halves(const double * ptr0, const double * ptr1) { return VXPREFIX(_load_halves)(ptr0, ptr1); } +#endif + //! @} + + //! @name Wide LUT of elements + //! @{ + //! @brief Load maximum available capacity register contents with array elements by provided indexes + inline v_uint8 vx_lut(const uchar * ptr, const int* idx) { return VXPREFIX(_lut)(ptr, idx); } + inline v_int8 vx_lut(const schar * ptr, const int* idx) { return VXPREFIX(_lut)(ptr, idx); } + inline v_uint16 vx_lut(const ushort * ptr, const int* idx) { return VXPREFIX(_lut)(ptr, idx); } + inline v_int16 vx_lut(const short* ptr, const int* idx) { return VXPREFIX(_lut)(ptr, idx); } + inline v_int32 vx_lut(const int* ptr, const int* idx) { return VXPREFIX(_lut)(ptr, idx); } + inline v_uint32 vx_lut(const unsigned* ptr, const int* idx) { return VXPREFIX(_lut)(ptr, idx); } + inline v_float32 vx_lut(const float* ptr, const int* idx) { return VXPREFIX(_lut)(ptr, idx); } + inline v_int64 vx_lut(const int64 * ptr, const int* idx) { return VXPREFIX(_lut)(ptr, idx); } + inline v_uint64 vx_lut(const uint64 * ptr, const int* idx) { return VXPREFIX(_lut)(ptr, idx); } +#if CV_SIMD_64F + inline v_float64 vx_lut(const double* ptr, const int* idx) { return VXPREFIX(_lut)(ptr, idx); } +#endif + //! @} + + //! @name Wide LUT of element pairs + //! @{ + //! @brief Load maximum available capacity register contents with array element pairs by provided indexes + inline v_uint8 vx_lut_pairs(const uchar * ptr, const int* idx) { return VXPREFIX(_lut_pairs)(ptr, idx); } + inline v_int8 vx_lut_pairs(const schar * ptr, const int* idx) { return VXPREFIX(_lut_pairs)(ptr, idx); } + inline v_uint16 vx_lut_pairs(const ushort * ptr, const int* idx) { return VXPREFIX(_lut_pairs)(ptr, idx); } + inline v_int16 vx_lut_pairs(const short* ptr, const int* idx) { return VXPREFIX(_lut_pairs)(ptr, idx); } + inline v_int32 vx_lut_pairs(const int* ptr, const int* idx) { return VXPREFIX(_lut_pairs)(ptr, idx); } + inline v_uint32 vx_lut_pairs(const unsigned* ptr, const int* idx) { return VXPREFIX(_lut_pairs)(ptr, idx); } + inline v_float32 vx_lut_pairs(const float* ptr, const int* idx) { return VXPREFIX(_lut_pairs)(ptr, idx); } + inline v_int64 vx_lut_pairs(const int64 * ptr, const int* idx) { return VXPREFIX(_lut_pairs)(ptr, idx); } + inline v_uint64 vx_lut_pairs(const uint64 * ptr, const int* idx) { return VXPREFIX(_lut_pairs)(ptr, idx); } +#if CV_SIMD_64F + inline v_float64 vx_lut_pairs(const double* ptr, const int* idx) { return VXPREFIX(_lut_pairs)(ptr, idx); } +#endif + //! @} + + //! @name Wide LUT of element quads + //! @{ + //! @brief Load maximum available capacity register contents with array element quads by provided indexes + inline v_uint8 vx_lut_quads(const uchar* ptr, const int* idx) { return VXPREFIX(_lut_quads)(ptr, idx); } + inline v_int8 vx_lut_quads(const schar* ptr, const int* idx) { return VXPREFIX(_lut_quads)(ptr, idx); } + inline v_uint16 vx_lut_quads(const ushort* ptr, const int* idx) { return VXPREFIX(_lut_quads)(ptr, idx); } + inline v_int16 vx_lut_quads(const short* ptr, const int* idx) { return VXPREFIX(_lut_quads)(ptr, idx); } + inline v_int32 vx_lut_quads(const int* ptr, const int* idx) { return VXPREFIX(_lut_quads)(ptr, idx); } + inline v_uint32 vx_lut_quads(const unsigned* ptr, const int* idx) { return VXPREFIX(_lut_quads)(ptr, idx); } + inline v_float32 vx_lut_quads(const float* ptr, const int* idx) { return VXPREFIX(_lut_quads)(ptr, idx); } + //! @} + + //! @name Wide load with double expansion + //! @{ + //! @brief Load maximum available capacity register contents from memory with double expand + inline v_uint16 vx_load_expand(const uchar * ptr) { return VXPREFIX(_load_expand)(ptr); } + inline v_int16 vx_load_expand(const schar * ptr) { return VXPREFIX(_load_expand)(ptr); } + inline v_uint32 vx_load_expand(const ushort * ptr) { return VXPREFIX(_load_expand)(ptr); } + inline v_int32 vx_load_expand(const short* ptr) { return VXPREFIX(_load_expand)(ptr); } + inline v_int64 vx_load_expand(const int* ptr) { return VXPREFIX(_load_expand)(ptr); } + inline v_uint64 vx_load_expand(const unsigned* ptr) { return VXPREFIX(_load_expand)(ptr); } + inline v_float32 vx_load_expand(const float16_t * ptr) { return VXPREFIX(_load_expand)(ptr); } + //! @} + + //! @name Wide load with quad expansion + //! @{ + //! @brief Load maximum available capacity register contents from memory with quad expand + inline v_uint32 vx_load_expand_q(const uchar * ptr) { return VXPREFIX(_load_expand_q)(ptr); } + inline v_int32 vx_load_expand_q(const schar * ptr) { return VXPREFIX(_load_expand_q)(ptr); } + //! @} + + /** @brief SIMD processing state cleanup call */ + inline void vx_cleanup() { VXPREFIX(_cleanup)(); } + + +//! @cond IGNORED + + // backward compatibility + template static inline + void vx_store(_Tp* dst, const _Tvec& v) { return v_store(dst, v); } + // backward compatibility + template static inline + void vx_store_aligned(_Tp* dst, const _Tvec& v) { return v_store_aligned(dst, v); } + +//! @endcond + + +//! @} + #undef VXPREFIX +} // namespace + +//! @cond IGNORED +#ifndef CV_SIMD_64F +#define CV_SIMD_64F 0 +#endif + +#ifndef CV_SIMD_FP16 +#define CV_SIMD_FP16 0 //!< Defined to 1 on native support of operations with float16x8_t / float16x16_t (SIMD256) types +#endif + +#ifndef CV_SIMD +#define CV_SIMD 0 +#endif + +#include "simd_utils.impl.hpp" + +#ifndef CV_DOXYGEN +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END +#endif + +} // cv:: + +//! @endcond + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_avx.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_avx.hpp new file mode 100644 index 0000000..979b616 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_avx.hpp @@ -0,0 +1,3177 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + +#ifndef OPENCV_HAL_INTRIN_AVX_HPP +#define OPENCV_HAL_INTRIN_AVX_HPP + +#define CV_SIMD256 1 +#define CV_SIMD256_64F 1 +#define CV_SIMD256_FP16 0 // no native operations with FP16 type. Only load/store from float32x8 are available (if CV_FP16 == 1) + +namespace cv +{ + +//! @cond IGNORED + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN + +///////// Utils //////////// + +inline __m256i _v256_combine(const __m128i& lo, const __m128i& hi) +{ return _mm256_inserti128_si256(_mm256_castsi128_si256(lo), hi, 1); } + +inline __m256 _v256_combine(const __m128& lo, const __m128& hi) +{ return _mm256_insertf128_ps(_mm256_castps128_ps256(lo), hi, 1); } + +inline __m256d _v256_combine(const __m128d& lo, const __m128d& hi) +{ return _mm256_insertf128_pd(_mm256_castpd128_pd256(lo), hi, 1); } + +inline int _v_cvtsi256_si32(const __m256i& a) +{ return _mm_cvtsi128_si32(_mm256_castsi256_si128(a)); } + +inline __m256i _v256_shuffle_odd_64(const __m256i& v) +{ return _mm256_permute4x64_epi64(v, _MM_SHUFFLE(3, 1, 2, 0)); } + +inline __m256d _v256_shuffle_odd_64(const __m256d& v) +{ return _mm256_permute4x64_pd(v, _MM_SHUFFLE(3, 1, 2, 0)); } + +template +inline __m256i _v256_permute2x128(const __m256i& a, const __m256i& b) +{ return _mm256_permute2x128_si256(a, b, imm); } + +template +inline __m256 _v256_permute2x128(const __m256& a, const __m256& b) +{ return _mm256_permute2f128_ps(a, b, imm); } + +template +inline __m256d _v256_permute2x128(const __m256d& a, const __m256d& b) +{ return _mm256_permute2f128_pd(a, b, imm); } + +template +inline _Tpvec v256_permute2x128(const _Tpvec& a, const _Tpvec& b) +{ return _Tpvec(_v256_permute2x128(a.val, b.val)); } + +template +inline __m256i _v256_permute4x64(const __m256i& a) +{ return _mm256_permute4x64_epi64(a, imm); } + +template +inline __m256d _v256_permute4x64(const __m256d& a) +{ return _mm256_permute4x64_pd(a, imm); } + +template +inline _Tpvec v256_permute4x64(const _Tpvec& a) +{ return _Tpvec(_v256_permute4x64(a.val)); } + +inline __m128i _v256_extract_high(const __m256i& v) +{ return _mm256_extracti128_si256(v, 1); } + +inline __m128 _v256_extract_high(const __m256& v) +{ return _mm256_extractf128_ps(v, 1); } + +inline __m128d _v256_extract_high(const __m256d& v) +{ return _mm256_extractf128_pd(v, 1); } + +inline __m128i _v256_extract_low(const __m256i& v) +{ return _mm256_castsi256_si128(v); } + +inline __m128 _v256_extract_low(const __m256& v) +{ return _mm256_castps256_ps128(v); } + +inline __m128d _v256_extract_low(const __m256d& v) +{ return _mm256_castpd256_pd128(v); } + +inline __m256i _v256_packs_epu32(const __m256i& a, const __m256i& b) +{ + const __m256i m = _mm256_set1_epi32(65535); + __m256i am = _mm256_min_epu32(a, m); + __m256i bm = _mm256_min_epu32(b, m); + return _mm256_packus_epi32(am, bm); +} + +template +inline int _v256_extract_epi8(const __m256i& a) +{ +#if defined(CV__SIMD_HAVE_mm256_extract_epi8) || (CV_AVX2 && (!defined(_MSC_VER) || _MSC_VER >= 1910/*MSVS 2017*/)) + return _mm256_extract_epi8(a, i); +#else + __m128i b = _mm256_extractf128_si256(a, ((i) >> 4)); + return _mm_extract_epi8(b, i & 15); // SSE4.1 +#endif +} + +template +inline int _v256_extract_epi16(const __m256i& a) +{ +#if defined(CV__SIMD_HAVE_mm256_extract_epi8) || (CV_AVX2 && (!defined(_MSC_VER) || _MSC_VER >= 1910/*MSVS 2017*/)) + return _mm256_extract_epi16(a, i); +#else + __m128i b = _mm256_extractf128_si256(a, ((i) >> 3)); + return _mm_extract_epi16(b, i & 7); // SSE2 +#endif +} + +template +inline int _v256_extract_epi32(const __m256i& a) +{ +#if defined(CV__SIMD_HAVE_mm256_extract_epi8) || (CV_AVX2 && (!defined(_MSC_VER) || _MSC_VER >= 1910/*MSVS 2017*/)) + return _mm256_extract_epi32(a, i); +#else + __m128i b = _mm256_extractf128_si256(a, ((i) >> 2)); + return _mm_extract_epi32(b, i & 3); // SSE4.1 +#endif +} + +template +inline int64 _v256_extract_epi64(const __m256i& a) +{ +#if defined(CV__SIMD_HAVE_mm256_extract_epi8) || (CV_AVX2 && (!defined(_MSC_VER) || _MSC_VER >= 1910/*MSVS 2017*/)) + return _mm256_extract_epi64(a, i); +#else + __m128i b = _mm256_extractf128_si256(a, ((i) >> 1)); + return _mm_extract_epi64(b, i & 1); // SSE4.1 +#endif +} + +///////// Types //////////// + +struct v_uint8x32 +{ + typedef uchar lane_type; + enum { nlanes = 32 }; + __m256i val; + + explicit v_uint8x32(__m256i v) : val(v) {} + v_uint8x32(uchar v0, uchar v1, uchar v2, uchar v3, + uchar v4, uchar v5, uchar v6, uchar v7, + uchar v8, uchar v9, uchar v10, uchar v11, + uchar v12, uchar v13, uchar v14, uchar v15, + uchar v16, uchar v17, uchar v18, uchar v19, + uchar v20, uchar v21, uchar v22, uchar v23, + uchar v24, uchar v25, uchar v26, uchar v27, + uchar v28, uchar v29, uchar v30, uchar v31) + { + val = _mm256_setr_epi8((char)v0, (char)v1, (char)v2, (char)v3, + (char)v4, (char)v5, (char)v6 , (char)v7, (char)v8, (char)v9, + (char)v10, (char)v11, (char)v12, (char)v13, (char)v14, (char)v15, + (char)v16, (char)v17, (char)v18, (char)v19, (char)v20, (char)v21, + (char)v22, (char)v23, (char)v24, (char)v25, (char)v26, (char)v27, + (char)v28, (char)v29, (char)v30, (char)v31); + } + /* coverity[uninit_ctor]: suppress warning */ + v_uint8x32() {} + + uchar get0() const { return (uchar)_v_cvtsi256_si32(val); } +}; + +struct v_int8x32 +{ + typedef schar lane_type; + enum { nlanes = 32 }; + __m256i val; + + explicit v_int8x32(__m256i v) : val(v) {} + v_int8x32(schar v0, schar v1, schar v2, schar v3, + schar v4, schar v5, schar v6, schar v7, + schar v8, schar v9, schar v10, schar v11, + schar v12, schar v13, schar v14, schar v15, + schar v16, schar v17, schar v18, schar v19, + schar v20, schar v21, schar v22, schar v23, + schar v24, schar v25, schar v26, schar v27, + schar v28, schar v29, schar v30, schar v31) + { + val = _mm256_setr_epi8(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, + v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31); + } + /* coverity[uninit_ctor]: suppress warning */ + v_int8x32() {} + + schar get0() const { return (schar)_v_cvtsi256_si32(val); } +}; + +struct v_uint16x16 +{ + typedef ushort lane_type; + enum { nlanes = 16 }; + __m256i val; + + explicit v_uint16x16(__m256i v) : val(v) {} + v_uint16x16(ushort v0, ushort v1, ushort v2, ushort v3, + ushort v4, ushort v5, ushort v6, ushort v7, + ushort v8, ushort v9, ushort v10, ushort v11, + ushort v12, ushort v13, ushort v14, ushort v15) + { + val = _mm256_setr_epi16((short)v0, (short)v1, (short)v2, (short)v3, + (short)v4, (short)v5, (short)v6, (short)v7, (short)v8, (short)v9, + (short)v10, (short)v11, (short)v12, (short)v13, (short)v14, (short)v15); + } + /* coverity[uninit_ctor]: suppress warning */ + v_uint16x16() {} + + ushort get0() const { return (ushort)_v_cvtsi256_si32(val); } +}; + +struct v_int16x16 +{ + typedef short lane_type; + enum { nlanes = 16 }; + __m256i val; + + explicit v_int16x16(__m256i v) : val(v) {} + v_int16x16(short v0, short v1, short v2, short v3, + short v4, short v5, short v6, short v7, + short v8, short v9, short v10, short v11, + short v12, short v13, short v14, short v15) + { + val = _mm256_setr_epi16(v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15); + } + /* coverity[uninit_ctor]: suppress warning */ + v_int16x16() {} + + short get0() const { return (short)_v_cvtsi256_si32(val); } +}; + +struct v_uint32x8 +{ + typedef unsigned lane_type; + enum { nlanes = 8 }; + __m256i val; + + explicit v_uint32x8(__m256i v) : val(v) {} + v_uint32x8(unsigned v0, unsigned v1, unsigned v2, unsigned v3, + unsigned v4, unsigned v5, unsigned v6, unsigned v7) + { + val = _mm256_setr_epi32((unsigned)v0, (unsigned)v1, (unsigned)v2, + (unsigned)v3, (unsigned)v4, (unsigned)v5, (unsigned)v6, (unsigned)v7); + } + /* coverity[uninit_ctor]: suppress warning */ + v_uint32x8() {} + + unsigned get0() const { return (unsigned)_v_cvtsi256_si32(val); } +}; + +struct v_int32x8 +{ + typedef int lane_type; + enum { nlanes = 8 }; + __m256i val; + + explicit v_int32x8(__m256i v) : val(v) {} + v_int32x8(int v0, int v1, int v2, int v3, + int v4, int v5, int v6, int v7) + { + val = _mm256_setr_epi32(v0, v1, v2, v3, v4, v5, v6, v7); + } + /* coverity[uninit_ctor]: suppress warning */ + v_int32x8() {} + + int get0() const { return _v_cvtsi256_si32(val); } +}; + +struct v_float32x8 +{ + typedef float lane_type; + enum { nlanes = 8 }; + __m256 val; + + explicit v_float32x8(__m256 v) : val(v) {} + v_float32x8(float v0, float v1, float v2, float v3, + float v4, float v5, float v6, float v7) + { + val = _mm256_setr_ps(v0, v1, v2, v3, v4, v5, v6, v7); + } + /* coverity[uninit_ctor]: suppress warning */ + v_float32x8() {} + + float get0() const { return _mm_cvtss_f32(_mm256_castps256_ps128(val)); } +}; + +struct v_uint64x4 +{ + typedef uint64 lane_type; + enum { nlanes = 4 }; + __m256i val; + + explicit v_uint64x4(__m256i v) : val(v) {} + v_uint64x4(uint64 v0, uint64 v1, uint64 v2, uint64 v3) + { val = _mm256_setr_epi64x((int64)v0, (int64)v1, (int64)v2, (int64)v3); } + /* coverity[uninit_ctor]: suppress warning */ + v_uint64x4() {} + + uint64 get0() const + { + #if defined __x86_64__ || defined _M_X64 + return (uint64)_mm_cvtsi128_si64(_mm256_castsi256_si128(val)); + #else + int a = _mm_cvtsi128_si32(_mm256_castsi256_si128(val)); + int b = _mm_cvtsi128_si32(_mm256_castsi256_si128(_mm256_srli_epi64(val, 32))); + return (unsigned)a | ((uint64)(unsigned)b << 32); + #endif + } +}; + +struct v_int64x4 +{ + typedef int64 lane_type; + enum { nlanes = 4 }; + __m256i val; + + explicit v_int64x4(__m256i v) : val(v) {} + v_int64x4(int64 v0, int64 v1, int64 v2, int64 v3) + { val = _mm256_setr_epi64x(v0, v1, v2, v3); } + /* coverity[uninit_ctor]: suppress warning */ + v_int64x4() {} + + int64 get0() const + { + #if defined __x86_64__ || defined _M_X64 + return (int64)_mm_cvtsi128_si64(_mm256_castsi256_si128(val)); + #else + int a = _mm_cvtsi128_si32(_mm256_castsi256_si128(val)); + int b = _mm_cvtsi128_si32(_mm256_castsi256_si128(_mm256_srli_epi64(val, 32))); + return (int64)((unsigned)a | ((uint64)(unsigned)b << 32)); + #endif + } +}; + +struct v_float64x4 +{ + typedef double lane_type; + enum { nlanes = 4 }; + __m256d val; + + explicit v_float64x4(__m256d v) : val(v) {} + v_float64x4(double v0, double v1, double v2, double v3) + { val = _mm256_setr_pd(v0, v1, v2, v3); } + /* coverity[uninit_ctor]: suppress warning */ + v_float64x4() {} + + double get0() const { return _mm_cvtsd_f64(_mm256_castpd256_pd128(val)); } +}; + +//////////////// Load and store operations /////////////// + +#define OPENCV_HAL_IMPL_AVX_LOADSTORE(_Tpvec, _Tp) \ + inline _Tpvec v256_load(const _Tp* ptr) \ + { return _Tpvec(_mm256_loadu_si256((const __m256i*)ptr)); } \ + inline _Tpvec v256_load_aligned(const _Tp* ptr) \ + { return _Tpvec(_mm256_load_si256((const __m256i*)ptr)); } \ + inline _Tpvec v256_load_low(const _Tp* ptr) \ + { \ + __m128i v128 = _mm_loadu_si128((const __m128i*)ptr); \ + return _Tpvec(_mm256_castsi128_si256(v128)); \ + } \ + inline _Tpvec v256_load_halves(const _Tp* ptr0, const _Tp* ptr1) \ + { \ + __m128i vlo = _mm_loadu_si128((const __m128i*)ptr0); \ + __m128i vhi = _mm_loadu_si128((const __m128i*)ptr1); \ + return _Tpvec(_v256_combine(vlo, vhi)); \ + } \ + inline void v_store(_Tp* ptr, const _Tpvec& a) \ + { _mm256_storeu_si256((__m256i*)ptr, a.val); } \ + inline void v_store_aligned(_Tp* ptr, const _Tpvec& a) \ + { _mm256_store_si256((__m256i*)ptr, a.val); } \ + inline void v_store_aligned_nocache(_Tp* ptr, const _Tpvec& a) \ + { _mm256_stream_si256((__m256i*)ptr, a.val); } \ + inline void v_store(_Tp* ptr, const _Tpvec& a, hal::StoreMode mode) \ + { \ + if( mode == hal::STORE_UNALIGNED ) \ + _mm256_storeu_si256((__m256i*)ptr, a.val); \ + else if( mode == hal::STORE_ALIGNED_NOCACHE ) \ + _mm256_stream_si256((__m256i*)ptr, a.val); \ + else \ + _mm256_store_si256((__m256i*)ptr, a.val); \ + } \ + inline void v_store_low(_Tp* ptr, const _Tpvec& a) \ + { _mm_storeu_si128((__m128i*)ptr, _v256_extract_low(a.val)); } \ + inline void v_store_high(_Tp* ptr, const _Tpvec& a) \ + { _mm_storeu_si128((__m128i*)ptr, _v256_extract_high(a.val)); } + +OPENCV_HAL_IMPL_AVX_LOADSTORE(v_uint8x32, uchar) +OPENCV_HAL_IMPL_AVX_LOADSTORE(v_int8x32, schar) +OPENCV_HAL_IMPL_AVX_LOADSTORE(v_uint16x16, ushort) +OPENCV_HAL_IMPL_AVX_LOADSTORE(v_int16x16, short) +OPENCV_HAL_IMPL_AVX_LOADSTORE(v_uint32x8, unsigned) +OPENCV_HAL_IMPL_AVX_LOADSTORE(v_int32x8, int) +OPENCV_HAL_IMPL_AVX_LOADSTORE(v_uint64x4, uint64) +OPENCV_HAL_IMPL_AVX_LOADSTORE(v_int64x4, int64) + +#define OPENCV_HAL_IMPL_AVX_LOADSTORE_FLT(_Tpvec, _Tp, suffix, halfreg) \ + inline _Tpvec v256_load(const _Tp* ptr) \ + { return _Tpvec(_mm256_loadu_##suffix(ptr)); } \ + inline _Tpvec v256_load_aligned(const _Tp* ptr) \ + { return _Tpvec(_mm256_load_##suffix(ptr)); } \ + inline _Tpvec v256_load_low(const _Tp* ptr) \ + { \ + return _Tpvec(_mm256_cast##suffix##128_##suffix##256 \ + (_mm_loadu_##suffix(ptr))); \ + } \ + inline _Tpvec v256_load_halves(const _Tp* ptr0, const _Tp* ptr1) \ + { \ + halfreg vlo = _mm_loadu_##suffix(ptr0); \ + halfreg vhi = _mm_loadu_##suffix(ptr1); \ + return _Tpvec(_v256_combine(vlo, vhi)); \ + } \ + inline void v_store(_Tp* ptr, const _Tpvec& a) \ + { _mm256_storeu_##suffix(ptr, a.val); } \ + inline void v_store_aligned(_Tp* ptr, const _Tpvec& a) \ + { _mm256_store_##suffix(ptr, a.val); } \ + inline void v_store_aligned_nocache(_Tp* ptr, const _Tpvec& a) \ + { _mm256_stream_##suffix(ptr, a.val); } \ + inline void v_store(_Tp* ptr, const _Tpvec& a, hal::StoreMode mode) \ + { \ + if( mode == hal::STORE_UNALIGNED ) \ + _mm256_storeu_##suffix(ptr, a.val); \ + else if( mode == hal::STORE_ALIGNED_NOCACHE ) \ + _mm256_stream_##suffix(ptr, a.val); \ + else \ + _mm256_store_##suffix(ptr, a.val); \ + } \ + inline void v_store_low(_Tp* ptr, const _Tpvec& a) \ + { _mm_storeu_##suffix(ptr, _v256_extract_low(a.val)); } \ + inline void v_store_high(_Tp* ptr, const _Tpvec& a) \ + { _mm_storeu_##suffix(ptr, _v256_extract_high(a.val)); } + +OPENCV_HAL_IMPL_AVX_LOADSTORE_FLT(v_float32x8, float, ps, __m128) +OPENCV_HAL_IMPL_AVX_LOADSTORE_FLT(v_float64x4, double, pd, __m128d) + +#define OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, _Tpvecf, suffix, cast) \ + inline _Tpvec v_reinterpret_as_##suffix(const _Tpvecf& a) \ + { return _Tpvec(cast(a.val)); } + +#define OPENCV_HAL_IMPL_AVX_INIT(_Tpvec, _Tp, suffix, ssuffix, ctype_s) \ + inline _Tpvec v256_setzero_##suffix() \ + { return _Tpvec(_mm256_setzero_si256()); } \ + inline _Tpvec v256_setall_##suffix(_Tp v) \ + { return _Tpvec(_mm256_set1_##ssuffix((ctype_s)v)); } \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_uint8x32, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_int8x32, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_uint16x16, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_int16x16, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_uint32x8, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_int32x8, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_uint64x4, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_int64x4, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_float32x8, suffix, _mm256_castps_si256) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_float64x4, suffix, _mm256_castpd_si256) + +OPENCV_HAL_IMPL_AVX_INIT(v_uint8x32, uchar, u8, epi8, char) +OPENCV_HAL_IMPL_AVX_INIT(v_int8x32, schar, s8, epi8, char) +OPENCV_HAL_IMPL_AVX_INIT(v_uint16x16, ushort, u16, epi16, short) +OPENCV_HAL_IMPL_AVX_INIT(v_int16x16, short, s16, epi16, short) +OPENCV_HAL_IMPL_AVX_INIT(v_uint32x8, unsigned, u32, epi32, int) +OPENCV_HAL_IMPL_AVX_INIT(v_int32x8, int, s32, epi32, int) +OPENCV_HAL_IMPL_AVX_INIT(v_uint64x4, uint64, u64, epi64x, int64) +OPENCV_HAL_IMPL_AVX_INIT(v_int64x4, int64, s64, epi64x, int64) + +#define OPENCV_HAL_IMPL_AVX_INIT_FLT(_Tpvec, _Tp, suffix, zsuffix, cast) \ + inline _Tpvec v256_setzero_##suffix() \ + { return _Tpvec(_mm256_setzero_##zsuffix()); } \ + inline _Tpvec v256_setall_##suffix(_Tp v) \ + { return _Tpvec(_mm256_set1_##zsuffix(v)); } \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_uint8x32, suffix, cast) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_int8x32, suffix, cast) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_uint16x16, suffix, cast) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_int16x16, suffix, cast) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_uint32x8, suffix, cast) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_int32x8, suffix, cast) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_uint64x4, suffix, cast) \ + OPENCV_HAL_IMPL_AVX_CAST(_Tpvec, v_int64x4, suffix, cast) + +OPENCV_HAL_IMPL_AVX_INIT_FLT(v_float32x8, float, f32, ps, _mm256_castsi256_ps) +OPENCV_HAL_IMPL_AVX_INIT_FLT(v_float64x4, double, f64, pd, _mm256_castsi256_pd) + +inline v_float32x8 v_reinterpret_as_f32(const v_float32x8& a) +{ return a; } +inline v_float32x8 v_reinterpret_as_f32(const v_float64x4& a) +{ return v_float32x8(_mm256_castpd_ps(a.val)); } + +inline v_float64x4 v_reinterpret_as_f64(const v_float64x4& a) +{ return a; } +inline v_float64x4 v_reinterpret_as_f64(const v_float32x8& a) +{ return v_float64x4(_mm256_castps_pd(a.val)); } + +/* Recombine */ +/*#define OPENCV_HAL_IMPL_AVX_COMBINE(_Tpvec, perm) \ + inline _Tpvec v_combine_low(const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(perm(a.val, b.val, 0x20)); } \ + inline _Tpvec v_combine_high(const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(perm(a.val, b.val, 0x31)); } \ + inline void v_recombine(const _Tpvec& a, const _Tpvec& b, \ + _Tpvec& c, _Tpvec& d) \ + { c = v_combine_low(a, b); d = v_combine_high(a, b); } + +#define OPENCV_HAL_IMPL_AVX_UNPACKS(_Tpvec, suffix) \ + OPENCV_HAL_IMPL_AVX_COMBINE(_Tpvec, _mm256_permute2x128_si256) \ + inline void v_zip(const _Tpvec& a0, const _Tpvec& a1, \ + _Tpvec& b0, _Tpvec& b1) \ + { \ + __m256i v0 = _v256_shuffle_odd_64(a0.val); \ + __m256i v1 = _v256_shuffle_odd_64(a1.val); \ + b0.val = _mm256_unpacklo_##suffix(v0, v1); \ + b1.val = _mm256_unpackhi_##suffix(v0, v1); \ + } + +OPENCV_HAL_IMPL_AVX_UNPACKS(v_uint8x32, epi8) +OPENCV_HAL_IMPL_AVX_UNPACKS(v_int8x32, epi8) +OPENCV_HAL_IMPL_AVX_UNPACKS(v_uint16x16, epi16) +OPENCV_HAL_IMPL_AVX_UNPACKS(v_int16x16, epi16) +OPENCV_HAL_IMPL_AVX_UNPACKS(v_uint32x8, epi32) +OPENCV_HAL_IMPL_AVX_UNPACKS(v_int32x8, epi32) +OPENCV_HAL_IMPL_AVX_UNPACKS(v_uint64x4, epi64) +OPENCV_HAL_IMPL_AVX_UNPACKS(v_int64x4, epi64) +OPENCV_HAL_IMPL_AVX_COMBINE(v_float32x8, _mm256_permute2f128_ps) +OPENCV_HAL_IMPL_AVX_COMBINE(v_float64x4, _mm256_permute2f128_pd) + +inline void v_zip(const v_float32x8& a0, const v_float32x8& a1, v_float32x8& b0, v_float32x8& b1) +{ + __m256 v0 = _mm256_unpacklo_ps(a0.val, a1.val); + __m256 v1 = _mm256_unpackhi_ps(a0.val, a1.val); + v_recombine(v_float32x8(v0), v_float32x8(v1), b0, b1); +} + +inline void v_zip(const v_float64x4& a0, const v_float64x4& a1, v_float64x4& b0, v_float64x4& b1) +{ + __m256d v0 = _v_shuffle_odd_64(a0.val); + __m256d v1 = _v_shuffle_odd_64(a1.val); + b0.val = _mm256_unpacklo_pd(v0, v1); + b1.val = _mm256_unpackhi_pd(v0, v1); +}*/ + +//////////////// Variant Value reordering /////////////// + +// unpacks +#define OPENCV_HAL_IMPL_AVX_UNPACK(_Tpvec, suffix) \ + inline _Tpvec v256_unpacklo(const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(_mm256_unpacklo_##suffix(a.val, b.val)); } \ + inline _Tpvec v256_unpackhi(const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(_mm256_unpackhi_##suffix(a.val, b.val)); } + +OPENCV_HAL_IMPL_AVX_UNPACK(v_uint8x32, epi8) +OPENCV_HAL_IMPL_AVX_UNPACK(v_int8x32, epi8) +OPENCV_HAL_IMPL_AVX_UNPACK(v_uint16x16, epi16) +OPENCV_HAL_IMPL_AVX_UNPACK(v_int16x16, epi16) +OPENCV_HAL_IMPL_AVX_UNPACK(v_uint32x8, epi32) +OPENCV_HAL_IMPL_AVX_UNPACK(v_int32x8, epi32) +OPENCV_HAL_IMPL_AVX_UNPACK(v_uint64x4, epi64) +OPENCV_HAL_IMPL_AVX_UNPACK(v_int64x4, epi64) +OPENCV_HAL_IMPL_AVX_UNPACK(v_float32x8, ps) +OPENCV_HAL_IMPL_AVX_UNPACK(v_float64x4, pd) + +// blend +#define OPENCV_HAL_IMPL_AVX_BLEND(_Tpvec, suffix) \ + template \ + inline _Tpvec v256_blend(const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(_mm256_blend_##suffix(a.val, b.val, m)); } + +OPENCV_HAL_IMPL_AVX_BLEND(v_uint16x16, epi16) +OPENCV_HAL_IMPL_AVX_BLEND(v_int16x16, epi16) +OPENCV_HAL_IMPL_AVX_BLEND(v_uint32x8, epi32) +OPENCV_HAL_IMPL_AVX_BLEND(v_int32x8, epi32) +OPENCV_HAL_IMPL_AVX_BLEND(v_float32x8, ps) +OPENCV_HAL_IMPL_AVX_BLEND(v_float64x4, pd) + +template +inline v_uint64x4 v256_blend(const v_uint64x4& a, const v_uint64x4& b) +{ + enum {M0 = m}; + enum {M1 = (M0 | (M0 << 2)) & 0x33}; + enum {M2 = (M1 | (M1 << 1)) & 0x55}; + enum {MM = M2 | (M2 << 1)}; + return v_uint64x4(_mm256_blend_epi32(a.val, b.val, MM)); +} +template +inline v_int64x4 v256_blend(const v_int64x4& a, const v_int64x4& b) +{ return v_int64x4(v256_blend(v_uint64x4(a.val), v_uint64x4(b.val)).val); } + +// shuffle +// todo: emulate 64bit +#define OPENCV_HAL_IMPL_AVX_SHUFFLE(_Tpvec, intrin) \ + template \ + inline _Tpvec v256_shuffle(const _Tpvec& a) \ + { return _Tpvec(_mm256_##intrin(a.val, m)); } + +OPENCV_HAL_IMPL_AVX_SHUFFLE(v_uint32x8, shuffle_epi32) +OPENCV_HAL_IMPL_AVX_SHUFFLE(v_int32x8, shuffle_epi32) +OPENCV_HAL_IMPL_AVX_SHUFFLE(v_float32x8, permute_ps) +OPENCV_HAL_IMPL_AVX_SHUFFLE(v_float64x4, permute_pd) + +template +inline void v256_zip(const _Tpvec& a, const _Tpvec& b, _Tpvec& ab0, _Tpvec& ab1) +{ + ab0 = v256_unpacklo(a, b); + ab1 = v256_unpackhi(a, b); +} + +template +inline _Tpvec v256_combine_diagonal(const _Tpvec& a, const _Tpvec& b) +{ return _Tpvec(_mm256_blend_epi32(a.val, b.val, 0xf0)); } + +inline v_float32x8 v256_combine_diagonal(const v_float32x8& a, const v_float32x8& b) +{ return v256_blend<0xf0>(a, b); } + +inline v_float64x4 v256_combine_diagonal(const v_float64x4& a, const v_float64x4& b) +{ return v256_blend<0xc>(a, b); } + +template +inline _Tpvec v256_alignr_128(const _Tpvec& a, const _Tpvec& b) +{ return v256_permute2x128<0x21>(a, b); } + +template +inline _Tpvec v256_alignr_64(const _Tpvec& a, const _Tpvec& b) +{ return _Tpvec(_mm256_alignr_epi8(a.val, b.val, 8)); } +inline v_float64x4 v256_alignr_64(const v_float64x4& a, const v_float64x4& b) +{ return v_float64x4(_mm256_shuffle_pd(b.val, a.val, _MM_SHUFFLE(0, 0, 1, 1))); } +// todo: emulate float32 + +template +inline _Tpvec v256_swap_halves(const _Tpvec& a) +{ return v256_permute2x128<1>(a, a); } + +template +inline _Tpvec v256_reverse_64(const _Tpvec& a) +{ return v256_permute4x64<_MM_SHUFFLE(0, 1, 2, 3)>(a); } + +// ZIP +#define OPENCV_HAL_IMPL_AVX_ZIP(_Tpvec) \ + inline _Tpvec v_combine_low(const _Tpvec& a, const _Tpvec& b) \ + { return v256_permute2x128<0x20>(a, b); } \ + inline _Tpvec v_combine_high(const _Tpvec& a, const _Tpvec& b) \ + { return v256_permute2x128<0x31>(a, b); } \ + inline void v_recombine(const _Tpvec& a, const _Tpvec& b, \ + _Tpvec& c, _Tpvec& d) \ + { \ + _Tpvec a1b0 = v256_alignr_128(a, b); \ + c = v256_combine_diagonal(a, a1b0); \ + d = v256_combine_diagonal(a1b0, b); \ + } \ + inline void v_zip(const _Tpvec& a, const _Tpvec& b, \ + _Tpvec& ab0, _Tpvec& ab1) \ + { \ + _Tpvec ab0ab2, ab1ab3; \ + v256_zip(a, b, ab0ab2, ab1ab3); \ + v_recombine(ab0ab2, ab1ab3, ab0, ab1); \ + } + +OPENCV_HAL_IMPL_AVX_ZIP(v_uint8x32) +OPENCV_HAL_IMPL_AVX_ZIP(v_int8x32) +OPENCV_HAL_IMPL_AVX_ZIP(v_uint16x16) +OPENCV_HAL_IMPL_AVX_ZIP(v_int16x16) +OPENCV_HAL_IMPL_AVX_ZIP(v_uint32x8) +OPENCV_HAL_IMPL_AVX_ZIP(v_int32x8) +OPENCV_HAL_IMPL_AVX_ZIP(v_uint64x4) +OPENCV_HAL_IMPL_AVX_ZIP(v_int64x4) +OPENCV_HAL_IMPL_AVX_ZIP(v_float32x8) +OPENCV_HAL_IMPL_AVX_ZIP(v_float64x4) + +////////// Arithmetic, bitwise and comparison operations ///////// + +/* Element-wise binary and unary operations */ + +/** Arithmetics **/ +#define OPENCV_HAL_IMPL_AVX_BIN_OP(bin_op, _Tpvec, intrin) \ + inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(intrin(a.val, b.val)); } \ + inline _Tpvec& operator bin_op##= (_Tpvec& a, const _Tpvec& b) \ + { a.val = intrin(a.val, b.val); return a; } + +OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_uint8x32, _mm256_adds_epu8) +OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_uint8x32, _mm256_subs_epu8) +OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_int8x32, _mm256_adds_epi8) +OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_int8x32, _mm256_subs_epi8) +OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_uint16x16, _mm256_adds_epu16) +OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_uint16x16, _mm256_subs_epu16) +OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_int16x16, _mm256_adds_epi16) +OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_int16x16, _mm256_subs_epi16) +OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_uint32x8, _mm256_add_epi32) +OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_uint32x8, _mm256_sub_epi32) +OPENCV_HAL_IMPL_AVX_BIN_OP(*, v_uint32x8, _mm256_mullo_epi32) +OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_int32x8, _mm256_add_epi32) +OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_int32x8, _mm256_sub_epi32) +OPENCV_HAL_IMPL_AVX_BIN_OP(*, v_int32x8, _mm256_mullo_epi32) +OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_uint64x4, _mm256_add_epi64) +OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_uint64x4, _mm256_sub_epi64) +OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_int64x4, _mm256_add_epi64) +OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_int64x4, _mm256_sub_epi64) + +OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_float32x8, _mm256_add_ps) +OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_float32x8, _mm256_sub_ps) +OPENCV_HAL_IMPL_AVX_BIN_OP(*, v_float32x8, _mm256_mul_ps) +OPENCV_HAL_IMPL_AVX_BIN_OP(/, v_float32x8, _mm256_div_ps) +OPENCV_HAL_IMPL_AVX_BIN_OP(+, v_float64x4, _mm256_add_pd) +OPENCV_HAL_IMPL_AVX_BIN_OP(-, v_float64x4, _mm256_sub_pd) +OPENCV_HAL_IMPL_AVX_BIN_OP(*, v_float64x4, _mm256_mul_pd) +OPENCV_HAL_IMPL_AVX_BIN_OP(/, v_float64x4, _mm256_div_pd) + +// saturating multiply 8-bit, 16-bit +inline v_uint8x32 operator * (const v_uint8x32& a, const v_uint8x32& b) +{ + v_uint16x16 c, d; + v_mul_expand(a, b, c, d); + return v_pack(c, d); +} +inline v_int8x32 operator * (const v_int8x32& a, const v_int8x32& b) +{ + v_int16x16 c, d; + v_mul_expand(a, b, c, d); + return v_pack(c, d); +} +inline v_uint16x16 operator * (const v_uint16x16& a, const v_uint16x16& b) +{ + __m256i pl = _mm256_mullo_epi16(a.val, b.val); + __m256i ph = _mm256_mulhi_epu16(a.val, b.val); + __m256i p0 = _mm256_unpacklo_epi16(pl, ph); + __m256i p1 = _mm256_unpackhi_epi16(pl, ph); + return v_uint16x16(_v256_packs_epu32(p0, p1)); +} +inline v_int16x16 operator * (const v_int16x16& a, const v_int16x16& b) +{ + __m256i pl = _mm256_mullo_epi16(a.val, b.val); + __m256i ph = _mm256_mulhi_epi16(a.val, b.val); + __m256i p0 = _mm256_unpacklo_epi16(pl, ph); + __m256i p1 = _mm256_unpackhi_epi16(pl, ph); + return v_int16x16(_mm256_packs_epi32(p0, p1)); +} +inline v_uint8x32& operator *= (v_uint8x32& a, const v_uint8x32& b) +{ a = a * b; return a; } +inline v_int8x32& operator *= (v_int8x32& a, const v_int8x32& b) +{ a = a * b; return a; } +inline v_uint16x16& operator *= (v_uint16x16& a, const v_uint16x16& b) +{ a = a * b; return a; } +inline v_int16x16& operator *= (v_int16x16& a, const v_int16x16& b) +{ a = a * b; return a; } + +/** Non-saturating arithmetics **/ +#define OPENCV_HAL_IMPL_AVX_BIN_FUNC(func, _Tpvec, intrin) \ + inline _Tpvec func(const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(intrin(a.val, b.val)); } + +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_add_wrap, v_uint8x32, _mm256_add_epi8) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_add_wrap, v_int8x32, _mm256_add_epi8) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_add_wrap, v_uint16x16, _mm256_add_epi16) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_add_wrap, v_int16x16, _mm256_add_epi16) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_sub_wrap, v_uint8x32, _mm256_sub_epi8) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_sub_wrap, v_int8x32, _mm256_sub_epi8) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_sub_wrap, v_uint16x16, _mm256_sub_epi16) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_sub_wrap, v_int16x16, _mm256_sub_epi16) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_mul_wrap, v_uint16x16, _mm256_mullo_epi16) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_mul_wrap, v_int16x16, _mm256_mullo_epi16) + +inline v_uint8x32 v_mul_wrap(const v_uint8x32& a, const v_uint8x32& b) +{ + __m256i ad = _mm256_srai_epi16(a.val, 8); + __m256i bd = _mm256_srai_epi16(b.val, 8); + __m256i p0 = _mm256_mullo_epi16(a.val, b.val); // even + __m256i p1 = _mm256_slli_epi16(_mm256_mullo_epi16(ad, bd), 8); // odd + + const __m256i b01 = _mm256_set1_epi32(0xFF00FF00); + return v_uint8x32(_mm256_blendv_epi8(p0, p1, b01)); +} +inline v_int8x32 v_mul_wrap(const v_int8x32& a, const v_int8x32& b) +{ + return v_reinterpret_as_s8(v_mul_wrap(v_reinterpret_as_u8(a), v_reinterpret_as_u8(b))); +} + +// Multiply and expand +inline void v_mul_expand(const v_uint8x32& a, const v_uint8x32& b, + v_uint16x16& c, v_uint16x16& d) +{ + v_uint16x16 a0, a1, b0, b1; + v_expand(a, a0, a1); + v_expand(b, b0, b1); + c = v_mul_wrap(a0, b0); + d = v_mul_wrap(a1, b1); +} + +inline void v_mul_expand(const v_int8x32& a, const v_int8x32& b, + v_int16x16& c, v_int16x16& d) +{ + v_int16x16 a0, a1, b0, b1; + v_expand(a, a0, a1); + v_expand(b, b0, b1); + c = v_mul_wrap(a0, b0); + d = v_mul_wrap(a1, b1); +} + +inline void v_mul_expand(const v_int16x16& a, const v_int16x16& b, + v_int32x8& c, v_int32x8& d) +{ + v_int16x16 vhi = v_int16x16(_mm256_mulhi_epi16(a.val, b.val)); + + v_int16x16 v0, v1; + v_zip(v_mul_wrap(a, b), vhi, v0, v1); + + c = v_reinterpret_as_s32(v0); + d = v_reinterpret_as_s32(v1); +} + +inline void v_mul_expand(const v_uint16x16& a, const v_uint16x16& b, + v_uint32x8& c, v_uint32x8& d) +{ + v_uint16x16 vhi = v_uint16x16(_mm256_mulhi_epu16(a.val, b.val)); + + v_uint16x16 v0, v1; + v_zip(v_mul_wrap(a, b), vhi, v0, v1); + + c = v_reinterpret_as_u32(v0); + d = v_reinterpret_as_u32(v1); +} + +inline void v_mul_expand(const v_uint32x8& a, const v_uint32x8& b, + v_uint64x4& c, v_uint64x4& d) +{ + __m256i v0 = _mm256_mul_epu32(a.val, b.val); + __m256i v1 = _mm256_mul_epu32(_mm256_srli_epi64(a.val, 32), _mm256_srli_epi64(b.val, 32)); + v_zip(v_uint64x4(v0), v_uint64x4(v1), c, d); +} + +inline v_int16x16 v_mul_hi(const v_int16x16& a, const v_int16x16& b) { return v_int16x16(_mm256_mulhi_epi16(a.val, b.val)); } +inline v_uint16x16 v_mul_hi(const v_uint16x16& a, const v_uint16x16& b) { return v_uint16x16(_mm256_mulhi_epu16(a.val, b.val)); } + +/** Bitwise shifts **/ +#define OPENCV_HAL_IMPL_AVX_SHIFT_OP(_Tpuvec, _Tpsvec, suffix, srai) \ + inline _Tpuvec operator << (const _Tpuvec& a, int imm) \ + { return _Tpuvec(_mm256_slli_##suffix(a.val, imm)); } \ + inline _Tpsvec operator << (const _Tpsvec& a, int imm) \ + { return _Tpsvec(_mm256_slli_##suffix(a.val, imm)); } \ + inline _Tpuvec operator >> (const _Tpuvec& a, int imm) \ + { return _Tpuvec(_mm256_srli_##suffix(a.val, imm)); } \ + inline _Tpsvec operator >> (const _Tpsvec& a, int imm) \ + { return _Tpsvec(srai(a.val, imm)); } \ + template \ + inline _Tpuvec v_shl(const _Tpuvec& a) \ + { return _Tpuvec(_mm256_slli_##suffix(a.val, imm)); } \ + template \ + inline _Tpsvec v_shl(const _Tpsvec& a) \ + { return _Tpsvec(_mm256_slli_##suffix(a.val, imm)); } \ + template \ + inline _Tpuvec v_shr(const _Tpuvec& a) \ + { return _Tpuvec(_mm256_srli_##suffix(a.val, imm)); } \ + template \ + inline _Tpsvec v_shr(const _Tpsvec& a) \ + { return _Tpsvec(srai(a.val, imm)); } + +OPENCV_HAL_IMPL_AVX_SHIFT_OP(v_uint16x16, v_int16x16, epi16, _mm256_srai_epi16) +OPENCV_HAL_IMPL_AVX_SHIFT_OP(v_uint32x8, v_int32x8, epi32, _mm256_srai_epi32) + +inline __m256i _mm256_srai_epi64xx(const __m256i a, int imm) +{ + __m256i d = _mm256_set1_epi64x((int64)1 << 63); + __m256i r = _mm256_srli_epi64(_mm256_add_epi64(a, d), imm); + return _mm256_sub_epi64(r, _mm256_srli_epi64(d, imm)); +} +OPENCV_HAL_IMPL_AVX_SHIFT_OP(v_uint64x4, v_int64x4, epi64, _mm256_srai_epi64xx) + + +/** Bitwise logic **/ +#define OPENCV_HAL_IMPL_AVX_LOGIC_OP(_Tpvec, suffix, not_const) \ + OPENCV_HAL_IMPL_AVX_BIN_OP(&, _Tpvec, _mm256_and_##suffix) \ + OPENCV_HAL_IMPL_AVX_BIN_OP(|, _Tpvec, _mm256_or_##suffix) \ + OPENCV_HAL_IMPL_AVX_BIN_OP(^, _Tpvec, _mm256_xor_##suffix) \ + inline _Tpvec operator ~ (const _Tpvec& a) \ + { return _Tpvec(_mm256_xor_##suffix(a.val, not_const)); } + +OPENCV_HAL_IMPL_AVX_LOGIC_OP(v_uint8x32, si256, _mm256_set1_epi32(-1)) +OPENCV_HAL_IMPL_AVX_LOGIC_OP(v_int8x32, si256, _mm256_set1_epi32(-1)) +OPENCV_HAL_IMPL_AVX_LOGIC_OP(v_uint16x16, si256, _mm256_set1_epi32(-1)) +OPENCV_HAL_IMPL_AVX_LOGIC_OP(v_int16x16, si256, _mm256_set1_epi32(-1)) +OPENCV_HAL_IMPL_AVX_LOGIC_OP(v_uint32x8, si256, _mm256_set1_epi32(-1)) +OPENCV_HAL_IMPL_AVX_LOGIC_OP(v_int32x8, si256, _mm256_set1_epi32(-1)) +OPENCV_HAL_IMPL_AVX_LOGIC_OP(v_uint64x4, si256, _mm256_set1_epi64x(-1)) +OPENCV_HAL_IMPL_AVX_LOGIC_OP(v_int64x4, si256, _mm256_set1_epi64x(-1)) +OPENCV_HAL_IMPL_AVX_LOGIC_OP(v_float32x8, ps, _mm256_castsi256_ps(_mm256_set1_epi32(-1))) +OPENCV_HAL_IMPL_AVX_LOGIC_OP(v_float64x4, pd, _mm256_castsi256_pd(_mm256_set1_epi32(-1))) + +/** Select **/ +#define OPENCV_HAL_IMPL_AVX_SELECT(_Tpvec, suffix) \ + inline _Tpvec v_select(const _Tpvec& mask, const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(_mm256_blendv_##suffix(b.val, a.val, mask.val)); } + +OPENCV_HAL_IMPL_AVX_SELECT(v_uint8x32, epi8) +OPENCV_HAL_IMPL_AVX_SELECT(v_int8x32, epi8) +OPENCV_HAL_IMPL_AVX_SELECT(v_uint16x16, epi8) +OPENCV_HAL_IMPL_AVX_SELECT(v_int16x16, epi8) +OPENCV_HAL_IMPL_AVX_SELECT(v_uint32x8, epi8) +OPENCV_HAL_IMPL_AVX_SELECT(v_int32x8, epi8) +OPENCV_HAL_IMPL_AVX_SELECT(v_float32x8, ps) +OPENCV_HAL_IMPL_AVX_SELECT(v_float64x4, pd) + +/** Comparison **/ +#define OPENCV_HAL_IMPL_AVX_CMP_OP_OV(_Tpvec) \ + inline _Tpvec operator != (const _Tpvec& a, const _Tpvec& b) \ + { return ~(a == b); } \ + inline _Tpvec operator < (const _Tpvec& a, const _Tpvec& b) \ + { return b > a; } \ + inline _Tpvec operator >= (const _Tpvec& a, const _Tpvec& b) \ + { return ~(a < b); } \ + inline _Tpvec operator <= (const _Tpvec& a, const _Tpvec& b) \ + { return b >= a; } + +#define OPENCV_HAL_IMPL_AVX_CMP_OP_INT(_Tpuvec, _Tpsvec, suffix, sbit) \ + inline _Tpuvec operator == (const _Tpuvec& a, const _Tpuvec& b) \ + { return _Tpuvec(_mm256_cmpeq_##suffix(a.val, b.val)); } \ + inline _Tpuvec operator > (const _Tpuvec& a, const _Tpuvec& b) \ + { \ + __m256i smask = _mm256_set1_##suffix(sbit); \ + return _Tpuvec(_mm256_cmpgt_##suffix( \ + _mm256_xor_si256(a.val, smask), \ + _mm256_xor_si256(b.val, smask))); \ + } \ + inline _Tpsvec operator == (const _Tpsvec& a, const _Tpsvec& b) \ + { return _Tpsvec(_mm256_cmpeq_##suffix(a.val, b.val)); } \ + inline _Tpsvec operator > (const _Tpsvec& a, const _Tpsvec& b) \ + { return _Tpsvec(_mm256_cmpgt_##suffix(a.val, b.val)); } \ + OPENCV_HAL_IMPL_AVX_CMP_OP_OV(_Tpuvec) \ + OPENCV_HAL_IMPL_AVX_CMP_OP_OV(_Tpsvec) + +OPENCV_HAL_IMPL_AVX_CMP_OP_INT(v_uint8x32, v_int8x32, epi8, (char)-128) +OPENCV_HAL_IMPL_AVX_CMP_OP_INT(v_uint16x16, v_int16x16, epi16, (short)-32768) +OPENCV_HAL_IMPL_AVX_CMP_OP_INT(v_uint32x8, v_int32x8, epi32, (int)0x80000000) + +#define OPENCV_HAL_IMPL_AVX_CMP_OP_64BIT(_Tpvec) \ + inline _Tpvec operator == (const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(_mm256_cmpeq_epi64(a.val, b.val)); } \ + inline _Tpvec operator != (const _Tpvec& a, const _Tpvec& b) \ + { return ~(a == b); } + +OPENCV_HAL_IMPL_AVX_CMP_OP_64BIT(v_uint64x4) +OPENCV_HAL_IMPL_AVX_CMP_OP_64BIT(v_int64x4) + +#define OPENCV_HAL_IMPL_AVX_CMP_FLT(bin_op, imm8, _Tpvec, suffix) \ + inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(_mm256_cmp_##suffix(a.val, b.val, imm8)); } + +#define OPENCV_HAL_IMPL_AVX_CMP_OP_FLT(_Tpvec, suffix) \ + OPENCV_HAL_IMPL_AVX_CMP_FLT(==, _CMP_EQ_OQ, _Tpvec, suffix) \ + OPENCV_HAL_IMPL_AVX_CMP_FLT(!=, _CMP_NEQ_OQ, _Tpvec, suffix) \ + OPENCV_HAL_IMPL_AVX_CMP_FLT(<, _CMP_LT_OQ, _Tpvec, suffix) \ + OPENCV_HAL_IMPL_AVX_CMP_FLT(>, _CMP_GT_OQ, _Tpvec, suffix) \ + OPENCV_HAL_IMPL_AVX_CMP_FLT(<=, _CMP_LE_OQ, _Tpvec, suffix) \ + OPENCV_HAL_IMPL_AVX_CMP_FLT(>=, _CMP_GE_OQ, _Tpvec, suffix) + +OPENCV_HAL_IMPL_AVX_CMP_OP_FLT(v_float32x8, ps) +OPENCV_HAL_IMPL_AVX_CMP_OP_FLT(v_float64x4, pd) + +inline v_float32x8 v_not_nan(const v_float32x8& a) +{ return v_float32x8(_mm256_cmp_ps(a.val, a.val, _CMP_ORD_Q)); } +inline v_float64x4 v_not_nan(const v_float64x4& a) +{ return v_float64x4(_mm256_cmp_pd(a.val, a.val, _CMP_ORD_Q)); } + +/** min/max **/ +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_min, v_uint8x32, _mm256_min_epu8) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_max, v_uint8x32, _mm256_max_epu8) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_min, v_int8x32, _mm256_min_epi8) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_max, v_int8x32, _mm256_max_epi8) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_min, v_uint16x16, _mm256_min_epu16) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_max, v_uint16x16, _mm256_max_epu16) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_min, v_int16x16, _mm256_min_epi16) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_max, v_int16x16, _mm256_max_epi16) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_min, v_uint32x8, _mm256_min_epu32) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_max, v_uint32x8, _mm256_max_epu32) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_min, v_int32x8, _mm256_min_epi32) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_max, v_int32x8, _mm256_max_epi32) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_min, v_float32x8, _mm256_min_ps) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_max, v_float32x8, _mm256_max_ps) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_min, v_float64x4, _mm256_min_pd) +OPENCV_HAL_IMPL_AVX_BIN_FUNC(v_max, v_float64x4, _mm256_max_pd) + +/** Rotate **/ +template +inline v_uint8x32 v_rotate_left(const v_uint8x32& a, const v_uint8x32& b) +{ + enum {IMM_R = (16 - imm) & 0xFF}; + enum {IMM_R2 = (32 - imm) & 0xFF}; + + if (imm == 0) return a; + if (imm == 32) return b; + if (imm > 32) return v_uint8x32(); + + __m256i swap = _mm256_permute2x128_si256(a.val, b.val, 0x03); + if (imm == 16) return v_uint8x32(swap); + if (imm < 16) return v_uint8x32(_mm256_alignr_epi8(a.val, swap, IMM_R)); + return v_uint8x32(_mm256_alignr_epi8(swap, b.val, IMM_R2)); // imm < 32 +} + +template +inline v_uint8x32 v_rotate_right(const v_uint8x32& a, const v_uint8x32& b) +{ + enum {IMM_L = (imm - 16) & 0xFF}; + + if (imm == 0) return a; + if (imm == 32) return b; + if (imm > 32) return v_uint8x32(); + + __m256i swap = _mm256_permute2x128_si256(a.val, b.val, 0x21); + if (imm == 16) return v_uint8x32(swap); + if (imm < 16) return v_uint8x32(_mm256_alignr_epi8(swap, a.val, imm)); + return v_uint8x32(_mm256_alignr_epi8(b.val, swap, IMM_L)); +} + +template +inline v_uint8x32 v_rotate_left(const v_uint8x32& a) +{ + enum {IMM_L = (imm - 16) & 0xFF}; + enum {IMM_R = (16 - imm) & 0xFF}; + + if (imm == 0) return a; + if (imm > 32) return v_uint8x32(); + + // ESAC control[3] ? [127:0] = 0 + __m256i swapz = _mm256_permute2x128_si256(a.val, a.val, _MM_SHUFFLE(0, 0, 2, 0)); + if (imm == 16) return v_uint8x32(swapz); + if (imm < 16) return v_uint8x32(_mm256_alignr_epi8(a.val, swapz, IMM_R)); + return v_uint8x32(_mm256_slli_si256(swapz, IMM_L)); +} + +template +inline v_uint8x32 v_rotate_right(const v_uint8x32& a) +{ + enum {IMM_L = (imm - 16) & 0xFF}; + + if (imm == 0) return a; + if (imm > 32) return v_uint8x32(); + + // ESAC control[3] ? [127:0] = 0 + __m256i swapz = _mm256_permute2x128_si256(a.val, a.val, _MM_SHUFFLE(2, 0, 0, 1)); + if (imm == 16) return v_uint8x32(swapz); + if (imm < 16) return v_uint8x32(_mm256_alignr_epi8(swapz, a.val, imm)); + return v_uint8x32(_mm256_srli_si256(swapz, IMM_L)); +} + +#define OPENCV_HAL_IMPL_AVX_ROTATE_CAST(intrin, _Tpvec, cast) \ + template \ + inline _Tpvec intrin(const _Tpvec& a, const _Tpvec& b) \ + { \ + enum {IMMxW = imm * sizeof(typename _Tpvec::lane_type)}; \ + v_uint8x32 ret = intrin(v_reinterpret_as_u8(a), \ + v_reinterpret_as_u8(b)); \ + return _Tpvec(cast(ret.val)); \ + } \ + template \ + inline _Tpvec intrin(const _Tpvec& a) \ + { \ + enum {IMMxW = imm * sizeof(typename _Tpvec::lane_type)}; \ + v_uint8x32 ret = intrin(v_reinterpret_as_u8(a)); \ + return _Tpvec(cast(ret.val)); \ + } + +#define OPENCV_HAL_IMPL_AVX_ROTATE(_Tpvec) \ + OPENCV_HAL_IMPL_AVX_ROTATE_CAST(v_rotate_left, _Tpvec, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX_ROTATE_CAST(v_rotate_right, _Tpvec, OPENCV_HAL_NOP) + +OPENCV_HAL_IMPL_AVX_ROTATE(v_int8x32) +OPENCV_HAL_IMPL_AVX_ROTATE(v_uint16x16) +OPENCV_HAL_IMPL_AVX_ROTATE(v_int16x16) +OPENCV_HAL_IMPL_AVX_ROTATE(v_uint32x8) +OPENCV_HAL_IMPL_AVX_ROTATE(v_int32x8) +OPENCV_HAL_IMPL_AVX_ROTATE(v_uint64x4) +OPENCV_HAL_IMPL_AVX_ROTATE(v_int64x4) + +OPENCV_HAL_IMPL_AVX_ROTATE_CAST(v_rotate_left, v_float32x8, _mm256_castsi256_ps) +OPENCV_HAL_IMPL_AVX_ROTATE_CAST(v_rotate_right, v_float32x8, _mm256_castsi256_ps) +OPENCV_HAL_IMPL_AVX_ROTATE_CAST(v_rotate_left, v_float64x4, _mm256_castsi256_pd) +OPENCV_HAL_IMPL_AVX_ROTATE_CAST(v_rotate_right, v_float64x4, _mm256_castsi256_pd) + +/** Reverse **/ +inline v_uint8x32 v_reverse(const v_uint8x32 &a) +{ + static const __m256i perm = _mm256_setr_epi8( + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + __m256i vec = _mm256_shuffle_epi8(a.val, perm); + return v_uint8x32(_mm256_permute2x128_si256(vec, vec, 1)); +} + +inline v_int8x32 v_reverse(const v_int8x32 &a) +{ return v_reinterpret_as_s8(v_reverse(v_reinterpret_as_u8(a))); } + +inline v_uint16x16 v_reverse(const v_uint16x16 &a) +{ + static const __m256i perm = _mm256_setr_epi8( + 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1, + 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1); + __m256i vec = _mm256_shuffle_epi8(a.val, perm); + return v_uint16x16(_mm256_permute2x128_si256(vec, vec, 1)); +} + +inline v_int16x16 v_reverse(const v_int16x16 &a) +{ return v_reinterpret_as_s16(v_reverse(v_reinterpret_as_u16(a))); } + +inline v_uint32x8 v_reverse(const v_uint32x8 &a) +{ + static const __m256i perm = _mm256_setr_epi32(7, 6, 5, 4, 3, 2, 1, 0); + return v_uint32x8(_mm256_permutevar8x32_epi32(a.val, perm)); +} + +inline v_int32x8 v_reverse(const v_int32x8 &a) +{ return v_reinterpret_as_s32(v_reverse(v_reinterpret_as_u32(a))); } + +inline v_float32x8 v_reverse(const v_float32x8 &a) +{ return v_reinterpret_as_f32(v_reverse(v_reinterpret_as_u32(a))); } + +inline v_uint64x4 v_reverse(const v_uint64x4 &a) +{ + return v_uint64x4(_mm256_permute4x64_epi64(a.val, _MM_SHUFFLE(0, 1, 2, 3))); +} + +inline v_int64x4 v_reverse(const v_int64x4 &a) +{ return v_reinterpret_as_s64(v_reverse(v_reinterpret_as_u64(a))); } + +inline v_float64x4 v_reverse(const v_float64x4 &a) +{ return v_reinterpret_as_f64(v_reverse(v_reinterpret_as_u64(a))); } + +////////// Reduce and mask ///////// + +/** Reduce **/ +inline unsigned v_reduce_sum(const v_uint8x32& a) +{ + __m256i half = _mm256_sad_epu8(a.val, _mm256_setzero_si256()); + __m128i quarter = _mm_add_epi32(_v256_extract_low(half), _v256_extract_high(half)); + return (unsigned)_mm_cvtsi128_si32(_mm_add_epi32(quarter, _mm_unpackhi_epi64(quarter, quarter))); +} +inline int v_reduce_sum(const v_int8x32& a) +{ + __m256i half = _mm256_sad_epu8(_mm256_xor_si256(a.val, _mm256_set1_epi8((schar)-128)), _mm256_setzero_si256()); + __m128i quarter = _mm_add_epi32(_v256_extract_low(half), _v256_extract_high(half)); + return (unsigned)_mm_cvtsi128_si32(_mm_add_epi32(quarter, _mm_unpackhi_epi64(quarter, quarter))) - 4096; +} +#define OPENCV_HAL_IMPL_AVX_REDUCE_32(_Tpvec, sctype, func, intrin) \ + inline sctype v_reduce_##func(const _Tpvec& a) \ + { \ + __m128i val = intrin(_v256_extract_low(a.val), _v256_extract_high(a.val)); \ + val = intrin(val, _mm_srli_si128(val,8)); \ + val = intrin(val, _mm_srli_si128(val,4)); \ + val = intrin(val, _mm_srli_si128(val,2)); \ + val = intrin(val, _mm_srli_si128(val,1)); \ + return (sctype)_mm_cvtsi128_si32(val); \ + } + +OPENCV_HAL_IMPL_AVX_REDUCE_32(v_uint8x32, uchar, min, _mm_min_epu8) +OPENCV_HAL_IMPL_AVX_REDUCE_32(v_int8x32, schar, min, _mm_min_epi8) +OPENCV_HAL_IMPL_AVX_REDUCE_32(v_uint8x32, uchar, max, _mm_max_epu8) +OPENCV_HAL_IMPL_AVX_REDUCE_32(v_int8x32, schar, max, _mm_max_epi8) + +#define OPENCV_HAL_IMPL_AVX_REDUCE_16(_Tpvec, sctype, func, intrin) \ + inline sctype v_reduce_##func(const _Tpvec& a) \ + { \ + __m128i v0 = _v256_extract_low(a.val); \ + __m128i v1 = _v256_extract_high(a.val); \ + v0 = intrin(v0, v1); \ + v0 = intrin(v0, _mm_srli_si128(v0, 8)); \ + v0 = intrin(v0, _mm_srli_si128(v0, 4)); \ + v0 = intrin(v0, _mm_srli_si128(v0, 2)); \ + return (sctype) _mm_cvtsi128_si32(v0); \ + } + +OPENCV_HAL_IMPL_AVX_REDUCE_16(v_uint16x16, ushort, min, _mm_min_epu16) +OPENCV_HAL_IMPL_AVX_REDUCE_16(v_int16x16, short, min, _mm_min_epi16) +OPENCV_HAL_IMPL_AVX_REDUCE_16(v_uint16x16, ushort, max, _mm_max_epu16) +OPENCV_HAL_IMPL_AVX_REDUCE_16(v_int16x16, short, max, _mm_max_epi16) + +#define OPENCV_HAL_IMPL_AVX_REDUCE_8(_Tpvec, sctype, func, intrin) \ + inline sctype v_reduce_##func(const _Tpvec& a) \ + { \ + __m128i v0 = _v256_extract_low(a.val); \ + __m128i v1 = _v256_extract_high(a.val); \ + v0 = intrin(v0, v1); \ + v0 = intrin(v0, _mm_srli_si128(v0, 8)); \ + v0 = intrin(v0, _mm_srli_si128(v0, 4)); \ + return (sctype) _mm_cvtsi128_si32(v0); \ + } + +OPENCV_HAL_IMPL_AVX_REDUCE_8(v_uint32x8, unsigned, min, _mm_min_epu32) +OPENCV_HAL_IMPL_AVX_REDUCE_8(v_int32x8, int, min, _mm_min_epi32) +OPENCV_HAL_IMPL_AVX_REDUCE_8(v_uint32x8, unsigned, max, _mm_max_epu32) +OPENCV_HAL_IMPL_AVX_REDUCE_8(v_int32x8, int, max, _mm_max_epi32) + +#define OPENCV_HAL_IMPL_AVX_REDUCE_FLT(func, intrin) \ + inline float v_reduce_##func(const v_float32x8& a) \ + { \ + __m128 v0 = _v256_extract_low(a.val); \ + __m128 v1 = _v256_extract_high(a.val); \ + v0 = intrin(v0, v1); \ + v0 = intrin(v0, _mm_permute_ps(v0, _MM_SHUFFLE(0, 0, 3, 2))); \ + v0 = intrin(v0, _mm_permute_ps(v0, _MM_SHUFFLE(0, 0, 0, 1))); \ + return _mm_cvtss_f32(v0); \ + } + +OPENCV_HAL_IMPL_AVX_REDUCE_FLT(min, _mm_min_ps) +OPENCV_HAL_IMPL_AVX_REDUCE_FLT(max, _mm_max_ps) + +inline int v_reduce_sum(const v_int32x8& a) +{ + __m256i s0 = _mm256_hadd_epi32(a.val, a.val); + s0 = _mm256_hadd_epi32(s0, s0); + + __m128i s1 = _v256_extract_high(s0); + s1 = _mm_add_epi32(_v256_extract_low(s0), s1); + + return _mm_cvtsi128_si32(s1); +} + +inline unsigned v_reduce_sum(const v_uint32x8& a) +{ return v_reduce_sum(v_reinterpret_as_s32(a)); } + +inline int v_reduce_sum(const v_int16x16& a) +{ return v_reduce_sum(v_expand_low(a) + v_expand_high(a)); } +inline unsigned v_reduce_sum(const v_uint16x16& a) +{ return v_reduce_sum(v_expand_low(a) + v_expand_high(a)); } + +inline float v_reduce_sum(const v_float32x8& a) +{ + __m256 s0 = _mm256_hadd_ps(a.val, a.val); + s0 = _mm256_hadd_ps(s0, s0); + + __m128 s1 = _v256_extract_high(s0); + s1 = _mm_add_ps(_v256_extract_low(s0), s1); + + return _mm_cvtss_f32(s1); +} + +inline uint64 v_reduce_sum(const v_uint64x4& a) +{ + uint64 CV_DECL_ALIGNED(32) idx[2]; + _mm_store_si128((__m128i*)idx, _mm_add_epi64(_v256_extract_low(a.val), _v256_extract_high(a.val))); + return idx[0] + idx[1]; +} +inline int64 v_reduce_sum(const v_int64x4& a) +{ + int64 CV_DECL_ALIGNED(32) idx[2]; + _mm_store_si128((__m128i*)idx, _mm_add_epi64(_v256_extract_low(a.val), _v256_extract_high(a.val))); + return idx[0] + idx[1]; +} +inline double v_reduce_sum(const v_float64x4& a) +{ + __m256d s0 = _mm256_hadd_pd(a.val, a.val); + return _mm_cvtsd_f64(_mm_add_pd(_v256_extract_low(s0), _v256_extract_high(s0))); +} + +inline v_float32x8 v_reduce_sum4(const v_float32x8& a, const v_float32x8& b, + const v_float32x8& c, const v_float32x8& d) +{ + __m256 ab = _mm256_hadd_ps(a.val, b.val); + __m256 cd = _mm256_hadd_ps(c.val, d.val); + return v_float32x8(_mm256_hadd_ps(ab, cd)); +} + +inline unsigned v_reduce_sad(const v_uint8x32& a, const v_uint8x32& b) +{ + __m256i half = _mm256_sad_epu8(a.val, b.val); + __m128i quarter = _mm_add_epi32(_v256_extract_low(half), _v256_extract_high(half)); + return (unsigned)_mm_cvtsi128_si32(_mm_add_epi32(quarter, _mm_unpackhi_epi64(quarter, quarter))); +} +inline unsigned v_reduce_sad(const v_int8x32& a, const v_int8x32& b) +{ + __m256i half = _mm256_set1_epi8(0x7f); + half = _mm256_sad_epu8(_mm256_add_epi8(a.val, half), _mm256_add_epi8(b.val, half)); + __m128i quarter = _mm_add_epi32(_v256_extract_low(half), _v256_extract_high(half)); + return (unsigned)_mm_cvtsi128_si32(_mm_add_epi32(quarter, _mm_unpackhi_epi64(quarter, quarter))); +} +inline unsigned v_reduce_sad(const v_uint16x16& a, const v_uint16x16& b) +{ + v_uint32x8 l, h; + v_expand(v_add_wrap(a - b, b - a), l, h); + return v_reduce_sum(l + h); +} +inline unsigned v_reduce_sad(const v_int16x16& a, const v_int16x16& b) +{ + v_uint32x8 l, h; + v_expand(v_reinterpret_as_u16(v_sub_wrap(v_max(a, b), v_min(a, b))), l, h); + return v_reduce_sum(l + h); +} +inline unsigned v_reduce_sad(const v_uint32x8& a, const v_uint32x8& b) +{ + return v_reduce_sum(v_max(a, b) - v_min(a, b)); +} +inline unsigned v_reduce_sad(const v_int32x8& a, const v_int32x8& b) +{ + v_int32x8 m = a < b; + return v_reduce_sum(v_reinterpret_as_u32(((a - b) ^ m) - m)); +} +inline float v_reduce_sad(const v_float32x8& a, const v_float32x8& b) +{ + return v_reduce_sum((a - b) & v_float32x8(_mm256_castsi256_ps(_mm256_set1_epi32(0x7fffffff)))); +} + +/** Popcount **/ +inline v_uint8x32 v_popcount(const v_uint8x32& a) +{ + __m256i _popcnt_table = _mm256_setr_epi8(0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4); + __m256i _popcnt_mask = _mm256_set1_epi8(0x0F); + return v_uint8x32(_mm256_add_epi8(_mm256_shuffle_epi8(_popcnt_table, _mm256_and_si256( a.val , _popcnt_mask)), + _mm256_shuffle_epi8(_popcnt_table, _mm256_and_si256(_mm256_srli_epi16(a.val, 4), _popcnt_mask)))); +} +inline v_uint16x16 v_popcount(const v_uint16x16& a) +{ + v_uint8x32 p = v_popcount(v_reinterpret_as_u8(a)); + p += v_rotate_right<1>(p); + return v_reinterpret_as_u16(p) & v256_setall_u16(0x00ff); +} +inline v_uint32x8 v_popcount(const v_uint32x8& a) +{ + v_uint8x32 p = v_popcount(v_reinterpret_as_u8(a)); + p += v_rotate_right<1>(p); + p += v_rotate_right<2>(p); + return v_reinterpret_as_u32(p) & v256_setall_u32(0x000000ff); +} +inline v_uint64x4 v_popcount(const v_uint64x4& a) +{ + return v_uint64x4(_mm256_sad_epu8(v_popcount(v_reinterpret_as_u8(a)).val, _mm256_setzero_si256())); +} +inline v_uint8x32 v_popcount(const v_int8x32& a) +{ return v_popcount(v_reinterpret_as_u8(a)); } +inline v_uint16x16 v_popcount(const v_int16x16& a) +{ return v_popcount(v_reinterpret_as_u16(a)); } +inline v_uint32x8 v_popcount(const v_int32x8& a) +{ return v_popcount(v_reinterpret_as_u32(a)); } +inline v_uint64x4 v_popcount(const v_int64x4& a) +{ return v_popcount(v_reinterpret_as_u64(a)); } + +/** Mask **/ +inline int v_signmask(const v_int8x32& a) +{ return _mm256_movemask_epi8(a.val); } +inline int v_signmask(const v_uint8x32& a) +{ return v_signmask(v_reinterpret_as_s8(a)); } + +inline int v_signmask(const v_int16x16& a) +{ return v_signmask(v_pack(a, a)) & 0xFFFF; } +inline int v_signmask(const v_uint16x16& a) +{ return v_signmask(v_reinterpret_as_s16(a)); } + +inline int v_signmask(const v_float32x8& a) +{ return _mm256_movemask_ps(a.val); } +inline int v_signmask(const v_float64x4& a) +{ return _mm256_movemask_pd(a.val); } + +inline int v_signmask(const v_int32x8& a) +{ return v_signmask(v_reinterpret_as_f32(a)); } +inline int v_signmask(const v_uint32x8& a) +{ return v_signmask(v_reinterpret_as_f32(a)); } + +inline int v_signmask(const v_int64x4& a) +{ return v_signmask(v_reinterpret_as_f64(a)); } +inline int v_signmask(const v_uint64x4& a) +{ return v_signmask(v_reinterpret_as_f64(a)); } + +inline int v_scan_forward(const v_int8x32& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))); } +inline int v_scan_forward(const v_uint8x32& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))); } +inline int v_scan_forward(const v_int16x16& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 2; } +inline int v_scan_forward(const v_uint16x16& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 2; } +inline int v_scan_forward(const v_int32x8& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 4; } +inline int v_scan_forward(const v_uint32x8& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 4; } +inline int v_scan_forward(const v_float32x8& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 4; } +inline int v_scan_forward(const v_int64x4& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 8; } +inline int v_scan_forward(const v_uint64x4& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 8; } +inline int v_scan_forward(const v_float64x4& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 8; } + +/** Checks **/ +#define OPENCV_HAL_IMPL_AVX_CHECK(_Tpvec, allmask) \ + inline bool v_check_all(const _Tpvec& a) { return v_signmask(a) == allmask; } \ + inline bool v_check_any(const _Tpvec& a) { return v_signmask(a) != 0; } +OPENCV_HAL_IMPL_AVX_CHECK(v_uint8x32, -1) +OPENCV_HAL_IMPL_AVX_CHECK(v_int8x32, -1) +OPENCV_HAL_IMPL_AVX_CHECK(v_uint32x8, 255) +OPENCV_HAL_IMPL_AVX_CHECK(v_int32x8, 255) +OPENCV_HAL_IMPL_AVX_CHECK(v_uint64x4, 15) +OPENCV_HAL_IMPL_AVX_CHECK(v_int64x4, 15) +OPENCV_HAL_IMPL_AVX_CHECK(v_float32x8, 255) +OPENCV_HAL_IMPL_AVX_CHECK(v_float64x4, 15) + +#define OPENCV_HAL_IMPL_AVX_CHECK_SHORT(_Tpvec) \ + inline bool v_check_all(const _Tpvec& a) { return (v_signmask(v_reinterpret_as_s8(a)) & 0xaaaaaaaa) == 0xaaaaaaaa; } \ + inline bool v_check_any(const _Tpvec& a) { return (v_signmask(v_reinterpret_as_s8(a)) & 0xaaaaaaaa) != 0; } +OPENCV_HAL_IMPL_AVX_CHECK_SHORT(v_uint16x16) +OPENCV_HAL_IMPL_AVX_CHECK_SHORT(v_int16x16) + +////////// Other math ///////// + +/** Some frequent operations **/ +#if CV_FMA3 +#define OPENCV_HAL_IMPL_AVX_MULADD(_Tpvec, suffix) \ + inline _Tpvec v_fma(const _Tpvec& a, const _Tpvec& b, const _Tpvec& c) \ + { return _Tpvec(_mm256_fmadd_##suffix(a.val, b.val, c.val)); } \ + inline _Tpvec v_muladd(const _Tpvec& a, const _Tpvec& b, const _Tpvec& c) \ + { return _Tpvec(_mm256_fmadd_##suffix(a.val, b.val, c.val)); } +#else +#define OPENCV_HAL_IMPL_AVX_MULADD(_Tpvec, suffix) \ + inline _Tpvec v_fma(const _Tpvec& a, const _Tpvec& b, const _Tpvec& c) \ + { return _Tpvec(_mm256_add_##suffix(_mm256_mul_##suffix(a.val, b.val), c.val)); } \ + inline _Tpvec v_muladd(const _Tpvec& a, const _Tpvec& b, const _Tpvec& c) \ + { return _Tpvec(_mm256_add_##suffix(_mm256_mul_##suffix(a.val, b.val), c.val)); } +#endif + +#define OPENCV_HAL_IMPL_AVX_MISC(_Tpvec, suffix) \ + inline _Tpvec v_sqrt(const _Tpvec& x) \ + { return _Tpvec(_mm256_sqrt_##suffix(x.val)); } \ + inline _Tpvec v_sqr_magnitude(const _Tpvec& a, const _Tpvec& b) \ + { return v_fma(a, a, b * b); } \ + inline _Tpvec v_magnitude(const _Tpvec& a, const _Tpvec& b) \ + { return v_sqrt(v_fma(a, a, b*b)); } + +OPENCV_HAL_IMPL_AVX_MULADD(v_float32x8, ps) +OPENCV_HAL_IMPL_AVX_MULADD(v_float64x4, pd) +OPENCV_HAL_IMPL_AVX_MISC(v_float32x8, ps) +OPENCV_HAL_IMPL_AVX_MISC(v_float64x4, pd) + +inline v_int32x8 v_fma(const v_int32x8& a, const v_int32x8& b, const v_int32x8& c) +{ + return a * b + c; +} + +inline v_int32x8 v_muladd(const v_int32x8& a, const v_int32x8& b, const v_int32x8& c) +{ + return v_fma(a, b, c); +} + +inline v_float32x8 v_invsqrt(const v_float32x8& x) +{ + v_float32x8 half = x * v256_setall_f32(0.5); + v_float32x8 t = v_float32x8(_mm256_rsqrt_ps(x.val)); + // todo: _mm256_fnmsub_ps + t *= v256_setall_f32(1.5) - ((t * t) * half); + return t; +} + +inline v_float64x4 v_invsqrt(const v_float64x4& x) +{ + return v256_setall_f64(1.) / v_sqrt(x); +} + +/** Absolute values **/ +#define OPENCV_HAL_IMPL_AVX_ABS(_Tpvec, suffix) \ + inline v_u##_Tpvec v_abs(const v_##_Tpvec& x) \ + { return v_u##_Tpvec(_mm256_abs_##suffix(x.val)); } + +OPENCV_HAL_IMPL_AVX_ABS(int8x32, epi8) +OPENCV_HAL_IMPL_AVX_ABS(int16x16, epi16) +OPENCV_HAL_IMPL_AVX_ABS(int32x8, epi32) + +inline v_float32x8 v_abs(const v_float32x8& x) +{ return x & v_float32x8(_mm256_castsi256_ps(_mm256_set1_epi32(0x7fffffff))); } +inline v_float64x4 v_abs(const v_float64x4& x) +{ return x & v_float64x4(_mm256_castsi256_pd(_mm256_srli_epi64(_mm256_set1_epi64x(-1), 1))); } + +/** Absolute difference **/ +inline v_uint8x32 v_absdiff(const v_uint8x32& a, const v_uint8x32& b) +{ return v_add_wrap(a - b, b - a); } +inline v_uint16x16 v_absdiff(const v_uint16x16& a, const v_uint16x16& b) +{ return v_add_wrap(a - b, b - a); } +inline v_uint32x8 v_absdiff(const v_uint32x8& a, const v_uint32x8& b) +{ return v_max(a, b) - v_min(a, b); } + +inline v_uint8x32 v_absdiff(const v_int8x32& a, const v_int8x32& b) +{ + v_int8x32 d = v_sub_wrap(a, b); + v_int8x32 m = a < b; + return v_reinterpret_as_u8(v_sub_wrap(d ^ m, m)); +} + +inline v_uint16x16 v_absdiff(const v_int16x16& a, const v_int16x16& b) +{ return v_reinterpret_as_u16(v_sub_wrap(v_max(a, b), v_min(a, b))); } + +inline v_uint32x8 v_absdiff(const v_int32x8& a, const v_int32x8& b) +{ + v_int32x8 d = a - b; + v_int32x8 m = a < b; + return v_reinterpret_as_u32((d ^ m) - m); +} + +inline v_float32x8 v_absdiff(const v_float32x8& a, const v_float32x8& b) +{ return v_abs(a - b); } + +inline v_float64x4 v_absdiff(const v_float64x4& a, const v_float64x4& b) +{ return v_abs(a - b); } + +/** Saturating absolute difference **/ +inline v_int8x32 v_absdiffs(const v_int8x32& a, const v_int8x32& b) +{ + v_int8x32 d = a - b; + v_int8x32 m = a < b; + return (d ^ m) - m; +} +inline v_int16x16 v_absdiffs(const v_int16x16& a, const v_int16x16& b) +{ return v_max(a, b) - v_min(a, b); } + +////////// Conversions ///////// + +/** Rounding **/ +inline v_int32x8 v_round(const v_float32x8& a) +{ return v_int32x8(_mm256_cvtps_epi32(a.val)); } + +inline v_int32x8 v_round(const v_float64x4& a) +{ return v_int32x8(_mm256_castsi128_si256(_mm256_cvtpd_epi32(a.val))); } + +inline v_int32x8 v_round(const v_float64x4& a, const v_float64x4& b) +{ + __m128i ai = _mm256_cvtpd_epi32(a.val), bi = _mm256_cvtpd_epi32(b.val); + return v_int32x8(_v256_combine(ai, bi)); +} + +inline v_int32x8 v_trunc(const v_float32x8& a) +{ return v_int32x8(_mm256_cvttps_epi32(a.val)); } + +inline v_int32x8 v_trunc(const v_float64x4& a) +{ return v_int32x8(_mm256_castsi128_si256(_mm256_cvttpd_epi32(a.val))); } + +inline v_int32x8 v_floor(const v_float32x8& a) +{ return v_int32x8(_mm256_cvttps_epi32(_mm256_floor_ps(a.val))); } + +inline v_int32x8 v_floor(const v_float64x4& a) +{ return v_trunc(v_float64x4(_mm256_floor_pd(a.val))); } + +inline v_int32x8 v_ceil(const v_float32x8& a) +{ return v_int32x8(_mm256_cvttps_epi32(_mm256_ceil_ps(a.val))); } + +inline v_int32x8 v_ceil(const v_float64x4& a) +{ return v_trunc(v_float64x4(_mm256_ceil_pd(a.val))); } + +/** To float **/ +inline v_float32x8 v_cvt_f32(const v_int32x8& a) +{ return v_float32x8(_mm256_cvtepi32_ps(a.val)); } + +inline v_float32x8 v_cvt_f32(const v_float64x4& a) +{ return v_float32x8(_mm256_castps128_ps256(_mm256_cvtpd_ps(a.val))); } + +inline v_float32x8 v_cvt_f32(const v_float64x4& a, const v_float64x4& b) +{ + __m128 af = _mm256_cvtpd_ps(a.val), bf = _mm256_cvtpd_ps(b.val); + return v_float32x8(_v256_combine(af, bf)); +} + +inline v_float64x4 v_cvt_f64(const v_int32x8& a) +{ return v_float64x4(_mm256_cvtepi32_pd(_v256_extract_low(a.val))); } + +inline v_float64x4 v_cvt_f64_high(const v_int32x8& a) +{ return v_float64x4(_mm256_cvtepi32_pd(_v256_extract_high(a.val))); } + +inline v_float64x4 v_cvt_f64(const v_float32x8& a) +{ return v_float64x4(_mm256_cvtps_pd(_v256_extract_low(a.val))); } + +inline v_float64x4 v_cvt_f64_high(const v_float32x8& a) +{ return v_float64x4(_mm256_cvtps_pd(_v256_extract_high(a.val))); } + +// from (Mysticial and wim) https://stackoverflow.com/q/41144668 +inline v_float64x4 v_cvt_f64(const v_int64x4& v) +{ + // constants encoded as floating-point + __m256i magic_i_lo = _mm256_set1_epi64x(0x4330000000000000); // 2^52 + __m256i magic_i_hi32 = _mm256_set1_epi64x(0x4530000080000000); // 2^84 + 2^63 + __m256i magic_i_all = _mm256_set1_epi64x(0x4530000080100000); // 2^84 + 2^63 + 2^52 + __m256d magic_d_all = _mm256_castsi256_pd(magic_i_all); + + // Blend the 32 lowest significant bits of v with magic_int_lo + __m256i v_lo = _mm256_blend_epi32(magic_i_lo, v.val, 0x55); + // Extract the 32 most significant bits of v + __m256i v_hi = _mm256_srli_epi64(v.val, 32); + // Flip the msb of v_hi and blend with 0x45300000 + v_hi = _mm256_xor_si256(v_hi, magic_i_hi32); + // Compute in double precision + __m256d v_hi_dbl = _mm256_sub_pd(_mm256_castsi256_pd(v_hi), magic_d_all); + // (v_hi - magic_d_all) + v_lo Do not assume associativity of floating point addition + __m256d result = _mm256_add_pd(v_hi_dbl, _mm256_castsi256_pd(v_lo)); + return v_float64x4(result); +} + +////////////// Lookup table access //////////////////// + +inline v_int8x32 v256_lut(const schar* tab, const int* idx) +{ + return v_int8x32(_mm256_setr_epi8(tab[idx[ 0]], tab[idx[ 1]], tab[idx[ 2]], tab[idx[ 3]], tab[idx[ 4]], tab[idx[ 5]], tab[idx[ 6]], tab[idx[ 7]], + tab[idx[ 8]], tab[idx[ 9]], tab[idx[10]], tab[idx[11]], tab[idx[12]], tab[idx[13]], tab[idx[14]], tab[idx[15]], + tab[idx[16]], tab[idx[17]], tab[idx[18]], tab[idx[19]], tab[idx[20]], tab[idx[21]], tab[idx[22]], tab[idx[23]], + tab[idx[24]], tab[idx[25]], tab[idx[26]], tab[idx[27]], tab[idx[28]], tab[idx[29]], tab[idx[30]], tab[idx[31]])); +} +inline v_int8x32 v256_lut_pairs(const schar* tab, const int* idx) +{ + return v_int8x32(_mm256_setr_epi16(*(const short*)(tab + idx[ 0]), *(const short*)(tab + idx[ 1]), *(const short*)(tab + idx[ 2]), *(const short*)(tab + idx[ 3]), + *(const short*)(tab + idx[ 4]), *(const short*)(tab + idx[ 5]), *(const short*)(tab + idx[ 6]), *(const short*)(tab + idx[ 7]), + *(const short*)(tab + idx[ 8]), *(const short*)(tab + idx[ 9]), *(const short*)(tab + idx[10]), *(const short*)(tab + idx[11]), + *(const short*)(tab + idx[12]), *(const short*)(tab + idx[13]), *(const short*)(tab + idx[14]), *(const short*)(tab + idx[15]))); +} +inline v_int8x32 v256_lut_quads(const schar* tab, const int* idx) +{ + return v_int8x32(_mm256_i32gather_epi32((const int*)tab, _mm256_loadu_si256((const __m256i*)idx), 1)); +} +inline v_uint8x32 v256_lut(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v256_lut((const schar *)tab, idx)); } +inline v_uint8x32 v256_lut_pairs(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v256_lut_pairs((const schar *)tab, idx)); } +inline v_uint8x32 v256_lut_quads(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v256_lut_quads((const schar *)tab, idx)); } + +inline v_int16x16 v256_lut(const short* tab, const int* idx) +{ + return v_int16x16(_mm256_setr_epi16(tab[idx[0]], tab[idx[1]], tab[idx[ 2]], tab[idx[ 3]], tab[idx[ 4]], tab[idx[ 5]], tab[idx[ 6]], tab[idx[ 7]], + tab[idx[8]], tab[idx[9]], tab[idx[10]], tab[idx[11]], tab[idx[12]], tab[idx[13]], tab[idx[14]], tab[idx[15]])); +} +inline v_int16x16 v256_lut_pairs(const short* tab, const int* idx) +{ + return v_int16x16(_mm256_i32gather_epi32((const int*)tab, _mm256_loadu_si256((const __m256i*)idx), 2)); +} +inline v_int16x16 v256_lut_quads(const short* tab, const int* idx) +{ +#if defined(__GNUC__) + return v_int16x16(_mm256_i32gather_epi64((const long long int*)tab, _mm_loadu_si128((const __m128i*)idx), 2));//Looks like intrinsic has wrong definition +#else + return v_int16x16(_mm256_i32gather_epi64((const int64*)tab, _mm_loadu_si128((const __m128i*)idx), 2)); +#endif +} +inline v_uint16x16 v256_lut(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v256_lut((const short *)tab, idx)); } +inline v_uint16x16 v256_lut_pairs(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v256_lut_pairs((const short *)tab, idx)); } +inline v_uint16x16 v256_lut_quads(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v256_lut_quads((const short *)tab, idx)); } + +inline v_int32x8 v256_lut(const int* tab, const int* idx) +{ + return v_int32x8(_mm256_i32gather_epi32(tab, _mm256_loadu_si256((const __m256i*)idx), 4)); +} +inline v_int32x8 v256_lut_pairs(const int* tab, const int* idx) +{ +#if defined(__GNUC__) + return v_int32x8(_mm256_i32gather_epi64((const long long int*)tab, _mm_loadu_si128((const __m128i*)idx), 4)); +#else + return v_int32x8(_mm256_i32gather_epi64((const int64*)tab, _mm_loadu_si128((const __m128i*)idx), 4)); +#endif +} +inline v_int32x8 v256_lut_quads(const int* tab, const int* idx) +{ + return v_int32x8(_v256_combine(_mm_loadu_si128((const __m128i*)(tab + idx[0])), _mm_loadu_si128((const __m128i*)(tab + idx[1])))); +} +inline v_uint32x8 v256_lut(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v256_lut((const int *)tab, idx)); } +inline v_uint32x8 v256_lut_pairs(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v256_lut_pairs((const int *)tab, idx)); } +inline v_uint32x8 v256_lut_quads(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v256_lut_quads((const int *)tab, idx)); } + +inline v_int64x4 v256_lut(const int64* tab, const int* idx) +{ +#if defined(__GNUC__) + return v_int64x4(_mm256_i32gather_epi64((const long long int*)tab, _mm_loadu_si128((const __m128i*)idx), 8)); +#else + return v_int64x4(_mm256_i32gather_epi64(tab, _mm_loadu_si128((const __m128i*)idx), 8)); +#endif +} +inline v_int64x4 v256_lut_pairs(const int64* tab, const int* idx) +{ + return v_int64x4(_v256_combine(_mm_loadu_si128((const __m128i*)(tab + idx[0])), _mm_loadu_si128((const __m128i*)(tab + idx[1])))); +} +inline v_uint64x4 v256_lut(const uint64* tab, const int* idx) { return v_reinterpret_as_u64(v256_lut((const int64 *)tab, idx)); } +inline v_uint64x4 v256_lut_pairs(const uint64* tab, const int* idx) { return v_reinterpret_as_u64(v256_lut_pairs((const int64 *)tab, idx)); } + +inline v_float32x8 v256_lut(const float* tab, const int* idx) +{ + return v_float32x8(_mm256_i32gather_ps(tab, _mm256_loadu_si256((const __m256i*)idx), 4)); +} +inline v_float32x8 v256_lut_pairs(const float* tab, const int* idx) { return v_reinterpret_as_f32(v256_lut_pairs((const int *)tab, idx)); } +inline v_float32x8 v256_lut_quads(const float* tab, const int* idx) { return v_reinterpret_as_f32(v256_lut_quads((const int *)tab, idx)); } + +inline v_float64x4 v256_lut(const double* tab, const int* idx) +{ + return v_float64x4(_mm256_i32gather_pd(tab, _mm_loadu_si128((const __m128i*)idx), 8)); +} +inline v_float64x4 v256_lut_pairs(const double* tab, const int* idx) { return v_float64x4(_v256_combine(_mm_loadu_pd(tab + idx[0]), _mm_loadu_pd(tab + idx[1]))); } + +inline v_int32x8 v_lut(const int* tab, const v_int32x8& idxvec) +{ + return v_int32x8(_mm256_i32gather_epi32(tab, idxvec.val, 4)); +} + +inline v_uint32x8 v_lut(const unsigned* tab, const v_int32x8& idxvec) +{ + return v_reinterpret_as_u32(v_lut((const int *)tab, idxvec)); +} + +inline v_float32x8 v_lut(const float* tab, const v_int32x8& idxvec) +{ + return v_float32x8(_mm256_i32gather_ps(tab, idxvec.val, 4)); +} + +inline v_float64x4 v_lut(const double* tab, const v_int32x8& idxvec) +{ + return v_float64x4(_mm256_i32gather_pd(tab, _mm256_castsi256_si128(idxvec.val), 8)); +} + +inline void v_lut_deinterleave(const float* tab, const v_int32x8& idxvec, v_float32x8& x, v_float32x8& y) +{ + int CV_DECL_ALIGNED(32) idx[8]; + v_store_aligned(idx, idxvec); + __m128 z = _mm_setzero_ps(); + __m128 xy01, xy45, xy23, xy67; + xy01 = _mm_loadl_pi(z, (const __m64*)(tab + idx[0])); + xy01 = _mm_loadh_pi(xy01, (const __m64*)(tab + idx[1])); + xy45 = _mm_loadl_pi(z, (const __m64*)(tab + idx[4])); + xy45 = _mm_loadh_pi(xy45, (const __m64*)(tab + idx[5])); + __m256 xy0145 = _v256_combine(xy01, xy45); + xy23 = _mm_loadl_pi(z, (const __m64*)(tab + idx[2])); + xy23 = _mm_loadh_pi(xy23, (const __m64*)(tab + idx[3])); + xy67 = _mm_loadl_pi(z, (const __m64*)(tab + idx[6])); + xy67 = _mm_loadh_pi(xy67, (const __m64*)(tab + idx[7])); + __m256 xy2367 = _v256_combine(xy23, xy67); + + __m256 xxyy0145 = _mm256_unpacklo_ps(xy0145, xy2367); + __m256 xxyy2367 = _mm256_unpackhi_ps(xy0145, xy2367); + + x = v_float32x8(_mm256_unpacklo_ps(xxyy0145, xxyy2367)); + y = v_float32x8(_mm256_unpackhi_ps(xxyy0145, xxyy2367)); +} + +inline void v_lut_deinterleave(const double* tab, const v_int32x8& idxvec, v_float64x4& x, v_float64x4& y) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_low(idx, idxvec); + __m128d xy0 = _mm_loadu_pd(tab + idx[0]); + __m128d xy2 = _mm_loadu_pd(tab + idx[2]); + __m128d xy1 = _mm_loadu_pd(tab + idx[1]); + __m128d xy3 = _mm_loadu_pd(tab + idx[3]); + __m256d xy02 = _v256_combine(xy0, xy2); + __m256d xy13 = _v256_combine(xy1, xy3); + + x = v_float64x4(_mm256_unpacklo_pd(xy02, xy13)); + y = v_float64x4(_mm256_unpackhi_pd(xy02, xy13)); +} + +inline v_int8x32 v_interleave_pairs(const v_int8x32& vec) +{ + return v_int8x32(_mm256_shuffle_epi8(vec.val, _mm256_set_epi64x(0x0f0d0e0c0b090a08, 0x0705060403010200, 0x0f0d0e0c0b090a08, 0x0705060403010200))); +} +inline v_uint8x32 v_interleave_pairs(const v_uint8x32& vec) { return v_reinterpret_as_u8(v_interleave_pairs(v_reinterpret_as_s8(vec))); } +inline v_int8x32 v_interleave_quads(const v_int8x32& vec) +{ + return v_int8x32(_mm256_shuffle_epi8(vec.val, _mm256_set_epi64x(0x0f0b0e0a0d090c08, 0x0703060205010400, 0x0f0b0e0a0d090c08, 0x0703060205010400))); +} +inline v_uint8x32 v_interleave_quads(const v_uint8x32& vec) { return v_reinterpret_as_u8(v_interleave_quads(v_reinterpret_as_s8(vec))); } + +inline v_int16x16 v_interleave_pairs(const v_int16x16& vec) +{ + return v_int16x16(_mm256_shuffle_epi8(vec.val, _mm256_set_epi64x(0x0f0e0b0a0d0c0908, 0x0706030205040100, 0x0f0e0b0a0d0c0908, 0x0706030205040100))); +} +inline v_uint16x16 v_interleave_pairs(const v_uint16x16& vec) { return v_reinterpret_as_u16(v_interleave_pairs(v_reinterpret_as_s16(vec))); } +inline v_int16x16 v_interleave_quads(const v_int16x16& vec) +{ + return v_int16x16(_mm256_shuffle_epi8(vec.val, _mm256_set_epi64x(0x0f0e07060d0c0504, 0x0b0a030209080100, 0x0f0e07060d0c0504, 0x0b0a030209080100))); +} +inline v_uint16x16 v_interleave_quads(const v_uint16x16& vec) { return v_reinterpret_as_u16(v_interleave_quads(v_reinterpret_as_s16(vec))); } + +inline v_int32x8 v_interleave_pairs(const v_int32x8& vec) +{ + return v_int32x8(_mm256_shuffle_epi32(vec.val, _MM_SHUFFLE(3, 1, 2, 0))); +} +inline v_uint32x8 v_interleave_pairs(const v_uint32x8& vec) { return v_reinterpret_as_u32(v_interleave_pairs(v_reinterpret_as_s32(vec))); } +inline v_float32x8 v_interleave_pairs(const v_float32x8& vec) { return v_reinterpret_as_f32(v_interleave_pairs(v_reinterpret_as_s32(vec))); } + +inline v_int8x32 v_pack_triplets(const v_int8x32& vec) +{ + return v_int8x32(_mm256_permutevar8x32_epi32(_mm256_shuffle_epi8(vec.val, _mm256_broadcastsi128_si256(_mm_set_epi64x(0xffffff0f0e0d0c0a, 0x0908060504020100))), + _mm256_set_epi64x(0x0000000700000007, 0x0000000600000005, 0x0000000400000002, 0x0000000100000000))); +} +inline v_uint8x32 v_pack_triplets(const v_uint8x32& vec) { return v_reinterpret_as_u8(v_pack_triplets(v_reinterpret_as_s8(vec))); } + +inline v_int16x16 v_pack_triplets(const v_int16x16& vec) +{ + return v_int16x16(_mm256_permutevar8x32_epi32(_mm256_shuffle_epi8(vec.val, _mm256_broadcastsi128_si256(_mm_set_epi64x(0xffff0f0e0d0c0b0a, 0x0908050403020100))), + _mm256_set_epi64x(0x0000000700000007, 0x0000000600000005, 0x0000000400000002, 0x0000000100000000))); +} +inline v_uint16x16 v_pack_triplets(const v_uint16x16& vec) { return v_reinterpret_as_u16(v_pack_triplets(v_reinterpret_as_s16(vec))); } + +inline v_int32x8 v_pack_triplets(const v_int32x8& vec) +{ + return v_int32x8(_mm256_permutevar8x32_epi32(vec.val, _mm256_set_epi64x(0x0000000700000007, 0x0000000600000005, 0x0000000400000002, 0x0000000100000000))); +} +inline v_uint32x8 v_pack_triplets(const v_uint32x8& vec) { return v_reinterpret_as_u32(v_pack_triplets(v_reinterpret_as_s32(vec))); } +inline v_float32x8 v_pack_triplets(const v_float32x8& vec) +{ + return v_float32x8(_mm256_permutevar8x32_ps(vec.val, _mm256_set_epi64x(0x0000000700000007, 0x0000000600000005, 0x0000000400000002, 0x0000000100000000))); +} + +////////// Matrix operations ///////// + +//////// Dot Product //////// + +// 16 >> 32 +inline v_int32x8 v_dotprod(const v_int16x16& a, const v_int16x16& b) +{ return v_int32x8(_mm256_madd_epi16(a.val, b.val)); } +inline v_int32x8 v_dotprod(const v_int16x16& a, const v_int16x16& b, const v_int32x8& c) +{ return v_dotprod(a, b) + c; } + +// 32 >> 64 +inline v_int64x4 v_dotprod(const v_int32x8& a, const v_int32x8& b) +{ + __m256i even = _mm256_mul_epi32(a.val, b.val); + __m256i odd = _mm256_mul_epi32(_mm256_srli_epi64(a.val, 32), _mm256_srli_epi64(b.val, 32)); + return v_int64x4(_mm256_add_epi64(even, odd)); +} +inline v_int64x4 v_dotprod(const v_int32x8& a, const v_int32x8& b, const v_int64x4& c) +{ return v_dotprod(a, b) + c; } + +// 8 >> 32 +inline v_uint32x8 v_dotprod_expand(const v_uint8x32& a, const v_uint8x32& b) +{ + __m256i even_m = _mm256_set1_epi32(0xFF00FF00); + __m256i even_a = _mm256_blendv_epi8(a.val, _mm256_setzero_si256(), even_m); + __m256i odd_a = _mm256_srli_epi16(a.val, 8); + + __m256i even_b = _mm256_blendv_epi8(b.val, _mm256_setzero_si256(), even_m); + __m256i odd_b = _mm256_srli_epi16(b.val, 8); + + __m256i prod0 = _mm256_madd_epi16(even_a, even_b); + __m256i prod1 = _mm256_madd_epi16(odd_a, odd_b); + return v_uint32x8(_mm256_add_epi32(prod0, prod1)); +} +inline v_uint32x8 v_dotprod_expand(const v_uint8x32& a, const v_uint8x32& b, const v_uint32x8& c) +{ return v_dotprod_expand(a, b) + c; } + +inline v_int32x8 v_dotprod_expand(const v_int8x32& a, const v_int8x32& b) +{ + __m256i even_a = _mm256_srai_epi16(_mm256_bslli_epi128(a.val, 1), 8); + __m256i odd_a = _mm256_srai_epi16(a.val, 8); + + __m256i even_b = _mm256_srai_epi16(_mm256_bslli_epi128(b.val, 1), 8); + __m256i odd_b = _mm256_srai_epi16(b.val, 8); + + __m256i prod0 = _mm256_madd_epi16(even_a, even_b); + __m256i prod1 = _mm256_madd_epi16(odd_a, odd_b); + return v_int32x8(_mm256_add_epi32(prod0, prod1)); +} +inline v_int32x8 v_dotprod_expand(const v_int8x32& a, const v_int8x32& b, const v_int32x8& c) +{ return v_dotprod_expand(a, b) + c; } + +// 16 >> 64 +inline v_uint64x4 v_dotprod_expand(const v_uint16x16& a, const v_uint16x16& b) +{ + __m256i mullo = _mm256_mullo_epi16(a.val, b.val); + __m256i mulhi = _mm256_mulhi_epu16(a.val, b.val); + __m256i mul0 = _mm256_unpacklo_epi16(mullo, mulhi); + __m256i mul1 = _mm256_unpackhi_epi16(mullo, mulhi); + + __m256i p02 = _mm256_blend_epi32(mul0, _mm256_setzero_si256(), 0xAA); + __m256i p13 = _mm256_srli_epi64(mul0, 32); + __m256i p46 = _mm256_blend_epi32(mul1, _mm256_setzero_si256(), 0xAA); + __m256i p57 = _mm256_srli_epi64(mul1, 32); + + __m256i p15_ = _mm256_add_epi64(p02, p13); + __m256i p9d_ = _mm256_add_epi64(p46, p57); + + return v_uint64x4(_mm256_add_epi64( + _mm256_unpacklo_epi64(p15_, p9d_), + _mm256_unpackhi_epi64(p15_, p9d_) + )); +} +inline v_uint64x4 v_dotprod_expand(const v_uint16x16& a, const v_uint16x16& b, const v_uint64x4& c) +{ return v_dotprod_expand(a, b) + c; } + +inline v_int64x4 v_dotprod_expand(const v_int16x16& a, const v_int16x16& b) +{ + __m256i prod = _mm256_madd_epi16(a.val, b.val); + __m256i sign = _mm256_srai_epi32(prod, 31); + + __m256i lo = _mm256_unpacklo_epi32(prod, sign); + __m256i hi = _mm256_unpackhi_epi32(prod, sign); + + return v_int64x4(_mm256_add_epi64( + _mm256_unpacklo_epi64(lo, hi), + _mm256_unpackhi_epi64(lo, hi) + )); +} +inline v_int64x4 v_dotprod_expand(const v_int16x16& a, const v_int16x16& b, const v_int64x4& c) +{ return v_dotprod_expand(a, b) + c; } + +// 32 >> 64f +inline v_float64x4 v_dotprod_expand(const v_int32x8& a, const v_int32x8& b) +{ return v_cvt_f64(v_dotprod(a, b)); } +inline v_float64x4 v_dotprod_expand(const v_int32x8& a, const v_int32x8& b, const v_float64x4& c) +{ return v_dotprod_expand(a, b) + c; } + +//////// Fast Dot Product //////// + +// 16 >> 32 +inline v_int32x8 v_dotprod_fast(const v_int16x16& a, const v_int16x16& b) +{ return v_dotprod(a, b); } +inline v_int32x8 v_dotprod_fast(const v_int16x16& a, const v_int16x16& b, const v_int32x8& c) +{ return v_dotprod(a, b, c); } + +// 32 >> 64 +inline v_int64x4 v_dotprod_fast(const v_int32x8& a, const v_int32x8& b) +{ return v_dotprod(a, b); } +inline v_int64x4 v_dotprod_fast(const v_int32x8& a, const v_int32x8& b, const v_int64x4& c) +{ return v_dotprod(a, b, c); } + +// 8 >> 32 +inline v_uint32x8 v_dotprod_expand_fast(const v_uint8x32& a, const v_uint8x32& b) +{ return v_dotprod_expand(a, b); } +inline v_uint32x8 v_dotprod_expand_fast(const v_uint8x32& a, const v_uint8x32& b, const v_uint32x8& c) +{ return v_dotprod_expand(a, b, c); } + +inline v_int32x8 v_dotprod_expand_fast(const v_int8x32& a, const v_int8x32& b) +{ return v_dotprod_expand(a, b); } +inline v_int32x8 v_dotprod_expand_fast(const v_int8x32& a, const v_int8x32& b, const v_int32x8& c) +{ return v_dotprod_expand(a, b, c); } + +// 16 >> 64 +inline v_uint64x4 v_dotprod_expand_fast(const v_uint16x16& a, const v_uint16x16& b) +{ + __m256i mullo = _mm256_mullo_epi16(a.val, b.val); + __m256i mulhi = _mm256_mulhi_epu16(a.val, b.val); + __m256i mul0 = _mm256_unpacklo_epi16(mullo, mulhi); + __m256i mul1 = _mm256_unpackhi_epi16(mullo, mulhi); + + __m256i p02 = _mm256_blend_epi32(mul0, _mm256_setzero_si256(), 0xAA); + __m256i p13 = _mm256_srli_epi64(mul0, 32); + __m256i p46 = _mm256_blend_epi32(mul1, _mm256_setzero_si256(), 0xAA); + __m256i p57 = _mm256_srli_epi64(mul1, 32); + + __m256i p15_ = _mm256_add_epi64(p02, p13); + __m256i p9d_ = _mm256_add_epi64(p46, p57); + + return v_uint64x4(_mm256_add_epi64(p15_, p9d_)); +} +inline v_uint64x4 v_dotprod_expand_fast(const v_uint16x16& a, const v_uint16x16& b, const v_uint64x4& c) +{ return v_dotprod_expand_fast(a, b) + c; } + +inline v_int64x4 v_dotprod_expand_fast(const v_int16x16& a, const v_int16x16& b) +{ + __m256i prod = _mm256_madd_epi16(a.val, b.val); + __m256i sign = _mm256_srai_epi32(prod, 31); + __m256i lo = _mm256_unpacklo_epi32(prod, sign); + __m256i hi = _mm256_unpackhi_epi32(prod, sign); + return v_int64x4(_mm256_add_epi64(lo, hi)); +} +inline v_int64x4 v_dotprod_expand_fast(const v_int16x16& a, const v_int16x16& b, const v_int64x4& c) +{ return v_dotprod_expand_fast(a, b) + c; } + +// 32 >> 64f +inline v_float64x4 v_dotprod_expand_fast(const v_int32x8& a, const v_int32x8& b) +{ return v_dotprod_expand(a, b); } +inline v_float64x4 v_dotprod_expand_fast(const v_int32x8& a, const v_int32x8& b, const v_float64x4& c) +{ return v_dotprod_expand(a, b, c); } + +#define OPENCV_HAL_AVX_SPLAT2_PS(a, im) \ + v_float32x8(_mm256_permute_ps(a.val, _MM_SHUFFLE(im, im, im, im))) + +inline v_float32x8 v_matmul(const v_float32x8& v, const v_float32x8& m0, + const v_float32x8& m1, const v_float32x8& m2, + const v_float32x8& m3) +{ + v_float32x8 v04 = OPENCV_HAL_AVX_SPLAT2_PS(v, 0); + v_float32x8 v15 = OPENCV_HAL_AVX_SPLAT2_PS(v, 1); + v_float32x8 v26 = OPENCV_HAL_AVX_SPLAT2_PS(v, 2); + v_float32x8 v37 = OPENCV_HAL_AVX_SPLAT2_PS(v, 3); + return v_fma(v04, m0, v_fma(v15, m1, v_fma(v26, m2, v37 * m3))); +} + +inline v_float32x8 v_matmuladd(const v_float32x8& v, const v_float32x8& m0, + const v_float32x8& m1, const v_float32x8& m2, + const v_float32x8& a) +{ + v_float32x8 v04 = OPENCV_HAL_AVX_SPLAT2_PS(v, 0); + v_float32x8 v15 = OPENCV_HAL_AVX_SPLAT2_PS(v, 1); + v_float32x8 v26 = OPENCV_HAL_AVX_SPLAT2_PS(v, 2); + return v_fma(v04, m0, v_fma(v15, m1, v_fma(v26, m2, a))); +} + +#define OPENCV_HAL_IMPL_AVX_TRANSPOSE4x4(_Tpvec, suffix, cast_from, cast_to) \ + inline void v_transpose4x4(const _Tpvec& a0, const _Tpvec& a1, \ + const _Tpvec& a2, const _Tpvec& a3, \ + _Tpvec& b0, _Tpvec& b1, _Tpvec& b2, _Tpvec& b3) \ + { \ + __m256i t0 = cast_from(_mm256_unpacklo_##suffix(a0.val, a1.val)); \ + __m256i t1 = cast_from(_mm256_unpacklo_##suffix(a2.val, a3.val)); \ + __m256i t2 = cast_from(_mm256_unpackhi_##suffix(a0.val, a1.val)); \ + __m256i t3 = cast_from(_mm256_unpackhi_##suffix(a2.val, a3.val)); \ + b0.val = cast_to(_mm256_unpacklo_epi64(t0, t1)); \ + b1.val = cast_to(_mm256_unpackhi_epi64(t0, t1)); \ + b2.val = cast_to(_mm256_unpacklo_epi64(t2, t3)); \ + b3.val = cast_to(_mm256_unpackhi_epi64(t2, t3)); \ + } + +OPENCV_HAL_IMPL_AVX_TRANSPOSE4x4(v_uint32x8, epi32, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_AVX_TRANSPOSE4x4(v_int32x8, epi32, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_AVX_TRANSPOSE4x4(v_float32x8, ps, _mm256_castps_si256, _mm256_castsi256_ps) + +//////////////// Value reordering /////////////// + +/* Expand */ +#define OPENCV_HAL_IMPL_AVX_EXPAND(_Tpvec, _Tpwvec, _Tp, intrin) \ + inline void v_expand(const _Tpvec& a, _Tpwvec& b0, _Tpwvec& b1) \ + { \ + b0.val = intrin(_v256_extract_low(a.val)); \ + b1.val = intrin(_v256_extract_high(a.val)); \ + } \ + inline _Tpwvec v_expand_low(const _Tpvec& a) \ + { return _Tpwvec(intrin(_v256_extract_low(a.val))); } \ + inline _Tpwvec v_expand_high(const _Tpvec& a) \ + { return _Tpwvec(intrin(_v256_extract_high(a.val))); } \ + inline _Tpwvec v256_load_expand(const _Tp* ptr) \ + { \ + __m128i a = _mm_loadu_si128((const __m128i*)ptr); \ + return _Tpwvec(intrin(a)); \ + } + +OPENCV_HAL_IMPL_AVX_EXPAND(v_uint8x32, v_uint16x16, uchar, _mm256_cvtepu8_epi16) +OPENCV_HAL_IMPL_AVX_EXPAND(v_int8x32, v_int16x16, schar, _mm256_cvtepi8_epi16) +OPENCV_HAL_IMPL_AVX_EXPAND(v_uint16x16, v_uint32x8, ushort, _mm256_cvtepu16_epi32) +OPENCV_HAL_IMPL_AVX_EXPAND(v_int16x16, v_int32x8, short, _mm256_cvtepi16_epi32) +OPENCV_HAL_IMPL_AVX_EXPAND(v_uint32x8, v_uint64x4, unsigned, _mm256_cvtepu32_epi64) +OPENCV_HAL_IMPL_AVX_EXPAND(v_int32x8, v_int64x4, int, _mm256_cvtepi32_epi64) + +#define OPENCV_HAL_IMPL_AVX_EXPAND_Q(_Tpvec, _Tp, intrin) \ + inline _Tpvec v256_load_expand_q(const _Tp* ptr) \ + { \ + __m128i a = _mm_loadl_epi64((const __m128i*)ptr); \ + return _Tpvec(intrin(a)); \ + } + +OPENCV_HAL_IMPL_AVX_EXPAND_Q(v_uint32x8, uchar, _mm256_cvtepu8_epi32) +OPENCV_HAL_IMPL_AVX_EXPAND_Q(v_int32x8, schar, _mm256_cvtepi8_epi32) + +/* pack */ +// 16 +inline v_int8x32 v_pack(const v_int16x16& a, const v_int16x16& b) +{ return v_int8x32(_v256_shuffle_odd_64(_mm256_packs_epi16(a.val, b.val))); } + +inline v_uint8x32 v_pack(const v_uint16x16& a, const v_uint16x16& b) +{ + __m256i t = _mm256_set1_epi16(255); + __m256i a1 = _mm256_min_epu16(a.val, t); + __m256i b1 = _mm256_min_epu16(b.val, t); + return v_uint8x32(_v256_shuffle_odd_64(_mm256_packus_epi16(a1, b1))); +} + +inline v_uint8x32 v_pack_u(const v_int16x16& a, const v_int16x16& b) +{ + return v_uint8x32(_v256_shuffle_odd_64(_mm256_packus_epi16(a.val, b.val))); +} + +inline void v_pack_store(schar* ptr, const v_int16x16& a) +{ v_store_low(ptr, v_pack(a, a)); } + +inline void v_pack_store(uchar* ptr, const v_uint16x16& a) +{ + const __m256i m = _mm256_set1_epi16(255); + __m256i am = _mm256_min_epu16(a.val, m); + am = _v256_shuffle_odd_64(_mm256_packus_epi16(am, am)); + v_store_low(ptr, v_uint8x32(am)); +} + +inline void v_pack_u_store(uchar* ptr, const v_int16x16& a) +{ v_store_low(ptr, v_pack_u(a, a)); } + +template inline +v_uint8x32 v_rshr_pack(const v_uint16x16& a, const v_uint16x16& b) +{ + // we assume that n > 0, and so the shifted 16-bit values can be treated as signed numbers. + v_uint16x16 delta = v256_setall_u16((short)(1 << (n-1))); + return v_pack_u(v_reinterpret_as_s16((a + delta) >> n), + v_reinterpret_as_s16((b + delta) >> n)); +} + +template inline +void v_rshr_pack_store(uchar* ptr, const v_uint16x16& a) +{ + v_uint16x16 delta = v256_setall_u16((short)(1 << (n-1))); + v_pack_u_store(ptr, v_reinterpret_as_s16((a + delta) >> n)); +} + +template inline +v_uint8x32 v_rshr_pack_u(const v_int16x16& a, const v_int16x16& b) +{ + v_int16x16 delta = v256_setall_s16((short)(1 << (n-1))); + return v_pack_u((a + delta) >> n, (b + delta) >> n); +} + +template inline +void v_rshr_pack_u_store(uchar* ptr, const v_int16x16& a) +{ + v_int16x16 delta = v256_setall_s16((short)(1 << (n-1))); + v_pack_u_store(ptr, (a + delta) >> n); +} + +template inline +v_int8x32 v_rshr_pack(const v_int16x16& a, const v_int16x16& b) +{ + v_int16x16 delta = v256_setall_s16((short)(1 << (n-1))); + return v_pack((a + delta) >> n, (b + delta) >> n); +} + +template inline +void v_rshr_pack_store(schar* ptr, const v_int16x16& a) +{ + v_int16x16 delta = v256_setall_s16((short)(1 << (n-1))); + v_pack_store(ptr, (a + delta) >> n); +} + +// 32 +inline v_int16x16 v_pack(const v_int32x8& a, const v_int32x8& b) +{ return v_int16x16(_v256_shuffle_odd_64(_mm256_packs_epi32(a.val, b.val))); } + +inline v_uint16x16 v_pack(const v_uint32x8& a, const v_uint32x8& b) +{ return v_uint16x16(_v256_shuffle_odd_64(_v256_packs_epu32(a.val, b.val))); } + +inline v_uint16x16 v_pack_u(const v_int32x8& a, const v_int32x8& b) +{ return v_uint16x16(_v256_shuffle_odd_64(_mm256_packus_epi32(a.val, b.val))); } + +inline void v_pack_store(short* ptr, const v_int32x8& a) +{ v_store_low(ptr, v_pack(a, a)); } + +inline void v_pack_store(ushort* ptr, const v_uint32x8& a) +{ + const __m256i m = _mm256_set1_epi32(65535); + __m256i am = _mm256_min_epu32(a.val, m); + am = _v256_shuffle_odd_64(_mm256_packus_epi32(am, am)); + v_store_low(ptr, v_uint16x16(am)); +} + +inline void v_pack_u_store(ushort* ptr, const v_int32x8& a) +{ v_store_low(ptr, v_pack_u(a, a)); } + + +template inline +v_uint16x16 v_rshr_pack(const v_uint32x8& a, const v_uint32x8& b) +{ + // we assume that n > 0, and so the shifted 32-bit values can be treated as signed numbers. + v_uint32x8 delta = v256_setall_u32(1 << (n-1)); + return v_pack_u(v_reinterpret_as_s32((a + delta) >> n), + v_reinterpret_as_s32((b + delta) >> n)); +} + +template inline +void v_rshr_pack_store(ushort* ptr, const v_uint32x8& a) +{ + v_uint32x8 delta = v256_setall_u32(1 << (n-1)); + v_pack_u_store(ptr, v_reinterpret_as_s32((a + delta) >> n)); +} + +template inline +v_uint16x16 v_rshr_pack_u(const v_int32x8& a, const v_int32x8& b) +{ + v_int32x8 delta = v256_setall_s32(1 << (n-1)); + return v_pack_u((a + delta) >> n, (b + delta) >> n); +} + +template inline +void v_rshr_pack_u_store(ushort* ptr, const v_int32x8& a) +{ + v_int32x8 delta = v256_setall_s32(1 << (n-1)); + v_pack_u_store(ptr, (a + delta) >> n); +} + +template inline +v_int16x16 v_rshr_pack(const v_int32x8& a, const v_int32x8& b) +{ + v_int32x8 delta = v256_setall_s32(1 << (n-1)); + return v_pack((a + delta) >> n, (b + delta) >> n); +} + +template inline +void v_rshr_pack_store(short* ptr, const v_int32x8& a) +{ + v_int32x8 delta = v256_setall_s32(1 << (n-1)); + v_pack_store(ptr, (a + delta) >> n); +} + +// 64 +// Non-saturating pack +inline v_uint32x8 v_pack(const v_uint64x4& a, const v_uint64x4& b) +{ + __m256i a0 = _mm256_shuffle_epi32(a.val, _MM_SHUFFLE(0, 0, 2, 0)); + __m256i b0 = _mm256_shuffle_epi32(b.val, _MM_SHUFFLE(0, 0, 2, 0)); + __m256i ab = _mm256_unpacklo_epi64(a0, b0); // a0, a1, b0, b1, a2, a3, b2, b3 + return v_uint32x8(_v256_shuffle_odd_64(ab)); +} + +inline v_int32x8 v_pack(const v_int64x4& a, const v_int64x4& b) +{ return v_reinterpret_as_s32(v_pack(v_reinterpret_as_u64(a), v_reinterpret_as_u64(b))); } + +inline void v_pack_store(unsigned* ptr, const v_uint64x4& a) +{ + __m256i a0 = _mm256_shuffle_epi32(a.val, _MM_SHUFFLE(0, 0, 2, 0)); + v_store_low(ptr, v_uint32x8(_v256_shuffle_odd_64(a0))); +} + +inline void v_pack_store(int* ptr, const v_int64x4& b) +{ v_pack_store((unsigned*)ptr, v_reinterpret_as_u64(b)); } + +template inline +v_uint32x8 v_rshr_pack(const v_uint64x4& a, const v_uint64x4& b) +{ + v_uint64x4 delta = v256_setall_u64((uint64)1 << (n-1)); + return v_pack((a + delta) >> n, (b + delta) >> n); +} + +template inline +void v_rshr_pack_store(unsigned* ptr, const v_uint64x4& a) +{ + v_uint64x4 delta = v256_setall_u64((uint64)1 << (n-1)); + v_pack_store(ptr, (a + delta) >> n); +} + +template inline +v_int32x8 v_rshr_pack(const v_int64x4& a, const v_int64x4& b) +{ + v_int64x4 delta = v256_setall_s64((int64)1 << (n-1)); + return v_pack((a + delta) >> n, (b + delta) >> n); +} + +template inline +void v_rshr_pack_store(int* ptr, const v_int64x4& a) +{ + v_int64x4 delta = v256_setall_s64((int64)1 << (n-1)); + v_pack_store(ptr, (a + delta) >> n); +} + +// pack boolean +inline v_uint8x32 v_pack_b(const v_uint16x16& a, const v_uint16x16& b) +{ + __m256i ab = _mm256_packs_epi16(a.val, b.val); + return v_uint8x32(_v256_shuffle_odd_64(ab)); +} + +inline v_uint8x32 v_pack_b(const v_uint32x8& a, const v_uint32x8& b, + const v_uint32x8& c, const v_uint32x8& d) +{ + __m256i ab = _mm256_packs_epi32(a.val, b.val); + __m256i cd = _mm256_packs_epi32(c.val, d.val); + + __m256i abcd = _v256_shuffle_odd_64(_mm256_packs_epi16(ab, cd)); + return v_uint8x32(_mm256_shuffle_epi32(abcd, _MM_SHUFFLE(3, 1, 2, 0))); +} + +inline v_uint8x32 v_pack_b(const v_uint64x4& a, const v_uint64x4& b, const v_uint64x4& c, + const v_uint64x4& d, const v_uint64x4& e, const v_uint64x4& f, + const v_uint64x4& g, const v_uint64x4& h) +{ + __m256i ab = _mm256_packs_epi32(a.val, b.val); + __m256i cd = _mm256_packs_epi32(c.val, d.val); + __m256i ef = _mm256_packs_epi32(e.val, f.val); + __m256i gh = _mm256_packs_epi32(g.val, h.val); + + __m256i abcd = _mm256_packs_epi32(ab, cd); + __m256i efgh = _mm256_packs_epi32(ef, gh); + __m256i pkall = _v256_shuffle_odd_64(_mm256_packs_epi16(abcd, efgh)); + + __m256i rev = _mm256_alignr_epi8(pkall, pkall, 8); + return v_uint8x32(_mm256_unpacklo_epi16(pkall, rev)); +} + +/* Recombine */ +// its up there with load and store operations + +/* Extract */ +#define OPENCV_HAL_IMPL_AVX_EXTRACT(_Tpvec) \ + template \ + inline _Tpvec v_extract(const _Tpvec& a, const _Tpvec& b) \ + { return v_rotate_right(a, b); } + +OPENCV_HAL_IMPL_AVX_EXTRACT(v_uint8x32) +OPENCV_HAL_IMPL_AVX_EXTRACT(v_int8x32) +OPENCV_HAL_IMPL_AVX_EXTRACT(v_uint16x16) +OPENCV_HAL_IMPL_AVX_EXTRACT(v_int16x16) +OPENCV_HAL_IMPL_AVX_EXTRACT(v_uint32x8) +OPENCV_HAL_IMPL_AVX_EXTRACT(v_int32x8) +OPENCV_HAL_IMPL_AVX_EXTRACT(v_uint64x4) +OPENCV_HAL_IMPL_AVX_EXTRACT(v_int64x4) +OPENCV_HAL_IMPL_AVX_EXTRACT(v_float32x8) +OPENCV_HAL_IMPL_AVX_EXTRACT(v_float64x4) + +template +inline uchar v_extract_n(v_uint8x32 a) +{ + return (uchar)_v256_extract_epi8(a.val); +} + +template +inline schar v_extract_n(v_int8x32 a) +{ + return (schar)v_extract_n(v_reinterpret_as_u8(a)); +} + +template +inline ushort v_extract_n(v_uint16x16 a) +{ + return (ushort)_v256_extract_epi16(a.val); +} + +template +inline short v_extract_n(v_int16x16 a) +{ + return (short)v_extract_n(v_reinterpret_as_u16(a)); +} + +template +inline uint v_extract_n(v_uint32x8 a) +{ + return (uint)_v256_extract_epi32(a.val); +} + +template +inline int v_extract_n(v_int32x8 a) +{ + return (int)v_extract_n(v_reinterpret_as_u32(a)); +} + +template +inline uint64 v_extract_n(v_uint64x4 a) +{ + return (uint64)_v256_extract_epi64(a.val); +} + +template +inline int64 v_extract_n(v_int64x4 v) +{ + return (int64)v_extract_n(v_reinterpret_as_u64(v)); +} + +template +inline float v_extract_n(v_float32x8 v) +{ + union { uint iv; float fv; } d; + d.iv = v_extract_n(v_reinterpret_as_u32(v)); + return d.fv; +} + +template +inline double v_extract_n(v_float64x4 v) +{ + union { uint64 iv; double dv; } d; + d.iv = v_extract_n(v_reinterpret_as_u64(v)); + return d.dv; +} + +template +inline v_uint32x8 v_broadcast_element(v_uint32x8 a) +{ + static const __m256i perm = _mm256_set1_epi32((char)i); + return v_uint32x8(_mm256_permutevar8x32_epi32(a.val, perm)); +} + +template +inline v_int32x8 v_broadcast_element(const v_int32x8 &a) +{ return v_reinterpret_as_s32(v_broadcast_element(v_reinterpret_as_u32(a))); } + +template +inline v_float32x8 v_broadcast_element(const v_float32x8 &a) +{ return v_reinterpret_as_f32(v_broadcast_element(v_reinterpret_as_u32(a))); } + + +///////////////////// load deinterleave ///////////////////////////// + +inline void v_load_deinterleave( const uchar* ptr, v_uint8x32& a, v_uint8x32& b ) +{ + __m256i ab0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i ab1 = _mm256_loadu_si256((const __m256i*)(ptr + 32)); + + const __m256i sh = _mm256_setr_epi8(0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11, 13, 15, + 0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11, 13, 15); + __m256i p0 = _mm256_shuffle_epi8(ab0, sh); + __m256i p1 = _mm256_shuffle_epi8(ab1, sh); + __m256i pl = _mm256_permute2x128_si256(p0, p1, 0 + 2*16); + __m256i ph = _mm256_permute2x128_si256(p0, p1, 1 + 3*16); + __m256i a0 = _mm256_unpacklo_epi64(pl, ph); + __m256i b0 = _mm256_unpackhi_epi64(pl, ph); + a = v_uint8x32(a0); + b = v_uint8x32(b0); +} + +inline void v_load_deinterleave( const ushort* ptr, v_uint16x16& a, v_uint16x16& b ) +{ + __m256i ab0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i ab1 = _mm256_loadu_si256((const __m256i*)(ptr + 16)); + + const __m256i sh = _mm256_setr_epi8(0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15, + 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15); + __m256i p0 = _mm256_shuffle_epi8(ab0, sh); + __m256i p1 = _mm256_shuffle_epi8(ab1, sh); + __m256i pl = _mm256_permute2x128_si256(p0, p1, 0 + 2*16); + __m256i ph = _mm256_permute2x128_si256(p0, p1, 1 + 3*16); + __m256i a0 = _mm256_unpacklo_epi64(pl, ph); + __m256i b0 = _mm256_unpackhi_epi64(pl, ph); + a = v_uint16x16(a0); + b = v_uint16x16(b0); +} + +inline void v_load_deinterleave( const unsigned* ptr, v_uint32x8& a, v_uint32x8& b ) +{ + __m256i ab0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i ab1 = _mm256_loadu_si256((const __m256i*)(ptr + 8)); + + enum { sh = 0+2*4+1*16+3*64 }; + __m256i p0 = _mm256_shuffle_epi32(ab0, sh); + __m256i p1 = _mm256_shuffle_epi32(ab1, sh); + __m256i pl = _mm256_permute2x128_si256(p0, p1, 0 + 2*16); + __m256i ph = _mm256_permute2x128_si256(p0, p1, 1 + 3*16); + __m256i a0 = _mm256_unpacklo_epi64(pl, ph); + __m256i b0 = _mm256_unpackhi_epi64(pl, ph); + a = v_uint32x8(a0); + b = v_uint32x8(b0); +} + +inline void v_load_deinterleave( const uint64* ptr, v_uint64x4& a, v_uint64x4& b ) +{ + __m256i ab0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i ab1 = _mm256_loadu_si256((const __m256i*)(ptr + 4)); + + __m256i pl = _mm256_permute2x128_si256(ab0, ab1, 0 + 2*16); + __m256i ph = _mm256_permute2x128_si256(ab0, ab1, 1 + 3*16); + __m256i a0 = _mm256_unpacklo_epi64(pl, ph); + __m256i b0 = _mm256_unpackhi_epi64(pl, ph); + a = v_uint64x4(a0); + b = v_uint64x4(b0); +} + +inline void v_load_deinterleave( const uchar* ptr, v_uint8x32& a, v_uint8x32& b, v_uint8x32& c ) +{ + __m256i bgr0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i bgr1 = _mm256_loadu_si256((const __m256i*)(ptr + 32)); + __m256i bgr2 = _mm256_loadu_si256((const __m256i*)(ptr + 64)); + + __m256i s02_low = _mm256_permute2x128_si256(bgr0, bgr2, 0 + 2*16); + __m256i s02_high = _mm256_permute2x128_si256(bgr0, bgr2, 1 + 3*16); + + const __m256i m0 = _mm256_setr_epi8(0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, + 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0); + const __m256i m1 = _mm256_setr_epi8(0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, + -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1); + + __m256i b0 = _mm256_blendv_epi8(_mm256_blendv_epi8(s02_low, s02_high, m0), bgr1, m1); + __m256i g0 = _mm256_blendv_epi8(_mm256_blendv_epi8(s02_high, s02_low, m1), bgr1, m0); + __m256i r0 = _mm256_blendv_epi8(_mm256_blendv_epi8(bgr1, s02_low, m0), s02_high, m1); + + const __m256i + sh_b = _mm256_setr_epi8(0, 3, 6, 9, 12, 15, 2, 5, 8, 11, 14, 1, 4, 7, 10, 13, + 0, 3, 6, 9, 12, 15, 2, 5, 8, 11, 14, 1, 4, 7, 10, 13), + sh_g = _mm256_setr_epi8(1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, 5, 8, 11, 14, + 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, 5, 8, 11, 14), + sh_r = _mm256_setr_epi8(2, 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, + 2, 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15); + b0 = _mm256_shuffle_epi8(b0, sh_b); + g0 = _mm256_shuffle_epi8(g0, sh_g); + r0 = _mm256_shuffle_epi8(r0, sh_r); + + a = v_uint8x32(b0); + b = v_uint8x32(g0); + c = v_uint8x32(r0); +} + +inline void v_load_deinterleave( const ushort* ptr, v_uint16x16& a, v_uint16x16& b, v_uint16x16& c ) +{ + __m256i bgr0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i bgr1 = _mm256_loadu_si256((const __m256i*)(ptr + 16)); + __m256i bgr2 = _mm256_loadu_si256((const __m256i*)(ptr + 32)); + + __m256i s02_low = _mm256_permute2x128_si256(bgr0, bgr2, 0 + 2*16); + __m256i s02_high = _mm256_permute2x128_si256(bgr0, bgr2, 1 + 3*16); + + const __m256i m0 = _mm256_setr_epi8(0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, + 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0); + const __m256i m1 = _mm256_setr_epi8(0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, + -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0); + __m256i b0 = _mm256_blendv_epi8(_mm256_blendv_epi8(s02_low, s02_high, m0), bgr1, m1); + __m256i g0 = _mm256_blendv_epi8(_mm256_blendv_epi8(bgr1, s02_low, m0), s02_high, m1); + __m256i r0 = _mm256_blendv_epi8(_mm256_blendv_epi8(s02_high, s02_low, m1), bgr1, m0); + const __m256i sh_b = _mm256_setr_epi8(0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5, 10, 11, + 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5, 10, 11); + const __m256i sh_g = _mm256_setr_epi8(2, 3, 8, 9, 14, 15, 4, 5, 10, 11, 0, 1, 6, 7, 12, 13, + 2, 3, 8, 9, 14, 15, 4, 5, 10, 11, 0, 1, 6, 7, 12, 13); + const __m256i sh_r = _mm256_setr_epi8(4, 5, 10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, + 4, 5, 10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15); + b0 = _mm256_shuffle_epi8(b0, sh_b); + g0 = _mm256_shuffle_epi8(g0, sh_g); + r0 = _mm256_shuffle_epi8(r0, sh_r); + + a = v_uint16x16(b0); + b = v_uint16x16(g0); + c = v_uint16x16(r0); +} + +inline void v_load_deinterleave( const unsigned* ptr, v_uint32x8& a, v_uint32x8& b, v_uint32x8& c ) +{ + __m256i bgr0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i bgr1 = _mm256_loadu_si256((const __m256i*)(ptr + 8)); + __m256i bgr2 = _mm256_loadu_si256((const __m256i*)(ptr + 16)); + + __m256i s02_low = _mm256_permute2x128_si256(bgr0, bgr2, 0 + 2*16); + __m256i s02_high = _mm256_permute2x128_si256(bgr0, bgr2, 1 + 3*16); + + __m256i b0 = _mm256_blend_epi32(_mm256_blend_epi32(s02_low, s02_high, 0x24), bgr1, 0x92); + __m256i g0 = _mm256_blend_epi32(_mm256_blend_epi32(s02_high, s02_low, 0x92), bgr1, 0x24); + __m256i r0 = _mm256_blend_epi32(_mm256_blend_epi32(bgr1, s02_low, 0x24), s02_high, 0x92); + + b0 = _mm256_shuffle_epi32(b0, 0x6c); + g0 = _mm256_shuffle_epi32(g0, 0xb1); + r0 = _mm256_shuffle_epi32(r0, 0xc6); + + a = v_uint32x8(b0); + b = v_uint32x8(g0); + c = v_uint32x8(r0); +} + +inline void v_load_deinterleave( const uint64* ptr, v_uint64x4& a, v_uint64x4& b, v_uint64x4& c ) +{ + __m256i bgr0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i bgr1 = _mm256_loadu_si256((const __m256i*)(ptr + 4)); + __m256i bgr2 = _mm256_loadu_si256((const __m256i*)(ptr + 8)); + + __m256i s01 = _mm256_blend_epi32(bgr0, bgr1, 0xf0); + __m256i s12 = _mm256_blend_epi32(bgr1, bgr2, 0xf0); + __m256i s20r = _mm256_permute4x64_epi64(_mm256_blend_epi32(bgr2, bgr0, 0xf0), 0x1b); + __m256i b0 = _mm256_unpacklo_epi64(s01, s20r); + __m256i g0 = _mm256_alignr_epi8(s12, s01, 8); + __m256i r0 = _mm256_unpackhi_epi64(s20r, s12); + + a = v_uint64x4(b0); + b = v_uint64x4(g0); + c = v_uint64x4(r0); +} + +inline void v_load_deinterleave( const uchar* ptr, v_uint8x32& a, v_uint8x32& b, v_uint8x32& c, v_uint8x32& d ) +{ + __m256i bgr0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i bgr1 = _mm256_loadu_si256((const __m256i*)(ptr + 32)); + __m256i bgr2 = _mm256_loadu_si256((const __m256i*)(ptr + 64)); + __m256i bgr3 = _mm256_loadu_si256((const __m256i*)(ptr + 96)); + const __m256i sh = _mm256_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, + 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15); + + __m256i p0 = _mm256_shuffle_epi8(bgr0, sh); + __m256i p1 = _mm256_shuffle_epi8(bgr1, sh); + __m256i p2 = _mm256_shuffle_epi8(bgr2, sh); + __m256i p3 = _mm256_shuffle_epi8(bgr3, sh); + + __m256i p01l = _mm256_unpacklo_epi32(p0, p1); + __m256i p01h = _mm256_unpackhi_epi32(p0, p1); + __m256i p23l = _mm256_unpacklo_epi32(p2, p3); + __m256i p23h = _mm256_unpackhi_epi32(p2, p3); + + __m256i pll = _mm256_permute2x128_si256(p01l, p23l, 0 + 2*16); + __m256i plh = _mm256_permute2x128_si256(p01l, p23l, 1 + 3*16); + __m256i phl = _mm256_permute2x128_si256(p01h, p23h, 0 + 2*16); + __m256i phh = _mm256_permute2x128_si256(p01h, p23h, 1 + 3*16); + + __m256i b0 = _mm256_unpacklo_epi32(pll, plh); + __m256i g0 = _mm256_unpackhi_epi32(pll, plh); + __m256i r0 = _mm256_unpacklo_epi32(phl, phh); + __m256i a0 = _mm256_unpackhi_epi32(phl, phh); + + a = v_uint8x32(b0); + b = v_uint8x32(g0); + c = v_uint8x32(r0); + d = v_uint8x32(a0); +} + +inline void v_load_deinterleave( const ushort* ptr, v_uint16x16& a, v_uint16x16& b, v_uint16x16& c, v_uint16x16& d ) +{ + __m256i bgr0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i bgr1 = _mm256_loadu_si256((const __m256i*)(ptr + 16)); + __m256i bgr2 = _mm256_loadu_si256((const __m256i*)(ptr + 32)); + __m256i bgr3 = _mm256_loadu_si256((const __m256i*)(ptr + 48)); + const __m256i sh = _mm256_setr_epi8(0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15, + 0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15); + __m256i p0 = _mm256_shuffle_epi8(bgr0, sh); + __m256i p1 = _mm256_shuffle_epi8(bgr1, sh); + __m256i p2 = _mm256_shuffle_epi8(bgr2, sh); + __m256i p3 = _mm256_shuffle_epi8(bgr3, sh); + + __m256i p01l = _mm256_unpacklo_epi32(p0, p1); + __m256i p01h = _mm256_unpackhi_epi32(p0, p1); + __m256i p23l = _mm256_unpacklo_epi32(p2, p3); + __m256i p23h = _mm256_unpackhi_epi32(p2, p3); + + __m256i pll = _mm256_permute2x128_si256(p01l, p23l, 0 + 2*16); + __m256i plh = _mm256_permute2x128_si256(p01l, p23l, 1 + 3*16); + __m256i phl = _mm256_permute2x128_si256(p01h, p23h, 0 + 2*16); + __m256i phh = _mm256_permute2x128_si256(p01h, p23h, 1 + 3*16); + + __m256i b0 = _mm256_unpacklo_epi32(pll, plh); + __m256i g0 = _mm256_unpackhi_epi32(pll, plh); + __m256i r0 = _mm256_unpacklo_epi32(phl, phh); + __m256i a0 = _mm256_unpackhi_epi32(phl, phh); + + a = v_uint16x16(b0); + b = v_uint16x16(g0); + c = v_uint16x16(r0); + d = v_uint16x16(a0); +} + +inline void v_load_deinterleave( const unsigned* ptr, v_uint32x8& a, v_uint32x8& b, v_uint32x8& c, v_uint32x8& d ) +{ + __m256i p0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i p1 = _mm256_loadu_si256((const __m256i*)(ptr + 8)); + __m256i p2 = _mm256_loadu_si256((const __m256i*)(ptr + 16)); + __m256i p3 = _mm256_loadu_si256((const __m256i*)(ptr + 24)); + + __m256i p01l = _mm256_unpacklo_epi32(p0, p1); + __m256i p01h = _mm256_unpackhi_epi32(p0, p1); + __m256i p23l = _mm256_unpacklo_epi32(p2, p3); + __m256i p23h = _mm256_unpackhi_epi32(p2, p3); + + __m256i pll = _mm256_permute2x128_si256(p01l, p23l, 0 + 2*16); + __m256i plh = _mm256_permute2x128_si256(p01l, p23l, 1 + 3*16); + __m256i phl = _mm256_permute2x128_si256(p01h, p23h, 0 + 2*16); + __m256i phh = _mm256_permute2x128_si256(p01h, p23h, 1 + 3*16); + + __m256i b0 = _mm256_unpacklo_epi32(pll, plh); + __m256i g0 = _mm256_unpackhi_epi32(pll, plh); + __m256i r0 = _mm256_unpacklo_epi32(phl, phh); + __m256i a0 = _mm256_unpackhi_epi32(phl, phh); + + a = v_uint32x8(b0); + b = v_uint32x8(g0); + c = v_uint32x8(r0); + d = v_uint32x8(a0); +} + +inline void v_load_deinterleave( const uint64* ptr, v_uint64x4& a, v_uint64x4& b, v_uint64x4& c, v_uint64x4& d ) +{ + __m256i bgra0 = _mm256_loadu_si256((const __m256i*)ptr); + __m256i bgra1 = _mm256_loadu_si256((const __m256i*)(ptr + 4)); + __m256i bgra2 = _mm256_loadu_si256((const __m256i*)(ptr + 8)); + __m256i bgra3 = _mm256_loadu_si256((const __m256i*)(ptr + 12)); + + __m256i l02 = _mm256_permute2x128_si256(bgra0, bgra2, 0 + 2*16); + __m256i h02 = _mm256_permute2x128_si256(bgra0, bgra2, 1 + 3*16); + __m256i l13 = _mm256_permute2x128_si256(bgra1, bgra3, 0 + 2*16); + __m256i h13 = _mm256_permute2x128_si256(bgra1, bgra3, 1 + 3*16); + + __m256i b0 = _mm256_unpacklo_epi64(l02, l13); + __m256i g0 = _mm256_unpackhi_epi64(l02, l13); + __m256i r0 = _mm256_unpacklo_epi64(h02, h13); + __m256i a0 = _mm256_unpackhi_epi64(h02, h13); + + a = v_uint64x4(b0); + b = v_uint64x4(g0); + c = v_uint64x4(r0); + d = v_uint64x4(a0); +} + +///////////////////////////// store interleave ///////////////////////////////////// + +inline void v_store_interleave( uchar* ptr, const v_uint8x32& x, const v_uint8x32& y, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m256i xy_l = _mm256_unpacklo_epi8(x.val, y.val); + __m256i xy_h = _mm256_unpackhi_epi8(x.val, y.val); + + __m256i xy0 = _mm256_permute2x128_si256(xy_l, xy_h, 0 + 2*16); + __m256i xy1 = _mm256_permute2x128_si256(xy_l, xy_h, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, xy0); + _mm256_stream_si256((__m256i*)(ptr + 32), xy1); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, xy0); + _mm256_store_si256((__m256i*)(ptr + 32), xy1); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, xy0); + _mm256_storeu_si256((__m256i*)(ptr + 32), xy1); + } +} + +inline void v_store_interleave( ushort* ptr, const v_uint16x16& x, const v_uint16x16& y, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m256i xy_l = _mm256_unpacklo_epi16(x.val, y.val); + __m256i xy_h = _mm256_unpackhi_epi16(x.val, y.val); + + __m256i xy0 = _mm256_permute2x128_si256(xy_l, xy_h, 0 + 2*16); + __m256i xy1 = _mm256_permute2x128_si256(xy_l, xy_h, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, xy0); + _mm256_stream_si256((__m256i*)(ptr + 16), xy1); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, xy0); + _mm256_store_si256((__m256i*)(ptr + 16), xy1); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, xy0); + _mm256_storeu_si256((__m256i*)(ptr + 16), xy1); + } +} + +inline void v_store_interleave( unsigned* ptr, const v_uint32x8& x, const v_uint32x8& y, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m256i xy_l = _mm256_unpacklo_epi32(x.val, y.val); + __m256i xy_h = _mm256_unpackhi_epi32(x.val, y.val); + + __m256i xy0 = _mm256_permute2x128_si256(xy_l, xy_h, 0 + 2*16); + __m256i xy1 = _mm256_permute2x128_si256(xy_l, xy_h, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, xy0); + _mm256_stream_si256((__m256i*)(ptr + 8), xy1); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, xy0); + _mm256_store_si256((__m256i*)(ptr + 8), xy1); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, xy0); + _mm256_storeu_si256((__m256i*)(ptr + 8), xy1); + } +} + +inline void v_store_interleave( uint64* ptr, const v_uint64x4& x, const v_uint64x4& y, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m256i xy_l = _mm256_unpacklo_epi64(x.val, y.val); + __m256i xy_h = _mm256_unpackhi_epi64(x.val, y.val); + + __m256i xy0 = _mm256_permute2x128_si256(xy_l, xy_h, 0 + 2*16); + __m256i xy1 = _mm256_permute2x128_si256(xy_l, xy_h, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, xy0); + _mm256_stream_si256((__m256i*)(ptr + 4), xy1); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, xy0); + _mm256_store_si256((__m256i*)(ptr + 4), xy1); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, xy0); + _mm256_storeu_si256((__m256i*)(ptr + 4), xy1); + } +} + +inline void v_store_interleave( uchar* ptr, const v_uint8x32& a, const v_uint8x32& b, const v_uint8x32& c, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + const __m256i sh_b = _mm256_setr_epi8( + 0, 11, 6, 1, 12, 7, 2, 13, 8, 3, 14, 9, 4, 15, 10, 5, + 0, 11, 6, 1, 12, 7, 2, 13, 8, 3, 14, 9, 4, 15, 10, 5); + const __m256i sh_g = _mm256_setr_epi8( + 5, 0, 11, 6, 1, 12, 7, 2, 13, 8, 3, 14, 9, 4, 15, 10, + 5, 0, 11, 6, 1, 12, 7, 2, 13, 8, 3, 14, 9, 4, 15, 10); + const __m256i sh_r = _mm256_setr_epi8( + 10, 5, 0, 11, 6, 1, 12, 7, 2, 13, 8, 3, 14, 9, 4, 15, + 10, 5, 0, 11, 6, 1, 12, 7, 2, 13, 8, 3, 14, 9, 4, 15); + + __m256i b0 = _mm256_shuffle_epi8(a.val, sh_b); + __m256i g0 = _mm256_shuffle_epi8(b.val, sh_g); + __m256i r0 = _mm256_shuffle_epi8(c.val, sh_r); + + const __m256i m0 = _mm256_setr_epi8(0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, + 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0); + const __m256i m1 = _mm256_setr_epi8(0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, + 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0); + + __m256i p0 = _mm256_blendv_epi8(_mm256_blendv_epi8(b0, g0, m0), r0, m1); + __m256i p1 = _mm256_blendv_epi8(_mm256_blendv_epi8(g0, r0, m0), b0, m1); + __m256i p2 = _mm256_blendv_epi8(_mm256_blendv_epi8(r0, b0, m0), g0, m1); + + __m256i bgr0 = _mm256_permute2x128_si256(p0, p1, 0 + 2*16); + __m256i bgr1 = _mm256_permute2x128_si256(p2, p0, 0 + 3*16); + __m256i bgr2 = _mm256_permute2x128_si256(p1, p2, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, bgr0); + _mm256_stream_si256((__m256i*)(ptr + 32), bgr1); + _mm256_stream_si256((__m256i*)(ptr + 64), bgr2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, bgr0); + _mm256_store_si256((__m256i*)(ptr + 32), bgr1); + _mm256_store_si256((__m256i*)(ptr + 64), bgr2); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, bgr0); + _mm256_storeu_si256((__m256i*)(ptr + 32), bgr1); + _mm256_storeu_si256((__m256i*)(ptr + 64), bgr2); + } +} + +inline void v_store_interleave( ushort* ptr, const v_uint16x16& a, const v_uint16x16& b, const v_uint16x16& c, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + const __m256i sh_b = _mm256_setr_epi8( + 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5, 10, 11, + 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5, 10, 11); + const __m256i sh_g = _mm256_setr_epi8( + 10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5, + 10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5); + const __m256i sh_r = _mm256_setr_epi8( + 4, 5, 10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, + 4, 5, 10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15); + + __m256i b0 = _mm256_shuffle_epi8(a.val, sh_b); + __m256i g0 = _mm256_shuffle_epi8(b.val, sh_g); + __m256i r0 = _mm256_shuffle_epi8(c.val, sh_r); + + const __m256i m0 = _mm256_setr_epi8(0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, + 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0); + const __m256i m1 = _mm256_setr_epi8(0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, + -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0); + + __m256i p0 = _mm256_blendv_epi8(_mm256_blendv_epi8(b0, g0, m0), r0, m1); + __m256i p1 = _mm256_blendv_epi8(_mm256_blendv_epi8(g0, r0, m0), b0, m1); + __m256i p2 = _mm256_blendv_epi8(_mm256_blendv_epi8(r0, b0, m0), g0, m1); + + __m256i bgr0 = _mm256_permute2x128_si256(p0, p2, 0 + 2*16); + //__m256i bgr1 = p1; + __m256i bgr2 = _mm256_permute2x128_si256(p0, p2, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, bgr0); + _mm256_stream_si256((__m256i*)(ptr + 16), p1); + _mm256_stream_si256((__m256i*)(ptr + 32), bgr2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, bgr0); + _mm256_store_si256((__m256i*)(ptr + 16), p1); + _mm256_store_si256((__m256i*)(ptr + 32), bgr2); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, bgr0); + _mm256_storeu_si256((__m256i*)(ptr + 16), p1); + _mm256_storeu_si256((__m256i*)(ptr + 32), bgr2); + } +} + +inline void v_store_interleave( unsigned* ptr, const v_uint32x8& a, const v_uint32x8& b, const v_uint32x8& c, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m256i b0 = _mm256_shuffle_epi32(a.val, 0x6c); + __m256i g0 = _mm256_shuffle_epi32(b.val, 0xb1); + __m256i r0 = _mm256_shuffle_epi32(c.val, 0xc6); + + __m256i p0 = _mm256_blend_epi32(_mm256_blend_epi32(b0, g0, 0x92), r0, 0x24); + __m256i p1 = _mm256_blend_epi32(_mm256_blend_epi32(g0, r0, 0x92), b0, 0x24); + __m256i p2 = _mm256_blend_epi32(_mm256_blend_epi32(r0, b0, 0x92), g0, 0x24); + + __m256i bgr0 = _mm256_permute2x128_si256(p0, p1, 0 + 2*16); + //__m256i bgr1 = p2; + __m256i bgr2 = _mm256_permute2x128_si256(p0, p1, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, bgr0); + _mm256_stream_si256((__m256i*)(ptr + 8), p2); + _mm256_stream_si256((__m256i*)(ptr + 16), bgr2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, bgr0); + _mm256_store_si256((__m256i*)(ptr + 8), p2); + _mm256_store_si256((__m256i*)(ptr + 16), bgr2); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, bgr0); + _mm256_storeu_si256((__m256i*)(ptr + 8), p2); + _mm256_storeu_si256((__m256i*)(ptr + 16), bgr2); + } +} + +inline void v_store_interleave( uint64* ptr, const v_uint64x4& a, const v_uint64x4& b, const v_uint64x4& c, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m256i s01 = _mm256_unpacklo_epi64(a.val, b.val); + __m256i s12 = _mm256_unpackhi_epi64(b.val, c.val); + __m256i s20 = _mm256_blend_epi32(c.val, a.val, 0xcc); + + __m256i bgr0 = _mm256_permute2x128_si256(s01, s20, 0 + 2*16); + __m256i bgr1 = _mm256_blend_epi32(s01, s12, 0x0f); + __m256i bgr2 = _mm256_permute2x128_si256(s20, s12, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, bgr0); + _mm256_stream_si256((__m256i*)(ptr + 4), bgr1); + _mm256_stream_si256((__m256i*)(ptr + 8), bgr2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, bgr0); + _mm256_store_si256((__m256i*)(ptr + 4), bgr1); + _mm256_store_si256((__m256i*)(ptr + 8), bgr2); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, bgr0); + _mm256_storeu_si256((__m256i*)(ptr + 4), bgr1); + _mm256_storeu_si256((__m256i*)(ptr + 8), bgr2); + } +} + +inline void v_store_interleave( uchar* ptr, const v_uint8x32& a, const v_uint8x32& b, + const v_uint8x32& c, const v_uint8x32& d, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m256i bg0 = _mm256_unpacklo_epi8(a.val, b.val); + __m256i bg1 = _mm256_unpackhi_epi8(a.val, b.val); + __m256i ra0 = _mm256_unpacklo_epi8(c.val, d.val); + __m256i ra1 = _mm256_unpackhi_epi8(c.val, d.val); + + __m256i bgra0_ = _mm256_unpacklo_epi16(bg0, ra0); + __m256i bgra1_ = _mm256_unpackhi_epi16(bg0, ra0); + __m256i bgra2_ = _mm256_unpacklo_epi16(bg1, ra1); + __m256i bgra3_ = _mm256_unpackhi_epi16(bg1, ra1); + + __m256i bgra0 = _mm256_permute2x128_si256(bgra0_, bgra1_, 0 + 2*16); + __m256i bgra2 = _mm256_permute2x128_si256(bgra0_, bgra1_, 1 + 3*16); + __m256i bgra1 = _mm256_permute2x128_si256(bgra2_, bgra3_, 0 + 2*16); + __m256i bgra3 = _mm256_permute2x128_si256(bgra2_, bgra3_, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, bgra0); + _mm256_stream_si256((__m256i*)(ptr + 32), bgra1); + _mm256_stream_si256((__m256i*)(ptr + 64), bgra2); + _mm256_stream_si256((__m256i*)(ptr + 96), bgra3); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, bgra0); + _mm256_store_si256((__m256i*)(ptr + 32), bgra1); + _mm256_store_si256((__m256i*)(ptr + 64), bgra2); + _mm256_store_si256((__m256i*)(ptr + 96), bgra3); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, bgra0); + _mm256_storeu_si256((__m256i*)(ptr + 32), bgra1); + _mm256_storeu_si256((__m256i*)(ptr + 64), bgra2); + _mm256_storeu_si256((__m256i*)(ptr + 96), bgra3); + } +} + +inline void v_store_interleave( ushort* ptr, const v_uint16x16& a, const v_uint16x16& b, + const v_uint16x16& c, const v_uint16x16& d, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m256i bg0 = _mm256_unpacklo_epi16(a.val, b.val); + __m256i bg1 = _mm256_unpackhi_epi16(a.val, b.val); + __m256i ra0 = _mm256_unpacklo_epi16(c.val, d.val); + __m256i ra1 = _mm256_unpackhi_epi16(c.val, d.val); + + __m256i bgra0_ = _mm256_unpacklo_epi32(bg0, ra0); + __m256i bgra1_ = _mm256_unpackhi_epi32(bg0, ra0); + __m256i bgra2_ = _mm256_unpacklo_epi32(bg1, ra1); + __m256i bgra3_ = _mm256_unpackhi_epi32(bg1, ra1); + + __m256i bgra0 = _mm256_permute2x128_si256(bgra0_, bgra1_, 0 + 2*16); + __m256i bgra2 = _mm256_permute2x128_si256(bgra0_, bgra1_, 1 + 3*16); + __m256i bgra1 = _mm256_permute2x128_si256(bgra2_, bgra3_, 0 + 2*16); + __m256i bgra3 = _mm256_permute2x128_si256(bgra2_, bgra3_, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, bgra0); + _mm256_stream_si256((__m256i*)(ptr + 16), bgra1); + _mm256_stream_si256((__m256i*)(ptr + 32), bgra2); + _mm256_stream_si256((__m256i*)(ptr + 48), bgra3); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, bgra0); + _mm256_store_si256((__m256i*)(ptr + 16), bgra1); + _mm256_store_si256((__m256i*)(ptr + 32), bgra2); + _mm256_store_si256((__m256i*)(ptr + 48), bgra3); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, bgra0); + _mm256_storeu_si256((__m256i*)(ptr + 16), bgra1); + _mm256_storeu_si256((__m256i*)(ptr + 32), bgra2); + _mm256_storeu_si256((__m256i*)(ptr + 48), bgra3); + } +} + +inline void v_store_interleave( unsigned* ptr, const v_uint32x8& a, const v_uint32x8& b, + const v_uint32x8& c, const v_uint32x8& d, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m256i bg0 = _mm256_unpacklo_epi32(a.val, b.val); + __m256i bg1 = _mm256_unpackhi_epi32(a.val, b.val); + __m256i ra0 = _mm256_unpacklo_epi32(c.val, d.val); + __m256i ra1 = _mm256_unpackhi_epi32(c.val, d.val); + + __m256i bgra0_ = _mm256_unpacklo_epi64(bg0, ra0); + __m256i bgra1_ = _mm256_unpackhi_epi64(bg0, ra0); + __m256i bgra2_ = _mm256_unpacklo_epi64(bg1, ra1); + __m256i bgra3_ = _mm256_unpackhi_epi64(bg1, ra1); + + __m256i bgra0 = _mm256_permute2x128_si256(bgra0_, bgra1_, 0 + 2*16); + __m256i bgra2 = _mm256_permute2x128_si256(bgra0_, bgra1_, 1 + 3*16); + __m256i bgra1 = _mm256_permute2x128_si256(bgra2_, bgra3_, 0 + 2*16); + __m256i bgra3 = _mm256_permute2x128_si256(bgra2_, bgra3_, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, bgra0); + _mm256_stream_si256((__m256i*)(ptr + 8), bgra1); + _mm256_stream_si256((__m256i*)(ptr + 16), bgra2); + _mm256_stream_si256((__m256i*)(ptr + 24), bgra3); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, bgra0); + _mm256_store_si256((__m256i*)(ptr + 8), bgra1); + _mm256_store_si256((__m256i*)(ptr + 16), bgra2); + _mm256_store_si256((__m256i*)(ptr + 24), bgra3); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, bgra0); + _mm256_storeu_si256((__m256i*)(ptr + 8), bgra1); + _mm256_storeu_si256((__m256i*)(ptr + 16), bgra2); + _mm256_storeu_si256((__m256i*)(ptr + 24), bgra3); + } +} + +inline void v_store_interleave( uint64* ptr, const v_uint64x4& a, const v_uint64x4& b, + const v_uint64x4& c, const v_uint64x4& d, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m256i bg0 = _mm256_unpacklo_epi64(a.val, b.val); + __m256i bg1 = _mm256_unpackhi_epi64(a.val, b.val); + __m256i ra0 = _mm256_unpacklo_epi64(c.val, d.val); + __m256i ra1 = _mm256_unpackhi_epi64(c.val, d.val); + + __m256i bgra0 = _mm256_permute2x128_si256(bg0, ra0, 0 + 2*16); + __m256i bgra1 = _mm256_permute2x128_si256(bg1, ra1, 0 + 2*16); + __m256i bgra2 = _mm256_permute2x128_si256(bg0, ra0, 1 + 3*16); + __m256i bgra3 = _mm256_permute2x128_si256(bg1, ra1, 1 + 3*16); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm256_stream_si256((__m256i*)ptr, bgra0); + _mm256_stream_si256((__m256i*)(ptr + 4), bgra1); + _mm256_stream_si256((__m256i*)(ptr + 8), bgra2); + _mm256_stream_si256((__m256i*)(ptr + 12), bgra3); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm256_store_si256((__m256i*)ptr, bgra0); + _mm256_store_si256((__m256i*)(ptr + 4), bgra1); + _mm256_store_si256((__m256i*)(ptr + 8), bgra2); + _mm256_store_si256((__m256i*)(ptr + 12), bgra3); + } + else + { + _mm256_storeu_si256((__m256i*)ptr, bgra0); + _mm256_storeu_si256((__m256i*)(ptr + 4), bgra1); + _mm256_storeu_si256((__m256i*)(ptr + 8), bgra2); + _mm256_storeu_si256((__m256i*)(ptr + 12), bgra3); + } +} + +#define OPENCV_HAL_IMPL_AVX_LOADSTORE_INTERLEAVE(_Tpvec0, _Tp0, suffix0, _Tpvec1, _Tp1, suffix1) \ +inline void v_load_deinterleave( const _Tp0* ptr, _Tpvec0& a0, _Tpvec0& b0 ) \ +{ \ + _Tpvec1 a1, b1; \ + v_load_deinterleave((const _Tp1*)ptr, a1, b1); \ + a0 = v_reinterpret_as_##suffix0(a1); \ + b0 = v_reinterpret_as_##suffix0(b1); \ +} \ +inline void v_load_deinterleave( const _Tp0* ptr, _Tpvec0& a0, _Tpvec0& b0, _Tpvec0& c0 ) \ +{ \ + _Tpvec1 a1, b1, c1; \ + v_load_deinterleave((const _Tp1*)ptr, a1, b1, c1); \ + a0 = v_reinterpret_as_##suffix0(a1); \ + b0 = v_reinterpret_as_##suffix0(b1); \ + c0 = v_reinterpret_as_##suffix0(c1); \ +} \ +inline void v_load_deinterleave( const _Tp0* ptr, _Tpvec0& a0, _Tpvec0& b0, _Tpvec0& c0, _Tpvec0& d0 ) \ +{ \ + _Tpvec1 a1, b1, c1, d1; \ + v_load_deinterleave((const _Tp1*)ptr, a1, b1, c1, d1); \ + a0 = v_reinterpret_as_##suffix0(a1); \ + b0 = v_reinterpret_as_##suffix0(b1); \ + c0 = v_reinterpret_as_##suffix0(c1); \ + d0 = v_reinterpret_as_##suffix0(d1); \ +} \ +inline void v_store_interleave( _Tp0* ptr, const _Tpvec0& a0, const _Tpvec0& b0, \ + hal::StoreMode mode=hal::STORE_UNALIGNED ) \ +{ \ + _Tpvec1 a1 = v_reinterpret_as_##suffix1(a0); \ + _Tpvec1 b1 = v_reinterpret_as_##suffix1(b0); \ + v_store_interleave((_Tp1*)ptr, a1, b1, mode); \ +} \ +inline void v_store_interleave( _Tp0* ptr, const _Tpvec0& a0, const _Tpvec0& b0, const _Tpvec0& c0, \ + hal::StoreMode mode=hal::STORE_UNALIGNED ) \ +{ \ + _Tpvec1 a1 = v_reinterpret_as_##suffix1(a0); \ + _Tpvec1 b1 = v_reinterpret_as_##suffix1(b0); \ + _Tpvec1 c1 = v_reinterpret_as_##suffix1(c0); \ + v_store_interleave((_Tp1*)ptr, a1, b1, c1, mode); \ +} \ +inline void v_store_interleave( _Tp0* ptr, const _Tpvec0& a0, const _Tpvec0& b0, \ + const _Tpvec0& c0, const _Tpvec0& d0, \ + hal::StoreMode mode=hal::STORE_UNALIGNED ) \ +{ \ + _Tpvec1 a1 = v_reinterpret_as_##suffix1(a0); \ + _Tpvec1 b1 = v_reinterpret_as_##suffix1(b0); \ + _Tpvec1 c1 = v_reinterpret_as_##suffix1(c0); \ + _Tpvec1 d1 = v_reinterpret_as_##suffix1(d0); \ + v_store_interleave((_Tp1*)ptr, a1, b1, c1, d1, mode); \ +} + +OPENCV_HAL_IMPL_AVX_LOADSTORE_INTERLEAVE(v_int8x32, schar, s8, v_uint8x32, uchar, u8) +OPENCV_HAL_IMPL_AVX_LOADSTORE_INTERLEAVE(v_int16x16, short, s16, v_uint16x16, ushort, u16) +OPENCV_HAL_IMPL_AVX_LOADSTORE_INTERLEAVE(v_int32x8, int, s32, v_uint32x8, unsigned, u32) +OPENCV_HAL_IMPL_AVX_LOADSTORE_INTERLEAVE(v_float32x8, float, f32, v_uint32x8, unsigned, u32) +OPENCV_HAL_IMPL_AVX_LOADSTORE_INTERLEAVE(v_int64x4, int64, s64, v_uint64x4, uint64, u64) +OPENCV_HAL_IMPL_AVX_LOADSTORE_INTERLEAVE(v_float64x4, double, f64, v_uint64x4, uint64, u64) + +// +// FP16 +// + +inline v_float32x8 v256_load_expand(const float16_t* ptr) +{ +#if CV_FP16 + return v_float32x8(_mm256_cvtph_ps(_mm_loadu_si128((const __m128i*)ptr))); +#else + float CV_DECL_ALIGNED(32) buf[8]; + for (int i = 0; i < 8; i++) + buf[i] = (float)ptr[i]; + return v256_load_aligned(buf); +#endif +} + +inline void v_pack_store(float16_t* ptr, const v_float32x8& a) +{ +#if CV_FP16 + __m128i ah = _mm256_cvtps_ph(a.val, 0); + _mm_storeu_si128((__m128i*)ptr, ah); +#else + float CV_DECL_ALIGNED(32) buf[8]; + v_store_aligned(buf, a); + for (int i = 0; i < 8; i++) + ptr[i] = float16_t(buf[i]); +#endif +} + +// +// end of FP16 +// + +inline void v256_cleanup() { _mm256_zeroall(); } + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END + +//! @endcond + +} // cv:: + +#endif // OPENCV_HAL_INTRIN_AVX_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_avx512.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_avx512.hpp new file mode 100644 index 0000000..d20d6dd --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_avx512.hpp @@ -0,0 +1,3090 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + +#ifndef OPENCV_HAL_INTRIN_AVX512_HPP +#define OPENCV_HAL_INTRIN_AVX512_HPP + +#if defined(_MSC_VER) && (_MSC_VER < 1920/*MSVS2019*/) +# pragma warning(disable:4146) // unary minus operator applied to unsigned type, result still unsigned +# pragma warning(disable:4309) // 'argument': truncation of constant value +# pragma warning(disable:4310) // cast truncates constant value +#endif + +#define CVT_ROUND_MODES_IMPLEMENTED 0 + +#define CV_SIMD512 1 +#define CV_SIMD512_64F 1 +#define CV_SIMD512_FP16 0 // no native operations with FP16 type. Only load/store from float32x8 are available (if CV_FP16 == 1) + +#define _v512_set_epu64(a7, a6, a5, a4, a3, a2, a1, a0) _mm512_set_epi64((int64)(a7),(int64)(a6),(int64)(a5),(int64)(a4),(int64)(a3),(int64)(a2),(int64)(a1),(int64)(a0)) +#define _v512_set_epu32(a15, a14, a13, a12, a11, a10, a9, a8, a7, a6, a5, a4, a3, a2, a1, a0) \ + _mm512_set_epi64(((int64)(a15)<<32)|(int64)(a14), ((int64)(a13)<<32)|(int64)(a12), ((int64)(a11)<<32)|(int64)(a10), ((int64)( a9)<<32)|(int64)( a8), \ + ((int64)( a7)<<32)|(int64)( a6), ((int64)( a5)<<32)|(int64)( a4), ((int64)( a3)<<32)|(int64)( a2), ((int64)( a1)<<32)|(int64)( a0)) +#define _v512_set_epu16(a31, a30, a29, a28, a27, a26, a25, a24, a23, a22, a21, a20, a19, a18, a17, a16, \ + a15, a14, a13, a12, a11, a10, a9, a8, a7, a6, a5, a4, a3, a2, a1, a0) \ + _v512_set_epu32(((unsigned)(a31)<<16)|(unsigned)(a30), ((unsigned)(a29)<<16)|(unsigned)(a28), ((unsigned)(a27)<<16)|(unsigned)(a26), ((unsigned)(a25)<<16)|(unsigned)(a24), \ + ((unsigned)(a23)<<16)|(unsigned)(a22), ((unsigned)(a21)<<16)|(unsigned)(a20), ((unsigned)(a19)<<16)|(unsigned)(a18), ((unsigned)(a17)<<16)|(unsigned)(a16), \ + ((unsigned)(a15)<<16)|(unsigned)(a14), ((unsigned)(a13)<<16)|(unsigned)(a12), ((unsigned)(a11)<<16)|(unsigned)(a10), ((unsigned)( a9)<<16)|(unsigned)( a8), \ + ((unsigned)( a7)<<16)|(unsigned)( a6), ((unsigned)( a5)<<16)|(unsigned)( a4), ((unsigned)( a3)<<16)|(unsigned)( a2), ((unsigned)( a1)<<16)|(unsigned)( a0)) +#define _v512_set_epu8(a63, a62, a61, a60, a59, a58, a57, a56, a55, a54, a53, a52, a51, a50, a49, a48, \ + a47, a46, a45, a44, a43, a42, a41, a40, a39, a38, a37, a36, a35, a34, a33, a32, \ + a31, a30, a29, a28, a27, a26, a25, a24, a23, a22, a21, a20, a19, a18, a17, a16, \ + a15, a14, a13, a12, a11, a10, a9, a8, a7, a6, a5, a4, a3, a2, a1, a0) \ + _v512_set_epu32(((unsigned)(a63)<<24)|((unsigned)(a62)<<16)|((unsigned)(a61)<<8)|(unsigned)(a60),((unsigned)(a59)<<24)|((unsigned)(a58)<<16)|((unsigned)(a57)<<8)|(unsigned)(a56), \ + ((unsigned)(a55)<<24)|((unsigned)(a54)<<16)|((unsigned)(a53)<<8)|(unsigned)(a52),((unsigned)(a51)<<24)|((unsigned)(a50)<<16)|((unsigned)(a49)<<8)|(unsigned)(a48), \ + ((unsigned)(a47)<<24)|((unsigned)(a46)<<16)|((unsigned)(a45)<<8)|(unsigned)(a44),((unsigned)(a43)<<24)|((unsigned)(a42)<<16)|((unsigned)(a41)<<8)|(unsigned)(a40), \ + ((unsigned)(a39)<<24)|((unsigned)(a38)<<16)|((unsigned)(a37)<<8)|(unsigned)(a36),((unsigned)(a35)<<24)|((unsigned)(a34)<<16)|((unsigned)(a33)<<8)|(unsigned)(a32), \ + ((unsigned)(a31)<<24)|((unsigned)(a30)<<16)|((unsigned)(a29)<<8)|(unsigned)(a28),((unsigned)(a27)<<24)|((unsigned)(a26)<<16)|((unsigned)(a25)<<8)|(unsigned)(a24), \ + ((unsigned)(a23)<<24)|((unsigned)(a22)<<16)|((unsigned)(a21)<<8)|(unsigned)(a20),((unsigned)(a19)<<24)|((unsigned)(a18)<<16)|((unsigned)(a17)<<8)|(unsigned)(a16), \ + ((unsigned)(a15)<<24)|((unsigned)(a14)<<16)|((unsigned)(a13)<<8)|(unsigned)(a12),((unsigned)(a11)<<24)|((unsigned)(a10)<<16)|((unsigned)( a9)<<8)|(unsigned)( a8), \ + ((unsigned)( a7)<<24)|((unsigned)( a6)<<16)|((unsigned)( a5)<<8)|(unsigned)( a4),((unsigned)( a3)<<24)|((unsigned)( a2)<<16)|((unsigned)( a1)<<8)|(unsigned)( a0)) +#define _v512_set_epi8(a63, a62, a61, a60, a59, a58, a57, a56, a55, a54, a53, a52, a51, a50, a49, a48, \ + a47, a46, a45, a44, a43, a42, a41, a40, a39, a38, a37, a36, a35, a34, a33, a32, \ + a31, a30, a29, a28, a27, a26, a25, a24, a23, a22, a21, a20, a19, a18, a17, a16, \ + a15, a14, a13, a12, a11, a10, a9, a8, a7, a6, a5, a4, a3, a2, a1, a0) \ + _v512_set_epu8((uchar)(a63), (uchar)(a62), (uchar)(a61), (uchar)(a60), (uchar)(a59), (uchar)(a58), (uchar)(a57), (uchar)(a56), \ + (uchar)(a55), (uchar)(a54), (uchar)(a53), (uchar)(a52), (uchar)(a51), (uchar)(a50), (uchar)(a49), (uchar)(a48), \ + (uchar)(a47), (uchar)(a46), (uchar)(a45), (uchar)(a44), (uchar)(a43), (uchar)(a42), (uchar)(a41), (uchar)(a40), \ + (uchar)(a39), (uchar)(a38), (uchar)(a37), (uchar)(a36), (uchar)(a35), (uchar)(a34), (uchar)(a33), (uchar)(a32), \ + (uchar)(a31), (uchar)(a30), (uchar)(a29), (uchar)(a28), (uchar)(a27), (uchar)(a26), (uchar)(a25), (uchar)(a24), \ + (uchar)(a23), (uchar)(a22), (uchar)(a21), (uchar)(a20), (uchar)(a19), (uchar)(a18), (uchar)(a17), (uchar)(a16), \ + (uchar)(a15), (uchar)(a14), (uchar)(a13), (uchar)(a12), (uchar)(a11), (uchar)(a10), (uchar)( a9), (uchar)( a8), \ + (uchar)( a7), (uchar)( a6), (uchar)( a5), (uchar)( a4), (uchar)( a3), (uchar)( a2), (uchar)( a1), (uchar)( a0)) + +#ifndef _mm512_cvtpd_pslo +#ifdef _mm512_zextsi256_si512 +#define _mm512_cvtpd_pslo(a) _mm512_zextps256_ps512(_mm512_cvtpd_ps(a)) +#else +//if preferred way to extend with zeros is unavailable +#define _mm512_cvtpd_pslo(a) _mm512_castps256_ps512(_mm512_cvtpd_ps(a)) +#endif +#endif +///////// Utils //////////// + +namespace +{ + +inline __m512i _v512_combine(const __m256i& lo, const __m256i& hi) +{ return _mm512_inserti32x8(_mm512_castsi256_si512(lo), hi, 1); } + +inline __m512 _v512_combine(const __m256& lo, const __m256& hi) +{ return _mm512_insertf32x8(_mm512_castps256_ps512(lo), hi, 1); } + +inline __m512d _v512_combine(const __m256d& lo, const __m256d& hi) +{ return _mm512_insertf64x4(_mm512_castpd256_pd512(lo), hi, 1); } + +inline int _v_cvtsi512_si32(const __m512i& a) +{ return _mm_cvtsi128_si32(_mm512_castsi512_si128(a)); } + +inline __m256i _v512_extract_high(const __m512i& v) +{ return _mm512_extracti32x8_epi32(v, 1); } + +inline __m256 _v512_extract_high(const __m512& v) +{ return _mm512_extractf32x8_ps(v, 1); } + +inline __m256d _v512_extract_high(const __m512d& v) +{ return _mm512_extractf64x4_pd(v, 1); } + +inline __m256i _v512_extract_low(const __m512i& v) +{ return _mm512_castsi512_si256(v); } + +inline __m256 _v512_extract_low(const __m512& v) +{ return _mm512_castps512_ps256(v); } + +inline __m256d _v512_extract_low(const __m512d& v) +{ return _mm512_castpd512_pd256(v); } + +inline __m512i _v512_insert(const __m512i& a, const __m256i& b) +{ return _mm512_inserti32x8(a, b, 0); } + +inline __m512 _v512_insert(const __m512& a, const __m256& b) +{ return _mm512_insertf32x8(a, b, 0); } + +inline __m512d _v512_insert(const __m512d& a, const __m256d& b) +{ return _mm512_insertf64x4(a, b, 0); } + +} + +namespace cv +{ + +//! @cond IGNORED + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN + +///////// Types //////////// + +struct v_uint8x64 +{ + typedef uchar lane_type; + enum { nlanes = 64 }; + __m512i val; + + explicit v_uint8x64(__m512i v) : val(v) {} + v_uint8x64(uchar v0, uchar v1, uchar v2, uchar v3, + uchar v4, uchar v5, uchar v6, uchar v7, + uchar v8, uchar v9, uchar v10, uchar v11, + uchar v12, uchar v13, uchar v14, uchar v15, + uchar v16, uchar v17, uchar v18, uchar v19, + uchar v20, uchar v21, uchar v22, uchar v23, + uchar v24, uchar v25, uchar v26, uchar v27, + uchar v28, uchar v29, uchar v30, uchar v31, + uchar v32, uchar v33, uchar v34, uchar v35, + uchar v36, uchar v37, uchar v38, uchar v39, + uchar v40, uchar v41, uchar v42, uchar v43, + uchar v44, uchar v45, uchar v46, uchar v47, + uchar v48, uchar v49, uchar v50, uchar v51, + uchar v52, uchar v53, uchar v54, uchar v55, + uchar v56, uchar v57, uchar v58, uchar v59, + uchar v60, uchar v61, uchar v62, uchar v63) + { + val = _v512_set_epu8(v63, v62, v61, v60, v59, v58, v57, v56, v55, v54, v53, v52, v51, v50, v49, v48, + v47, v46, v45, v44, v43, v42, v41, v40, v39, v38, v37, v36, v35, v34, v33, v32, + v31, v30, v29, v28, v27, v26, v25, v24, v23, v22, v21, v20, v19, v18, v17, v16, + v15, v14, v13, v12, v11, v10, v9, v8, v7, v6, v5, v4, v3, v2, v1, v0); + } + v_uint8x64() {} + + static inline v_uint8x64 zero() { return v_uint8x64(_mm512_setzero_si512()); } + + uchar get0() const { return (uchar)_v_cvtsi512_si32(val); } +}; + +struct v_int8x64 +{ + typedef schar lane_type; + enum { nlanes = 64 }; + __m512i val; + + explicit v_int8x64(__m512i v) : val(v) {} + v_int8x64(schar v0, schar v1, schar v2, schar v3, + schar v4, schar v5, schar v6, schar v7, + schar v8, schar v9, schar v10, schar v11, + schar v12, schar v13, schar v14, schar v15, + schar v16, schar v17, schar v18, schar v19, + schar v20, schar v21, schar v22, schar v23, + schar v24, schar v25, schar v26, schar v27, + schar v28, schar v29, schar v30, schar v31, + schar v32, schar v33, schar v34, schar v35, + schar v36, schar v37, schar v38, schar v39, + schar v40, schar v41, schar v42, schar v43, + schar v44, schar v45, schar v46, schar v47, + schar v48, schar v49, schar v50, schar v51, + schar v52, schar v53, schar v54, schar v55, + schar v56, schar v57, schar v58, schar v59, + schar v60, schar v61, schar v62, schar v63) + { + val = _v512_set_epi8(v63, v62, v61, v60, v59, v58, v57, v56, v55, v54, v53, v52, v51, v50, v49, v48, + v47, v46, v45, v44, v43, v42, v41, v40, v39, v38, v37, v36, v35, v34, v33, v32, + v31, v30, v29, v28, v27, v26, v25, v24, v23, v22, v21, v20, v19, v18, v17, v16, + v15, v14, v13, v12, v11, v10, v9, v8, v7, v6, v5, v4, v3, v2, v1, v0); + } + v_int8x64() {} + + static inline v_int8x64 zero() { return v_int8x64(_mm512_setzero_si512()); } + + schar get0() const { return (schar)_v_cvtsi512_si32(val); } +}; + +struct v_uint16x32 +{ + typedef ushort lane_type; + enum { nlanes = 32 }; + __m512i val; + + explicit v_uint16x32(__m512i v) : val(v) {} + v_uint16x32(ushort v0, ushort v1, ushort v2, ushort v3, + ushort v4, ushort v5, ushort v6, ushort v7, + ushort v8, ushort v9, ushort v10, ushort v11, + ushort v12, ushort v13, ushort v14, ushort v15, + ushort v16, ushort v17, ushort v18, ushort v19, + ushort v20, ushort v21, ushort v22, ushort v23, + ushort v24, ushort v25, ushort v26, ushort v27, + ushort v28, ushort v29, ushort v30, ushort v31) + { + val = _v512_set_epu16(v31, v30, v29, v28, v27, v26, v25, v24, v23, v22, v21, v20, v19, v18, v17, v16, + v15, v14, v13, v12, v11, v10, v9, v8, v7, v6, v5, v4, v3, v2, v1, v0); + } + v_uint16x32() {} + + static inline v_uint16x32 zero() { return v_uint16x32(_mm512_setzero_si512()); } + + ushort get0() const { return (ushort)_v_cvtsi512_si32(val); } +}; + +struct v_int16x32 +{ + typedef short lane_type; + enum { nlanes = 32 }; + __m512i val; + + explicit v_int16x32(__m512i v) : val(v) {} + v_int16x32(short v0, short v1, short v2, short v3, short v4, short v5, short v6, short v7, + short v8, short v9, short v10, short v11, short v12, short v13, short v14, short v15, + short v16, short v17, short v18, short v19, short v20, short v21, short v22, short v23, + short v24, short v25, short v26, short v27, short v28, short v29, short v30, short v31) + { + val = _v512_set_epu16((ushort)v31, (ushort)v30, (ushort)v29, (ushort)v28, (ushort)v27, (ushort)v26, (ushort)v25, (ushort)v24, + (ushort)v23, (ushort)v22, (ushort)v21, (ushort)v20, (ushort)v19, (ushort)v18, (ushort)v17, (ushort)v16, + (ushort)v15, (ushort)v14, (ushort)v13, (ushort)v12, (ushort)v11, (ushort)v10, (ushort)v9 , (ushort)v8, + (ushort)v7 , (ushort)v6 , (ushort)v5 , (ushort)v4 , (ushort)v3 , (ushort)v2 , (ushort)v1 , (ushort)v0); + } + v_int16x32() {} + + static inline v_int16x32 zero() { return v_int16x32(_mm512_setzero_si512()); } + + short get0() const { return (short)_v_cvtsi512_si32(val); } +}; + +struct v_uint32x16 +{ + typedef unsigned lane_type; + enum { nlanes = 16 }; + __m512i val; + + explicit v_uint32x16(__m512i v) : val(v) {} + v_uint32x16(unsigned v0, unsigned v1, unsigned v2, unsigned v3, + unsigned v4, unsigned v5, unsigned v6, unsigned v7, + unsigned v8, unsigned v9, unsigned v10, unsigned v11, + unsigned v12, unsigned v13, unsigned v14, unsigned v15) + { + val = _mm512_setr_epi32((int)v0, (int)v1, (int)v2, (int)v3, (int)v4, (int)v5, (int)v6, (int)v7, + (int)v8, (int)v9, (int)v10, (int)v11, (int)v12, (int)v13, (int)v14, (int)v15); + } + v_uint32x16() {} + + static inline v_uint32x16 zero() { return v_uint32x16(_mm512_setzero_si512()); } + + unsigned get0() const { return (unsigned)_v_cvtsi512_si32(val); } +}; + +struct v_int32x16 +{ + typedef int lane_type; + enum { nlanes = 16 }; + __m512i val; + + explicit v_int32x16(__m512i v) : val(v) {} + v_int32x16(int v0, int v1, int v2, int v3, int v4, int v5, int v6, int v7, + int v8, int v9, int v10, int v11, int v12, int v13, int v14, int v15) + { + val = _mm512_setr_epi32(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15); + } + v_int32x16() {} + + static inline v_int32x16 zero() { return v_int32x16(_mm512_setzero_si512()); } + + int get0() const { return _v_cvtsi512_si32(val); } +}; + +struct v_float32x16 +{ + typedef float lane_type; + enum { nlanes = 16 }; + __m512 val; + + explicit v_float32x16(__m512 v) : val(v) {} + v_float32x16(float v0, float v1, float v2, float v3, float v4, float v5, float v6, float v7, + float v8, float v9, float v10, float v11, float v12, float v13, float v14, float v15) + { + val = _mm512_setr_ps(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15); + } + v_float32x16() {} + + static inline v_float32x16 zero() { return v_float32x16(_mm512_setzero_ps()); } + + float get0() const { return _mm_cvtss_f32(_mm512_castps512_ps128(val)); } +}; + +struct v_uint64x8 +{ + typedef uint64 lane_type; + enum { nlanes = 8 }; + __m512i val; + + explicit v_uint64x8(__m512i v) : val(v) {} + v_uint64x8(uint64 v0, uint64 v1, uint64 v2, uint64 v3, uint64 v4, uint64 v5, uint64 v6, uint64 v7) + { val = _mm512_setr_epi64((int64)v0, (int64)v1, (int64)v2, (int64)v3, (int64)v4, (int64)v5, (int64)v6, (int64)v7); } + v_uint64x8() {} + + static inline v_uint64x8 zero() { return v_uint64x8(_mm512_setzero_si512()); } + + uint64 get0() const + { + #if defined __x86_64__ || defined _M_X64 + return (uint64)_mm_cvtsi128_si64(_mm512_castsi512_si128(val)); + #else + int a = _mm_cvtsi128_si32(_mm512_castsi512_si128(val)); + int b = _mm_cvtsi128_si32(_mm512_castsi512_si128(_mm512_srli_epi64(val, 32))); + return (unsigned)a | ((uint64)(unsigned)b << 32); + #endif + } +}; + +struct v_int64x8 +{ + typedef int64 lane_type; + enum { nlanes = 8 }; + __m512i val; + + explicit v_int64x8(__m512i v) : val(v) {} + v_int64x8(int64 v0, int64 v1, int64 v2, int64 v3, int64 v4, int64 v5, int64 v6, int64 v7) + { val = _mm512_setr_epi64(v0, v1, v2, v3, v4, v5, v6, v7); } + v_int64x8() {} + + static inline v_int64x8 zero() { return v_int64x8(_mm512_setzero_si512()); } + + int64 get0() const + { + #if defined __x86_64__ || defined _M_X64 + return (int64)_mm_cvtsi128_si64(_mm512_castsi512_si128(val)); + #else + int a = _mm_cvtsi128_si32(_mm512_castsi512_si128(val)); + int b = _mm_cvtsi128_si32(_mm512_castsi512_si128(_mm512_srli_epi64(val, 32))); + return (int64)((unsigned)a | ((uint64)(unsigned)b << 32)); + #endif + } +}; + +struct v_float64x8 +{ + typedef double lane_type; + enum { nlanes = 8 }; + __m512d val; + + explicit v_float64x8(__m512d v) : val(v) {} + v_float64x8(double v0, double v1, double v2, double v3, double v4, double v5, double v6, double v7) + { val = _mm512_setr_pd(v0, v1, v2, v3, v4, v5, v6, v7); } + v_float64x8() {} + + static inline v_float64x8 zero() { return v_float64x8(_mm512_setzero_pd()); } + + double get0() const { return _mm_cvtsd_f64(_mm512_castpd512_pd128(val)); } +}; + +//////////////// Load and store operations /////////////// + +#define OPENCV_HAL_IMPL_AVX512_LOADSTORE(_Tpvec, _Tp) \ + inline _Tpvec v512_load(const _Tp* ptr) \ + { return _Tpvec(_mm512_loadu_si512((const __m512i*)ptr)); } \ + inline _Tpvec v512_load_aligned(const _Tp* ptr) \ + { return _Tpvec(_mm512_load_si512((const __m512i*)ptr)); } \ + inline _Tpvec v512_load_low(const _Tp* ptr) \ + { \ + __m256i v256 = _mm256_loadu_si256((const __m256i*)ptr); \ + return _Tpvec(_mm512_castsi256_si512(v256)); \ + } \ + inline _Tpvec v512_load_halves(const _Tp* ptr0, const _Tp* ptr1) \ + { \ + __m256i vlo = _mm256_loadu_si256((const __m256i*)ptr0); \ + __m256i vhi = _mm256_loadu_si256((const __m256i*)ptr1); \ + return _Tpvec(_v512_combine(vlo, vhi)); \ + } \ + inline void v_store(_Tp* ptr, const _Tpvec& a) \ + { _mm512_storeu_si512((__m512i*)ptr, a.val); } \ + inline void v_store_aligned(_Tp* ptr, const _Tpvec& a) \ + { _mm512_store_si512((__m512i*)ptr, a.val); } \ + inline void v_store_aligned_nocache(_Tp* ptr, const _Tpvec& a) \ + { _mm512_stream_si512((__m512i*)ptr, a.val); } \ + inline void v_store(_Tp* ptr, const _Tpvec& a, hal::StoreMode mode) \ + { \ + if( mode == hal::STORE_UNALIGNED ) \ + _mm512_storeu_si512((__m512i*)ptr, a.val); \ + else if( mode == hal::STORE_ALIGNED_NOCACHE ) \ + _mm512_stream_si512((__m512i*)ptr, a.val); \ + else \ + _mm512_store_si512((__m512i*)ptr, a.val); \ + } \ + inline void v_store_low(_Tp* ptr, const _Tpvec& a) \ + { _mm256_storeu_si256((__m256i*)ptr, _v512_extract_low(a.val)); } \ + inline void v_store_high(_Tp* ptr, const _Tpvec& a) \ + { _mm256_storeu_si256((__m256i*)ptr, _v512_extract_high(a.val)); } + +OPENCV_HAL_IMPL_AVX512_LOADSTORE(v_uint8x64, uchar) +OPENCV_HAL_IMPL_AVX512_LOADSTORE(v_int8x64, schar) +OPENCV_HAL_IMPL_AVX512_LOADSTORE(v_uint16x32, ushort) +OPENCV_HAL_IMPL_AVX512_LOADSTORE(v_int16x32, short) +OPENCV_HAL_IMPL_AVX512_LOADSTORE(v_uint32x16, unsigned) +OPENCV_HAL_IMPL_AVX512_LOADSTORE(v_int32x16, int) +OPENCV_HAL_IMPL_AVX512_LOADSTORE(v_uint64x8, uint64) +OPENCV_HAL_IMPL_AVX512_LOADSTORE(v_int64x8, int64) + +#define OPENCV_HAL_IMPL_AVX512_LOADSTORE_FLT(_Tpvec, _Tp, suffix, halfreg) \ + inline _Tpvec v512_load(const _Tp* ptr) \ + { return _Tpvec(_mm512_loadu_##suffix(ptr)); } \ + inline _Tpvec v512_load_aligned(const _Tp* ptr) \ + { return _Tpvec(_mm512_load_##suffix(ptr)); } \ + inline _Tpvec v512_load_low(const _Tp* ptr) \ + { \ + return _Tpvec(_mm512_cast##suffix##256_##suffix##512 \ + (_mm256_loadu_##suffix(ptr))); \ + } \ + inline _Tpvec v512_load_halves(const _Tp* ptr0, const _Tp* ptr1) \ + { \ + halfreg vlo = _mm256_loadu_##suffix(ptr0); \ + halfreg vhi = _mm256_loadu_##suffix(ptr1); \ + return _Tpvec(_v512_combine(vlo, vhi)); \ + } \ + inline void v_store(_Tp* ptr, const _Tpvec& a) \ + { _mm512_storeu_##suffix(ptr, a.val); } \ + inline void v_store_aligned(_Tp* ptr, const _Tpvec& a) \ + { _mm512_store_##suffix(ptr, a.val); } \ + inline void v_store_aligned_nocache(_Tp* ptr, const _Tpvec& a) \ + { _mm512_stream_##suffix(ptr, a.val); } \ + inline void v_store(_Tp* ptr, const _Tpvec& a, hal::StoreMode mode) \ + { \ + if( mode == hal::STORE_UNALIGNED ) \ + _mm512_storeu_##suffix(ptr, a.val); \ + else if( mode == hal::STORE_ALIGNED_NOCACHE ) \ + _mm512_stream_##suffix(ptr, a.val); \ + else \ + _mm512_store_##suffix(ptr, a.val); \ + } \ + inline void v_store_low(_Tp* ptr, const _Tpvec& a) \ + { _mm256_storeu_##suffix(ptr, _v512_extract_low(a.val)); } \ + inline void v_store_high(_Tp* ptr, const _Tpvec& a) \ + { _mm256_storeu_##suffix(ptr, _v512_extract_high(a.val)); } + +OPENCV_HAL_IMPL_AVX512_LOADSTORE_FLT(v_float32x16, float, ps, __m256) +OPENCV_HAL_IMPL_AVX512_LOADSTORE_FLT(v_float64x8, double, pd, __m256d) + +#define OPENCV_HAL_IMPL_AVX512_CAST(_Tpvec, _Tpvecf, suffix, cast) \ + inline _Tpvec v_reinterpret_as_##suffix(const _Tpvecf& a) \ + { return _Tpvec(cast(a.val)); } + +#define OPENCV_HAL_IMPL_AVX512_INIT(_Tpvec, _Tp, suffix, ssuffix, ctype_s) \ + inline _Tpvec v512_setzero_##suffix() \ + { return _Tpvec(_mm512_setzero_si512()); } \ + inline _Tpvec v512_setall_##suffix(_Tp v) \ + { return _Tpvec(_mm512_set1_##ssuffix((ctype_s)v)); } \ + OPENCV_HAL_IMPL_AVX512_CAST(_Tpvec, v_uint8x64, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX512_CAST(_Tpvec, v_int8x64, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX512_CAST(_Tpvec, v_uint16x32, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX512_CAST(_Tpvec, v_int16x32, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX512_CAST(_Tpvec, v_uint32x16, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX512_CAST(_Tpvec, v_int32x16, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX512_CAST(_Tpvec, v_uint64x8, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX512_CAST(_Tpvec, v_int64x8, suffix, OPENCV_HAL_NOP) \ + OPENCV_HAL_IMPL_AVX512_CAST(_Tpvec, v_float32x16, suffix, _mm512_castps_si512) \ + OPENCV_HAL_IMPL_AVX512_CAST(_Tpvec, v_float64x8, suffix, _mm512_castpd_si512) + +OPENCV_HAL_IMPL_AVX512_INIT(v_uint8x64, uchar, u8, epi8, char) +OPENCV_HAL_IMPL_AVX512_INIT(v_int8x64, schar, s8, epi8, char) +OPENCV_HAL_IMPL_AVX512_INIT(v_uint16x32, ushort, u16, epi16, short) +OPENCV_HAL_IMPL_AVX512_INIT(v_int16x32, short, s16, epi16, short) +OPENCV_HAL_IMPL_AVX512_INIT(v_uint32x16, unsigned, u32, epi32, int) +OPENCV_HAL_IMPL_AVX512_INIT(v_int32x16, int, s32, epi32, int) +OPENCV_HAL_IMPL_AVX512_INIT(v_uint64x8, uint64, u64, epi64, int64) +OPENCV_HAL_IMPL_AVX512_INIT(v_int64x8, int64, s64, epi64, int64) + +#define OPENCV_HAL_IMPL_AVX512_INIT_FLT(_Tpvec, _Tp, suffix, zsuffix, cast) \ + inline _Tpvec v512_setzero_##suffix() \ + { return _Tpvec(_mm512_setzero_##zsuffix()); } \ + inline _Tpvec v512_setall_##suffix(_Tp v) \ + { return _Tpvec(_mm512_set1_##zsuffix(v)); } \ + OPENCV_HAL_IMPL_AVX512_CAST(_Tpvec, v_uint8x64, suffix, cast) \ + OPENCV_HAL_IMPL_AVX512_CAST(_Tpvec, v_int8x64, suffix, cast) \ + OPENCV_HAL_IMPL_AVX512_CAST(_Tpvec, v_uint16x32, suffix, cast) \ + OPENCV_HAL_IMPL_AVX512_CAST(_Tpvec, v_int16x32, suffix, cast) \ + OPENCV_HAL_IMPL_AVX512_CAST(_Tpvec, v_uint32x16, suffix, cast) \ + OPENCV_HAL_IMPL_AVX512_CAST(_Tpvec, v_int32x16, suffix, cast) \ + OPENCV_HAL_IMPL_AVX512_CAST(_Tpvec, v_uint64x8, suffix, cast) \ + OPENCV_HAL_IMPL_AVX512_CAST(_Tpvec, v_int64x8, suffix, cast) + +OPENCV_HAL_IMPL_AVX512_INIT_FLT(v_float32x16, float, f32, ps, _mm512_castsi512_ps) +OPENCV_HAL_IMPL_AVX512_INIT_FLT(v_float64x8, double, f64, pd, _mm512_castsi512_pd) + +inline v_float32x16 v_reinterpret_as_f32(const v_float32x16& a) +{ return a; } +inline v_float32x16 v_reinterpret_as_f32(const v_float64x8& a) +{ return v_float32x16(_mm512_castpd_ps(a.val)); } + +inline v_float64x8 v_reinterpret_as_f64(const v_float64x8& a) +{ return a; } +inline v_float64x8 v_reinterpret_as_f64(const v_float32x16& a) +{ return v_float64x8(_mm512_castps_pd(a.val)); } + +// FP16 +inline v_float32x16 v512_load_expand(const float16_t* ptr) +{ + return v_float32x16(_mm512_cvtph_ps(_mm256_loadu_si256((const __m256i*)ptr))); +} + +inline void v_pack_store(float16_t* ptr, const v_float32x16& a) +{ + __m256i ah = _mm512_cvtps_ph(a.val, 0); + _mm256_storeu_si256((__m256i*)ptr, ah); +} + +/* Recombine & ZIP */ +inline void v_zip(const v_int8x64& a, const v_int8x64& b, v_int8x64& ab0, v_int8x64& ab1) +{ +#if CV_AVX_512VBMI + __m512i mask0 = _v512_set_epu8( 95, 31, 94, 30, 93, 29, 92, 28, 91, 27, 90, 26, 89, 25, 88, 24, + 87, 23, 86, 22, 85, 21, 84, 20, 83, 19, 82, 18, 81, 17, 80, 16, + 79, 15, 78, 14, 77, 13, 76, 12, 75, 11, 74, 10, 73, 9, 72, 8, + 71, 7, 70, 6, 69, 5, 68, 4, 67, 3, 66, 2, 65, 1, 64, 0); + ab0 = v_int8x64(_mm512_permutex2var_epi8(a.val, mask0, b.val)); + __m512i mask1 = _v512_set_epu8(127, 63, 126, 62, 125, 61, 124, 60, 123, 59, 122, 58, 121, 57, 120, 56, + 119, 55, 118, 54, 117, 53, 116, 52, 115, 51, 114, 50, 113, 49, 112, 48, + 111, 47, 110, 46, 109, 45, 108, 44, 107, 43, 106, 42, 105, 41, 104, 40, + 103, 39, 102, 38, 101, 37, 100, 36, 99, 35, 98, 34, 97, 33, 96, 32); + ab1 = v_int8x64(_mm512_permutex2var_epi8(a.val, mask1, b.val)); +#else + __m512i low = _mm512_unpacklo_epi8(a.val, b.val); + __m512i high = _mm512_unpackhi_epi8(a.val, b.val); + ab0 = v_int8x64(_mm512_permutex2var_epi64(low, _v512_set_epu64(11, 10, 3, 2, 9, 8, 1, 0), high)); + ab1 = v_int8x64(_mm512_permutex2var_epi64(low, _v512_set_epu64(15, 14, 7, 6, 13, 12, 5, 4), high)); +#endif +} +inline void v_zip(const v_int16x32& a, const v_int16x32& b, v_int16x32& ab0, v_int16x32& ab1) +{ + __m512i mask0 = _v512_set_epu16(47, 15, 46, 14, 45, 13, 44, 12, 43, 11, 42, 10, 41, 9, 40, 8, + 39, 7, 38, 6, 37, 5, 36, 4, 35, 3, 34, 2, 33, 1, 32, 0); + ab0 = v_int16x32(_mm512_permutex2var_epi16(a.val, mask0, b.val)); + __m512i mask1 = _v512_set_epu16(63, 31, 62, 30, 61, 29, 60, 28, 59, 27, 58, 26, 57, 25, 56, 24, + 55, 23, 54, 22, 53, 21, 52, 20, 51, 19, 50, 18, 49, 17, 48, 16); + ab1 = v_int16x32(_mm512_permutex2var_epi16(a.val, mask1, b.val)); +} +inline void v_zip(const v_int32x16& a, const v_int32x16& b, v_int32x16& ab0, v_int32x16& ab1) +{ + __m512i mask0 = _v512_set_epu32(23, 7, 22, 6, 21, 5, 20, 4, 19, 3, 18, 2, 17, 1, 16, 0); + ab0 = v_int32x16(_mm512_permutex2var_epi32(a.val, mask0, b.val)); + __m512i mask1 = _v512_set_epu32(31, 15, 30, 14, 29, 13, 28, 12, 27, 11, 26, 10, 25, 9, 24, 8); + ab1 = v_int32x16(_mm512_permutex2var_epi32(a.val, mask1, b.val)); +} +inline void v_zip(const v_int64x8& a, const v_int64x8& b, v_int64x8& ab0, v_int64x8& ab1) +{ + __m512i mask0 = _v512_set_epu64(11, 3, 10, 2, 9, 1, 8, 0); + ab0 = v_int64x8(_mm512_permutex2var_epi64(a.val, mask0, b.val)); + __m512i mask1 = _v512_set_epu64(15, 7, 14, 6, 13, 5, 12, 4); + ab1 = v_int64x8(_mm512_permutex2var_epi64(a.val, mask1, b.val)); +} + +inline void v_zip(const v_uint8x64& a, const v_uint8x64& b, v_uint8x64& ab0, v_uint8x64& ab1) +{ + v_int8x64 i0, i1; + v_zip(v_reinterpret_as_s8(a), v_reinterpret_as_s8(b), i0, i1); + ab0 = v_reinterpret_as_u8(i0); + ab1 = v_reinterpret_as_u8(i1); +} +inline void v_zip(const v_uint16x32& a, const v_uint16x32& b, v_uint16x32& ab0, v_uint16x32& ab1) +{ + v_int16x32 i0, i1; + v_zip(v_reinterpret_as_s16(a), v_reinterpret_as_s16(b), i0, i1); + ab0 = v_reinterpret_as_u16(i0); + ab1 = v_reinterpret_as_u16(i1); +} +inline void v_zip(const v_uint32x16& a, const v_uint32x16& b, v_uint32x16& ab0, v_uint32x16& ab1) +{ + v_int32x16 i0, i1; + v_zip(v_reinterpret_as_s32(a), v_reinterpret_as_s32(b), i0, i1); + ab0 = v_reinterpret_as_u32(i0); + ab1 = v_reinterpret_as_u32(i1); +} +inline void v_zip(const v_uint64x8& a, const v_uint64x8& b, v_uint64x8& ab0, v_uint64x8& ab1) +{ + v_int64x8 i0, i1; + v_zip(v_reinterpret_as_s64(a), v_reinterpret_as_s64(b), i0, i1); + ab0 = v_reinterpret_as_u64(i0); + ab1 = v_reinterpret_as_u64(i1); +} +inline void v_zip(const v_float32x16& a, const v_float32x16& b, v_float32x16& ab0, v_float32x16& ab1) +{ + v_int32x16 i0, i1; + v_zip(v_reinterpret_as_s32(a), v_reinterpret_as_s32(b), i0, i1); + ab0 = v_reinterpret_as_f32(i0); + ab1 = v_reinterpret_as_f32(i1); +} +inline void v_zip(const v_float64x8& a, const v_float64x8& b, v_float64x8& ab0, v_float64x8& ab1) +{ + v_int64x8 i0, i1; + v_zip(v_reinterpret_as_s64(a), v_reinterpret_as_s64(b), i0, i1); + ab0 = v_reinterpret_as_f64(i0); + ab1 = v_reinterpret_as_f64(i1); +} + +#define OPENCV_HAL_IMPL_AVX512_COMBINE(_Tpvec, suffix) \ + inline _Tpvec v_combine_low(const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(_v512_combine(_v512_extract_low(a.val), _v512_extract_low(b.val))); } \ + inline _Tpvec v_combine_high(const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(_v512_insert(b.val, _v512_extract_high(a.val))); } \ + inline void v_recombine(const _Tpvec& a, const _Tpvec& b, \ + _Tpvec& c, _Tpvec& d) \ + { \ + c.val = _v512_combine(_v512_extract_low(a.val),_v512_extract_low(b.val)); \ + d.val = _v512_insert(b.val,_v512_extract_high(a.val)); \ + } + + +OPENCV_HAL_IMPL_AVX512_COMBINE(v_uint8x64, epi8) +OPENCV_HAL_IMPL_AVX512_COMBINE(v_int8x64, epi8) +OPENCV_HAL_IMPL_AVX512_COMBINE(v_uint16x32, epi16) +OPENCV_HAL_IMPL_AVX512_COMBINE(v_int16x32, epi16) +OPENCV_HAL_IMPL_AVX512_COMBINE(v_uint32x16, epi32) +OPENCV_HAL_IMPL_AVX512_COMBINE(v_int32x16, epi32) +OPENCV_HAL_IMPL_AVX512_COMBINE(v_uint64x8, epi64) +OPENCV_HAL_IMPL_AVX512_COMBINE(v_int64x8, epi64) +OPENCV_HAL_IMPL_AVX512_COMBINE(v_float32x16, ps) +OPENCV_HAL_IMPL_AVX512_COMBINE(v_float64x8, pd) + +////////// Arithmetic, bitwise and comparison operations ///////// + +/* Element-wise binary and unary operations */ + +/** Non-saturating arithmetics **/ +#define OPENCV_HAL_IMPL_AVX512_BIN_FUNC(func, _Tpvec, intrin) \ + inline _Tpvec func(const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(intrin(a.val, b.val)); } + +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_add_wrap, v_uint8x64, _mm512_add_epi8) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_add_wrap, v_int8x64, _mm512_add_epi8) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_add_wrap, v_uint16x32, _mm512_add_epi16) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_add_wrap, v_int16x32, _mm512_add_epi16) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_sub_wrap, v_uint8x64, _mm512_sub_epi8) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_sub_wrap, v_int8x64, _mm512_sub_epi8) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_sub_wrap, v_uint16x32, _mm512_sub_epi16) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_sub_wrap, v_int16x32, _mm512_sub_epi16) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_mul_wrap, v_uint16x32, _mm512_mullo_epi16) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_mul_wrap, v_int16x32, _mm512_mullo_epi16) + +inline v_uint8x64 v_mul_wrap(const v_uint8x64& a, const v_uint8x64& b) +{ + __m512i ad = _mm512_srai_epi16(a.val, 8); + __m512i bd = _mm512_srai_epi16(b.val, 8); + __m512i p0 = _mm512_mullo_epi16(a.val, b.val); // even + __m512i p1 = _mm512_slli_epi16(_mm512_mullo_epi16(ad, bd), 8); // odd + return v_uint8x64(_mm512_mask_blend_epi8(0xAAAAAAAAAAAAAAAA, p0, p1)); +} +inline v_int8x64 v_mul_wrap(const v_int8x64& a, const v_int8x64& b) +{ + return v_reinterpret_as_s8(v_mul_wrap(v_reinterpret_as_u8(a), v_reinterpret_as_u8(b))); +} + +#define OPENCV_HAL_IMPL_AVX512_BIN_OP(bin_op, _Tpvec, intrin) \ + inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(intrin(a.val, b.val)); } \ + inline _Tpvec& operator bin_op##= (_Tpvec& a, const _Tpvec& b) \ + { a.val = intrin(a.val, b.val); return a; } + +OPENCV_HAL_IMPL_AVX512_BIN_OP(+, v_uint32x16, _mm512_add_epi32) +OPENCV_HAL_IMPL_AVX512_BIN_OP(-, v_uint32x16, _mm512_sub_epi32) +OPENCV_HAL_IMPL_AVX512_BIN_OP(+, v_int32x16, _mm512_add_epi32) +OPENCV_HAL_IMPL_AVX512_BIN_OP(-, v_int32x16, _mm512_sub_epi32) +OPENCV_HAL_IMPL_AVX512_BIN_OP(+, v_uint64x8, _mm512_add_epi64) +OPENCV_HAL_IMPL_AVX512_BIN_OP(-, v_uint64x8, _mm512_sub_epi64) +OPENCV_HAL_IMPL_AVX512_BIN_OP(+, v_int64x8, _mm512_add_epi64) +OPENCV_HAL_IMPL_AVX512_BIN_OP(-, v_int64x8, _mm512_sub_epi64) + +OPENCV_HAL_IMPL_AVX512_BIN_OP(*, v_uint32x16, _mm512_mullo_epi32) +OPENCV_HAL_IMPL_AVX512_BIN_OP(*, v_int32x16, _mm512_mullo_epi32) +OPENCV_HAL_IMPL_AVX512_BIN_OP(*, v_uint64x8, _mm512_mullo_epi64) +OPENCV_HAL_IMPL_AVX512_BIN_OP(*, v_int64x8, _mm512_mullo_epi64) + +/** Saturating arithmetics **/ +OPENCV_HAL_IMPL_AVX512_BIN_OP(+, v_uint8x64, _mm512_adds_epu8) +OPENCV_HAL_IMPL_AVX512_BIN_OP(-, v_uint8x64, _mm512_subs_epu8) +OPENCV_HAL_IMPL_AVX512_BIN_OP(+, v_int8x64, _mm512_adds_epi8) +OPENCV_HAL_IMPL_AVX512_BIN_OP(-, v_int8x64, _mm512_subs_epi8) +OPENCV_HAL_IMPL_AVX512_BIN_OP(+, v_uint16x32, _mm512_adds_epu16) +OPENCV_HAL_IMPL_AVX512_BIN_OP(-, v_uint16x32, _mm512_subs_epu16) +OPENCV_HAL_IMPL_AVX512_BIN_OP(+, v_int16x32, _mm512_adds_epi16) +OPENCV_HAL_IMPL_AVX512_BIN_OP(-, v_int16x32, _mm512_subs_epi16) + +OPENCV_HAL_IMPL_AVX512_BIN_OP(+, v_float32x16, _mm512_add_ps) +OPENCV_HAL_IMPL_AVX512_BIN_OP(-, v_float32x16, _mm512_sub_ps) +OPENCV_HAL_IMPL_AVX512_BIN_OP(*, v_float32x16, _mm512_mul_ps) +OPENCV_HAL_IMPL_AVX512_BIN_OP(/, v_float32x16, _mm512_div_ps) +OPENCV_HAL_IMPL_AVX512_BIN_OP(+, v_float64x8, _mm512_add_pd) +OPENCV_HAL_IMPL_AVX512_BIN_OP(-, v_float64x8, _mm512_sub_pd) +OPENCV_HAL_IMPL_AVX512_BIN_OP(*, v_float64x8, _mm512_mul_pd) +OPENCV_HAL_IMPL_AVX512_BIN_OP(/, v_float64x8, _mm512_div_pd) + +// saturating multiply +inline v_uint8x64 operator * (const v_uint8x64& a, const v_uint8x64& b) +{ + v_uint16x32 c, d; + v_mul_expand(a, b, c, d); + return v_pack(c, d); +} +inline v_int8x64 operator * (const v_int8x64& a, const v_int8x64& b) +{ + v_int16x32 c, d; + v_mul_expand(a, b, c, d); + return v_pack(c, d); +} +inline v_uint16x32 operator * (const v_uint16x32& a, const v_uint16x32& b) +{ + __m512i pl = _mm512_mullo_epi16(a.val, b.val); + __m512i ph = _mm512_mulhi_epu16(a.val, b.val); + __m512i p0 = _mm512_unpacklo_epi16(pl, ph); + __m512i p1 = _mm512_unpackhi_epi16(pl, ph); + + const __m512i m = _mm512_set1_epi32(65535); + return v_uint16x32(_mm512_packus_epi32(_mm512_min_epu32(p0, m), _mm512_min_epu32(p1, m))); +} +inline v_int16x32 operator * (const v_int16x32& a, const v_int16x32& b) +{ + __m512i pl = _mm512_mullo_epi16(a.val, b.val); + __m512i ph = _mm512_mulhi_epi16(a.val, b.val); + __m512i p0 = _mm512_unpacklo_epi16(pl, ph); + __m512i p1 = _mm512_unpackhi_epi16(pl, ph); + return v_int16x32(_mm512_packs_epi32(p0, p1)); +} + +inline v_uint8x64& operator *= (v_uint8x64& a, const v_uint8x64& b) +{ a = a * b; return a; } +inline v_int8x64& operator *= (v_int8x64& a, const v_int8x64& b) +{ a = a * b; return a; } +inline v_uint16x32& operator *= (v_uint16x32& a, const v_uint16x32& b) +{ a = a * b; return a; } +inline v_int16x32& operator *= (v_int16x32& a, const v_int16x32& b) +{ a = a * b; return a; } + +inline v_int16x32 v_mul_hi(const v_int16x32& a, const v_int16x32& b) { return v_int16x32(_mm512_mulhi_epi16(a.val, b.val)); } +inline v_uint16x32 v_mul_hi(const v_uint16x32& a, const v_uint16x32& b) { return v_uint16x32(_mm512_mulhi_epu16(a.val, b.val)); } + +// Multiply and expand +inline void v_mul_expand(const v_uint8x64& a, const v_uint8x64& b, + v_uint16x32& c, v_uint16x32& d) +{ + v_uint16x32 a0, a1, b0, b1; + v_expand(a, a0, a1); + v_expand(b, b0, b1); + c = v_mul_wrap(a0, b0); + d = v_mul_wrap(a1, b1); +} + +inline void v_mul_expand(const v_int8x64& a, const v_int8x64& b, + v_int16x32& c, v_int16x32& d) +{ + v_int16x32 a0, a1, b0, b1; + v_expand(a, a0, a1); + v_expand(b, b0, b1); + c = v_mul_wrap(a0, b0); + d = v_mul_wrap(a1, b1); +} + +inline void v_mul_expand(const v_int16x32& a, const v_int16x32& b, + v_int32x16& c, v_int32x16& d) +{ + v_int16x32 v0, v1; + v_zip(v_mul_wrap(a, b), v_mul_hi(a, b), v0, v1); + + c = v_reinterpret_as_s32(v0); + d = v_reinterpret_as_s32(v1); +} + +inline void v_mul_expand(const v_uint16x32& a, const v_uint16x32& b, + v_uint32x16& c, v_uint32x16& d) +{ + v_uint16x32 v0, v1; + v_zip(v_mul_wrap(a, b), v_mul_hi(a, b), v0, v1); + + c = v_reinterpret_as_u32(v0); + d = v_reinterpret_as_u32(v1); +} + +inline void v_mul_expand(const v_uint32x16& a, const v_uint32x16& b, + v_uint64x8& c, v_uint64x8& d) +{ + v_zip(v_uint64x8(_mm512_mul_epu32(a.val, b.val)), + v_uint64x8(_mm512_mul_epu32(_mm512_srli_epi64(a.val, 32), _mm512_srli_epi64(b.val, 32))), c, d); +} + +inline void v_mul_expand(const v_int32x16& a, const v_int32x16& b, + v_int64x8& c, v_int64x8& d) +{ + v_zip(v_int64x8(_mm512_mul_epi32(a.val, b.val)), + v_int64x8(_mm512_mul_epi32(_mm512_srli_epi64(a.val, 32), _mm512_srli_epi64(b.val, 32))), c, d); +} + +/** Bitwise shifts **/ +#define OPENCV_HAL_IMPL_AVX512_SHIFT_OP(_Tpuvec, _Tpsvec, suffix) \ + inline _Tpuvec operator << (const _Tpuvec& a, int imm) \ + { return _Tpuvec(_mm512_slli_##suffix(a.val, imm)); } \ + inline _Tpsvec operator << (const _Tpsvec& a, int imm) \ + { return _Tpsvec(_mm512_slli_##suffix(a.val, imm)); } \ + inline _Tpuvec operator >> (const _Tpuvec& a, int imm) \ + { return _Tpuvec(_mm512_srli_##suffix(a.val, imm)); } \ + inline _Tpsvec operator >> (const _Tpsvec& a, int imm) \ + { return _Tpsvec(_mm512_srai_##suffix(a.val, imm)); } \ + template \ + inline _Tpuvec v_shl(const _Tpuvec& a) \ + { return _Tpuvec(_mm512_slli_##suffix(a.val, imm)); } \ + template \ + inline _Tpsvec v_shl(const _Tpsvec& a) \ + { return _Tpsvec(_mm512_slli_##suffix(a.val, imm)); } \ + template \ + inline _Tpuvec v_shr(const _Tpuvec& a) \ + { return _Tpuvec(_mm512_srli_##suffix(a.val, imm)); } \ + template \ + inline _Tpsvec v_shr(const _Tpsvec& a) \ + { return _Tpsvec(_mm512_srai_##suffix(a.val, imm)); } + +OPENCV_HAL_IMPL_AVX512_SHIFT_OP(v_uint16x32, v_int16x32, epi16) +OPENCV_HAL_IMPL_AVX512_SHIFT_OP(v_uint32x16, v_int32x16, epi32) +OPENCV_HAL_IMPL_AVX512_SHIFT_OP(v_uint64x8, v_int64x8, epi64) + + +/** Bitwise logic **/ +#define OPENCV_HAL_IMPL_AVX512_LOGIC_OP(_Tpvec, suffix, not_const) \ + OPENCV_HAL_IMPL_AVX512_BIN_OP(&, _Tpvec, _mm512_and_##suffix) \ + OPENCV_HAL_IMPL_AVX512_BIN_OP(|, _Tpvec, _mm512_or_##suffix) \ + OPENCV_HAL_IMPL_AVX512_BIN_OP(^, _Tpvec, _mm512_xor_##suffix) \ + inline _Tpvec operator ~ (const _Tpvec& a) \ + { return _Tpvec(_mm512_xor_##suffix(a.val, not_const)); } + +OPENCV_HAL_IMPL_AVX512_LOGIC_OP(v_uint8x64, si512, _mm512_set1_epi32(-1)) +OPENCV_HAL_IMPL_AVX512_LOGIC_OP(v_int8x64, si512, _mm512_set1_epi32(-1)) +OPENCV_HAL_IMPL_AVX512_LOGIC_OP(v_uint16x32, si512, _mm512_set1_epi32(-1)) +OPENCV_HAL_IMPL_AVX512_LOGIC_OP(v_int16x32, si512, _mm512_set1_epi32(-1)) +OPENCV_HAL_IMPL_AVX512_LOGIC_OP(v_uint32x16, si512, _mm512_set1_epi32(-1)) +OPENCV_HAL_IMPL_AVX512_LOGIC_OP(v_int32x16, si512, _mm512_set1_epi32(-1)) +OPENCV_HAL_IMPL_AVX512_LOGIC_OP(v_uint64x8, si512, _mm512_set1_epi64(-1)) +OPENCV_HAL_IMPL_AVX512_LOGIC_OP(v_int64x8, si512, _mm512_set1_epi64(-1)) +OPENCV_HAL_IMPL_AVX512_LOGIC_OP(v_float32x16, ps, _mm512_castsi512_ps(_mm512_set1_epi32(-1))) +OPENCV_HAL_IMPL_AVX512_LOGIC_OP(v_float64x8, pd, _mm512_castsi512_pd(_mm512_set1_epi32(-1))) + +/** Select **/ +#define OPENCV_HAL_IMPL_AVX512_SELECT(_Tpvec, suffix, zsuf) \ + inline _Tpvec v_select(const _Tpvec& mask, const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(_mm512_mask_blend_##suffix(_mm512_cmp_##suffix##_mask(mask.val, _mm512_setzero_##zsuf(), _MM_CMPINT_EQ), a.val, b.val)); } + +OPENCV_HAL_IMPL_AVX512_SELECT(v_uint8x64, epi8, si512) +OPENCV_HAL_IMPL_AVX512_SELECT(v_int8x64, epi8, si512) +OPENCV_HAL_IMPL_AVX512_SELECT(v_uint16x32, epi16, si512) +OPENCV_HAL_IMPL_AVX512_SELECT(v_int16x32, epi16, si512) +OPENCV_HAL_IMPL_AVX512_SELECT(v_uint32x16, epi32, si512) +OPENCV_HAL_IMPL_AVX512_SELECT(v_int32x16, epi32, si512) +OPENCV_HAL_IMPL_AVX512_SELECT(v_uint64x8, epi64, si512) +OPENCV_HAL_IMPL_AVX512_SELECT(v_int64x8, epi64, si512) +OPENCV_HAL_IMPL_AVX512_SELECT(v_float32x16, ps, ps) +OPENCV_HAL_IMPL_AVX512_SELECT(v_float64x8, pd, pd) + +/** Comparison **/ +#define OPENCV_HAL_IMPL_AVX512_CMP_INT(bin_op, imm8, _Tpvec, sufcmp, sufset, tval) \ + inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(_mm512_maskz_set1_##sufset(_mm512_cmp_##sufcmp##_mask(a.val, b.val, imm8), tval)); } + +#define OPENCV_HAL_IMPL_AVX512_CMP_OP_INT(_Tpvec, sufcmp, sufset, tval) \ + OPENCV_HAL_IMPL_AVX512_CMP_INT(==, _MM_CMPINT_EQ, _Tpvec, sufcmp, sufset, tval) \ + OPENCV_HAL_IMPL_AVX512_CMP_INT(!=, _MM_CMPINT_NE, _Tpvec, sufcmp, sufset, tval) \ + OPENCV_HAL_IMPL_AVX512_CMP_INT(<, _MM_CMPINT_LT, _Tpvec, sufcmp, sufset, tval) \ + OPENCV_HAL_IMPL_AVX512_CMP_INT(>, _MM_CMPINT_NLE, _Tpvec, sufcmp, sufset, tval) \ + OPENCV_HAL_IMPL_AVX512_CMP_INT(<=, _MM_CMPINT_LE, _Tpvec, sufcmp, sufset, tval) \ + OPENCV_HAL_IMPL_AVX512_CMP_INT(>=, _MM_CMPINT_NLT, _Tpvec, sufcmp, sufset, tval) + +OPENCV_HAL_IMPL_AVX512_CMP_OP_INT(v_uint8x64, epu8, epi8, (char)-1) +OPENCV_HAL_IMPL_AVX512_CMP_OP_INT(v_int8x64, epi8, epi8, (char)-1) +OPENCV_HAL_IMPL_AVX512_CMP_OP_INT(v_uint16x32, epu16, epi16, (short)-1) +OPENCV_HAL_IMPL_AVX512_CMP_OP_INT(v_int16x32, epi16, epi16, (short)-1) +OPENCV_HAL_IMPL_AVX512_CMP_OP_INT(v_uint32x16, epu32, epi32, (int)-1) +OPENCV_HAL_IMPL_AVX512_CMP_OP_INT(v_int32x16, epi32, epi32, (int)-1) +OPENCV_HAL_IMPL_AVX512_CMP_OP_INT(v_uint64x8, epu64, epi64, (int64)-1) +OPENCV_HAL_IMPL_AVX512_CMP_OP_INT(v_int64x8, epi64, epi64, (int64)-1) + +#define OPENCV_HAL_IMPL_AVX512_CMP_FLT(bin_op, imm8, _Tpvec, sufcmp, sufset, tval) \ + inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \ + { return _Tpvec(_mm512_castsi512_##sufcmp(_mm512_maskz_set1_##sufset(_mm512_cmp_##sufcmp##_mask(a.val, b.val, imm8), tval))); } + +#define OPENCV_HAL_IMPL_AVX512_CMP_OP_FLT(_Tpvec, sufcmp, sufset, tval) \ + OPENCV_HAL_IMPL_AVX512_CMP_FLT(==, _CMP_EQ_OQ, _Tpvec, sufcmp, sufset, tval) \ + OPENCV_HAL_IMPL_AVX512_CMP_FLT(!=, _CMP_NEQ_OQ, _Tpvec, sufcmp, sufset, tval) \ + OPENCV_HAL_IMPL_AVX512_CMP_FLT(<, _CMP_LT_OQ, _Tpvec, sufcmp, sufset, tval) \ + OPENCV_HAL_IMPL_AVX512_CMP_FLT(>, _CMP_GT_OQ, _Tpvec, sufcmp, sufset, tval) \ + OPENCV_HAL_IMPL_AVX512_CMP_FLT(<=, _CMP_LE_OQ, _Tpvec, sufcmp, sufset, tval) \ + OPENCV_HAL_IMPL_AVX512_CMP_FLT(>=, _CMP_GE_OQ, _Tpvec, sufcmp, sufset, tval) + +OPENCV_HAL_IMPL_AVX512_CMP_OP_FLT(v_float32x16, ps, epi32, (int)-1) +OPENCV_HAL_IMPL_AVX512_CMP_OP_FLT(v_float64x8, pd, epi64, (int64)-1) + +inline v_float32x16 v_not_nan(const v_float32x16& a) +{ return v_float32x16(_mm512_castsi512_ps(_mm512_maskz_set1_epi32(_mm512_cmp_ps_mask(a.val, a.val, _CMP_ORD_Q), (int)-1))); } +inline v_float64x8 v_not_nan(const v_float64x8& a) +{ return v_float64x8(_mm512_castsi512_pd(_mm512_maskz_set1_epi64(_mm512_cmp_pd_mask(a.val, a.val, _CMP_ORD_Q), (int64)-1))); } + +/** min/max **/ +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_min, v_uint8x64, _mm512_min_epu8) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_max, v_uint8x64, _mm512_max_epu8) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_min, v_int8x64, _mm512_min_epi8) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_max, v_int8x64, _mm512_max_epi8) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_min, v_uint16x32, _mm512_min_epu16) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_max, v_uint16x32, _mm512_max_epu16) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_min, v_int16x32, _mm512_min_epi16) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_max, v_int16x32, _mm512_max_epi16) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_min, v_uint32x16, _mm512_min_epu32) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_max, v_uint32x16, _mm512_max_epu32) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_min, v_int32x16, _mm512_min_epi32) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_max, v_int32x16, _mm512_max_epi32) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_min, v_uint64x8, _mm512_min_epu64) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_max, v_uint64x8, _mm512_max_epu64) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_min, v_int64x8, _mm512_min_epi64) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_max, v_int64x8, _mm512_max_epi64) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_min, v_float32x16, _mm512_min_ps) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_max, v_float32x16, _mm512_max_ps) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_min, v_float64x8, _mm512_min_pd) +OPENCV_HAL_IMPL_AVX512_BIN_FUNC(v_max, v_float64x8, _mm512_max_pd) + +/** Rotate **/ +namespace { + template + struct _v_rotate_right { static inline v_int8x64 eval(const v_int8x64&, const v_int8x64&) { return v_int8x64(); }}; + template + struct _v_rotate_right { static inline v_int8x64 eval(const v_int8x64& a, const v_int8x64& b) + { + return v_int8x64(_mm512_or_si512(_mm512_srli_epi32(_mm512_alignr_epi32(b.val, a.val, imm32 ), imm4 *8), + _mm512_slli_epi32(_mm512_alignr_epi32(b.val, a.val, imm32 + 1), (4-imm4)*8))); + }}; + template + struct _v_rotate_right { static inline v_int8x64 eval(const v_int8x64& a, const v_int8x64& b) + { + return v_int8x64(_mm512_or_si512(_mm512_srli_epi32(_mm512_alignr_epi32(b.val, a.val, 15), imm4 *8), + _mm512_slli_epi32( b.val, (4-imm4)*8))); + }}; + template + struct _v_rotate_right { static inline v_int8x64 eval(const v_int8x64&, const v_int8x64& b) + { + return v_int8x64(_mm512_or_si512(_mm512_srli_epi32(_mm512_alignr_epi32(_mm512_setzero_si512(), b.val, imm32 - 16), imm4 *8), + _mm512_slli_epi32(_mm512_alignr_epi32(_mm512_setzero_si512(), b.val, imm32 - 15), (4-imm4)*8))); + }}; + template + struct _v_rotate_right { static inline v_int8x64 eval(const v_int8x64&, const v_int8x64& b) + { return v_int8x64(_mm512_srli_epi32(_mm512_alignr_epi32(_mm512_setzero_si512(), b.val, 15), imm4*8)); }}; + template + struct _v_rotate_right { static inline v_int8x64 eval(const v_int8x64& a, const v_int8x64& b) + { return v_int8x64(_mm512_alignr_epi32(b.val, a.val, imm32)); }}; + template<> + struct _v_rotate_right { static inline v_int8x64 eval(const v_int8x64& a, const v_int8x64&) { return a; }}; + template + struct _v_rotate_right { static inline v_int8x64 eval(const v_int8x64&, const v_int8x64& b) + { return v_int8x64(_mm512_alignr_epi32(_mm512_setzero_si512(), b.val, imm32 - 16)); }}; + template<> + struct _v_rotate_right { static inline v_int8x64 eval(const v_int8x64&, const v_int8x64& b) { return b; }}; + template<> + struct _v_rotate_right { static inline v_int8x64 eval(const v_int8x64&, const v_int8x64&) { return v_int8x64(); }}; +} +template inline v_int8x64 v_rotate_right(const v_int8x64& a, const v_int8x64& b) +{ + return imm >= 128 ? v_int8x64() : +#if CV_AVX_512VBMI + v_int8x64(_mm512_permutex2var_epi8(a.val, + _v512_set_epu8(0x3f + imm, 0x3e + imm, 0x3d + imm, 0x3c + imm, 0x3b + imm, 0x3a + imm, 0x39 + imm, 0x38 + imm, + 0x37 + imm, 0x36 + imm, 0x35 + imm, 0x34 + imm, 0x33 + imm, 0x32 + imm, 0x31 + imm, 0x30 + imm, + 0x2f + imm, 0x2e + imm, 0x2d + imm, 0x2c + imm, 0x2b + imm, 0x2a + imm, 0x29 + imm, 0x28 + imm, + 0x27 + imm, 0x26 + imm, 0x25 + imm, 0x24 + imm, 0x23 + imm, 0x22 + imm, 0x21 + imm, 0x20 + imm, + 0x1f + imm, 0x1e + imm, 0x1d + imm, 0x1c + imm, 0x1b + imm, 0x1a + imm, 0x19 + imm, 0x18 + imm, + 0x17 + imm, 0x16 + imm, 0x15 + imm, 0x14 + imm, 0x13 + imm, 0x12 + imm, 0x11 + imm, 0x10 + imm, + 0x0f + imm, 0x0e + imm, 0x0d + imm, 0x0c + imm, 0x0b + imm, 0x0a + imm, 0x09 + imm, 0x08 + imm, + 0x07 + imm, 0x06 + imm, 0x05 + imm, 0x04 + imm, 0x03 + imm, 0x02 + imm, 0x01 + imm, 0x00 + imm), b.val)); +#else + _v_rotate_right 15), imm/4>::eval(a, b); +#endif +} +template +inline v_int8x64 v_rotate_left(const v_int8x64& a, const v_int8x64& b) +{ + if (imm == 0) return a; + if (imm == 64) return b; + if (imm >= 128) return v_int8x64(); +#if CV_AVX_512VBMI + return v_int8x64(_mm512_permutex2var_epi8(b.val, + _v512_set_epi8(0x7f - imm,0x7e - imm,0x7d - imm,0x7c - imm,0x7b - imm,0x7a - imm,0x79 - imm,0x78 - imm, + 0x77 - imm,0x76 - imm,0x75 - imm,0x74 - imm,0x73 - imm,0x72 - imm,0x71 - imm,0x70 - imm, + 0x6f - imm,0x6e - imm,0x6d - imm,0x6c - imm,0x6b - imm,0x6a - imm,0x69 - imm,0x68 - imm, + 0x67 - imm,0x66 - imm,0x65 - imm,0x64 - imm,0x63 - imm,0x62 - imm,0x61 - imm,0x60 - imm, + 0x5f - imm,0x5e - imm,0x5d - imm,0x5c - imm,0x5b - imm,0x5a - imm,0x59 - imm,0x58 - imm, + 0x57 - imm,0x56 - imm,0x55 - imm,0x54 - imm,0x53 - imm,0x52 - imm,0x51 - imm,0x50 - imm, + 0x4f - imm,0x4e - imm,0x4d - imm,0x4c - imm,0x4b - imm,0x4a - imm,0x49 - imm,0x48 - imm, + 0x47 - imm,0x46 - imm,0x45 - imm,0x44 - imm,0x43 - imm,0x42 - imm,0x41 - imm,0x40 - imm), a.val)); +#else + return imm < 64 ? v_rotate_right<64 - imm>(b, a) : v_rotate_right<128 - imm>(v512_setzero_s8(), b); +#endif +} +template +inline v_int8x64 v_rotate_right(const v_int8x64& a) +{ + if (imm == 0) return a; + if (imm >= 64) return v_int8x64(); +#if CV_AVX_512VBMI + return v_int8x64(_mm512_maskz_permutexvar_epi8(0xFFFFFFFFFFFFFFFF >> imm, + _v512_set_epu8(0x3f + imm,0x3e + imm,0x3d + imm,0x3c + imm,0x3b + imm,0x3a + imm,0x39 + imm,0x38 + imm, + 0x37 + imm,0x36 + imm,0x35 + imm,0x34 + imm,0x33 + imm,0x32 + imm,0x31 + imm,0x30 + imm, + 0x2f + imm,0x2e + imm,0x2d + imm,0x2c + imm,0x2b + imm,0x2a + imm,0x29 + imm,0x28 + imm, + 0x27 + imm,0x26 + imm,0x25 + imm,0x24 + imm,0x23 + imm,0x22 + imm,0x21 + imm,0x20 + imm, + 0x1f + imm,0x1e + imm,0x1d + imm,0x1c + imm,0x1b + imm,0x1a + imm,0x19 + imm,0x18 + imm, + 0x17 + imm,0x16 + imm,0x15 + imm,0x14 + imm,0x13 + imm,0x12 + imm,0x11 + imm,0x10 + imm, + 0x0f + imm,0x0e + imm,0x0d + imm,0x0c + imm,0x0b + imm,0x0a + imm,0x09 + imm,0x08 + imm, + 0x07 + imm,0x06 + imm,0x05 + imm,0x04 + imm,0x03 + imm,0x02 + imm,0x01 + imm,0x00 + imm), a.val)); +#else + return v_rotate_right(a, v512_setzero_s8()); +#endif +} +template +inline v_int8x64 v_rotate_left(const v_int8x64& a) +{ + if (imm == 0) return a; + if (imm >= 64) return v_int8x64(); +#if CV_AVX_512VBMI + return v_int8x64(_mm512_maskz_permutexvar_epi8(0xFFFFFFFFFFFFFFFF << imm, + _v512_set_epi8(0x3f - imm,0x3e - imm,0x3d - imm,0x3c - imm,0x3b - imm,0x3a - imm,0x39 - imm,0x38 - imm, + 0x37 - imm,0x36 - imm,0x35 - imm,0x34 - imm,0x33 - imm,0x32 - imm,0x31 - imm,0x30 - imm, + 0x2f - imm,0x2e - imm,0x2d - imm,0x2c - imm,0x2b - imm,0x2a - imm,0x29 - imm,0x28 - imm, + 0x27 - imm,0x26 - imm,0x25 - imm,0x24 - imm,0x23 - imm,0x22 - imm,0x21 - imm,0x20 - imm, + 0x1f - imm,0x1e - imm,0x1d - imm,0x1c - imm,0x1b - imm,0x1a - imm,0x19 - imm,0x18 - imm, + 0x17 - imm,0x16 - imm,0x15 - imm,0x14 - imm,0x13 - imm,0x12 - imm,0x11 - imm,0x10 - imm, + 0x0f - imm,0x0e - imm,0x0d - imm,0x0c - imm,0x0b - imm,0x0a - imm,0x09 - imm,0x08 - imm, + 0x07 - imm,0x06 - imm,0x05 - imm,0x04 - imm,0x03 - imm,0x02 - imm,0x01 - imm,0x00 - imm), a.val)); +#else + return v_rotate_right<64 - imm>(v512_setzero_s8(), a); +#endif +} + +#define OPENCV_HAL_IMPL_AVX512_ROTATE_PM(_Tpvec, suffix) \ +template inline _Tpvec v_rotate_left(const _Tpvec& a, const _Tpvec& b) \ +{ return v_reinterpret_as_##suffix(v_rotate_left(v_reinterpret_as_s8(a), v_reinterpret_as_s8(b))); } \ +template inline _Tpvec v_rotate_right(const _Tpvec& a, const _Tpvec& b) \ +{ return v_reinterpret_as_##suffix(v_rotate_right(v_reinterpret_as_s8(a), v_reinterpret_as_s8(b))); } \ +template inline _Tpvec v_rotate_left(const _Tpvec& a) \ +{ return v_reinterpret_as_##suffix(v_rotate_left(v_reinterpret_as_s8(a))); } \ +template inline _Tpvec v_rotate_right(const _Tpvec& a) \ +{ return v_reinterpret_as_##suffix(v_rotate_right(v_reinterpret_as_s8(a))); } + +#define OPENCV_HAL_IMPL_AVX512_ROTATE_EC(_Tpvec, suffix) \ +template \ +inline _Tpvec v_rotate_left(const _Tpvec& a, const _Tpvec& b) \ +{ \ + enum { SHIFT2 = (_Tpvec::nlanes - imm) }; \ + enum { MASK = ((1 << _Tpvec::nlanes) - 1) }; \ + if (imm == 0) return a; \ + if (imm == _Tpvec::nlanes) return b; \ + if (imm >= 2*_Tpvec::nlanes) return _Tpvec::zero(); \ + return _Tpvec(_mm512_mask_expand_##suffix(_mm512_maskz_compress_##suffix((MASK << SHIFT2)&MASK, b.val), (MASK << (imm))&MASK, a.val)); \ +} \ +template \ +inline _Tpvec v_rotate_right(const _Tpvec& a, const _Tpvec& b) \ +{ \ + enum { SHIFT2 = (_Tpvec::nlanes - imm) }; \ + enum { MASK = ((1 << _Tpvec::nlanes) - 1) }; \ + if (imm == 0) return a; \ + if (imm == _Tpvec::nlanes) return b; \ + if (imm >= 2*_Tpvec::nlanes) return _Tpvec::zero(); \ + return _Tpvec(_mm512_mask_expand_##suffix(_mm512_maskz_compress_##suffix((MASK << (imm))&MASK, a.val), (MASK << SHIFT2)&MASK, b.val)); \ +} \ +template \ +inline _Tpvec v_rotate_left(const _Tpvec& a) \ +{ \ + if (imm == 0) return a; \ + if (imm >= _Tpvec::nlanes) return _Tpvec::zero(); \ + return _Tpvec(_mm512_maskz_expand_##suffix((1 << _Tpvec::nlanes) - (1 << (imm)), a.val)); \ +} \ +template \ +inline _Tpvec v_rotate_right(const _Tpvec& a) \ +{ \ + if (imm == 0) return a; \ + if (imm >= _Tpvec::nlanes) return _Tpvec::zero(); \ + return _Tpvec(_mm512_maskz_compress_##suffix((1 << _Tpvec::nlanes) - (1 << (imm)), a.val)); \ +} + +OPENCV_HAL_IMPL_AVX512_ROTATE_PM(v_uint8x64, u8) +OPENCV_HAL_IMPL_AVX512_ROTATE_PM(v_uint16x32, u16) +OPENCV_HAL_IMPL_AVX512_ROTATE_PM(v_int16x32, s16) +OPENCV_HAL_IMPL_AVX512_ROTATE_EC(v_uint32x16, epi32) +OPENCV_HAL_IMPL_AVX512_ROTATE_EC(v_int32x16, epi32) +OPENCV_HAL_IMPL_AVX512_ROTATE_EC(v_uint64x8, epi64) +OPENCV_HAL_IMPL_AVX512_ROTATE_EC(v_int64x8, epi64) +OPENCV_HAL_IMPL_AVX512_ROTATE_EC(v_float32x16, ps) +OPENCV_HAL_IMPL_AVX512_ROTATE_EC(v_float64x8, pd) + +/** Reverse **/ +inline v_uint8x64 v_reverse(const v_uint8x64 &a) +{ +#if CV_AVX_512VBMI + static const __m512i perm = _mm512_set_epi32( + 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f, + 0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f, + 0x20212223, 0x24252627, 0x28292a2b, 0x2c2d2e2f, + 0x30313233, 0x34353637, 0x38393a3b, 0x3c3d3e3f); + return v_uint8x64(_mm512_permutexvar_epi8(perm, a.val)); +#else + static const __m512i shuf = _mm512_set_epi32( + 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f, + 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f, + 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f, + 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f); + static const __m512i perm = _mm512_set_epi64(1, 0, 3, 2, 5, 4, 7, 6); + __m512i vec = _mm512_shuffle_epi8(a.val, shuf); + return v_uint8x64(_mm512_permutexvar_epi64(perm, vec)); +#endif +} + +inline v_int8x64 v_reverse(const v_int8x64 &a) +{ return v_reinterpret_as_s8(v_reverse(v_reinterpret_as_u8(a))); } + +inline v_uint16x32 v_reverse(const v_uint16x32 &a) +{ +#if CV_AVX_512VBMI + static const __m512i perm = _mm512_set_epi32( + 0x00000001, 0x00020003, 0x00040005, 0x00060007, + 0x00080009, 0x000a000b, 0x000c000d, 0x000e000f, + 0x00100011, 0x00120013, 0x00140015, 0x00160017, + 0x00180019, 0x001a001b, 0x001c001d, 0x001e001f); + return v_uint16x32(_mm512_permutexvar_epi16(perm, a.val)); +#else + static const __m512i shuf = _mm512_set_epi32( + 0x01000302, 0x05040706, 0x09080b0a, 0x0d0c0f0e, + 0x01000302, 0x05040706, 0x09080b0a, 0x0d0c0f0e, + 0x01000302, 0x05040706, 0x09080b0a, 0x0d0c0f0e, + 0x01000302, 0x05040706, 0x09080b0a, 0x0d0c0f0e); + static const __m512i perm = _mm512_set_epi64(1, 0, 3, 2, 5, 4, 7, 6); + __m512i vec = _mm512_shuffle_epi8(a.val, shuf); + return v_uint16x32(_mm512_permutexvar_epi64(perm, vec)); +#endif +} + +inline v_int16x32 v_reverse(const v_int16x32 &a) +{ return v_reinterpret_as_s16(v_reverse(v_reinterpret_as_u16(a))); } + +inline v_uint32x16 v_reverse(const v_uint32x16 &a) +{ + static const __m512i perm = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,14, 15); + return v_uint32x16(_mm512_permutexvar_epi32(perm, a.val)); +} + +inline v_int32x16 v_reverse(const v_int32x16 &a) +{ return v_reinterpret_as_s32(v_reverse(v_reinterpret_as_u32(a))); } + +inline v_float32x16 v_reverse(const v_float32x16 &a) +{ return v_reinterpret_as_f32(v_reverse(v_reinterpret_as_u32(a))); } + +inline v_uint64x8 v_reverse(const v_uint64x8 &a) +{ + static const __m512i perm = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + return v_uint64x8(_mm512_permutexvar_epi64(perm, a.val)); +} + +inline v_int64x8 v_reverse(const v_int64x8 &a) +{ return v_reinterpret_as_s64(v_reverse(v_reinterpret_as_u64(a))); } + +inline v_float64x8 v_reverse(const v_float64x8 &a) +{ return v_reinterpret_as_f64(v_reverse(v_reinterpret_as_u64(a))); } + +////////// Reduce ///////// + +/** Reduce **/ +#define OPENCV_HAL_IMPL_AVX512_REDUCE_ADD64(a, b) a + b +#define OPENCV_HAL_IMPL_AVX512_REDUCE_8(sctype, func, _Tpvec, ifunc, scop) \ + inline sctype v_reduce_##func(const _Tpvec& a) \ + { __m256i half = _mm256_##ifunc(_v512_extract_low(a.val), _v512_extract_high(a.val)); \ + sctype CV_DECL_ALIGNED(64) idx[2]; \ + _mm_store_si128((__m128i*)idx, _mm_##ifunc(_mm256_castsi256_si128(half), _mm256_extracti128_si256(half, 1))); \ + return scop(idx[0], idx[1]); } +OPENCV_HAL_IMPL_AVX512_REDUCE_8(uint64, min, v_uint64x8, min_epu64, min) +OPENCV_HAL_IMPL_AVX512_REDUCE_8(uint64, max, v_uint64x8, max_epu64, max) +OPENCV_HAL_IMPL_AVX512_REDUCE_8(uint64, sum, v_uint64x8, add_epi64, OPENCV_HAL_IMPL_AVX512_REDUCE_ADD64) +OPENCV_HAL_IMPL_AVX512_REDUCE_8(int64, min, v_int64x8, min_epi64, min) +OPENCV_HAL_IMPL_AVX512_REDUCE_8(int64, max, v_int64x8, max_epi64, max) +OPENCV_HAL_IMPL_AVX512_REDUCE_8(int64, sum, v_int64x8, add_epi64, OPENCV_HAL_IMPL_AVX512_REDUCE_ADD64) + +#define OPENCV_HAL_IMPL_AVX512_REDUCE_8F(func, ifunc, scop) \ + inline double v_reduce_##func(const v_float64x8& a) \ + { __m256d half = _mm256_##ifunc(_v512_extract_low(a.val), _v512_extract_high(a.val)); \ + double CV_DECL_ALIGNED(64) idx[2]; \ + _mm_store_pd(idx, _mm_##ifunc(_mm256_castpd256_pd128(half), _mm256_extractf128_pd(half, 1))); \ + return scop(idx[0], idx[1]); } +OPENCV_HAL_IMPL_AVX512_REDUCE_8F(min, min_pd, min) +OPENCV_HAL_IMPL_AVX512_REDUCE_8F(max, max_pd, max) +OPENCV_HAL_IMPL_AVX512_REDUCE_8F(sum, add_pd, OPENCV_HAL_IMPL_AVX512_REDUCE_ADD64) + +#define OPENCV_HAL_IMPL_AVX512_REDUCE_16(sctype, func, _Tpvec, ifunc) \ + inline sctype v_reduce_##func(const _Tpvec& a) \ + { __m256i half = _mm256_##ifunc(_v512_extract_low(a.val), _v512_extract_high(a.val)); \ + __m128i quarter = _mm_##ifunc(_mm256_castsi256_si128(half), _mm256_extracti128_si256(half, 1)); \ + quarter = _mm_##ifunc(quarter, _mm_srli_si128(quarter, 8)); \ + quarter = _mm_##ifunc(quarter, _mm_srli_si128(quarter, 4)); \ + return (sctype)_mm_cvtsi128_si32(quarter); } +OPENCV_HAL_IMPL_AVX512_REDUCE_16(uint, min, v_uint32x16, min_epu32) +OPENCV_HAL_IMPL_AVX512_REDUCE_16(uint, max, v_uint32x16, max_epu32) +OPENCV_HAL_IMPL_AVX512_REDUCE_16(int, min, v_int32x16, min_epi32) +OPENCV_HAL_IMPL_AVX512_REDUCE_16(int, max, v_int32x16, max_epi32) + +#define OPENCV_HAL_IMPL_AVX512_REDUCE_16F(func, ifunc) \ + inline float v_reduce_##func(const v_float32x16& a) \ + { __m256 half = _mm256_##ifunc(_v512_extract_low(a.val), _v512_extract_high(a.val)); \ + __m128 quarter = _mm_##ifunc(_mm256_castps256_ps128(half), _mm256_extractf128_ps(half, 1)); \ + quarter = _mm_##ifunc(quarter, _mm_permute_ps(quarter, _MM_SHUFFLE(0, 0, 3, 2))); \ + quarter = _mm_##ifunc(quarter, _mm_permute_ps(quarter, _MM_SHUFFLE(0, 0, 0, 1))); \ + return _mm_cvtss_f32(quarter); } +OPENCV_HAL_IMPL_AVX512_REDUCE_16F(min, min_ps) +OPENCV_HAL_IMPL_AVX512_REDUCE_16F(max, max_ps) + +inline float v_reduce_sum(const v_float32x16& a) +{ + __m256 half = _mm256_add_ps(_v512_extract_low(a.val), _v512_extract_high(a.val)); + __m128 quarter = _mm_add_ps(_mm256_castps256_ps128(half), _mm256_extractf128_ps(half, 1)); + quarter = _mm_hadd_ps(quarter, quarter); + return _mm_cvtss_f32(_mm_hadd_ps(quarter, quarter)); +} +inline int v_reduce_sum(const v_int32x16& a) +{ + __m256i half = _mm256_add_epi32(_v512_extract_low(a.val), _v512_extract_high(a.val)); + __m128i quarter = _mm_add_epi32(_mm256_castsi256_si128(half), _mm256_extracti128_si256(half, 1)); + quarter = _mm_hadd_epi32(quarter, quarter); + return _mm_cvtsi128_si32(_mm_hadd_epi32(quarter, quarter)); +} +inline uint v_reduce_sum(const v_uint32x16& a) +{ return (uint)v_reduce_sum(v_reinterpret_as_s32(a)); } + +#define OPENCV_HAL_IMPL_AVX512_REDUCE_32(sctype, func, _Tpvec, ifunc) \ + inline sctype v_reduce_##func(const _Tpvec& a) \ + { __m256i half = _mm256_##ifunc(_v512_extract_low(a.val), _v512_extract_high(a.val)); \ + __m128i quarter = _mm_##ifunc(_mm256_castsi256_si128(half), _mm256_extracti128_si256(half, 1)); \ + quarter = _mm_##ifunc(quarter, _mm_srli_si128(quarter, 8)); \ + quarter = _mm_##ifunc(quarter, _mm_srli_si128(quarter, 4)); \ + quarter = _mm_##ifunc(quarter, _mm_srli_si128(quarter, 2)); \ + return (sctype)_mm_cvtsi128_si32(quarter); } +OPENCV_HAL_IMPL_AVX512_REDUCE_32(ushort, min, v_uint16x32, min_epu16) +OPENCV_HAL_IMPL_AVX512_REDUCE_32(ushort, max, v_uint16x32, max_epu16) +OPENCV_HAL_IMPL_AVX512_REDUCE_32(short, min, v_int16x32, min_epi16) +OPENCV_HAL_IMPL_AVX512_REDUCE_32(short, max, v_int16x32, max_epi16) + +inline int v_reduce_sum(const v_int16x32& a) +{ return v_reduce_sum(v_expand_low(a) + v_expand_high(a)); } +inline uint v_reduce_sum(const v_uint16x32& a) +{ return v_reduce_sum(v_expand_low(a) + v_expand_high(a)); } + +#define OPENCV_HAL_IMPL_AVX512_REDUCE_64(sctype, func, _Tpvec, ifunc) \ + inline sctype v_reduce_##func(const _Tpvec& a) \ + { __m256i half = _mm256_##ifunc(_v512_extract_low(a.val), _v512_extract_high(a.val)); \ + __m128i quarter = _mm_##ifunc(_mm256_castsi256_si128(half), _mm256_extracti128_si256(half, 1)); \ + quarter = _mm_##ifunc(quarter, _mm_srli_si128(quarter, 8)); \ + quarter = _mm_##ifunc(quarter, _mm_srli_si128(quarter, 4)); \ + quarter = _mm_##ifunc(quarter, _mm_srli_si128(quarter, 2)); \ + quarter = _mm_##ifunc(quarter, _mm_srli_si128(quarter, 1)); \ + return (sctype)_mm_cvtsi128_si32(quarter); } +OPENCV_HAL_IMPL_AVX512_REDUCE_64(uchar, min, v_uint8x64, min_epu8) +OPENCV_HAL_IMPL_AVX512_REDUCE_64(uchar, max, v_uint8x64, max_epu8) +OPENCV_HAL_IMPL_AVX512_REDUCE_64(schar, min, v_int8x64, min_epi8) +OPENCV_HAL_IMPL_AVX512_REDUCE_64(schar, max, v_int8x64, max_epi8) + +#define OPENCV_HAL_IMPL_AVX512_REDUCE_64_SUM(sctype, _Tpvec, suffix) \ + inline sctype v_reduce_sum(const _Tpvec& a) \ + { __m512i a16 = _mm512_add_epi16(_mm512_cvt##suffix##_epi16(_v512_extract_low(a.val)), \ + _mm512_cvt##suffix##_epi16(_v512_extract_high(a.val))); \ + a16 = _mm512_cvtepi16_epi32(_mm256_add_epi16(_v512_extract_low(a16), _v512_extract_high(a16))); \ + __m256i a8 = _mm256_add_epi32(_v512_extract_low(a16), _v512_extract_high(a16)); \ + __m128i a4 = _mm_add_epi32(_mm256_castsi256_si128(a8), _mm256_extracti128_si256(a8, 1)); \ + a4 = _mm_hadd_epi32(a4, a4); \ + return (sctype)_mm_cvtsi128_si32(_mm_hadd_epi32(a4, a4)); } +OPENCV_HAL_IMPL_AVX512_REDUCE_64_SUM(uint, v_uint8x64, epu8) +OPENCV_HAL_IMPL_AVX512_REDUCE_64_SUM(int, v_int8x64, epi8) + +inline v_float32x16 v_reduce_sum4(const v_float32x16& a, const v_float32x16& b, + const v_float32x16& c, const v_float32x16& d) +{ + __m256 abl = _mm256_hadd_ps(_v512_extract_low(a.val), _v512_extract_low(b.val)); + __m256 abh = _mm256_hadd_ps(_v512_extract_high(a.val), _v512_extract_high(b.val)); + __m256 cdl = _mm256_hadd_ps(_v512_extract_low(c.val), _v512_extract_low(d.val)); + __m256 cdh = _mm256_hadd_ps(_v512_extract_high(c.val), _v512_extract_high(d.val)); + return v_float32x16(_v512_combine(_mm256_hadd_ps(abl, cdl), _mm256_hadd_ps(abh, cdh))); +} + +inline unsigned v_reduce_sad(const v_uint8x64& a, const v_uint8x64& b) +{ + __m512i val = _mm512_sad_epu8(a.val, b.val); + __m256i half = _mm256_add_epi32(_v512_extract_low(val), _v512_extract_high(val)); + __m128i quarter = _mm_add_epi32(_mm256_castsi256_si128(half), _mm256_extracti128_si256(half, 1)); + return (unsigned)_mm_cvtsi128_si32(_mm_add_epi32(quarter, _mm_unpackhi_epi64(quarter, quarter))); +} +inline unsigned v_reduce_sad(const v_int8x64& a, const v_int8x64& b) +{ + __m512i val = _mm512_set1_epi8(-128); + val = _mm512_sad_epu8(_mm512_add_epi8(a.val, val), _mm512_add_epi8(b.val, val)); + __m256i half = _mm256_add_epi32(_v512_extract_low(val), _v512_extract_high(val)); + __m128i quarter = _mm_add_epi32(_mm256_castsi256_si128(half), _mm256_extracti128_si256(half, 1)); + return (unsigned)_mm_cvtsi128_si32(_mm_add_epi32(quarter, _mm_unpackhi_epi64(quarter, quarter))); +} +inline unsigned v_reduce_sad(const v_uint16x32& a, const v_uint16x32& b) +{ return v_reduce_sum(v_add_wrap(a - b, b - a)); } +inline unsigned v_reduce_sad(const v_int16x32& a, const v_int16x32& b) +{ return v_reduce_sum(v_reinterpret_as_u16(v_sub_wrap(v_max(a, b), v_min(a, b)))); } +inline unsigned v_reduce_sad(const v_uint32x16& a, const v_uint32x16& b) +{ return v_reduce_sum(v_max(a, b) - v_min(a, b)); } +inline unsigned v_reduce_sad(const v_int32x16& a, const v_int32x16& b) +{ return v_reduce_sum(v_reinterpret_as_u32(v_max(a, b) - v_min(a, b))); } +inline float v_reduce_sad(const v_float32x16& a, const v_float32x16& b) +{ return v_reduce_sum((a - b) & v_float32x16(_mm512_castsi512_ps(_mm512_set1_epi32(0x7fffffff)))); } +inline double v_reduce_sad(const v_float64x8& a, const v_float64x8& b) +{ return v_reduce_sum((a - b) & v_float64x8(_mm512_castsi512_pd(_mm512_set1_epi64(0x7fffffffffffffff)))); } + +/** Popcount **/ +inline v_uint8x64 v_popcount(const v_int8x64& a) +{ +#if CV_AVX_512BITALG + return v_uint8x64(_mm512_popcnt_epi8(a.val)); +#elif CV_AVX_512VBMI + __m512i _popcnt_table0 = _v512_set_epu8(7, 6, 6, 5, 6, 5, 5, 4, 6, 5, 5, 4, 5, 4, 4, 3, + 5, 4, 4, 3, 4, 3, 3, 2, 4, 3, 3, 2, 3, 2, 2, 1, + 5, 4, 4, 3, 4, 3, 3, 2, 4, 3, 3, 2, 3, 2, 2, 1, + 4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0); + __m512i _popcnt_table1 = _v512_set_epu8(7, 6, 6, 5, 6, 5, 5, 4, 6, 5, 5, 4, 5, 4, 4, 3, + 6, 5, 5, 4, 5, 4, 4, 3, 5, 4, 4, 3, 4, 3, 3, 2, + 6, 5, 5, 4, 5, 4, 4, 3, 5, 4, 4, 3, 4, 3, 3, 2, + 5, 4, 4, 3, 4, 3, 3, 2, 4, 3, 3, 2, 3, 2, 2, 1); + return v_uint8x64(_mm512_sub_epi8(_mm512_permutex2var_epi8(_popcnt_table0, a.val, _popcnt_table1), _mm512_movm_epi8(_mm512_movepi8_mask(a.val)))); +#else + __m512i _popcnt_table = _mm512_set4_epi32(0x04030302, 0x03020201, 0x03020201, 0x02010100); + __m512i _popcnt_mask = _mm512_set1_epi8(0x0F); + + return v_uint8x64(_mm512_add_epi8(_mm512_shuffle_epi8(_popcnt_table, _mm512_and_si512( a.val, _popcnt_mask)), + _mm512_shuffle_epi8(_popcnt_table, _mm512_and_si512(_mm512_srli_epi16(a.val, 4), _popcnt_mask)))); +#endif +} +inline v_uint16x32 v_popcount(const v_int16x32& a) +{ +#if CV_AVX_512BITALG + return v_uint16x32(_mm512_popcnt_epi16(a.val)); +#elif CV_AVX_512VPOPCNTDQ + __m512i zero = _mm512_setzero_si512(); + return v_uint16x32(_mm512_packs_epi32(_mm512_popcnt_epi32(_mm512_unpacklo_epi16(a.val, zero)), + _mm512_popcnt_epi32(_mm512_unpackhi_epi16(a.val, zero)))); +#else + v_uint8x64 p = v_popcount(v_reinterpret_as_s8(a)); + p += v_rotate_right<1>(p); + return v_reinterpret_as_u16(p) & v512_setall_u16(0x00ff); +#endif +} +inline v_uint32x16 v_popcount(const v_int32x16& a) +{ +#if CV_AVX_512VPOPCNTDQ + return v_uint32x16(_mm512_popcnt_epi32(a.val)); +#else + v_uint8x64 p = v_popcount(v_reinterpret_as_s8(a)); + p += v_rotate_right<1>(p); + p += v_rotate_right<2>(p); + return v_reinterpret_as_u32(p) & v512_setall_u32(0x000000ff); +#endif +} +inline v_uint64x8 v_popcount(const v_int64x8& a) +{ +#if CV_AVX_512VPOPCNTDQ + return v_uint64x8(_mm512_popcnt_epi64(a.val)); +#else + return v_uint64x8(_mm512_sad_epu8(v_popcount(v_reinterpret_as_s8(a)).val, _mm512_setzero_si512())); +#endif +} + + +inline v_uint8x64 v_popcount(const v_uint8x64& a) { return v_popcount(v_reinterpret_as_s8 (a)); } +inline v_uint16x32 v_popcount(const v_uint16x32& a) { return v_popcount(v_reinterpret_as_s16(a)); } +inline v_uint32x16 v_popcount(const v_uint32x16& a) { return v_popcount(v_reinterpret_as_s32(a)); } +inline v_uint64x8 v_popcount(const v_uint64x8& a) { return v_popcount(v_reinterpret_as_s64(a)); } + + +////////// Other math ///////// + +/** Some frequent operations **/ +#if CV_FMA3 +#define OPENCV_HAL_IMPL_AVX512_MULADD(_Tpvec, suffix) \ + inline _Tpvec v_fma(const _Tpvec& a, const _Tpvec& b, const _Tpvec& c) \ + { return _Tpvec(_mm512_fmadd_##suffix(a.val, b.val, c.val)); } \ + inline _Tpvec v_muladd(const _Tpvec& a, const _Tpvec& b, const _Tpvec& c) \ + { return _Tpvec(_mm512_fmadd_##suffix(a.val, b.val, c.val)); } +#else +#define OPENCV_HAL_IMPL_AVX512_MULADD(_Tpvec, suffix) \ + inline _Tpvec v_fma(const _Tpvec& a, const _Tpvec& b, const _Tpvec& c) \ + { return _Tpvec(_mm512_add_##suffix(_mm512_mul_##suffix(a.val, b.val), c.val)); } \ + inline _Tpvec v_muladd(const _Tpvec& a, const _Tpvec& b, const _Tpvec& c) \ + { return _Tpvec(_mm512_add_##suffix(_mm512_mul_##suffix(a.val, b.val), c.val)); } +#endif + +#define OPENCV_HAL_IMPL_AVX512_MISC(_Tpvec, suffix) \ + inline _Tpvec v_sqrt(const _Tpvec& x) \ + { return _Tpvec(_mm512_sqrt_##suffix(x.val)); } \ + inline _Tpvec v_sqr_magnitude(const _Tpvec& a, const _Tpvec& b) \ + { return v_fma(a, a, b * b); } \ + inline _Tpvec v_magnitude(const _Tpvec& a, const _Tpvec& b) \ + { return v_sqrt(v_fma(a, a, b * b)); } + +OPENCV_HAL_IMPL_AVX512_MULADD(v_float32x16, ps) +OPENCV_HAL_IMPL_AVX512_MULADD(v_float64x8, pd) +OPENCV_HAL_IMPL_AVX512_MISC(v_float32x16, ps) +OPENCV_HAL_IMPL_AVX512_MISC(v_float64x8, pd) + +inline v_int32x16 v_fma(const v_int32x16& a, const v_int32x16& b, const v_int32x16& c) +{ return a * b + c; } +inline v_int32x16 v_muladd(const v_int32x16& a, const v_int32x16& b, const v_int32x16& c) +{ return v_fma(a, b, c); } + +inline v_float32x16 v_invsqrt(const v_float32x16& x) +{ +#if CV_AVX_512ER + return v_float32x16(_mm512_rsqrt28_ps(x.val)); +#else + v_float32x16 half = x * v512_setall_f32(0.5); + v_float32x16 t = v_float32x16(_mm512_rsqrt14_ps(x.val)); + t *= v512_setall_f32(1.5) - ((t * t) * half); + return t; +#endif +} + +inline v_float64x8 v_invsqrt(const v_float64x8& x) +{ +#if CV_AVX_512ER + return v_float64x8(_mm512_rsqrt28_pd(x.val)); +#else + return v512_setall_f64(1.) / v_sqrt(x); +// v_float64x8 half = x * v512_setall_f64(0.5); +// v_float64x8 t = v_float64x8(_mm512_rsqrt14_pd(x.val)); +// t *= v512_setall_f64(1.5) - ((t * t) * half); +// t *= v512_setall_f64(1.5) - ((t * t) * half); +// return t; +#endif +} + +/** Absolute values **/ +#define OPENCV_HAL_IMPL_AVX512_ABS(_Tpvec, _Tpuvec, suffix) \ + inline _Tpuvec v_abs(const _Tpvec& x) \ + { return _Tpuvec(_mm512_abs_##suffix(x.val)); } + +OPENCV_HAL_IMPL_AVX512_ABS(v_int8x64, v_uint8x64, epi8) +OPENCV_HAL_IMPL_AVX512_ABS(v_int16x32, v_uint16x32, epi16) +OPENCV_HAL_IMPL_AVX512_ABS(v_int32x16, v_uint32x16, epi32) +OPENCV_HAL_IMPL_AVX512_ABS(v_int64x8, v_uint64x8, epi64) + +inline v_float32x16 v_abs(const v_float32x16& x) +{ +#ifdef _mm512_abs_pd + return v_float32x16(_mm512_abs_ps(x.val)); +#else + return v_float32x16(_mm512_castsi512_ps(_mm512_and_si512(_mm512_castps_si512(x.val), + _v512_set_epu64(0x7FFFFFFF7FFFFFFF, 0x7FFFFFFF7FFFFFFF, 0x7FFFFFFF7FFFFFFF, 0x7FFFFFFF7FFFFFFF, + 0x7FFFFFFF7FFFFFFF, 0x7FFFFFFF7FFFFFFF, 0x7FFFFFFF7FFFFFFF, 0x7FFFFFFF7FFFFFFF)))); +#endif +} + +inline v_float64x8 v_abs(const v_float64x8& x) +{ +#ifdef _mm512_abs_pd + #if defined __GNUC__ && (__GNUC__ < 7 || (__GNUC__ == 7 && __GNUC_MINOR__ <= 3) || (__GNUC__ == 8 && __GNUC_MINOR__ <= 2)) + // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87476 + return v_float64x8(_mm512_abs_pd(_mm512_castpd_ps(x.val))); + #else + return v_float64x8(_mm512_abs_pd(x.val)); + #endif +#else + return v_float64x8(_mm512_castsi512_pd(_mm512_and_si512(_mm512_castpd_si512(x.val), + _v512_set_epu64(0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, + 0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF)))); +#endif +} + +/** Absolute difference **/ +inline v_uint8x64 v_absdiff(const v_uint8x64& a, const v_uint8x64& b) +{ return v_add_wrap(a - b, b - a); } +inline v_uint16x32 v_absdiff(const v_uint16x32& a, const v_uint16x32& b) +{ return v_add_wrap(a - b, b - a); } +inline v_uint32x16 v_absdiff(const v_uint32x16& a, const v_uint32x16& b) +{ return v_max(a, b) - v_min(a, b); } + +inline v_uint8x64 v_absdiff(const v_int8x64& a, const v_int8x64& b) +{ + v_int8x64 d = v_sub_wrap(a, b); + v_int8x64 m = a < b; + return v_reinterpret_as_u8(v_sub_wrap(d ^ m, m)); +} + +inline v_uint16x32 v_absdiff(const v_int16x32& a, const v_int16x32& b) +{ return v_reinterpret_as_u16(v_sub_wrap(v_max(a, b), v_min(a, b))); } + +inline v_uint32x16 v_absdiff(const v_int32x16& a, const v_int32x16& b) +{ + v_int32x16 d = a - b; + v_int32x16 m = a < b; + return v_reinterpret_as_u32((d ^ m) - m); +} + +inline v_float32x16 v_absdiff(const v_float32x16& a, const v_float32x16& b) +{ return v_abs(a - b); } + +inline v_float64x8 v_absdiff(const v_float64x8& a, const v_float64x8& b) +{ return v_abs(a - b); } + +/** Saturating absolute difference **/ +inline v_int8x64 v_absdiffs(const v_int8x64& a, const v_int8x64& b) +{ + v_int8x64 d = a - b; + v_int8x64 m = a < b; + return (d ^ m) - m; +} +inline v_int16x32 v_absdiffs(const v_int16x32& a, const v_int16x32& b) +{ return v_max(a, b) - v_min(a, b); } + +////////// Conversions ///////// + +/** Rounding **/ +inline v_int32x16 v_round(const v_float32x16& a) +{ return v_int32x16(_mm512_cvtps_epi32(a.val)); } + +inline v_int32x16 v_round(const v_float64x8& a) +{ return v_int32x16(_mm512_castsi256_si512(_mm512_cvtpd_epi32(a.val))); } + +inline v_int32x16 v_round(const v_float64x8& a, const v_float64x8& b) +{ return v_int32x16(_v512_combine(_mm512_cvtpd_epi32(a.val), _mm512_cvtpd_epi32(b.val))); } + +inline v_int32x16 v_trunc(const v_float32x16& a) +{ return v_int32x16(_mm512_cvttps_epi32(a.val)); } + +inline v_int32x16 v_trunc(const v_float64x8& a) +{ return v_int32x16(_mm512_castsi256_si512(_mm512_cvttpd_epi32(a.val))); } + +#if CVT_ROUND_MODES_IMPLEMENTED +inline v_int32x16 v_floor(const v_float32x16& a) +{ return v_int32x16(_mm512_cvt_roundps_epi32(a.val, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC)); } + +inline v_int32x16 v_floor(const v_float64x8& a) +{ return v_int32x16(_mm512_castsi256_si512(_mm512_cvt_roundpd_epi32(a.val, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC))); } + +inline v_int32x16 v_ceil(const v_float32x16& a) +{ return v_int32x16(_mm512_cvt_roundps_epi32(a.val, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC)); } + +inline v_int32x16 v_ceil(const v_float64x8& a) +{ return v_int32x16(_mm512_castsi256_si512(_mm512_cvt_roundpd_epi32(a.val, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC))); } +#else +inline v_int32x16 v_floor(const v_float32x16& a) +{ return v_int32x16(_mm512_cvtps_epi32(_mm512_roundscale_ps(a.val, 1))); } + +inline v_int32x16 v_floor(const v_float64x8& a) +{ return v_int32x16(_mm512_castsi256_si512(_mm512_cvtpd_epi32(_mm512_roundscale_pd(a.val, 1)))); } + +inline v_int32x16 v_ceil(const v_float32x16& a) +{ return v_int32x16(_mm512_cvtps_epi32(_mm512_roundscale_ps(a.val, 2))); } + +inline v_int32x16 v_ceil(const v_float64x8& a) +{ return v_int32x16(_mm512_castsi256_si512(_mm512_cvtpd_epi32(_mm512_roundscale_pd(a.val, 2)))); } +#endif + +/** To float **/ +inline v_float32x16 v_cvt_f32(const v_int32x16& a) +{ return v_float32x16(_mm512_cvtepi32_ps(a.val)); } + +inline v_float32x16 v_cvt_f32(const v_float64x8& a) +{ return v_float32x16(_mm512_cvtpd_pslo(a.val)); } + +inline v_float32x16 v_cvt_f32(const v_float64x8& a, const v_float64x8& b) +{ return v_float32x16(_v512_combine(_mm512_cvtpd_ps(a.val), _mm512_cvtpd_ps(b.val))); } + +inline v_float64x8 v_cvt_f64(const v_int32x16& a) +{ return v_float64x8(_mm512_cvtepi32_pd(_v512_extract_low(a.val))); } + +inline v_float64x8 v_cvt_f64_high(const v_int32x16& a) +{ return v_float64x8(_mm512_cvtepi32_pd(_v512_extract_high(a.val))); } + +inline v_float64x8 v_cvt_f64(const v_float32x16& a) +{ return v_float64x8(_mm512_cvtps_pd(_v512_extract_low(a.val))); } + +inline v_float64x8 v_cvt_f64_high(const v_float32x16& a) +{ return v_float64x8(_mm512_cvtps_pd(_v512_extract_high(a.val))); } + +// from (Mysticial and wim) https://stackoverflow.com/q/41144668 +inline v_float64x8 v_cvt_f64(const v_int64x8& v) +{ +#if CV_AVX_512DQ + return v_float64x8(_mm512_cvtepi64_pd(v.val)); +#else + // constants encoded as floating-point + __m512i magic_i_lo = _mm512_set1_epi64(0x4330000000000000); // 2^52 + __m512i magic_i_hi32 = _mm512_set1_epi64(0x4530000080000000); // 2^84 + 2^63 + __m512i magic_i_all = _mm512_set1_epi64(0x4530000080100000); // 2^84 + 2^63 + 2^52 + __m512d magic_d_all = _mm512_castsi512_pd(magic_i_all); + + // Blend the 32 lowest significant bits of v with magic_int_lo + __m512i v_lo = _mm512_mask_blend_epi32(0x5555, magic_i_lo, v.val); + // Extract the 32 most significant bits of v + __m512i v_hi = _mm512_srli_epi64(v.val, 32); + // Flip the msb of v_hi and blend with 0x45300000 + v_hi = _mm512_xor_si512(v_hi, magic_i_hi32); + // Compute in double precision + __m512d v_hi_dbl = _mm512_sub_pd(_mm512_castsi512_pd(v_hi), magic_d_all); + // (v_hi - magic_d_all) + v_lo Do not assume associativity of floating point addition + __m512d result = _mm512_add_pd(v_hi_dbl, _mm512_castsi512_pd(v_lo)); + return v_float64x8(result); +#endif +} + +////////////// Lookup table access //////////////////// + +inline v_int8x64 v512_lut(const schar* tab, const int* idx) +{ + __m128i p0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_mm512_loadu_si512((const __m512i*)idx ), (const int *)tab, 1)); + __m128i p1 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_mm512_loadu_si512((const __m512i*)idx + 1), (const int *)tab, 1)); + __m128i p2 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_mm512_loadu_si512((const __m512i*)idx + 2), (const int *)tab, 1)); + __m128i p3 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_mm512_loadu_si512((const __m512i*)idx + 3), (const int *)tab, 1)); + return v_int8x64(_mm512_inserti32x4(_mm512_inserti32x4(_mm512_inserti32x4(_mm512_castsi128_si512(p0), p1, 1), p2, 2), p3, 3)); +} +inline v_int8x64 v512_lut_pairs(const schar* tab, const int* idx) +{ + __m256i p0 = _mm512_cvtepi32_epi16(_mm512_i32gather_epi32(_mm512_loadu_si512((const __m512i*)idx ), (const int *)tab, 1)); + __m256i p1 = _mm512_cvtepi32_epi16(_mm512_i32gather_epi32(_mm512_loadu_si512((const __m512i*)idx + 1), (const int *)tab, 1)); + return v_int8x64(_v512_combine(p0, p1)); +} +inline v_int8x64 v512_lut_quads(const schar* tab, const int* idx) +{ + return v_int8x64(_mm512_i32gather_epi32(_mm512_loadu_si512((const __m512i*)idx), (const int *)tab, 1)); +} +inline v_uint8x64 v512_lut(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v512_lut((const schar *)tab, idx)); } +inline v_uint8x64 v512_lut_pairs(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v512_lut_pairs((const schar *)tab, idx)); } +inline v_uint8x64 v512_lut_quads(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v512_lut_quads((const schar *)tab, idx)); } + +inline v_int16x32 v512_lut(const short* tab, const int* idx) +{ + __m256i p0 = _mm512_cvtepi32_epi16(_mm512_i32gather_epi32(_mm512_loadu_si512((const __m512i*)idx ), (const int *)tab, 2)); + __m256i p1 = _mm512_cvtepi32_epi16(_mm512_i32gather_epi32(_mm512_loadu_si512((const __m512i*)idx + 1), (const int *)tab, 2)); + return v_int16x32(_v512_combine(p0, p1)); +} +inline v_int16x32 v512_lut_pairs(const short* tab, const int* idx) +{ + return v_int16x32(_mm512_i32gather_epi32(_mm512_loadu_si512((const __m512i*)idx), (const int *)tab, 2)); +} +inline v_int16x32 v512_lut_quads(const short* tab, const int* idx) +{ +#if defined(__GNUC__) + return v_int16x32(_mm512_i32gather_epi64(_mm256_loadu_si256((const __m256i*)idx), (const long long int*)tab, 2)); +#else + return v_int16x32(_mm512_i32gather_epi64(_mm256_loadu_si256((const __m256i*)idx), (const int64*)tab, 2)); +#endif +} +inline v_uint16x32 v512_lut(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v512_lut((const short *)tab, idx)); } +inline v_uint16x32 v512_lut_pairs(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v512_lut_pairs((const short *)tab, idx)); } +inline v_uint16x32 v512_lut_quads(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v512_lut_quads((const short *)tab, idx)); } + +inline v_int32x16 v512_lut(const int* tab, const int* idx) +{ + return v_int32x16(_mm512_i32gather_epi32(_mm512_loadu_si512((const __m512i*)idx), tab, 4)); +} +inline v_int32x16 v512_lut_pairs(const int* tab, const int* idx) +{ +#if defined(__GNUC__) + return v_int32x16(_mm512_i32gather_epi64(_mm256_loadu_si256((const __m256i*)idx), (const long long int*)tab, 4)); +#else + return v_int32x16(_mm512_i32gather_epi64(_mm256_loadu_si256((const __m256i*)idx), (const int64*)tab, 4)); +#endif +} +inline v_int32x16 v512_lut_quads(const int* tab, const int* idx) +{ + return v_int32x16(_mm512_inserti32x4(_mm512_inserti32x4(_mm512_inserti32x4(_mm512_castsi128_si512( + _mm_loadu_si128((const __m128i*)(tab + idx[0]))), + _mm_loadu_si128((const __m128i*)(tab + idx[1])), 1), + _mm_loadu_si128((const __m128i*)(tab + idx[2])), 2), + _mm_loadu_si128((const __m128i*)(tab + idx[3])), 3)); +} +inline v_uint32x16 v512_lut(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v512_lut((const int *)tab, idx)); } +inline v_uint32x16 v512_lut_pairs(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v512_lut_pairs((const int *)tab, idx)); } +inline v_uint32x16 v512_lut_quads(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v512_lut_quads((const int *)tab, idx)); } + +inline v_int64x8 v512_lut(const int64* tab, const int* idx) +{ +#if defined(__GNUC__) + return v_int64x8(_mm512_i32gather_epi64(_mm256_loadu_si256((const __m256i*)idx), (const long long int*)tab, 8)); +#else + return v_int64x8(_mm512_i32gather_epi64(_mm256_loadu_si256((const __m256i*)idx), tab , 8)); +#endif +} +inline v_int64x8 v512_lut_pairs(const int64* tab, const int* idx) +{ + return v_int64x8(_mm512_inserti32x4(_mm512_inserti32x4(_mm512_inserti32x4(_mm512_castsi128_si512( + _mm_loadu_si128((const __m128i*)(tab + idx[0]))), + _mm_loadu_si128((const __m128i*)(tab + idx[1])), 1), + _mm_loadu_si128((const __m128i*)(tab + idx[2])), 2), + _mm_loadu_si128((const __m128i*)(tab + idx[3])), 3)); +} +inline v_uint64x8 v512_lut(const uint64* tab, const int* idx) { return v_reinterpret_as_u64(v512_lut((const int64 *)tab, idx)); } +inline v_uint64x8 v512_lut_pairs(const uint64* tab, const int* idx) { return v_reinterpret_as_u64(v512_lut_pairs((const int64 *)tab, idx)); } + +inline v_float32x16 v512_lut(const float* tab, const int* idx) +{ + return v_float32x16(_mm512_i32gather_ps(_mm512_loadu_si512((const __m512i*)idx), tab, 4)); +} +inline v_float32x16 v512_lut_pairs(const float* tab, const int* idx) { return v_reinterpret_as_f32(v512_lut_pairs((const int *)tab, idx)); } +inline v_float32x16 v512_lut_quads(const float* tab, const int* idx) { return v_reinterpret_as_f32(v512_lut_quads((const int *)tab, idx)); } + +inline v_float64x8 v512_lut(const double* tab, const int* idx) +{ + return v_float64x8(_mm512_i32gather_pd(_mm256_loadu_si256((const __m256i*)idx), tab, 8)); +} +inline v_float64x8 v512_lut_pairs(const double* tab, const int* idx) +{ + return v_float64x8(_mm512_insertf64x2(_mm512_insertf64x2(_mm512_insertf64x2(_mm512_castpd128_pd512( + _mm_loadu_pd(tab + idx[0])), + _mm_loadu_pd(tab + idx[1]), 1), + _mm_loadu_pd(tab + idx[2]), 2), + _mm_loadu_pd(tab + idx[3]), 3)); +} + +inline v_int32x16 v_lut(const int* tab, const v_int32x16& idxvec) +{ + return v_int32x16(_mm512_i32gather_epi32(idxvec.val, tab, 4)); +} + +inline v_uint32x16 v_lut(const unsigned* tab, const v_int32x16& idxvec) +{ + return v_reinterpret_as_u32(v_lut((const int *)tab, idxvec)); +} + +inline v_float32x16 v_lut(const float* tab, const v_int32x16& idxvec) +{ + return v_float32x16(_mm512_i32gather_ps(idxvec.val, tab, 4)); +} + +inline v_float64x8 v_lut(const double* tab, const v_int32x16& idxvec) +{ + return v_float64x8(_mm512_i32gather_pd(_v512_extract_low(idxvec.val), tab, 8)); +} + +inline void v_lut_deinterleave(const float* tab, const v_int32x16& idxvec, v_float32x16& x, v_float32x16& y) +{ + x.val = _mm512_i32gather_ps(idxvec.val, tab, 4); + y.val = _mm512_i32gather_ps(idxvec.val, &tab[1], 4); +} + +inline void v_lut_deinterleave(const double* tab, const v_int32x16& idxvec, v_float64x8& x, v_float64x8& y) +{ + x.val = _mm512_i32gather_pd(_v512_extract_low(idxvec.val), tab, 8); + y.val = _mm512_i32gather_pd(_v512_extract_low(idxvec.val), &tab[1], 8); +} + +inline v_int8x64 v_interleave_pairs(const v_int8x64& vec) +{ + return v_int8x64(_mm512_shuffle_epi8(vec.val, _mm512_set4_epi32(0x0f0d0e0c, 0x0b090a08, 0x07050604, 0x03010200))); +} +inline v_uint8x64 v_interleave_pairs(const v_uint8x64& vec) { return v_reinterpret_as_u8(v_interleave_pairs(v_reinterpret_as_s8(vec))); } +inline v_int8x64 v_interleave_quads(const v_int8x64& vec) +{ + return v_int8x64(_mm512_shuffle_epi8(vec.val, _mm512_set4_epi32(0x0f0b0e0a, 0x0d090c08, 0x07030602, 0x05010400))); +} +inline v_uint8x64 v_interleave_quads(const v_uint8x64& vec) { return v_reinterpret_as_u8(v_interleave_quads(v_reinterpret_as_s8(vec))); } + +inline v_int16x32 v_interleave_pairs(const v_int16x32& vec) +{ + return v_int16x32(_mm512_shuffle_epi8(vec.val, _mm512_set4_epi32(0x0f0e0b0a, 0x0d0c0908, 0x07060302, 0x05040100))); +} +inline v_uint16x32 v_interleave_pairs(const v_uint16x32& vec) { return v_reinterpret_as_u16(v_interleave_pairs(v_reinterpret_as_s16(vec))); } +inline v_int16x32 v_interleave_quads(const v_int16x32& vec) +{ + return v_int16x32(_mm512_shuffle_epi8(vec.val, _mm512_set4_epi32(0x0f0e0706, 0x0d0c0504, 0x0b0a0302, 0x09080100))); +} +inline v_uint16x32 v_interleave_quads(const v_uint16x32& vec) { return v_reinterpret_as_u16(v_interleave_quads(v_reinterpret_as_s16(vec))); } + +inline v_int32x16 v_interleave_pairs(const v_int32x16& vec) +{ + return v_int32x16(_mm512_shuffle_epi32(vec.val, _MM_PERM_ACBD)); +} +inline v_uint32x16 v_interleave_pairs(const v_uint32x16& vec) { return v_reinterpret_as_u32(v_interleave_pairs(v_reinterpret_as_s32(vec))); } +inline v_float32x16 v_interleave_pairs(const v_float32x16& vec) { return v_reinterpret_as_f32(v_interleave_pairs(v_reinterpret_as_s32(vec))); } + +inline v_int8x64 v_pack_triplets(const v_int8x64& vec) +{ + return v_int8x64(_mm512_permutexvar_epi32(_v512_set_epu64(0x0000000f0000000f, 0x0000000f0000000f, 0x0000000e0000000d, 0x0000000c0000000a, + 0x0000000900000008, 0x0000000600000005, 0x0000000400000002, 0x0000000100000000), + _mm512_shuffle_epi8(vec.val, _mm512_set4_epi32(0xffffff0f, 0x0e0d0c0a, 0x09080605, 0x04020100)))); +} +inline v_uint8x64 v_pack_triplets(const v_uint8x64& vec) { return v_reinterpret_as_u8(v_pack_triplets(v_reinterpret_as_s8(vec))); } + +inline v_int16x32 v_pack_triplets(const v_int16x32& vec) +{ + return v_int16x32(_mm512_permutexvar_epi16(_v512_set_epu64(0x001f001f001f001f, 0x001f001f001f001f, 0x001e001d001c001a, 0x0019001800160015, + 0x0014001200110010, 0x000e000d000c000a, 0x0009000800060005, 0x0004000200010000), vec.val)); +} +inline v_uint16x32 v_pack_triplets(const v_uint16x32& vec) { return v_reinterpret_as_u16(v_pack_triplets(v_reinterpret_as_s16(vec))); } + +inline v_int32x16 v_pack_triplets(const v_int32x16& vec) +{ + return v_int32x16(_mm512_permutexvar_epi32(_v512_set_epu64(0x0000000f0000000f, 0x0000000f0000000f, 0x0000000e0000000d, 0x0000000c0000000a, + 0x0000000900000008, 0x0000000600000005, 0x0000000400000002, 0x0000000100000000), vec.val)); +} +inline v_uint32x16 v_pack_triplets(const v_uint32x16& vec) { return v_reinterpret_as_u32(v_pack_triplets(v_reinterpret_as_s32(vec))); } +inline v_float32x16 v_pack_triplets(const v_float32x16& vec) +{ + return v_float32x16(_mm512_permutexvar_ps(_v512_set_epu64(0x0000000f0000000f, 0x0000000f0000000f, 0x0000000e0000000d, 0x0000000c0000000a, + 0x0000000900000008, 0x0000000600000005, 0x0000000400000002, 0x0000000100000000), vec.val)); +} + +////////// Matrix operations ///////// + +//////// Dot Product //////// + +// 16 >> 32 +inline v_int32x16 v_dotprod(const v_int16x32& a, const v_int16x32& b) +{ return v_int32x16(_mm512_madd_epi16(a.val, b.val)); } +inline v_int32x16 v_dotprod(const v_int16x32& a, const v_int16x32& b, const v_int32x16& c) +{ return v_dotprod(a, b) + c; } + +// 32 >> 64 +inline v_int64x8 v_dotprod(const v_int32x16& a, const v_int32x16& b) +{ + __m512i even = _mm512_mul_epi32(a.val, b.val); + __m512i odd = _mm512_mul_epi32(_mm512_srli_epi64(a.val, 32), _mm512_srli_epi64(b.val, 32)); + return v_int64x8(_mm512_add_epi64(even, odd)); +} +inline v_int64x8 v_dotprod(const v_int32x16& a, const v_int32x16& b, const v_int64x8& c) +{ return v_dotprod(a, b) + c; } + +// 8 >> 32 +inline v_uint32x16 v_dotprod_expand(const v_uint8x64& a, const v_uint8x64& b) +{ + __m512i even_a = _mm512_mask_blend_epi8(0xAAAAAAAAAAAAAAAA, a.val, _mm512_setzero_si512()); + __m512i odd_a = _mm512_srli_epi16(a.val, 8); + + __m512i even_b = _mm512_mask_blend_epi8(0xAAAAAAAAAAAAAAAA, b.val, _mm512_setzero_si512()); + __m512i odd_b = _mm512_srli_epi16(b.val, 8); + + __m512i prod0 = _mm512_madd_epi16(even_a, even_b); + __m512i prod1 = _mm512_madd_epi16(odd_a, odd_b); + return v_uint32x16(_mm512_add_epi32(prod0, prod1)); +} +inline v_uint32x16 v_dotprod_expand(const v_uint8x64& a, const v_uint8x64& b, const v_uint32x16& c) +{ return v_dotprod_expand(a, b) + c; } + +inline v_int32x16 v_dotprod_expand(const v_int8x64& a, const v_int8x64& b) +{ + __m512i even_a = _mm512_srai_epi16(_mm512_bslli_epi128(a.val, 1), 8); + __m512i odd_a = _mm512_srai_epi16(a.val, 8); + + __m512i even_b = _mm512_srai_epi16(_mm512_bslli_epi128(b.val, 1), 8); + __m512i odd_b = _mm512_srai_epi16(b.val, 8); + + __m512i prod0 = _mm512_madd_epi16(even_a, even_b); + __m512i prod1 = _mm512_madd_epi16(odd_a, odd_b); + return v_int32x16(_mm512_add_epi32(prod0, prod1)); +} +inline v_int32x16 v_dotprod_expand(const v_int8x64& a, const v_int8x64& b, const v_int32x16& c) +{ return v_dotprod_expand(a, b) + c; } + +// 16 >> 64 +inline v_uint64x8 v_dotprod_expand(const v_uint16x32& a, const v_uint16x32& b) +{ + __m512i mullo = _mm512_mullo_epi16(a.val, b.val); + __m512i mulhi = _mm512_mulhi_epu16(a.val, b.val); + __m512i mul0 = _mm512_unpacklo_epi16(mullo, mulhi); + __m512i mul1 = _mm512_unpackhi_epi16(mullo, mulhi); + + __m512i p02 = _mm512_mask_blend_epi32(0xAAAA, mul0, _mm512_setzero_si512()); + __m512i p13 = _mm512_srli_epi64(mul0, 32); + __m512i p46 = _mm512_mask_blend_epi32(0xAAAA, mul1, _mm512_setzero_si512()); + __m512i p57 = _mm512_srli_epi64(mul1, 32); + + __m512i p15_ = _mm512_add_epi64(p02, p13); + __m512i p9d_ = _mm512_add_epi64(p46, p57); + + return v_uint64x8(_mm512_add_epi64( + _mm512_unpacklo_epi64(p15_, p9d_), + _mm512_unpackhi_epi64(p15_, p9d_) + )); +} +inline v_uint64x8 v_dotprod_expand(const v_uint16x32& a, const v_uint16x32& b, const v_uint64x8& c) +{ return v_dotprod_expand(a, b) + c; } + +inline v_int64x8 v_dotprod_expand(const v_int16x32& a, const v_int16x32& b) +{ + __m512i prod = _mm512_madd_epi16(a.val, b.val); + __m512i even = _mm512_srai_epi64(_mm512_bslli_epi128(prod, 4), 32); + __m512i odd = _mm512_srai_epi64(prod, 32); + return v_int64x8(_mm512_add_epi64(even, odd)); +} +inline v_int64x8 v_dotprod_expand(const v_int16x32& a, const v_int16x32& b, const v_int64x8& c) +{ return v_dotprod_expand(a, b) + c; } + +// 32 >> 64f +inline v_float64x8 v_dotprod_expand(const v_int32x16& a, const v_int32x16& b) +{ return v_cvt_f64(v_dotprod(a, b)); } +inline v_float64x8 v_dotprod_expand(const v_int32x16& a, const v_int32x16& b, const v_float64x8& c) +{ return v_dotprod_expand(a, b) + c; } + +//////// Fast Dot Product //////// + +// 16 >> 32 +inline v_int32x16 v_dotprod_fast(const v_int16x32& a, const v_int16x32& b) +{ return v_dotprod(a, b); } +inline v_int32x16 v_dotprod_fast(const v_int16x32& a, const v_int16x32& b, const v_int32x16& c) +{ return v_dotprod(a, b, c); } + +// 32 >> 64 +inline v_int64x8 v_dotprod_fast(const v_int32x16& a, const v_int32x16& b) +{ return v_dotprod(a, b); } +inline v_int64x8 v_dotprod_fast(const v_int32x16& a, const v_int32x16& b, const v_int64x8& c) +{ return v_dotprod(a, b, c); } + +// 8 >> 32 +inline v_uint32x16 v_dotprod_expand_fast(const v_uint8x64& a, const v_uint8x64& b) +{ return v_dotprod_expand(a, b); } +inline v_uint32x16 v_dotprod_expand_fast(const v_uint8x64& a, const v_uint8x64& b, const v_uint32x16& c) +{ return v_dotprod_expand(a, b, c); } + +inline v_int32x16 v_dotprod_expand_fast(const v_int8x64& a, const v_int8x64& b) +{ return v_dotprod_expand(a, b); } +inline v_int32x16 v_dotprod_expand_fast(const v_int8x64& a, const v_int8x64& b, const v_int32x16& c) +{ return v_dotprod_expand(a, b, c); } + +// 16 >> 64 +inline v_uint64x8 v_dotprod_expand_fast(const v_uint16x32& a, const v_uint16x32& b) +{ + __m512i mullo = _mm512_mullo_epi16(a.val, b.val); + __m512i mulhi = _mm512_mulhi_epu16(a.val, b.val); + __m512i mul0 = _mm512_unpacklo_epi16(mullo, mulhi); + __m512i mul1 = _mm512_unpackhi_epi16(mullo, mulhi); + + __m512i p02 = _mm512_mask_blend_epi32(0xAAAA, mul0, _mm512_setzero_si512()); + __m512i p13 = _mm512_srli_epi64(mul0, 32); + __m512i p46 = _mm512_mask_blend_epi32(0xAAAA, mul1, _mm512_setzero_si512()); + __m512i p57 = _mm512_srli_epi64(mul1, 32); + + __m512i p15_ = _mm512_add_epi64(p02, p13); + __m512i p9d_ = _mm512_add_epi64(p46, p57); + return v_uint64x8(_mm512_add_epi64(p15_, p9d_)); +} +inline v_uint64x8 v_dotprod_expand_fast(const v_uint16x32& a, const v_uint16x32& b, const v_uint64x8& c) +{ return v_dotprod_expand_fast(a, b) + c; } + +inline v_int64x8 v_dotprod_expand_fast(const v_int16x32& a, const v_int16x32& b) +{ return v_dotprod_expand(a, b); } +inline v_int64x8 v_dotprod_expand_fast(const v_int16x32& a, const v_int16x32& b, const v_int64x8& c) +{ return v_dotprod_expand(a, b, c); } + +// 32 >> 64f +inline v_float64x8 v_dotprod_expand_fast(const v_int32x16& a, const v_int32x16& b) +{ return v_dotprod_expand(a, b); } +inline v_float64x8 v_dotprod_expand_fast(const v_int32x16& a, const v_int32x16& b, const v_float64x8& c) +{ return v_dotprod_expand(a, b) + c; } + + +#define OPENCV_HAL_AVX512_SPLAT2_PS(a, im) \ + v_float32x16(_mm512_permute_ps(a.val, _MM_SHUFFLE(im, im, im, im))) + +inline v_float32x16 v_matmul(const v_float32x16& v, + const v_float32x16& m0, const v_float32x16& m1, + const v_float32x16& m2, const v_float32x16& m3) +{ + v_float32x16 v04 = OPENCV_HAL_AVX512_SPLAT2_PS(v, 0); + v_float32x16 v15 = OPENCV_HAL_AVX512_SPLAT2_PS(v, 1); + v_float32x16 v26 = OPENCV_HAL_AVX512_SPLAT2_PS(v, 2); + v_float32x16 v37 = OPENCV_HAL_AVX512_SPLAT2_PS(v, 3); + return v_fma(v04, m0, v_fma(v15, m1, v_fma(v26, m2, v37 * m3))); +} + +inline v_float32x16 v_matmuladd(const v_float32x16& v, + const v_float32x16& m0, const v_float32x16& m1, + const v_float32x16& m2, const v_float32x16& a) +{ + v_float32x16 v04 = OPENCV_HAL_AVX512_SPLAT2_PS(v, 0); + v_float32x16 v15 = OPENCV_HAL_AVX512_SPLAT2_PS(v, 1); + v_float32x16 v26 = OPENCV_HAL_AVX512_SPLAT2_PS(v, 2); + return v_fma(v04, m0, v_fma(v15, m1, v_fma(v26, m2, a))); +} + +#define OPENCV_HAL_IMPL_AVX512_TRANSPOSE4x4(_Tpvec, suffix, cast_from, cast_to) \ + inline void v_transpose4x4(const _Tpvec& a0, const _Tpvec& a1, \ + const _Tpvec& a2, const _Tpvec& a3, \ + _Tpvec& b0, _Tpvec& b1, _Tpvec& b2, _Tpvec& b3) \ + { \ + __m512i t0 = cast_from(_mm512_unpacklo_##suffix(a0.val, a1.val)); \ + __m512i t1 = cast_from(_mm512_unpacklo_##suffix(a2.val, a3.val)); \ + __m512i t2 = cast_from(_mm512_unpackhi_##suffix(a0.val, a1.val)); \ + __m512i t3 = cast_from(_mm512_unpackhi_##suffix(a2.val, a3.val)); \ + b0.val = cast_to(_mm512_unpacklo_epi64(t0, t1)); \ + b1.val = cast_to(_mm512_unpackhi_epi64(t0, t1)); \ + b2.val = cast_to(_mm512_unpacklo_epi64(t2, t3)); \ + b3.val = cast_to(_mm512_unpackhi_epi64(t2, t3)); \ + } + +OPENCV_HAL_IMPL_AVX512_TRANSPOSE4x4(v_uint32x16, epi32, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_AVX512_TRANSPOSE4x4(v_int32x16, epi32, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_AVX512_TRANSPOSE4x4(v_float32x16, ps, _mm512_castps_si512, _mm512_castsi512_ps) + +//////////////// Value reordering /////////////// + +/* Expand */ +#define OPENCV_HAL_IMPL_AVX512_EXPAND(_Tpvec, _Tpwvec, _Tp, intrin) \ + inline void v_expand(const _Tpvec& a, _Tpwvec& b0, _Tpwvec& b1) \ + { \ + b0.val = intrin(_v512_extract_low(a.val)); \ + b1.val = intrin(_v512_extract_high(a.val)); \ + } \ + inline _Tpwvec v_expand_low(const _Tpvec& a) \ + { return _Tpwvec(intrin(_v512_extract_low(a.val))); } \ + inline _Tpwvec v_expand_high(const _Tpvec& a) \ + { return _Tpwvec(intrin(_v512_extract_high(a.val))); } \ + inline _Tpwvec v512_load_expand(const _Tp* ptr) \ + { \ + __m256i a = _mm256_loadu_si256((const __m256i*)ptr); \ + return _Tpwvec(intrin(a)); \ + } + +OPENCV_HAL_IMPL_AVX512_EXPAND(v_uint8x64, v_uint16x32, uchar, _mm512_cvtepu8_epi16) +OPENCV_HAL_IMPL_AVX512_EXPAND(v_int8x64, v_int16x32, schar, _mm512_cvtepi8_epi16) +OPENCV_HAL_IMPL_AVX512_EXPAND(v_uint16x32, v_uint32x16, ushort, _mm512_cvtepu16_epi32) +OPENCV_HAL_IMPL_AVX512_EXPAND(v_int16x32, v_int32x16, short, _mm512_cvtepi16_epi32) +OPENCV_HAL_IMPL_AVX512_EXPAND(v_uint32x16, v_uint64x8, unsigned, _mm512_cvtepu32_epi64) +OPENCV_HAL_IMPL_AVX512_EXPAND(v_int32x16, v_int64x8, int, _mm512_cvtepi32_epi64) + +#define OPENCV_HAL_IMPL_AVX512_EXPAND_Q(_Tpvec, _Tp, intrin) \ + inline _Tpvec v512_load_expand_q(const _Tp* ptr) \ + { \ + __m128i a = _mm_loadu_si128((const __m128i*)ptr); \ + return _Tpvec(intrin(a)); \ + } + +OPENCV_HAL_IMPL_AVX512_EXPAND_Q(v_uint32x16, uchar, _mm512_cvtepu8_epi32) +OPENCV_HAL_IMPL_AVX512_EXPAND_Q(v_int32x16, schar, _mm512_cvtepi8_epi32) + +/* pack */ +// 16 +inline v_int8x64 v_pack(const v_int16x32& a, const v_int16x32& b) +{ return v_int8x64(_mm512_permutexvar_epi64(_v512_set_epu64(7, 5, 3, 1, 6, 4, 2, 0), _mm512_packs_epi16(a.val, b.val))); } + +inline v_uint8x64 v_pack(const v_uint16x32& a, const v_uint16x32& b) +{ + const __m512i t = _mm512_set1_epi16(255); + return v_uint8x64(_v512_combine(_mm512_cvtepi16_epi8(_mm512_min_epu16(a.val, t)), _mm512_cvtepi16_epi8(_mm512_min_epu16(b.val, t)))); +} + +inline v_uint8x64 v_pack_u(const v_int16x32& a, const v_int16x32& b) +{ + return v_uint8x64(_mm512_permutexvar_epi64(_v512_set_epu64(7, 5, 3, 1, 6, 4, 2, 0), _mm512_packus_epi16(a.val, b.val))); +} + +inline void v_pack_store(schar* ptr, const v_int16x32& a) +{ v_store_low(ptr, v_pack(a, a)); } + +inline void v_pack_store(uchar* ptr, const v_uint16x32& a) +{ + const __m512i m = _mm512_set1_epi16(255); + _mm256_storeu_si256((__m256i*)ptr, _mm512_cvtepi16_epi8(_mm512_min_epu16(a.val, m))); +} + +inline void v_pack_u_store(uchar* ptr, const v_int16x32& a) +{ v_store_low(ptr, v_pack_u(a, a)); } + +template inline +v_uint8x64 v_rshr_pack(const v_uint16x32& a, const v_uint16x32& b) +{ + // we assume that n > 0, and so the shifted 16-bit values can be treated as signed numbers. + v_uint16x32 delta = v512_setall_u16((short)(1 << (n-1))); + return v_pack_u(v_reinterpret_as_s16((a + delta) >> n), + v_reinterpret_as_s16((b + delta) >> n)); +} + +template inline +void v_rshr_pack_store(uchar* ptr, const v_uint16x32& a) +{ + v_uint16x32 delta = v512_setall_u16((short)(1 << (n-1))); + v_pack_u_store(ptr, v_reinterpret_as_s16((a + delta) >> n)); +} + +template inline +v_uint8x64 v_rshr_pack_u(const v_int16x32& a, const v_int16x32& b) +{ + v_int16x32 delta = v512_setall_s16((short)(1 << (n-1))); + return v_pack_u((a + delta) >> n, (b + delta) >> n); +} + +template inline +void v_rshr_pack_u_store(uchar* ptr, const v_int16x32& a) +{ + v_int16x32 delta = v512_setall_s16((short)(1 << (n-1))); + v_pack_u_store(ptr, (a + delta) >> n); +} + +template inline +v_int8x64 v_rshr_pack(const v_int16x32& a, const v_int16x32& b) +{ + v_int16x32 delta = v512_setall_s16((short)(1 << (n-1))); + return v_pack((a + delta) >> n, (b + delta) >> n); +} + +template inline +void v_rshr_pack_store(schar* ptr, const v_int16x32& a) +{ + v_int16x32 delta = v512_setall_s16((short)(1 << (n-1))); + v_pack_store(ptr, (a + delta) >> n); +} + +// 32 +inline v_int16x32 v_pack(const v_int32x16& a, const v_int32x16& b) +{ return v_int16x32(_mm512_permutexvar_epi64(_v512_set_epu64(7, 5, 3, 1, 6, 4, 2, 0), _mm512_packs_epi32(a.val, b.val))); } + +inline v_uint16x32 v_pack(const v_uint32x16& a, const v_uint32x16& b) +{ + const __m512i m = _mm512_set1_epi32(65535); + return v_uint16x32(_v512_combine(_mm512_cvtepi32_epi16(_mm512_min_epu32(a.val, m)), _mm512_cvtepi32_epi16(_mm512_min_epu32(b.val, m)))); +} + +inline v_uint16x32 v_pack_u(const v_int32x16& a, const v_int32x16& b) +{ return v_uint16x32(_mm512_permutexvar_epi64(_v512_set_epu64(7, 5, 3, 1, 6, 4, 2, 0), _mm512_packus_epi32(a.val, b.val))); } + +inline void v_pack_store(short* ptr, const v_int32x16& a) +{ v_store_low(ptr, v_pack(a, a)); } + +inline void v_pack_store(ushort* ptr, const v_uint32x16& a) +{ + const __m512i m = _mm512_set1_epi32(65535); + _mm256_storeu_si256((__m256i*)ptr, _mm512_cvtepi32_epi16(_mm512_min_epu32(a.val, m))); +} + +inline void v_pack_u_store(ushort* ptr, const v_int32x16& a) +{ v_store_low(ptr, v_pack_u(a, a)); } + + +template inline +v_uint16x32 v_rshr_pack(const v_uint32x16& a, const v_uint32x16& b) +{ + v_uint32x16 delta = v512_setall_u32(1 << (n-1)); + return v_pack_u(v_reinterpret_as_s32((a + delta) >> n), + v_reinterpret_as_s32((b + delta) >> n)); +} + +template inline +void v_rshr_pack_store(ushort* ptr, const v_uint32x16& a) +{ + v_uint32x16 delta = v512_setall_u32(1 << (n-1)); + v_pack_u_store(ptr, v_reinterpret_as_s32((a + delta) >> n)); +} + +template inline +v_uint16x32 v_rshr_pack_u(const v_int32x16& a, const v_int32x16& b) +{ + v_int32x16 delta = v512_setall_s32(1 << (n-1)); + return v_pack_u((a + delta) >> n, (b + delta) >> n); +} + +template inline +void v_rshr_pack_u_store(ushort* ptr, const v_int32x16& a) +{ + v_int32x16 delta = v512_setall_s32(1 << (n-1)); + v_pack_u_store(ptr, (a + delta) >> n); +} + +template inline +v_int16x32 v_rshr_pack(const v_int32x16& a, const v_int32x16& b) +{ + v_int32x16 delta = v512_setall_s32(1 << (n-1)); + return v_pack((a + delta) >> n, (b + delta) >> n); +} + +template inline +void v_rshr_pack_store(short* ptr, const v_int32x16& a) +{ + v_int32x16 delta = v512_setall_s32(1 << (n-1)); + v_pack_store(ptr, (a + delta) >> n); +} + +// 64 +// Non-saturating pack +inline v_uint32x16 v_pack(const v_uint64x8& a, const v_uint64x8& b) +{ return v_uint32x16(_v512_combine(_mm512_cvtepi64_epi32(a.val), _mm512_cvtepi64_epi32(b.val))); } + +inline v_int32x16 v_pack(const v_int64x8& a, const v_int64x8& b) +{ return v_reinterpret_as_s32(v_pack(v_reinterpret_as_u64(a), v_reinterpret_as_u64(b))); } + +inline void v_pack_store(unsigned* ptr, const v_uint64x8& a) +{ _mm256_storeu_si256((__m256i*)ptr, _mm512_cvtepi64_epi32(a.val)); } + +inline void v_pack_store(int* ptr, const v_int64x8& b) +{ v_pack_store((unsigned*)ptr, v_reinterpret_as_u64(b)); } + +template inline +v_uint32x16 v_rshr_pack(const v_uint64x8& a, const v_uint64x8& b) +{ + v_uint64x8 delta = v512_setall_u64((uint64)1 << (n-1)); + return v_pack((a + delta) >> n, (b + delta) >> n); +} + +template inline +void v_rshr_pack_store(unsigned* ptr, const v_uint64x8& a) +{ + v_uint64x8 delta = v512_setall_u64((uint64)1 << (n-1)); + v_pack_store(ptr, (a + delta) >> n); +} + +template inline +v_int32x16 v_rshr_pack(const v_int64x8& a, const v_int64x8& b) +{ + v_int64x8 delta = v512_setall_s64((int64)1 << (n-1)); + return v_pack((a + delta) >> n, (b + delta) >> n); +} + +template inline +void v_rshr_pack_store(int* ptr, const v_int64x8& a) +{ + v_int64x8 delta = v512_setall_s64((int64)1 << (n-1)); + v_pack_store(ptr, (a + delta) >> n); +} + +// pack boolean +inline v_uint8x64 v_pack_b(const v_uint16x32& a, const v_uint16x32& b) +{ return v_uint8x64(_mm512_permutexvar_epi64(_v512_set_epu64(7, 5, 3, 1, 6, 4, 2, 0), _mm512_packs_epi16(a.val, b.val))); } + +inline v_uint8x64 v_pack_b(const v_uint32x16& a, const v_uint32x16& b, + const v_uint32x16& c, const v_uint32x16& d) +{ + __m512i ab = _mm512_packs_epi32(a.val, b.val); + __m512i cd = _mm512_packs_epi32(c.val, d.val); + + return v_uint8x64(_mm512_permutexvar_epi32(_v512_set_epu32(15, 11, 7, 3, 14, 10, 6, 2, 13, 9, 5, 1, 12, 8, 4, 0), _mm512_packs_epi16(ab, cd))); +} + +inline v_uint8x64 v_pack_b(const v_uint64x8& a, const v_uint64x8& b, const v_uint64x8& c, + const v_uint64x8& d, const v_uint64x8& e, const v_uint64x8& f, + const v_uint64x8& g, const v_uint64x8& h) +{ + __m512i ab = _mm512_packs_epi32(a.val, b.val); + __m512i cd = _mm512_packs_epi32(c.val, d.val); + __m512i ef = _mm512_packs_epi32(e.val, f.val); + __m512i gh = _mm512_packs_epi32(g.val, h.val); + + __m512i abcd = _mm512_packs_epi32(ab, cd); + __m512i efgh = _mm512_packs_epi32(ef, gh); + + return v_uint8x64(_mm512_permutexvar_epi16(_v512_set_epu16(31, 23, 15, 7, 30, 22, 14, 6, 29, 21, 13, 5, 28, 20, 12, 4, + 27, 19, 11, 3, 26, 18, 10, 2, 25, 17, 9, 1, 24, 16, 8, 0), _mm512_packs_epi16(abcd, efgh))); +} + +/* Recombine */ +// its up there with load and store operations + +/* Extract */ +#define OPENCV_HAL_IMPL_AVX512_EXTRACT(_Tpvec) \ + template \ + inline _Tpvec v_extract(const _Tpvec& a, const _Tpvec& b) \ + { return v_rotate_right(a, b); } + +OPENCV_HAL_IMPL_AVX512_EXTRACT(v_uint8x64) +OPENCV_HAL_IMPL_AVX512_EXTRACT(v_int8x64) +OPENCV_HAL_IMPL_AVX512_EXTRACT(v_uint16x32) +OPENCV_HAL_IMPL_AVX512_EXTRACT(v_int16x32) +OPENCV_HAL_IMPL_AVX512_EXTRACT(v_uint32x16) +OPENCV_HAL_IMPL_AVX512_EXTRACT(v_int32x16) +OPENCV_HAL_IMPL_AVX512_EXTRACT(v_uint64x8) +OPENCV_HAL_IMPL_AVX512_EXTRACT(v_int64x8) +OPENCV_HAL_IMPL_AVX512_EXTRACT(v_float32x16) +OPENCV_HAL_IMPL_AVX512_EXTRACT(v_float64x8) + +#define OPENCV_HAL_IMPL_AVX512_EXTRACT_N(_Tpvec, _Tp) \ +template inline _Tp v_extract_n(_Tpvec v) { return v_rotate_right(v).get0(); } + +OPENCV_HAL_IMPL_AVX512_EXTRACT_N(v_uint8x64, uchar) +OPENCV_HAL_IMPL_AVX512_EXTRACT_N(v_int8x64, schar) +OPENCV_HAL_IMPL_AVX512_EXTRACT_N(v_uint16x32, ushort) +OPENCV_HAL_IMPL_AVX512_EXTRACT_N(v_int16x32, short) +OPENCV_HAL_IMPL_AVX512_EXTRACT_N(v_uint32x16, uint) +OPENCV_HAL_IMPL_AVX512_EXTRACT_N(v_int32x16, int) +OPENCV_HAL_IMPL_AVX512_EXTRACT_N(v_uint64x8, uint64) +OPENCV_HAL_IMPL_AVX512_EXTRACT_N(v_int64x8, int64) +OPENCV_HAL_IMPL_AVX512_EXTRACT_N(v_float32x16, float) +OPENCV_HAL_IMPL_AVX512_EXTRACT_N(v_float64x8, double) + +template +inline v_uint32x16 v_broadcast_element(v_uint32x16 a) +{ + static const __m512i perm = _mm512_set1_epi32((char)i); + return v_uint32x16(_mm512_permutexvar_epi32(perm, a.val)); +} + +template +inline v_int32x16 v_broadcast_element(const v_int32x16 &a) +{ return v_reinterpret_as_s32(v_broadcast_element(v_reinterpret_as_u32(a))); } + +template +inline v_float32x16 v_broadcast_element(const v_float32x16 &a) +{ return v_reinterpret_as_f32(v_broadcast_element(v_reinterpret_as_u32(a))); } + + +///////////////////// load deinterleave ///////////////////////////// + +inline void v_load_deinterleave( const uchar* ptr, v_uint8x64& a, v_uint8x64& b ) +{ + __m512i ab0 = _mm512_loadu_si512((const __m512i*)ptr); + __m512i ab1 = _mm512_loadu_si512((const __m512i*)(ptr + 64)); +#if CV_AVX_512VBMI + __m512i mask0 = _v512_set_epu8(126, 124, 122, 120, 118, 116, 114, 112, 110, 108, 106, 104, 102, 100, 98, 96, + 94, 92, 90, 88, 86, 84, 82, 80, 78, 76, 74, 72, 70, 68, 66, 64, + 62, 60, 58, 56, 54, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, + 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0); + __m512i mask1 = _v512_set_epu8(127, 125, 123, 121, 119, 117, 115, 113, 111, 109, 107, 105, 103, 101, 99, 97, + 95, 93, 91, 89, 87, 85, 83, 81, 79, 77, 75, 73, 71, 69, 67, 65, + 63, 61, 59, 57, 55, 53, 51, 49, 47, 45, 43, 41, 39, 37, 35, 33, + 31, 29, 27, 25, 23, 21, 19, 17, 15, 13, 11, 9, 7, 5, 3, 1); + a = v_uint8x64(_mm512_permutex2var_epi8(ab0, mask0, ab1)); + b = v_uint8x64(_mm512_permutex2var_epi8(ab0, mask1, ab1)); +#else + __m512i mask0 = _mm512_set4_epi32(0x0f0d0b09, 0x07050301, 0x0e0c0a08, 0x06040200); + __m512i a0b0 = _mm512_shuffle_epi8(ab0, mask0); + __m512i a1b1 = _mm512_shuffle_epi8(ab1, mask0); + __m512i mask1 = _v512_set_epu64(14, 12, 10, 8, 6, 4, 2, 0); + __m512i mask2 = _v512_set_epu64(15, 13, 11, 9, 7, 5, 3, 1); + a = v_uint8x64(_mm512_permutex2var_epi64(a0b0, mask1, a1b1)); + b = v_uint8x64(_mm512_permutex2var_epi64(a0b0, mask2, a1b1)); +#endif +} + +inline void v_load_deinterleave( const ushort* ptr, v_uint16x32& a, v_uint16x32& b ) +{ + __m512i ab0 = _mm512_loadu_si512((const __m512i*)ptr); + __m512i ab1 = _mm512_loadu_si512((const __m512i*)(ptr + 32)); + __m512i mask0 = _v512_set_epu16(62, 60, 58, 56, 54, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, + 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0); + __m512i mask1 = _v512_set_epu16(63, 61, 59, 57, 55, 53, 51, 49, 47, 45, 43, 41, 39, 37, 35, 33, + 31, 29, 27, 25, 23, 21, 19, 17, 15, 13, 11, 9, 7, 5, 3, 1); + a = v_uint16x32(_mm512_permutex2var_epi16(ab0, mask0, ab1)); + b = v_uint16x32(_mm512_permutex2var_epi16(ab0, mask1, ab1)); +} + +inline void v_load_deinterleave( const unsigned* ptr, v_uint32x16& a, v_uint32x16& b ) +{ + __m512i ab0 = _mm512_loadu_si512((const __m512i*)ptr); + __m512i ab1 = _mm512_loadu_si512((const __m512i*)(ptr + 16)); + __m512i mask0 = _v512_set_epu32(30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0); + __m512i mask1 = _v512_set_epu32(31, 29, 27, 25, 23, 21, 19, 17, 15, 13, 11, 9, 7, 5, 3, 1); + a = v_uint32x16(_mm512_permutex2var_epi32(ab0, mask0, ab1)); + b = v_uint32x16(_mm512_permutex2var_epi32(ab0, mask1, ab1)); +} + +inline void v_load_deinterleave( const uint64* ptr, v_uint64x8& a, v_uint64x8& b ) +{ + __m512i ab0 = _mm512_loadu_si512((const __m512i*)ptr); + __m512i ab1 = _mm512_loadu_si512((const __m512i*)(ptr + 8)); + __m512i mask0 = _v512_set_epu64(14, 12, 10, 8, 6, 4, 2, 0); + __m512i mask1 = _v512_set_epu64(15, 13, 11, 9, 7, 5, 3, 1); + a = v_uint64x8(_mm512_permutex2var_epi64(ab0, mask0, ab1)); + b = v_uint64x8(_mm512_permutex2var_epi64(ab0, mask1, ab1)); +} + +inline void v_load_deinterleave( const uchar* ptr, v_uint8x64& a, v_uint8x64& b, v_uint8x64& c ) +{ + __m512i bgr0 = _mm512_loadu_si512((const __m512i*)ptr); + __m512i bgr1 = _mm512_loadu_si512((const __m512i*)(ptr + 64)); + __m512i bgr2 = _mm512_loadu_si512((const __m512i*)(ptr + 128)); + +#if CV_AVX_512VBMI2 + __m512i mask0 = _v512_set_epu8(126, 123, 120, 117, 114, 111, 108, 105, 102, 99, 96, 93, 90, 87, 84, 81, + 78, 75, 72, 69, 66, 63, 60, 57, 54, 51, 48, 45, 42, 39, 36, 33, + 30, 27, 24, 21, 18, 15, 12, 9, 6, 3, 0, 62, 59, 56, 53, 50, + 47, 44, 41, 38, 35, 32, 29, 26, 23, 20, 17, 14, 11, 8, 5, 2); + __m512i r0b01 = _mm512_permutex2var_epi8(bgr0, mask0, bgr1); + __m512i b1g12 = _mm512_permutex2var_epi8(bgr1, mask0, bgr2); + __m512i r12b2 = _mm512_permutex2var_epi8(bgr1, + _v512_set_epu8(125, 122, 119, 116, 113, 110, 107, 104, 101, 98, 95, 92, 89, 86, 83, 80, + 77, 74, 71, 68, 65, 127, 124, 121, 118, 115, 112, 109, 106, 103, 100, 97, + 94, 91, 88, 85, 82, 79, 76, 73, 70, 67, 64, 61, 58, 55, 52, 49, + 46, 43, 40, 37, 34, 31, 28, 25, 22, 19, 16, 13, 10, 7, 4, 1), bgr2); + a = v_uint8x64(_mm512_mask_compress_epi8(r12b2, 0xffffffffffe00000, r0b01)); + b = v_uint8x64(_mm512_mask_compress_epi8(b1g12, 0x2492492492492492, bgr0)); + c = v_uint8x64(_mm512_mask_expand_epi8(r0b01, 0xffffffffffe00000, r12b2)); +#elif CV_AVX_512VBMI + __m512i b0g0b1 = _mm512_mask_blend_epi8(0xb6db6db6db6db6db, bgr1, bgr0); + __m512i g1r1g2 = _mm512_mask_blend_epi8(0xb6db6db6db6db6db, bgr2, bgr1); + __m512i r2b2r0 = _mm512_mask_blend_epi8(0xb6db6db6db6db6db, bgr0, bgr2); + a = v_uint8x64(_mm512_permutex2var_epi8(b0g0b1, _v512_set_epu8(125, 122, 119, 116, 113, 110, 107, 104, 101, 98, 95, 92, 89, 86, 83, 80, + 77, 74, 71, 68, 65, 63, 61, 60, 58, 57, 55, 54, 52, 51, 49, 48, + 46, 45, 43, 42, 40, 39, 37, 36, 34, 33, 31, 30, 28, 27, 25, 24, + 23, 21, 20, 18, 17, 15, 14, 12, 11, 9, 8, 6, 5, 3, 2, 0), bgr2)); + b = v_uint8x64(_mm512_permutex2var_epi8(g1r1g2, _v512_set_epu8( 63, 61, 60, 58, 57, 55, 54, 52, 51, 49, 48, 46, 45, 43, 42, 40, + 39, 37, 36, 34, 33, 31, 30, 28, 27, 25, 24, 23, 21, 20, 18, 17, + 15, 14, 12, 11, 9, 8, 6, 5, 3, 2, 0, 126, 123, 120, 117, 114, + 111, 108, 105, 102, 99, 96, 93, 90, 87, 84, 81, 78, 75, 72, 69, 66), bgr0)); + c = v_uint8x64(_mm512_permutex2var_epi8(r2b2r0, _v512_set_epu8( 63, 60, 57, 54, 51, 48, 45, 42, 39, 36, 33, 30, 27, 24, 21, 18, + 15, 12, 9, 6, 3, 0, 125, 122, 119, 116, 113, 110, 107, 104, 101, 98, + 95, 92, 89, 86, 83, 80, 77, 74, 71, 68, 65, 62, 59, 56, 53, 50, + 47, 44, 41, 38, 35, 32, 29, 26, 23, 20, 17, 14, 11, 8, 5, 2), bgr1)); +#else + __m512i mask0 = _v512_set_epu16(61, 58, 55, 52, 49, 46, 43, 40, 37, 34, 63, 60, 57, 54, 51, 48, + 45, 42, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3, 0); + __m512i b01g1 = _mm512_permutex2var_epi16(bgr0, mask0, bgr1); + __m512i r12b2 = _mm512_permutex2var_epi16(bgr1, mask0, bgr2); + __m512i g20r0 = _mm512_permutex2var_epi16(bgr2, mask0, bgr0); + + __m512i b0g0 = _mm512_mask_blend_epi32(0xf800, b01g1, r12b2); + __m512i r0b1 = _mm512_permutex2var_epi16(bgr1, _v512_set_epu16(42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 29, 26, 23, 20, 17, + 14, 11, 8, 5, 2, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43), g20r0); + __m512i g1r1 = _mm512_alignr_epi32(r12b2, g20r0, 11); + a = v_uint8x64(_mm512_mask_blend_epi8(0xAAAAAAAAAAAAAAAA, b0g0, r0b1)); + c = v_uint8x64(_mm512_mask_blend_epi8(0xAAAAAAAAAAAAAAAA, r0b1, g1r1)); + b = v_uint8x64(_mm512_shuffle_epi8(_mm512_mask_blend_epi8(0xAAAAAAAAAAAAAAAA, g1r1, b0g0), _mm512_set4_epi32(0x0e0f0c0d, 0x0a0b0809, 0x06070405, 0x02030001))); +#endif +} + +inline void v_load_deinterleave( const ushort* ptr, v_uint16x32& a, v_uint16x32& b, v_uint16x32& c ) +{ + __m512i bgr0 = _mm512_loadu_si512((const __m512i*)ptr); + __m512i bgr1 = _mm512_loadu_si512((const __m512i*)(ptr + 32)); + __m512i bgr2 = _mm512_loadu_si512((const __m512i*)(ptr + 64)); + + __m512i mask0 = _v512_set_epu16(61, 58, 55, 52, 49, 46, 43, 40, 37, 34, 63, 60, 57, 54, 51, 48, + 45, 42, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3, 0); + __m512i b01g1 = _mm512_permutex2var_epi16(bgr0, mask0, bgr1); + __m512i r12b2 = _mm512_permutex2var_epi16(bgr1, mask0, bgr2); + __m512i g20r0 = _mm512_permutex2var_epi16(bgr2, mask0, bgr0); + + a = v_uint16x32(_mm512_mask_blend_epi32(0xf800, b01g1, r12b2)); + b = v_uint16x32(_mm512_permutex2var_epi16(bgr1, _v512_set_epu16(42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 29, 26, 23, 20, 17, + 14, 11, 8, 5, 2, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43), g20r0)); + c = v_uint16x32(_mm512_alignr_epi32(r12b2, g20r0, 11)); +} + +inline void v_load_deinterleave( const unsigned* ptr, v_uint32x16& a, v_uint32x16& b, v_uint32x16& c ) +{ + __m512i bgr0 = _mm512_loadu_si512((const __m512i*)ptr); + __m512i bgr1 = _mm512_loadu_si512((const __m512i*)(ptr + 16)); + __m512i bgr2 = _mm512_loadu_si512((const __m512i*)(ptr + 32)); + + __m512i mask0 = _v512_set_epu32(29, 26, 23, 20, 17, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3, 0); + __m512i b01r1 = _mm512_permutex2var_epi32(bgr0, mask0, bgr1); + __m512i g12b2 = _mm512_permutex2var_epi32(bgr1, mask0, bgr2); + __m512i r20g0 = _mm512_permutex2var_epi32(bgr2, mask0, bgr0); + + a = v_uint32x16(_mm512_mask_blend_epi32(0xf800, b01r1, g12b2)); + b = v_uint32x16(_mm512_alignr_epi32(g12b2, r20g0, 11)); + c = v_uint32x16(_mm512_permutex2var_epi32(bgr1, _v512_set_epu32(21, 20, 19, 18, 17, 16, 13, 10, 7, 4, 1, 26, 25, 24, 23, 22), r20g0)); +} + +inline void v_load_deinterleave( const uint64* ptr, v_uint64x8& a, v_uint64x8& b, v_uint64x8& c ) +{ + __m512i bgr0 = _mm512_loadu_si512((const __m512i*)ptr); + __m512i bgr1 = _mm512_loadu_si512((const __m512i*)(ptr + 8)); + __m512i bgr2 = _mm512_loadu_si512((const __m512i*)(ptr + 16)); + + __m512i mask0 = _v512_set_epu64(13, 10, 15, 12, 9, 6, 3, 0); + __m512i b01g1 = _mm512_permutex2var_epi64(bgr0, mask0, bgr1); + __m512i r12b2 = _mm512_permutex2var_epi64(bgr1, mask0, bgr2); + __m512i g20r0 = _mm512_permutex2var_epi64(bgr2, mask0, bgr0); + + a = v_uint64x8(_mm512_mask_blend_epi64(0xc0, b01g1, r12b2)); + c = v_uint64x8(_mm512_alignr_epi64(r12b2, g20r0, 6)); + b = v_uint64x8(_mm512_permutex2var_epi64(bgr1, _v512_set_epu64(10, 9, 8, 5, 2, 13, 12, 11), g20r0)); +} + +inline void v_load_deinterleave( const uchar* ptr, v_uint8x64& a, v_uint8x64& b, v_uint8x64& c, v_uint8x64& d ) +{ + __m512i bgra0 = _mm512_loadu_si512((const __m512i*)ptr); + __m512i bgra1 = _mm512_loadu_si512((const __m512i*)(ptr + 64)); + __m512i bgra2 = _mm512_loadu_si512((const __m512i*)(ptr + 128)); + __m512i bgra3 = _mm512_loadu_si512((const __m512i*)(ptr + 192)); + +#if CV_AVX_512VBMI + __m512i mask0 = _v512_set_epu8(126, 124, 122, 120, 118, 116, 114, 112, 110, 108, 106, 104, 102, 100, 98, 96, + 94, 92, 90, 88, 86, 84, 82, 80, 78, 76, 74, 72, 70, 68, 66, 64, + 62, 60, 58, 56, 54, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, + 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0); + __m512i mask1 = _v512_set_epu8(127, 125, 123, 121, 119, 117, 115, 113, 111, 109, 107, 105, 103, 101, 99, 97, + 95, 93, 91, 89, 87, 85, 83, 81, 79, 77, 75, 73, 71, 69, 67, 65, + 63, 61, 59, 57, 55, 53, 51, 49, 47, 45, 43, 41, 39, 37, 35, 33, + 31, 29, 27, 25, 23, 21, 19, 17, 15, 13, 11, 9, 7, 5, 3, 1); + + __m512i br01 = _mm512_permutex2var_epi8(bgra0, mask0, bgra1); + __m512i ga01 = _mm512_permutex2var_epi8(bgra0, mask1, bgra1); + __m512i br23 = _mm512_permutex2var_epi8(bgra2, mask0, bgra3); + __m512i ga23 = _mm512_permutex2var_epi8(bgra2, mask1, bgra3); + + a = v_uint8x64(_mm512_permutex2var_epi8(br01, mask0, br23)); + c = v_uint8x64(_mm512_permutex2var_epi8(br01, mask1, br23)); + b = v_uint8x64(_mm512_permutex2var_epi8(ga01, mask0, ga23)); + d = v_uint8x64(_mm512_permutex2var_epi8(ga01, mask1, ga23)); +#else + __m512i mask = _mm512_set4_epi32(0x0f0b0703, 0x0e0a0602, 0x0d090501, 0x0c080400); + __m512i b0g0r0a0 = _mm512_shuffle_epi8(bgra0, mask); + __m512i b1g1r1a1 = _mm512_shuffle_epi8(bgra1, mask); + __m512i b2g2r2a2 = _mm512_shuffle_epi8(bgra2, mask); + __m512i b3g3r3a3 = _mm512_shuffle_epi8(bgra3, mask); + + __m512i mask0 = _v512_set_epu32(30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0); + __m512i mask1 = _v512_set_epu32(31, 29, 27, 25, 23, 21, 19, 17, 15, 13, 11, 9, 7, 5, 3, 1); + + __m512i br01 = _mm512_permutex2var_epi32(b0g0r0a0, mask0, b1g1r1a1); + __m512i ga01 = _mm512_permutex2var_epi32(b0g0r0a0, mask1, b1g1r1a1); + __m512i br23 = _mm512_permutex2var_epi32(b2g2r2a2, mask0, b3g3r3a3); + __m512i ga23 = _mm512_permutex2var_epi32(b2g2r2a2, mask1, b3g3r3a3); + + a = v_uint8x64(_mm512_permutex2var_epi32(br01, mask0, br23)); + c = v_uint8x64(_mm512_permutex2var_epi32(br01, mask1, br23)); + b = v_uint8x64(_mm512_permutex2var_epi32(ga01, mask0, ga23)); + d = v_uint8x64(_mm512_permutex2var_epi32(ga01, mask1, ga23)); +#endif +} + +inline void v_load_deinterleave( const ushort* ptr, v_uint16x32& a, v_uint16x32& b, v_uint16x32& c, v_uint16x32& d ) +{ + __m512i bgra0 = _mm512_loadu_si512((const __m512i*)ptr); + __m512i bgra1 = _mm512_loadu_si512((const __m512i*)(ptr + 32)); + __m512i bgra2 = _mm512_loadu_si512((const __m512i*)(ptr + 64)); + __m512i bgra3 = _mm512_loadu_si512((const __m512i*)(ptr + 96)); + + __m512i mask0 = _v512_set_epu16(62, 60, 58, 56, 54, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, + 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0); + __m512i mask1 = _v512_set_epu16(63, 61, 59, 57, 55, 53, 51, 49, 47, 45, 43, 41, 39, 37, 35, 33, + 31, 29, 27, 25, 23, 21, 19, 17, 15, 13, 11, 9, 7, 5, 3, 1); + + __m512i br01 = _mm512_permutex2var_epi16(bgra0, mask0, bgra1); + __m512i ga01 = _mm512_permutex2var_epi16(bgra0, mask1, bgra1); + __m512i br23 = _mm512_permutex2var_epi16(bgra2, mask0, bgra3); + __m512i ga23 = _mm512_permutex2var_epi16(bgra2, mask1, bgra3); + + a = v_uint16x32(_mm512_permutex2var_epi16(br01, mask0, br23)); + c = v_uint16x32(_mm512_permutex2var_epi16(br01, mask1, br23)); + b = v_uint16x32(_mm512_permutex2var_epi16(ga01, mask0, ga23)); + d = v_uint16x32(_mm512_permutex2var_epi16(ga01, mask1, ga23)); +} + +inline void v_load_deinterleave( const unsigned* ptr, v_uint32x16& a, v_uint32x16& b, v_uint32x16& c, v_uint32x16& d ) +{ + __m512i bgra0 = _mm512_loadu_si512((const __m512i*)ptr); + __m512i bgra1 = _mm512_loadu_si512((const __m512i*)(ptr + 16)); + __m512i bgra2 = _mm512_loadu_si512((const __m512i*)(ptr + 32)); + __m512i bgra3 = _mm512_loadu_si512((const __m512i*)(ptr + 48)); + + __m512i mask0 = _v512_set_epu32(30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0); + __m512i mask1 = _v512_set_epu32(31, 29, 27, 25, 23, 21, 19, 17, 15, 13, 11, 9, 7, 5, 3, 1); + + __m512i br01 = _mm512_permutex2var_epi32(bgra0, mask0, bgra1); + __m512i ga01 = _mm512_permutex2var_epi32(bgra0, mask1, bgra1); + __m512i br23 = _mm512_permutex2var_epi32(bgra2, mask0, bgra3); + __m512i ga23 = _mm512_permutex2var_epi32(bgra2, mask1, bgra3); + + a = v_uint32x16(_mm512_permutex2var_epi32(br01, mask0, br23)); + c = v_uint32x16(_mm512_permutex2var_epi32(br01, mask1, br23)); + b = v_uint32x16(_mm512_permutex2var_epi32(ga01, mask0, ga23)); + d = v_uint32x16(_mm512_permutex2var_epi32(ga01, mask1, ga23)); +} + +inline void v_load_deinterleave( const uint64* ptr, v_uint64x8& a, v_uint64x8& b, v_uint64x8& c, v_uint64x8& d ) +{ + __m512i bgra0 = _mm512_loadu_si512((const __m512i*)ptr); + __m512i bgra1 = _mm512_loadu_si512((const __m512i*)(ptr + 8)); + __m512i bgra2 = _mm512_loadu_si512((const __m512i*)(ptr + 16)); + __m512i bgra3 = _mm512_loadu_si512((const __m512i*)(ptr + 24)); + + __m512i mask0 = _v512_set_epu64(14, 12, 10, 8, 6, 4, 2, 0); + __m512i mask1 = _v512_set_epu64(15, 13, 11, 9, 7, 5, 3, 1); + + __m512i br01 = _mm512_permutex2var_epi64(bgra0, mask0, bgra1); + __m512i ga01 = _mm512_permutex2var_epi64(bgra0, mask1, bgra1); + __m512i br23 = _mm512_permutex2var_epi64(bgra2, mask0, bgra3); + __m512i ga23 = _mm512_permutex2var_epi64(bgra2, mask1, bgra3); + + a = v_uint64x8(_mm512_permutex2var_epi64(br01, mask0, br23)); + c = v_uint64x8(_mm512_permutex2var_epi64(br01, mask1, br23)); + b = v_uint64x8(_mm512_permutex2var_epi64(ga01, mask0, ga23)); + d = v_uint64x8(_mm512_permutex2var_epi64(ga01, mask1, ga23)); +} + +///////////////////////////// store interleave ///////////////////////////////////// + +inline void v_store_interleave( uchar* ptr, const v_uint8x64& x, const v_uint8x64& y, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + v_uint8x64 low, high; + v_zip(x, y, low, high); + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm512_stream_si512((__m512i*)ptr, low.val); + _mm512_stream_si512((__m512i*)(ptr + 64), high.val); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm512_store_si512((__m512i*)ptr, low.val); + _mm512_store_si512((__m512i*)(ptr + 64), high.val); + } + else + { + _mm512_storeu_si512((__m512i*)ptr, low.val); + _mm512_storeu_si512((__m512i*)(ptr + 64), high.val); + } +} + +inline void v_store_interleave( ushort* ptr, const v_uint16x32& x, const v_uint16x32& y, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + v_uint16x32 low, high; + v_zip(x, y, low, high); + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm512_stream_si512((__m512i*)ptr, low.val); + _mm512_stream_si512((__m512i*)(ptr + 32), high.val); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm512_store_si512((__m512i*)ptr, low.val); + _mm512_store_si512((__m512i*)(ptr + 32), high.val); + } + else + { + _mm512_storeu_si512((__m512i*)ptr, low.val); + _mm512_storeu_si512((__m512i*)(ptr + 32), high.val); + } +} + +inline void v_store_interleave( unsigned* ptr, const v_uint32x16& x, const v_uint32x16& y, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + v_uint32x16 low, high; + v_zip(x, y, low, high); + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm512_stream_si512((__m512i*)ptr, low.val); + _mm512_stream_si512((__m512i*)(ptr + 16), high.val); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm512_store_si512((__m512i*)ptr, low.val); + _mm512_store_si512((__m512i*)(ptr + 16), high.val); + } + else + { + _mm512_storeu_si512((__m512i*)ptr, low.val); + _mm512_storeu_si512((__m512i*)(ptr + 16), high.val); + } +} + +inline void v_store_interleave( uint64* ptr, const v_uint64x8& x, const v_uint64x8& y, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + v_uint64x8 low, high; + v_zip(x, y, low, high); + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm512_stream_si512((__m512i*)ptr, low.val); + _mm512_stream_si512((__m512i*)(ptr + 8), high.val); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm512_store_si512((__m512i*)ptr, low.val); + _mm512_store_si512((__m512i*)(ptr + 8), high.val); + } + else + { + _mm512_storeu_si512((__m512i*)ptr, low.val); + _mm512_storeu_si512((__m512i*)(ptr + 8), high.val); + } +} + +inline void v_store_interleave( uchar* ptr, const v_uint8x64& a, const v_uint8x64& b, const v_uint8x64& c, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ +#if CV_AVX_512VBMI + __m512i mask0 = _v512_set_epu8(127, 84, 20, 126, 83, 19, 125, 82, 18, 124, 81, 17, 123, 80, 16, 122, + 79, 15, 121, 78, 14, 120, 77, 13, 119, 76, 12, 118, 75, 11, 117, 74, + 10, 116, 73, 9, 115, 72, 8, 114, 71, 7, 113, 70, 6, 112, 69, 5, + 111, 68, 4, 110, 67, 3, 109, 66, 2, 108, 65, 1, 107, 64, 0, 106); + __m512i mask1 = _v512_set_epu8( 21, 42, 105, 20, 41, 104, 19, 40, 103, 18, 39, 102, 17, 38, 101, 16, + 37, 100, 15, 36, 99, 14, 35, 98, 13, 34, 97, 12, 33, 96, 11, 32, + 95, 10, 31, 94, 9, 30, 93, 8, 29, 92, 7, 28, 91, 6, 27, 90, + 5, 26, 89, 4, 25, 88, 3, 24, 87, 2, 23, 86, 1, 22, 85, 0); + __m512i mask2 = _v512_set_epu8(106, 127, 63, 105, 126, 62, 104, 125, 61, 103, 124, 60, 102, 123, 59, 101, + 122, 58, 100, 121, 57, 99, 120, 56, 98, 119, 55, 97, 118, 54, 96, 117, + 53, 95, 116, 52, 94, 115, 51, 93, 114, 50, 92, 113, 49, 91, 112, 48, + 90, 111, 47, 89, 110, 46, 88, 109, 45, 87, 108, 44, 86, 107, 43, 85); + __m512i r2g0r0 = _mm512_permutex2var_epi8(b.val, mask0, c.val); + __m512i b0r1b1 = _mm512_permutex2var_epi8(a.val, mask1, c.val); + __m512i g1b2g2 = _mm512_permutex2var_epi8(a.val, mask2, b.val); + + __m512i bgr0 = _mm512_mask_blend_epi8(0x9249249249249249, r2g0r0, b0r1b1); + __m512i bgr1 = _mm512_mask_blend_epi8(0x9249249249249249, b0r1b1, g1b2g2); + __m512i bgr2 = _mm512_mask_blend_epi8(0x9249249249249249, g1b2g2, r2g0r0); +#else + __m512i g1g0 = _mm512_shuffle_epi8(b.val, _mm512_set4_epi32(0x0e0f0c0d, 0x0a0b0809, 0x06070405, 0x02030001)); + __m512i b0g0 = _mm512_mask_blend_epi8(0xAAAAAAAAAAAAAAAA, a.val, g1g0); + __m512i r0b1 = _mm512_mask_blend_epi8(0xAAAAAAAAAAAAAAAA, c.val, a.val); + __m512i g1r1 = _mm512_mask_blend_epi8(0xAAAAAAAAAAAAAAAA, g1g0, c.val); + + __m512i mask0 = _v512_set_epu16(42, 10, 31, 41, 9, 30, 40, 8, 29, 39, 7, 28, 38, 6, 27, 37, + 5, 26, 36, 4, 25, 35, 3, 24, 34, 2, 23, 33, 1, 22, 32, 0); + __m512i mask1 = _v512_set_epu16(21, 52, 41, 20, 51, 40, 19, 50, 39, 18, 49, 38, 17, 48, 37, 16, + 47, 36, 15, 46, 35, 14, 45, 34, 13, 44, 33, 12, 43, 32, 11, 42); + __m512i mask2 = _v512_set_epu16(63, 31, 20, 62, 30, 19, 61, 29, 18, 60, 28, 17, 59, 27, 16, 58, + 26, 15, 57, 25, 14, 56, 24, 13, 55, 23, 12, 54, 22, 11, 53, 21); + __m512i b0g0b2 = _mm512_permutex2var_epi16(b0g0, mask0, r0b1); + __m512i r1b1r0 = _mm512_permutex2var_epi16(b0g0, mask1, g1r1); + __m512i g2r2g1 = _mm512_permutex2var_epi16(r0b1, mask2, g1r1); + + __m512i bgr0 = _mm512_mask_blend_epi16(0x24924924, b0g0b2, r1b1r0); + __m512i bgr1 = _mm512_mask_blend_epi16(0x24924924, r1b1r0, g2r2g1); + __m512i bgr2 = _mm512_mask_blend_epi16(0x24924924, g2r2g1, b0g0b2); +#endif + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm512_stream_si512((__m512i*)ptr, bgr0); + _mm512_stream_si512((__m512i*)(ptr + 64), bgr1); + _mm512_stream_si512((__m512i*)(ptr + 128), bgr2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm512_store_si512((__m512i*)ptr, bgr0); + _mm512_store_si512((__m512i*)(ptr + 64), bgr1); + _mm512_store_si512((__m512i*)(ptr + 128), bgr2); + } + else + { + _mm512_storeu_si512((__m512i*)ptr, bgr0); + _mm512_storeu_si512((__m512i*)(ptr + 64), bgr1); + _mm512_storeu_si512((__m512i*)(ptr + 128), bgr2); + } +} + +inline void v_store_interleave( ushort* ptr, const v_uint16x32& a, const v_uint16x32& b, const v_uint16x32& c, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m512i mask0 = _v512_set_epu16(42, 10, 31, 41, 9, 30, 40, 8, 29, 39, 7, 28, 38, 6, 27, 37, + 5, 26, 36, 4, 25, 35, 3, 24, 34, 2, 23, 33, 1, 22, 32, 0); + __m512i mask1 = _v512_set_epu16(21, 52, 41, 20, 51, 40, 19, 50, 39, 18, 49, 38, 17, 48, 37, 16, + 47, 36, 15, 46, 35, 14, 45, 34, 13, 44, 33, 12, 43, 32, 11, 42); + __m512i mask2 = _v512_set_epu16(63, 31, 20, 62, 30, 19, 61, 29, 18, 60, 28, 17, 59, 27, 16, 58, + 26, 15, 57, 25, 14, 56, 24, 13, 55, 23, 12, 54, 22, 11, 53, 21); + __m512i b0g0b2 = _mm512_permutex2var_epi16(a.val, mask0, b.val); + __m512i r1b1r0 = _mm512_permutex2var_epi16(a.val, mask1, c.val); + __m512i g2r2g1 = _mm512_permutex2var_epi16(b.val, mask2, c.val); + + __m512i bgr0 = _mm512_mask_blend_epi16(0x24924924, b0g0b2, r1b1r0); + __m512i bgr1 = _mm512_mask_blend_epi16(0x24924924, r1b1r0, g2r2g1); + __m512i bgr2 = _mm512_mask_blend_epi16(0x24924924, g2r2g1, b0g0b2); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm512_stream_si512((__m512i*)ptr, bgr0); + _mm512_stream_si512((__m512i*)(ptr + 32), bgr1); + _mm512_stream_si512((__m512i*)(ptr + 64), bgr2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm512_store_si512((__m512i*)ptr, bgr0); + _mm512_store_si512((__m512i*)(ptr + 32), bgr1); + _mm512_store_si512((__m512i*)(ptr + 64), bgr2); + } + else + { + _mm512_storeu_si512((__m512i*)ptr, bgr0); + _mm512_storeu_si512((__m512i*)(ptr + 32), bgr1); + _mm512_storeu_si512((__m512i*)(ptr + 64), bgr2); + } +} + +inline void v_store_interleave( unsigned* ptr, const v_uint32x16& a, const v_uint32x16& b, const v_uint32x16& c, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m512i mask0 = _v512_set_epu32(26, 31, 15, 25, 30, 14, 24, 29, 13, 23, 28, 12, 22, 27, 11, 21); + __m512i mask1 = _v512_set_epu32(31, 10, 25, 30, 9, 24, 29, 8, 23, 28, 7, 22, 27, 6, 21, 26); + __m512i g1b2g2 = _mm512_permutex2var_epi32(a.val, mask0, b.val); + __m512i r2r1b1 = _mm512_permutex2var_epi32(a.val, mask1, c.val); + + __m512i bgr0 = _mm512_mask_expand_epi32(_mm512_mask_expand_epi32(_mm512_maskz_expand_epi32(0x9249, a.val), 0x2492, b.val), 0x4924, c.val); + __m512i bgr1 = _mm512_mask_blend_epi32(0x9249, r2r1b1, g1b2g2); + __m512i bgr2 = _mm512_mask_blend_epi32(0x9249, g1b2g2, r2r1b1); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm512_stream_si512((__m512i*)ptr, bgr0); + _mm512_stream_si512((__m512i*)(ptr + 16), bgr1); + _mm512_stream_si512((__m512i*)(ptr + 32), bgr2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm512_store_si512((__m512i*)ptr, bgr0); + _mm512_store_si512((__m512i*)(ptr + 16), bgr1); + _mm512_store_si512((__m512i*)(ptr + 32), bgr2); + } + else + { + _mm512_storeu_si512((__m512i*)ptr, bgr0); + _mm512_storeu_si512((__m512i*)(ptr + 16), bgr1); + _mm512_storeu_si512((__m512i*)(ptr + 32), bgr2); + } +} + +inline void v_store_interleave( uint64* ptr, const v_uint64x8& a, const v_uint64x8& b, const v_uint64x8& c, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + __m512i mask0 = _v512_set_epu64( 5, 12, 7, 4, 11, 6, 3, 10); + __m512i mask1 = _v512_set_epu64(15, 7, 4, 14, 6, 3, 13, 5); + __m512i r1b1b2 = _mm512_permutex2var_epi64(a.val, mask0, c.val); + __m512i g2r2g1 = _mm512_permutex2var_epi64(b.val, mask1, c.val); + + __m512i bgr0 = _mm512_mask_expand_epi64(_mm512_mask_expand_epi64(_mm512_maskz_expand_epi64(0x49, a.val), 0x92, b.val), 0x24, c.val); + __m512i bgr1 = _mm512_mask_blend_epi64(0xdb, g2r2g1, r1b1b2); + __m512i bgr2 = _mm512_mask_blend_epi64(0xdb, r1b1b2, g2r2g1); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm512_stream_si512((__m512i*)ptr, bgr0); + _mm512_stream_si512((__m512i*)(ptr + 8), bgr1); + _mm512_stream_si512((__m512i*)(ptr + 16), bgr2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm512_store_si512((__m512i*)ptr, bgr0); + _mm512_store_si512((__m512i*)(ptr + 8), bgr1); + _mm512_store_si512((__m512i*)(ptr + 16), bgr2); + } + else + { + _mm512_storeu_si512((__m512i*)ptr, bgr0); + _mm512_storeu_si512((__m512i*)(ptr + 8), bgr1); + _mm512_storeu_si512((__m512i*)(ptr + 16), bgr2); + } +} + +inline void v_store_interleave( uchar* ptr, const v_uint8x64& a, const v_uint8x64& b, + const v_uint8x64& c, const v_uint8x64& d, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + v_uint8x64 br01, br23, ga01, ga23; + v_zip(a, c, br01, br23); + v_zip(b, d, ga01, ga23); + v_uint8x64 bgra0, bgra1, bgra2, bgra3; + v_zip(br01, ga01, bgra0, bgra1); + v_zip(br23, ga23, bgra2, bgra3); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm512_stream_si512((__m512i*)ptr, bgra0.val); + _mm512_stream_si512((__m512i*)(ptr + 64), bgra1.val); + _mm512_stream_si512((__m512i*)(ptr + 128), bgra2.val); + _mm512_stream_si512((__m512i*)(ptr + 192), bgra3.val); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm512_store_si512((__m512i*)ptr, bgra0.val); + _mm512_store_si512((__m512i*)(ptr + 64), bgra1.val); + _mm512_store_si512((__m512i*)(ptr + 128), bgra2.val); + _mm512_store_si512((__m512i*)(ptr + 192), bgra3.val); + } + else + { + _mm512_storeu_si512((__m512i*)ptr, bgra0.val); + _mm512_storeu_si512((__m512i*)(ptr + 64), bgra1.val); + _mm512_storeu_si512((__m512i*)(ptr + 128), bgra2.val); + _mm512_storeu_si512((__m512i*)(ptr + 192), bgra3.val); + } +} + +inline void v_store_interleave( ushort* ptr, const v_uint16x32& a, const v_uint16x32& b, + const v_uint16x32& c, const v_uint16x32& d, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + v_uint16x32 br01, br23, ga01, ga23; + v_zip(a, c, br01, br23); + v_zip(b, d, ga01, ga23); + v_uint16x32 bgra0, bgra1, bgra2, bgra3; + v_zip(br01, ga01, bgra0, bgra1); + v_zip(br23, ga23, bgra2, bgra3); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm512_stream_si512((__m512i*)ptr, bgra0.val); + _mm512_stream_si512((__m512i*)(ptr + 32), bgra1.val); + _mm512_stream_si512((__m512i*)(ptr + 64), bgra2.val); + _mm512_stream_si512((__m512i*)(ptr + 96), bgra3.val); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm512_store_si512((__m512i*)ptr, bgra0.val); + _mm512_store_si512((__m512i*)(ptr + 32), bgra1.val); + _mm512_store_si512((__m512i*)(ptr + 64), bgra2.val); + _mm512_store_si512((__m512i*)(ptr + 96), bgra3.val); + } + else + { + _mm512_storeu_si512((__m512i*)ptr, bgra0.val); + _mm512_storeu_si512((__m512i*)(ptr + 32), bgra1.val); + _mm512_storeu_si512((__m512i*)(ptr + 64), bgra2.val); + _mm512_storeu_si512((__m512i*)(ptr + 96), bgra3.val); + } +} + +inline void v_store_interleave( unsigned* ptr, const v_uint32x16& a, const v_uint32x16& b, + const v_uint32x16& c, const v_uint32x16& d, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + v_uint32x16 br01, br23, ga01, ga23; + v_zip(a, c, br01, br23); + v_zip(b, d, ga01, ga23); + v_uint32x16 bgra0, bgra1, bgra2, bgra3; + v_zip(br01, ga01, bgra0, bgra1); + v_zip(br23, ga23, bgra2, bgra3); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm512_stream_si512((__m512i*)ptr, bgra0.val); + _mm512_stream_si512((__m512i*)(ptr + 16), bgra1.val); + _mm512_stream_si512((__m512i*)(ptr + 32), bgra2.val); + _mm512_stream_si512((__m512i*)(ptr + 48), bgra3.val); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm512_store_si512((__m512i*)ptr, bgra0.val); + _mm512_store_si512((__m512i*)(ptr + 16), bgra1.val); + _mm512_store_si512((__m512i*)(ptr + 32), bgra2.val); + _mm512_store_si512((__m512i*)(ptr + 48), bgra3.val); + } + else + { + _mm512_storeu_si512((__m512i*)ptr, bgra0.val); + _mm512_storeu_si512((__m512i*)(ptr + 16), bgra1.val); + _mm512_storeu_si512((__m512i*)(ptr + 32), bgra2.val); + _mm512_storeu_si512((__m512i*)(ptr + 48), bgra3.val); + } +} + +inline void v_store_interleave( uint64* ptr, const v_uint64x8& a, const v_uint64x8& b, + const v_uint64x8& c, const v_uint64x8& d, + hal::StoreMode mode=hal::STORE_UNALIGNED ) +{ + v_uint64x8 br01, br23, ga01, ga23; + v_zip(a, c, br01, br23); + v_zip(b, d, ga01, ga23); + v_uint64x8 bgra0, bgra1, bgra2, bgra3; + v_zip(br01, ga01, bgra0, bgra1); + v_zip(br23, ga23, bgra2, bgra3); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm512_stream_si512((__m512i*)ptr, bgra0.val); + _mm512_stream_si512((__m512i*)(ptr + 8), bgra1.val); + _mm512_stream_si512((__m512i*)(ptr + 16), bgra2.val); + _mm512_stream_si512((__m512i*)(ptr + 24), bgra3.val); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm512_store_si512((__m512i*)ptr, bgra0.val); + _mm512_store_si512((__m512i*)(ptr + 8), bgra1.val); + _mm512_store_si512((__m512i*)(ptr + 16), bgra2.val); + _mm512_store_si512((__m512i*)(ptr + 24), bgra3.val); + } + else + { + _mm512_storeu_si512((__m512i*)ptr, bgra0.val); + _mm512_storeu_si512((__m512i*)(ptr + 8), bgra1.val); + _mm512_storeu_si512((__m512i*)(ptr + 16), bgra2.val); + _mm512_storeu_si512((__m512i*)(ptr + 24), bgra3.val); + } +} + +#define OPENCV_HAL_IMPL_AVX512_LOADSTORE_INTERLEAVE(_Tpvec0, _Tp0, suffix0, _Tpvec1, _Tp1, suffix1) \ +inline void v_load_deinterleave( const _Tp0* ptr, _Tpvec0& a0, _Tpvec0& b0 ) \ +{ \ + _Tpvec1 a1, b1; \ + v_load_deinterleave((const _Tp1*)ptr, a1, b1); \ + a0 = v_reinterpret_as_##suffix0(a1); \ + b0 = v_reinterpret_as_##suffix0(b1); \ +} \ +inline void v_load_deinterleave( const _Tp0* ptr, _Tpvec0& a0, _Tpvec0& b0, _Tpvec0& c0 ) \ +{ \ + _Tpvec1 a1, b1, c1; \ + v_load_deinterleave((const _Tp1*)ptr, a1, b1, c1); \ + a0 = v_reinterpret_as_##suffix0(a1); \ + b0 = v_reinterpret_as_##suffix0(b1); \ + c0 = v_reinterpret_as_##suffix0(c1); \ +} \ +inline void v_load_deinterleave( const _Tp0* ptr, _Tpvec0& a0, _Tpvec0& b0, _Tpvec0& c0, _Tpvec0& d0 ) \ +{ \ + _Tpvec1 a1, b1, c1, d1; \ + v_load_deinterleave((const _Tp1*)ptr, a1, b1, c1, d1); \ + a0 = v_reinterpret_as_##suffix0(a1); \ + b0 = v_reinterpret_as_##suffix0(b1); \ + c0 = v_reinterpret_as_##suffix0(c1); \ + d0 = v_reinterpret_as_##suffix0(d1); \ +} \ +inline void v_store_interleave( _Tp0* ptr, const _Tpvec0& a0, const _Tpvec0& b0, \ + hal::StoreMode mode=hal::STORE_UNALIGNED ) \ +{ \ + _Tpvec1 a1 = v_reinterpret_as_##suffix1(a0); \ + _Tpvec1 b1 = v_reinterpret_as_##suffix1(b0); \ + v_store_interleave((_Tp1*)ptr, a1, b1, mode); \ +} \ +inline void v_store_interleave( _Tp0* ptr, const _Tpvec0& a0, const _Tpvec0& b0, const _Tpvec0& c0, \ + hal::StoreMode mode=hal::STORE_UNALIGNED ) \ +{ \ + _Tpvec1 a1 = v_reinterpret_as_##suffix1(a0); \ + _Tpvec1 b1 = v_reinterpret_as_##suffix1(b0); \ + _Tpvec1 c1 = v_reinterpret_as_##suffix1(c0); \ + v_store_interleave((_Tp1*)ptr, a1, b1, c1, mode); \ +} \ +inline void v_store_interleave( _Tp0* ptr, const _Tpvec0& a0, const _Tpvec0& b0, \ + const _Tpvec0& c0, const _Tpvec0& d0, \ + hal::StoreMode mode=hal::STORE_UNALIGNED ) \ +{ \ + _Tpvec1 a1 = v_reinterpret_as_##suffix1(a0); \ + _Tpvec1 b1 = v_reinterpret_as_##suffix1(b0); \ + _Tpvec1 c1 = v_reinterpret_as_##suffix1(c0); \ + _Tpvec1 d1 = v_reinterpret_as_##suffix1(d0); \ + v_store_interleave((_Tp1*)ptr, a1, b1, c1, d1, mode); \ +} + +OPENCV_HAL_IMPL_AVX512_LOADSTORE_INTERLEAVE(v_int8x64, schar, s8, v_uint8x64, uchar, u8) +OPENCV_HAL_IMPL_AVX512_LOADSTORE_INTERLEAVE(v_int16x32, short, s16, v_uint16x32, ushort, u16) +OPENCV_HAL_IMPL_AVX512_LOADSTORE_INTERLEAVE(v_int32x16, int, s32, v_uint32x16, unsigned, u32) +OPENCV_HAL_IMPL_AVX512_LOADSTORE_INTERLEAVE(v_float32x16, float, f32, v_uint32x16, unsigned, u32) +OPENCV_HAL_IMPL_AVX512_LOADSTORE_INTERLEAVE(v_int64x8, int64, s64, v_uint64x8, uint64, u64) +OPENCV_HAL_IMPL_AVX512_LOADSTORE_INTERLEAVE(v_float64x8, double, f64, v_uint64x8, uint64, u64) + +////////// Mask and checks ///////// + +/** Mask **/ +inline int64 v_signmask(const v_int8x64& a) { return (int64)_mm512_movepi8_mask(a.val); } +inline int v_signmask(const v_int16x32& a) { return (int)_mm512_cmp_epi16_mask(a.val, _mm512_setzero_si512(), _MM_CMPINT_LT); } +inline int v_signmask(const v_int32x16& a) { return (int)_mm512_cmp_epi32_mask(a.val, _mm512_setzero_si512(), _MM_CMPINT_LT); } +inline int v_signmask(const v_int64x8& a) { return (int)_mm512_cmp_epi64_mask(a.val, _mm512_setzero_si512(), _MM_CMPINT_LT); } + +inline int64 v_signmask(const v_uint8x64& a) { return v_signmask(v_reinterpret_as_s8(a)); } +inline int v_signmask(const v_uint16x32& a) { return v_signmask(v_reinterpret_as_s16(a)); } +inline int v_signmask(const v_uint32x16& a) { return v_signmask(v_reinterpret_as_s32(a)); } +inline int v_signmask(const v_uint64x8& a) { return v_signmask(v_reinterpret_as_s64(a)); } +inline int v_signmask(const v_float32x16& a) { return v_signmask(v_reinterpret_as_s32(a)); } +inline int v_signmask(const v_float64x8& a) { return v_signmask(v_reinterpret_as_s64(a)); } + +/** Checks **/ +inline bool v_check_all(const v_int8x64& a) { return !(bool)_mm512_cmp_epi8_mask(a.val, _mm512_setzero_si512(), _MM_CMPINT_NLT); } +inline bool v_check_any(const v_int8x64& a) { return (bool)_mm512_movepi8_mask(a.val); } +inline bool v_check_all(const v_int16x32& a) { return !(bool)_mm512_cmp_epi16_mask(a.val, _mm512_setzero_si512(), _MM_CMPINT_NLT); } +inline bool v_check_any(const v_int16x32& a) { return (bool)_mm512_cmp_epi16_mask(a.val, _mm512_setzero_si512(), _MM_CMPINT_LT); } +inline bool v_check_all(const v_int32x16& a) { return !(bool)_mm512_cmp_epi32_mask(a.val, _mm512_setzero_si512(), _MM_CMPINT_NLT); } +inline bool v_check_any(const v_int32x16& a) { return (bool)_mm512_cmp_epi32_mask(a.val, _mm512_setzero_si512(), _MM_CMPINT_LT); } +inline bool v_check_all(const v_int64x8& a) { return !(bool)_mm512_cmp_epi64_mask(a.val, _mm512_setzero_si512(), _MM_CMPINT_NLT); } +inline bool v_check_any(const v_int64x8& a) { return (bool)_mm512_cmp_epi64_mask(a.val, _mm512_setzero_si512(), _MM_CMPINT_LT); } + +inline bool v_check_all(const v_float32x16& a) { return v_check_all(v_reinterpret_as_s32(a)); } +inline bool v_check_any(const v_float32x16& a) { return v_check_any(v_reinterpret_as_s32(a)); } +inline bool v_check_all(const v_float64x8& a) { return v_check_all(v_reinterpret_as_s64(a)); } +inline bool v_check_any(const v_float64x8& a) { return v_check_any(v_reinterpret_as_s64(a)); } +inline bool v_check_all(const v_uint8x64& a) { return v_check_all(v_reinterpret_as_s8(a)); } +inline bool v_check_all(const v_uint16x32& a) { return v_check_all(v_reinterpret_as_s16(a)); } +inline bool v_check_all(const v_uint32x16& a) { return v_check_all(v_reinterpret_as_s32(a)); } +inline bool v_check_all(const v_uint64x8& a) { return v_check_all(v_reinterpret_as_s64(a)); } +inline bool v_check_any(const v_uint8x64& a) { return v_check_any(v_reinterpret_as_s8(a)); } +inline bool v_check_any(const v_uint16x32& a) { return v_check_any(v_reinterpret_as_s16(a)); } +inline bool v_check_any(const v_uint32x16& a) { return v_check_any(v_reinterpret_as_s32(a)); } +inline bool v_check_any(const v_uint64x8& a) { return v_check_any(v_reinterpret_as_s64(a)); } + +inline int v_scan_forward(const v_int8x64& a) +{ + int64 mask = _mm512_movepi8_mask(a.val); + int mask32 = (int)mask; + return mask != 0 ? mask32 != 0 ? trailingZeros32(mask32) : 32 + trailingZeros32((int)(mask >> 32)) : 0; +} +inline int v_scan_forward(const v_uint8x64& a) { return v_scan_forward(v_reinterpret_as_s8(a)); } +inline int v_scan_forward(const v_int16x32& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s16(a))); } +inline int v_scan_forward(const v_uint16x32& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s16(a))); } +inline int v_scan_forward(const v_int32x16& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s16(a))) / 2; } +inline int v_scan_forward(const v_uint32x16& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s16(a))) / 2; } +inline int v_scan_forward(const v_float32x16& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s16(a))) / 2; } +inline int v_scan_forward(const v_int64x8& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s16(a))) / 4; } +inline int v_scan_forward(const v_uint64x8& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s16(a))) / 4; } +inline int v_scan_forward(const v_float64x8& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s16(a))) / 4; } + +inline void v512_cleanup() { _mm256_zeroall(); } + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END + +//! @endcond + +} // cv:: + +#endif // OPENCV_HAL_INTRIN_AVX_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_cpp.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_cpp.hpp new file mode 100644 index 0000000..4622214 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_cpp.hpp @@ -0,0 +1,3320 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_HAL_INTRIN_CPP_HPP +#define OPENCV_HAL_INTRIN_CPP_HPP + +#include +#include +#include +#include "opencv2/core/saturate.hpp" + +//! @cond IGNORED +#define CV_SIMD128_CPP 1 +#if defined(CV_FORCE_SIMD128_CPP) +#define CV_SIMD128 1 +#define CV_SIMD128_64F 1 +#endif +#if defined(CV_DOXYGEN) +#define CV_SIMD128 1 +#define CV_SIMD128_64F 1 +#define CV_SIMD256 1 +#define CV_SIMD256_64F 1 +#define CV_SIMD512 1 +#define CV_SIMD512_64F 1 +#else +#define CV_SIMD256 0 // Explicitly disable SIMD256 and SIMD512 support for scalar intrinsic implementation +#define CV_SIMD512 0 // to avoid warnings during compilation +#endif +//! @endcond + +namespace cv +{ + +#ifndef CV_DOXYGEN +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN +#endif + +/** @addtogroup core_hal_intrin + +"Universal intrinsics" is a types and functions set intended to simplify vectorization of code on +different platforms. Currently a few different SIMD extensions on different architectures are supported. +128 bit registers of various types support is implemented for a wide range of architectures +including x86(__SSE/SSE2/SSE4.2__), ARM(__NEON__), PowerPC(__VSX__), MIPS(__MSA__). +256 bit long registers are supported on x86(__AVX2__) and 512 bit long registers are supported on x86(__AVX512__). +In case when there is no SIMD extension available during compilation, fallback C++ implementation of intrinsics +will be chosen and code will work as expected although it could be slower. + +### Types + +There are several types representing packed values vector registers, each type is +implemented as a structure based on a one SIMD register. + +- cv::v_uint8 and cv::v_int8: 8-bit integer values (unsigned/signed) - char +- cv::v_uint16 and cv::v_int16: 16-bit integer values (unsigned/signed) - short +- cv::v_uint32 and cv::v_int32: 32-bit integer values (unsigned/signed) - int +- cv::v_uint64 and cv::v_int64: 64-bit integer values (unsigned/signed) - int64 +- cv::v_float32: 32-bit floating point values (signed) - float +- cv::v_float64: 64-bit floating point values (signed) - double + +Exact bit length(and value quantity) of listed types is compile time deduced and depends on architecture SIMD +capabilities chosen as available during compilation of the library. All the types contains __nlanes__ enumeration +to check for exact value quantity of the type. + +In case the exact bit length of the type is important it is possible to use specific fixed length register types. + +There are several types representing 128-bit registers. + +- cv::v_uint8x16 and cv::v_int8x16: sixteen 8-bit integer values (unsigned/signed) - char +- cv::v_uint16x8 and cv::v_int16x8: eight 16-bit integer values (unsigned/signed) - short +- cv::v_uint32x4 and cv::v_int32x4: four 32-bit integer values (unsigned/signed) - int +- cv::v_uint64x2 and cv::v_int64x2: two 64-bit integer values (unsigned/signed) - int64 +- cv::v_float32x4: four 32-bit floating point values (signed) - float +- cv::v_float64x2: two 64-bit floating point values (signed) - double + +There are several types representing 256-bit registers. + +- cv::v_uint8x32 and cv::v_int8x32: thirty two 8-bit integer values (unsigned/signed) - char +- cv::v_uint16x16 and cv::v_int16x16: sixteen 16-bit integer values (unsigned/signed) - short +- cv::v_uint32x8 and cv::v_int32x8: eight 32-bit integer values (unsigned/signed) - int +- cv::v_uint64x4 and cv::v_int64x4: four 64-bit integer values (unsigned/signed) - int64 +- cv::v_float32x8: eight 32-bit floating point values (signed) - float +- cv::v_float64x4: four 64-bit floating point values (signed) - double + +@note +256 bit registers at the moment implemented for AVX2 SIMD extension only, if you want to use this type directly, +don't forget to check the CV_SIMD256 preprocessor definition: +@code +#if CV_SIMD256 +//... +#endif +@endcode + +There are several types representing 512-bit registers. + +- cv::v_uint8x64 and cv::v_int8x64: sixty four 8-bit integer values (unsigned/signed) - char +- cv::v_uint16x32 and cv::v_int16x32: thirty two 16-bit integer values (unsigned/signed) - short +- cv::v_uint32x16 and cv::v_int32x16: sixteen 32-bit integer values (unsigned/signed) - int +- cv::v_uint64x8 and cv::v_int64x8: eight 64-bit integer values (unsigned/signed) - int64 +- cv::v_float32x16: sixteen 32-bit floating point values (signed) - float +- cv::v_float64x8: eight 64-bit floating point values (signed) - double +@note +512 bit registers at the moment implemented for AVX512 SIMD extension only, if you want to use this type directly, +don't forget to check the CV_SIMD512 preprocessor definition. + +@note +cv::v_float64x2 is not implemented in NEON variant, if you want to use this type, don't forget to +check the CV_SIMD128_64F preprocessor definition. + +### Load and store operations + +These operations allow to set contents of the register explicitly or by loading it from some memory +block and to save contents of the register to memory block. + +There are variable size register load operations that provide result of maximum available size +depending on chosen platform capabilities. +- Constructors: +@ref v_reg::v_reg(const _Tp *ptr) "from memory", +- Other create methods: +vx_setall_s8, vx_setall_u8, ..., +vx_setzero_u8, vx_setzero_s8, ... +- Memory load operations: +vx_load, vx_load_aligned, vx_load_low, vx_load_halves, +- Memory operations with expansion of values: +vx_load_expand, vx_load_expand_q + +Also there are fixed size register load/store operations. + +For 128 bit registers +- Constructors: +@ref v_reg::v_reg(const _Tp *ptr) "from memory", +@ref v_reg::v_reg(_Tp s0, _Tp s1) "from two values", ... +- Other create methods: +@ref v_setall_s8, @ref v_setall_u8, ..., +@ref v_setzero_u8, @ref v_setzero_s8, ... +- Memory load operations: +@ref v_load, @ref v_load_aligned, @ref v_load_low, @ref v_load_halves, +- Memory operations with expansion of values: +@ref v_load_expand, @ref v_load_expand_q + +For 256 bit registers(check CV_SIMD256 preprocessor definition) +- Constructors: +@ref v_reg::v_reg(const _Tp *ptr) "from memory", +@ref v_reg::v_reg(_Tp s0, _Tp s1, _Tp s2, _Tp s3) "from four values", ... +- Other create methods: +@ref v256_setall_s8, @ref v256_setall_u8, ..., +@ref v256_setzero_u8, @ref v256_setzero_s8, ... +- Memory load operations: +@ref v256_load, @ref v256_load_aligned, @ref v256_load_low, @ref v256_load_halves, +- Memory operations with expansion of values: +@ref v256_load_expand, @ref v256_load_expand_q + +For 512 bit registers(check CV_SIMD512 preprocessor definition) +- Constructors: +@ref v_reg::v_reg(const _Tp *ptr) "from memory", +@ref v_reg::v_reg(_Tp s0, _Tp s1, _Tp s2, _Tp s3, _Tp s4, _Tp s5, _Tp s6, _Tp s7) "from eight values", ... +- Other create methods: +@ref v512_setall_s8, @ref v512_setall_u8, ..., +@ref v512_setzero_u8, @ref v512_setzero_s8, ... +- Memory load operations: +@ref v512_load, @ref v512_load_aligned, @ref v512_load_low, @ref v512_load_halves, +- Memory operations with expansion of values: +@ref v512_load_expand, @ref v512_load_expand_q + +Store to memory operations are similar across different platform capabilities: +@ref v_store, @ref v_store_aligned, +@ref v_store_high, @ref v_store_low + +### Value reordering + +These operations allow to reorder or recombine elements in one or multiple vectors. + +- Interleave, deinterleave (2, 3 and 4 channels): @ref v_load_deinterleave, @ref v_store_interleave +- Expand: @ref v_expand, @ref v_expand_low, @ref v_expand_high +- Pack: @ref v_pack, @ref v_pack_u, @ref v_pack_b, @ref v_rshr_pack, @ref v_rshr_pack_u, +@ref v_pack_store, @ref v_pack_u_store, @ref v_rshr_pack_store, @ref v_rshr_pack_u_store +- Recombine: @ref v_zip, @ref v_recombine, @ref v_combine_low, @ref v_combine_high +- Reverse: @ref v_reverse +- Extract: @ref v_extract + + +### Arithmetic, bitwise and comparison operations + +Element-wise binary and unary operations. + +- Arithmetics: +@ref operator +(const v_reg &a, const v_reg &b) "+", +@ref operator -(const v_reg &a, const v_reg &b) "-", +@ref operator *(const v_reg &a, const v_reg &b) "*", +@ref operator /(const v_reg &a, const v_reg &b) "/", +@ref v_mul_expand + +- Non-saturating arithmetics: @ref v_add_wrap, @ref v_sub_wrap + +- Bitwise shifts: +@ref operator <<(const v_reg &a, int s) "<<", +@ref operator >>(const v_reg &a, int s) ">>", +@ref v_shl, @ref v_shr + +- Bitwise logic: +@ref operator &(const v_reg &a, const v_reg &b) "&", +@ref operator |(const v_reg &a, const v_reg &b) "|", +@ref operator ^(const v_reg &a, const v_reg &b) "^", +@ref operator ~(const v_reg &a) "~" + +- Comparison: +@ref operator >(const v_reg &a, const v_reg &b) ">", +@ref operator >=(const v_reg &a, const v_reg &b) ">=", +@ref operator <(const v_reg &a, const v_reg &b) "<", +@ref operator <=(const v_reg &a, const v_reg &b) "<=", +@ref operator ==(const v_reg &a, const v_reg &b) "==", +@ref operator !=(const v_reg &a, const v_reg &b) "!=" + +- min/max: @ref v_min, @ref v_max + +### Reduce and mask + +Most of these operations return only one value. + +- Reduce: @ref v_reduce_min, @ref v_reduce_max, @ref v_reduce_sum, @ref v_popcount +- Mask: @ref v_signmask, @ref v_check_all, @ref v_check_any, @ref v_select + +### Other math + +- Some frequent operations: @ref v_sqrt, @ref v_invsqrt, @ref v_magnitude, @ref v_sqr_magnitude +- Absolute values: @ref v_abs, @ref v_absdiff, @ref v_absdiffs + +### Conversions + +Different type conversions and casts: + +- Rounding: @ref v_round, @ref v_floor, @ref v_ceil, @ref v_trunc, +- To float: @ref v_cvt_f32, @ref v_cvt_f64 +- Reinterpret: @ref v_reinterpret_as_u8, @ref v_reinterpret_as_s8, ... + +### Matrix operations + +In these operations vectors represent matrix rows/columns: @ref v_dotprod, @ref v_dotprod_fast, +@ref v_dotprod_expand, @ref v_dotprod_expand_fast, @ref v_matmul, @ref v_transpose4x4 + +### Usability + +Most operations are implemented only for some subset of the available types, following matrices +shows the applicability of different operations to the types. + +Regular integers: + +| Operations\\Types | uint 8 | int 8 | uint 16 | int 16 | uint 32 | int 32 | +|-------------------|:-:|:-:|:-:|:-:|:-:|:-:| +|load, store | x | x | x | x | x | x | +|interleave | x | x | x | x | x | x | +|expand | x | x | x | x | x | x | +|expand_low | x | x | x | x | x | x | +|expand_high | x | x | x | x | x | x | +|expand_q | x | x | | | | | +|add, sub | x | x | x | x | x | x | +|add_wrap, sub_wrap | x | x | x | x | | | +|mul_wrap | x | x | x | x | | | +|mul | x | x | x | x | x | x | +|mul_expand | x | x | x | x | x | | +|compare | x | x | x | x | x | x | +|shift | | | x | x | x | x | +|dotprod | | | | x | | x | +|dotprod_fast | | | | x | | x | +|dotprod_expand | x | x | x | x | | x | +|dotprod_expand_fast| x | x | x | x | | x | +|logical | x | x | x | x | x | x | +|min, max | x | x | x | x | x | x | +|absdiff | x | x | x | x | x | x | +|absdiffs | | x | | x | | | +|reduce | x | x | x | x | x | x | +|mask | x | x | x | x | x | x | +|pack | x | x | x | x | x | x | +|pack_u | x | | x | | | | +|pack_b | x | | | | | | +|unpack | x | x | x | x | x | x | +|extract | x | x | x | x | x | x | +|rotate (lanes) | x | x | x | x | x | x | +|cvt_flt32 | | | | | | x | +|cvt_flt64 | | | | | | x | +|transpose4x4 | | | | | x | x | +|reverse | x | x | x | x | x | x | +|extract_n | x | x | x | x | x | x | +|broadcast_element | | | | | x | x | + +Big integers: + +| Operations\\Types | uint 64 | int 64 | +|-------------------|:-:|:-:| +|load, store | x | x | +|add, sub | x | x | +|shift | x | x | +|logical | x | x | +|reverse | x | x | +|extract | x | x | +|rotate (lanes) | x | x | +|cvt_flt64 | | x | +|extract_n | x | x | + +Floating point: + +| Operations\\Types | float 32 | float 64 | +|-------------------|:-:|:-:| +|load, store | x | x | +|interleave | x | | +|add, sub | x | x | +|mul | x | x | +|div | x | x | +|compare | x | x | +|min, max | x | x | +|absdiff | x | x | +|reduce | x | | +|mask | x | x | +|unpack | x | x | +|cvt_flt32 | | x | +|cvt_flt64 | x | | +|sqrt, abs | x | x | +|float math | x | x | +|transpose4x4 | x | | +|extract | x | x | +|rotate (lanes) | x | x | +|reverse | x | x | +|extract_n | x | x | +|broadcast_element | x | | + + @{ */ + +template struct v_reg +{ +//! @cond IGNORED + typedef _Tp lane_type; + enum { nlanes = n }; +// !@endcond + + /** @brief Constructor + + Initializes register with data from memory + @param ptr pointer to memory block with data for register */ + explicit v_reg(const _Tp* ptr) { for( int i = 0; i < n; i++ ) s[i] = ptr[i]; } + + /** @brief Constructor + + Initializes register with two 64-bit values */ + v_reg(_Tp s0, _Tp s1) { s[0] = s0; s[1] = s1; } + + /** @brief Constructor + + Initializes register with four 32-bit values */ + v_reg(_Tp s0, _Tp s1, _Tp s2, _Tp s3) { s[0] = s0; s[1] = s1; s[2] = s2; s[3] = s3; } + + /** @brief Constructor + + Initializes register with eight 16-bit values */ + v_reg(_Tp s0, _Tp s1, _Tp s2, _Tp s3, + _Tp s4, _Tp s5, _Tp s6, _Tp s7) + { + s[0] = s0; s[1] = s1; s[2] = s2; s[3] = s3; + s[4] = s4; s[5] = s5; s[6] = s6; s[7] = s7; + } + + /** @brief Constructor + + Initializes register with sixteen 8-bit values */ + v_reg(_Tp s0, _Tp s1, _Tp s2, _Tp s3, + _Tp s4, _Tp s5, _Tp s6, _Tp s7, + _Tp s8, _Tp s9, _Tp s10, _Tp s11, + _Tp s12, _Tp s13, _Tp s14, _Tp s15) + { + s[0] = s0; s[1] = s1; s[2] = s2; s[3] = s3; + s[4] = s4; s[5] = s5; s[6] = s6; s[7] = s7; + s[8] = s8; s[9] = s9; s[10] = s10; s[11] = s11; + s[12] = s12; s[13] = s13; s[14] = s14; s[15] = s15; + } + + /** @brief Default constructor + + Does not initialize anything*/ + v_reg() {} + + /** @brief Copy constructor */ + v_reg(const v_reg<_Tp, n> & r) + { + for( int i = 0; i < n; i++ ) + s[i] = r.s[i]; + } + /** @brief Access first value + + Returns value of the first lane according to register type, for example: + @code{.cpp} + v_int32x4 r(1, 2, 3, 4); + int v = r.get0(); // returns 1 + v_uint64x2 r(1, 2); + uint64_t v = r.get0(); // returns 1 + @endcode + */ + _Tp get0() const { return s[0]; } + +//! @cond IGNORED + _Tp get(const int i) const { return s[i]; } + v_reg<_Tp, n> high() const + { + v_reg<_Tp, n> c; + int i; + for( i = 0; i < n/2; i++ ) + { + c.s[i] = s[i+(n/2)]; + c.s[i+(n/2)] = 0; + } + return c; + } + + static v_reg<_Tp, n> zero() + { + v_reg<_Tp, n> c; + for( int i = 0; i < n; i++ ) + c.s[i] = (_Tp)0; + return c; + } + + static v_reg<_Tp, n> all(_Tp s) + { + v_reg<_Tp, n> c; + for( int i = 0; i < n; i++ ) + c.s[i] = s; + return c; + } + + template v_reg<_Tp2, n2> reinterpret_as() const + { + size_t bytes = std::min(sizeof(_Tp2)*n2, sizeof(_Tp)*n); + v_reg<_Tp2, n2> c; + std::memcpy(&c.s[0], &s[0], bytes); + return c; + } + + v_reg& operator=(const v_reg<_Tp, n> & r) + { + for( int i = 0; i < n; i++ ) + s[i] = r.s[i]; + return *this; + } + + _Tp s[n]; +//! @endcond +}; + +/** @brief Sixteen 8-bit unsigned integer values */ +typedef v_reg v_uint8x16; +/** @brief Sixteen 8-bit signed integer values */ +typedef v_reg v_int8x16; +/** @brief Eight 16-bit unsigned integer values */ +typedef v_reg v_uint16x8; +/** @brief Eight 16-bit signed integer values */ +typedef v_reg v_int16x8; +/** @brief Four 32-bit unsigned integer values */ +typedef v_reg v_uint32x4; +/** @brief Four 32-bit signed integer values */ +typedef v_reg v_int32x4; +/** @brief Four 32-bit floating point values (single precision) */ +typedef v_reg v_float32x4; +/** @brief Two 64-bit floating point values (double precision) */ +typedef v_reg v_float64x2; +/** @brief Two 64-bit unsigned integer values */ +typedef v_reg v_uint64x2; +/** @brief Two 64-bit signed integer values */ +typedef v_reg v_int64x2; + +#if CV_SIMD256 +/** @brief Thirty two 8-bit unsigned integer values */ +typedef v_reg v_uint8x32; +/** @brief Thirty two 8-bit signed integer values */ +typedef v_reg v_int8x32; +/** @brief Sixteen 16-bit unsigned integer values */ +typedef v_reg v_uint16x16; +/** @brief Sixteen 16-bit signed integer values */ +typedef v_reg v_int16x16; +/** @brief Eight 32-bit unsigned integer values */ +typedef v_reg v_uint32x8; +/** @brief Eight 32-bit signed integer values */ +typedef v_reg v_int32x8; +/** @brief Eight 32-bit floating point values (single precision) */ +typedef v_reg v_float32x8; +/** @brief Four 64-bit floating point values (double precision) */ +typedef v_reg v_float64x4; +/** @brief Four 64-bit unsigned integer values */ +typedef v_reg v_uint64x4; +/** @brief Four 64-bit signed integer values */ +typedef v_reg v_int64x4; +#endif + +#if CV_SIMD512 +/** @brief Sixty four 8-bit unsigned integer values */ +typedef v_reg v_uint8x64; +/** @brief Sixty four 8-bit signed integer values */ +typedef v_reg v_int8x64; +/** @brief Thirty two 16-bit unsigned integer values */ +typedef v_reg v_uint16x32; +/** @brief Thirty two 16-bit signed integer values */ +typedef v_reg v_int16x32; +/** @brief Sixteen 32-bit unsigned integer values */ +typedef v_reg v_uint32x16; +/** @brief Sixteen 32-bit signed integer values */ +typedef v_reg v_int32x16; +/** @brief Sixteen 32-bit floating point values (single precision) */ +typedef v_reg v_float32x16; +/** @brief Eight 64-bit floating point values (double precision) */ +typedef v_reg v_float64x8; +/** @brief Eight 64-bit unsigned integer values */ +typedef v_reg v_uint64x8; +/** @brief Eight 64-bit signed integer values */ +typedef v_reg v_int64x8; +#endif + +enum { + simd128_width = 16, +#if CV_SIMD256 + simd256_width = 32, +#endif +#if CV_SIMD512 + simd512_width = 64, + simdmax_width = simd512_width +#elif CV_SIMD256 + simdmax_width = simd256_width +#else + simdmax_width = simd128_width +#endif +}; + +/** @brief Add values + +For all types. */ +template CV_INLINE v_reg<_Tp, n> operator+(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b); +template CV_INLINE v_reg<_Tp, n>& operator+=(v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b); + +/** @brief Subtract values + +For all types. */ +template CV_INLINE v_reg<_Tp, n> operator-(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b); +template CV_INLINE v_reg<_Tp, n>& operator-=(v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b); + +/** @brief Multiply values + +For 16- and 32-bit integer types and floating types. */ +template CV_INLINE v_reg<_Tp, n> operator*(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b); +template CV_INLINE v_reg<_Tp, n>& operator*=(v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b); + +/** @brief Divide values + +For floating types only. */ +template CV_INLINE v_reg<_Tp, n> operator/(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b); +template CV_INLINE v_reg<_Tp, n>& operator/=(v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b); + + +/** @brief Bitwise AND + +Only for integer types. */ +template CV_INLINE v_reg<_Tp, n> operator&(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b); +template CV_INLINE v_reg<_Tp, n>& operator&=(v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b); + +/** @brief Bitwise OR + +Only for integer types. */ +template CV_INLINE v_reg<_Tp, n> operator|(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b); +template CV_INLINE v_reg<_Tp, n>& operator|=(v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b); + +/** @brief Bitwise XOR + +Only for integer types.*/ +template CV_INLINE v_reg<_Tp, n> operator^(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b); +template CV_INLINE v_reg<_Tp, n>& operator^=(v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b); + +/** @brief Bitwise NOT + +Only for integer types.*/ +template CV_INLINE v_reg<_Tp, n> operator~(const v_reg<_Tp, n>& a); + + +#ifndef CV_DOXYGEN + +#define CV__HAL_INTRIN_EXPAND_WITH_INTEGER_TYPES(macro_name, ...) \ +__CV_EXPAND(macro_name(uchar, __VA_ARGS__)) \ +__CV_EXPAND(macro_name(schar, __VA_ARGS__)) \ +__CV_EXPAND(macro_name(ushort, __VA_ARGS__)) \ +__CV_EXPAND(macro_name(short, __VA_ARGS__)) \ +__CV_EXPAND(macro_name(unsigned, __VA_ARGS__)) \ +__CV_EXPAND(macro_name(int, __VA_ARGS__)) \ +__CV_EXPAND(macro_name(uint64, __VA_ARGS__)) \ +__CV_EXPAND(macro_name(int64, __VA_ARGS__)) \ + +#define CV__HAL_INTRIN_EXPAND_WITH_FP_TYPES(macro_name, ...) \ +__CV_EXPAND(macro_name(float, __VA_ARGS__)) \ +__CV_EXPAND(macro_name(double, __VA_ARGS__)) \ + +#define CV__HAL_INTRIN_EXPAND_WITH_ALL_TYPES(macro_name, ...) \ +CV__HAL_INTRIN_EXPAND_WITH_INTEGER_TYPES(macro_name, __VA_ARGS__) \ +CV__HAL_INTRIN_EXPAND_WITH_FP_TYPES(macro_name, __VA_ARGS__) \ + +#define CV__HAL_INTRIN_IMPL_BIN_OP_(_Tp, bin_op) \ +template inline \ +v_reg<_Tp, n> operator bin_op (const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \ +{ \ + v_reg<_Tp, n> c; \ + for( int i = 0; i < n; i++ ) \ + c.s[i] = saturate_cast<_Tp>(a.s[i] bin_op b.s[i]); \ + return c; \ +} \ +template inline \ +v_reg<_Tp, n>& operator bin_op##= (v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \ +{ \ + for( int i = 0; i < n; i++ ) \ + a.s[i] = saturate_cast<_Tp>(a.s[i] bin_op b.s[i]); \ + return a; \ +} + +#define CV__HAL_INTRIN_IMPL_BIN_OP(bin_op) CV__HAL_INTRIN_EXPAND_WITH_ALL_TYPES(CV__HAL_INTRIN_IMPL_BIN_OP_, bin_op) + +CV__HAL_INTRIN_IMPL_BIN_OP(+) +CV__HAL_INTRIN_IMPL_BIN_OP(-) +CV__HAL_INTRIN_IMPL_BIN_OP(*) +CV__HAL_INTRIN_EXPAND_WITH_FP_TYPES(CV__HAL_INTRIN_IMPL_BIN_OP_, /) + +#define CV__HAL_INTRIN_IMPL_BIT_OP_(_Tp, bit_op) \ +template CV_INLINE \ +v_reg<_Tp, n> operator bit_op (const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \ +{ \ + v_reg<_Tp, n> c; \ + typedef typename V_TypeTraits<_Tp>::int_type itype; \ + for( int i = 0; i < n; i++ ) \ + c.s[i] = V_TypeTraits<_Tp>::reinterpret_from_int((itype)(V_TypeTraits<_Tp>::reinterpret_int(a.s[i]) bit_op \ + V_TypeTraits<_Tp>::reinterpret_int(b.s[i]))); \ + return c; \ +} \ +template CV_INLINE \ +v_reg<_Tp, n>& operator bit_op##= (v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \ +{ \ + typedef typename V_TypeTraits<_Tp>::int_type itype; \ + for( int i = 0; i < n; i++ ) \ + a.s[i] = V_TypeTraits<_Tp>::reinterpret_from_int((itype)(V_TypeTraits<_Tp>::reinterpret_int(a.s[i]) bit_op \ + V_TypeTraits<_Tp>::reinterpret_int(b.s[i]))); \ + return a; \ +} + +#define CV__HAL_INTRIN_IMPL_BIT_OP(bit_op) \ +CV__HAL_INTRIN_EXPAND_WITH_INTEGER_TYPES(CV__HAL_INTRIN_IMPL_BIT_OP_, bit_op) \ +CV__HAL_INTRIN_EXPAND_WITH_FP_TYPES(CV__HAL_INTRIN_IMPL_BIT_OP_, bit_op) /* TODO: FIXIT remove this after masks refactoring */ + + +CV__HAL_INTRIN_IMPL_BIT_OP(&) +CV__HAL_INTRIN_IMPL_BIT_OP(|) +CV__HAL_INTRIN_IMPL_BIT_OP(^) + +#define CV__HAL_INTRIN_IMPL_BITWISE_NOT_(_Tp, dummy) \ +template CV_INLINE \ +v_reg<_Tp, n> operator ~ (const v_reg<_Tp, n>& a) \ +{ \ + v_reg<_Tp, n> c; \ + for( int i = 0; i < n; i++ ) \ + c.s[i] = V_TypeTraits<_Tp>::reinterpret_from_int(~V_TypeTraits<_Tp>::reinterpret_int(a.s[i])); \ + return c; \ +} \ + +CV__HAL_INTRIN_EXPAND_WITH_INTEGER_TYPES(CV__HAL_INTRIN_IMPL_BITWISE_NOT_, ~) + +#endif // !CV_DOXYGEN + + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_MATH_FUNC(func, cfunc, _Tp2) \ +template inline v_reg<_Tp2, n> func(const v_reg<_Tp, n>& a) \ +{ \ + v_reg<_Tp2, n> c; \ + for( int i = 0; i < n; i++ ) \ + c.s[i] = cfunc(a.s[i]); \ + return c; \ +} + +/** @brief Square root of elements + +Only for floating point types.*/ +OPENCV_HAL_IMPL_MATH_FUNC(v_sqrt, std::sqrt, _Tp) + +//! @cond IGNORED +OPENCV_HAL_IMPL_MATH_FUNC(v_sin, std::sin, _Tp) +OPENCV_HAL_IMPL_MATH_FUNC(v_cos, std::cos, _Tp) +OPENCV_HAL_IMPL_MATH_FUNC(v_exp, std::exp, _Tp) +OPENCV_HAL_IMPL_MATH_FUNC(v_log, std::log, _Tp) +//! @endcond + +/** @brief Absolute value of elements + +Only for floating point types.*/ +OPENCV_HAL_IMPL_MATH_FUNC(v_abs, (typename V_TypeTraits<_Tp>::abs_type)std::abs, + typename V_TypeTraits<_Tp>::abs_type) + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_MINMAX_FUNC(func, cfunc) \ +template inline v_reg<_Tp, n> func(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \ +{ \ + v_reg<_Tp, n> c; \ + for( int i = 0; i < n; i++ ) \ + c.s[i] = cfunc(a.s[i], b.s[i]); \ + return c; \ +} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_REDUCE_MINMAX_FUNC(func, cfunc) \ +template inline _Tp func(const v_reg<_Tp, n>& a) \ +{ \ + _Tp c = a.s[0]; \ + for( int i = 1; i < n; i++ ) \ + c = cfunc(c, a.s[i]); \ + return c; \ +} + +/** @brief Choose min values for each pair + +Scheme: +@code +{A1 A2 ...} +{B1 B2 ...} +-------------- +{min(A1,B1) min(A2,B2) ...} +@endcode +For all types except 64-bit integer. */ +OPENCV_HAL_IMPL_MINMAX_FUNC(v_min, std::min) + +/** @brief Choose max values for each pair + +Scheme: +@code +{A1 A2 ...} +{B1 B2 ...} +-------------- +{max(A1,B1) max(A2,B2) ...} +@endcode +For all types except 64-bit integer. */ +OPENCV_HAL_IMPL_MINMAX_FUNC(v_max, std::max) + +/** @brief Find one min value + +Scheme: +@code +{A1 A2 A3 ...} => min(A1,A2,A3,...) +@endcode +For all types except 64-bit integer and 64-bit floating point types. */ +OPENCV_HAL_IMPL_REDUCE_MINMAX_FUNC(v_reduce_min, std::min) + +/** @brief Find one max value + +Scheme: +@code +{A1 A2 A3 ...} => max(A1,A2,A3,...) +@endcode +For all types except 64-bit integer and 64-bit floating point types. */ +OPENCV_HAL_IMPL_REDUCE_MINMAX_FUNC(v_reduce_max, std::max) + +static const unsigned char popCountTable[] = +{ + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, +}; +/** @brief Count the 1 bits in the vector lanes and return result as corresponding unsigned type + +Scheme: +@code +{A1 A2 A3 ...} => {popcount(A1), popcount(A2), popcount(A3), ...} +@endcode +For all integer types. */ +template +inline v_reg::abs_type, n> v_popcount(const v_reg<_Tp, n>& a) +{ + v_reg::abs_type, n> b = v_reg::abs_type, n>::zero(); + for (int i = 0; i < n*(int)sizeof(_Tp); i++) + b.s[i/sizeof(_Tp)] += popCountTable[v_reinterpret_as_u8(a).s[i]]; + return b; +} + + +//! @cond IGNORED +template +inline void v_minmax( const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b, + v_reg<_Tp, n>& minval, v_reg<_Tp, n>& maxval ) +{ + for( int i = 0; i < n; i++ ) + { + minval.s[i] = std::min(a.s[i], b.s[i]); + maxval.s[i] = std::max(a.s[i], b.s[i]); + } +} +//! @endcond + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_CMP_OP(cmp_op) \ +template \ +inline v_reg<_Tp, n> operator cmp_op(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \ +{ \ + typedef typename V_TypeTraits<_Tp>::int_type itype; \ + v_reg<_Tp, n> c; \ + for( int i = 0; i < n; i++ ) \ + c.s[i] = V_TypeTraits<_Tp>::reinterpret_from_int((itype)-(int)(a.s[i] cmp_op b.s[i])); \ + return c; \ +} + +/** @brief Less-than comparison + +For all types except 64-bit integer values. */ +OPENCV_HAL_IMPL_CMP_OP(<) + +/** @brief Greater-than comparison + +For all types except 64-bit integer values. */ +OPENCV_HAL_IMPL_CMP_OP(>) + +/** @brief Less-than or equal comparison + +For all types except 64-bit integer values. */ +OPENCV_HAL_IMPL_CMP_OP(<=) + +/** @brief Greater-than or equal comparison + +For all types except 64-bit integer values. */ +OPENCV_HAL_IMPL_CMP_OP(>=) + +/** @brief Equal comparison + +For all types except 64-bit integer values. */ +OPENCV_HAL_IMPL_CMP_OP(==) + +/** @brief Not equal comparison + +For all types except 64-bit integer values. */ +OPENCV_HAL_IMPL_CMP_OP(!=) + +template +inline v_reg v_not_nan(const v_reg& a) +{ + typedef typename V_TypeTraits::int_type itype; + v_reg c; + for (int i = 0; i < n; i++) + c.s[i] = V_TypeTraits::reinterpret_from_int((itype)-(int)(a.s[i] == a.s[i])); + return c; +} +template +inline v_reg v_not_nan(const v_reg& a) +{ + typedef typename V_TypeTraits::int_type itype; + v_reg c; + for (int i = 0; i < n; i++) + c.s[i] = V_TypeTraits::reinterpret_from_int((itype)-(int)(a.s[i] == a.s[i])); + return c; +} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_ARITHM_OP(func, bin_op, cast_op, _Tp2) \ +template \ +inline v_reg<_Tp2, n> func(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \ +{ \ + typedef _Tp2 rtype; \ + v_reg c; \ + for( int i = 0; i < n; i++ ) \ + c.s[i] = cast_op(a.s[i] bin_op b.s[i]); \ + return c; \ +} + +/** @brief Add values without saturation + +For 8- and 16-bit integer values. */ +OPENCV_HAL_IMPL_ARITHM_OP(v_add_wrap, +, (_Tp), _Tp) + +/** @brief Subtract values without saturation + +For 8- and 16-bit integer values. */ +OPENCV_HAL_IMPL_ARITHM_OP(v_sub_wrap, -, (_Tp), _Tp) + +/** @brief Multiply values without saturation + +For 8- and 16-bit integer values. */ +OPENCV_HAL_IMPL_ARITHM_OP(v_mul_wrap, *, (_Tp), _Tp) + +//! @cond IGNORED +template inline T _absdiff(T a, T b) +{ + return a > b ? a - b : b - a; +} +//! @endcond + +/** @brief Absolute difference + +Returns \f$ |a - b| \f$ converted to corresponding unsigned type. +Example: +@code{.cpp} +v_int32x4 a, b; // {1, 2, 3, 4} and {4, 3, 2, 1} +v_uint32x4 c = v_absdiff(a, b); // result is {3, 1, 1, 3} +@endcode +For 8-, 16-, 32-bit integer source types. */ +template +inline v_reg::abs_type, n> v_absdiff(const v_reg<_Tp, n>& a, const v_reg<_Tp, n> & b) +{ + typedef typename V_TypeTraits<_Tp>::abs_type rtype; + v_reg c; + const rtype mask = (rtype)(std::numeric_limits<_Tp>::is_signed ? (1 << (sizeof(rtype)*8 - 1)) : 0); + for( int i = 0; i < n; i++ ) + { + rtype ua = a.s[i] ^ mask; + rtype ub = b.s[i] ^ mask; + c.s[i] = _absdiff(ua, ub); + } + return c; +} + +/** @overload + +For 32-bit floating point values */ +template inline v_reg v_absdiff(const v_reg& a, const v_reg& b) +{ + v_reg c; + for( int i = 0; i < c.nlanes; i++ ) + c.s[i] = _absdiff(a.s[i], b.s[i]); + return c; +} + +/** @overload + +For 64-bit floating point values */ +template inline v_reg v_absdiff(const v_reg& a, const v_reg& b) +{ + v_reg c; + for( int i = 0; i < c.nlanes; i++ ) + c.s[i] = _absdiff(a.s[i], b.s[i]); + return c; +} + +/** @brief Saturating absolute difference + +Returns \f$ saturate(|a - b|) \f$ . +For 8-, 16-bit signed integer source types. */ +template +inline v_reg<_Tp, n> v_absdiffs(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + v_reg<_Tp, n> c; + for( int i = 0; i < n; i++) + c.s[i] = saturate_cast<_Tp>(std::abs(a.s[i] - b.s[i])); + return c; +} + +/** @brief Inversed square root + +Returns \f$ 1/sqrt(a) \f$ +For floating point types only. */ +template +inline v_reg<_Tp, n> v_invsqrt(const v_reg<_Tp, n>& a) +{ + v_reg<_Tp, n> c; + for( int i = 0; i < n; i++ ) + c.s[i] = 1.f/std::sqrt(a.s[i]); + return c; +} + +/** @brief Magnitude + +Returns \f$ sqrt(a^2 + b^2) \f$ +For floating point types only. */ +template +inline v_reg<_Tp, n> v_magnitude(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + v_reg<_Tp, n> c; + for( int i = 0; i < n; i++ ) + c.s[i] = std::sqrt(a.s[i]*a.s[i] + b.s[i]*b.s[i]); + return c; +} + +/** @brief Square of the magnitude + +Returns \f$ a^2 + b^2 \f$ +For floating point types only. */ +template +inline v_reg<_Tp, n> v_sqr_magnitude(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + v_reg<_Tp, n> c; + for( int i = 0; i < n; i++ ) + c.s[i] = a.s[i]*a.s[i] + b.s[i]*b.s[i]; + return c; +} + +/** @brief Multiply and add + + Returns \f$ a*b + c \f$ + For floating point types and signed 32bit int only. */ +template +inline v_reg<_Tp, n> v_fma(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b, + const v_reg<_Tp, n>& c) +{ + v_reg<_Tp, n> d; + for( int i = 0; i < n; i++ ) + d.s[i] = a.s[i]*b.s[i] + c.s[i]; + return d; +} + +/** @brief A synonym for v_fma */ +template +inline v_reg<_Tp, n> v_muladd(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b, + const v_reg<_Tp, n>& c) +{ + return v_fma(a, b, c); +} + +/** @brief Dot product of elements + +Multiply values in two registers and sum adjacent result pairs. + +Scheme: +@code + {A1 A2 ...} // 16-bit +x {B1 B2 ...} // 16-bit +------------- +{A1B1+A2B2 ...} // 32-bit + +@endcode +*/ +template inline v_reg::w_type, n/2> +v_dotprod(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + typedef typename V_TypeTraits<_Tp>::w_type w_type; + v_reg c; + for( int i = 0; i < (n/2); i++ ) + c.s[i] = (w_type)a.s[i*2]*b.s[i*2] + (w_type)a.s[i*2+1]*b.s[i*2+1]; + return c; +} + +/** @brief Dot product of elements + +Same as cv::v_dotprod, but add a third element to the sum of adjacent pairs. +Scheme: +@code + {A1 A2 ...} // 16-bit +x {B1 B2 ...} // 16-bit +------------- + {A1B1+A2B2+C1 ...} // 32-bit +@endcode +*/ +template inline v_reg::w_type, n/2> +v_dotprod(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b, + const v_reg::w_type, n / 2>& c) +{ + typedef typename V_TypeTraits<_Tp>::w_type w_type; + v_reg s; + for( int i = 0; i < (n/2); i++ ) + s.s[i] = (w_type)a.s[i*2]*b.s[i*2] + (w_type)a.s[i*2+1]*b.s[i*2+1] + c.s[i]; + return s; +} + +/** @brief Fast Dot product of elements + +Same as cv::v_dotprod, but it may perform unorder sum between result pairs in some platforms, +this intrinsic can be used if the sum among all lanes is only matters +and also it should be yielding better performance on the affected platforms. + +*/ +template inline v_reg::w_type, n/2> +v_dotprod_fast(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ return v_dotprod(a, b); } + +/** @brief Fast Dot product of elements + +Same as cv::v_dotprod_fast, but add a third element to the sum of adjacent pairs. +*/ +template inline v_reg::w_type, n/2> +v_dotprod_fast(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b, + const v_reg::w_type, n / 2>& c) +{ return v_dotprod(a, b, c); } + +/** @brief Dot product of elements and expand + +Multiply values in two registers and expand the sum of adjacent result pairs. + +Scheme: +@code + {A1 A2 A3 A4 ...} // 8-bit +x {B1 B2 B3 B4 ...} // 8-bit +------------- + {A1B1+A2B2+A3B3+A4B4 ...} // 32-bit + +@endcode +*/ +template inline v_reg::q_type, n/4> +v_dotprod_expand(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + typedef typename V_TypeTraits<_Tp>::q_type q_type; + v_reg s; + for( int i = 0; i < (n/4); i++ ) + s.s[i] = (q_type)a.s[i*4 ]*b.s[i*4 ] + (q_type)a.s[i*4 + 1]*b.s[i*4 + 1] + + (q_type)a.s[i*4 + 2]*b.s[i*4 + 2] + (q_type)a.s[i*4 + 3]*b.s[i*4 + 3]; + return s; +} + +/** @brief Dot product of elements + +Same as cv::v_dotprod_expand, but add a third element to the sum of adjacent pairs. +Scheme: +@code + {A1 A2 A3 A4 ...} // 8-bit +x {B1 B2 B3 B4 ...} // 8-bit +------------- + {A1B1+A2B2+A3B3+A4B4+C1 ...} // 32-bit +@endcode +*/ +template inline v_reg::q_type, n/4> +v_dotprod_expand(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b, + const v_reg::q_type, n / 4>& c) +{ + typedef typename V_TypeTraits<_Tp>::q_type q_type; + v_reg s; + for( int i = 0; i < (n/4); i++ ) + s.s[i] = (q_type)a.s[i*4 ]*b.s[i*4 ] + (q_type)a.s[i*4 + 1]*b.s[i*4 + 1] + + (q_type)a.s[i*4 + 2]*b.s[i*4 + 2] + (q_type)a.s[i*4 + 3]*b.s[i*4 + 3] + c.s[i]; + return s; +} + +/** @brief Fast Dot product of elements and expand + +Multiply values in two registers and expand the sum of adjacent result pairs. + +Same as cv::v_dotprod_expand, but it may perform unorder sum between result pairs in some platforms, +this intrinsic can be used if the sum among all lanes is only matters +and also it should be yielding better performance on the affected platforms. + +*/ +template inline v_reg::q_type, n/4> +v_dotprod_expand_fast(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ return v_dotprod_expand(a, b); } + +/** @brief Fast Dot product of elements + +Same as cv::v_dotprod_expand_fast, but add a third element to the sum of adjacent pairs. +*/ +template inline v_reg::q_type, n/4> +v_dotprod_expand_fast(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b, + const v_reg::q_type, n / 4>& c) +{ return v_dotprod_expand(a, b, c); } + +/** @brief Multiply and expand + +Multiply values two registers and store results in two registers with wider pack type. +Scheme: +@code + {A B C D} // 32-bit +x {E F G H} // 32-bit +--------------- +{AE BF} // 64-bit + {CG DH} // 64-bit +@endcode +Example: +@code{.cpp} +v_uint32x4 a, b; // {1,2,3,4} and {2,2,2,2} +v_uint64x2 c, d; // results +v_mul_expand(a, b, c, d); // c, d = {2,4}, {6, 8} +@endcode +Implemented only for 16- and unsigned 32-bit source types (v_int16x8, v_uint16x8, v_uint32x4). +*/ +template inline void v_mul_expand(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b, + v_reg::w_type, n/2>& c, + v_reg::w_type, n/2>& d) +{ + typedef typename V_TypeTraits<_Tp>::w_type w_type; + for( int i = 0; i < (n/2); i++ ) + { + c.s[i] = (w_type)a.s[i]*b.s[i]; + d.s[i] = (w_type)a.s[i+(n/2)]*b.s[i+(n/2)]; + } +} + +/** @brief Multiply and extract high part + +Multiply values two registers and store high part of the results. +Implemented only for 16-bit source types (v_int16x8, v_uint16x8). Returns \f$ a*b >> 16 \f$ +*/ +template inline v_reg<_Tp, n> v_mul_hi(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + typedef typename V_TypeTraits<_Tp>::w_type w_type; + v_reg<_Tp, n> c; + for (int i = 0; i < n; i++) + c.s[i] = (_Tp)(((w_type)a.s[i] * b.s[i]) >> sizeof(_Tp)*8); + return c; +} + +//! @cond IGNORED +template inline void v_hsum(const v_reg<_Tp, n>& a, + v_reg::w_type, n/2>& c) +{ + typedef typename V_TypeTraits<_Tp>::w_type w_type; + for( int i = 0; i < (n/2); i++ ) + { + c.s[i] = (w_type)a.s[i*2] + a.s[i*2+1]; + } +} +//! @endcond + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_SHIFT_OP(shift_op) \ +template inline v_reg<_Tp, n> operator shift_op(const v_reg<_Tp, n>& a, int imm) \ +{ \ + v_reg<_Tp, n> c; \ + for( int i = 0; i < n; i++ ) \ + c.s[i] = (_Tp)(a.s[i] shift_op imm); \ + return c; \ +} + +/** @brief Bitwise shift left + +For 16-, 32- and 64-bit integer values. */ +OPENCV_HAL_IMPL_SHIFT_OP(<< ) + +/** @brief Bitwise shift right + +For 16-, 32- and 64-bit integer values. */ +OPENCV_HAL_IMPL_SHIFT_OP(>> ) + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_ROTATE_SHIFT_OP(suffix,opA,opB) \ +template inline v_reg<_Tp, n> v_rotate_##suffix(const v_reg<_Tp, n>& a) \ +{ \ + v_reg<_Tp, n> b; \ + for (int i = 0; i < n; i++) \ + { \ + int sIndex = i opA imm; \ + if (0 <= sIndex && sIndex < n) \ + { \ + b.s[i] = a.s[sIndex]; \ + } \ + else \ + { \ + b.s[i] = 0; \ + } \ + } \ + return b; \ +} \ +template inline v_reg<_Tp, n> v_rotate_##suffix(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \ +{ \ + v_reg<_Tp, n> c; \ + for (int i = 0; i < n; i++) \ + { \ + int aIndex = i opA imm; \ + int bIndex = i opA imm opB n; \ + if (0 <= bIndex && bIndex < n) \ + { \ + c.s[i] = b.s[bIndex]; \ + } \ + else if (0 <= aIndex && aIndex < n) \ + { \ + c.s[i] = a.s[aIndex]; \ + } \ + else \ + { \ + c.s[i] = 0; \ + } \ + } \ + return c; \ +} + +/** @brief Element shift left among vector + +For all type */ +OPENCV_HAL_IMPL_ROTATE_SHIFT_OP(left, -, +) + +/** @brief Element shift right among vector + +For all type */ +OPENCV_HAL_IMPL_ROTATE_SHIFT_OP(right, +, -) + +/** @brief Sum packed values + +Scheme: +@code +{A1 A2 A3 ...} => sum{A1,A2,A3,...} +@endcode +*/ +template inline typename V_TypeTraits<_Tp>::sum_type v_reduce_sum(const v_reg<_Tp, n>& a) +{ + typename V_TypeTraits<_Tp>::sum_type c = a.s[0]; + for( int i = 1; i < n; i++ ) + c += a.s[i]; + return c; +} + +/** @brief Sums all elements of each input vector, returns the vector of sums + + Scheme: + @code + result[0] = a[0] + a[1] + a[2] + a[3] + result[1] = b[0] + b[1] + b[2] + b[3] + result[2] = c[0] + c[1] + c[2] + c[3] + result[3] = d[0] + d[1] + d[2] + d[3] + @endcode +*/ +template inline v_reg v_reduce_sum4(const v_reg& a, const v_reg& b, + const v_reg& c, const v_reg& d) +{ + v_reg r; + for(int i = 0; i < (n/4); i++) + { + r.s[i*4 + 0] = a.s[i*4 + 0] + a.s[i*4 + 1] + a.s[i*4 + 2] + a.s[i*4 + 3]; + r.s[i*4 + 1] = b.s[i*4 + 0] + b.s[i*4 + 1] + b.s[i*4 + 2] + b.s[i*4 + 3]; + r.s[i*4 + 2] = c.s[i*4 + 0] + c.s[i*4 + 1] + c.s[i*4 + 2] + c.s[i*4 + 3]; + r.s[i*4 + 3] = d.s[i*4 + 0] + d.s[i*4 + 1] + d.s[i*4 + 2] + d.s[i*4 + 3]; + } + return r; +} + +/** @brief Sum absolute differences of values + +Scheme: +@code +{A1 A2 A3 ...} {B1 B2 B3 ...} => sum{ABS(A1-B1),abs(A2-B2),abs(A3-B3),...} +@endcode +For all types except 64-bit types.*/ +template inline typename V_TypeTraits< typename V_TypeTraits<_Tp>::abs_type >::sum_type v_reduce_sad(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + typename V_TypeTraits< typename V_TypeTraits<_Tp>::abs_type >::sum_type c = _absdiff(a.s[0], b.s[0]); + for (int i = 1; i < n; i++) + c += _absdiff(a.s[i], b.s[i]); + return c; +} + +/** @brief Get negative values mask +@deprecated v_signmask depends on a lane count heavily and therefore isn't universal enough + +Returned value is a bit mask with bits set to 1 on places corresponding to negative packed values indexes. +Example: +@code{.cpp} +v_int32x4 r; // set to {-1, -1, 1, 1} +int mask = v_signmask(r); // mask = 3 <== 00000000 00000000 00000000 00000011 +@endcode +*/ +template inline int v_signmask(const v_reg<_Tp, n>& a) +{ + int mask = 0; + for( int i = 0; i < n; i++ ) + mask |= (V_TypeTraits<_Tp>::reinterpret_int(a.s[i]) < 0) << i; + return mask; +} + +/** @brief Get first negative lane index + +Returned value is an index of first negative lane (undefined for input of all positive values) +Example: +@code{.cpp} +v_int32x4 r; // set to {0, 0, -1, -1} +int idx = v_heading_zeros(r); // idx = 2 +@endcode +*/ +template inline int v_scan_forward(const v_reg<_Tp, n>& a) +{ + for (int i = 0; i < n; i++) + if(V_TypeTraits<_Tp>::reinterpret_int(a.s[i]) < 0) + return i; + return 0; +} + +/** @brief Check if all packed values are less than zero + +Unsigned values will be casted to signed: `uchar 254 => char -2`. +*/ +template inline bool v_check_all(const v_reg<_Tp, n>& a) +{ + for( int i = 0; i < n; i++ ) + if( V_TypeTraits<_Tp>::reinterpret_int(a.s[i]) >= 0 ) + return false; + return true; +} + +/** @brief Check if any of packed values is less than zero + +Unsigned values will be casted to signed: `uchar 254 => char -2`. +*/ +template inline bool v_check_any(const v_reg<_Tp, n>& a) +{ + for( int i = 0; i < n; i++ ) + if( V_TypeTraits<_Tp>::reinterpret_int(a.s[i]) < 0 ) + return true; + return false; +} + +/** @brief Per-element select (blend operation) + +Return value will be built by combining values _a_ and _b_ using the following scheme: + result[i] = mask[i] ? a[i] : b[i]; + +@note: _mask_ element values are restricted to these values: +- 0: select element from _b_ +- 0xff/0xffff/etc: select element from _a_ +(fully compatible with bitwise-based operator) +*/ +template inline v_reg<_Tp, n> v_select(const v_reg<_Tp, n>& mask, + const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + typedef V_TypeTraits<_Tp> Traits; + typedef typename Traits::int_type int_type; + v_reg<_Tp, n> c; + for( int i = 0; i < n; i++ ) + { + int_type m = Traits::reinterpret_int(mask.s[i]); + CV_DbgAssert(m == 0 || m == (~(int_type)0)); // restrict mask values: 0 or 0xff/0xffff/etc + c.s[i] = m ? a.s[i] : b.s[i]; + } + return c; +} + +/** @brief Expand values to the wider pack type + +Copy contents of register to two registers with 2x wider pack type. +Scheme: +@code + int32x4 int64x2 int64x2 +{A B C D} ==> {A B} , {C D} +@endcode */ +template inline void v_expand(const v_reg<_Tp, n>& a, + v_reg::w_type, n/2>& b0, + v_reg::w_type, n/2>& b1) +{ + for( int i = 0; i < (n/2); i++ ) + { + b0.s[i] = a.s[i]; + b1.s[i] = a.s[i+(n/2)]; + } +} + +/** @brief Expand lower values to the wider pack type + +Same as cv::v_expand, but return lower half of the vector. + +Scheme: +@code + int32x4 int64x2 +{A B C D} ==> {A B} +@endcode */ +template +inline v_reg::w_type, n/2> +v_expand_low(const v_reg<_Tp, n>& a) +{ + v_reg::w_type, n/2> b; + for( int i = 0; i < (n/2); i++ ) + b.s[i] = a.s[i]; + return b; +} + +/** @brief Expand higher values to the wider pack type + +Same as cv::v_expand_low, but expand higher half of the vector instead. + +Scheme: +@code + int32x4 int64x2 +{A B C D} ==> {C D} +@endcode */ +template +inline v_reg::w_type, n/2> +v_expand_high(const v_reg<_Tp, n>& a) +{ + v_reg::w_type, n/2> b; + for( int i = 0; i < (n/2); i++ ) + b.s[i] = a.s[i+(n/2)]; + return b; +} + +//! @cond IGNORED +template inline v_reg::int_type, n> + v_reinterpret_as_int(const v_reg<_Tp, n>& a) +{ + v_reg::int_type, n> c; + for( int i = 0; i < n; i++ ) + c.s[i] = V_TypeTraits<_Tp>::reinterpret_int(a.s[i]); + return c; +} + +template inline v_reg::uint_type, n> + v_reinterpret_as_uint(const v_reg<_Tp, n>& a) +{ + v_reg::uint_type, n> c; + for( int i = 0; i < n; i++ ) + c.s[i] = V_TypeTraits<_Tp>::reinterpret_uint(a.s[i]); + return c; +} +//! @endcond + +/** @brief Interleave two vectors + +Scheme: +@code + {A1 A2 A3 A4} + {B1 B2 B3 B4} +--------------- + {A1 B1 A2 B2} and {A3 B3 A4 B4} +@endcode +For all types except 64-bit. +*/ +template inline void v_zip( const v_reg<_Tp, n>& a0, const v_reg<_Tp, n>& a1, + v_reg<_Tp, n>& b0, v_reg<_Tp, n>& b1 ) +{ + int i; + for( i = 0; i < n/2; i++ ) + { + b0.s[i*2] = a0.s[i]; + b0.s[i*2+1] = a1.s[i]; + } + for( ; i < n; i++ ) + { + b1.s[i*2-n] = a0.s[i]; + b1.s[i*2-n+1] = a1.s[i]; + } +} + +/** @brief Load register contents from memory + +@param ptr pointer to memory block with data +@return register object + +@note Returned type will be detected from passed pointer type, for example uchar ==> cv::v_uint8x16, int ==> cv::v_int32x4, etc. + +@note Use vx_load version to get maximum available register length result + +@note Alignment requirement: +if CV_STRONG_ALIGNMENT=1 then passed pointer must be aligned (`sizeof(lane type)` should be enough). +Do not cast pointer types without runtime check for pointer alignment (like `uchar*` => `int*`). + */ +template +inline v_reg<_Tp, simd128_width / sizeof(_Tp)> v_load(const _Tp* ptr) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + return v_reg<_Tp, simd128_width / sizeof(_Tp)>(ptr); +} + +#if CV_SIMD256 +/** @brief Load 256-bit length register contents from memory + +@param ptr pointer to memory block with data +@return register object + +@note Returned type will be detected from passed pointer type, for example uchar ==> cv::v_uint8x32, int ==> cv::v_int32x8, etc. + +@note Check CV_SIMD256 preprocessor definition prior to use. +Use vx_load version to get maximum available register length result + +@note Alignment requirement: +if CV_STRONG_ALIGNMENT=1 then passed pointer must be aligned (`sizeof(lane type)` should be enough). +Do not cast pointer types without runtime check for pointer alignment (like `uchar*` => `int*`). + */ +template +inline v_reg<_Tp, simd256_width / sizeof(_Tp)> v256_load(const _Tp* ptr) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + return v_reg<_Tp, simd256_width / sizeof(_Tp)>(ptr); +} +#endif + +#if CV_SIMD512 +/** @brief Load 512-bit length register contents from memory + +@param ptr pointer to memory block with data +@return register object + +@note Returned type will be detected from passed pointer type, for example uchar ==> cv::v_uint8x64, int ==> cv::v_int32x16, etc. + +@note Check CV_SIMD512 preprocessor definition prior to use. +Use vx_load version to get maximum available register length result + +@note Alignment requirement: +if CV_STRONG_ALIGNMENT=1 then passed pointer must be aligned (`sizeof(lane type)` should be enough). +Do not cast pointer types without runtime check for pointer alignment (like `uchar*` => `int*`). + */ +template +inline v_reg<_Tp, simd512_width / sizeof(_Tp)> v512_load(const _Tp* ptr) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + return v_reg<_Tp, simd512_width / sizeof(_Tp)>(ptr); +} +#endif + +/** @brief Load register contents from memory (aligned) + +similar to cv::v_load, but source memory block should be aligned (to 16-byte boundary in case of SIMD128, 32-byte - SIMD256, etc) + +@note Use vx_load_aligned version to get maximum available register length result +*/ +template +inline v_reg<_Tp, simd128_width / sizeof(_Tp)> v_load_aligned(const _Tp* ptr) +{ + CV_Assert(isAligned)>(ptr)); + return v_reg<_Tp, simd128_width / sizeof(_Tp)>(ptr); +} + +#if CV_SIMD256 +/** @brief Load register contents from memory (aligned) + +similar to cv::v256_load, but source memory block should be aligned (to 32-byte boundary in case of SIMD256, 64-byte - SIMD512, etc) + +@note Check CV_SIMD256 preprocessor definition prior to use. +Use vx_load_aligned version to get maximum available register length result +*/ +template +inline v_reg<_Tp, simd256_width / sizeof(_Tp)> v256_load_aligned(const _Tp* ptr) +{ + CV_Assert(isAligned)>(ptr)); + return v_reg<_Tp, simd256_width / sizeof(_Tp)>(ptr); +} +#endif + +#if CV_SIMD512 +/** @brief Load register contents from memory (aligned) + +similar to cv::v512_load, but source memory block should be aligned (to 64-byte boundary in case of SIMD512, etc) + +@note Check CV_SIMD512 preprocessor definition prior to use. +Use vx_load_aligned version to get maximum available register length result +*/ +template +inline v_reg<_Tp, simd512_width / sizeof(_Tp)> v512_load_aligned(const _Tp* ptr) +{ + CV_Assert(isAligned)>(ptr)); + return v_reg<_Tp, simd512_width / sizeof(_Tp)>(ptr); +} +#endif + +/** @brief Load 64-bits of data to lower part (high part is undefined). + +@param ptr memory block containing data for first half (0..n/2) + +@code{.cpp} +int lo[2] = { 1, 2 }; +v_int32x4 r = v_load_low(lo); +@endcode + +@note Use vx_load_low version to get maximum available register length result +*/ +template +inline v_reg<_Tp, simd128_width / sizeof(_Tp)> v_load_low(const _Tp* ptr) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + v_reg<_Tp, simd128_width / sizeof(_Tp)> c; + for( int i = 0; i < c.nlanes/2; i++ ) + { + c.s[i] = ptr[i]; + } + return c; +} + +#if CV_SIMD256 +/** @brief Load 128-bits of data to lower part (high part is undefined). + +@param ptr memory block containing data for first half (0..n/2) + +@code{.cpp} +int lo[4] = { 1, 2, 3, 4 }; +v_int32x8 r = v256_load_low(lo); +@endcode + +@note Check CV_SIMD256 preprocessor definition prior to use. +Use vx_load_low version to get maximum available register length result +*/ +template +inline v_reg<_Tp, simd256_width / sizeof(_Tp)> v256_load_low(const _Tp* ptr) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + v_reg<_Tp, simd256_width / sizeof(_Tp)> c; + for (int i = 0; i < c.nlanes / 2; i++) + { + c.s[i] = ptr[i]; + } + return c; +} +#endif + +#if CV_SIMD512 +/** @brief Load 256-bits of data to lower part (high part is undefined). + +@param ptr memory block containing data for first half (0..n/2) + +@code{.cpp} +int lo[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; +v_int32x16 r = v512_load_low(lo); +@endcode + +@note Check CV_SIMD512 preprocessor definition prior to use. +Use vx_load_low version to get maximum available register length result +*/ +template +inline v_reg<_Tp, simd512_width / sizeof(_Tp)> v512_load_low(const _Tp* ptr) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + v_reg<_Tp, simd512_width / sizeof(_Tp)> c; + for (int i = 0; i < c.nlanes / 2; i++) + { + c.s[i] = ptr[i]; + } + return c; +} +#endif + +/** @brief Load register contents from two memory blocks + +@param loptr memory block containing data for first half (0..n/2) +@param hiptr memory block containing data for second half (n/2..n) + +@code{.cpp} +int lo[2] = { 1, 2 }, hi[2] = { 3, 4 }; +v_int32x4 r = v_load_halves(lo, hi); +@endcode + +@note Use vx_load_halves version to get maximum available register length result +*/ +template +inline v_reg<_Tp, simd128_width / sizeof(_Tp)> v_load_halves(const _Tp* loptr, const _Tp* hiptr) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(loptr)); + CV_Assert(isAligned(hiptr)); +#endif + v_reg<_Tp, simd128_width / sizeof(_Tp)> c; + for( int i = 0; i < c.nlanes/2; i++ ) + { + c.s[i] = loptr[i]; + c.s[i+c.nlanes/2] = hiptr[i]; + } + return c; +} + +#if CV_SIMD256 +/** @brief Load register contents from two memory blocks + +@param loptr memory block containing data for first half (0..n/2) +@param hiptr memory block containing data for second half (n/2..n) + +@code{.cpp} +int lo[4] = { 1, 2, 3, 4 }, hi[4] = { 5, 6, 7, 8 }; +v_int32x8 r = v256_load_halves(lo, hi); +@endcode + +@note Check CV_SIMD256 preprocessor definition prior to use. +Use vx_load_halves version to get maximum available register length result +*/ +template +inline v_reg<_Tp, simd256_width / sizeof(_Tp)> v256_load_halves(const _Tp* loptr, const _Tp* hiptr) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(loptr)); + CV_Assert(isAligned(hiptr)); +#endif + v_reg<_Tp, simd256_width / sizeof(_Tp)> c; + for (int i = 0; i < c.nlanes / 2; i++) + { + c.s[i] = loptr[i]; + c.s[i + c.nlanes / 2] = hiptr[i]; + } + return c; +} +#endif + +#if CV_SIMD512 +/** @brief Load register contents from two memory blocks + +@param loptr memory block containing data for first half (0..n/2) +@param hiptr memory block containing data for second half (n/2..n) + +@code{.cpp} +int lo[4] = { 1, 2, 3, 4, 5, 6, 7, 8 }, hi[4] = { 9, 10, 11, 12, 13, 14, 15, 16 }; +v_int32x16 r = v512_load_halves(lo, hi); +@endcode + +@note Check CV_SIMD512 preprocessor definition prior to use. +Use vx_load_halves version to get maximum available register length result +*/ +template +inline v_reg<_Tp, simd512_width / sizeof(_Tp)> v512_load_halves(const _Tp* loptr, const _Tp* hiptr) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(loptr)); + CV_Assert(isAligned(hiptr)); +#endif + v_reg<_Tp, simd512_width / sizeof(_Tp)> c; + for (int i = 0; i < c.nlanes / 2; i++) + { + c.s[i] = loptr[i]; + c.s[i + c.nlanes / 2] = hiptr[i]; + } + return c; +} +#endif + +/** @brief Load register contents from memory with double expand + +Same as cv::v_load, but result pack type will be 2x wider than memory type. + +@code{.cpp} +short buf[4] = {1, 2, 3, 4}; // type is int16 +v_int32x4 r = v_load_expand(buf); // r = {1, 2, 3, 4} - type is int32 +@endcode +For 8-, 16-, 32-bit integer source types. + +@note Use vx_load_expand version to get maximum available register length result +*/ +template +inline v_reg::w_type, simd128_width / sizeof(typename V_TypeTraits<_Tp>::w_type)> +v_load_expand(const _Tp* ptr) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + typedef typename V_TypeTraits<_Tp>::w_type w_type; + v_reg c; + for( int i = 0; i < c.nlanes; i++ ) + { + c.s[i] = ptr[i]; + } + return c; +} + +#if CV_SIMD256 +/** @brief Load register contents from memory with double expand + +Same as cv::v256_load, but result pack type will be 2x wider than memory type. + +@code{.cpp} +short buf[8] = {1, 2, 3, 4, 5, 6, 7, 8}; // type is int16 +v_int32x8 r = v256_load_expand(buf); // r = {1, 2, 3, 4, 5, 6, 7, 8} - type is int32 +@endcode +For 8-, 16-, 32-bit integer source types. + +@note Check CV_SIMD256 preprocessor definition prior to use. +Use vx_load_expand version to get maximum available register length result +*/ +template +inline v_reg::w_type, simd256_width / sizeof(typename V_TypeTraits<_Tp>::w_type)> +v256_load_expand(const _Tp* ptr) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + typedef typename V_TypeTraits<_Tp>::w_type w_type; + v_reg c; + for (int i = 0; i < c.nlanes; i++) + { + c.s[i] = ptr[i]; + } + return c; +} +#endif + +#if CV_SIMD512 +/** @brief Load register contents from memory with double expand + +Same as cv::v512_load, but result pack type will be 2x wider than memory type. + +@code{.cpp} +short buf[8] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; // type is int16 +v_int32x16 r = v512_load_expand(buf); // r = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} - type is int32 +@endcode +For 8-, 16-, 32-bit integer source types. + +@note Check CV_SIMD512 preprocessor definition prior to use. +Use vx_load_expand version to get maximum available register length result +*/ +template +inline v_reg::w_type, simd512_width / sizeof(typename V_TypeTraits<_Tp>::w_type)> +v512_load_expand(const _Tp* ptr) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + typedef typename V_TypeTraits<_Tp>::w_type w_type; + v_reg c; + for (int i = 0; i < c.nlanes; i++) + { + c.s[i] = ptr[i]; + } + return c; +} +#endif + +/** @brief Load register contents from memory with quad expand + +Same as cv::v_load_expand, but result type is 4 times wider than source. +@code{.cpp} +char buf[4] = {1, 2, 3, 4}; // type is int8 +v_int32x4 r = v_load_expand_q(buf); // r = {1, 2, 3, 4} - type is int32 +@endcode +For 8-bit integer source types. + +@note Use vx_load_expand_q version to get maximum available register length result +*/ +template +inline v_reg::q_type, simd128_width / sizeof(typename V_TypeTraits<_Tp>::q_type)> +v_load_expand_q(const _Tp* ptr) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + typedef typename V_TypeTraits<_Tp>::q_type q_type; + v_reg c; + for( int i = 0; i < c.nlanes; i++ ) + { + c.s[i] = ptr[i]; + } + return c; +} + +#if CV_SIMD256 +/** @brief Load register contents from memory with quad expand + +Same as cv::v256_load_expand, but result type is 4 times wider than source. +@code{.cpp} +char buf[8] = {1, 2, 3, 4, 5, 6, 7, 8}; // type is int8 +v_int32x8 r = v256_load_expand_q(buf); // r = {1, 2, 3, 4, 5, 6, 7, 8} - type is int32 +@endcode +For 8-bit integer source types. + +@note Check CV_SIMD256 preprocessor definition prior to use. +Use vx_load_expand_q version to get maximum available register length result +*/ +template +inline v_reg::q_type, simd256_width / sizeof(typename V_TypeTraits<_Tp>::q_type)> +v256_load_expand_q(const _Tp* ptr) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + typedef typename V_TypeTraits<_Tp>::q_type q_type; + v_reg c; + for (int i = 0; i < c.nlanes; i++) + { + c.s[i] = ptr[i]; + } + return c; +} +#endif + +#if CV_SIMD512 +/** @brief Load register contents from memory with quad expand + +Same as cv::v512_load_expand, but result type is 4 times wider than source. +@code{.cpp} +char buf[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; // type is int8 +v_int32x16 r = v512_load_expand_q(buf); // r = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} - type is int32 +@endcode +For 8-bit integer source types. + +@note Check CV_SIMD512 preprocessor definition prior to use. +Use vx_load_expand_q version to get maximum available register length result +*/ +template +inline v_reg::q_type, simd512_width / sizeof(typename V_TypeTraits<_Tp>::q_type)> +v512_load_expand_q(const _Tp* ptr) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + typedef typename V_TypeTraits<_Tp>::q_type q_type; + v_reg c; + for (int i = 0; i < c.nlanes; i++) + { + c.s[i] = ptr[i]; + } + return c; +} +#endif + +/** @brief Load and deinterleave (2 channels) + +Load data from memory deinterleave and store to 2 registers. +Scheme: +@code +{A1 B1 A2 B2 ...} ==> {A1 A2 ...}, {B1 B2 ...} +@endcode +For all types except 64-bit. */ +template inline void v_load_deinterleave(const _Tp* ptr, v_reg<_Tp, n>& a, + v_reg<_Tp, n>& b) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + int i, i2; + for( i = i2 = 0; i < n; i++, i2 += 2 ) + { + a.s[i] = ptr[i2]; + b.s[i] = ptr[i2+1]; + } +} + +/** @brief Load and deinterleave (3 channels) + +Load data from memory deinterleave and store to 3 registers. +Scheme: +@code +{A1 B1 C1 A2 B2 C2 ...} ==> {A1 A2 ...}, {B1 B2 ...}, {C1 C2 ...} +@endcode +For all types except 64-bit. */ +template inline void v_load_deinterleave(const _Tp* ptr, v_reg<_Tp, n>& a, + v_reg<_Tp, n>& b, v_reg<_Tp, n>& c) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + int i, i3; + for( i = i3 = 0; i < n; i++, i3 += 3 ) + { + a.s[i] = ptr[i3]; + b.s[i] = ptr[i3+1]; + c.s[i] = ptr[i3+2]; + } +} + +/** @brief Load and deinterleave (4 channels) + +Load data from memory deinterleave and store to 4 registers. +Scheme: +@code +{A1 B1 C1 D1 A2 B2 C2 D2 ...} ==> {A1 A2 ...}, {B1 B2 ...}, {C1 C2 ...}, {D1 D2 ...} +@endcode +For all types except 64-bit. */ +template +inline void v_load_deinterleave(const _Tp* ptr, v_reg<_Tp, n>& a, + v_reg<_Tp, n>& b, v_reg<_Tp, n>& c, + v_reg<_Tp, n>& d) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + int i, i4; + for( i = i4 = 0; i < n; i++, i4 += 4 ) + { + a.s[i] = ptr[i4]; + b.s[i] = ptr[i4+1]; + c.s[i] = ptr[i4+2]; + d.s[i] = ptr[i4+3]; + } +} + +/** @brief Interleave and store (2 channels) + +Interleave and store data from 2 registers to memory. +Scheme: +@code +{A1 A2 ...}, {B1 B2 ...} ==> {A1 B1 A2 B2 ...} +@endcode +For all types except 64-bit. */ +template +inline void v_store_interleave( _Tp* ptr, const v_reg<_Tp, n>& a, + const v_reg<_Tp, n>& b, + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + int i, i2; + for( i = i2 = 0; i < n; i++, i2 += 2 ) + { + ptr[i2] = a.s[i]; + ptr[i2+1] = b.s[i]; + } +} + +/** @brief Interleave and store (3 channels) + +Interleave and store data from 3 registers to memory. +Scheme: +@code +{A1 A2 ...}, {B1 B2 ...}, {C1 C2 ...} ==> {A1 B1 C1 A2 B2 C2 ...} +@endcode +For all types except 64-bit. */ +template +inline void v_store_interleave( _Tp* ptr, const v_reg<_Tp, n>& a, + const v_reg<_Tp, n>& b, const v_reg<_Tp, n>& c, + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + int i, i3; + for( i = i3 = 0; i < n; i++, i3 += 3 ) + { + ptr[i3] = a.s[i]; + ptr[i3+1] = b.s[i]; + ptr[i3+2] = c.s[i]; + } +} + +/** @brief Interleave and store (4 channels) + +Interleave and store data from 4 registers to memory. +Scheme: +@code +{A1 A2 ...}, {B1 B2 ...}, {C1 C2 ...}, {D1 D2 ...} ==> {A1 B1 C1 D1 A2 B2 C2 D2 ...} +@endcode +For all types except 64-bit. */ +template inline void v_store_interleave( _Tp* ptr, const v_reg<_Tp, n>& a, + const v_reg<_Tp, n>& b, const v_reg<_Tp, n>& c, + const v_reg<_Tp, n>& d, + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + int i, i4; + for( i = i4 = 0; i < n; i++, i4 += 4 ) + { + ptr[i4] = a.s[i]; + ptr[i4+1] = b.s[i]; + ptr[i4+2] = c.s[i]; + ptr[i4+3] = d.s[i]; + } +} + +/** @brief Store data to memory + +Store register contents to memory. +Scheme: +@code + REG {A B C D} ==> MEM {A B C D} +@endcode +Pointer can be unaligned. */ +template +inline void v_store(_Tp* ptr, const v_reg<_Tp, n>& a) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + for( int i = 0; i < n; i++ ) + ptr[i] = a.s[i]; +} + +template +inline void v_store(_Tp* ptr, const v_reg<_Tp, n>& a, hal::StoreMode /*mode*/) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + v_store(ptr, a); +} + +/** @brief Store data to memory (lower half) + +Store lower half of register contents to memory. +Scheme: +@code + REG {A B C D} ==> MEM {A B} +@endcode */ +template +inline void v_store_low(_Tp* ptr, const v_reg<_Tp, n>& a) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + for( int i = 0; i < (n/2); i++ ) + ptr[i] = a.s[i]; +} + +/** @brief Store data to memory (higher half) + +Store higher half of register contents to memory. +Scheme: +@code + REG {A B C D} ==> MEM {C D} +@endcode */ +template +inline void v_store_high(_Tp* ptr, const v_reg<_Tp, n>& a) +{ +#if CV_STRONG_ALIGNMENT + CV_Assert(isAligned(ptr)); +#endif + for( int i = 0; i < (n/2); i++ ) + ptr[i] = a.s[i+(n/2)]; +} + +/** @brief Store data to memory (aligned) + +Store register contents to memory. +Scheme: +@code + REG {A B C D} ==> MEM {A B C D} +@endcode +Pointer __should__ be aligned by 16-byte boundary. */ +template +inline void v_store_aligned(_Tp* ptr, const v_reg<_Tp, n>& a) +{ + CV_Assert(isAligned)>(ptr)); + v_store(ptr, a); +} + +template +inline void v_store_aligned_nocache(_Tp* ptr, const v_reg<_Tp, n>& a) +{ + CV_Assert(isAligned)>(ptr)); + v_store(ptr, a); +} + +template +inline void v_store_aligned(_Tp* ptr, const v_reg<_Tp, n>& a, hal::StoreMode /*mode*/) +{ + CV_Assert(isAligned)>(ptr)); + v_store(ptr, a); +} + +/** @brief Combine vector from first elements of two vectors + +Scheme: +@code + {A1 A2 A3 A4} + {B1 B2 B3 B4} +--------------- + {A1 A2 B1 B2} +@endcode +For all types except 64-bit. */ +template +inline v_reg<_Tp, n> v_combine_low(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + v_reg<_Tp, n> c; + for( int i = 0; i < (n/2); i++ ) + { + c.s[i] = a.s[i]; + c.s[i+(n/2)] = b.s[i]; + } + return c; +} + +/** @brief Combine vector from last elements of two vectors + +Scheme: +@code + {A1 A2 A3 A4} + {B1 B2 B3 B4} +--------------- + {A3 A4 B3 B4} +@endcode +For all types except 64-bit. */ +template +inline v_reg<_Tp, n> v_combine_high(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + v_reg<_Tp, n> c; + for( int i = 0; i < (n/2); i++ ) + { + c.s[i] = a.s[i+(n/2)]; + c.s[i+(n/2)] = b.s[i+(n/2)]; + } + return c; +} + +/** @brief Combine two vectors from lower and higher parts of two other vectors + +@code{.cpp} +low = cv::v_combine_low(a, b); +high = cv::v_combine_high(a, b); +@endcode */ +template +inline void v_recombine(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b, + v_reg<_Tp, n>& low, v_reg<_Tp, n>& high) +{ + for( int i = 0; i < (n/2); i++ ) + { + low.s[i] = a.s[i]; + low.s[i+(n/2)] = b.s[i]; + high.s[i] = a.s[i+(n/2)]; + high.s[i+(n/2)] = b.s[i+(n/2)]; + } +} + +/** @brief Vector reverse order + +Reverse the order of the vector +Scheme: +@code + REG {A1 ... An} ==> REG {An ... A1} +@endcode +For all types. */ +template +inline v_reg<_Tp, n> v_reverse(const v_reg<_Tp, n>& a) +{ + v_reg<_Tp, n> c; + for( int i = 0; i < n; i++ ) + c.s[i] = a.s[n-i-1]; + return c; +} + +/** @brief Vector extract + +Scheme: +@code + {A1 A2 A3 A4} + {B1 B2 B3 B4} +======================== +shift = 1 {A2 A3 A4 B1} +shift = 2 {A3 A4 B1 B2} +shift = 3 {A4 B1 B2 B3} +@endcode +Restriction: 0 <= shift < nlanes + +Usage: +@code +v_int32x4 a, b, c; +c = v_extract<2>(a, b); +@endcode +For all types. */ +template +inline v_reg<_Tp, n> v_extract(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + v_reg<_Tp, n> r; + const int shift = n - s; + int i = 0; + for (; i < shift; ++i) + r.s[i] = a.s[i+s]; + for (; i < n; ++i) + r.s[i] = b.s[i-shift]; + return r; +} + +/** @brief Vector extract + +Scheme: +Return the s-th element of v. +Restriction: 0 <= s < nlanes + +Usage: +@code +v_int32x4 a; +int r; +r = v_extract_n<2>(a); +@endcode +For all types. */ +template +inline _Tp v_extract_n(const v_reg<_Tp, n>& v) +{ + CV_DbgAssert(s >= 0 && s < n); + return v.s[s]; +} + +/** @brief Broadcast i-th element of vector + +Scheme: +@code +{ v[0] v[1] v[2] ... v[SZ] } => { v[i], v[i], v[i] ... v[i] } +@endcode +Restriction: 0 <= i < nlanes +Supported types: 32-bit integers and floats (s32/u32/f32) + */ +template +inline v_reg<_Tp, n> v_broadcast_element(const v_reg<_Tp, n>& a) +{ + CV_DbgAssert(i >= 0 && i < n); + return v_reg<_Tp, n>::all(a.s[i]); +} + +/** @brief Round elements + +Rounds each value. Input type is float vector ==> output type is int vector. +@note Only for floating point types. +*/ +template inline v_reg v_round(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + c.s[i] = cvRound(a.s[i]); + return c; +} + +/** @overload */ +template inline v_reg v_round(const v_reg& a, const v_reg& b) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + { + c.s[i] = cvRound(a.s[i]); + c.s[i+n] = cvRound(b.s[i]); + } + return c; +} + +/** @brief Floor elements + +Floor each value. Input type is float vector ==> output type is int vector. +@note Only for floating point types. +*/ +template inline v_reg v_floor(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + c.s[i] = cvFloor(a.s[i]); + return c; +} + +/** @brief Ceil elements + +Ceil each value. Input type is float vector ==> output type is int vector. +@note Only for floating point types. +*/ +template inline v_reg v_ceil(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + c.s[i] = cvCeil(a.s[i]); + return c; +} + +/** @brief Truncate elements + +Truncate each value. Input type is float vector ==> output type is int vector. +@note Only for floating point types. +*/ +template inline v_reg v_trunc(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + c.s[i] = (int)(a.s[i]); + return c; +} + +/** @overload */ +template inline v_reg v_round(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + { + c.s[i] = cvRound(a.s[i]); + c.s[i+n] = 0; + } + return c; +} + +/** @overload */ +template inline v_reg v_floor(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + { + c.s[i] = cvFloor(a.s[i]); + c.s[i+n] = 0; + } + return c; +} + +/** @overload */ +template inline v_reg v_ceil(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + { + c.s[i] = cvCeil(a.s[i]); + c.s[i+n] = 0; + } + return c; +} + +/** @overload */ +template inline v_reg v_trunc(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + { + c.s[i] = (int)(a.s[i]); + c.s[i+n] = 0; + } + return c; +} + +/** @brief Convert to float + +Supported input type is cv::v_int32. */ +template inline v_reg v_cvt_f32(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + c.s[i] = (float)a.s[i]; + return c; +} + +/** @brief Convert lower half to float + +Supported input type is cv::v_float64. */ +template inline v_reg v_cvt_f32(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + { + c.s[i] = (float)a.s[i]; + c.s[i+n] = 0; + } + return c; +} + +/** @brief Convert to float + +Supported input type is cv::v_float64. */ +template inline v_reg v_cvt_f32(const v_reg& a, const v_reg& b) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + { + c.s[i] = (float)a.s[i]; + c.s[i+n] = (float)b.s[i]; + } + return c; +} + +/** @brief Convert lower half to double + +Supported input type is cv::v_int32. */ +template CV_INLINE v_reg v_cvt_f64(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < (n/2); i++ ) + c.s[i] = (double)a.s[i]; + return c; +} + +/** @brief Convert to double high part of vector + +Supported input type is cv::v_int32. */ +template CV_INLINE v_reg v_cvt_f64_high(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < (n/2); i++ ) + c.s[i] = (double)a.s[i + (n/2)]; + return c; +} + +/** @brief Convert lower half to double + +Supported input type is cv::v_float32. */ +template CV_INLINE v_reg v_cvt_f64(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < (n/2); i++ ) + c.s[i] = (double)a.s[i]; + return c; +} + +/** @brief Convert to double high part of vector + +Supported input type is cv::v_float32. */ +template CV_INLINE v_reg v_cvt_f64_high(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < (n/2); i++ ) + c.s[i] = (double)a.s[i + (n/2)]; + return c; +} + +/** @brief Convert to double + +Supported input type is cv::v_int64. */ +template CV_INLINE v_reg v_cvt_f64(const v_reg& a) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + c.s[i] = (double)a.s[i]; + return c; +} + + +template inline v_reg<_Tp, simd128_width / sizeof(_Tp)> v_lut(const _Tp* tab, const int* idx) +{ + v_reg<_Tp, simd128_width / sizeof(_Tp)> c; + for (int i = 0; i < c.nlanes; i++) + c.s[i] = tab[idx[i]]; + return c; +} +template inline v_reg<_Tp, simd128_width / sizeof(_Tp)> v_lut_pairs(const _Tp* tab, const int* idx) +{ + v_reg<_Tp, simd128_width / sizeof(_Tp)> c; + for (int i = 0; i < c.nlanes; i++) + c.s[i] = tab[idx[i / 2] + i % 2]; + return c; +} +template inline v_reg<_Tp, simd128_width / sizeof(_Tp)> v_lut_quads(const _Tp* tab, const int* idx) +{ + v_reg<_Tp, simd128_width / sizeof(_Tp)> c; + for (int i = 0; i < c.nlanes; i++) + c.s[i] = tab[idx[i / 4] + i % 4]; + return c; +} + +template inline v_reg v_lut(const int* tab, const v_reg& idx) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + c.s[i] = tab[idx.s[i]]; + return c; +} + +template inline v_reg v_lut(const unsigned* tab, const v_reg& idx) +{ + v_reg c; + for (int i = 0; i < n; i++) + c.s[i] = tab[idx.s[i]]; + return c; +} + +template inline v_reg v_lut(const float* tab, const v_reg& idx) +{ + v_reg c; + for( int i = 0; i < n; i++ ) + c.s[i] = tab[idx.s[i]]; + return c; +} + +template inline v_reg v_lut(const double* tab, const v_reg& idx) +{ + v_reg c; + for( int i = 0; i < n/2; i++ ) + c.s[i] = tab[idx.s[i]]; + return c; +} + + +template inline void v_lut_deinterleave(const float* tab, const v_reg& idx, + v_reg& x, v_reg& y) +{ + for( int i = 0; i < n; i++ ) + { + int j = idx.s[i]; + x.s[i] = tab[j]; + y.s[i] = tab[j+1]; + } +} + +template inline void v_lut_deinterleave(const double* tab, const v_reg& idx, + v_reg& x, v_reg& y) +{ + for( int i = 0; i < n; i++ ) + { + int j = idx.s[i]; + x.s[i] = tab[j]; + y.s[i] = tab[j+1]; + } +} + +template inline v_reg<_Tp, n> v_interleave_pairs(const v_reg<_Tp, n>& vec) +{ + v_reg<_Tp, n> c; + for (int i = 0; i < n/4; i++) + { + c.s[4*i ] = vec.s[4*i ]; + c.s[4*i+1] = vec.s[4*i+2]; + c.s[4*i+2] = vec.s[4*i+1]; + c.s[4*i+3] = vec.s[4*i+3]; + } + return c; +} + +template inline v_reg<_Tp, n> v_interleave_quads(const v_reg<_Tp, n>& vec) +{ + v_reg<_Tp, n> c; + for (int i = 0; i < n/8; i++) + { + c.s[8*i ] = vec.s[8*i ]; + c.s[8*i+1] = vec.s[8*i+4]; + c.s[8*i+2] = vec.s[8*i+1]; + c.s[8*i+3] = vec.s[8*i+5]; + c.s[8*i+4] = vec.s[8*i+2]; + c.s[8*i+5] = vec.s[8*i+6]; + c.s[8*i+6] = vec.s[8*i+3]; + c.s[8*i+7] = vec.s[8*i+7]; + } + return c; +} + +template inline v_reg<_Tp, n> v_pack_triplets(const v_reg<_Tp, n>& vec) +{ + v_reg<_Tp, n> c; + for (int i = 0; i < n/4; i++) + { + c.s[3*i ] = vec.s[4*i ]; + c.s[3*i+1] = vec.s[4*i+1]; + c.s[3*i+2] = vec.s[4*i+2]; + } + return c; +} + +/** @brief Transpose 4x4 matrix + +Scheme: +@code +a0 {A1 A2 A3 A4} +a1 {B1 B2 B3 B4} +a2 {C1 C2 C3 C4} +a3 {D1 D2 D3 D4} +=============== +b0 {A1 B1 C1 D1} +b1 {A2 B2 C2 D2} +b2 {A3 B3 C3 D3} +b3 {A4 B4 C4 D4} +@endcode +*/ +template +inline void v_transpose4x4( v_reg<_Tp, n>& a0, const v_reg<_Tp, n>& a1, + const v_reg<_Tp, n>& a2, const v_reg<_Tp, n>& a3, + v_reg<_Tp, n>& b0, v_reg<_Tp, n>& b1, + v_reg<_Tp, n>& b2, v_reg<_Tp, n>& b3 ) +{ + for (int i = 0; i < n / 4; i++) + { + b0.s[0 + i*4] = a0.s[0 + i*4]; b0.s[1 + i*4] = a1.s[0 + i*4]; + b0.s[2 + i*4] = a2.s[0 + i*4]; b0.s[3 + i*4] = a3.s[0 + i*4]; + b1.s[0 + i*4] = a0.s[1 + i*4]; b1.s[1 + i*4] = a1.s[1 + i*4]; + b1.s[2 + i*4] = a2.s[1 + i*4]; b1.s[3 + i*4] = a3.s[1 + i*4]; + b2.s[0 + i*4] = a0.s[2 + i*4]; b2.s[1 + i*4] = a1.s[2 + i*4]; + b2.s[2 + i*4] = a2.s[2 + i*4]; b2.s[3 + i*4] = a3.s[2 + i*4]; + b3.s[0 + i*4] = a0.s[3 + i*4]; b3.s[1 + i*4] = a1.s[3 + i*4]; + b3.s[2 + i*4] = a2.s[3 + i*4]; b3.s[3 + i*4] = a3.s[3 + i*4]; + } +} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_C_INIT_ZERO(_Tpvec, prefix, suffix) \ +inline _Tpvec prefix##_setzero_##suffix() { return _Tpvec::zero(); } + +//! @name Init with zero +//! @{ +//! @brief Create new vector with zero elements +OPENCV_HAL_IMPL_C_INIT_ZERO(v_uint8x16, v, u8) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_int8x16, v, s8) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_uint16x8, v, u16) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_int16x8, v, s16) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_uint32x4, v, u32) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_int32x4, v, s32) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_float32x4, v, f32) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_float64x2, v, f64) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_uint64x2, v, u64) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_int64x2, v, s64) + +#if CV_SIMD256 +OPENCV_HAL_IMPL_C_INIT_ZERO(v_uint8x32, v256, u8) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_int8x32, v256, s8) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_uint16x16, v256, u16) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_int16x16, v256, s16) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_uint32x8, v256, u32) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_int32x8, v256, s32) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_float32x8, v256, f32) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_float64x4, v256, f64) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_uint64x4, v256, u64) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_int64x4, v256, s64) +#endif + +#if CV_SIMD512 +OPENCV_HAL_IMPL_C_INIT_ZERO(v_uint8x64, v512, u8) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_int8x64, v512, s8) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_uint16x32, v512, u16) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_int16x32, v512, s16) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_uint32x16, v512, u32) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_int32x16, v512, s32) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_float32x16, v512, f32) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_float64x8, v512, f64) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_uint64x8, v512, u64) +OPENCV_HAL_IMPL_C_INIT_ZERO(v_int64x8, v512, s64) +#endif +//! @} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_C_INIT_VAL(_Tpvec, _Tp, prefix, suffix) \ +inline _Tpvec prefix##_setall_##suffix(_Tp val) { return _Tpvec::all(val); } + +//! @name Init with value +//! @{ +//! @brief Create new vector with elements set to a specific value +OPENCV_HAL_IMPL_C_INIT_VAL(v_uint8x16, uchar, v, u8) +OPENCV_HAL_IMPL_C_INIT_VAL(v_int8x16, schar, v, s8) +OPENCV_HAL_IMPL_C_INIT_VAL(v_uint16x8, ushort, v, u16) +OPENCV_HAL_IMPL_C_INIT_VAL(v_int16x8, short, v, s16) +OPENCV_HAL_IMPL_C_INIT_VAL(v_uint32x4, unsigned, v, u32) +OPENCV_HAL_IMPL_C_INIT_VAL(v_int32x4, int, v, s32) +OPENCV_HAL_IMPL_C_INIT_VAL(v_float32x4, float, v, f32) +OPENCV_HAL_IMPL_C_INIT_VAL(v_float64x2, double, v, f64) +OPENCV_HAL_IMPL_C_INIT_VAL(v_uint64x2, uint64, v, u64) +OPENCV_HAL_IMPL_C_INIT_VAL(v_int64x2, int64, v, s64) + +#if CV_SIMD256 +OPENCV_HAL_IMPL_C_INIT_VAL(v_uint8x32, uchar, v256, u8) +OPENCV_HAL_IMPL_C_INIT_VAL(v_int8x32, schar, v256, s8) +OPENCV_HAL_IMPL_C_INIT_VAL(v_uint16x16, ushort, v256, u16) +OPENCV_HAL_IMPL_C_INIT_VAL(v_int16x16, short, v256, s16) +OPENCV_HAL_IMPL_C_INIT_VAL(v_uint32x8, unsigned, v256, u32) +OPENCV_HAL_IMPL_C_INIT_VAL(v_int32x8, int, v256, s32) +OPENCV_HAL_IMPL_C_INIT_VAL(v_float32x8, float, v256, f32) +OPENCV_HAL_IMPL_C_INIT_VAL(v_float64x4, double, v256, f64) +OPENCV_HAL_IMPL_C_INIT_VAL(v_uint64x4, uint64, v256, u64) +OPENCV_HAL_IMPL_C_INIT_VAL(v_int64x4, int64, v256, s64) +#endif + +#if CV_SIMD512 +OPENCV_HAL_IMPL_C_INIT_VAL(v_uint8x64, uchar, v512, u8) +OPENCV_HAL_IMPL_C_INIT_VAL(v_int8x64, schar, v512, s8) +OPENCV_HAL_IMPL_C_INIT_VAL(v_uint16x32, ushort, v512, u16) +OPENCV_HAL_IMPL_C_INIT_VAL(v_int16x32, short, v512, s16) +OPENCV_HAL_IMPL_C_INIT_VAL(v_uint32x16, unsigned, v512, u32) +OPENCV_HAL_IMPL_C_INIT_VAL(v_int32x16, int, v512, s32) +OPENCV_HAL_IMPL_C_INIT_VAL(v_float32x16, float, v512, f32) +OPENCV_HAL_IMPL_C_INIT_VAL(v_float64x8, double, v512, f64) +OPENCV_HAL_IMPL_C_INIT_VAL(v_uint64x8, uint64, v512, u64) +OPENCV_HAL_IMPL_C_INIT_VAL(v_int64x8, int64, v512, s64) +#endif +//! @} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_C_REINTERPRET(_Tp, suffix) \ +template inline v_reg<_Tp, n0*sizeof(_Tp0)/sizeof(_Tp)> \ + v_reinterpret_as_##suffix(const v_reg<_Tp0, n0>& a) \ +{ return a.template reinterpret_as<_Tp, n0*sizeof(_Tp0)/sizeof(_Tp)>(); } + +//! @name Reinterpret +//! @{ +//! @brief Convert vector to different type without modifying underlying data. +OPENCV_HAL_IMPL_C_REINTERPRET(uchar, u8) +OPENCV_HAL_IMPL_C_REINTERPRET(schar, s8) +OPENCV_HAL_IMPL_C_REINTERPRET(ushort, u16) +OPENCV_HAL_IMPL_C_REINTERPRET(short, s16) +OPENCV_HAL_IMPL_C_REINTERPRET(unsigned, u32) +OPENCV_HAL_IMPL_C_REINTERPRET(int, s32) +OPENCV_HAL_IMPL_C_REINTERPRET(float, f32) +OPENCV_HAL_IMPL_C_REINTERPRET(double, f64) +OPENCV_HAL_IMPL_C_REINTERPRET(uint64, u64) +OPENCV_HAL_IMPL_C_REINTERPRET(int64, s64) +//! @} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_C_SHIFTL(_Tp) \ +template inline v_reg<_Tp, n> v_shl(const v_reg<_Tp, n>& a) \ +{ return a << shift; } + +//! @name Left shift +//! @{ +//! @brief Shift left +OPENCV_HAL_IMPL_C_SHIFTL(ushort) +OPENCV_HAL_IMPL_C_SHIFTL(short) +OPENCV_HAL_IMPL_C_SHIFTL(unsigned) +OPENCV_HAL_IMPL_C_SHIFTL(int) +OPENCV_HAL_IMPL_C_SHIFTL(uint64) +OPENCV_HAL_IMPL_C_SHIFTL(int64) +//! @} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_C_SHIFTR(_Tp) \ +template inline v_reg<_Tp, n> v_shr(const v_reg<_Tp, n>& a) \ +{ return a >> shift; } + +//! @name Right shift +//! @{ +//! @brief Shift right +OPENCV_HAL_IMPL_C_SHIFTR(ushort) +OPENCV_HAL_IMPL_C_SHIFTR(short) +OPENCV_HAL_IMPL_C_SHIFTR(unsigned) +OPENCV_HAL_IMPL_C_SHIFTR(int) +OPENCV_HAL_IMPL_C_SHIFTR(uint64) +OPENCV_HAL_IMPL_C_SHIFTR(int64) +//! @} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_C_RSHIFTR(_Tp) \ +template inline v_reg<_Tp, n> v_rshr(const v_reg<_Tp, n>& a) \ +{ \ + v_reg<_Tp, n> c; \ + for( int i = 0; i < n; i++ ) \ + c.s[i] = (_Tp)((a.s[i] + ((_Tp)1 << (shift - 1))) >> shift); \ + return c; \ +} + +//! @name Rounding shift +//! @{ +//! @brief Rounding shift right +OPENCV_HAL_IMPL_C_RSHIFTR(ushort) +OPENCV_HAL_IMPL_C_RSHIFTR(short) +OPENCV_HAL_IMPL_C_RSHIFTR(unsigned) +OPENCV_HAL_IMPL_C_RSHIFTR(int) +OPENCV_HAL_IMPL_C_RSHIFTR(uint64) +OPENCV_HAL_IMPL_C_RSHIFTR(int64) +//! @} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_C_PACK(_Tp, _Tpn, pack_suffix, cast) \ +template inline v_reg<_Tpn, 2*n> v_##pack_suffix(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \ +{ \ + v_reg<_Tpn, 2*n> c; \ + for( int i = 0; i < n; i++ ) \ + { \ + c.s[i] = cast<_Tpn>(a.s[i]); \ + c.s[i+n] = cast<_Tpn>(b.s[i]); \ + } \ + return c; \ +} + +//! @name Pack +//! @{ +//! @brief Pack values from two vectors to one +//! +//! Return vector type have twice more elements than input vector types. Variant with _u_ suffix also +//! converts to corresponding unsigned type. +//! +//! - pack: for 16-, 32- and 64-bit integer input types +//! - pack_u: for 16- and 32-bit signed integer input types +//! +//! @note All variants except 64-bit use saturation. +OPENCV_HAL_IMPL_C_PACK(ushort, uchar, pack, saturate_cast) +OPENCV_HAL_IMPL_C_PACK(short, schar, pack, saturate_cast) +OPENCV_HAL_IMPL_C_PACK(unsigned, ushort, pack, saturate_cast) +OPENCV_HAL_IMPL_C_PACK(int, short, pack, saturate_cast) +OPENCV_HAL_IMPL_C_PACK(uint64, unsigned, pack, static_cast) +OPENCV_HAL_IMPL_C_PACK(int64, int, pack, static_cast) +OPENCV_HAL_IMPL_C_PACK(short, uchar, pack_u, saturate_cast) +OPENCV_HAL_IMPL_C_PACK(int, ushort, pack_u, saturate_cast) +//! @} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_C_RSHR_PACK(_Tp, _Tpn, pack_suffix, cast) \ +template inline v_reg<_Tpn, 2*n> v_rshr_##pack_suffix(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) \ +{ \ + v_reg<_Tpn, 2*n> c; \ + for( int i = 0; i < n; i++ ) \ + { \ + c.s[i] = cast<_Tpn>((a.s[i] + ((_Tp)1 << (shift - 1))) >> shift); \ + c.s[i+n] = cast<_Tpn>((b.s[i] + ((_Tp)1 << (shift - 1))) >> shift); \ + } \ + return c; \ +} + +//! @name Pack with rounding shift +//! @{ +//! @brief Pack values from two vectors to one with rounding shift +//! +//! Values from the input vectors will be shifted right by _n_ bits with rounding, converted to narrower +//! type and returned in the result vector. Variant with _u_ suffix converts to unsigned type. +//! +//! - pack: for 16-, 32- and 64-bit integer input types +//! - pack_u: for 16- and 32-bit signed integer input types +//! +//! @note All variants except 64-bit use saturation. +OPENCV_HAL_IMPL_C_RSHR_PACK(ushort, uchar, pack, saturate_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK(short, schar, pack, saturate_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK(unsigned, ushort, pack, saturate_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK(int, short, pack, saturate_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK(uint64, unsigned, pack, static_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK(int64, int, pack, static_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK(short, uchar, pack_u, saturate_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK(int, ushort, pack_u, saturate_cast) +//! @} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_C_PACK_STORE(_Tp, _Tpn, pack_suffix, cast) \ +template inline void v_##pack_suffix##_store(_Tpn* ptr, const v_reg<_Tp, n>& a) \ +{ \ + for( int i = 0; i < n; i++ ) \ + ptr[i] = cast<_Tpn>(a.s[i]); \ +} + +//! @name Pack and store +//! @{ +//! @brief Store values from the input vector into memory with pack +//! +//! Values will be stored into memory with conversion to narrower type. +//! Variant with _u_ suffix converts to corresponding unsigned type. +//! +//! - pack: for 16-, 32- and 64-bit integer input types +//! - pack_u: for 16- and 32-bit signed integer input types +//! +//! @note All variants except 64-bit use saturation. +OPENCV_HAL_IMPL_C_PACK_STORE(ushort, uchar, pack, saturate_cast) +OPENCV_HAL_IMPL_C_PACK_STORE(short, schar, pack, saturate_cast) +OPENCV_HAL_IMPL_C_PACK_STORE(unsigned, ushort, pack, saturate_cast) +OPENCV_HAL_IMPL_C_PACK_STORE(int, short, pack, saturate_cast) +OPENCV_HAL_IMPL_C_PACK_STORE(uint64, unsigned, pack, static_cast) +OPENCV_HAL_IMPL_C_PACK_STORE(int64, int, pack, static_cast) +OPENCV_HAL_IMPL_C_PACK_STORE(short, uchar, pack_u, saturate_cast) +OPENCV_HAL_IMPL_C_PACK_STORE(int, ushort, pack_u, saturate_cast) +//! @} + +//! @brief Helper macro +//! @ingroup core_hal_intrin_impl +#define OPENCV_HAL_IMPL_C_RSHR_PACK_STORE(_Tp, _Tpn, pack_suffix, cast) \ +template inline void v_rshr_##pack_suffix##_store(_Tpn* ptr, const v_reg<_Tp, n>& a) \ +{ \ + for( int i = 0; i < n; i++ ) \ + ptr[i] = cast<_Tpn>((a.s[i] + ((_Tp)1 << (shift - 1))) >> shift); \ +} + +//! @name Pack and store with rounding shift +//! @{ +//! @brief Store values from the input vector into memory with pack +//! +//! Values will be shifted _n_ bits right with rounding, converted to narrower type and stored into +//! memory. Variant with _u_ suffix converts to unsigned type. +//! +//! - pack: for 16-, 32- and 64-bit integer input types +//! - pack_u: for 16- and 32-bit signed integer input types +//! +//! @note All variants except 64-bit use saturation. +OPENCV_HAL_IMPL_C_RSHR_PACK_STORE(ushort, uchar, pack, saturate_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK_STORE(short, schar, pack, saturate_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK_STORE(unsigned, ushort, pack, saturate_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK_STORE(int, short, pack, saturate_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK_STORE(uint64, unsigned, pack, static_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK_STORE(int64, int, pack, static_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK_STORE(short, uchar, pack_u, saturate_cast) +OPENCV_HAL_IMPL_C_RSHR_PACK_STORE(int, ushort, pack_u, saturate_cast) +//! @} + +//! @cond IGNORED +template +inline void _pack_b(_Tpm* mptr, const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + for (int i = 0; i < n; ++i) + { + mptr[i] = (_Tpm)a.s[i]; + mptr[i + n] = (_Tpm)b.s[i]; + } +} +//! @endcond + +//! @name Pack boolean values +//! @{ +//! @brief Pack boolean values from multiple vectors to one unsigned 8-bit integer vector +//! +//! @note Must provide valid boolean values to guarantee same result for all architectures. + +/** @brief +//! For 16-bit boolean values + +Scheme: +@code +a {0xFFFF 0 0 0xFFFF 0 0xFFFF 0xFFFF 0} +b {0xFFFF 0 0xFFFF 0 0 0xFFFF 0 0xFFFF} +=============== +{ + 0xFF 0 0 0xFF 0 0xFF 0xFF 0 + 0xFF 0 0xFF 0 0 0xFF 0 0xFF +} +@endcode */ + +template inline v_reg v_pack_b(const v_reg& a, const v_reg& b) +{ + v_reg mask; + _pack_b(mask.s, a, b); + return mask; +} + +/** @overload +For 32-bit boolean values + +Scheme: +@code +a {0xFFFF.. 0 0 0xFFFF..} +b {0 0xFFFF.. 0xFFFF.. 0} +c {0xFFFF.. 0 0xFFFF.. 0} +d {0 0xFFFF.. 0 0xFFFF..} +=============== +{ + 0xFF 0 0 0xFF 0 0xFF 0xFF 0 + 0xFF 0 0xFF 0 0 0xFF 0 0xFF +} +@endcode */ + +template inline v_reg v_pack_b(const v_reg& a, const v_reg& b, + const v_reg& c, const v_reg& d) +{ + v_reg mask; + _pack_b(mask.s, a, b); + _pack_b(mask.s + 2*n, c, d); + return mask; +} + +/** @overload +For 64-bit boolean values + +Scheme: +@code +a {0xFFFF.. 0} +b {0 0xFFFF..} +c {0xFFFF.. 0} +d {0 0xFFFF..} + +e {0xFFFF.. 0} +f {0xFFFF.. 0} +g {0 0xFFFF..} +h {0 0xFFFF..} +=============== +{ + 0xFF 0 0 0xFF 0xFF 0 0 0xFF + 0xFF 0 0xFF 0 0 0xFF 0 0xFF +} +@endcode */ +template inline v_reg v_pack_b(const v_reg& a, const v_reg& b, + const v_reg& c, const v_reg& d, + const v_reg& e, const v_reg& f, + const v_reg& g, const v_reg& h) +{ + v_reg mask; + _pack_b(mask.s, a, b); + _pack_b(mask.s + 2*n, c, d); + _pack_b(mask.s + 4*n, e, f); + _pack_b(mask.s + 6*n, g, h); + return mask; +} +//! @} + +/** @brief Matrix multiplication + +Scheme: +@code +{A0 A1 A2 A3} |V0| +{B0 B1 B2 B3} |V1| +{C0 C1 C2 C3} |V2| +{D0 D1 D2 D3} x |V3| +==================== +{R0 R1 R2 R3}, where: +R0 = A0V0 + B0V1 + C0V2 + D0V3, +R1 = A1V0 + B1V1 + C1V2 + D1V3 +... +@endcode +*/ +template +inline v_reg v_matmul(const v_reg& v, + const v_reg& a, const v_reg& b, + const v_reg& c, const v_reg& d) +{ + v_reg res; + for (int i = 0; i < n / 4; i++) + { + res.s[0 + i*4] = v.s[0 + i*4] * a.s[0 + i*4] + v.s[1 + i*4] * b.s[0 + i*4] + v.s[2 + i*4] * c.s[0 + i*4] + v.s[3 + i*4] * d.s[0 + i*4]; + res.s[1 + i*4] = v.s[0 + i*4] * a.s[1 + i*4] + v.s[1 + i*4] * b.s[1 + i*4] + v.s[2 + i*4] * c.s[1 + i*4] + v.s[3 + i*4] * d.s[1 + i*4]; + res.s[2 + i*4] = v.s[0 + i*4] * a.s[2 + i*4] + v.s[1 + i*4] * b.s[2 + i*4] + v.s[2 + i*4] * c.s[2 + i*4] + v.s[3 + i*4] * d.s[2 + i*4]; + res.s[3 + i*4] = v.s[0 + i*4] * a.s[3 + i*4] + v.s[1 + i*4] * b.s[3 + i*4] + v.s[2 + i*4] * c.s[3 + i*4] + v.s[3 + i*4] * d.s[3 + i*4]; + } + return res; +} + +/** @brief Matrix multiplication and add + +Scheme: +@code +{A0 A1 A2 A3} |V0| |D0| +{B0 B1 B2 B3} |V1| |D1| +{C0 C1 C2 C3} x |V2| + |D2| +==================== |D3| +{R0 R1 R2 R3}, where: +R0 = A0V0 + B0V1 + C0V2 + D0, +R1 = A1V0 + B1V1 + C1V2 + D1 +... +@endcode +*/ +template +inline v_reg v_matmuladd(const v_reg& v, + const v_reg& a, const v_reg& b, + const v_reg& c, const v_reg& d) +{ + v_reg res; + for (int i = 0; i < n / 4; i++) + { + res.s[0 + i * 4] = v.s[0 + i * 4] * a.s[0 + i * 4] + v.s[1 + i * 4] * b.s[0 + i * 4] + v.s[2 + i * 4] * c.s[0 + i * 4] + d.s[0 + i * 4]; + res.s[1 + i * 4] = v.s[0 + i * 4] * a.s[1 + i * 4] + v.s[1 + i * 4] * b.s[1 + i * 4] + v.s[2 + i * 4] * c.s[1 + i * 4] + d.s[1 + i * 4]; + res.s[2 + i * 4] = v.s[0 + i * 4] * a.s[2 + i * 4] + v.s[1 + i * 4] * b.s[2 + i * 4] + v.s[2 + i * 4] * c.s[2 + i * 4] + d.s[2 + i * 4]; + res.s[3 + i * 4] = v.s[0 + i * 4] * a.s[3 + i * 4] + v.s[1 + i * 4] * b.s[3 + i * 4] + v.s[2 + i * 4] * c.s[3 + i * 4] + d.s[3 + i * 4]; + } + return res; +} + + +template inline v_reg v_dotprod_expand(const v_reg& a, const v_reg& b) +{ return v_fma(v_cvt_f64(a), v_cvt_f64(b), v_cvt_f64_high(a) * v_cvt_f64_high(b)); } +template inline v_reg v_dotprod_expand(const v_reg& a, const v_reg& b, + const v_reg& c) +{ return v_fma(v_cvt_f64(a), v_cvt_f64(b), v_fma(v_cvt_f64_high(a), v_cvt_f64_high(b), c)); } + +template inline v_reg v_dotprod_expand_fast(const v_reg& a, const v_reg& b) +{ return v_dotprod_expand(a, b); } +template inline v_reg v_dotprod_expand_fast(const v_reg& a, const v_reg& b, + const v_reg& c) +{ return v_dotprod_expand(a, b, c); } + +////// FP16 support /////// + +inline v_reg +v_load_expand(const float16_t* ptr) +{ + v_reg v; + for( int i = 0; i < v.nlanes; i++ ) + { + v.s[i] = ptr[i]; + } + return v; +} +#if CV_SIMD256 +inline v_reg +v256_load_expand(const float16_t* ptr) +{ + v_reg v; + for (int i = 0; i < v.nlanes; i++) + { + v.s[i] = ptr[i]; + } + return v; +} +#endif +#if CV_SIMD512 +inline v_reg +v512_load_expand(const float16_t* ptr) +{ + v_reg v; + for (int i = 0; i < v.nlanes; i++) + { + v.s[i] = ptr[i]; + } + return v; +} +#endif + +template inline void +v_pack_store(float16_t* ptr, const v_reg& v) +{ + for( int i = 0; i < v.nlanes; i++ ) + { + ptr[i] = float16_t(v.s[i]); + } +} + +inline void v_cleanup() {} +#if CV_SIMD256 +inline void v256_cleanup() {} +#endif +#if CV_SIMD512 +inline void v512_cleanup() {} +#endif + +//! @} + +#ifndef CV_DOXYGEN +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END +#endif +} + +#if !defined(CV_DOXYGEN) +#undef CV_SIMD256 +#undef CV_SIMD512 +#endif + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_forward.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_forward.hpp new file mode 100644 index 0000000..979f15a --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_forward.hpp @@ -0,0 +1,191 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + +#ifndef CV__SIMD_FORWARD +#error "Need to pre-define forward width" +#endif + +namespace cv +{ + +//! @cond IGNORED + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN + +/** Types **/ +#if CV__SIMD_FORWARD == 1024 +// [todo] 1024 +#error "1024-long ops not implemented yet" +#elif CV__SIMD_FORWARD == 512 +// 512 +#define __CV_VX(fun) v512_##fun +#define __CV_V_UINT8 v_uint8x64 +#define __CV_V_INT8 v_int8x64 +#define __CV_V_UINT16 v_uint16x32 +#define __CV_V_INT16 v_int16x32 +#define __CV_V_UINT32 v_uint32x16 +#define __CV_V_INT32 v_int32x16 +#define __CV_V_UINT64 v_uint64x8 +#define __CV_V_INT64 v_int64x8 +#define __CV_V_FLOAT32 v_float32x16 +#define __CV_V_FLOAT64 v_float64x8 +struct v_uint8x64; +struct v_int8x64; +struct v_uint16x32; +struct v_int16x32; +struct v_uint32x16; +struct v_int32x16; +struct v_uint64x8; +struct v_int64x8; +struct v_float32x16; +struct v_float64x8; +#elif CV__SIMD_FORWARD == 256 +// 256 +#define __CV_VX(fun) v256_##fun +#define __CV_V_UINT8 v_uint8x32 +#define __CV_V_INT8 v_int8x32 +#define __CV_V_UINT16 v_uint16x16 +#define __CV_V_INT16 v_int16x16 +#define __CV_V_UINT32 v_uint32x8 +#define __CV_V_INT32 v_int32x8 +#define __CV_V_UINT64 v_uint64x4 +#define __CV_V_INT64 v_int64x4 +#define __CV_V_FLOAT32 v_float32x8 +#define __CV_V_FLOAT64 v_float64x4 +struct v_uint8x32; +struct v_int8x32; +struct v_uint16x16; +struct v_int16x16; +struct v_uint32x8; +struct v_int32x8; +struct v_uint64x4; +struct v_int64x4; +struct v_float32x8; +struct v_float64x4; +#else +// 128 +#define __CV_VX(fun) v_##fun +#define __CV_V_UINT8 v_uint8x16 +#define __CV_V_INT8 v_int8x16 +#define __CV_V_UINT16 v_uint16x8 +#define __CV_V_INT16 v_int16x8 +#define __CV_V_UINT32 v_uint32x4 +#define __CV_V_INT32 v_int32x4 +#define __CV_V_UINT64 v_uint64x2 +#define __CV_V_INT64 v_int64x2 +#define __CV_V_FLOAT32 v_float32x4 +#define __CV_V_FLOAT64 v_float64x2 +struct v_uint8x16; +struct v_int8x16; +struct v_uint16x8; +struct v_int16x8; +struct v_uint32x4; +struct v_int32x4; +struct v_uint64x2; +struct v_int64x2; +struct v_float32x4; +struct v_float64x2; +#endif + +/** Value reordering **/ + +// Expansion +void v_expand(const __CV_V_UINT8&, __CV_V_UINT16&, __CV_V_UINT16&); +void v_expand(const __CV_V_INT8&, __CV_V_INT16&, __CV_V_INT16&); +void v_expand(const __CV_V_UINT16&, __CV_V_UINT32&, __CV_V_UINT32&); +void v_expand(const __CV_V_INT16&, __CV_V_INT32&, __CV_V_INT32&); +void v_expand(const __CV_V_UINT32&, __CV_V_UINT64&, __CV_V_UINT64&); +void v_expand(const __CV_V_INT32&, __CV_V_INT64&, __CV_V_INT64&); +// Low Expansion +__CV_V_UINT16 v_expand_low(const __CV_V_UINT8&); +__CV_V_INT16 v_expand_low(const __CV_V_INT8&); +__CV_V_UINT32 v_expand_low(const __CV_V_UINT16&); +__CV_V_INT32 v_expand_low(const __CV_V_INT16&); +__CV_V_UINT64 v_expand_low(const __CV_V_UINT32&); +__CV_V_INT64 v_expand_low(const __CV_V_INT32&); +// High Expansion +__CV_V_UINT16 v_expand_high(const __CV_V_UINT8&); +__CV_V_INT16 v_expand_high(const __CV_V_INT8&); +__CV_V_UINT32 v_expand_high(const __CV_V_UINT16&); +__CV_V_INT32 v_expand_high(const __CV_V_INT16&); +__CV_V_UINT64 v_expand_high(const __CV_V_UINT32&); +__CV_V_INT64 v_expand_high(const __CV_V_INT32&); +// Load & Low Expansion +__CV_V_UINT16 __CV_VX(load_expand)(const uchar*); +__CV_V_INT16 __CV_VX(load_expand)(const schar*); +__CV_V_UINT32 __CV_VX(load_expand)(const ushort*); +__CV_V_INT32 __CV_VX(load_expand)(const short*); +__CV_V_UINT64 __CV_VX(load_expand)(const uint*); +__CV_V_INT64 __CV_VX(load_expand)(const int*); +// Load lower 8-bit and expand into 32-bit +__CV_V_UINT32 __CV_VX(load_expand_q)(const uchar*); +__CV_V_INT32 __CV_VX(load_expand_q)(const schar*); + +// Saturating Pack +__CV_V_UINT8 v_pack(const __CV_V_UINT16&, const __CV_V_UINT16&); +__CV_V_INT8 v_pack(const __CV_V_INT16&, const __CV_V_INT16&); +__CV_V_UINT16 v_pack(const __CV_V_UINT32&, const __CV_V_UINT32&); +__CV_V_INT16 v_pack(const __CV_V_INT32&, const __CV_V_INT32&); +// Non-saturating Pack +__CV_V_UINT32 v_pack(const __CV_V_UINT64&, const __CV_V_UINT64&); +__CV_V_INT32 v_pack(const __CV_V_INT64&, const __CV_V_INT64&); +// Pack signed integers with unsigned saturation +__CV_V_UINT8 v_pack_u(const __CV_V_INT16&, const __CV_V_INT16&); +__CV_V_UINT16 v_pack_u(const __CV_V_INT32&, const __CV_V_INT32&); + +/** Arithmetic, bitwise and comparison operations **/ + +// Non-saturating multiply +#if CV_VSX +template +Tvec v_mul_wrap(const Tvec& a, const Tvec& b); +#else +__CV_V_UINT8 v_mul_wrap(const __CV_V_UINT8&, const __CV_V_UINT8&); +__CV_V_INT8 v_mul_wrap(const __CV_V_INT8&, const __CV_V_INT8&); +__CV_V_UINT16 v_mul_wrap(const __CV_V_UINT16&, const __CV_V_UINT16&); +__CV_V_INT16 v_mul_wrap(const __CV_V_INT16&, const __CV_V_INT16&); +#endif + +// Multiply and expand +#if CV_VSX +template +void v_mul_expand(const Tvec& a, const Tvec& b, Twvec& c, Twvec& d); +#else +void v_mul_expand(const __CV_V_UINT8&, const __CV_V_UINT8&, __CV_V_UINT16&, __CV_V_UINT16&); +void v_mul_expand(const __CV_V_INT8&, const __CV_V_INT8&, __CV_V_INT16&, __CV_V_INT16&); +void v_mul_expand(const __CV_V_UINT16&, const __CV_V_UINT16&, __CV_V_UINT32&, __CV_V_UINT32&); +void v_mul_expand(const __CV_V_INT16&, const __CV_V_INT16&, __CV_V_INT32&, __CV_V_INT32&); +void v_mul_expand(const __CV_V_UINT32&, const __CV_V_UINT32&, __CV_V_UINT64&, __CV_V_UINT64&); +void v_mul_expand(const __CV_V_INT32&, const __CV_V_INT32&, __CV_V_INT64&, __CV_V_INT64&); +#endif + +// Conversions +__CV_V_FLOAT32 v_cvt_f32(const __CV_V_INT32& a); +__CV_V_FLOAT32 v_cvt_f32(const __CV_V_FLOAT64& a); +__CV_V_FLOAT32 v_cvt_f32(const __CV_V_FLOAT64& a, const __CV_V_FLOAT64& b); +__CV_V_FLOAT64 v_cvt_f64(const __CV_V_INT32& a); +__CV_V_FLOAT64 v_cvt_f64_high(const __CV_V_INT32& a); +__CV_V_FLOAT64 v_cvt_f64(const __CV_V_FLOAT32& a); +__CV_V_FLOAT64 v_cvt_f64_high(const __CV_V_FLOAT32& a); +__CV_V_FLOAT64 v_cvt_f64(const __CV_V_INT64& a); + +/** Cleanup **/ +#undef CV__SIMD_FORWARD +#undef __CV_VX +#undef __CV_V_UINT8 +#undef __CV_V_INT8 +#undef __CV_V_UINT16 +#undef __CV_V_INT16 +#undef __CV_V_UINT32 +#undef __CV_V_INT32 +#undef __CV_V_UINT64 +#undef __CV_V_INT64 +#undef __CV_V_FLOAT32 +#undef __CV_V_FLOAT64 + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END + +//! @endcond + +} // cv:: \ No newline at end of file diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_msa.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_msa.hpp new file mode 100644 index 0000000..c035fda --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_msa.hpp @@ -0,0 +1,1887 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_HAL_INTRIN_MSA_HPP +#define OPENCV_HAL_INTRIN_MSA_HPP + +#include +#include "opencv2/core/utility.hpp" + +namespace cv +{ + +//! @cond IGNORED +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN + +#define CV_SIMD128 1 + +//MSA implements 128-bit wide vector registers shared with the 64-bit wide floating-point unit registers. +//MSA and FPU can not be both present, unless the FPU has 64-bit floating-point registers. +#define CV_SIMD128_64F 1 + +struct v_uint8x16 +{ + typedef uchar lane_type; + enum { nlanes = 16 }; + + v_uint8x16() {} + explicit v_uint8x16(v16u8 v) : val(v) {} + v_uint8x16(uchar v0, uchar v1, uchar v2, uchar v3, uchar v4, uchar v5, uchar v6, uchar v7, + uchar v8, uchar v9, uchar v10, uchar v11, uchar v12, uchar v13, uchar v14, uchar v15) + { + uchar v[] = {v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15}; + val = msa_ld1q_u8(v); + } + + uchar get0() const + { + return msa_getq_lane_u8(val, 0); + } + + v16u8 val; +}; + +struct v_int8x16 +{ + typedef schar lane_type; + enum { nlanes = 16 }; + + v_int8x16() {} + explicit v_int8x16(v16i8 v) : val(v) {} + v_int8x16(schar v0, schar v1, schar v2, schar v3, schar v4, schar v5, schar v6, schar v7, + schar v8, schar v9, schar v10, schar v11, schar v12, schar v13, schar v14, schar v15) + { + schar v[] = {v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15}; + val = msa_ld1q_s8(v); + } + + schar get0() const + { + return msa_getq_lane_s8(val, 0); + } + + v16i8 val; +}; + +struct v_uint16x8 +{ + typedef ushort lane_type; + enum { nlanes = 8 }; + + v_uint16x8() {} + explicit v_uint16x8(v8u16 v) : val(v) {} + v_uint16x8(ushort v0, ushort v1, ushort v2, ushort v3, ushort v4, ushort v5, ushort v6, ushort v7) + { + ushort v[] = {v0, v1, v2, v3, v4, v5, v6, v7}; + val = msa_ld1q_u16(v); + } + + ushort get0() const + { + return msa_getq_lane_u16(val, 0); + } + + v8u16 val; +}; + +struct v_int16x8 +{ + typedef short lane_type; + enum { nlanes = 8 }; + + v_int16x8() {} + explicit v_int16x8(v8i16 v) : val(v) {} + v_int16x8(short v0, short v1, short v2, short v3, short v4, short v5, short v6, short v7) + { + short v[] = {v0, v1, v2, v3, v4, v5, v6, v7}; + val = msa_ld1q_s16(v); + } + + short get0() const + { + return msa_getq_lane_s16(val, 0); + } + + v8i16 val; +}; + +struct v_uint32x4 +{ + typedef unsigned int lane_type; + enum { nlanes = 4 }; + + v_uint32x4() {} + explicit v_uint32x4(v4u32 v) : val(v) {} + v_uint32x4(unsigned int v0, unsigned int v1, unsigned int v2, unsigned int v3) + { + unsigned int v[] = {v0, v1, v2, v3}; + val = msa_ld1q_u32(v); + } + + unsigned int get0() const + { + return msa_getq_lane_u32(val, 0); + } + + v4u32 val; +}; + +struct v_int32x4 +{ + typedef int lane_type; + enum { nlanes = 4 }; + + v_int32x4() {} + explicit v_int32x4(v4i32 v) : val(v) {} + v_int32x4(int v0, int v1, int v2, int v3) + { + int v[] = {v0, v1, v2, v3}; + val = msa_ld1q_s32(v); + } + + int get0() const + { + return msa_getq_lane_s32(val, 0); + } + + v4i32 val; +}; + +struct v_float32x4 +{ + typedef float lane_type; + enum { nlanes = 4 }; + + v_float32x4() {} + explicit v_float32x4(v4f32 v) : val(v) {} + v_float32x4(float v0, float v1, float v2, float v3) + { + float v[] = {v0, v1, v2, v3}; + val = msa_ld1q_f32(v); + } + + float get0() const + { + return msa_getq_lane_f32(val, 0); + } + + v4f32 val; +}; + +struct v_uint64x2 +{ + typedef uint64 lane_type; + enum { nlanes = 2 }; + + v_uint64x2() {} + explicit v_uint64x2(v2u64 v) : val(v) {} + v_uint64x2(uint64 v0, uint64 v1) + { + uint64 v[] = {v0, v1}; + val = msa_ld1q_u64(v); + } + + uint64 get0() const + { + return msa_getq_lane_u64(val, 0); + } + + v2u64 val; +}; + +struct v_int64x2 +{ + typedef int64 lane_type; + enum { nlanes = 2 }; + + v_int64x2() {} + explicit v_int64x2(v2i64 v) : val(v) {} + v_int64x2(int64 v0, int64 v1) + { + int64 v[] = {v0, v1}; + val = msa_ld1q_s64(v); + } + + int64 get0() const + { + return msa_getq_lane_s64(val, 0); + } + + v2i64 val; +}; + +struct v_float64x2 +{ + typedef double lane_type; + enum { nlanes = 2 }; + + v_float64x2() {} + explicit v_float64x2(v2f64 v) : val(v) {} + v_float64x2(double v0, double v1) + { + double v[] = {v0, v1}; + val = msa_ld1q_f64(v); + } + + double get0() const + { + return msa_getq_lane_f64(val, 0); + } + + v2f64 val; +}; + +#define OPENCV_HAL_IMPL_MSA_INIT(_Tpv, _Tp, suffix) \ +inline v_##_Tpv v_setzero_##suffix() { return v_##_Tpv(msa_dupq_n_##suffix((_Tp)0)); } \ +inline v_##_Tpv v_setall_##suffix(_Tp v) { return v_##_Tpv(msa_dupq_n_##suffix(v)); } \ +inline v_uint8x16 v_reinterpret_as_u8(const v_##_Tpv& v) { return v_uint8x16(MSA_TPV_REINTERPRET(v16u8, v.val)); } \ +inline v_int8x16 v_reinterpret_as_s8(const v_##_Tpv& v) { return v_int8x16(MSA_TPV_REINTERPRET(v16i8, v.val)); } \ +inline v_uint16x8 v_reinterpret_as_u16(const v_##_Tpv& v) { return v_uint16x8(MSA_TPV_REINTERPRET(v8u16, v.val)); } \ +inline v_int16x8 v_reinterpret_as_s16(const v_##_Tpv& v) { return v_int16x8(MSA_TPV_REINTERPRET(v8i16, v.val)); } \ +inline v_uint32x4 v_reinterpret_as_u32(const v_##_Tpv& v) { return v_uint32x4(MSA_TPV_REINTERPRET(v4u32, v.val)); } \ +inline v_int32x4 v_reinterpret_as_s32(const v_##_Tpv& v) { return v_int32x4(MSA_TPV_REINTERPRET(v4i32, v.val)); } \ +inline v_uint64x2 v_reinterpret_as_u64(const v_##_Tpv& v) { return v_uint64x2(MSA_TPV_REINTERPRET(v2u64, v.val)); } \ +inline v_int64x2 v_reinterpret_as_s64(const v_##_Tpv& v) { return v_int64x2(MSA_TPV_REINTERPRET(v2i64, v.val)); } \ +inline v_float32x4 v_reinterpret_as_f32(const v_##_Tpv& v) { return v_float32x4(MSA_TPV_REINTERPRET(v4f32, v.val)); } \ +inline v_float64x2 v_reinterpret_as_f64(const v_##_Tpv& v) { return v_float64x2(MSA_TPV_REINTERPRET(v2f64, v.val)); } + +OPENCV_HAL_IMPL_MSA_INIT(uint8x16, uchar, u8) +OPENCV_HAL_IMPL_MSA_INIT(int8x16, schar, s8) +OPENCV_HAL_IMPL_MSA_INIT(uint16x8, ushort, u16) +OPENCV_HAL_IMPL_MSA_INIT(int16x8, short, s16) +OPENCV_HAL_IMPL_MSA_INIT(uint32x4, unsigned int, u32) +OPENCV_HAL_IMPL_MSA_INIT(int32x4, int, s32) +OPENCV_HAL_IMPL_MSA_INIT(uint64x2, uint64, u64) +OPENCV_HAL_IMPL_MSA_INIT(int64x2, int64, s64) +OPENCV_HAL_IMPL_MSA_INIT(float32x4, float, f32) +OPENCV_HAL_IMPL_MSA_INIT(float64x2, double, f64) + +#define OPENCV_HAL_IMPL_MSA_PACK(_Tpvec, _Tpwvec, pack, mov, rshr) \ +inline _Tpvec v_##pack(const _Tpwvec& a, const _Tpwvec& b) \ +{ \ + return _Tpvec(mov(a.val, b.val)); \ +} \ +template inline \ +_Tpvec v_rshr_##pack(const _Tpwvec& a, const _Tpwvec& b) \ +{ \ + return _Tpvec(rshr(a.val, b.val, n)); \ +} + +OPENCV_HAL_IMPL_MSA_PACK(v_uint8x16, v_uint16x8, pack, msa_qpack_u16, msa_qrpackr_u16) +OPENCV_HAL_IMPL_MSA_PACK(v_int8x16, v_int16x8, pack, msa_qpack_s16, msa_qrpackr_s16) +OPENCV_HAL_IMPL_MSA_PACK(v_uint16x8, v_uint32x4, pack, msa_qpack_u32, msa_qrpackr_u32) +OPENCV_HAL_IMPL_MSA_PACK(v_int16x8, v_int32x4, pack, msa_qpack_s32, msa_qrpackr_s32) +OPENCV_HAL_IMPL_MSA_PACK(v_uint32x4, v_uint64x2, pack, msa_pack_u64, msa_rpackr_u64) +OPENCV_HAL_IMPL_MSA_PACK(v_int32x4, v_int64x2, pack, msa_pack_s64, msa_rpackr_s64) +OPENCV_HAL_IMPL_MSA_PACK(v_uint8x16, v_int16x8, pack_u, msa_qpacku_s16, msa_qrpackru_s16) +OPENCV_HAL_IMPL_MSA_PACK(v_uint16x8, v_int32x4, pack_u, msa_qpacku_s32, msa_qrpackru_s32) + +#define OPENCV_HAL_IMPL_MSA_PACK_STORE(_Tpvec, _Tp, hreg, suffix, _Tpwvec, pack, mov, rshr) \ +inline void v_##pack##_store(_Tp* ptr, const _Tpwvec& a) \ +{ \ + hreg a1 = mov(a.val); \ + msa_st1_##suffix(ptr, a1); \ +} \ +template inline \ +void v_rshr_##pack##_store(_Tp* ptr, const _Tpwvec& a) \ +{ \ + hreg a1 = rshr(a.val, n); \ + msa_st1_##suffix(ptr, a1); \ +} + +OPENCV_HAL_IMPL_MSA_PACK_STORE(v_uint8x16, uchar, v8u8, u8, v_uint16x8, pack, msa_qmovn_u16, msa_qrshrn_n_u16) +OPENCV_HAL_IMPL_MSA_PACK_STORE(v_int8x16, schar, v8i8, s8, v_int16x8, pack, msa_qmovn_s16, msa_qrshrn_n_s16) +OPENCV_HAL_IMPL_MSA_PACK_STORE(v_uint16x8, ushort, v4u16, u16, v_uint32x4, pack, msa_qmovn_u32, msa_qrshrn_n_u32) +OPENCV_HAL_IMPL_MSA_PACK_STORE(v_int16x8, short, v4i16, s16, v_int32x4, pack, msa_qmovn_s32, msa_qrshrn_n_s32) +OPENCV_HAL_IMPL_MSA_PACK_STORE(v_uint32x4, unsigned, v2u32, u32, v_uint64x2, pack, msa_movn_u64, msa_rshrn_n_u64) +OPENCV_HAL_IMPL_MSA_PACK_STORE(v_int32x4, int, v2i32, s32, v_int64x2, pack, msa_movn_s64, msa_rshrn_n_s64) +OPENCV_HAL_IMPL_MSA_PACK_STORE(v_uint8x16, uchar, v8u8, u8, v_int16x8, pack_u, msa_qmovun_s16, msa_qrshrun_n_s16) +OPENCV_HAL_IMPL_MSA_PACK_STORE(v_uint16x8, ushort, v4u16, u16, v_int32x4, pack_u, msa_qmovun_s32, msa_qrshrun_n_s32) + +// pack boolean +inline v_uint8x16 v_pack_b(const v_uint16x8& a, const v_uint16x8& b) +{ + return v_uint8x16(msa_pack_u16(a.val, b.val)); +} + +inline v_uint8x16 v_pack_b(const v_uint32x4& a, const v_uint32x4& b, + const v_uint32x4& c, const v_uint32x4& d) +{ + return v_uint8x16(msa_pack_u16(msa_pack_u32(a.val, b.val), msa_pack_u32(c.val, d.val))); +} + +inline v_uint8x16 v_pack_b(const v_uint64x2& a, const v_uint64x2& b, const v_uint64x2& c, + const v_uint64x2& d, const v_uint64x2& e, const v_uint64x2& f, + const v_uint64x2& g, const v_uint64x2& h) +{ + v8u16 abcd = msa_pack_u32(msa_pack_u64(a.val, b.val), msa_pack_u64(c.val, d.val)); + v8u16 efgh = msa_pack_u32(msa_pack_u64(e.val, f.val), msa_pack_u64(g.val, h.val)); + return v_uint8x16(msa_pack_u16(abcd, efgh)); +} + +inline v_float32x4 v_matmul(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& m3) +{ + v4f32 v0 = v.val; + v4f32 res = msa_mulq_lane_f32(m0.val, v0, 0); + res = msa_mlaq_lane_f32(res, m1.val, v0, 1); + res = msa_mlaq_lane_f32(res, m2.val, v0, 2); + res = msa_mlaq_lane_f32(res, m3.val, v0, 3); + return v_float32x4(res); +} + +inline v_float32x4 v_matmuladd(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& a) +{ + v4f32 v0 = v.val; + v4f32 res = msa_mulq_lane_f32(m0.val, v0, 0); + res = msa_mlaq_lane_f32(res, m1.val, v0, 1); + res = msa_mlaq_lane_f32(res, m2.val, v0, 2); + res = msa_addq_f32(res, a.val); + return v_float32x4(res); +} + +#define OPENCV_HAL_IMPL_MSA_BIN_OP(bin_op, _Tpvec, intrin) \ +inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(intrin(a.val, b.val)); \ +} \ +inline _Tpvec& operator bin_op##= (_Tpvec& a, const _Tpvec& b) \ +{ \ + a.val = intrin(a.val, b.val); \ + return a; \ +} + +OPENCV_HAL_IMPL_MSA_BIN_OP(+, v_uint8x16, msa_qaddq_u8) +OPENCV_HAL_IMPL_MSA_BIN_OP(-, v_uint8x16, msa_qsubq_u8) +OPENCV_HAL_IMPL_MSA_BIN_OP(+, v_int8x16, msa_qaddq_s8) +OPENCV_HAL_IMPL_MSA_BIN_OP(-, v_int8x16, msa_qsubq_s8) +OPENCV_HAL_IMPL_MSA_BIN_OP(+, v_uint16x8, msa_qaddq_u16) +OPENCV_HAL_IMPL_MSA_BIN_OP(-, v_uint16x8, msa_qsubq_u16) +OPENCV_HAL_IMPL_MSA_BIN_OP(+, v_int16x8, msa_qaddq_s16) +OPENCV_HAL_IMPL_MSA_BIN_OP(-, v_int16x8, msa_qsubq_s16) +OPENCV_HAL_IMPL_MSA_BIN_OP(+, v_int32x4, msa_addq_s32) +OPENCV_HAL_IMPL_MSA_BIN_OP(-, v_int32x4, msa_subq_s32) +OPENCV_HAL_IMPL_MSA_BIN_OP(*, v_int32x4, msa_mulq_s32) +OPENCV_HAL_IMPL_MSA_BIN_OP(+, v_uint32x4, msa_addq_u32) +OPENCV_HAL_IMPL_MSA_BIN_OP(-, v_uint32x4, msa_subq_u32) +OPENCV_HAL_IMPL_MSA_BIN_OP(*, v_uint32x4, msa_mulq_u32) +OPENCV_HAL_IMPL_MSA_BIN_OP(+, v_float32x4, msa_addq_f32) +OPENCV_HAL_IMPL_MSA_BIN_OP(-, v_float32x4, msa_subq_f32) +OPENCV_HAL_IMPL_MSA_BIN_OP(*, v_float32x4, msa_mulq_f32) +OPENCV_HAL_IMPL_MSA_BIN_OP(+, v_int64x2, msa_addq_s64) +OPENCV_HAL_IMPL_MSA_BIN_OP(-, v_int64x2, msa_subq_s64) +OPENCV_HAL_IMPL_MSA_BIN_OP(+, v_uint64x2, msa_addq_u64) +OPENCV_HAL_IMPL_MSA_BIN_OP(-, v_uint64x2, msa_subq_u64) +OPENCV_HAL_IMPL_MSA_BIN_OP(/, v_float32x4, msa_divq_f32) +OPENCV_HAL_IMPL_MSA_BIN_OP(+, v_float64x2, msa_addq_f64) +OPENCV_HAL_IMPL_MSA_BIN_OP(-, v_float64x2, msa_subq_f64) +OPENCV_HAL_IMPL_MSA_BIN_OP(*, v_float64x2, msa_mulq_f64) +OPENCV_HAL_IMPL_MSA_BIN_OP(/, v_float64x2, msa_divq_f64) + +// saturating multiply 8-bit, 16-bit +#define OPENCV_HAL_IMPL_MSA_MUL_SAT(_Tpvec, _Tpwvec) \ +inline _Tpvec operator * (const _Tpvec& a, const _Tpvec& b) \ +{ \ + _Tpwvec c, d; \ + v_mul_expand(a, b, c, d); \ + return v_pack(c, d); \ +} \ +inline _Tpvec& operator *= (_Tpvec& a, const _Tpvec& b) \ +{a = a * b; return a; } + +OPENCV_HAL_IMPL_MSA_MUL_SAT(v_int8x16, v_int16x8) +OPENCV_HAL_IMPL_MSA_MUL_SAT(v_uint8x16, v_uint16x8) +OPENCV_HAL_IMPL_MSA_MUL_SAT(v_int16x8, v_int32x4) +OPENCV_HAL_IMPL_MSA_MUL_SAT(v_uint16x8, v_uint32x4) + +// Multiply and expand +inline void v_mul_expand(const v_int8x16& a, const v_int8x16& b, + v_int16x8& c, v_int16x8& d) +{ + v16i8 a_lo, a_hi, b_lo, b_hi; + + ILVRL_B2_SB(a.val, msa_dupq_n_s8(0), a_lo, a_hi); + ILVRL_B2_SB(b.val, msa_dupq_n_s8(0), b_lo, b_hi); + c.val = msa_mulq_s16(msa_paddlq_s8(a_lo), msa_paddlq_s8(b_lo)); + d.val = msa_mulq_s16(msa_paddlq_s8(a_hi), msa_paddlq_s8(b_hi)); +} + +inline void v_mul_expand(const v_uint8x16& a, const v_uint8x16& b, + v_uint16x8& c, v_uint16x8& d) +{ + v16u8 a_lo, a_hi, b_lo, b_hi; + + ILVRL_B2_UB(a.val, msa_dupq_n_u8(0), a_lo, a_hi); + ILVRL_B2_UB(b.val, msa_dupq_n_u8(0), b_lo, b_hi); + c.val = msa_mulq_u16(msa_paddlq_u8(a_lo), msa_paddlq_u8(b_lo)); + d.val = msa_mulq_u16(msa_paddlq_u8(a_hi), msa_paddlq_u8(b_hi)); +} + +inline void v_mul_expand(const v_int16x8& a, const v_int16x8& b, + v_int32x4& c, v_int32x4& d) +{ + v8i16 a_lo, a_hi, b_lo, b_hi; + + ILVRL_H2_SH(a.val, msa_dupq_n_s16(0), a_lo, a_hi); + ILVRL_H2_SH(b.val, msa_dupq_n_s16(0), b_lo, b_hi); + c.val = msa_mulq_s32(msa_paddlq_s16(a_lo), msa_paddlq_s16(b_lo)); + d.val = msa_mulq_s32(msa_paddlq_s16(a_hi), msa_paddlq_s16(b_hi)); +} + +inline void v_mul_expand(const v_uint16x8& a, const v_uint16x8& b, + v_uint32x4& c, v_uint32x4& d) +{ + v8u16 a_lo, a_hi, b_lo, b_hi; + + ILVRL_H2_UH(a.val, msa_dupq_n_u16(0), a_lo, a_hi); + ILVRL_H2_UH(b.val, msa_dupq_n_u16(0), b_lo, b_hi); + c.val = msa_mulq_u32(msa_paddlq_u16(a_lo), msa_paddlq_u16(b_lo)); + d.val = msa_mulq_u32(msa_paddlq_u16(a_hi), msa_paddlq_u16(b_hi)); +} + +inline void v_mul_expand(const v_uint32x4& a, const v_uint32x4& b, + v_uint64x2& c, v_uint64x2& d) +{ + v4u32 a_lo, a_hi, b_lo, b_hi; + + ILVRL_W2_UW(a.val, msa_dupq_n_u32(0), a_lo, a_hi); + ILVRL_W2_UW(b.val, msa_dupq_n_u32(0), b_lo, b_hi); + c.val = msa_mulq_u64(msa_paddlq_u32(a_lo), msa_paddlq_u32(b_lo)); + d.val = msa_mulq_u64(msa_paddlq_u32(a_hi), msa_paddlq_u32(b_hi)); +} + +inline v_int16x8 v_mul_hi(const v_int16x8& a, const v_int16x8& b) +{ + v8i16 a_lo, a_hi, b_lo, b_hi; + + ILVRL_H2_SH(a.val, msa_dupq_n_s16(0), a_lo, a_hi); + ILVRL_H2_SH(b.val, msa_dupq_n_s16(0), b_lo, b_hi); + + return v_int16x8(msa_packr_s32(msa_mulq_s32(msa_paddlq_s16(a_lo), msa_paddlq_s16(b_lo)), + msa_mulq_s32(msa_paddlq_s16(a_hi), msa_paddlq_s16(b_hi)), 16)); +} + +inline v_uint16x8 v_mul_hi(const v_uint16x8& a, const v_uint16x8& b) +{ + v8u16 a_lo, a_hi, b_lo, b_hi; + + ILVRL_H2_UH(a.val, msa_dupq_n_u16(0), a_lo, a_hi); + ILVRL_H2_UH(b.val, msa_dupq_n_u16(0), b_lo, b_hi); + + return v_uint16x8(msa_packr_u32(msa_mulq_u32(msa_paddlq_u16(a_lo), msa_paddlq_u16(b_lo)), + msa_mulq_u32(msa_paddlq_u16(a_hi), msa_paddlq_u16(b_hi)), 16)); +} + +//////// Dot Product //////// + +// 16 >> 32 +inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b) +{ return v_int32x4(msa_dotp_s_w(a.val, b.val)); } +inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b, const v_int32x4& c) +{ return v_int32x4(msa_dpadd_s_w(c.val , a.val, b.val)); } + +// 32 >> 64 +inline v_int64x2 v_dotprod(const v_int32x4& a, const v_int32x4& b) +{ return v_int64x2(msa_dotp_s_d(a.val, b.val)); } +inline v_int64x2 v_dotprod(const v_int32x4& a, const v_int32x4& b, const v_int64x2& c) +{ return v_int64x2(msa_dpadd_s_d(c.val , a.val, b.val)); } + +// 8 >> 32 +inline v_uint32x4 v_dotprod_expand(const v_uint8x16& a, const v_uint8x16& b) +{ + v8u16 even_a = msa_shrq_n_u16(msa_shlq_n_u16(MSA_TPV_REINTERPRET(v8u16, a.val), 8), 8); + v8u16 odd_a = msa_shrq_n_u16(MSA_TPV_REINTERPRET(v8u16, a.val), 8); + v8u16 even_b = msa_shrq_n_u16(msa_shlq_n_u16(MSA_TPV_REINTERPRET(v8u16, b.val), 8), 8); + v8u16 odd_b = msa_shrq_n_u16(MSA_TPV_REINTERPRET(v8u16, b.val), 8); + v4u32 prod = msa_dotp_u_w(even_a, even_b); + return v_uint32x4(msa_dpadd_u_w(prod, odd_a, odd_b)); +} +inline v_uint32x4 v_dotprod_expand(const v_uint8x16& a, const v_uint8x16& b, const v_uint32x4& c) +{ + v8u16 even_a = msa_shrq_n_u16(msa_shlq_n_u16(MSA_TPV_REINTERPRET(v8u16, a.val), 8), 8); + v8u16 odd_a = msa_shrq_n_u16(MSA_TPV_REINTERPRET(v8u16, a.val), 8); + v8u16 even_b = msa_shrq_n_u16(msa_shlq_n_u16(MSA_TPV_REINTERPRET(v8u16, b.val), 8), 8); + v8u16 odd_b = msa_shrq_n_u16(MSA_TPV_REINTERPRET(v8u16, b.val), 8); + v4u32 prod = msa_dpadd_u_w(c.val, even_a, even_b); + return v_uint32x4(msa_dpadd_u_w(prod, odd_a, odd_b)); +} + +inline v_int32x4 v_dotprod_expand(const v_int8x16& a, const v_int8x16& b) +{ + v8i16 prod = msa_dotp_s_h(a.val, b.val); + return v_int32x4(msa_hadd_s32(prod, prod)); +} +inline v_int32x4 v_dotprod_expand(const v_int8x16& a, const v_int8x16& b, + const v_int32x4& c) +{ return v_dotprod_expand(a, b) + c; } + +// 16 >> 64 +inline v_uint64x2 v_dotprod_expand(const v_uint16x8& a, const v_uint16x8& b) +{ + v4u32 even_a = msa_shrq_n_u32(msa_shlq_n_u32(MSA_TPV_REINTERPRET(v4u32, a.val), 16), 16); + v4u32 odd_a = msa_shrq_n_u32(MSA_TPV_REINTERPRET(v4u32, a.val), 16); + v4u32 even_b = msa_shrq_n_u32(msa_shlq_n_u32(MSA_TPV_REINTERPRET(v4u32, b.val), 16), 16); + v4u32 odd_b = msa_shrq_n_u32(MSA_TPV_REINTERPRET(v4u32, b.val), 16); + v2u64 prod = msa_dotp_u_d(even_a, even_b); + return v_uint64x2(msa_dpadd_u_d(prod, odd_a, odd_b)); +} +inline v_uint64x2 v_dotprod_expand(const v_uint16x8& a, const v_uint16x8& b, + const v_uint64x2& c) +{ + v4u32 even_a = msa_shrq_n_u32(msa_shlq_n_u32(MSA_TPV_REINTERPRET(v4u32, a.val), 16), 16); + v4u32 odd_a = msa_shrq_n_u32(MSA_TPV_REINTERPRET(v4u32, a.val), 16); + v4u32 even_b = msa_shrq_n_u32(msa_shlq_n_u32(MSA_TPV_REINTERPRET(v4u32, b.val), 16), 16); + v4u32 odd_b = msa_shrq_n_u32(MSA_TPV_REINTERPRET(v4u32, b.val), 16); + v2u64 prod = msa_dpadd_u_d(c.val, even_a, even_b); + return v_uint64x2(msa_dpadd_u_d(prod, odd_a, odd_b)); +} + +inline v_int64x2 v_dotprod_expand(const v_int16x8& a, const v_int16x8& b) +{ + v4i32 prod = msa_dotp_s_w(a.val, b.val); + return v_int64x2(msa_hadd_s64(prod, prod)); +} +inline v_int64x2 v_dotprod_expand(const v_int16x8& a, const v_int16x8& b, const v_int64x2& c) +{ return v_dotprod_expand(a, b) + c; } + +// 32 >> 64f +inline v_float64x2 v_dotprod_expand(const v_int32x4& a, const v_int32x4& b) +{ return v_cvt_f64(v_dotprod(a, b)); } +inline v_float64x2 v_dotprod_expand(const v_int32x4& a, const v_int32x4& b, const v_float64x2& c) +{ return v_dotprod_expand(a, b) + c; } + + +//////// Fast Dot Product //////// + +// 16 >> 32 +inline v_int32x4 v_dotprod_fast(const v_int16x8& a, const v_int16x8& b) +{ return v_dotprod(a, b); } +inline v_int32x4 v_dotprod_fast(const v_int16x8& a, const v_int16x8& b, const v_int32x4& c) +{ return v_dotprod(a, b, c); } + +// 32 >> 64 +inline v_int64x2 v_dotprod_fast(const v_int32x4& a, const v_int32x4& b) +{ return v_dotprod(a, b); } +inline v_int64x2 v_dotprod_fast(const v_int32x4& a, const v_int32x4& b, const v_int64x2& c) +{ return v_dotprod(a, b, c); } + +// 8 >> 32 +inline v_uint32x4 v_dotprod_expand_fast(const v_uint8x16& a, const v_uint8x16& b) +{ return v_dotprod_expand(a, b); } +inline v_uint32x4 v_dotprod_expand_fast(const v_uint8x16& a, const v_uint8x16& b, const v_uint32x4& c) +{ return v_dotprod_expand(a, b, c); } +inline v_int32x4 v_dotprod_expand_fast(const v_int8x16& a, const v_int8x16& b) +{ return v_dotprod_expand(a, b); } +inline v_int32x4 v_dotprod_expand_fast(const v_int8x16& a, const v_int8x16& b, const v_int32x4& c) +{ return v_dotprod_expand(a, b, c); } + +// 16 >> 64 +inline v_uint64x2 v_dotprod_expand_fast(const v_uint16x8& a, const v_uint16x8& b) +{ return v_dotprod_expand(a, b); } +inline v_uint64x2 v_dotprod_expand_fast(const v_uint16x8& a, const v_uint16x8& b, const v_uint64x2& c) +{ return v_dotprod_expand(a, b, c); } +inline v_int64x2 v_dotprod_expand_fast(const v_int16x8& a, const v_int16x8& b) +{ return v_dotprod_expand(a, b); } +inline v_int64x2 v_dotprod_expand_fast(const v_int16x8& a, const v_int16x8& b, const v_int64x2& c) +{ return v_dotprod_expand(a, b, c); } + +// 32 >> 64f +inline v_float64x2 v_dotprod_expand_fast(const v_int32x4& a, const v_int32x4& b) +{ return v_dotprod_expand(a, b); } +inline v_float64x2 v_dotprod_expand_fast(const v_int32x4& a, const v_int32x4& b, const v_float64x2& c) +{ return v_dotprod_expand(a, b, c); } + +#define OPENCV_HAL_IMPL_MSA_LOGIC_OP(_Tpvec, _Tpv, suffix) \ +OPENCV_HAL_IMPL_MSA_BIN_OP(&, _Tpvec, msa_andq_##suffix) \ +OPENCV_HAL_IMPL_MSA_BIN_OP(|, _Tpvec, msa_orrq_##suffix) \ +OPENCV_HAL_IMPL_MSA_BIN_OP(^, _Tpvec, msa_eorq_##suffix) \ +inline _Tpvec operator ~ (const _Tpvec& a) \ +{ \ + return _Tpvec(MSA_TPV_REINTERPRET(_Tpv, msa_mvnq_u8(MSA_TPV_REINTERPRET(v16u8, a.val)))); \ +} + +OPENCV_HAL_IMPL_MSA_LOGIC_OP(v_uint8x16, v16u8, u8) +OPENCV_HAL_IMPL_MSA_LOGIC_OP(v_int8x16, v16i8, s8) +OPENCV_HAL_IMPL_MSA_LOGIC_OP(v_uint16x8, v8u16, u16) +OPENCV_HAL_IMPL_MSA_LOGIC_OP(v_int16x8, v8i16, s16) +OPENCV_HAL_IMPL_MSA_LOGIC_OP(v_uint32x4, v4u32, u32) +OPENCV_HAL_IMPL_MSA_LOGIC_OP(v_int32x4, v4i32, s32) +OPENCV_HAL_IMPL_MSA_LOGIC_OP(v_uint64x2, v2u64, u64) +OPENCV_HAL_IMPL_MSA_LOGIC_OP(v_int64x2, v2i64, s64) + +#define OPENCV_HAL_IMPL_MSA_FLT_BIT_OP(bin_op, intrin) \ +inline v_float32x4 operator bin_op (const v_float32x4& a, const v_float32x4& b) \ +{ \ + return v_float32x4(MSA_TPV_REINTERPRET(v4f32, intrin(MSA_TPV_REINTERPRET(v4i32, a.val), MSA_TPV_REINTERPRET(v4i32, b.val)))); \ +} \ +inline v_float32x4& operator bin_op##= (v_float32x4& a, const v_float32x4& b) \ +{ \ + a.val = MSA_TPV_REINTERPRET(v4f32, intrin(MSA_TPV_REINTERPRET(v4i32, a.val), MSA_TPV_REINTERPRET(v4i32, b.val))); \ + return a; \ +} + +OPENCV_HAL_IMPL_MSA_FLT_BIT_OP(&, msa_andq_s32) +OPENCV_HAL_IMPL_MSA_FLT_BIT_OP(|, msa_orrq_s32) +OPENCV_HAL_IMPL_MSA_FLT_BIT_OP(^, msa_eorq_s32) + +inline v_float32x4 operator ~ (const v_float32x4& a) +{ + return v_float32x4(MSA_TPV_REINTERPRET(v4f32, msa_mvnq_s32(MSA_TPV_REINTERPRET(v4i32, a.val)))); +} + +/* v_abs */ +#define OPENCV_HAL_IMPL_MSA_ABS(_Tpuvec, _Tpsvec, usuffix, ssuffix) \ +inline _Tpuvec v_abs(const _Tpsvec& a) \ +{ \ + return v_reinterpret_as_##usuffix(_Tpsvec(msa_absq_##ssuffix(a.val))); \ +} + +OPENCV_HAL_IMPL_MSA_ABS(v_uint8x16, v_int8x16, u8, s8) +OPENCV_HAL_IMPL_MSA_ABS(v_uint16x8, v_int16x8, u16, s16) +OPENCV_HAL_IMPL_MSA_ABS(v_uint32x4, v_int32x4, u32, s32) + +/* v_abs(float), v_sqrt, v_invsqrt */ +#define OPENCV_HAL_IMPL_MSA_BASIC_FUNC(_Tpvec, func, intrin) \ +inline _Tpvec func(const _Tpvec& a) \ +{ \ + return _Tpvec(intrin(a.val)); \ +} + +OPENCV_HAL_IMPL_MSA_BASIC_FUNC(v_float32x4, v_abs, msa_absq_f32) +OPENCV_HAL_IMPL_MSA_BASIC_FUNC(v_float64x2, v_abs, msa_absq_f64) +OPENCV_HAL_IMPL_MSA_BASIC_FUNC(v_float32x4, v_sqrt, msa_sqrtq_f32) +OPENCV_HAL_IMPL_MSA_BASIC_FUNC(v_float32x4, v_invsqrt, msa_rsqrtq_f32) +OPENCV_HAL_IMPL_MSA_BASIC_FUNC(v_float64x2, v_sqrt, msa_sqrtq_f64) +OPENCV_HAL_IMPL_MSA_BASIC_FUNC(v_float64x2, v_invsqrt, msa_rsqrtq_f64) + +#define OPENCV_HAL_IMPL_MSA_DBL_BIT_OP(bin_op, intrin) \ +inline v_float64x2 operator bin_op (const v_float64x2& a, const v_float64x2& b) \ +{ \ + return v_float64x2(MSA_TPV_REINTERPRET(v2f64, intrin(MSA_TPV_REINTERPRET(v2i64, a.val), MSA_TPV_REINTERPRET(v2i64, b.val)))); \ +} \ +inline v_float64x2& operator bin_op##= (v_float64x2& a, const v_float64x2& b) \ +{ \ + a.val = MSA_TPV_REINTERPRET(v2f64, intrin(MSA_TPV_REINTERPRET(v2i64, a.val), MSA_TPV_REINTERPRET(v2i64, b.val))); \ + return a; \ +} + +OPENCV_HAL_IMPL_MSA_DBL_BIT_OP(&, msa_andq_s64) +OPENCV_HAL_IMPL_MSA_DBL_BIT_OP(|, msa_orrq_s64) +OPENCV_HAL_IMPL_MSA_DBL_BIT_OP(^, msa_eorq_s64) + +inline v_float64x2 operator ~ (const v_float64x2& a) +{ + return v_float64x2(MSA_TPV_REINTERPRET(v2f64, msa_mvnq_s32(MSA_TPV_REINTERPRET(v4i32, a.val)))); +} + +// TODO: exp, log, sin, cos + +#define OPENCV_HAL_IMPL_MSA_BIN_FUNC(_Tpvec, func, intrin) \ +inline _Tpvec func(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(intrin(a.val, b.val)); \ +} + +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_uint8x16, v_min, msa_minq_u8) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_uint8x16, v_max, msa_maxq_u8) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_int8x16, v_min, msa_minq_s8) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_int8x16, v_max, msa_maxq_s8) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_uint16x8, v_min, msa_minq_u16) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_uint16x8, v_max, msa_maxq_u16) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_int16x8, v_min, msa_minq_s16) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_int16x8, v_max, msa_maxq_s16) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_uint32x4, v_min, msa_minq_u32) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_uint32x4, v_max, msa_maxq_u32) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_int32x4, v_min, msa_minq_s32) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_int32x4, v_max, msa_maxq_s32) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_float32x4, v_min, msa_minq_f32) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_float32x4, v_max, msa_maxq_f32) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_float64x2, v_min, msa_minq_f64) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_float64x2, v_max, msa_maxq_f64) + +#define OPENCV_HAL_IMPL_MSA_INT_CMP_OP(_Tpvec, _Tpv, suffix, not_suffix) \ +inline _Tpvec operator == (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(MSA_TPV_REINTERPRET(_Tpv, msa_ceqq_##suffix(a.val, b.val))); } \ +inline _Tpvec operator != (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(MSA_TPV_REINTERPRET(_Tpv, msa_mvnq_##not_suffix(msa_ceqq_##suffix(a.val, b.val)))); } \ +inline _Tpvec operator < (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(MSA_TPV_REINTERPRET(_Tpv, msa_cltq_##suffix(a.val, b.val))); } \ +inline _Tpvec operator > (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(MSA_TPV_REINTERPRET(_Tpv, msa_cgtq_##suffix(a.val, b.val))); } \ +inline _Tpvec operator <= (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(MSA_TPV_REINTERPRET(_Tpv, msa_cleq_##suffix(a.val, b.val))); } \ +inline _Tpvec operator >= (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(MSA_TPV_REINTERPRET(_Tpv, msa_cgeq_##suffix(a.val, b.val))); } + +OPENCV_HAL_IMPL_MSA_INT_CMP_OP(v_uint8x16, v16u8, u8, u8) +OPENCV_HAL_IMPL_MSA_INT_CMP_OP(v_int8x16, v16i8, s8, u8) +OPENCV_HAL_IMPL_MSA_INT_CMP_OP(v_uint16x8, v8u16, u16, u16) +OPENCV_HAL_IMPL_MSA_INT_CMP_OP(v_int16x8, v8i16, s16, u16) +OPENCV_HAL_IMPL_MSA_INT_CMP_OP(v_uint32x4, v4u32, u32, u32) +OPENCV_HAL_IMPL_MSA_INT_CMP_OP(v_int32x4, v4i32, s32, u32) +OPENCV_HAL_IMPL_MSA_INT_CMP_OP(v_float32x4, v4f32, f32, u32) +OPENCV_HAL_IMPL_MSA_INT_CMP_OP(v_uint64x2, v2u64, u64, u64) +OPENCV_HAL_IMPL_MSA_INT_CMP_OP(v_int64x2, v2i64, s64, u64) +OPENCV_HAL_IMPL_MSA_INT_CMP_OP(v_float64x2, v2f64, f64, u64) + +inline v_float32x4 v_not_nan(const v_float32x4& a) +{ return v_float32x4(MSA_TPV_REINTERPRET(v4f32, msa_ceqq_f32(a.val, a.val))); } +inline v_float64x2 v_not_nan(const v_float64x2& a) +{ return v_float64x2(MSA_TPV_REINTERPRET(v2f64, msa_ceqq_f64(a.val, a.val))); } + +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_uint8x16, v_add_wrap, msa_addq_u8) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_int8x16, v_add_wrap, msa_addq_s8) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_uint16x8, v_add_wrap, msa_addq_u16) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_int16x8, v_add_wrap, msa_addq_s16) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_uint8x16, v_sub_wrap, msa_subq_u8) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_int8x16, v_sub_wrap, msa_subq_s8) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_uint16x8, v_sub_wrap, msa_subq_u16) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_int16x8, v_sub_wrap, msa_subq_s16) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_uint8x16, v_mul_wrap, msa_mulq_u8) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_int8x16, v_mul_wrap, msa_mulq_s8) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_uint16x8, v_mul_wrap, msa_mulq_u16) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_int16x8, v_mul_wrap, msa_mulq_s16) + +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_uint8x16, v_absdiff, msa_abdq_u8) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_uint16x8, v_absdiff, msa_abdq_u16) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_uint32x4, v_absdiff, msa_abdq_u32) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_float32x4, v_absdiff, msa_abdq_f32) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_float64x2, v_absdiff, msa_abdq_f64) + +/** Saturating absolute difference **/ +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_int8x16, v_absdiffs, msa_qabdq_s8) +OPENCV_HAL_IMPL_MSA_BIN_FUNC(v_int16x8, v_absdiffs, msa_qabdq_s16) + +#define OPENCV_HAL_IMPL_MSA_BIN_FUNC2(_Tpvec, _Tpvec2, _Tpv, func, intrin) \ +inline _Tpvec2 func(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec2(MSA_TPV_REINTERPRET(_Tpv, intrin(a.val, b.val))); \ +} + +OPENCV_HAL_IMPL_MSA_BIN_FUNC2(v_int8x16, v_uint8x16, v16u8, v_absdiff, msa_abdq_s8) +OPENCV_HAL_IMPL_MSA_BIN_FUNC2(v_int16x8, v_uint16x8, v8u16, v_absdiff, msa_abdq_s16) +OPENCV_HAL_IMPL_MSA_BIN_FUNC2(v_int32x4, v_uint32x4, v4u32, v_absdiff, msa_abdq_s32) + +/* v_magnitude, v_sqr_magnitude, v_fma, v_muladd */ +inline v_float32x4 v_magnitude(const v_float32x4& a, const v_float32x4& b) +{ + v_float32x4 x(msa_mlaq_f32(msa_mulq_f32(a.val, a.val), b.val, b.val)); + return v_sqrt(x); +} + +inline v_float32x4 v_sqr_magnitude(const v_float32x4& a, const v_float32x4& b) +{ + return v_float32x4(msa_mlaq_f32(msa_mulq_f32(a.val, a.val), b.val, b.val)); +} + +inline v_float32x4 v_fma(const v_float32x4& a, const v_float32x4& b, const v_float32x4& c) +{ + return v_float32x4(msa_mlaq_f32(c.val, a.val, b.val)); +} + +inline v_int32x4 v_fma(const v_int32x4& a, const v_int32x4& b, const v_int32x4& c) +{ + return v_int32x4(msa_mlaq_s32(c.val, a.val, b.val)); +} + +inline v_float32x4 v_muladd(const v_float32x4& a, const v_float32x4& b, const v_float32x4& c) +{ + return v_fma(a, b, c); +} + +inline v_int32x4 v_muladd(const v_int32x4& a, const v_int32x4& b, const v_int32x4& c) +{ + return v_fma(a, b, c); +} + +inline v_float64x2 v_magnitude(const v_float64x2& a, const v_float64x2& b) +{ + v_float64x2 x(msa_mlaq_f64(msa_mulq_f64(a.val, a.val), b.val, b.val)); + return v_sqrt(x); +} + +inline v_float64x2 v_sqr_magnitude(const v_float64x2& a, const v_float64x2& b) +{ + return v_float64x2(msa_mlaq_f64(msa_mulq_f64(a.val, a.val), b.val, b.val)); +} + +inline v_float64x2 v_fma(const v_float64x2& a, const v_float64x2& b, const v_float64x2& c) +{ + return v_float64x2(msa_mlaq_f64(c.val, a.val, b.val)); +} + +inline v_float64x2 v_muladd(const v_float64x2& a, const v_float64x2& b, const v_float64x2& c) +{ + return v_fma(a, b, c); +} + +// trade efficiency for convenience +#define OPENCV_HAL_IMPL_MSA_SHIFT_OP(_Tpvec, suffix, _Tps, ssuffix) \ +inline _Tpvec operator << (const _Tpvec& a, int n) \ +{ return _Tpvec(msa_shlq_##suffix(a.val, msa_dupq_n_##ssuffix((_Tps)n))); } \ +inline _Tpvec operator >> (const _Tpvec& a, int n) \ +{ return _Tpvec(msa_shrq_##suffix(a.val, msa_dupq_n_##ssuffix((_Tps)n))); } \ +template inline _Tpvec v_shl(const _Tpvec& a) \ +{ return _Tpvec(msa_shlq_n_##suffix(a.val, n)); } \ +template inline _Tpvec v_shr(const _Tpvec& a) \ +{ return _Tpvec(msa_shrq_n_##suffix(a.val, n)); } \ +template inline _Tpvec v_rshr(const _Tpvec& a) \ +{ return _Tpvec(msa_rshrq_n_##suffix(a.val, n)); } + +OPENCV_HAL_IMPL_MSA_SHIFT_OP(v_uint8x16, u8, schar, s8) +OPENCV_HAL_IMPL_MSA_SHIFT_OP(v_int8x16, s8, schar, s8) +OPENCV_HAL_IMPL_MSA_SHIFT_OP(v_uint16x8, u16, short, s16) +OPENCV_HAL_IMPL_MSA_SHIFT_OP(v_int16x8, s16, short, s16) +OPENCV_HAL_IMPL_MSA_SHIFT_OP(v_uint32x4, u32, int, s32) +OPENCV_HAL_IMPL_MSA_SHIFT_OP(v_int32x4, s32, int, s32) +OPENCV_HAL_IMPL_MSA_SHIFT_OP(v_uint64x2, u64, int64, s64) +OPENCV_HAL_IMPL_MSA_SHIFT_OP(v_int64x2, s64, int64, s64) + +/* v_rotate_right, v_rotate_left */ +#define OPENCV_HAL_IMPL_MSA_ROTATE_OP(_Tpvec, _Tpv, _Tpvs, suffix) \ +template inline _Tpvec v_rotate_right(const _Tpvec& a) \ +{ \ + return _Tpvec(MSA_TPV_REINTERPRET(_Tpv, msa_extq_##suffix(MSA_TPV_REINTERPRET(_Tpvs, a.val), msa_dupq_n_##suffix(0), n))); \ +} \ +template inline _Tpvec v_rotate_left(const _Tpvec& a) \ +{ \ + return _Tpvec(MSA_TPV_REINTERPRET(_Tpv, msa_extq_##suffix(msa_dupq_n_##suffix(0), MSA_TPV_REINTERPRET(_Tpvs, a.val), _Tpvec::nlanes - n))); \ +} \ +template<> inline _Tpvec v_rotate_left<0>(const _Tpvec& a) \ +{ \ + return a; \ +} \ +template inline _Tpvec v_rotate_right(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(MSA_TPV_REINTERPRET(_Tpv, msa_extq_##suffix(MSA_TPV_REINTERPRET(_Tpvs, a.val), MSA_TPV_REINTERPRET(_Tpvs, b.val), n))); \ +} \ +template inline _Tpvec v_rotate_left(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(MSA_TPV_REINTERPRET(_Tpv, msa_extq_##suffix(MSA_TPV_REINTERPRET(_Tpvs, b.val), MSA_TPV_REINTERPRET(_Tpvs, a.val), _Tpvec::nlanes - n))); \ +} \ +template<> inline _Tpvec v_rotate_left<0>(const _Tpvec& a, const _Tpvec& b) \ +{ \ + CV_UNUSED(b); \ + return a; \ +} + +OPENCV_HAL_IMPL_MSA_ROTATE_OP(v_uint8x16, v16u8, v16i8, s8) +OPENCV_HAL_IMPL_MSA_ROTATE_OP(v_int8x16, v16i8, v16i8, s8) +OPENCV_HAL_IMPL_MSA_ROTATE_OP(v_uint16x8, v8u16, v8i16, s16) +OPENCV_HAL_IMPL_MSA_ROTATE_OP(v_int16x8, v8i16, v8i16, s16) +OPENCV_HAL_IMPL_MSA_ROTATE_OP(v_uint32x4, v4u32, v4i32, s32) +OPENCV_HAL_IMPL_MSA_ROTATE_OP(v_int32x4, v4i32, v4i32, s32) +OPENCV_HAL_IMPL_MSA_ROTATE_OP(v_float32x4, v4f32, v4i32, s32) +OPENCV_HAL_IMPL_MSA_ROTATE_OP(v_uint64x2, v2u64, v2i64, s64) +OPENCV_HAL_IMPL_MSA_ROTATE_OP(v_int64x2, v2i64, v2i64, s64) +OPENCV_HAL_IMPL_MSA_ROTATE_OP(v_float64x2, v2f64, v2i64, s64) + +#define OPENCV_HAL_IMPL_MSA_LOADSTORE_OP(_Tpvec, _Tp, suffix) \ +inline _Tpvec v_load(const _Tp* ptr) \ +{ return _Tpvec(msa_ld1q_##suffix(ptr)); } \ +inline _Tpvec v_load_aligned(const _Tp* ptr) \ +{ return _Tpvec(msa_ld1q_##suffix(ptr)); } \ +inline _Tpvec v_load_low(const _Tp* ptr) \ +{ return _Tpvec(msa_combine_##suffix(msa_ld1_##suffix(ptr), msa_dup_n_##suffix((_Tp)0))); } \ +inline _Tpvec v_load_halves(const _Tp* ptr0, const _Tp* ptr1) \ +{ return _Tpvec(msa_combine_##suffix(msa_ld1_##suffix(ptr0), msa_ld1_##suffix(ptr1))); } \ +inline void v_store(_Tp* ptr, const _Tpvec& a) \ +{ msa_st1q_##suffix(ptr, a.val); } \ +inline void v_store_aligned(_Tp* ptr, const _Tpvec& a) \ +{ msa_st1q_##suffix(ptr, a.val); } \ +inline void v_store_aligned_nocache(_Tp* ptr, const _Tpvec& a) \ +{ msa_st1q_##suffix(ptr, a.val); } \ +inline void v_store(_Tp* ptr, const _Tpvec& a, hal::StoreMode /*mode*/) \ +{ msa_st1q_##suffix(ptr, a.val); } \ +inline void v_store_low(_Tp* ptr, const _Tpvec& a) \ +{ \ + int n = _Tpvec::nlanes; \ + for( int i = 0; i < (n/2); i++ ) \ + ptr[i] = a.val[i]; \ +} \ +inline void v_store_high(_Tp* ptr, const _Tpvec& a) \ +{ \ + int n = _Tpvec::nlanes; \ + for( int i = 0; i < (n/2); i++ ) \ + ptr[i] = a.val[i+(n/2)]; \ +} + +OPENCV_HAL_IMPL_MSA_LOADSTORE_OP(v_uint8x16, uchar, u8) +OPENCV_HAL_IMPL_MSA_LOADSTORE_OP(v_int8x16, schar, s8) +OPENCV_HAL_IMPL_MSA_LOADSTORE_OP(v_uint16x8, ushort, u16) +OPENCV_HAL_IMPL_MSA_LOADSTORE_OP(v_int16x8, short, s16) +OPENCV_HAL_IMPL_MSA_LOADSTORE_OP(v_uint32x4, unsigned, u32) +OPENCV_HAL_IMPL_MSA_LOADSTORE_OP(v_int32x4, int, s32) +OPENCV_HAL_IMPL_MSA_LOADSTORE_OP(v_uint64x2, uint64, u64) +OPENCV_HAL_IMPL_MSA_LOADSTORE_OP(v_int64x2, int64, s64) +OPENCV_HAL_IMPL_MSA_LOADSTORE_OP(v_float32x4, float, f32) +OPENCV_HAL_IMPL_MSA_LOADSTORE_OP(v_float64x2, double, f64) + + +/** Reverse **/ +inline v_uint8x16 v_reverse(const v_uint8x16 &a) +{ + v_uint8x16 c = v_uint8x16((v16u8)__builtin_msa_vshf_b((v16i8)((v2i64){0x08090A0B0C0D0E0F, 0x0001020304050607}), msa_dupq_n_s8(0), (v16i8)a.val)); + return c; +} + +inline v_int8x16 v_reverse(const v_int8x16 &a) +{ return v_reinterpret_as_s8(v_reverse(v_reinterpret_as_u8(a))); } + +inline v_uint16x8 v_reverse(const v_uint16x8 &a) +{ + v_uint16x8 c = v_uint16x8((v8u16)__builtin_msa_vshf_h((v8i16)((v2i64){0x0004000500060007, 0x0000000100020003}), msa_dupq_n_s16(0), (v8i16)a.val)); + return c; +} + +inline v_int16x8 v_reverse(const v_int16x8 &a) +{ return v_reinterpret_as_s16(v_reverse(v_reinterpret_as_u16(a))); } + +inline v_uint32x4 v_reverse(const v_uint32x4 &a) +{ + v_uint32x4 c; + c.val[0] = a.val[3]; + c.val[1] = a.val[2]; + c.val[2] = a.val[1]; + c.val[3] = a.val[0]; + return c; +} + +inline v_int32x4 v_reverse(const v_int32x4 &a) +{ return v_reinterpret_as_s32(v_reverse(v_reinterpret_as_u32(a))); } + +inline v_float32x4 v_reverse(const v_float32x4 &a) +{ return v_reinterpret_as_f32(v_reverse(v_reinterpret_as_u32(a))); } + +inline v_uint64x2 v_reverse(const v_uint64x2 &a) +{ + v_uint64x2 c; + c.val[0] = a.val[1]; + c.val[1] = a.val[0]; + return c; +} + +inline v_int64x2 v_reverse(const v_int64x2 &a) +{ return v_reinterpret_as_s64(v_reverse(v_reinterpret_as_u64(a))); } + +inline v_float64x2 v_reverse(const v_float64x2 &a) +{ return v_reinterpret_as_f64(v_reverse(v_reinterpret_as_u64(a))); } + + +#define OPENCV_HAL_IMPL_MSA_REDUCE_OP_8U(func, cfunc) \ +inline unsigned short v_reduce_##func(const v_uint16x8& a) \ +{ \ + v8u16 a_lo, a_hi; \ + ILVRL_H2_UH(a.val, msa_dupq_n_u16(0), a_lo, a_hi); \ + v4u32 b = msa_##func##q_u32(msa_paddlq_u16(a_lo), msa_paddlq_u16(a_hi)); \ + v4u32 b_lo, b_hi; \ + ILVRL_W2_UW(b, msa_dupq_n_u32(0), b_lo, b_hi); \ + v2u64 c = msa_##func##q_u64(msa_paddlq_u32(b_lo), msa_paddlq_u32(b_hi)); \ + return (unsigned short)cfunc(c[0], c[1]); \ +} + +OPENCV_HAL_IMPL_MSA_REDUCE_OP_8U(max, std::max) +OPENCV_HAL_IMPL_MSA_REDUCE_OP_8U(min, std::min) + +#define OPENCV_HAL_IMPL_MSA_REDUCE_OP_8S(func, cfunc) \ +inline short v_reduce_##func(const v_int16x8& a) \ +{ \ + v8i16 a_lo, a_hi; \ + ILVRL_H2_SH(a.val, msa_dupq_n_s16(0), a_lo, a_hi); \ + v4i32 b = msa_##func##q_s32(msa_paddlq_s16(a_lo), msa_paddlq_s16(a_hi)); \ + v4i32 b_lo, b_hi; \ + ILVRL_W2_SW(b, msa_dupq_n_s32(0), b_lo, b_hi); \ + v2i64 c = msa_##func##q_s64(msa_paddlq_s32(b_lo), msa_paddlq_s32(b_hi)); \ + return (short)cfunc(c[0], c[1]); \ +} + +OPENCV_HAL_IMPL_MSA_REDUCE_OP_8S(max, std::max) +OPENCV_HAL_IMPL_MSA_REDUCE_OP_8S(min, std::min) + +#define OPENCV_HAL_IMPL_MSA_REDUCE_OP_4(_Tpvec, scalartype, func, cfunc) \ +inline scalartype v_reduce_##func(const _Tpvec& a) \ +{ \ + return (scalartype)cfunc(cfunc(a.val[0], a.val[1]), cfunc(a.val[2], a.val[3])); \ +} + +OPENCV_HAL_IMPL_MSA_REDUCE_OP_4(v_uint32x4, unsigned, max, std::max) +OPENCV_HAL_IMPL_MSA_REDUCE_OP_4(v_uint32x4, unsigned, min, std::min) +OPENCV_HAL_IMPL_MSA_REDUCE_OP_4(v_int32x4, int, max, std::max) +OPENCV_HAL_IMPL_MSA_REDUCE_OP_4(v_int32x4, int, min, std::min) +OPENCV_HAL_IMPL_MSA_REDUCE_OP_4(v_float32x4, float, max, std::max) +OPENCV_HAL_IMPL_MSA_REDUCE_OP_4(v_float32x4, float, min, std::min) + + +#define OPENCV_HAL_IMPL_MSA_REDUCE_OP_16(_Tpvec, scalartype, _Tpvec2, func) \ +inline scalartype v_reduce_##func(const _Tpvec& a) \ +{ \ + _Tpvec2 a1, a2; \ + v_expand(a, a1, a2); \ + return (scalartype)v_reduce_##func(v_##func(a1, a2)); \ +} + +OPENCV_HAL_IMPL_MSA_REDUCE_OP_16(v_uint8x16, uchar, v_uint16x8, min) +OPENCV_HAL_IMPL_MSA_REDUCE_OP_16(v_uint8x16, uchar, v_uint16x8, max) +OPENCV_HAL_IMPL_MSA_REDUCE_OP_16(v_int8x16, char, v_int16x8, min) +OPENCV_HAL_IMPL_MSA_REDUCE_OP_16(v_int8x16, char, v_int16x8, max) + + + +#define OPENCV_HAL_IMPL_MSA_REDUCE_SUM(_Tpvec, scalartype, suffix) \ +inline scalartype v_reduce_sum(const _Tpvec& a) \ +{ \ + return (scalartype)msa_sum_##suffix(a.val); \ +} + +OPENCV_HAL_IMPL_MSA_REDUCE_SUM(v_uint8x16, unsigned short, u8) +OPENCV_HAL_IMPL_MSA_REDUCE_SUM(v_int8x16, short, s8) +OPENCV_HAL_IMPL_MSA_REDUCE_SUM(v_uint16x8, unsigned, u16) +OPENCV_HAL_IMPL_MSA_REDUCE_SUM(v_int16x8, int, s16) +OPENCV_HAL_IMPL_MSA_REDUCE_SUM(v_uint32x4, uint64_t, u32) +OPENCV_HAL_IMPL_MSA_REDUCE_SUM(v_int32x4, int64_t, s32) +OPENCV_HAL_IMPL_MSA_REDUCE_SUM(v_float32x4, float, f32) + +inline uint64 v_reduce_sum(const v_uint64x2& a) +{ return (uint64)(msa_getq_lane_u64(a.val, 0) + msa_getq_lane_u64(a.val, 1)); } +inline int64 v_reduce_sum(const v_int64x2& a) +{ return (int64)(msa_getq_lane_s64(a.val, 0) + msa_getq_lane_s64(a.val, 1)); } +inline double v_reduce_sum(const v_float64x2& a) +{ + return msa_getq_lane_f64(a.val, 0) + msa_getq_lane_f64(a.val, 1); +} + +/* v_reduce_sum4, v_reduce_sad */ +inline v_float32x4 v_reduce_sum4(const v_float32x4& a, const v_float32x4& b, + const v_float32x4& c, const v_float32x4& d) +{ + v4f32 u0 = msa_addq_f32(MSA_TPV_REINTERPRET(v4f32, msa_ilvevq_s32(MSA_TPV_REINTERPRET(v4i32, b.val), MSA_TPV_REINTERPRET(v4i32, a.val))), + MSA_TPV_REINTERPRET(v4f32, msa_ilvodq_s32(MSA_TPV_REINTERPRET(v4i32, b.val), MSA_TPV_REINTERPRET(v4i32, a.val)))); // a0+a1 b0+b1 a2+a3 b2+b3 + v4f32 u1 = msa_addq_f32(MSA_TPV_REINTERPRET(v4f32, msa_ilvevq_s32(MSA_TPV_REINTERPRET(v4i32, d.val), MSA_TPV_REINTERPRET(v4i32, c.val))), + MSA_TPV_REINTERPRET(v4f32, msa_ilvodq_s32(MSA_TPV_REINTERPRET(v4i32, d.val), MSA_TPV_REINTERPRET(v4i32, c.val)))); // c0+c1 d0+d1 c2+c3 d2+d3 + + return v_float32x4(msa_addq_f32(MSA_TPV_REINTERPRET(v4f32, msa_ilvrq_s64(MSA_TPV_REINTERPRET(v2i64, u1), MSA_TPV_REINTERPRET(v2i64, u0))), + MSA_TPV_REINTERPRET(v4f32, msa_ilvlq_s64(MSA_TPV_REINTERPRET(v2i64, u1), MSA_TPV_REINTERPRET(v2i64, u0))))); +} + +inline unsigned v_reduce_sad(const v_uint8x16& a, const v_uint8x16& b) +{ + v16u8 t0 = msa_abdq_u8(a.val, b.val); + v8u16 t1 = msa_paddlq_u8(t0); + v4u32 t2 = msa_paddlq_u16(t1); + return msa_sum_u32(t2); +} +inline unsigned v_reduce_sad(const v_int8x16& a, const v_int8x16& b) +{ + v16u8 t0 = MSA_TPV_REINTERPRET(v16u8, msa_abdq_s8(a.val, b.val)); + v8u16 t1 = msa_paddlq_u8(t0); + v4u32 t2 = msa_paddlq_u16(t1); + return msa_sum_u32(t2); +} +inline unsigned v_reduce_sad(const v_uint16x8& a, const v_uint16x8& b) +{ + v8u16 t0 = msa_abdq_u16(a.val, b.val); + v4u32 t1 = msa_paddlq_u16(t0); + return msa_sum_u32(t1); +} +inline unsigned v_reduce_sad(const v_int16x8& a, const v_int16x8& b) +{ + v8u16 t0 = MSA_TPV_REINTERPRET(v8u16, msa_abdq_s16(a.val, b.val)); + v4u32 t1 = msa_paddlq_u16(t0); + return msa_sum_u32(t1); +} +inline unsigned v_reduce_sad(const v_uint32x4& a, const v_uint32x4& b) +{ + v4u32 t0 = msa_abdq_u32(a.val, b.val); + return msa_sum_u32(t0); +} +inline unsigned v_reduce_sad(const v_int32x4& a, const v_int32x4& b) +{ + v4u32 t0 = MSA_TPV_REINTERPRET(v4u32, msa_abdq_s32(a.val, b.val)); + return msa_sum_u32(t0); +} +inline float v_reduce_sad(const v_float32x4& a, const v_float32x4& b) +{ + v4f32 t0 = msa_abdq_f32(a.val, b.val); + return msa_sum_f32(t0); +} + +/* v_popcount */ +#define OPENCV_HAL_IMPL_MSA_POPCOUNT_SIZE8(_Tpvec) \ +inline v_uint8x16 v_popcount(const _Tpvec& a) \ +{ \ + v16u8 t = MSA_TPV_REINTERPRET(v16u8, msa_cntq_s8(MSA_TPV_REINTERPRET(v16i8, a.val))); \ + return v_uint8x16(t); \ +} +OPENCV_HAL_IMPL_MSA_POPCOUNT_SIZE8(v_uint8x16) +OPENCV_HAL_IMPL_MSA_POPCOUNT_SIZE8(v_int8x16) + +#define OPENCV_HAL_IMPL_MSA_POPCOUNT_SIZE16(_Tpvec) \ +inline v_uint16x8 v_popcount(const _Tpvec& a) \ +{ \ + v8u16 t = MSA_TPV_REINTERPRET(v8u16, msa_cntq_s16(MSA_TPV_REINTERPRET(v8i16, a.val))); \ + return v_uint16x8(t); \ +} +OPENCV_HAL_IMPL_MSA_POPCOUNT_SIZE16(v_uint16x8) +OPENCV_HAL_IMPL_MSA_POPCOUNT_SIZE16(v_int16x8) + +#define OPENCV_HAL_IMPL_MSA_POPCOUNT_SIZE32(_Tpvec) \ +inline v_uint32x4 v_popcount(const _Tpvec& a) \ +{ \ + v4u32 t = MSA_TPV_REINTERPRET(v4u32, msa_cntq_s32(MSA_TPV_REINTERPRET(v4i32, a.val))); \ + return v_uint32x4(t); \ +} +OPENCV_HAL_IMPL_MSA_POPCOUNT_SIZE32(v_uint32x4) +OPENCV_HAL_IMPL_MSA_POPCOUNT_SIZE32(v_int32x4) + +#define OPENCV_HAL_IMPL_MSA_POPCOUNT_SIZE64(_Tpvec) \ +inline v_uint64x2 v_popcount(const _Tpvec& a) \ +{ \ + v2u64 t = MSA_TPV_REINTERPRET(v2u64, msa_cntq_s64(MSA_TPV_REINTERPRET(v2i64, a.val))); \ + return v_uint64x2(t); \ +} +OPENCV_HAL_IMPL_MSA_POPCOUNT_SIZE64(v_uint64x2) +OPENCV_HAL_IMPL_MSA_POPCOUNT_SIZE64(v_int64x2) + +inline int v_signmask(const v_uint8x16& a) +{ + v8i8 m0 = msa_create_s8(CV_BIG_UINT(0x0706050403020100)); + v16u8 v0 = msa_shlq_u8(msa_shrq_n_u8(a.val, 7), msa_combine_s8(m0, m0)); + v8u16 v1 = msa_paddlq_u8(v0); + v4u32 v2 = msa_paddlq_u16(v1); + v2u64 v3 = msa_paddlq_u32(v2); + return (int)msa_getq_lane_u64(v3, 0) + ((int)msa_getq_lane_u64(v3, 1) << 8); +} +inline int v_signmask(const v_int8x16& a) +{ return v_signmask(v_reinterpret_as_u8(a)); } + +inline int v_signmask(const v_uint16x8& a) +{ + v4i16 m0 = msa_create_s16(CV_BIG_UINT(0x0003000200010000)); + v8u16 v0 = msa_shlq_u16(msa_shrq_n_u16(a.val, 15), msa_combine_s16(m0, m0)); + v4u32 v1 = msa_paddlq_u16(v0); + v2u64 v2 = msa_paddlq_u32(v1); + return (int)msa_getq_lane_u64(v2, 0) + ((int)msa_getq_lane_u64(v2, 1) << 4); +} +inline int v_signmask(const v_int16x8& a) +{ return v_signmask(v_reinterpret_as_u16(a)); } + +inline int v_signmask(const v_uint32x4& a) +{ + v2i32 m0 = msa_create_s32(CV_BIG_UINT(0x0000000100000000)); + v4u32 v0 = msa_shlq_u32(msa_shrq_n_u32(a.val, 31), msa_combine_s32(m0, m0)); + v2u64 v1 = msa_paddlq_u32(v0); + return (int)msa_getq_lane_u64(v1, 0) + ((int)msa_getq_lane_u64(v1, 1) << 2); +} +inline int v_signmask(const v_int32x4& a) +{ return v_signmask(v_reinterpret_as_u32(a)); } +inline int v_signmask(const v_float32x4& a) +{ return v_signmask(v_reinterpret_as_u32(a)); } + +inline int v_signmask(const v_uint64x2& a) +{ + v2u64 v0 = msa_shrq_n_u64(a.val, 63); + return (int)msa_getq_lane_u64(v0, 0) + ((int)msa_getq_lane_u64(v0, 1) << 1); +} +inline int v_signmask(const v_int64x2& a) +{ return v_signmask(v_reinterpret_as_u64(a)); } +inline int v_signmask(const v_float64x2& a) +{ return v_signmask(v_reinterpret_as_u64(a)); } + +inline int v_scan_forward(const v_int8x16& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_uint8x16& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_int16x8& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_uint16x8& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_int32x4& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_uint32x4& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_float32x4& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_int64x2& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_uint64x2& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_float64x2& a) { return trailingZeros32(v_signmask(a)); } + +#define OPENCV_HAL_IMPL_MSA_CHECK_ALLANY(_Tpvec, _Tpvec2, suffix, shift) \ +inline bool v_check_all(const v_##_Tpvec& a) \ +{ \ + _Tpvec2 v0 = msa_shrq_n_##suffix(msa_mvnq_##suffix(a.val), shift); \ + v2u64 v1 = MSA_TPV_REINTERPRET(v2u64, v0); \ + return (msa_getq_lane_u64(v1, 0) | msa_getq_lane_u64(v1, 1)) == 0; \ +} \ +inline bool v_check_any(const v_##_Tpvec& a) \ +{ \ + _Tpvec2 v0 = msa_shrq_n_##suffix(a.val, shift); \ + v2u64 v1 = MSA_TPV_REINTERPRET(v2u64, v0); \ + return (msa_getq_lane_u64(v1, 0) | msa_getq_lane_u64(v1, 1)) != 0; \ +} + +OPENCV_HAL_IMPL_MSA_CHECK_ALLANY(uint8x16, v16u8, u8, 7) +OPENCV_HAL_IMPL_MSA_CHECK_ALLANY(uint16x8, v8u16, u16, 15) +OPENCV_HAL_IMPL_MSA_CHECK_ALLANY(uint32x4, v4u32, u32, 31) +OPENCV_HAL_IMPL_MSA_CHECK_ALLANY(uint64x2, v2u64, u64, 63) + +inline bool v_check_all(const v_int8x16& a) +{ return v_check_all(v_reinterpret_as_u8(a)); } +inline bool v_check_all(const v_int16x8& a) +{ return v_check_all(v_reinterpret_as_u16(a)); } +inline bool v_check_all(const v_int32x4& a) +{ return v_check_all(v_reinterpret_as_u32(a)); } +inline bool v_check_all(const v_float32x4& a) +{ return v_check_all(v_reinterpret_as_u32(a)); } + +inline bool v_check_any(const v_int8x16& a) +{ return v_check_any(v_reinterpret_as_u8(a)); } +inline bool v_check_any(const v_int16x8& a) +{ return v_check_any(v_reinterpret_as_u16(a)); } +inline bool v_check_any(const v_int32x4& a) +{ return v_check_any(v_reinterpret_as_u32(a)); } +inline bool v_check_any(const v_float32x4& a) +{ return v_check_any(v_reinterpret_as_u32(a)); } + +inline bool v_check_all(const v_int64x2& a) +{ return v_check_all(v_reinterpret_as_u64(a)); } +inline bool v_check_all(const v_float64x2& a) +{ return v_check_all(v_reinterpret_as_u64(a)); } +inline bool v_check_any(const v_int64x2& a) +{ return v_check_any(v_reinterpret_as_u64(a)); } +inline bool v_check_any(const v_float64x2& a) +{ return v_check_any(v_reinterpret_as_u64(a)); } + +/* v_select */ +#define OPENCV_HAL_IMPL_MSA_SELECT(_Tpvec, _Tpv, _Tpvu) \ +inline _Tpvec v_select(const _Tpvec& mask, const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(MSA_TPV_REINTERPRET(_Tpv, msa_bslq_u8(MSA_TPV_REINTERPRET(_Tpvu, mask.val), \ + MSA_TPV_REINTERPRET(_Tpvu, b.val), MSA_TPV_REINTERPRET(_Tpvu, a.val)))); \ +} + +OPENCV_HAL_IMPL_MSA_SELECT(v_uint8x16, v16u8, v16u8) +OPENCV_HAL_IMPL_MSA_SELECT(v_int8x16, v16i8, v16u8) +OPENCV_HAL_IMPL_MSA_SELECT(v_uint16x8, v8u16, v16u8) +OPENCV_HAL_IMPL_MSA_SELECT(v_int16x8, v8i16, v16u8) +OPENCV_HAL_IMPL_MSA_SELECT(v_uint32x4, v4u32, v16u8) +OPENCV_HAL_IMPL_MSA_SELECT(v_int32x4, v4i32, v16u8) +OPENCV_HAL_IMPL_MSA_SELECT(v_float32x4, v4f32, v16u8) +OPENCV_HAL_IMPL_MSA_SELECT(v_float64x2, v2f64, v16u8) + +#define OPENCV_HAL_IMPL_MSA_EXPAND(_Tpvec, _Tpwvec, _Tp, suffix, ssuffix, _Tpv, _Tpvs) \ +inline void v_expand(const _Tpvec& a, _Tpwvec& b0, _Tpwvec& b1) \ +{ \ + _Tpv a_lo = MSA_TPV_REINTERPRET(_Tpv, msa_ilvrq_##ssuffix(MSA_TPV_REINTERPRET(_Tpvs, a.val), msa_dupq_n_##ssuffix(0))); \ + _Tpv a_hi = MSA_TPV_REINTERPRET(_Tpv, msa_ilvlq_##ssuffix(MSA_TPV_REINTERPRET(_Tpvs, a.val), msa_dupq_n_##ssuffix(0))); \ + b0.val = msa_paddlq_##suffix(a_lo); \ + b1.val = msa_paddlq_##suffix(a_hi); \ +} \ +inline _Tpwvec v_expand_low(const _Tpvec& a) \ +{ \ + _Tpv a_lo = MSA_TPV_REINTERPRET(_Tpv, msa_ilvrq_##ssuffix(MSA_TPV_REINTERPRET(_Tpvs, a.val), msa_dupq_n_##ssuffix(0))); \ + return _Tpwvec(msa_paddlq_##suffix(a_lo)); \ +} \ +inline _Tpwvec v_expand_high(const _Tpvec& a) \ +{ \ + _Tpv a_hi = MSA_TPV_REINTERPRET(_Tpv, msa_ilvlq_##ssuffix(MSA_TPV_REINTERPRET(_Tpvs, a.val), msa_dupq_n_##ssuffix(0))); \ + return _Tpwvec(msa_paddlq_##suffix(a_hi)); \ +} \ +inline _Tpwvec v_load_expand(const _Tp* ptr) \ +{ \ + return _Tpwvec(msa_movl_##suffix(msa_ld1_##suffix(ptr))); \ +} + +OPENCV_HAL_IMPL_MSA_EXPAND(v_uint8x16, v_uint16x8, uchar, u8, s8, v16u8, v16i8) +OPENCV_HAL_IMPL_MSA_EXPAND(v_int8x16, v_int16x8, schar, s8, s8, v16i8, v16i8) +OPENCV_HAL_IMPL_MSA_EXPAND(v_uint16x8, v_uint32x4, ushort, u16, s16, v8u16, v8i16) +OPENCV_HAL_IMPL_MSA_EXPAND(v_int16x8, v_int32x4, short, s16, s16, v8i16, v8i16) +OPENCV_HAL_IMPL_MSA_EXPAND(v_uint32x4, v_uint64x2, uint, u32, s32, v4u32, v4i32) +OPENCV_HAL_IMPL_MSA_EXPAND(v_int32x4, v_int64x2, int, s32, s32, v4i32, v4i32) + +inline v_uint32x4 v_load_expand_q(const uchar* ptr) +{ + return v_uint32x4((v4u32){ptr[0], ptr[1], ptr[2], ptr[3]}); +} + +inline v_int32x4 v_load_expand_q(const schar* ptr) +{ + return v_int32x4((v4i32){ptr[0], ptr[1], ptr[2], ptr[3]}); +} + +/* v_zip, v_combine_low, v_combine_high, v_recombine */ +#define OPENCV_HAL_IMPL_MSA_UNPACKS(_Tpvec, _Tpv, _Tpvs, ssuffix) \ +inline void v_zip(const _Tpvec& a0, const _Tpvec& a1, _Tpvec& b0, _Tpvec& b1) \ +{ \ + b0.val = MSA_TPV_REINTERPRET(_Tpv, msa_ilvrq_##ssuffix(MSA_TPV_REINTERPRET(_Tpvs, a1.val), MSA_TPV_REINTERPRET(_Tpvs, a0.val))); \ + b1.val = MSA_TPV_REINTERPRET(_Tpv, msa_ilvlq_##ssuffix(MSA_TPV_REINTERPRET(_Tpvs, a1.val), MSA_TPV_REINTERPRET(_Tpvs, a0.val))); \ +} \ +inline _Tpvec v_combine_low(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(MSA_TPV_REINTERPRET(_Tpv, msa_ilvrq_s64(MSA_TPV_REINTERPRET(v2i64, b.val), MSA_TPV_REINTERPRET(v2i64, a.val)))); \ +} \ +inline _Tpvec v_combine_high(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(MSA_TPV_REINTERPRET(_Tpv, msa_ilvlq_s64(MSA_TPV_REINTERPRET(v2i64, b.val), MSA_TPV_REINTERPRET(v2i64, a.val)))); \ +} \ +inline void v_recombine(const _Tpvec& a, const _Tpvec& b, _Tpvec& c, _Tpvec& d) \ +{ \ + c.val = MSA_TPV_REINTERPRET(_Tpv, msa_ilvrq_s64(MSA_TPV_REINTERPRET(v2i64, b.val), MSA_TPV_REINTERPRET(v2i64, a.val))); \ + d.val = MSA_TPV_REINTERPRET(_Tpv, msa_ilvlq_s64(MSA_TPV_REINTERPRET(v2i64, b.val), MSA_TPV_REINTERPRET(v2i64, a.val))); \ +} + +OPENCV_HAL_IMPL_MSA_UNPACKS(v_uint8x16, v16u8, v16i8, s8) +OPENCV_HAL_IMPL_MSA_UNPACKS(v_int8x16, v16i8, v16i8, s8) +OPENCV_HAL_IMPL_MSA_UNPACKS(v_uint16x8, v8u16, v8i16, s16) +OPENCV_HAL_IMPL_MSA_UNPACKS(v_int16x8, v8i16, v8i16, s16) +OPENCV_HAL_IMPL_MSA_UNPACKS(v_uint32x4, v4u32, v4i32, s32) +OPENCV_HAL_IMPL_MSA_UNPACKS(v_int32x4, v4i32, v4i32, s32) +OPENCV_HAL_IMPL_MSA_UNPACKS(v_float32x4, v4f32, v4i32, s32) +OPENCV_HAL_IMPL_MSA_UNPACKS(v_float64x2, v2f64, v2i64, s64) + +/* v_extract */ +#define OPENCV_HAL_IMPL_MSA_EXTRACT(_Tpvec, _Tpv, _Tpvs, suffix) \ +template \ +inline _Tpvec v_extract(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(MSA_TPV_REINTERPRET(_Tpv, msa_extq_##suffix(MSA_TPV_REINTERPRET(_Tpvs, a.val), MSA_TPV_REINTERPRET(_Tpvs, b.val), s))); \ +} + +OPENCV_HAL_IMPL_MSA_EXTRACT(v_uint8x16, v16u8, v16i8, s8) +OPENCV_HAL_IMPL_MSA_EXTRACT(v_int8x16, v16i8, v16i8, s8) +OPENCV_HAL_IMPL_MSA_EXTRACT(v_uint16x8, v8u16, v8i16, s16) +OPENCV_HAL_IMPL_MSA_EXTRACT(v_int16x8, v8i16, v8i16, s16) +OPENCV_HAL_IMPL_MSA_EXTRACT(v_uint32x4, v4u32, v4i32, s32) +OPENCV_HAL_IMPL_MSA_EXTRACT(v_int32x4, v4i32, v4i32, s32) +OPENCV_HAL_IMPL_MSA_EXTRACT(v_uint64x2, v2u64, v2i64, s64) +OPENCV_HAL_IMPL_MSA_EXTRACT(v_int64x2, v2i64, v2i64, s64) +OPENCV_HAL_IMPL_MSA_EXTRACT(v_float32x4, v4f32, v4i32, s32) +OPENCV_HAL_IMPL_MSA_EXTRACT(v_float64x2, v2f64, v2i64, s64) + +/* v_round, v_floor, v_ceil, v_trunc */ +inline v_int32x4 v_round(const v_float32x4& a) +{ + return v_int32x4(msa_cvttintq_s32_f32(a.val)); +} + +inline v_int32x4 v_floor(const v_float32x4& a) +{ + v4i32 a1 = msa_cvttintq_s32_f32(a.val); + return v_int32x4(msa_addq_s32(a1, MSA_TPV_REINTERPRET(v4i32, msa_cgtq_f32(msa_cvtfintq_f32_s32(a1), a.val)))); +} + +inline v_int32x4 v_ceil(const v_float32x4& a) +{ + v4i32 a1 = msa_cvttintq_s32_f32(a.val); + return v_int32x4(msa_subq_s32(a1, MSA_TPV_REINTERPRET(v4i32, msa_cgtq_f32(a.val, msa_cvtfintq_f32_s32(a1))))); +} + +inline v_int32x4 v_trunc(const v_float32x4& a) +{ + return v_int32x4(msa_cvttruncq_s32_f32(a.val)); +} + +inline v_int32x4 v_round(const v_float64x2& a) +{ + return v_int32x4(msa_pack_s64(msa_cvttintq_s64_f64(a.val), msa_dupq_n_s64(0))); +} + +inline v_int32x4 v_round(const v_float64x2& a, const v_float64x2& b) +{ + return v_int32x4(msa_pack_s64(msa_cvttintq_s64_f64(a.val), msa_cvttintq_s64_f64(b.val))); +} + +inline v_int32x4 v_floor(const v_float64x2& a) +{ + v2f64 a1 = msa_cvtrintq_f64(a.val); + return v_int32x4(msa_pack_s64(msa_addq_s64(msa_cvttruncq_s64_f64(a1), MSA_TPV_REINTERPRET(v2i64, msa_cgtq_f64(a1, a.val))), msa_dupq_n_s64(0))); +} + +inline v_int32x4 v_ceil(const v_float64x2& a) +{ + v2f64 a1 = msa_cvtrintq_f64(a.val); + return v_int32x4(msa_pack_s64(msa_subq_s64(msa_cvttruncq_s64_f64(a1), MSA_TPV_REINTERPRET(v2i64, msa_cgtq_f64(a.val, a1))), msa_dupq_n_s64(0))); +} + +inline v_int32x4 v_trunc(const v_float64x2& a) +{ + return v_int32x4(msa_pack_s64(msa_cvttruncq_s64_f64(a.val), msa_dupq_n_s64(0))); +} + +#define OPENCV_HAL_IMPL_MSA_TRANSPOSE4x4(_Tpvec, _Tpv, _Tpvs, ssuffix) \ +inline void v_transpose4x4(const _Tpvec& a0, const _Tpvec& a1, \ + const _Tpvec& a2, const _Tpvec& a3, \ + _Tpvec& b0, _Tpvec& b1, \ + _Tpvec& b2, _Tpvec& b3) \ +{ \ + _Tpv t00 = MSA_TPV_REINTERPRET(_Tpv, msa_ilvrq_##ssuffix(MSA_TPV_REINTERPRET(_Tpvs, a1.val), MSA_TPV_REINTERPRET(_Tpvs, a0.val))); \ + _Tpv t01 = MSA_TPV_REINTERPRET(_Tpv, msa_ilvlq_##ssuffix(MSA_TPV_REINTERPRET(_Tpvs, a1.val), MSA_TPV_REINTERPRET(_Tpvs, a0.val))); \ + _Tpv t10 = MSA_TPV_REINTERPRET(_Tpv, msa_ilvrq_##ssuffix(MSA_TPV_REINTERPRET(_Tpvs, a3.val), MSA_TPV_REINTERPRET(_Tpvs, a2.val))); \ + _Tpv t11 = MSA_TPV_REINTERPRET(_Tpv, msa_ilvlq_##ssuffix(MSA_TPV_REINTERPRET(_Tpvs, a3.val), MSA_TPV_REINTERPRET(_Tpvs, a2.val))); \ + b0.val = MSA_TPV_REINTERPRET(_Tpv, msa_ilvrq_s64(MSA_TPV_REINTERPRET(v2i64, t10), MSA_TPV_REINTERPRET(v2i64, t00))); \ + b1.val = MSA_TPV_REINTERPRET(_Tpv, msa_ilvlq_s64(MSA_TPV_REINTERPRET(v2i64, t10), MSA_TPV_REINTERPRET(v2i64, t00))); \ + b2.val = MSA_TPV_REINTERPRET(_Tpv, msa_ilvrq_s64(MSA_TPV_REINTERPRET(v2i64, t11), MSA_TPV_REINTERPRET(v2i64, t01))); \ + b3.val = MSA_TPV_REINTERPRET(_Tpv, msa_ilvlq_s64(MSA_TPV_REINTERPRET(v2i64, t11), MSA_TPV_REINTERPRET(v2i64, t01))); \ +} + +OPENCV_HAL_IMPL_MSA_TRANSPOSE4x4(v_uint32x4, v4u32, v4i32, s32) +OPENCV_HAL_IMPL_MSA_TRANSPOSE4x4(v_int32x4, v4i32, v4i32, s32) +OPENCV_HAL_IMPL_MSA_TRANSPOSE4x4(v_float32x4, v4f32, v4i32, s32) + +#define OPENCV_HAL_IMPL_MSA_INTERLEAVED(_Tpvec, _Tp, suffix) \ +inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec& a, v_##_Tpvec& b) \ +{ \ + msa_ld2q_##suffix(ptr, &a.val, &b.val); \ +} \ +inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec& a, v_##_Tpvec& b, v_##_Tpvec& c) \ +{ \ + msa_ld3q_##suffix(ptr, &a.val, &b.val, &c.val); \ +} \ +inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec& a, v_##_Tpvec& b, \ + v_##_Tpvec& c, v_##_Tpvec& d) \ +{ \ + msa_ld4q_##suffix(ptr, &a.val, &b.val, &c.val, &d.val); \ +} \ +inline void v_store_interleave( _Tp* ptr, const v_##_Tpvec& a, const v_##_Tpvec& b, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ \ + msa_st2q_##suffix(ptr, a.val, b.val); \ +} \ +inline void v_store_interleave( _Tp* ptr, const v_##_Tpvec& a, const v_##_Tpvec& b, \ + const v_##_Tpvec& c, hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ \ + msa_st3q_##suffix(ptr, a.val, b.val, c.val); \ +} \ +inline void v_store_interleave( _Tp* ptr, const v_##_Tpvec& a, const v_##_Tpvec& b, \ + const v_##_Tpvec& c, const v_##_Tpvec& d, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED ) \ +{ \ + msa_st4q_##suffix(ptr, a.val, b.val, c.val, d.val); \ +} + +OPENCV_HAL_IMPL_MSA_INTERLEAVED(uint8x16, uchar, u8) +OPENCV_HAL_IMPL_MSA_INTERLEAVED(int8x16, schar, s8) +OPENCV_HAL_IMPL_MSA_INTERLEAVED(uint16x8, ushort, u16) +OPENCV_HAL_IMPL_MSA_INTERLEAVED(int16x8, short, s16) +OPENCV_HAL_IMPL_MSA_INTERLEAVED(uint32x4, unsigned, u32) +OPENCV_HAL_IMPL_MSA_INTERLEAVED(int32x4, int, s32) +OPENCV_HAL_IMPL_MSA_INTERLEAVED(float32x4, float, f32) +OPENCV_HAL_IMPL_MSA_INTERLEAVED(uint64x2, uint64, u64) +OPENCV_HAL_IMPL_MSA_INTERLEAVED(int64x2, int64, s64) +OPENCV_HAL_IMPL_MSA_INTERLEAVED(float64x2, double, f64) + +/* v_cvt_f32, v_cvt_f64, v_cvt_f64_high */ +inline v_float32x4 v_cvt_f32(const v_int32x4& a) +{ + return v_float32x4(msa_cvtfintq_f32_s32(a.val)); +} + +inline v_float32x4 v_cvt_f32(const v_float64x2& a) +{ + return v_float32x4(msa_cvtfq_f32_f64(a.val, msa_dupq_n_f64(0.0f))); +} + +inline v_float32x4 v_cvt_f32(const v_float64x2& a, const v_float64x2& b) +{ + return v_float32x4(msa_cvtfq_f32_f64(a.val, b.val)); +} + +inline v_float64x2 v_cvt_f64(const v_int32x4& a) +{ + return v_float64x2(msa_cvtflq_f64_f32(msa_cvtfintq_f32_s32(a.val))); +} + +inline v_float64x2 v_cvt_f64_high(const v_int32x4& a) +{ + return v_float64x2(msa_cvtfhq_f64_f32(msa_cvtfintq_f32_s32(a.val))); +} + +inline v_float64x2 v_cvt_f64(const v_float32x4& a) +{ + return v_float64x2(msa_cvtflq_f64_f32(a.val)); +} + +inline v_float64x2 v_cvt_f64_high(const v_float32x4& a) +{ + return v_float64x2(msa_cvtfhq_f64_f32(a.val)); +} + +inline v_float64x2 v_cvt_f64(const v_int64x2& a) +{ + return v_float64x2(msa_cvtfintq_f64_s64(a.val)); +} + +////////////// Lookup table access //////////////////// +inline v_int8x16 v_lut(const schar* tab, const int* idx) +{ + schar CV_DECL_ALIGNED(32) elems[16] = + { + tab[idx[ 0]], + tab[idx[ 1]], + tab[idx[ 2]], + tab[idx[ 3]], + tab[idx[ 4]], + tab[idx[ 5]], + tab[idx[ 6]], + tab[idx[ 7]], + tab[idx[ 8]], + tab[idx[ 9]], + tab[idx[10]], + tab[idx[11]], + tab[idx[12]], + tab[idx[13]], + tab[idx[14]], + tab[idx[15]] + }; + return v_int8x16(msa_ld1q_s8(elems)); +} +inline v_int8x16 v_lut_pairs(const schar* tab, const int* idx) +{ + schar CV_DECL_ALIGNED(32) elems[16] = + { + tab[idx[0]], + tab[idx[0] + 1], + tab[idx[1]], + tab[idx[1] + 1], + tab[idx[2]], + tab[idx[2] + 1], + tab[idx[3]], + tab[idx[3] + 1], + tab[idx[4]], + tab[idx[4] + 1], + tab[idx[5]], + tab[idx[5] + 1], + tab[idx[6]], + tab[idx[6] + 1], + tab[idx[7]], + tab[idx[7] + 1] + }; + return v_int8x16(msa_ld1q_s8(elems)); +} +inline v_int8x16 v_lut_quads(const schar* tab, const int* idx) +{ + schar CV_DECL_ALIGNED(32) elems[16] = + { + tab[idx[0]], + tab[idx[0] + 1], + tab[idx[0] + 2], + tab[idx[0] + 3], + tab[idx[1]], + tab[idx[1] + 1], + tab[idx[1] + 2], + tab[idx[1] + 3], + tab[idx[2]], + tab[idx[2] + 1], + tab[idx[2] + 2], + tab[idx[2] + 3], + tab[idx[3]], + tab[idx[3] + 1], + tab[idx[3] + 2], + tab[idx[3] + 3] + }; + return v_int8x16(msa_ld1q_s8(elems)); +} +inline v_uint8x16 v_lut(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut((schar*)tab, idx)); } +inline v_uint8x16 v_lut_pairs(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut_pairs((schar*)tab, idx)); } +inline v_uint8x16 v_lut_quads(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut_quads((schar*)tab, idx)); } + + +inline v_int16x8 v_lut(const short* tab, const int* idx) +{ + short CV_DECL_ALIGNED(32) elems[8] = + { + tab[idx[0]], + tab[idx[1]], + tab[idx[2]], + tab[idx[3]], + tab[idx[4]], + tab[idx[5]], + tab[idx[6]], + tab[idx[7]] + }; + return v_int16x8(msa_ld1q_s16(elems)); +} +inline v_int16x8 v_lut_pairs(const short* tab, const int* idx) +{ + short CV_DECL_ALIGNED(32) elems[8] = + { + tab[idx[0]], + tab[idx[0] + 1], + tab[idx[1]], + tab[idx[1] + 1], + tab[idx[2]], + tab[idx[2] + 1], + tab[idx[3]], + tab[idx[3] + 1] + }; + return v_int16x8(msa_ld1q_s16(elems)); +} +inline v_int16x8 v_lut_quads(const short* tab, const int* idx) +{ + return v_int16x8(msa_combine_s16(msa_ld1_s16(tab + idx[0]), msa_ld1_s16(tab + idx[1]))); +} +inline v_uint16x8 v_lut(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut((short*)tab, idx)); } +inline v_uint16x8 v_lut_pairs(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut_pairs((short*)tab, idx)); } +inline v_uint16x8 v_lut_quads(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut_quads((short*)tab, idx)); } + +inline v_int32x4 v_lut(const int* tab, const int* idx) +{ + int CV_DECL_ALIGNED(32) elems[4] = + { + tab[idx[0]], + tab[idx[1]], + tab[idx[2]], + tab[idx[3]] + }; + return v_int32x4(msa_ld1q_s32(elems)); +} +inline v_int32x4 v_lut_pairs(const int* tab, const int* idx) +{ + return v_int32x4(msa_combine_s32(msa_ld1_s32(tab + idx[0]), msa_ld1_s32(tab + idx[1]))); +} +inline v_int32x4 v_lut_quads(const int* tab, const int* idx) +{ + return v_int32x4(msa_ld1q_s32(tab + idx[0])); +} +inline v_uint32x4 v_lut(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut((int*)tab, idx)); } +inline v_uint32x4 v_lut_pairs(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut_pairs((int*)tab, idx)); } +inline v_uint32x4 v_lut_quads(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut_quads((int*)tab, idx)); } + +inline v_int64x2 v_lut(const int64_t* tab, const int* idx) +{ + return v_int64x2(msa_combine_s64(msa_create_s64(tab[idx[0]]), msa_create_s64(tab[idx[1]]))); +} +inline v_int64x2 v_lut_pairs(const int64_t* tab, const int* idx) +{ + return v_int64x2(msa_ld1q_s64(tab + idx[0])); +} +inline v_uint64x2 v_lut(const uint64_t* tab, const int* idx) { return v_reinterpret_as_u64(v_lut((const int64_t *)tab, idx)); } +inline v_uint64x2 v_lut_pairs(const uint64_t* tab, const int* idx) { return v_reinterpret_as_u64(v_lut_pairs((const int64_t *)tab, idx)); } + +inline v_float32x4 v_lut(const float* tab, const int* idx) +{ + float CV_DECL_ALIGNED(32) elems[4] = + { + tab[idx[0]], + tab[idx[1]], + tab[idx[2]], + tab[idx[3]] + }; + return v_float32x4(msa_ld1q_f32(elems)); +} +inline v_float32x4 v_lut_pairs(const float* tab, const int* idx) +{ + uint64 CV_DECL_ALIGNED(32) elems[2] = + { + *(uint64*)(tab + idx[0]), + *(uint64*)(tab + idx[1]) + }; + return v_float32x4(MSA_TPV_REINTERPRET(v4f32, msa_ld1q_u64(elems))); +} +inline v_float32x4 v_lut_quads(const float* tab, const int* idx) +{ + return v_float32x4(msa_ld1q_f32(tab + idx[0])); +} + +inline v_int32x4 v_lut(const int* tab, const v_int32x4& idxvec) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + + return v_int32x4(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]]); +} + +inline v_uint32x4 v_lut(const unsigned* tab, const v_int32x4& idxvec) +{ + unsigned CV_DECL_ALIGNED(32) elems[4] = + { + tab[msa_getq_lane_s32(idxvec.val, 0)], + tab[msa_getq_lane_s32(idxvec.val, 1)], + tab[msa_getq_lane_s32(idxvec.val, 2)], + tab[msa_getq_lane_s32(idxvec.val, 3)] + }; + return v_uint32x4(msa_ld1q_u32(elems)); +} + +inline v_float32x4 v_lut(const float* tab, const v_int32x4& idxvec) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + + return v_float32x4(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]]); +} + +inline void v_lut_deinterleave(const float* tab, const v_int32x4& idxvec, v_float32x4& x, v_float32x4& y) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + + v4f32 xy02 = msa_combine_f32(msa_ld1_f32(tab + idx[0]), msa_ld1_f32(tab + idx[2])); + v4f32 xy13 = msa_combine_f32(msa_ld1_f32(tab + idx[1]), msa_ld1_f32(tab + idx[3])); + x = v_float32x4(MSA_TPV_REINTERPRET(v4f32, msa_ilvevq_s32(MSA_TPV_REINTERPRET(v4i32, xy13), MSA_TPV_REINTERPRET(v4i32, xy02)))); + y = v_float32x4(MSA_TPV_REINTERPRET(v4f32, msa_ilvodq_s32(MSA_TPV_REINTERPRET(v4i32, xy13), MSA_TPV_REINTERPRET(v4i32, xy02)))); +} + +inline v_int8x16 v_interleave_pairs(const v_int8x16& vec) +{ + v_int8x16 c = v_int8x16(__builtin_msa_vshf_b((v16i8)((v2i64){0x0705060403010200, 0x0F0D0E0C0B090A08}), msa_dupq_n_s8(0), vec.val)); + return c; +} +inline v_uint8x16 v_interleave_pairs(const v_uint8x16& vec) +{ return v_reinterpret_as_u8(v_interleave_pairs(v_reinterpret_as_s8(vec))); } +inline v_int8x16 v_interleave_quads(const v_int8x16& vec) +{ + v_int8x16 c = v_int8x16(__builtin_msa_vshf_b((v16i8)((v2i64){0x0703060205010400, 0x0F0B0E0A0D090C08}), msa_dupq_n_s8(0), vec.val)); + return c; +} +inline v_uint8x16 v_interleave_quads(const v_uint8x16& vec) { return v_reinterpret_as_u8(v_interleave_quads(v_reinterpret_as_s8(vec))); } + +inline v_int16x8 v_interleave_pairs(const v_int16x8& vec) +{ + v_int16x8 c = v_int16x8(__builtin_msa_vshf_h((v8i16)((v2i64){0x0003000100020000, 0x0007000500060004}), msa_dupq_n_s16(0), vec.val)); + return c; +} + +inline v_uint16x8 v_interleave_pairs(const v_uint16x8& vec) { return v_reinterpret_as_u16(v_interleave_pairs(v_reinterpret_as_s16(vec))); } + +inline v_int16x8 v_interleave_quads(const v_int16x8& vec) +{ + v_int16x8 c = v_int16x8(__builtin_msa_vshf_h((v8i16)((v2i64){0x0005000100040000, 0x0007000300060002}), msa_dupq_n_s16(0), vec.val)); + return c; +} + +inline v_uint16x8 v_interleave_quads(const v_uint16x8& vec) { return v_reinterpret_as_u16(v_interleave_quads(v_reinterpret_as_s16(vec))); } + +inline v_int32x4 v_interleave_pairs(const v_int32x4& vec) +{ + v_int32x4 c; + c.val[0] = vec.val[0]; + c.val[1] = vec.val[2]; + c.val[2] = vec.val[1]; + c.val[3] = vec.val[3]; + return c; +} + +inline v_uint32x4 v_interleave_pairs(const v_uint32x4& vec) { return v_reinterpret_as_u32(v_interleave_pairs(v_reinterpret_as_s32(vec))); } +inline v_float32x4 v_interleave_pairs(const v_float32x4& vec) { return v_reinterpret_as_f32(v_interleave_pairs(v_reinterpret_as_s32(vec))); } + +inline v_int8x16 v_pack_triplets(const v_int8x16& vec) +{ + v_int8x16 c = v_int8x16(__builtin_msa_vshf_b((v16i8)((v2i64){0x0908060504020100, 0x131211100E0D0C0A}), msa_dupq_n_s8(0), vec.val)); + return c; +} + +inline v_uint8x16 v_pack_triplets(const v_uint8x16& vec) { return v_reinterpret_as_u8(v_pack_triplets(v_reinterpret_as_s8(vec))); } + +inline v_int16x8 v_pack_triplets(const v_int16x8& vec) +{ + v_int16x8 c = v_int16x8(__builtin_msa_vshf_h((v8i16)((v2i64){0x0004000200010000, 0x0009000800060005}), msa_dupq_n_s16(0), vec.val)); + return c; +} + +inline v_uint16x8 v_pack_triplets(const v_uint16x8& vec) { return v_reinterpret_as_u16(v_pack_triplets(v_reinterpret_as_s16(vec))); } +inline v_int32x4 v_pack_triplets(const v_int32x4& vec) { return vec; } +inline v_uint32x4 v_pack_triplets(const v_uint32x4& vec) { return vec; } +inline v_float32x4 v_pack_triplets(const v_float32x4& vec) { return vec; } + +inline v_float64x2 v_lut(const double* tab, const int* idx) +{ + double CV_DECL_ALIGNED(32) elems[2] = + { + tab[idx[0]], + tab[idx[1]] + }; + return v_float64x2(msa_ld1q_f64(elems)); +} + +inline v_float64x2 v_lut_pairs(const double* tab, const int* idx) +{ + return v_float64x2(msa_ld1q_f64(tab + idx[0])); +} + +inline v_float64x2 v_lut(const double* tab, const v_int32x4& idxvec) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + + return v_float64x2(tab[idx[0]], tab[idx[1]]); +} + +inline void v_lut_deinterleave(const double* tab, const v_int32x4& idxvec, v_float64x2& x, v_float64x2& y) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + + v2f64 xy0 = msa_ld1q_f64(tab + idx[0]); + v2f64 xy1 = msa_ld1q_f64(tab + idx[1]); + x = v_float64x2(MSA_TPV_REINTERPRET(v2f64, msa_ilvevq_s64(MSA_TPV_REINTERPRET(v2i64, xy1), MSA_TPV_REINTERPRET(v2i64, xy0)))); + y = v_float64x2(MSA_TPV_REINTERPRET(v2f64, msa_ilvodq_s64(MSA_TPV_REINTERPRET(v2i64, xy1), MSA_TPV_REINTERPRET(v2i64, xy0)))); +} + +template +inline typename _Tp::lane_type v_extract_n(const _Tp& a) +{ + return v_rotate_right(a).get0(); +} + +template +inline v_uint32x4 v_broadcast_element(const v_uint32x4& a) +{ + return v_setall_u32(v_extract_n(a)); +} +template +inline v_int32x4 v_broadcast_element(const v_int32x4& a) +{ + return v_setall_s32(v_extract_n(a)); +} +template +inline v_float32x4 v_broadcast_element(const v_float32x4& a) +{ + return v_setall_f32(v_extract_n(a)); +} + +////// FP16 support /////// +#if CV_FP16 +inline v_float32x4 v_load_expand(const float16_t* ptr) +{ +#ifndef msa_ld1_f16 + v4f16 v = (v4f16)msa_ld1_s16((const short*)ptr); +#else + v4f16 v = msa_ld1_f16((const __fp16*)ptr); +#endif + return v_float32x4(msa_cvt_f32_f16(v)); +} + +inline void v_pack_store(float16_t* ptr, const v_float32x4& v) +{ + v4f16 hv = msa_cvt_f16_f32(v.val); + +#ifndef msa_st1_f16 + msa_st1_s16((short*)ptr, (int16x4_t)hv); +#else + msa_st1_f16((__fp16*)ptr, hv); +#endif +} +#else +inline v_float32x4 v_load_expand(const float16_t* ptr) +{ + float buf[4]; + for( int i = 0; i < 4; i++ ) + buf[i] = (float)ptr[i]; + return v_load(buf); +} + +inline void v_pack_store(float16_t* ptr, const v_float32x4& v) +{ + float buf[4]; + v_store(buf, v); + for( int i = 0; i < 4; i++ ) + ptr[i] = (float16_t)buf[i]; +} +#endif + +inline void v_cleanup() {} + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END + +//! @endcond + +} + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_neon.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_neon.hpp new file mode 100644 index 0000000..28cf813 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_neon.hpp @@ -0,0 +1,2615 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_HAL_INTRIN_NEON_HPP +#define OPENCV_HAL_INTRIN_NEON_HPP + +#include +#include "opencv2/core/utility.hpp" + +namespace cv +{ + +//! @cond IGNORED + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN + +#define CV_SIMD128 1 +#if defined(__aarch64__) || defined(_M_ARM64) +#define CV_SIMD128_64F 1 +#else +#define CV_SIMD128_64F 0 +#endif + +// The following macro checks if the code is being compiled for the +// AArch64 execution state of Armv8, to enable the 128-bit +// intrinsics. The macro `__ARM_64BIT_STATE` is the one recommended by +// the Arm C Language Extension (ACLE) specifications [1] to check the +// availability of 128-bit intrinsics, and it is supporrted by clang +// and gcc. The macro `_M_ARM64` is the equivalent one for Microsoft +// Visual Studio [2] . +// +// [1] https://developer.arm.com/documentation/101028/0012/13--Advanced-SIMD--Neon--intrinsics +// [2] https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros +#if defined(__ARM_64BIT_STATE) || defined(_M_ARM64) +#define CV_NEON_AARCH64 1 +#else +#define CV_NEON_AARCH64 0 +#endif + +// TODO +#define CV_NEON_DOT 0 + +//////////// Utils //////////// + +#if CV_SIMD128_64F +#define OPENCV_HAL_IMPL_NEON_UNZIP(_Tpv, _Tpvx2, suffix) \ + inline void _v128_unzip(const _Tpv& a, const _Tpv& b, _Tpv& c, _Tpv& d) \ + { c = vuzp1q_##suffix(a, b); d = vuzp2q_##suffix(a, b); } +#define OPENCV_HAL_IMPL_NEON_UNZIP_L(_Tpv, _Tpvx2, suffix) \ + inline void _v128_unzip(const _Tpv&a, const _Tpv&b, _Tpv& c, _Tpv& d) \ + { c = vuzp1_##suffix(a, b); d = vuzp2_##suffix(a, b); } +#else +#define OPENCV_HAL_IMPL_NEON_UNZIP(_Tpv, _Tpvx2, suffix) \ + inline void _v128_unzip(const _Tpv& a, const _Tpv& b, _Tpv& c, _Tpv& d) \ + { _Tpvx2 ab = vuzpq_##suffix(a, b); c = ab.val[0]; d = ab.val[1]; } +#define OPENCV_HAL_IMPL_NEON_UNZIP_L(_Tpv, _Tpvx2, suffix) \ + inline void _v128_unzip(const _Tpv& a, const _Tpv& b, _Tpv& c, _Tpv& d) \ + { _Tpvx2 ab = vuzp_##suffix(a, b); c = ab.val[0]; d = ab.val[1]; } +#endif + +#if CV_SIMD128_64F +#define OPENCV_HAL_IMPL_NEON_REINTERPRET(_Tpv, suffix) \ + template static inline \ + _Tpv vreinterpretq_##suffix##_f64(T a) { return (_Tpv) a; } \ + template static inline \ + float64x2_t vreinterpretq_f64_##suffix(T a) { return (float64x2_t) a; } +#else +#define OPENCV_HAL_IMPL_NEON_REINTERPRET(_Tpv, suffix) +#endif + +#define OPENCV_HAL_IMPL_NEON_UTILS_SUFFIX(_Tpv, _Tpvl, suffix) \ + OPENCV_HAL_IMPL_NEON_UNZIP(_Tpv##_t, _Tpv##x2_t, suffix) \ + OPENCV_HAL_IMPL_NEON_UNZIP_L(_Tpvl##_t, _Tpvl##x2_t, suffix) \ + OPENCV_HAL_IMPL_NEON_REINTERPRET(_Tpv##_t, suffix) + +#define OPENCV_HAL_IMPL_NEON_UTILS_SUFFIX_I64(_Tpv, _Tpvl, suffix) \ + OPENCV_HAL_IMPL_NEON_REINTERPRET(_Tpv##_t, suffix) + +#define OPENCV_HAL_IMPL_NEON_UTILS_SUFFIX_F64(_Tpv, _Tpvl, suffix) \ + OPENCV_HAL_IMPL_NEON_UNZIP(_Tpv##_t, _Tpv##x2_t, suffix) + +OPENCV_HAL_IMPL_NEON_UTILS_SUFFIX(uint8x16, uint8x8, u8) +OPENCV_HAL_IMPL_NEON_UTILS_SUFFIX(int8x16, int8x8, s8) +OPENCV_HAL_IMPL_NEON_UTILS_SUFFIX(uint16x8, uint16x4, u16) +OPENCV_HAL_IMPL_NEON_UTILS_SUFFIX(int16x8, int16x4, s16) +OPENCV_HAL_IMPL_NEON_UTILS_SUFFIX(uint32x4, uint32x2, u32) +OPENCV_HAL_IMPL_NEON_UTILS_SUFFIX(int32x4, int32x2, s32) +OPENCV_HAL_IMPL_NEON_UTILS_SUFFIX(float32x4, float32x2, f32) +OPENCV_HAL_IMPL_NEON_UTILS_SUFFIX_I64(uint64x2, uint64x1, u64) +OPENCV_HAL_IMPL_NEON_UTILS_SUFFIX_I64(int64x2, int64x1, s64) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_UTILS_SUFFIX_F64(float64x2, float64x1,f64) +#endif + +//////////// Types //////////// + +struct v_uint8x16 +{ + typedef uchar lane_type; + enum { nlanes = 16 }; + + v_uint8x16() {} + explicit v_uint8x16(uint8x16_t v) : val(v) {} + v_uint8x16(uchar v0, uchar v1, uchar v2, uchar v3, uchar v4, uchar v5, uchar v6, uchar v7, + uchar v8, uchar v9, uchar v10, uchar v11, uchar v12, uchar v13, uchar v14, uchar v15) + { + uchar v[] = {v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15}; + val = vld1q_u8(v); + } + uchar get0() const + { + return vgetq_lane_u8(val, 0); + } + + uint8x16_t val; +}; + +struct v_int8x16 +{ + typedef schar lane_type; + enum { nlanes = 16 }; + + v_int8x16() {} + explicit v_int8x16(int8x16_t v) : val(v) {} + v_int8x16(schar v0, schar v1, schar v2, schar v3, schar v4, schar v5, schar v6, schar v7, + schar v8, schar v9, schar v10, schar v11, schar v12, schar v13, schar v14, schar v15) + { + schar v[] = {v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15}; + val = vld1q_s8(v); + } + schar get0() const + { + return vgetq_lane_s8(val, 0); + } + + int8x16_t val; +}; + +struct v_uint16x8 +{ + typedef ushort lane_type; + enum { nlanes = 8 }; + + v_uint16x8() {} + explicit v_uint16x8(uint16x8_t v) : val(v) {} + v_uint16x8(ushort v0, ushort v1, ushort v2, ushort v3, ushort v4, ushort v5, ushort v6, ushort v7) + { + ushort v[] = {v0, v1, v2, v3, v4, v5, v6, v7}; + val = vld1q_u16(v); + } + ushort get0() const + { + return vgetq_lane_u16(val, 0); + } + + uint16x8_t val; +}; + +struct v_int16x8 +{ + typedef short lane_type; + enum { nlanes = 8 }; + + v_int16x8() {} + explicit v_int16x8(int16x8_t v) : val(v) {} + v_int16x8(short v0, short v1, short v2, short v3, short v4, short v5, short v6, short v7) + { + short v[] = {v0, v1, v2, v3, v4, v5, v6, v7}; + val = vld1q_s16(v); + } + short get0() const + { + return vgetq_lane_s16(val, 0); + } + + int16x8_t val; +}; + +struct v_uint32x4 +{ + typedef unsigned lane_type; + enum { nlanes = 4 }; + + v_uint32x4() {} + explicit v_uint32x4(uint32x4_t v) : val(v) {} + v_uint32x4(unsigned v0, unsigned v1, unsigned v2, unsigned v3) + { + unsigned v[] = {v0, v1, v2, v3}; + val = vld1q_u32(v); + } + unsigned get0() const + { + return vgetq_lane_u32(val, 0); + } + + uint32x4_t val; +}; + +struct v_int32x4 +{ + typedef int lane_type; + enum { nlanes = 4 }; + + v_int32x4() {} + explicit v_int32x4(int32x4_t v) : val(v) {} + v_int32x4(int v0, int v1, int v2, int v3) + { + int v[] = {v0, v1, v2, v3}; + val = vld1q_s32(v); + } + int get0() const + { + return vgetq_lane_s32(val, 0); + } + int32x4_t val; +}; + +struct v_float32x4 +{ + typedef float lane_type; + enum { nlanes = 4 }; + + v_float32x4() {} + explicit v_float32x4(float32x4_t v) : val(v) {} + v_float32x4(float v0, float v1, float v2, float v3) + { + float v[] = {v0, v1, v2, v3}; + val = vld1q_f32(v); + } + float get0() const + { + return vgetq_lane_f32(val, 0); + } + float32x4_t val; +}; + +struct v_uint64x2 +{ + typedef uint64 lane_type; + enum { nlanes = 2 }; + + v_uint64x2() {} + explicit v_uint64x2(uint64x2_t v) : val(v) {} + v_uint64x2(uint64 v0, uint64 v1) + { + uint64 v[] = {v0, v1}; + val = vld1q_u64(v); + } + uint64 get0() const + { + return vgetq_lane_u64(val, 0); + } + uint64x2_t val; +}; + +struct v_int64x2 +{ + typedef int64 lane_type; + enum { nlanes = 2 }; + + v_int64x2() {} + explicit v_int64x2(int64x2_t v) : val(v) {} + v_int64x2(int64 v0, int64 v1) + { + int64 v[] = {v0, v1}; + val = vld1q_s64(v); + } + int64 get0() const + { + return vgetq_lane_s64(val, 0); + } + int64x2_t val; +}; + +#if CV_SIMD128_64F +struct v_float64x2 +{ + typedef double lane_type; + enum { nlanes = 2 }; + + v_float64x2() {} + explicit v_float64x2(float64x2_t v) : val(v) {} + v_float64x2(double v0, double v1) + { + double v[] = {v0, v1}; + val = vld1q_f64(v); + } + double get0() const + { + return vgetq_lane_f64(val, 0); + } + float64x2_t val; +}; +#endif + +#define OPENCV_HAL_IMPL_NEON_INIT(_Tpv, _Tp, suffix) \ +inline v_##_Tpv v_setzero_##suffix() { return v_##_Tpv(vdupq_n_##suffix((_Tp)0)); } \ +inline v_##_Tpv v_setall_##suffix(_Tp v) { return v_##_Tpv(vdupq_n_##suffix(v)); } \ +inline _Tpv##_t vreinterpretq_##suffix##_##suffix(_Tpv##_t v) { return v; } \ +inline v_uint8x16 v_reinterpret_as_u8(const v_##_Tpv& v) { return v_uint8x16(vreinterpretq_u8_##suffix(v.val)); } \ +inline v_int8x16 v_reinterpret_as_s8(const v_##_Tpv& v) { return v_int8x16(vreinterpretq_s8_##suffix(v.val)); } \ +inline v_uint16x8 v_reinterpret_as_u16(const v_##_Tpv& v) { return v_uint16x8(vreinterpretq_u16_##suffix(v.val)); } \ +inline v_int16x8 v_reinterpret_as_s16(const v_##_Tpv& v) { return v_int16x8(vreinterpretq_s16_##suffix(v.val)); } \ +inline v_uint32x4 v_reinterpret_as_u32(const v_##_Tpv& v) { return v_uint32x4(vreinterpretq_u32_##suffix(v.val)); } \ +inline v_int32x4 v_reinterpret_as_s32(const v_##_Tpv& v) { return v_int32x4(vreinterpretq_s32_##suffix(v.val)); } \ +inline v_uint64x2 v_reinterpret_as_u64(const v_##_Tpv& v) { return v_uint64x2(vreinterpretq_u64_##suffix(v.val)); } \ +inline v_int64x2 v_reinterpret_as_s64(const v_##_Tpv& v) { return v_int64x2(vreinterpretq_s64_##suffix(v.val)); } \ +inline v_float32x4 v_reinterpret_as_f32(const v_##_Tpv& v) { return v_float32x4(vreinterpretq_f32_##suffix(v.val)); } + +OPENCV_HAL_IMPL_NEON_INIT(uint8x16, uchar, u8) +OPENCV_HAL_IMPL_NEON_INIT(int8x16, schar, s8) +OPENCV_HAL_IMPL_NEON_INIT(uint16x8, ushort, u16) +OPENCV_HAL_IMPL_NEON_INIT(int16x8, short, s16) +OPENCV_HAL_IMPL_NEON_INIT(uint32x4, unsigned, u32) +OPENCV_HAL_IMPL_NEON_INIT(int32x4, int, s32) +OPENCV_HAL_IMPL_NEON_INIT(uint64x2, uint64, u64) +OPENCV_HAL_IMPL_NEON_INIT(int64x2, int64, s64) +OPENCV_HAL_IMPL_NEON_INIT(float32x4, float, f32) +#if CV_SIMD128_64F +#define OPENCV_HAL_IMPL_NEON_INIT_64(_Tpv, suffix) \ +inline v_float64x2 v_reinterpret_as_f64(const v_##_Tpv& v) { return v_float64x2(vreinterpretq_f64_##suffix(v.val)); } +OPENCV_HAL_IMPL_NEON_INIT(float64x2, double, f64) +OPENCV_HAL_IMPL_NEON_INIT_64(uint8x16, u8) +OPENCV_HAL_IMPL_NEON_INIT_64(int8x16, s8) +OPENCV_HAL_IMPL_NEON_INIT_64(uint16x8, u16) +OPENCV_HAL_IMPL_NEON_INIT_64(int16x8, s16) +OPENCV_HAL_IMPL_NEON_INIT_64(uint32x4, u32) +OPENCV_HAL_IMPL_NEON_INIT_64(int32x4, s32) +OPENCV_HAL_IMPL_NEON_INIT_64(uint64x2, u64) +OPENCV_HAL_IMPL_NEON_INIT_64(int64x2, s64) +OPENCV_HAL_IMPL_NEON_INIT_64(float32x4, f32) +OPENCV_HAL_IMPL_NEON_INIT_64(float64x2, f64) +#endif + +#define OPENCV_HAL_IMPL_NEON_PACK(_Tpvec, _Tp, hreg, suffix, _Tpwvec, pack, mov, rshr) \ +inline _Tpvec v_##pack(const _Tpwvec& a, const _Tpwvec& b) \ +{ \ + hreg a1 = mov(a.val), b1 = mov(b.val); \ + return _Tpvec(vcombine_##suffix(a1, b1)); \ +} \ +inline void v_##pack##_store(_Tp* ptr, const _Tpwvec& a) \ +{ \ + hreg a1 = mov(a.val); \ + vst1_##suffix(ptr, a1); \ +} \ +template inline \ +_Tpvec v_rshr_##pack(const _Tpwvec& a, const _Tpwvec& b) \ +{ \ + hreg a1 = rshr(a.val, n); \ + hreg b1 = rshr(b.val, n); \ + return _Tpvec(vcombine_##suffix(a1, b1)); \ +} \ +template inline \ +void v_rshr_##pack##_store(_Tp* ptr, const _Tpwvec& a) \ +{ \ + hreg a1 = rshr(a.val, n); \ + vst1_##suffix(ptr, a1); \ +} + +OPENCV_HAL_IMPL_NEON_PACK(v_uint8x16, uchar, uint8x8_t, u8, v_uint16x8, pack, vqmovn_u16, vqrshrn_n_u16) +OPENCV_HAL_IMPL_NEON_PACK(v_int8x16, schar, int8x8_t, s8, v_int16x8, pack, vqmovn_s16, vqrshrn_n_s16) +OPENCV_HAL_IMPL_NEON_PACK(v_uint16x8, ushort, uint16x4_t, u16, v_uint32x4, pack, vqmovn_u32, vqrshrn_n_u32) +OPENCV_HAL_IMPL_NEON_PACK(v_int16x8, short, int16x4_t, s16, v_int32x4, pack, vqmovn_s32, vqrshrn_n_s32) +OPENCV_HAL_IMPL_NEON_PACK(v_uint32x4, unsigned, uint32x2_t, u32, v_uint64x2, pack, vmovn_u64, vrshrn_n_u64) +OPENCV_HAL_IMPL_NEON_PACK(v_int32x4, int, int32x2_t, s32, v_int64x2, pack, vmovn_s64, vrshrn_n_s64) + +OPENCV_HAL_IMPL_NEON_PACK(v_uint8x16, uchar, uint8x8_t, u8, v_int16x8, pack_u, vqmovun_s16, vqrshrun_n_s16) +OPENCV_HAL_IMPL_NEON_PACK(v_uint16x8, ushort, uint16x4_t, u16, v_int32x4, pack_u, vqmovun_s32, vqrshrun_n_s32) + +// pack boolean +inline v_uint8x16 v_pack_b(const v_uint16x8& a, const v_uint16x8& b) +{ + uint8x16_t ab = vcombine_u8(vmovn_u16(a.val), vmovn_u16(b.val)); + return v_uint8x16(ab); +} + +inline v_uint8x16 v_pack_b(const v_uint32x4& a, const v_uint32x4& b, + const v_uint32x4& c, const v_uint32x4& d) +{ + uint16x8_t nab = vcombine_u16(vmovn_u32(a.val), vmovn_u32(b.val)); + uint16x8_t ncd = vcombine_u16(vmovn_u32(c.val), vmovn_u32(d.val)); + return v_uint8x16(vcombine_u8(vmovn_u16(nab), vmovn_u16(ncd))); +} + +inline v_uint8x16 v_pack_b(const v_uint64x2& a, const v_uint64x2& b, const v_uint64x2& c, + const v_uint64x2& d, const v_uint64x2& e, const v_uint64x2& f, + const v_uint64x2& g, const v_uint64x2& h) +{ + uint32x4_t ab = vcombine_u32(vmovn_u64(a.val), vmovn_u64(b.val)); + uint32x4_t cd = vcombine_u32(vmovn_u64(c.val), vmovn_u64(d.val)); + uint32x4_t ef = vcombine_u32(vmovn_u64(e.val), vmovn_u64(f.val)); + uint32x4_t gh = vcombine_u32(vmovn_u64(g.val), vmovn_u64(h.val)); + + uint16x8_t abcd = vcombine_u16(vmovn_u32(ab), vmovn_u32(cd)); + uint16x8_t efgh = vcombine_u16(vmovn_u32(ef), vmovn_u32(gh)); + return v_uint8x16(vcombine_u8(vmovn_u16(abcd), vmovn_u16(efgh))); +} + +inline v_float32x4 v_matmul(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& m3) +{ + float32x2_t vl = vget_low_f32(v.val), vh = vget_high_f32(v.val); + float32x4_t res = vmulq_lane_f32(m0.val, vl, 0); + res = vmlaq_lane_f32(res, m1.val, vl, 1); + res = vmlaq_lane_f32(res, m2.val, vh, 0); + res = vmlaq_lane_f32(res, m3.val, vh, 1); + return v_float32x4(res); +} + +inline v_float32x4 v_matmuladd(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& a) +{ + float32x2_t vl = vget_low_f32(v.val), vh = vget_high_f32(v.val); + float32x4_t res = vmulq_lane_f32(m0.val, vl, 0); + res = vmlaq_lane_f32(res, m1.val, vl, 1); + res = vmlaq_lane_f32(res, m2.val, vh, 0); + res = vaddq_f32(res, a.val); + return v_float32x4(res); +} + +#define OPENCV_HAL_IMPL_NEON_BIN_OP(bin_op, _Tpvec, intrin) \ +inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(intrin(a.val, b.val)); \ +} \ +inline _Tpvec& operator bin_op##= (_Tpvec& a, const _Tpvec& b) \ +{ \ + a.val = intrin(a.val, b.val); \ + return a; \ +} + +OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_uint8x16, vqaddq_u8) +OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_uint8x16, vqsubq_u8) +OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_int8x16, vqaddq_s8) +OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_int8x16, vqsubq_s8) +OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_uint16x8, vqaddq_u16) +OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_uint16x8, vqsubq_u16) +OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_int16x8, vqaddq_s16) +OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_int16x8, vqsubq_s16) +OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_int32x4, vaddq_s32) +OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_int32x4, vsubq_s32) +OPENCV_HAL_IMPL_NEON_BIN_OP(*, v_int32x4, vmulq_s32) +OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_uint32x4, vaddq_u32) +OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_uint32x4, vsubq_u32) +OPENCV_HAL_IMPL_NEON_BIN_OP(*, v_uint32x4, vmulq_u32) +OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_float32x4, vaddq_f32) +OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_float32x4, vsubq_f32) +OPENCV_HAL_IMPL_NEON_BIN_OP(*, v_float32x4, vmulq_f32) +OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_int64x2, vaddq_s64) +OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_int64x2, vsubq_s64) +OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_uint64x2, vaddq_u64) +OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_uint64x2, vsubq_u64) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_BIN_OP(/, v_float32x4, vdivq_f32) +OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_float64x2, vaddq_f64) +OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_float64x2, vsubq_f64) +OPENCV_HAL_IMPL_NEON_BIN_OP(*, v_float64x2, vmulq_f64) +OPENCV_HAL_IMPL_NEON_BIN_OP(/, v_float64x2, vdivq_f64) +#else +inline v_float32x4 operator / (const v_float32x4& a, const v_float32x4& b) +{ + float32x4_t reciprocal = vrecpeq_f32(b.val); + reciprocal = vmulq_f32(vrecpsq_f32(b.val, reciprocal), reciprocal); + reciprocal = vmulq_f32(vrecpsq_f32(b.val, reciprocal), reciprocal); + return v_float32x4(vmulq_f32(a.val, reciprocal)); +} +inline v_float32x4& operator /= (v_float32x4& a, const v_float32x4& b) +{ + float32x4_t reciprocal = vrecpeq_f32(b.val); + reciprocal = vmulq_f32(vrecpsq_f32(b.val, reciprocal), reciprocal); + reciprocal = vmulq_f32(vrecpsq_f32(b.val, reciprocal), reciprocal); + a.val = vmulq_f32(a.val, reciprocal); + return a; +} +#endif + +// saturating multiply 8-bit, 16-bit +#define OPENCV_HAL_IMPL_NEON_MUL_SAT(_Tpvec, _Tpwvec) \ + inline _Tpvec operator * (const _Tpvec& a, const _Tpvec& b) \ + { \ + _Tpwvec c, d; \ + v_mul_expand(a, b, c, d); \ + return v_pack(c, d); \ + } \ + inline _Tpvec& operator *= (_Tpvec& a, const _Tpvec& b) \ + { a = a * b; return a; } + +OPENCV_HAL_IMPL_NEON_MUL_SAT(v_int8x16, v_int16x8) +OPENCV_HAL_IMPL_NEON_MUL_SAT(v_uint8x16, v_uint16x8) +OPENCV_HAL_IMPL_NEON_MUL_SAT(v_int16x8, v_int32x4) +OPENCV_HAL_IMPL_NEON_MUL_SAT(v_uint16x8, v_uint32x4) + +// Multiply and expand +inline void v_mul_expand(const v_int8x16& a, const v_int8x16& b, + v_int16x8& c, v_int16x8& d) +{ + c.val = vmull_s8(vget_low_s8(a.val), vget_low_s8(b.val)); +#if CV_NEON_AARCH64 + d.val = vmull_high_s8(a.val, b.val); +#else // #if CV_NEON_AARCH64 + d.val = vmull_s8(vget_high_s8(a.val), vget_high_s8(b.val)); +#endif // #if CV_NEON_AARCH64 +} + +inline void v_mul_expand(const v_uint8x16& a, const v_uint8x16& b, + v_uint16x8& c, v_uint16x8& d) +{ + c.val = vmull_u8(vget_low_u8(a.val), vget_low_u8(b.val)); +#if CV_NEON_AARCH64 + d.val = vmull_high_u8(a.val, b.val); +#else // #if CV_NEON_AARCH64 + d.val = vmull_u8(vget_high_u8(a.val), vget_high_u8(b.val)); +#endif // #if CV_NEON_AARCH64 +} + +inline void v_mul_expand(const v_int16x8& a, const v_int16x8& b, + v_int32x4& c, v_int32x4& d) +{ + c.val = vmull_s16(vget_low_s16(a.val), vget_low_s16(b.val)); +#if CV_NEON_AARCH64 + d.val = vmull_high_s16(a.val, b.val); +#else // #if CV_NEON_AARCH64 + d.val = vmull_s16(vget_high_s16(a.val), vget_high_s16(b.val)); +#endif // #if CV_NEON_AARCH64 +} + +inline void v_mul_expand(const v_uint16x8& a, const v_uint16x8& b, + v_uint32x4& c, v_uint32x4& d) +{ + c.val = vmull_u16(vget_low_u16(a.val), vget_low_u16(b.val)); +#if CV_NEON_AARCH64 + d.val = vmull_high_u16(a.val, b.val); +#else // #if CV_NEON_AARCH64 + d.val = vmull_u16(vget_high_u16(a.val), vget_high_u16(b.val)); +#endif // #if CV_NEON_AARCH64 +} + +inline void v_mul_expand(const v_uint32x4& a, const v_uint32x4& b, + v_uint64x2& c, v_uint64x2& d) +{ + c.val = vmull_u32(vget_low_u32(a.val), vget_low_u32(b.val)); +#if CV_NEON_AARCH64 + d.val = vmull_high_u32(a.val, b.val); +#else // #if CV_NEON_AARCH64 + d.val = vmull_u32(vget_high_u32(a.val), vget_high_u32(b.val)); +#endif // #if CV_NEON_AARCH64 +} + +inline v_int16x8 v_mul_hi(const v_int16x8& a, const v_int16x8& b) +{ +#if CV_NEON_AARCH64 + int32x4_t c = vmull_high_s16(a.val, b.val); +#else // #if CV_NEON_AARCH64 + int32x4_t c = vmull_s16(vget_high_s16(a.val), vget_high_s16(b.val)); +#endif // #if CV_NEON_AARCH64 + return v_int16x8(vcombine_s16( + vshrn_n_s32(vmull_s16( vget_low_s16(a.val), vget_low_s16(b.val)), 16), + vshrn_n_s32(c, 16) + )); +} +inline v_uint16x8 v_mul_hi(const v_uint16x8& a, const v_uint16x8& b) +{ +#if CV_NEON_AARCH64 + uint32x4_t c = vmull_high_u16(a.val, b.val); +#else // #if CV_NEON_AARCH64 + uint32x4_t c = vmull_u16(vget_high_u16(a.val), vget_high_u16(b.val)); +#endif // #if CV_NEON_AARCH64 + return v_uint16x8(vcombine_u16( + vshrn_n_u32(vmull_u16( vget_low_u16(a.val), vget_low_u16(b.val)), 16), + vshrn_n_u32(c, 16) + )); +} + +//////// Dot Product //////// + +// 16 >> 32 +inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b) +{ + int16x8_t uzp1, uzp2; + _v128_unzip(a.val, b.val, uzp1, uzp2); + int16x4_t a0 = vget_low_s16(uzp1); + int16x4_t b0 = vget_high_s16(uzp1); + int16x4_t a1 = vget_low_s16(uzp2); + int16x4_t b1 = vget_high_s16(uzp2); + int32x4_t p = vmull_s16(a0, b0); + return v_int32x4(vmlal_s16(p, a1, b1)); +} +inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b, const v_int32x4& c) +{ + int16x8_t uzp1, uzp2; + _v128_unzip(a.val, b.val, uzp1, uzp2); + int16x4_t a0 = vget_low_s16(uzp1); + int16x4_t b0 = vget_high_s16(uzp1); + int16x4_t a1 = vget_low_s16(uzp2); + int16x4_t b1 = vget_high_s16(uzp2); + int32x4_t p = vmlal_s16(c.val, a0, b0); + return v_int32x4(vmlal_s16(p, a1, b1)); +} + +// 32 >> 64 +inline v_int64x2 v_dotprod(const v_int32x4& a, const v_int32x4& b) +{ + int32x4_t uzp1, uzp2; + _v128_unzip(a.val, b.val, uzp1, uzp2); + int32x2_t a0 = vget_low_s32(uzp1); + int32x2_t b0 = vget_high_s32(uzp1); + int32x2_t a1 = vget_low_s32(uzp2); + int32x2_t b1 = vget_high_s32(uzp2); + int64x2_t p = vmull_s32(a0, b0); + return v_int64x2(vmlal_s32(p, a1, b1)); +} +inline v_int64x2 v_dotprod(const v_int32x4& a, const v_int32x4& b, const v_int64x2& c) +{ + int32x4_t uzp1, uzp2; + _v128_unzip(a.val, b.val, uzp1, uzp2); + int32x2_t a0 = vget_low_s32(uzp1); + int32x2_t b0 = vget_high_s32(uzp1); + int32x2_t a1 = vget_low_s32(uzp2); + int32x2_t b1 = vget_high_s32(uzp2); + int64x2_t p = vmlal_s32(c.val, a0, b0); + return v_int64x2(vmlal_s32(p, a1, b1)); +} + +// 8 >> 32 +inline v_uint32x4 v_dotprod_expand(const v_uint8x16& a, const v_uint8x16& b) +{ +#if CV_NEON_DOT + return v_uint32x4(vdotq_u32(vdupq_n_u32(0), a.val, b.val)); +#else + const uint8x16_t zero = vreinterpretq_u8_u32(vdupq_n_u32(0)); + const uint8x16_t mask = vreinterpretq_u8_u32(vdupq_n_u32(0x00FF00FF)); + const uint16x8_t zero32 = vreinterpretq_u16_u32(vdupq_n_u32(0)); + const uint16x8_t mask32 = vreinterpretq_u16_u32(vdupq_n_u32(0x0000FFFF)); + + uint16x8_t even = vmulq_u16(vreinterpretq_u16_u8(vbslq_u8(mask, a.val, zero)), + vreinterpretq_u16_u8(vbslq_u8(mask, b.val, zero))); + uint16x8_t odd = vmulq_u16(vshrq_n_u16(vreinterpretq_u16_u8(a.val), 8), + vshrq_n_u16(vreinterpretq_u16_u8(b.val), 8)); + + uint32x4_t s0 = vaddq_u32(vreinterpretq_u32_u16(vbslq_u16(mask32, even, zero32)), + vreinterpretq_u32_u16(vbslq_u16(mask32, odd, zero32))); + uint32x4_t s1 = vaddq_u32(vshrq_n_u32(vreinterpretq_u32_u16(even), 16), + vshrq_n_u32(vreinterpretq_u32_u16(odd), 16)); + return v_uint32x4(vaddq_u32(s0, s1)); +#endif +} +inline v_uint32x4 v_dotprod_expand(const v_uint8x16& a, const v_uint8x16& b, + const v_uint32x4& c) +{ +#if CV_NEON_DOT + return v_uint32x4(vdotq_u32(c.val, a.val, b.val)); +#else + return v_dotprod_expand(a, b) + c; +#endif +} + +inline v_int32x4 v_dotprod_expand(const v_int8x16& a, const v_int8x16& b) +{ +#if CV_NEON_DOT + return v_int32x4(vdotq_s32(vdupq_n_s32(0), a.val, b.val)); +#else + int16x8_t p0 = vmull_s8(vget_low_s8(a.val), vget_low_s8(b.val)); + int16x8_t p1 = vmull_s8(vget_high_s8(a.val), vget_high_s8(b.val)); + int16x8_t uzp1, uzp2; + _v128_unzip(p0, p1, uzp1, uzp2); + int16x8_t sum = vaddq_s16(uzp1, uzp2); + int16x4_t uzpl1, uzpl2; + _v128_unzip(vget_low_s16(sum), vget_high_s16(sum), uzpl1, uzpl2); + return v_int32x4(vaddl_s16(uzpl1, uzpl2)); +#endif +} +inline v_int32x4 v_dotprod_expand(const v_int8x16& a, const v_int8x16& b, + const v_int32x4& c) +{ +#if CV_NEON_DOT + return v_int32x4(vdotq_s32(c.val, a.val, b.val)); +#else + return v_dotprod_expand(a, b) + c; +#endif +} + +// 16 >> 64 +inline v_uint64x2 v_dotprod_expand(const v_uint16x8& a, const v_uint16x8& b) +{ + const uint16x8_t zero = vreinterpretq_u16_u32(vdupq_n_u32(0)); + const uint16x8_t mask = vreinterpretq_u16_u32(vdupq_n_u32(0x0000FFFF)); + + uint32x4_t even = vmulq_u32(vreinterpretq_u32_u16(vbslq_u16(mask, a.val, zero)), + vreinterpretq_u32_u16(vbslq_u16(mask, b.val, zero))); + uint32x4_t odd = vmulq_u32(vshrq_n_u32(vreinterpretq_u32_u16(a.val), 16), + vshrq_n_u32(vreinterpretq_u32_u16(b.val), 16)); + uint32x4_t uzp1, uzp2; + _v128_unzip(even, odd, uzp1, uzp2); + uint64x2_t s0 = vaddl_u32(vget_low_u32(uzp1), vget_high_u32(uzp1)); + uint64x2_t s1 = vaddl_u32(vget_low_u32(uzp2), vget_high_u32(uzp2)); + return v_uint64x2(vaddq_u64(s0, s1)); +} +inline v_uint64x2 v_dotprod_expand(const v_uint16x8& a, const v_uint16x8& b, const v_uint64x2& c) +{ return v_dotprod_expand(a, b) + c; } + +inline v_int64x2 v_dotprod_expand(const v_int16x8& a, const v_int16x8& b) +{ + int32x4_t p0 = vmull_s16(vget_low_s16(a.val), vget_low_s16(b.val)); + int32x4_t p1 = vmull_s16(vget_high_s16(a.val), vget_high_s16(b.val)); + + int32x4_t uzp1, uzp2; + _v128_unzip(p0, p1, uzp1, uzp2); + int32x4_t sum = vaddq_s32(uzp1, uzp2); + + int32x2_t uzpl1, uzpl2; + _v128_unzip(vget_low_s32(sum), vget_high_s32(sum), uzpl1, uzpl2); + return v_int64x2(vaddl_s32(uzpl1, uzpl2)); +} +inline v_int64x2 v_dotprod_expand(const v_int16x8& a, const v_int16x8& b, + const v_int64x2& c) +{ return v_dotprod_expand(a, b) + c; } + +// 32 >> 64f +#if CV_SIMD128_64F +inline v_float64x2 v_dotprod_expand(const v_int32x4& a, const v_int32x4& b) +{ return v_cvt_f64(v_dotprod(a, b)); } +inline v_float64x2 v_dotprod_expand(const v_int32x4& a, const v_int32x4& b, + const v_float64x2& c) +{ return v_dotprod_expand(a, b) + c; } +#endif + +//////// Fast Dot Product //////// + +// 16 >> 32 +inline v_int32x4 v_dotprod_fast(const v_int16x8& a, const v_int16x8& b) +{ +#if CV_NEON_AARCH64 + int32x4_t p = vmull_s16(vget_low_s16(a.val), vget_low_s16(b.val)); + return v_int32x4(vmlal_high_s16(p, a.val, b.val)); +#else + int16x4_t a0 = vget_low_s16(a.val); + int16x4_t a1 = vget_high_s16(a.val); + int16x4_t b0 = vget_low_s16(b.val); + int16x4_t b1 = vget_high_s16(b.val); + int32x4_t p = vmull_s16(a0, b0); + return v_int32x4(vmlal_s16(p, a1, b1)); +#endif +} +inline v_int32x4 v_dotprod_fast(const v_int16x8& a, const v_int16x8& b, const v_int32x4& c) +{ +#if CV_NEON_AARCH64 + int32x4_t p = vmlal_s16(c.val, vget_low_s16(a.val), vget_low_s16(b.val)); + return v_int32x4(vmlal_high_s16(p, a.val, b.val)); +#else + int16x4_t a0 = vget_low_s16(a.val); + int16x4_t a1 = vget_high_s16(a.val); + int16x4_t b0 = vget_low_s16(b.val); + int16x4_t b1 = vget_high_s16(b.val); + int32x4_t p = vmlal_s16(c.val, a0, b0); + return v_int32x4(vmlal_s16(p, a1, b1)); +#endif +} + +// 32 >> 64 +inline v_int64x2 v_dotprod_fast(const v_int32x4& a, const v_int32x4& b) +{ +#if CV_NEON_AARCH64 + int64x2_t p = vmull_s32(vget_low_s32(a.val), vget_low_s32(b.val)); + return v_int64x2(vmlal_high_s32(p, a.val, b.val)); +#else + int32x2_t a0 = vget_low_s32(a.val); + int32x2_t a1 = vget_high_s32(a.val); + int32x2_t b0 = vget_low_s32(b.val); + int32x2_t b1 = vget_high_s32(b.val); + int64x2_t p = vmull_s32(a0, b0); + return v_int64x2(vmlal_s32(p, a1, b1)); +#endif +} +inline v_int64x2 v_dotprod_fast(const v_int32x4& a, const v_int32x4& b, const v_int64x2& c) +{ +#if CV_NEON_AARCH64 + int64x2_t p = vmlal_s32(c.val, vget_low_s32(a.val), vget_low_s32(b.val)); + return v_int64x2(vmlal_high_s32(p, a.val, b.val)); +#else + int32x2_t a0 = vget_low_s32(a.val); + int32x2_t a1 = vget_high_s32(a.val); + int32x2_t b0 = vget_low_s32(b.val); + int32x2_t b1 = vget_high_s32(b.val); + int64x2_t p = vmlal_s32(c.val, a0, b0); + return v_int64x2(vmlal_s32(p, a1, b1)); +#endif +} + +// 8 >> 32 +inline v_uint32x4 v_dotprod_expand_fast(const v_uint8x16& a, const v_uint8x16& b) +{ +#if CV_NEON_DOT + return v_uint32x4(vdotq_u32(vdupq_n_u32(0), a.val, b.val)); +#else + uint16x8_t p0 = vmull_u8(vget_low_u8(a.val), vget_low_u8(b.val)); + uint16x8_t p1 = vmull_u8(vget_high_u8(a.val), vget_high_u8(b.val)); + uint32x4_t s0 = vaddl_u16(vget_low_u16(p0), vget_low_u16(p1)); + uint32x4_t s1 = vaddl_u16(vget_high_u16(p0), vget_high_u16(p1)); + return v_uint32x4(vaddq_u32(s0, s1)); +#endif +} +inline v_uint32x4 v_dotprod_expand_fast(const v_uint8x16& a, const v_uint8x16& b, const v_uint32x4& c) +{ +#if CV_NEON_DOT + return v_uint32x4(vdotq_u32(c.val, a.val, b.val)); +#else + return v_dotprod_expand_fast(a, b) + c; +#endif +} + +inline v_int32x4 v_dotprod_expand_fast(const v_int8x16& a, const v_int8x16& b) +{ +#if CV_NEON_DOT + return v_int32x4(vdotq_s32(vdupq_n_s32(0), a.val, b.val)); +#else + int16x8_t prod = vmull_s8(vget_low_s8(a.val), vget_low_s8(b.val)); + prod = vmlal_s8(prod, vget_high_s8(a.val), vget_high_s8(b.val)); + return v_int32x4(vaddl_s16(vget_low_s16(prod), vget_high_s16(prod))); +#endif +} +inline v_int32x4 v_dotprod_expand_fast(const v_int8x16& a, const v_int8x16& b, const v_int32x4& c) +{ +#if CV_NEON_DOT + return v_int32x4(vdotq_s32(c.val, a.val, b.val)); +#else + return v_dotprod_expand_fast(a, b) + c; +#endif +} + +// 16 >> 64 +inline v_uint64x2 v_dotprod_expand_fast(const v_uint16x8& a, const v_uint16x8& b) +{ + uint32x4_t p0 = vmull_u16(vget_low_u16(a.val), vget_low_u16(b.val)); + uint32x4_t p1 = vmull_u16(vget_high_u16(a.val), vget_high_u16(b.val)); + uint64x2_t s0 = vaddl_u32(vget_low_u32(p0), vget_high_u32(p0)); + uint64x2_t s1 = vaddl_u32(vget_low_u32(p1), vget_high_u32(p1)); + return v_uint64x2(vaddq_u64(s0, s1)); +} +inline v_uint64x2 v_dotprod_expand_fast(const v_uint16x8& a, const v_uint16x8& b, const v_uint64x2& c) +{ return v_dotprod_expand_fast(a, b) + c; } + +inline v_int64x2 v_dotprod_expand_fast(const v_int16x8& a, const v_int16x8& b) +{ + int32x4_t prod = vmull_s16(vget_low_s16(a.val), vget_low_s16(b.val)); + prod = vmlal_s16(prod, vget_high_s16(a.val), vget_high_s16(b.val)); + return v_int64x2(vaddl_s32(vget_low_s32(prod), vget_high_s32(prod))); +} +inline v_int64x2 v_dotprod_expand_fast(const v_int16x8& a, const v_int16x8& b, const v_int64x2& c) +{ return v_dotprod_expand_fast(a, b) + c; } + +// 32 >> 64f +#if CV_SIMD128_64F +inline v_float64x2 v_dotprod_expand_fast(const v_int32x4& a, const v_int32x4& b) +{ return v_cvt_f64(v_dotprod_fast(a, b)); } +inline v_float64x2 v_dotprod_expand_fast(const v_int32x4& a, const v_int32x4& b, const v_float64x2& c) +{ return v_dotprod_expand_fast(a, b) + c; } +#endif + + +#define OPENCV_HAL_IMPL_NEON_LOGIC_OP(_Tpvec, suffix) \ + OPENCV_HAL_IMPL_NEON_BIN_OP(&, _Tpvec, vandq_##suffix) \ + OPENCV_HAL_IMPL_NEON_BIN_OP(|, _Tpvec, vorrq_##suffix) \ + OPENCV_HAL_IMPL_NEON_BIN_OP(^, _Tpvec, veorq_##suffix) \ + inline _Tpvec operator ~ (const _Tpvec& a) \ + { \ + return _Tpvec(vreinterpretq_##suffix##_u8(vmvnq_u8(vreinterpretq_u8_##suffix(a.val)))); \ + } + +OPENCV_HAL_IMPL_NEON_LOGIC_OP(v_uint8x16, u8) +OPENCV_HAL_IMPL_NEON_LOGIC_OP(v_int8x16, s8) +OPENCV_HAL_IMPL_NEON_LOGIC_OP(v_uint16x8, u16) +OPENCV_HAL_IMPL_NEON_LOGIC_OP(v_int16x8, s16) +OPENCV_HAL_IMPL_NEON_LOGIC_OP(v_uint32x4, u32) +OPENCV_HAL_IMPL_NEON_LOGIC_OP(v_int32x4, s32) +OPENCV_HAL_IMPL_NEON_LOGIC_OP(v_uint64x2, u64) +OPENCV_HAL_IMPL_NEON_LOGIC_OP(v_int64x2, s64) + +#define OPENCV_HAL_IMPL_NEON_FLT_BIT_OP(bin_op, intrin) \ +inline v_float32x4 operator bin_op (const v_float32x4& a, const v_float32x4& b) \ +{ \ + return v_float32x4(vreinterpretq_f32_s32(intrin(vreinterpretq_s32_f32(a.val), vreinterpretq_s32_f32(b.val)))); \ +} \ +inline v_float32x4& operator bin_op##= (v_float32x4& a, const v_float32x4& b) \ +{ \ + a.val = vreinterpretq_f32_s32(intrin(vreinterpretq_s32_f32(a.val), vreinterpretq_s32_f32(b.val))); \ + return a; \ +} + +OPENCV_HAL_IMPL_NEON_FLT_BIT_OP(&, vandq_s32) +OPENCV_HAL_IMPL_NEON_FLT_BIT_OP(|, vorrq_s32) +OPENCV_HAL_IMPL_NEON_FLT_BIT_OP(^, veorq_s32) + +inline v_float32x4 operator ~ (const v_float32x4& a) +{ + return v_float32x4(vreinterpretq_f32_s32(vmvnq_s32(vreinterpretq_s32_f32(a.val)))); +} + +#if CV_SIMD128_64F +inline v_float32x4 v_sqrt(const v_float32x4& x) +{ + return v_float32x4(vsqrtq_f32(x.val)); +} + +inline v_float32x4 v_invsqrt(const v_float32x4& x) +{ + v_float32x4 one = v_setall_f32(1.0f); + return one / v_sqrt(x); +} +#else +inline v_float32x4 v_sqrt(const v_float32x4& x) +{ + float32x4_t x1 = vmaxq_f32(x.val, vdupq_n_f32(FLT_MIN)); + float32x4_t e = vrsqrteq_f32(x1); + e = vmulq_f32(vrsqrtsq_f32(vmulq_f32(x1, e), e), e); + e = vmulq_f32(vrsqrtsq_f32(vmulq_f32(x1, e), e), e); + return v_float32x4(vmulq_f32(x.val, e)); +} + +inline v_float32x4 v_invsqrt(const v_float32x4& x) +{ + float32x4_t e = vrsqrteq_f32(x.val); + e = vmulq_f32(vrsqrtsq_f32(vmulq_f32(x.val, e), e), e); + e = vmulq_f32(vrsqrtsq_f32(vmulq_f32(x.val, e), e), e); + return v_float32x4(e); +} +#endif + +#define OPENCV_HAL_IMPL_NEON_ABS(_Tpuvec, _Tpsvec, usuffix, ssuffix) \ +inline _Tpuvec v_abs(const _Tpsvec& a) { return v_reinterpret_as_##usuffix(_Tpsvec(vabsq_##ssuffix(a.val))); } + +OPENCV_HAL_IMPL_NEON_ABS(v_uint8x16, v_int8x16, u8, s8) +OPENCV_HAL_IMPL_NEON_ABS(v_uint16x8, v_int16x8, u16, s16) +OPENCV_HAL_IMPL_NEON_ABS(v_uint32x4, v_int32x4, u32, s32) + +inline v_float32x4 v_abs(v_float32x4 x) +{ return v_float32x4(vabsq_f32(x.val)); } + +#if CV_SIMD128_64F +#define OPENCV_HAL_IMPL_NEON_DBL_BIT_OP(bin_op, intrin) \ +inline v_float64x2 operator bin_op (const v_float64x2& a, const v_float64x2& b) \ +{ \ + return v_float64x2(vreinterpretq_f64_s64(intrin(vreinterpretq_s64_f64(a.val), vreinterpretq_s64_f64(b.val)))); \ +} \ +inline v_float64x2& operator bin_op##= (v_float64x2& a, const v_float64x2& b) \ +{ \ + a.val = vreinterpretq_f64_s64(intrin(vreinterpretq_s64_f64(a.val), vreinterpretq_s64_f64(b.val))); \ + return a; \ +} + +OPENCV_HAL_IMPL_NEON_DBL_BIT_OP(&, vandq_s64) +OPENCV_HAL_IMPL_NEON_DBL_BIT_OP(|, vorrq_s64) +OPENCV_HAL_IMPL_NEON_DBL_BIT_OP(^, veorq_s64) + +inline v_float64x2 operator ~ (const v_float64x2& a) +{ + return v_float64x2(vreinterpretq_f64_s32(vmvnq_s32(vreinterpretq_s32_f64(a.val)))); +} + +inline v_float64x2 v_sqrt(const v_float64x2& x) +{ + return v_float64x2(vsqrtq_f64(x.val)); +} + +inline v_float64x2 v_invsqrt(const v_float64x2& x) +{ + v_float64x2 one = v_setall_f64(1.0f); + return one / v_sqrt(x); +} + +inline v_float64x2 v_abs(v_float64x2 x) +{ return v_float64x2(vabsq_f64(x.val)); } +#endif + +// TODO: exp, log, sin, cos + +#define OPENCV_HAL_IMPL_NEON_BIN_FUNC(_Tpvec, func, intrin) \ +inline _Tpvec func(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(intrin(a.val, b.val)); \ +} + +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint8x16, v_min, vminq_u8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint8x16, v_max, vmaxq_u8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int8x16, v_min, vminq_s8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int8x16, v_max, vmaxq_s8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint16x8, v_min, vminq_u16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint16x8, v_max, vmaxq_u16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int16x8, v_min, vminq_s16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int16x8, v_max, vmaxq_s16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint32x4, v_min, vminq_u32) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint32x4, v_max, vmaxq_u32) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int32x4, v_min, vminq_s32) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int32x4, v_max, vmaxq_s32) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_float32x4, v_min, vminq_f32) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_float32x4, v_max, vmaxq_f32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_float64x2, v_min, vminq_f64) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_float64x2, v_max, vmaxq_f64) +#endif + +#if CV_SIMD128_64F +inline int64x2_t vmvnq_s64(int64x2_t a) +{ + int64x2_t vx = vreinterpretq_s64_u32(vdupq_n_u32(0xFFFFFFFF)); + return veorq_s64(a, vx); +} +inline uint64x2_t vmvnq_u64(uint64x2_t a) +{ + uint64x2_t vx = vreinterpretq_u64_u32(vdupq_n_u32(0xFFFFFFFF)); + return veorq_u64(a, vx); +} +#endif +#define OPENCV_HAL_IMPL_NEON_INT_CMP_OP(_Tpvec, cast, suffix, not_suffix) \ +inline _Tpvec operator == (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(cast(vceqq_##suffix(a.val, b.val))); } \ +inline _Tpvec operator != (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(cast(vmvnq_##not_suffix(vceqq_##suffix(a.val, b.val)))); } \ +inline _Tpvec operator < (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(cast(vcltq_##suffix(a.val, b.val))); } \ +inline _Tpvec operator > (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(cast(vcgtq_##suffix(a.val, b.val))); } \ +inline _Tpvec operator <= (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(cast(vcleq_##suffix(a.val, b.val))); } \ +inline _Tpvec operator >= (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(cast(vcgeq_##suffix(a.val, b.val))); } + +OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_uint8x16, OPENCV_HAL_NOP, u8, u8) +OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_int8x16, vreinterpretq_s8_u8, s8, u8) +OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_uint16x8, OPENCV_HAL_NOP, u16, u16) +OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_int16x8, vreinterpretq_s16_u16, s16, u16) +OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_uint32x4, OPENCV_HAL_NOP, u32, u32) +OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_int32x4, vreinterpretq_s32_u32, s32, u32) +OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_float32x4, vreinterpretq_f32_u32, f32, u32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_uint64x2, OPENCV_HAL_NOP, u64, u64) +OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_int64x2, vreinterpretq_s64_u64, s64, u64) +OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_float64x2, vreinterpretq_f64_u64, f64, u64) +#endif + +inline v_float32x4 v_not_nan(const v_float32x4& a) +{ return v_float32x4(vreinterpretq_f32_u32(vceqq_f32(a.val, a.val))); } +#if CV_SIMD128_64F +inline v_float64x2 v_not_nan(const v_float64x2& a) +{ return v_float64x2(vreinterpretq_f64_u64(vceqq_f64(a.val, a.val))); } +#endif + +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint8x16, v_add_wrap, vaddq_u8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int8x16, v_add_wrap, vaddq_s8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint16x8, v_add_wrap, vaddq_u16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int16x8, v_add_wrap, vaddq_s16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint8x16, v_sub_wrap, vsubq_u8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int8x16, v_sub_wrap, vsubq_s8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint16x8, v_sub_wrap, vsubq_u16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int16x8, v_sub_wrap, vsubq_s16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint8x16, v_mul_wrap, vmulq_u8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int8x16, v_mul_wrap, vmulq_s8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint16x8, v_mul_wrap, vmulq_u16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int16x8, v_mul_wrap, vmulq_s16) + +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint8x16, v_absdiff, vabdq_u8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint16x8, v_absdiff, vabdq_u16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint32x4, v_absdiff, vabdq_u32) +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_float32x4, v_absdiff, vabdq_f32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_float64x2, v_absdiff, vabdq_f64) +#endif + +/** Saturating absolute difference **/ +inline v_int8x16 v_absdiffs(const v_int8x16& a, const v_int8x16& b) +{ return v_int8x16(vqabsq_s8(vqsubq_s8(a.val, b.val))); } +inline v_int16x8 v_absdiffs(const v_int16x8& a, const v_int16x8& b) +{ return v_int16x8(vqabsq_s16(vqsubq_s16(a.val, b.val))); } + +#define OPENCV_HAL_IMPL_NEON_BIN_FUNC2(_Tpvec, _Tpvec2, cast, func, intrin) \ +inline _Tpvec2 func(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec2(cast(intrin(a.val, b.val))); \ +} + +OPENCV_HAL_IMPL_NEON_BIN_FUNC2(v_int8x16, v_uint8x16, vreinterpretq_u8_s8, v_absdiff, vabdq_s8) +OPENCV_HAL_IMPL_NEON_BIN_FUNC2(v_int16x8, v_uint16x8, vreinterpretq_u16_s16, v_absdiff, vabdq_s16) +OPENCV_HAL_IMPL_NEON_BIN_FUNC2(v_int32x4, v_uint32x4, vreinterpretq_u32_s32, v_absdiff, vabdq_s32) + +inline v_float32x4 v_magnitude(const v_float32x4& a, const v_float32x4& b) +{ + v_float32x4 x(vmlaq_f32(vmulq_f32(a.val, a.val), b.val, b.val)); + return v_sqrt(x); +} + +inline v_float32x4 v_sqr_magnitude(const v_float32x4& a, const v_float32x4& b) +{ + return v_float32x4(vmlaq_f32(vmulq_f32(a.val, a.val), b.val, b.val)); +} + +inline v_float32x4 v_fma(const v_float32x4& a, const v_float32x4& b, const v_float32x4& c) +{ +#if CV_SIMD128_64F + // ARMv8, which adds support for 64-bit floating-point (so CV_SIMD128_64F is defined), + // also adds FMA support both for single- and double-precision floating-point vectors + return v_float32x4(vfmaq_f32(c.val, a.val, b.val)); +#else + return v_float32x4(vmlaq_f32(c.val, a.val, b.val)); +#endif +} + +inline v_int32x4 v_fma(const v_int32x4& a, const v_int32x4& b, const v_int32x4& c) +{ + return v_int32x4(vmlaq_s32(c.val, a.val, b.val)); +} + +inline v_float32x4 v_muladd(const v_float32x4& a, const v_float32x4& b, const v_float32x4& c) +{ + return v_fma(a, b, c); +} + +inline v_int32x4 v_muladd(const v_int32x4& a, const v_int32x4& b, const v_int32x4& c) +{ + return v_fma(a, b, c); +} + +#if CV_SIMD128_64F +inline v_float64x2 v_magnitude(const v_float64x2& a, const v_float64x2& b) +{ + v_float64x2 x(vaddq_f64(vmulq_f64(a.val, a.val), vmulq_f64(b.val, b.val))); + return v_sqrt(x); +} + +inline v_float64x2 v_sqr_magnitude(const v_float64x2& a, const v_float64x2& b) +{ + return v_float64x2(vaddq_f64(vmulq_f64(a.val, a.val), vmulq_f64(b.val, b.val))); +} + +inline v_float64x2 v_fma(const v_float64x2& a, const v_float64x2& b, const v_float64x2& c) +{ + return v_float64x2(vfmaq_f64(c.val, a.val, b.val)); +} + +inline v_float64x2 v_muladd(const v_float64x2& a, const v_float64x2& b, const v_float64x2& c) +{ + return v_fma(a, b, c); +} +#endif + +// trade efficiency for convenience +#define OPENCV_HAL_IMPL_NEON_SHIFT_OP(_Tpvec, suffix, _Tps, ssuffix) \ +inline _Tpvec operator << (const _Tpvec& a, int n) \ +{ return _Tpvec(vshlq_##suffix(a.val, vdupq_n_##ssuffix((_Tps)n))); } \ +inline _Tpvec operator >> (const _Tpvec& a, int n) \ +{ return _Tpvec(vshlq_##suffix(a.val, vdupq_n_##ssuffix((_Tps)-n))); } \ +template inline _Tpvec v_shl(const _Tpvec& a) \ +{ return _Tpvec(vshlq_n_##suffix(a.val, n)); } \ +template inline _Tpvec v_shr(const _Tpvec& a) \ +{ return _Tpvec(vshrq_n_##suffix(a.val, n)); } \ +template inline _Tpvec v_rshr(const _Tpvec& a) \ +{ return _Tpvec(vrshrq_n_##suffix(a.val, n)); } + +OPENCV_HAL_IMPL_NEON_SHIFT_OP(v_uint8x16, u8, schar, s8) +OPENCV_HAL_IMPL_NEON_SHIFT_OP(v_int8x16, s8, schar, s8) +OPENCV_HAL_IMPL_NEON_SHIFT_OP(v_uint16x8, u16, short, s16) +OPENCV_HAL_IMPL_NEON_SHIFT_OP(v_int16x8, s16, short, s16) +OPENCV_HAL_IMPL_NEON_SHIFT_OP(v_uint32x4, u32, int, s32) +OPENCV_HAL_IMPL_NEON_SHIFT_OP(v_int32x4, s32, int, s32) +OPENCV_HAL_IMPL_NEON_SHIFT_OP(v_uint64x2, u64, int64, s64) +OPENCV_HAL_IMPL_NEON_SHIFT_OP(v_int64x2, s64, int64, s64) + +#define OPENCV_HAL_IMPL_NEON_ROTATE_OP(_Tpvec, suffix) \ +template inline _Tpvec v_rotate_right(const _Tpvec& a) \ +{ return _Tpvec(vextq_##suffix(a.val, vdupq_n_##suffix(0), n)); } \ +template inline _Tpvec v_rotate_left(const _Tpvec& a) \ +{ return _Tpvec(vextq_##suffix(vdupq_n_##suffix(0), a.val, _Tpvec::nlanes - n)); } \ +template<> inline _Tpvec v_rotate_left<0>(const _Tpvec& a) \ +{ return a; } \ +template inline _Tpvec v_rotate_right(const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vextq_##suffix(a.val, b.val, n)); } \ +template inline _Tpvec v_rotate_left(const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vextq_##suffix(b.val, a.val, _Tpvec::nlanes - n)); } \ +template<> inline _Tpvec v_rotate_left<0>(const _Tpvec& a, const _Tpvec& b) \ +{ CV_UNUSED(b); return a; } + +OPENCV_HAL_IMPL_NEON_ROTATE_OP(v_uint8x16, u8) +OPENCV_HAL_IMPL_NEON_ROTATE_OP(v_int8x16, s8) +OPENCV_HAL_IMPL_NEON_ROTATE_OP(v_uint16x8, u16) +OPENCV_HAL_IMPL_NEON_ROTATE_OP(v_int16x8, s16) +OPENCV_HAL_IMPL_NEON_ROTATE_OP(v_uint32x4, u32) +OPENCV_HAL_IMPL_NEON_ROTATE_OP(v_int32x4, s32) +OPENCV_HAL_IMPL_NEON_ROTATE_OP(v_float32x4, f32) +OPENCV_HAL_IMPL_NEON_ROTATE_OP(v_uint64x2, u64) +OPENCV_HAL_IMPL_NEON_ROTATE_OP(v_int64x2, s64) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_ROTATE_OP(v_float64x2, f64) +#endif + +#if defined(__clang__) && defined(__aarch64__) +// avoid LD2 instruction. details: https://github.com/opencv/opencv/issues/14863 +#define OPENCV_HAL_IMPL_NEON_LOAD_LOW_OP(_Tpvec, _Tp, suffix) \ +inline _Tpvec v_load_low(const _Tp* ptr) \ +{ \ +typedef uint64 CV_DECL_ALIGNED(1) unaligned_uint64; \ +uint64 v = *(unaligned_uint64*)ptr; \ +return _Tpvec(v_reinterpret_as_##suffix(v_uint64x2(v, (uint64)123456))); \ +} +#else +#define OPENCV_HAL_IMPL_NEON_LOAD_LOW_OP(_Tpvec, _Tp, suffix) \ +inline _Tpvec v_load_low(const _Tp* ptr) \ +{ return _Tpvec(vcombine_##suffix(vld1_##suffix(ptr), vdup_n_##suffix((_Tp)0))); } +#endif + +#define OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(_Tpvec, _Tp, suffix) \ +inline _Tpvec v_load(const _Tp* ptr) \ +{ return _Tpvec(vld1q_##suffix(ptr)); } \ +inline _Tpvec v_load_aligned(const _Tp* ptr) \ +{ return _Tpvec(vld1q_##suffix(ptr)); } \ +OPENCV_HAL_IMPL_NEON_LOAD_LOW_OP(_Tpvec, _Tp, suffix) \ +inline _Tpvec v_load_halves(const _Tp* ptr0, const _Tp* ptr1) \ +{ return _Tpvec(vcombine_##suffix(vld1_##suffix(ptr0), vld1_##suffix(ptr1))); } \ +inline void v_store(_Tp* ptr, const _Tpvec& a) \ +{ vst1q_##suffix(ptr, a.val); } \ +inline void v_store_aligned(_Tp* ptr, const _Tpvec& a) \ +{ vst1q_##suffix(ptr, a.val); } \ +inline void v_store_aligned_nocache(_Tp* ptr, const _Tpvec& a) \ +{ vst1q_##suffix(ptr, a.val); } \ +inline void v_store(_Tp* ptr, const _Tpvec& a, hal::StoreMode /*mode*/) \ +{ vst1q_##suffix(ptr, a.val); } \ +inline void v_store_low(_Tp* ptr, const _Tpvec& a) \ +{ vst1_##suffix(ptr, vget_low_##suffix(a.val)); } \ +inline void v_store_high(_Tp* ptr, const _Tpvec& a) \ +{ vst1_##suffix(ptr, vget_high_##suffix(a.val)); } + +OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_uint8x16, uchar, u8) +OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_int8x16, schar, s8) +OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_uint16x8, ushort, u16) +OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_int16x8, short, s16) +OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_uint32x4, unsigned, u32) +OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_int32x4, int, s32) +OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_uint64x2, uint64, u64) +OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_int64x2, int64, s64) +OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_float32x4, float, f32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_float64x2, double, f64) +#endif + +inline unsigned v_reduce_sum(const v_uint8x16& a) +{ +#if CV_NEON_AARCH64 + uint16_t t0 = vaddlvq_u8(a.val); + return t0; +#else // #if CV_NEON_AARCH64 + uint32x4_t t0 = vpaddlq_u16(vpaddlq_u8(a.val)); + uint32x2_t t1 = vpadd_u32(vget_low_u32(t0), vget_high_u32(t0)); + return vget_lane_u32(vpadd_u32(t1, t1), 0); +#endif // #if CV_NEON_AARCH64 +} +inline int v_reduce_sum(const v_int8x16& a) +{ +#if CV_NEON_AARCH64 + int16_t t0 = vaddlvq_s8(a.val); + return t0; +#else // #if CV_NEON_AARCH64 + int32x4_t t0 = vpaddlq_s16(vpaddlq_s8(a.val)); + int32x2_t t1 = vpadd_s32(vget_low_s32(t0), vget_high_s32(t0)); + return vget_lane_s32(vpadd_s32(t1, t1), 0); +#endif // #if CV_NEON_AARCH64 +} +inline unsigned v_reduce_sum(const v_uint16x8& a) +{ +#if CV_NEON_AARCH64 + uint32_t t0 = vaddlvq_u16(a.val); + return t0; +#else // #if CV_NEON_AARCH64 + uint32x4_t t0 = vpaddlq_u16(a.val); + uint32x2_t t1 = vpadd_u32(vget_low_u32(t0), vget_high_u32(t0)); + return vget_lane_u32(vpadd_u32(t1, t1), 0); +#endif // #if CV_NEON_AARCH64 +} +inline int v_reduce_sum(const v_int16x8& a) +{ +#if CV_NEON_AARCH64 + int32_t t0 = vaddlvq_s16(a.val); + return t0; +#else // #if CV_NEON_AARCH64 + int32x4_t t0 = vpaddlq_s16(a.val); + int32x2_t t1 = vpadd_s32(vget_low_s32(t0), vget_high_s32(t0)); + return vget_lane_s32(vpadd_s32(t1, t1), 0); +#endif // #if CV_NEON_AARCH64 +} + +#if CV_NEON_AARCH64 +#define OPENCV_HAL_IMPL_NEON_REDUCE_OP_16(_Tpvec, _Tpnvec, scalartype, func, vectorfunc, suffix) \ +inline scalartype v_reduce_##func(const _Tpvec& a) \ +{ \ + return v##vectorfunc##vq_##suffix(a.val); \ +} +#else // #if CV_NEON_AARCH64 +#define OPENCV_HAL_IMPL_NEON_REDUCE_OP_16(_Tpvec, _Tpnvec, scalartype, func, vectorfunc, suffix) \ +inline scalartype v_reduce_##func(const _Tpvec& a) \ +{ \ + _Tpnvec##_t a0 = vp##vectorfunc##_##suffix(vget_low_##suffix(a.val), vget_high_##suffix(a.val)); \ + a0 = vp##vectorfunc##_##suffix(a0, a0); \ + a0 = vp##vectorfunc##_##suffix(a0, a0); \ + return (scalartype)vget_lane_##suffix(vp##vectorfunc##_##suffix(a0, a0),0); \ +} +#endif // #if CV_NEON_AARCH64 + +OPENCV_HAL_IMPL_NEON_REDUCE_OP_16(v_uint8x16, uint8x8, uchar, max, max, u8) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_16(v_uint8x16, uint8x8, uchar, min, min, u8) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_16(v_int8x16, int8x8, schar, max, max, s8) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_16(v_int8x16, int8x8, schar, min, min, s8) + +#if CV_NEON_AARCH64 +#define OPENCV_HAL_IMPL_NEON_REDUCE_OP_8(_Tpvec, _Tpnvec, scalartype, func, vectorfunc, suffix) \ +inline scalartype v_reduce_##func(const _Tpvec& a) \ +{ \ + return v##vectorfunc##vq_##suffix(a.val); \ +} +#else // #if CV_NEON_AARCH64 +#define OPENCV_HAL_IMPL_NEON_REDUCE_OP_8(_Tpvec, _Tpnvec, scalartype, func, vectorfunc, suffix) \ +inline scalartype v_reduce_##func(const _Tpvec& a) \ +{ \ + _Tpnvec##_t a0 = vp##vectorfunc##_##suffix(vget_low_##suffix(a.val), vget_high_##suffix(a.val)); \ + a0 = vp##vectorfunc##_##suffix(a0, a0); \ + return (scalartype)vget_lane_##suffix(vp##vectorfunc##_##suffix(a0, a0),0); \ +} +#endif // #if CV_NEON_AARCH64 + +OPENCV_HAL_IMPL_NEON_REDUCE_OP_8(v_uint16x8, uint16x4, ushort, max, max, u16) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_8(v_uint16x8, uint16x4, ushort, min, min, u16) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_8(v_int16x8, int16x4, short, max, max, s16) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_8(v_int16x8, int16x4, short, min, min, s16) + +#if CV_NEON_AARCH64 +#define OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(_Tpvec, _Tpnvec, scalartype, func, vectorfunc, suffix) \ +inline scalartype v_reduce_##func(const _Tpvec& a) \ +{ \ + return v##vectorfunc##vq_##suffix(a.val); \ +} +#else // #if CV_NEON_AARCH64 +#define OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(_Tpvec, _Tpnvec, scalartype, func, vectorfunc, suffix) \ +inline scalartype v_reduce_##func(const _Tpvec& a) \ +{ \ + _Tpnvec##_t a0 = vp##vectorfunc##_##suffix(vget_low_##suffix(a.val), vget_high_##suffix(a.val)); \ + return (scalartype)vget_lane_##suffix(vp##vectorfunc##_##suffix(a0, vget_high_##suffix(a.val)),0); \ +} +#endif // #if CV_NEON_AARCH64 + +OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_uint32x4, uint32x2, unsigned, sum, add, u32) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_uint32x4, uint32x2, unsigned, max, max, u32) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_uint32x4, uint32x2, unsigned, min, min, u32) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_int32x4, int32x2, int, sum, add, s32) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_int32x4, int32x2, int, max, max, s32) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_int32x4, int32x2, int, min, min, s32) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_float32x4, float32x2, float, sum, add, f32) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_float32x4, float32x2, float, max, max, f32) +OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_float32x4, float32x2, float, min, min, f32) + +inline uint64 v_reduce_sum(const v_uint64x2& a) +{ +#if CV_NEON_AARCH64 + return vaddvq_u64(a.val); +#else // #if CV_NEON_AARCH64 + return vget_lane_u64(vadd_u64(vget_low_u64(a.val), vget_high_u64(a.val)),0); +#endif // #if CV_NEON_AARCH64 +} +inline int64 v_reduce_sum(const v_int64x2& a) +{ +#if CV_NEON_AARCH64 + return vaddvq_s64(a.val); +#else // #if CV_NEON_AARCH64 + return vget_lane_s64(vadd_s64(vget_low_s64(a.val), vget_high_s64(a.val)),0); +#endif // #if CV_NEON_AARCH64 +} +#if CV_SIMD128_64F +inline double v_reduce_sum(const v_float64x2& a) +{ + return vaddvq_f64(a.val); +} +#endif + +inline v_float32x4 v_reduce_sum4(const v_float32x4& a, const v_float32x4& b, + const v_float32x4& c, const v_float32x4& d) +{ +#if CV_NEON_AARCH64 + float32x4_t ab = vpaddq_f32(a.val, b.val); // a0+a1 a2+a3 b0+b1 b2+b3 + float32x4_t cd = vpaddq_f32(c.val, d.val); // c0+c1 d0+d1 c2+c3 d2+d3 + return v_float32x4(vpaddq_f32(ab, cd)); // sumA sumB sumC sumD +#else // #if CV_NEON_AARCH64 + float32x4x2_t ab = vtrnq_f32(a.val, b.val); + float32x4x2_t cd = vtrnq_f32(c.val, d.val); + + float32x4_t u0 = vaddq_f32(ab.val[0], ab.val[1]); // a0+a1 b0+b1 a2+a3 b2+b3 + float32x4_t u1 = vaddq_f32(cd.val[0], cd.val[1]); // c0+c1 d0+d1 c2+c3 d2+d3 + + float32x4_t v0 = vcombine_f32(vget_low_f32(u0), vget_low_f32(u1)); + float32x4_t v1 = vcombine_f32(vget_high_f32(u0), vget_high_f32(u1)); + + return v_float32x4(vaddq_f32(v0, v1)); +#endif // #if CV_NEON_AARCH64 +} + +inline unsigned v_reduce_sad(const v_uint8x16& a, const v_uint8x16& b) +{ +#if CV_NEON_AARCH64 + uint8x16_t t0 = vabdq_u8(a.val, b.val); + uint16_t t1 = vaddlvq_u8(t0); + return t1; +#else // #if CV_NEON_AARCH64 + uint32x4_t t0 = vpaddlq_u16(vpaddlq_u8(vabdq_u8(a.val, b.val))); + uint32x2_t t1 = vpadd_u32(vget_low_u32(t0), vget_high_u32(t0)); + return vget_lane_u32(vpadd_u32(t1, t1), 0); +#endif // #if CV_NEON_AARCH64 +} +inline unsigned v_reduce_sad(const v_int8x16& a, const v_int8x16& b) +{ +#if CV_NEON_AARCH64 + uint8x16_t t0 = vreinterpretq_u8_s8(vabdq_s8(a.val, b.val)); + uint16_t t1 = vaddlvq_u8(t0); + return t1; +#else // #if CV_NEON_AARCH64 + uint32x4_t t0 = vpaddlq_u16(vpaddlq_u8(vreinterpretq_u8_s8(vabdq_s8(a.val, b.val)))); + uint32x2_t t1 = vpadd_u32(vget_low_u32(t0), vget_high_u32(t0)); + return vget_lane_u32(vpadd_u32(t1, t1), 0); +#endif // #if CV_NEON_AARCH64 +} +inline unsigned v_reduce_sad(const v_uint16x8& a, const v_uint16x8& b) +{ +#if CV_NEON_AARCH64 + uint16x8_t t0 = vabdq_u16(a.val, b.val); + uint32_t t1 = vaddlvq_u16(t0); + return t1; +#else // #if CV_NEON_AARCH64 + uint32x4_t t0 = vpaddlq_u16(vabdq_u16(a.val, b.val)); + uint32x2_t t1 = vpadd_u32(vget_low_u32(t0), vget_high_u32(t0)); + return vget_lane_u32(vpadd_u32(t1, t1), 0); +#endif // #if CV_NEON_AARCH64 +} +inline unsigned v_reduce_sad(const v_int16x8& a, const v_int16x8& b) +{ +#if CV_NEON_AARCH64 + uint16x8_t t0 = vreinterpretq_u16_s16(vabdq_s16(a.val, b.val)); + uint32_t t1 = vaddlvq_u16(t0); + return t1; +#else // #if CV_NEON_AARCH64 + uint32x4_t t0 = vpaddlq_u16(vreinterpretq_u16_s16(vabdq_s16(a.val, b.val))); + uint32x2_t t1 = vpadd_u32(vget_low_u32(t0), vget_high_u32(t0)); + return vget_lane_u32(vpadd_u32(t1, t1), 0); +#endif // #if CV_NEON_AARCH64 +} +inline unsigned v_reduce_sad(const v_uint32x4& a, const v_uint32x4& b) +{ +#if CV_NEON_AARCH64 + uint32x4_t t0 = vabdq_u32(a.val, b.val); + uint32_t t1 = vaddvq_u32(t0); + return t1; +#else // #if CV_NEON_AARCH64 + uint32x4_t t0 = vabdq_u32(a.val, b.val); + uint32x2_t t1 = vpadd_u32(vget_low_u32(t0), vget_high_u32(t0)); + return vget_lane_u32(vpadd_u32(t1, t1), 0); +#endif // #if CV_NEON_AARCH64 +} +inline unsigned v_reduce_sad(const v_int32x4& a, const v_int32x4& b) +{ +#if CV_NEON_AARCH64 + uint32x4_t t0 = vreinterpretq_u32_s32(vabdq_s32(a.val, b.val)); + uint32_t t1 = vaddvq_u32(t0); + return t1; +#else // #if CV_NEON_AARCH64 + uint32x4_t t0 = vreinterpretq_u32_s32(vabdq_s32(a.val, b.val)); + uint32x2_t t1 = vpadd_u32(vget_low_u32(t0), vget_high_u32(t0)); + return vget_lane_u32(vpadd_u32(t1, t1), 0); +#endif // #if CV_NEON_AARCH64 +} +inline float v_reduce_sad(const v_float32x4& a, const v_float32x4& b) +{ +#if CV_NEON_AARCH64 + float32x4_t t0 = vabdq_f32(a.val, b.val); + return vaddvq_f32(t0); +#else // #if CV_NEON_AARCH64 + float32x4_t t0 = vabdq_f32(a.val, b.val); + float32x2_t t1 = vpadd_f32(vget_low_f32(t0), vget_high_f32(t0)); + return vget_lane_f32(vpadd_f32(t1, t1), 0); +#endif // #if CV_NEON_AARCH64 +} + +inline v_uint8x16 v_popcount(const v_uint8x16& a) +{ return v_uint8x16(vcntq_u8(a.val)); } +inline v_uint8x16 v_popcount(const v_int8x16& a) +{ return v_uint8x16(vcntq_u8(vreinterpretq_u8_s8(a.val))); } +inline v_uint16x8 v_popcount(const v_uint16x8& a) +{ return v_uint16x8(vpaddlq_u8(vcntq_u8(vreinterpretq_u8_u16(a.val)))); } +inline v_uint16x8 v_popcount(const v_int16x8& a) +{ return v_uint16x8(vpaddlq_u8(vcntq_u8(vreinterpretq_u8_s16(a.val)))); } +inline v_uint32x4 v_popcount(const v_uint32x4& a) +{ return v_uint32x4(vpaddlq_u16(vpaddlq_u8(vcntq_u8(vreinterpretq_u8_u32(a.val))))); } +inline v_uint32x4 v_popcount(const v_int32x4& a) +{ return v_uint32x4(vpaddlq_u16(vpaddlq_u8(vcntq_u8(vreinterpretq_u8_s32(a.val))))); } +inline v_uint64x2 v_popcount(const v_uint64x2& a) +{ return v_uint64x2(vpaddlq_u32(vpaddlq_u16(vpaddlq_u8(vcntq_u8(vreinterpretq_u8_u64(a.val)))))); } +inline v_uint64x2 v_popcount(const v_int64x2& a) +{ return v_uint64x2(vpaddlq_u32(vpaddlq_u16(vpaddlq_u8(vcntq_u8(vreinterpretq_u8_s64(a.val)))))); } + +inline int v_signmask(const v_uint8x16& a) +{ +#if CV_NEON_AARCH64 + const int8x16_t signPosition = {0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7}; + const uint8x16_t byteOrder = {0,8,1,9,2,10,3,11,4,12,5,13,6,14,7,15}; + uint8x16_t v0 = vshlq_u8(vshrq_n_u8(a.val, 7), signPosition); + uint8x16_t v1 = vqtbl1q_u8(v0, byteOrder); + uint32_t t0 = vaddlvq_u16(vreinterpretq_u16_u8(v1)); + return t0; +#else // #if CV_NEON_AARCH64 + int8x8_t m0 = vcreate_s8(CV_BIG_UINT(0x0706050403020100)); + uint8x16_t v0 = vshlq_u8(vshrq_n_u8(a.val, 7), vcombine_s8(m0, m0)); + uint64x2_t v1 = vpaddlq_u32(vpaddlq_u16(vpaddlq_u8(v0))); + return (int)vgetq_lane_u64(v1, 0) + ((int)vgetq_lane_u64(v1, 1) << 8); +#endif // #if CV_NEON_AARCH64 +} + +inline int v_signmask(const v_int8x16& a) +{ return v_signmask(v_reinterpret_as_u8(a)); } + +inline int v_signmask(const v_uint16x8& a) +{ +#if CV_NEON_AARCH64 + const int16x8_t signPosition = {0,1,2,3,4,5,6,7}; + uint16x8_t v0 = vshlq_u16(vshrq_n_u16(a.val, 15), signPosition); + uint32_t t0 = vaddlvq_u16(v0); + return t0; +#else // #if CV_NEON_AARCH64 + int16x4_t m0 = vcreate_s16(CV_BIG_UINT(0x0003000200010000)); + uint16x8_t v0 = vshlq_u16(vshrq_n_u16(a.val, 15), vcombine_s16(m0, m0)); + uint64x2_t v1 = vpaddlq_u32(vpaddlq_u16(v0)); + return (int)vgetq_lane_u64(v1, 0) + ((int)vgetq_lane_u64(v1, 1) << 4); +#endif // #if CV_NEON_AARCH64 +} +inline int v_signmask(const v_int16x8& a) +{ return v_signmask(v_reinterpret_as_u16(a)); } + +inline int v_signmask(const v_uint32x4& a) +{ +#if CV_NEON_AARCH64 + const int32x4_t signPosition = {0,1,2,3}; + uint32x4_t v0 = vshlq_u32(vshrq_n_u32(a.val, 31), signPosition); + uint32_t t0 = vaddvq_u32(v0); + return t0; +#else // #if CV_NEON_AARCH64 + int32x2_t m0 = vcreate_s32(CV_BIG_UINT(0x0000000100000000)); + uint32x4_t v0 = vshlq_u32(vshrq_n_u32(a.val, 31), vcombine_s32(m0, m0)); + uint64x2_t v1 = vpaddlq_u32(v0); + return (int)vgetq_lane_u64(v1, 0) + ((int)vgetq_lane_u64(v1, 1) << 2); +#endif // #if CV_NEON_AARCH64 +} +inline int v_signmask(const v_int32x4& a) +{ return v_signmask(v_reinterpret_as_u32(a)); } +inline int v_signmask(const v_float32x4& a) +{ return v_signmask(v_reinterpret_as_u32(a)); } +inline int v_signmask(const v_uint64x2& a) +{ +#if CV_NEON_AARCH64 + const int64x2_t signPosition = {0,1}; + uint64x2_t v0 = vshlq_u64(vshrq_n_u64(a.val, 63), signPosition); + uint64_t t0 = vaddvq_u64(v0); + return t0; +#else // #if CV_NEON_AARCH64 + int64x1_t m0 = vdup_n_s64(0); + uint64x2_t v0 = vshlq_u64(vshrq_n_u64(a.val, 63), vcombine_s64(m0, m0)); + return (int)vgetq_lane_u64(v0, 0) + ((int)vgetq_lane_u64(v0, 1) << 1); +#endif // #if CV_NEON_AARCH64 +} +inline int v_signmask(const v_int64x2& a) +{ return v_signmask(v_reinterpret_as_u64(a)); } +#if CV_SIMD128_64F +inline int v_signmask(const v_float64x2& a) +{ return v_signmask(v_reinterpret_as_u64(a)); } +#endif + +inline int v_scan_forward(const v_int8x16& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_uint8x16& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_int16x8& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_uint16x8& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_int32x4& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_uint32x4& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_float32x4& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_int64x2& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_uint64x2& a) { return trailingZeros32(v_signmask(a)); } +#if CV_SIMD128_64F +inline int v_scan_forward(const v_float64x2& a) { return trailingZeros32(v_signmask(a)); } +#endif + +#if CV_NEON_AARCH64 + #define OPENCV_HAL_IMPL_NEON_CHECK_ALLANY(_Tpvec, suffix, shift) \ + inline bool v_check_all(const v_##_Tpvec& a) \ + { \ + return (vminvq_##suffix(a.val) >> shift) != 0; \ + } \ + inline bool v_check_any(const v_##_Tpvec& a) \ + { \ + return (vmaxvq_##suffix(a.val) >> shift) != 0; \ + } +#else // #if CV_NEON_AARCH64 + #define OPENCV_HAL_IMPL_NEON_CHECK_ALLANY(_Tpvec, suffix, shift) \ + inline bool v_check_all(const v_##_Tpvec& a) \ + { \ + _Tpvec##_t v0 = vshrq_n_##suffix(vmvnq_##suffix(a.val), shift); \ + uint64x2_t v1 = vreinterpretq_u64_##suffix(v0); \ + return (vgetq_lane_u64(v1, 0) | vgetq_lane_u64(v1, 1)) == 0; \ + } \ + inline bool v_check_any(const v_##_Tpvec& a) \ + { \ + _Tpvec##_t v0 = vshrq_n_##suffix(a.val, shift); \ + uint64x2_t v1 = vreinterpretq_u64_##suffix(v0); \ + return (vgetq_lane_u64(v1, 0) | vgetq_lane_u64(v1, 1)) != 0; \ + } +#endif // #if CV_NEON_AARCH64 + +OPENCV_HAL_IMPL_NEON_CHECK_ALLANY(uint8x16, u8, 7) +OPENCV_HAL_IMPL_NEON_CHECK_ALLANY(uint16x8, u16, 15) +OPENCV_HAL_IMPL_NEON_CHECK_ALLANY(uint32x4, u32, 31) + +inline bool v_check_all(const v_uint64x2& a) +{ + uint64x2_t v0 = vshrq_n_u64(a.val, 63); + return (vgetq_lane_u64(v0, 0) & vgetq_lane_u64(v0, 1)) == 1; +} +inline bool v_check_any(const v_uint64x2& a) +{ + uint64x2_t v0 = vshrq_n_u64(a.val, 63); + return (vgetq_lane_u64(v0, 0) | vgetq_lane_u64(v0, 1)) != 0; +} + +inline bool v_check_all(const v_int8x16& a) +{ return v_check_all(v_reinterpret_as_u8(a)); } +inline bool v_check_all(const v_int16x8& a) +{ return v_check_all(v_reinterpret_as_u16(a)); } +inline bool v_check_all(const v_int32x4& a) +{ return v_check_all(v_reinterpret_as_u32(a)); } +inline bool v_check_all(const v_float32x4& a) +{ return v_check_all(v_reinterpret_as_u32(a)); } + +inline bool v_check_any(const v_int8x16& a) +{ return v_check_any(v_reinterpret_as_u8(a)); } +inline bool v_check_any(const v_int16x8& a) +{ return v_check_any(v_reinterpret_as_u16(a)); } +inline bool v_check_any(const v_int32x4& a) +{ return v_check_any(v_reinterpret_as_u32(a)); } +inline bool v_check_any(const v_float32x4& a) +{ return v_check_any(v_reinterpret_as_u32(a)); } + +inline bool v_check_all(const v_int64x2& a) +{ return v_check_all(v_reinterpret_as_u64(a)); } +inline bool v_check_any(const v_int64x2& a) +{ return v_check_any(v_reinterpret_as_u64(a)); } +#if CV_SIMD128_64F +inline bool v_check_all(const v_float64x2& a) +{ return v_check_all(v_reinterpret_as_u64(a)); } +inline bool v_check_any(const v_float64x2& a) +{ return v_check_any(v_reinterpret_as_u64(a)); } +#endif + +#define OPENCV_HAL_IMPL_NEON_SELECT(_Tpvec, suffix, usuffix) \ +inline _Tpvec v_select(const _Tpvec& mask, const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(vbslq_##suffix(vreinterpretq_##usuffix##_##suffix(mask.val), a.val, b.val)); \ +} + +OPENCV_HAL_IMPL_NEON_SELECT(v_uint8x16, u8, u8) +OPENCV_HAL_IMPL_NEON_SELECT(v_int8x16, s8, u8) +OPENCV_HAL_IMPL_NEON_SELECT(v_uint16x8, u16, u16) +OPENCV_HAL_IMPL_NEON_SELECT(v_int16x8, s16, u16) +OPENCV_HAL_IMPL_NEON_SELECT(v_uint32x4, u32, u32) +OPENCV_HAL_IMPL_NEON_SELECT(v_int32x4, s32, u32) +OPENCV_HAL_IMPL_NEON_SELECT(v_float32x4, f32, u32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_SELECT(v_float64x2, f64, u64) +#endif + +#if CV_NEON_AARCH64 +#define OPENCV_HAL_IMPL_NEON_EXPAND(_Tpvec, _Tpwvec, _Tp, suffix) \ +inline void v_expand(const _Tpvec& a, _Tpwvec& b0, _Tpwvec& b1) \ +{ \ + b0.val = vmovl_##suffix(vget_low_##suffix(a.val)); \ + b1.val = vmovl_high_##suffix(a.val); \ +} \ +inline _Tpwvec v_expand_low(const _Tpvec& a) \ +{ \ + return _Tpwvec(vmovl_##suffix(vget_low_##suffix(a.val))); \ +} \ +inline _Tpwvec v_expand_high(const _Tpvec& a) \ +{ \ + return _Tpwvec(vmovl_high_##suffix(a.val)); \ +} \ +inline _Tpwvec v_load_expand(const _Tp* ptr) \ +{ \ + return _Tpwvec(vmovl_##suffix(vld1_##suffix(ptr))); \ +} +#else +#define OPENCV_HAL_IMPL_NEON_EXPAND(_Tpvec, _Tpwvec, _Tp, suffix) \ +inline void v_expand(const _Tpvec& a, _Tpwvec& b0, _Tpwvec& b1) \ +{ \ + b0.val = vmovl_##suffix(vget_low_##suffix(a.val)); \ + b1.val = vmovl_##suffix(vget_high_##suffix(a.val)); \ +} \ +inline _Tpwvec v_expand_low(const _Tpvec& a) \ +{ \ + return _Tpwvec(vmovl_##suffix(vget_low_##suffix(a.val))); \ +} \ +inline _Tpwvec v_expand_high(const _Tpvec& a) \ +{ \ + return _Tpwvec(vmovl_##suffix(vget_high_##suffix(a.val))); \ +} \ +inline _Tpwvec v_load_expand(const _Tp* ptr) \ +{ \ + return _Tpwvec(vmovl_##suffix(vld1_##suffix(ptr))); \ +} +#endif + +OPENCV_HAL_IMPL_NEON_EXPAND(v_uint8x16, v_uint16x8, uchar, u8) +OPENCV_HAL_IMPL_NEON_EXPAND(v_int8x16, v_int16x8, schar, s8) +OPENCV_HAL_IMPL_NEON_EXPAND(v_uint16x8, v_uint32x4, ushort, u16) +OPENCV_HAL_IMPL_NEON_EXPAND(v_int16x8, v_int32x4, short, s16) +OPENCV_HAL_IMPL_NEON_EXPAND(v_uint32x4, v_uint64x2, uint, u32) +OPENCV_HAL_IMPL_NEON_EXPAND(v_int32x4, v_int64x2, int, s32) + +inline v_uint32x4 v_load_expand_q(const uchar* ptr) +{ + typedef unsigned int CV_DECL_ALIGNED(1) unaligned_uint; + uint8x8_t v0 = vcreate_u8(*(unaligned_uint*)ptr); + uint16x4_t v1 = vget_low_u16(vmovl_u8(v0)); + return v_uint32x4(vmovl_u16(v1)); +} + +inline v_int32x4 v_load_expand_q(const schar* ptr) +{ + typedef unsigned int CV_DECL_ALIGNED(1) unaligned_uint; + int8x8_t v0 = vcreate_s8(*(unaligned_uint*)ptr); + int16x4_t v1 = vget_low_s16(vmovl_s8(v0)); + return v_int32x4(vmovl_s16(v1)); +} + +#if defined(__aarch64__) || defined(_M_ARM64) +#define OPENCV_HAL_IMPL_NEON_UNPACKS(_Tpvec, suffix) \ +inline void v_zip(const v_##_Tpvec& a0, const v_##_Tpvec& a1, v_##_Tpvec& b0, v_##_Tpvec& b1) \ +{ \ + b0.val = vzip1q_##suffix(a0.val, a1.val); \ + b1.val = vzip2q_##suffix(a0.val, a1.val); \ +} \ +inline v_##_Tpvec v_combine_low(const v_##_Tpvec& a, const v_##_Tpvec& b) \ +{ \ + return v_##_Tpvec(vcombine_##suffix(vget_low_##suffix(a.val), vget_low_##suffix(b.val))); \ +} \ +inline v_##_Tpvec v_combine_high(const v_##_Tpvec& a, const v_##_Tpvec& b) \ +{ \ + return v_##_Tpvec(vcombine_##suffix(vget_high_##suffix(a.val), vget_high_##suffix(b.val))); \ +} \ +inline void v_recombine(const v_##_Tpvec& a, const v_##_Tpvec& b, v_##_Tpvec& c, v_##_Tpvec& d) \ +{ \ + c.val = vcombine_##suffix(vget_low_##suffix(a.val), vget_low_##suffix(b.val)); \ + d.val = vcombine_##suffix(vget_high_##suffix(a.val), vget_high_##suffix(b.val)); \ +} +#else +#define OPENCV_HAL_IMPL_NEON_UNPACKS(_Tpvec, suffix) \ +inline void v_zip(const v_##_Tpvec& a0, const v_##_Tpvec& a1, v_##_Tpvec& b0, v_##_Tpvec& b1) \ +{ \ + _Tpvec##x2_t p = vzipq_##suffix(a0.val, a1.val); \ + b0.val = p.val[0]; \ + b1.val = p.val[1]; \ +} \ +inline v_##_Tpvec v_combine_low(const v_##_Tpvec& a, const v_##_Tpvec& b) \ +{ \ + return v_##_Tpvec(vcombine_##suffix(vget_low_##suffix(a.val), vget_low_##suffix(b.val))); \ +} \ +inline v_##_Tpvec v_combine_high(const v_##_Tpvec& a, const v_##_Tpvec& b) \ +{ \ + return v_##_Tpvec(vcombine_##suffix(vget_high_##suffix(a.val), vget_high_##suffix(b.val))); \ +} \ +inline void v_recombine(const v_##_Tpvec& a, const v_##_Tpvec& b, v_##_Tpvec& c, v_##_Tpvec& d) \ +{ \ + c.val = vcombine_##suffix(vget_low_##suffix(a.val), vget_low_##suffix(b.val)); \ + d.val = vcombine_##suffix(vget_high_##suffix(a.val), vget_high_##suffix(b.val)); \ +} +#endif + +OPENCV_HAL_IMPL_NEON_UNPACKS(uint8x16, u8) +OPENCV_HAL_IMPL_NEON_UNPACKS(int8x16, s8) +OPENCV_HAL_IMPL_NEON_UNPACKS(uint16x8, u16) +OPENCV_HAL_IMPL_NEON_UNPACKS(int16x8, s16) +OPENCV_HAL_IMPL_NEON_UNPACKS(uint32x4, u32) +OPENCV_HAL_IMPL_NEON_UNPACKS(int32x4, s32) +OPENCV_HAL_IMPL_NEON_UNPACKS(float32x4, f32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_UNPACKS(float64x2, f64) +#endif + +inline v_uint8x16 v_reverse(const v_uint8x16 &a) +{ + uint8x16_t vec = vrev64q_u8(a.val); + return v_uint8x16(vextq_u8(vec, vec, 8)); +} + +inline v_int8x16 v_reverse(const v_int8x16 &a) +{ return v_reinterpret_as_s8(v_reverse(v_reinterpret_as_u8(a))); } + +inline v_uint16x8 v_reverse(const v_uint16x8 &a) +{ + uint16x8_t vec = vrev64q_u16(a.val); + return v_uint16x8(vextq_u16(vec, vec, 4)); +} + +inline v_int16x8 v_reverse(const v_int16x8 &a) +{ return v_reinterpret_as_s16(v_reverse(v_reinterpret_as_u16(a))); } + +inline v_uint32x4 v_reverse(const v_uint32x4 &a) +{ + uint32x4_t vec = vrev64q_u32(a.val); + return v_uint32x4(vextq_u32(vec, vec, 2)); +} + +inline v_int32x4 v_reverse(const v_int32x4 &a) +{ return v_reinterpret_as_s32(v_reverse(v_reinterpret_as_u32(a))); } + +inline v_float32x4 v_reverse(const v_float32x4 &a) +{ return v_reinterpret_as_f32(v_reverse(v_reinterpret_as_u32(a))); } + +inline v_uint64x2 v_reverse(const v_uint64x2 &a) +{ + uint64x2_t vec = a.val; + uint64x1_t vec_lo = vget_low_u64(vec); + uint64x1_t vec_hi = vget_high_u64(vec); + return v_uint64x2(vcombine_u64(vec_hi, vec_lo)); +} + +inline v_int64x2 v_reverse(const v_int64x2 &a) +{ return v_reinterpret_as_s64(v_reverse(v_reinterpret_as_u64(a))); } + +#if CV_SIMD128_64F +inline v_float64x2 v_reverse(const v_float64x2 &a) +{ return v_reinterpret_as_f64(v_reverse(v_reinterpret_as_u64(a))); } +#endif + +#define OPENCV_HAL_IMPL_NEON_EXTRACT(_Tpvec, suffix) \ +template \ +inline v_##_Tpvec v_extract(const v_##_Tpvec& a, const v_##_Tpvec& b) \ +{ \ + return v_##_Tpvec(vextq_##suffix(a.val, b.val, s)); \ +} + +OPENCV_HAL_IMPL_NEON_EXTRACT(uint8x16, u8) +OPENCV_HAL_IMPL_NEON_EXTRACT(int8x16, s8) +OPENCV_HAL_IMPL_NEON_EXTRACT(uint16x8, u16) +OPENCV_HAL_IMPL_NEON_EXTRACT(int16x8, s16) +OPENCV_HAL_IMPL_NEON_EXTRACT(uint32x4, u32) +OPENCV_HAL_IMPL_NEON_EXTRACT(int32x4, s32) +OPENCV_HAL_IMPL_NEON_EXTRACT(uint64x2, u64) +OPENCV_HAL_IMPL_NEON_EXTRACT(int64x2, s64) +OPENCV_HAL_IMPL_NEON_EXTRACT(float32x4, f32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_EXTRACT(float64x2, f64) +#endif + +#define OPENCV_HAL_IMPL_NEON_EXTRACT_N(_Tpvec, _Tp, suffix) \ +template inline _Tp v_extract_n(_Tpvec v) { return vgetq_lane_##suffix(v.val, i); } + +OPENCV_HAL_IMPL_NEON_EXTRACT_N(v_uint8x16, uchar, u8) +OPENCV_HAL_IMPL_NEON_EXTRACT_N(v_int8x16, schar, s8) +OPENCV_HAL_IMPL_NEON_EXTRACT_N(v_uint16x8, ushort, u16) +OPENCV_HAL_IMPL_NEON_EXTRACT_N(v_int16x8, short, s16) +OPENCV_HAL_IMPL_NEON_EXTRACT_N(v_uint32x4, uint, u32) +OPENCV_HAL_IMPL_NEON_EXTRACT_N(v_int32x4, int, s32) +OPENCV_HAL_IMPL_NEON_EXTRACT_N(v_uint64x2, uint64, u64) +OPENCV_HAL_IMPL_NEON_EXTRACT_N(v_int64x2, int64, s64) +OPENCV_HAL_IMPL_NEON_EXTRACT_N(v_float32x4, float, f32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_EXTRACT_N(v_float64x2, double, f64) +#endif + +#define OPENCV_HAL_IMPL_NEON_BROADCAST(_Tpvec, _Tp, suffix) \ +template inline _Tpvec v_broadcast_element(_Tpvec v) { _Tp t = v_extract_n(v); return v_setall_##suffix(t); } + +OPENCV_HAL_IMPL_NEON_BROADCAST(v_uint8x16, uchar, u8) +OPENCV_HAL_IMPL_NEON_BROADCAST(v_int8x16, schar, s8) +OPENCV_HAL_IMPL_NEON_BROADCAST(v_uint16x8, ushort, u16) +OPENCV_HAL_IMPL_NEON_BROADCAST(v_int16x8, short, s16) +OPENCV_HAL_IMPL_NEON_BROADCAST(v_uint32x4, uint, u32) +OPENCV_HAL_IMPL_NEON_BROADCAST(v_int32x4, int, s32) +OPENCV_HAL_IMPL_NEON_BROADCAST(v_uint64x2, uint64, u64) +OPENCV_HAL_IMPL_NEON_BROADCAST(v_int64x2, int64, s64) +OPENCV_HAL_IMPL_NEON_BROADCAST(v_float32x4, float, f32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_BROADCAST(v_float64x2, double, f64) +#endif + +#if CV_SIMD128_64F +inline v_int32x4 v_round(const v_float32x4& a) +{ + float32x4_t a_ = a.val; + int32x4_t result; +#if defined _MSC_VER + result = vcvtnq_s32_f32(a_); +#else + __asm__ ("fcvtns %0.4s, %1.4s" + : "=w"(result) + : "w"(a_) + : /* No clobbers */); +#endif + return v_int32x4(result); +} +#else +inline v_int32x4 v_round(const v_float32x4& a) +{ + static const int32x4_t v_sign = vdupq_n_s32(1 << 31), + v_05 = vreinterpretq_s32_f32(vdupq_n_f32(0.5f)); + + int32x4_t v_addition = vorrq_s32(v_05, vandq_s32(v_sign, vreinterpretq_s32_f32(a.val))); + return v_int32x4(vcvtq_s32_f32(vaddq_f32(a.val, vreinterpretq_f32_s32(v_addition)))); +} +#endif +inline v_int32x4 v_floor(const v_float32x4& a) +{ + int32x4_t a1 = vcvtq_s32_f32(a.val); + uint32x4_t mask = vcgtq_f32(vcvtq_f32_s32(a1), a.val); + return v_int32x4(vaddq_s32(a1, vreinterpretq_s32_u32(mask))); +} + +inline v_int32x4 v_ceil(const v_float32x4& a) +{ + int32x4_t a1 = vcvtq_s32_f32(a.val); + uint32x4_t mask = vcgtq_f32(a.val, vcvtq_f32_s32(a1)); + return v_int32x4(vsubq_s32(a1, vreinterpretq_s32_u32(mask))); +} + +inline v_int32x4 v_trunc(const v_float32x4& a) +{ return v_int32x4(vcvtq_s32_f32(a.val)); } + +#if CV_SIMD128_64F +inline v_int32x4 v_round(const v_float64x2& a) +{ + static const int32x2_t zero = vdup_n_s32(0); + return v_int32x4(vcombine_s32(vmovn_s64(vcvtaq_s64_f64(a.val)), zero)); +} + +inline v_int32x4 v_round(const v_float64x2& a, const v_float64x2& b) +{ + return v_int32x4(vcombine_s32(vmovn_s64(vcvtaq_s64_f64(a.val)), vmovn_s64(vcvtaq_s64_f64(b.val)))); +} + +inline v_int32x4 v_floor(const v_float64x2& a) +{ + static const int32x2_t zero = vdup_n_s32(0); + int64x2_t a1 = vcvtq_s64_f64(a.val); + uint64x2_t mask = vcgtq_f64(vcvtq_f64_s64(a1), a.val); + a1 = vaddq_s64(a1, vreinterpretq_s64_u64(mask)); + return v_int32x4(vcombine_s32(vmovn_s64(a1), zero)); +} + +inline v_int32x4 v_ceil(const v_float64x2& a) +{ + static const int32x2_t zero = vdup_n_s32(0); + int64x2_t a1 = vcvtq_s64_f64(a.val); + uint64x2_t mask = vcgtq_f64(a.val, vcvtq_f64_s64(a1)); + a1 = vsubq_s64(a1, vreinterpretq_s64_u64(mask)); + return v_int32x4(vcombine_s32(vmovn_s64(a1), zero)); +} + +inline v_int32x4 v_trunc(const v_float64x2& a) +{ + static const int32x2_t zero = vdup_n_s32(0); + return v_int32x4(vcombine_s32(vmovn_s64(vcvtaq_s64_f64(a.val)), zero)); +} +#endif + +#if CV_NEON_AARCH64 +#define OPENCV_HAL_IMPL_NEON_TRANSPOSE4x4(_Tpvec, suffix) \ +inline void v_transpose4x4(const v_##_Tpvec& a0, const v_##_Tpvec& a1, \ + const v_##_Tpvec& a2, const v_##_Tpvec& a3, \ + v_##_Tpvec& b0, v_##_Tpvec& b1, \ + v_##_Tpvec& b2, v_##_Tpvec& b3) \ +{ \ + /* -- Pass 1: 64b transpose */ \ + _Tpvec##_t t0 = vreinterpretq_##suffix##32_##suffix##64( \ + vtrn1q_##suffix##64(vreinterpretq_##suffix##64_##suffix##32(a0.val), \ + vreinterpretq_##suffix##64_##suffix##32(a2.val))); \ + _Tpvec##_t t1 = vreinterpretq_##suffix##32_##suffix##64( \ + vtrn1q_##suffix##64(vreinterpretq_##suffix##64_##suffix##32(a1.val), \ + vreinterpretq_##suffix##64_##suffix##32(a3.val))); \ + _Tpvec##_t t2 = vreinterpretq_##suffix##32_##suffix##64( \ + vtrn2q_##suffix##64(vreinterpretq_##suffix##64_##suffix##32(a0.val), \ + vreinterpretq_##suffix##64_##suffix##32(a2.val))); \ + _Tpvec##_t t3 = vreinterpretq_##suffix##32_##suffix##64( \ + vtrn2q_##suffix##64(vreinterpretq_##suffix##64_##suffix##32(a1.val), \ + vreinterpretq_##suffix##64_##suffix##32(a3.val))); \ + /* -- Pass 2: 32b transpose */ \ + b0.val = vtrn1q_##suffix##32(t0, t1); \ + b1.val = vtrn2q_##suffix##32(t0, t1); \ + b2.val = vtrn1q_##suffix##32(t2, t3); \ + b3.val = vtrn2q_##suffix##32(t2, t3); \ +} + +OPENCV_HAL_IMPL_NEON_TRANSPOSE4x4(uint32x4, u) +OPENCV_HAL_IMPL_NEON_TRANSPOSE4x4(int32x4, s) +OPENCV_HAL_IMPL_NEON_TRANSPOSE4x4(float32x4, f) +#else // #if CV_NEON_AARCH64 +#define OPENCV_HAL_IMPL_NEON_TRANSPOSE4x4(_Tpvec, suffix) \ +inline void v_transpose4x4(const v_##_Tpvec& a0, const v_##_Tpvec& a1, \ + const v_##_Tpvec& a2, const v_##_Tpvec& a3, \ + v_##_Tpvec& b0, v_##_Tpvec& b1, \ + v_##_Tpvec& b2, v_##_Tpvec& b3) \ +{ \ + /* m00 m01 m02 m03 */ \ + /* m10 m11 m12 m13 */ \ + /* m20 m21 m22 m23 */ \ + /* m30 m31 m32 m33 */ \ + _Tpvec##x2_t t0 = vtrnq_##suffix(a0.val, a1.val); \ + _Tpvec##x2_t t1 = vtrnq_##suffix(a2.val, a3.val); \ + /* m00 m10 m02 m12 */ \ + /* m01 m11 m03 m13 */ \ + /* m20 m30 m22 m32 */ \ + /* m21 m31 m23 m33 */ \ + b0.val = vcombine_##suffix(vget_low_##suffix(t0.val[0]), vget_low_##suffix(t1.val[0])); \ + b1.val = vcombine_##suffix(vget_low_##suffix(t0.val[1]), vget_low_##suffix(t1.val[1])); \ + b2.val = vcombine_##suffix(vget_high_##suffix(t0.val[0]), vget_high_##suffix(t1.val[0])); \ + b3.val = vcombine_##suffix(vget_high_##suffix(t0.val[1]), vget_high_##suffix(t1.val[1])); \ +} + +OPENCV_HAL_IMPL_NEON_TRANSPOSE4x4(uint32x4, u32) +OPENCV_HAL_IMPL_NEON_TRANSPOSE4x4(int32x4, s32) +OPENCV_HAL_IMPL_NEON_TRANSPOSE4x4(float32x4, f32) +#endif // #if CV_NEON_AARCH64 + +#define OPENCV_HAL_IMPL_NEON_INTERLEAVED(_Tpvec, _Tp, suffix) \ +inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec& a, v_##_Tpvec& b) \ +{ \ + _Tpvec##x2_t v = vld2q_##suffix(ptr); \ + a.val = v.val[0]; \ + b.val = v.val[1]; \ +} \ +inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec& a, v_##_Tpvec& b, v_##_Tpvec& c) \ +{ \ + _Tpvec##x3_t v = vld3q_##suffix(ptr); \ + a.val = v.val[0]; \ + b.val = v.val[1]; \ + c.val = v.val[2]; \ +} \ +inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec& a, v_##_Tpvec& b, \ + v_##_Tpvec& c, v_##_Tpvec& d) \ +{ \ + _Tpvec##x4_t v = vld4q_##suffix(ptr); \ + a.val = v.val[0]; \ + b.val = v.val[1]; \ + c.val = v.val[2]; \ + d.val = v.val[3]; \ +} \ +inline void v_store_interleave( _Tp* ptr, const v_##_Tpvec& a, const v_##_Tpvec& b, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ \ + _Tpvec##x2_t v; \ + v.val[0] = a.val; \ + v.val[1] = b.val; \ + vst2q_##suffix(ptr, v); \ +} \ +inline void v_store_interleave( _Tp* ptr, const v_##_Tpvec& a, const v_##_Tpvec& b, \ + const v_##_Tpvec& c, hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ \ + _Tpvec##x3_t v; \ + v.val[0] = a.val; \ + v.val[1] = b.val; \ + v.val[2] = c.val; \ + vst3q_##suffix(ptr, v); \ +} \ +inline void v_store_interleave( _Tp* ptr, const v_##_Tpvec& a, const v_##_Tpvec& b, \ + const v_##_Tpvec& c, const v_##_Tpvec& d, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED ) \ +{ \ + _Tpvec##x4_t v; \ + v.val[0] = a.val; \ + v.val[1] = b.val; \ + v.val[2] = c.val; \ + v.val[3] = d.val; \ + vst4q_##suffix(ptr, v); \ +} + +#define OPENCV_HAL_IMPL_NEON_INTERLEAVED_INT64(tp, suffix) \ +inline void v_load_deinterleave( const tp* ptr, v_##tp##x2& a, v_##tp##x2& b ) \ +{ \ + tp##x1_t a0 = vld1_##suffix(ptr); \ + tp##x1_t b0 = vld1_##suffix(ptr + 1); \ + tp##x1_t a1 = vld1_##suffix(ptr + 2); \ + tp##x1_t b1 = vld1_##suffix(ptr + 3); \ + a = v_##tp##x2(vcombine_##suffix(a0, a1)); \ + b = v_##tp##x2(vcombine_##suffix(b0, b1)); \ +} \ + \ +inline void v_load_deinterleave( const tp* ptr, v_##tp##x2& a, \ + v_##tp##x2& b, v_##tp##x2& c ) \ +{ \ + tp##x1_t a0 = vld1_##suffix(ptr); \ + tp##x1_t b0 = vld1_##suffix(ptr + 1); \ + tp##x1_t c0 = vld1_##suffix(ptr + 2); \ + tp##x1_t a1 = vld1_##suffix(ptr + 3); \ + tp##x1_t b1 = vld1_##suffix(ptr + 4); \ + tp##x1_t c1 = vld1_##suffix(ptr + 5); \ + a = v_##tp##x2(vcombine_##suffix(a0, a1)); \ + b = v_##tp##x2(vcombine_##suffix(b0, b1)); \ + c = v_##tp##x2(vcombine_##suffix(c0, c1)); \ +} \ + \ +inline void v_load_deinterleave( const tp* ptr, v_##tp##x2& a, v_##tp##x2& b, \ + v_##tp##x2& c, v_##tp##x2& d ) \ +{ \ + tp##x1_t a0 = vld1_##suffix(ptr); \ + tp##x1_t b0 = vld1_##suffix(ptr + 1); \ + tp##x1_t c0 = vld1_##suffix(ptr + 2); \ + tp##x1_t d0 = vld1_##suffix(ptr + 3); \ + tp##x1_t a1 = vld1_##suffix(ptr + 4); \ + tp##x1_t b1 = vld1_##suffix(ptr + 5); \ + tp##x1_t c1 = vld1_##suffix(ptr + 6); \ + tp##x1_t d1 = vld1_##suffix(ptr + 7); \ + a = v_##tp##x2(vcombine_##suffix(a0, a1)); \ + b = v_##tp##x2(vcombine_##suffix(b0, b1)); \ + c = v_##tp##x2(vcombine_##suffix(c0, c1)); \ + d = v_##tp##x2(vcombine_##suffix(d0, d1)); \ +} \ + \ +inline void v_store_interleave( tp* ptr, const v_##tp##x2& a, const v_##tp##x2& b, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ \ + vst1_##suffix(ptr, vget_low_##suffix(a.val)); \ + vst1_##suffix(ptr + 1, vget_low_##suffix(b.val)); \ + vst1_##suffix(ptr + 2, vget_high_##suffix(a.val)); \ + vst1_##suffix(ptr + 3, vget_high_##suffix(b.val)); \ +} \ + \ +inline void v_store_interleave( tp* ptr, const v_##tp##x2& a, \ + const v_##tp##x2& b, const v_##tp##x2& c, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ \ + vst1_##suffix(ptr, vget_low_##suffix(a.val)); \ + vst1_##suffix(ptr + 1, vget_low_##suffix(b.val)); \ + vst1_##suffix(ptr + 2, vget_low_##suffix(c.val)); \ + vst1_##suffix(ptr + 3, vget_high_##suffix(a.val)); \ + vst1_##suffix(ptr + 4, vget_high_##suffix(b.val)); \ + vst1_##suffix(ptr + 5, vget_high_##suffix(c.val)); \ +} \ + \ +inline void v_store_interleave( tp* ptr, const v_##tp##x2& a, const v_##tp##x2& b, \ + const v_##tp##x2& c, const v_##tp##x2& d, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ \ + vst1_##suffix(ptr, vget_low_##suffix(a.val)); \ + vst1_##suffix(ptr + 1, vget_low_##suffix(b.val)); \ + vst1_##suffix(ptr + 2, vget_low_##suffix(c.val)); \ + vst1_##suffix(ptr + 3, vget_low_##suffix(d.val)); \ + vst1_##suffix(ptr + 4, vget_high_##suffix(a.val)); \ + vst1_##suffix(ptr + 5, vget_high_##suffix(b.val)); \ + vst1_##suffix(ptr + 6, vget_high_##suffix(c.val)); \ + vst1_##suffix(ptr + 7, vget_high_##suffix(d.val)); \ +} + +OPENCV_HAL_IMPL_NEON_INTERLEAVED(uint8x16, uchar, u8) +OPENCV_HAL_IMPL_NEON_INTERLEAVED(int8x16, schar, s8) +OPENCV_HAL_IMPL_NEON_INTERLEAVED(uint16x8, ushort, u16) +OPENCV_HAL_IMPL_NEON_INTERLEAVED(int16x8, short, s16) +OPENCV_HAL_IMPL_NEON_INTERLEAVED(uint32x4, unsigned, u32) +OPENCV_HAL_IMPL_NEON_INTERLEAVED(int32x4, int, s32) +OPENCV_HAL_IMPL_NEON_INTERLEAVED(float32x4, float, f32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_NEON_INTERLEAVED(float64x2, double, f64) +#endif + +OPENCV_HAL_IMPL_NEON_INTERLEAVED_INT64(int64, s64) +OPENCV_HAL_IMPL_NEON_INTERLEAVED_INT64(uint64, u64) + +inline v_float32x4 v_cvt_f32(const v_int32x4& a) +{ + return v_float32x4(vcvtq_f32_s32(a.val)); +} + +#if CV_SIMD128_64F +inline v_float32x4 v_cvt_f32(const v_float64x2& a) +{ + float32x2_t zero = vdup_n_f32(0.0f); + return v_float32x4(vcombine_f32(vcvt_f32_f64(a.val), zero)); +} + +inline v_float32x4 v_cvt_f32(const v_float64x2& a, const v_float64x2& b) +{ + return v_float32x4(vcombine_f32(vcvt_f32_f64(a.val), vcvt_f32_f64(b.val))); +} + +inline v_float64x2 v_cvt_f64(const v_int32x4& a) +{ + return v_float64x2(vcvt_f64_f32(vcvt_f32_s32(vget_low_s32(a.val)))); +} + +inline v_float64x2 v_cvt_f64_high(const v_int32x4& a) +{ + return v_float64x2(vcvt_f64_f32(vcvt_f32_s32(vget_high_s32(a.val)))); +} + +inline v_float64x2 v_cvt_f64(const v_float32x4& a) +{ + return v_float64x2(vcvt_f64_f32(vget_low_f32(a.val))); +} + +inline v_float64x2 v_cvt_f64_high(const v_float32x4& a) +{ + return v_float64x2(vcvt_f64_f32(vget_high_f32(a.val))); +} + +inline v_float64x2 v_cvt_f64(const v_int64x2& a) +{ return v_float64x2(vcvtq_f64_s64(a.val)); } + +#endif + +////////////// Lookup table access //////////////////// + +inline v_int8x16 v_lut(const schar* tab, const int* idx) +{ + schar CV_DECL_ALIGNED(32) elems[16] = + { + tab[idx[ 0]], + tab[idx[ 1]], + tab[idx[ 2]], + tab[idx[ 3]], + tab[idx[ 4]], + tab[idx[ 5]], + tab[idx[ 6]], + tab[idx[ 7]], + tab[idx[ 8]], + tab[idx[ 9]], + tab[idx[10]], + tab[idx[11]], + tab[idx[12]], + tab[idx[13]], + tab[idx[14]], + tab[idx[15]] + }; + return v_int8x16(vld1q_s8(elems)); +} +inline v_int8x16 v_lut_pairs(const schar* tab, const int* idx) +{ + schar CV_DECL_ALIGNED(32) elems[16] = + { + tab[idx[0]], + tab[idx[0] + 1], + tab[idx[1]], + tab[idx[1] + 1], + tab[idx[2]], + tab[idx[2] + 1], + tab[idx[3]], + tab[idx[3] + 1], + tab[idx[4]], + tab[idx[4] + 1], + tab[idx[5]], + tab[idx[5] + 1], + tab[idx[6]], + tab[idx[6] + 1], + tab[idx[7]], + tab[idx[7] + 1] + }; + return v_int8x16(vld1q_s8(elems)); +} +inline v_int8x16 v_lut_quads(const schar* tab, const int* idx) +{ + schar CV_DECL_ALIGNED(32) elems[16] = + { + tab[idx[0]], + tab[idx[0] + 1], + tab[idx[0] + 2], + tab[idx[0] + 3], + tab[idx[1]], + tab[idx[1] + 1], + tab[idx[1] + 2], + tab[idx[1] + 3], + tab[idx[2]], + tab[idx[2] + 1], + tab[idx[2] + 2], + tab[idx[2] + 3], + tab[idx[3]], + tab[idx[3] + 1], + tab[idx[3] + 2], + tab[idx[3] + 3] + }; + return v_int8x16(vld1q_s8(elems)); +} +inline v_uint8x16 v_lut(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut((schar*)tab, idx)); } +inline v_uint8x16 v_lut_pairs(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut_pairs((schar*)tab, idx)); } +inline v_uint8x16 v_lut_quads(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut_quads((schar*)tab, idx)); } + +inline v_int16x8 v_lut(const short* tab, const int* idx) +{ + short CV_DECL_ALIGNED(32) elems[8] = + { + tab[idx[0]], + tab[idx[1]], + tab[idx[2]], + tab[idx[3]], + tab[idx[4]], + tab[idx[5]], + tab[idx[6]], + tab[idx[7]] + }; + return v_int16x8(vld1q_s16(elems)); +} +inline v_int16x8 v_lut_pairs(const short* tab, const int* idx) +{ + short CV_DECL_ALIGNED(32) elems[8] = + { + tab[idx[0]], + tab[idx[0] + 1], + tab[idx[1]], + tab[idx[1] + 1], + tab[idx[2]], + tab[idx[2] + 1], + tab[idx[3]], + tab[idx[3] + 1] + }; + return v_int16x8(vld1q_s16(elems)); +} +inline v_int16x8 v_lut_quads(const short* tab, const int* idx) +{ + return v_int16x8(vcombine_s16(vld1_s16(tab + idx[0]), vld1_s16(tab + idx[1]))); +} +inline v_uint16x8 v_lut(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut((short*)tab, idx)); } +inline v_uint16x8 v_lut_pairs(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut_pairs((short*)tab, idx)); } +inline v_uint16x8 v_lut_quads(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut_quads((short*)tab, idx)); } + +inline v_int32x4 v_lut(const int* tab, const int* idx) +{ + int CV_DECL_ALIGNED(32) elems[4] = + { + tab[idx[0]], + tab[idx[1]], + tab[idx[2]], + tab[idx[3]] + }; + return v_int32x4(vld1q_s32(elems)); +} +inline v_int32x4 v_lut_pairs(const int* tab, const int* idx) +{ + return v_int32x4(vcombine_s32(vld1_s32(tab + idx[0]), vld1_s32(tab + idx[1]))); +} +inline v_int32x4 v_lut_quads(const int* tab, const int* idx) +{ + return v_int32x4(vld1q_s32(tab + idx[0])); +} +inline v_uint32x4 v_lut(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut((int*)tab, idx)); } +inline v_uint32x4 v_lut_pairs(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut_pairs((int*)tab, idx)); } +inline v_uint32x4 v_lut_quads(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut_quads((int*)tab, idx)); } + +inline v_int64x2 v_lut(const int64_t* tab, const int* idx) +{ + return v_int64x2(vcombine_s64(vcreate_s64(tab[idx[0]]), vcreate_s64(tab[idx[1]]))); +} +inline v_int64x2 v_lut_pairs(const int64_t* tab, const int* idx) +{ + return v_int64x2(vld1q_s64(tab + idx[0])); +} +inline v_uint64x2 v_lut(const uint64_t* tab, const int* idx) { return v_reinterpret_as_u64(v_lut((const int64_t *)tab, idx)); } +inline v_uint64x2 v_lut_pairs(const uint64_t* tab, const int* idx) { return v_reinterpret_as_u64(v_lut_pairs((const int64_t *)tab, idx)); } + +inline v_float32x4 v_lut(const float* tab, const int* idx) +{ + float CV_DECL_ALIGNED(32) elems[4] = + { + tab[idx[0]], + tab[idx[1]], + tab[idx[2]], + tab[idx[3]] + }; + return v_float32x4(vld1q_f32(elems)); +} +inline v_float32x4 v_lut_pairs(const float* tab, const int* idx) +{ + typedef uint64 CV_DECL_ALIGNED(1) unaligned_uint64; + + uint64 CV_DECL_ALIGNED(32) elems[2] = + { + *(unaligned_uint64*)(tab + idx[0]), + *(unaligned_uint64*)(tab + idx[1]) + }; + return v_float32x4(vreinterpretq_f32_u64(vld1q_u64(elems))); +} +inline v_float32x4 v_lut_quads(const float* tab, const int* idx) +{ + return v_float32x4(vld1q_f32(tab + idx[0])); +} + +inline v_int32x4 v_lut(const int* tab, const v_int32x4& idxvec) +{ + int CV_DECL_ALIGNED(32) elems[4] = + { + tab[vgetq_lane_s32(idxvec.val, 0)], + tab[vgetq_lane_s32(idxvec.val, 1)], + tab[vgetq_lane_s32(idxvec.val, 2)], + tab[vgetq_lane_s32(idxvec.val, 3)] + }; + return v_int32x4(vld1q_s32(elems)); +} + +inline v_uint32x4 v_lut(const unsigned* tab, const v_int32x4& idxvec) +{ + unsigned CV_DECL_ALIGNED(32) elems[4] = + { + tab[vgetq_lane_s32(idxvec.val, 0)], + tab[vgetq_lane_s32(idxvec.val, 1)], + tab[vgetq_lane_s32(idxvec.val, 2)], + tab[vgetq_lane_s32(idxvec.val, 3)] + }; + return v_uint32x4(vld1q_u32(elems)); +} + +inline v_float32x4 v_lut(const float* tab, const v_int32x4& idxvec) +{ + float CV_DECL_ALIGNED(32) elems[4] = + { + tab[vgetq_lane_s32(idxvec.val, 0)], + tab[vgetq_lane_s32(idxvec.val, 1)], + tab[vgetq_lane_s32(idxvec.val, 2)], + tab[vgetq_lane_s32(idxvec.val, 3)] + }; + return v_float32x4(vld1q_f32(elems)); +} + +inline void v_lut_deinterleave(const float* tab, const v_int32x4& idxvec, v_float32x4& x, v_float32x4& y) +{ + /*int CV_DECL_ALIGNED(32) idx[4]; + v_store(idx, idxvec); + + float32x4_t xy02 = vcombine_f32(vld1_f32(tab + idx[0]), vld1_f32(tab + idx[2])); + float32x4_t xy13 = vcombine_f32(vld1_f32(tab + idx[1]), vld1_f32(tab + idx[3])); + + float32x4x2_t xxyy = vuzpq_f32(xy02, xy13); + x = v_float32x4(xxyy.val[0]); + y = v_float32x4(xxyy.val[1]);*/ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + + x = v_float32x4(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]]); + y = v_float32x4(tab[idx[0]+1], tab[idx[1]+1], tab[idx[2]+1], tab[idx[3]+1]); +} + +inline v_int8x16 v_interleave_pairs(const v_int8x16& vec) +{ + return v_int8x16(vcombine_s8(vtbl1_s8(vget_low_s8(vec.val), vcreate_s8(0x0705060403010200)), vtbl1_s8(vget_high_s8(vec.val), vcreate_s8(0x0705060403010200)))); +} +inline v_uint8x16 v_interleave_pairs(const v_uint8x16& vec) { return v_reinterpret_as_u8(v_interleave_pairs(v_reinterpret_as_s8(vec))); } +inline v_int8x16 v_interleave_quads(const v_int8x16& vec) +{ + return v_int8x16(vcombine_s8(vtbl1_s8(vget_low_s8(vec.val), vcreate_s8(0x0703060205010400)), vtbl1_s8(vget_high_s8(vec.val), vcreate_s8(0x0703060205010400)))); +} +inline v_uint8x16 v_interleave_quads(const v_uint8x16& vec) { return v_reinterpret_as_u8(v_interleave_quads(v_reinterpret_as_s8(vec))); } + +inline v_int16x8 v_interleave_pairs(const v_int16x8& vec) +{ + return v_int16x8(vreinterpretq_s16_s8(vcombine_s8(vtbl1_s8(vget_low_s8(vreinterpretq_s8_s16(vec.val)), vcreate_s8(0x0706030205040100)), vtbl1_s8(vget_high_s8(vreinterpretq_s8_s16(vec.val)), vcreate_s8(0x0706030205040100))))); +} +inline v_uint16x8 v_interleave_pairs(const v_uint16x8& vec) { return v_reinterpret_as_u16(v_interleave_pairs(v_reinterpret_as_s16(vec))); } +inline v_int16x8 v_interleave_quads(const v_int16x8& vec) +{ + int16x4x2_t res = vzip_s16(vget_low_s16(vec.val), vget_high_s16(vec.val)); + return v_int16x8(vcombine_s16(res.val[0], res.val[1])); +} +inline v_uint16x8 v_interleave_quads(const v_uint16x8& vec) { return v_reinterpret_as_u16(v_interleave_quads(v_reinterpret_as_s16(vec))); } + +inline v_int32x4 v_interleave_pairs(const v_int32x4& vec) +{ + int32x2x2_t res = vzip_s32(vget_low_s32(vec.val), vget_high_s32(vec.val)); + return v_int32x4(vcombine_s32(res.val[0], res.val[1])); +} +inline v_uint32x4 v_interleave_pairs(const v_uint32x4& vec) { return v_reinterpret_as_u32(v_interleave_pairs(v_reinterpret_as_s32(vec))); } +inline v_float32x4 v_interleave_pairs(const v_float32x4& vec) { return v_reinterpret_as_f32(v_interleave_pairs(v_reinterpret_as_s32(vec))); } + +inline v_int8x16 v_pack_triplets(const v_int8x16& vec) +{ + return v_int8x16(vextq_s8(vcombine_s8(vtbl1_s8(vget_low_s8(vec.val), vcreate_s8(0x0605040201000000)), vtbl1_s8(vget_high_s8(vec.val), vcreate_s8(0x0807060504020100))), vdupq_n_s8(0), 2)); +} +inline v_uint8x16 v_pack_triplets(const v_uint8x16& vec) { return v_reinterpret_as_u8(v_pack_triplets(v_reinterpret_as_s8(vec))); } + +inline v_int16x8 v_pack_triplets(const v_int16x8& vec) +{ + return v_int16x8(vreinterpretq_s16_s8(vextq_s8(vcombine_s8(vtbl1_s8(vget_low_s8(vreinterpretq_s8_s16(vec.val)), vcreate_s8(0x0504030201000000)), vget_high_s8(vreinterpretq_s8_s16(vec.val))), vdupq_n_s8(0), 2))); +} +inline v_uint16x8 v_pack_triplets(const v_uint16x8& vec) { return v_reinterpret_as_u16(v_pack_triplets(v_reinterpret_as_s16(vec))); } + +inline v_int32x4 v_pack_triplets(const v_int32x4& vec) { return vec; } +inline v_uint32x4 v_pack_triplets(const v_uint32x4& vec) { return vec; } +inline v_float32x4 v_pack_triplets(const v_float32x4& vec) { return vec; } + +#if CV_SIMD128_64F +inline v_float64x2 v_lut(const double* tab, const int* idx) +{ + double CV_DECL_ALIGNED(32) elems[2] = + { + tab[idx[0]], + tab[idx[1]] + }; + return v_float64x2(vld1q_f64(elems)); +} + +inline v_float64x2 v_lut_pairs(const double* tab, const int* idx) +{ + return v_float64x2(vld1q_f64(tab + idx[0])); +} + +inline v_float64x2 v_lut(const double* tab, const v_int32x4& idxvec) +{ + double CV_DECL_ALIGNED(32) elems[2] = + { + tab[vgetq_lane_s32(idxvec.val, 0)], + tab[vgetq_lane_s32(idxvec.val, 1)], + }; + return v_float64x2(vld1q_f64(elems)); +} + +inline void v_lut_deinterleave(const double* tab, const v_int32x4& idxvec, v_float64x2& x, v_float64x2& y) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + + x = v_float64x2(tab[idx[0]], tab[idx[1]]); + y = v_float64x2(tab[idx[0]+1], tab[idx[1]+1]); +} +#endif + +////// FP16 support /////// +#if CV_FP16 +inline v_float32x4 v_load_expand(const float16_t* ptr) +{ + float16x4_t v = + #ifndef vld1_f16 // APPLE compiler defines vld1_f16 as macro + (float16x4_t)vld1_s16((const short*)ptr); + #else + vld1_f16((const __fp16*)ptr); + #endif + return v_float32x4(vcvt_f32_f16(v)); +} + +inline void v_pack_store(float16_t* ptr, const v_float32x4& v) +{ + float16x4_t hv = vcvt_f16_f32(v.val); + + #ifndef vst1_f16 // APPLE compiler defines vst1_f16 as macro + vst1_s16((short*)ptr, (int16x4_t)hv); + #else + vst1_f16((__fp16*)ptr, hv); + #endif +} +#else +inline v_float32x4 v_load_expand(const float16_t* ptr) +{ + const int N = 4; + float buf[N]; + for( int i = 0; i < N; i++ ) buf[i] = (float)ptr[i]; + return v_load(buf); +} + +inline void v_pack_store(float16_t* ptr, const v_float32x4& v) +{ + const int N = 4; + float buf[N]; + v_store(buf, v); + for( int i = 0; i < N; i++ ) ptr[i] = float16_t(buf[i]); +} +#endif + +inline void v_cleanup() {} + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END + +//! @endcond + +} + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_rvv.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_rvv.hpp new file mode 100644 index 0000000..a592976 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_rvv.hpp @@ -0,0 +1,3320 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +// The original implementation has been contributed by Yin Zhang. +// Copyright (C) 2020, Institute of Software, Chinese Academy of Sciences. + +#ifndef OPENCV_HAL_INTRIN_RVV_HPP +#define OPENCV_HAL_INTRIN_RVV_HPP + +#include + +namespace cv +{ + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN + +#define CV_SIMD128 1 +#define CV_SIMD128_64F 1 + +//////////// Unsupported native intrinsics in C++ //////////// +// The following types have been defined in clang, but not in GCC yet. +#ifndef __clang__ + +struct vuint8mf2_t +{ + uchar val[8] = {0}; + vuint8mf2_t() {} + vuint8mf2_t(const uchar* ptr) + { + for (int i = 0; i < 8; ++i) + { + val[i] = ptr[i]; + } + } +}; +struct vint8mf2_t +{ + schar val[8] = {0}; + vint8mf2_t() {} + vint8mf2_t(const schar* ptr) + { + for (int i = 0; i < 8; ++i) + { + val[i] = ptr[i]; + } + } +}; +struct vuint16mf2_t +{ + ushort val[4] = {0}; + vuint16mf2_t() {} + vuint16mf2_t(const ushort* ptr) + { + for (int i = 0; i < 4; ++i) + { + val[i] = ptr[i]; + } + } +}; +struct vint16mf2_t +{ + short val[4] = {0}; + vint16mf2_t() {} + vint16mf2_t(const short* ptr) + { + for (int i = 0; i < 4; ++i) + { + val[i] = ptr[i]; + } + } +}; +struct vuint32mf2_t +{ + unsigned val[2] = {0}; + vuint32mf2_t() {} + vuint32mf2_t(const unsigned* ptr) + { + val[0] = ptr[0]; + val[1] = ptr[1]; + } +}; +struct vint32mf2_t +{ + int val[2] = {0}; + vint32mf2_t() {} + vint32mf2_t(const int* ptr) + { + val[0] = ptr[0]; + val[1] = ptr[1]; + } +}; +struct vfloat32mf2_t +{ + float val[2] = {0}; + vfloat32mf2_t() {} + vfloat32mf2_t(const float* ptr) + { + val[0] = ptr[0]; + val[1] = ptr[1]; + } +}; +struct vuint64mf2_t +{ + uint64 val[1] = {0}; + vuint64mf2_t() {} + vuint64mf2_t(const uint64* ptr) + { + val[0] = ptr[0]; + } +}; +struct vint64mf2_t +{ + int64 val[1] = {0}; + vint64mf2_t() {} + vint64mf2_t(const int64* ptr) + { + val[0] = ptr[0]; + } +}; +struct vfloat64mf2_t +{ + double val[1] = {0}; + vfloat64mf2_t() {} + vfloat64mf2_t(const double* ptr) + { + val[0] = ptr[0]; + } +}; +struct vuint8mf4_t +{ + uchar val[4] = {0}; + vuint8mf4_t() {} + vuint8mf4_t(const uchar* ptr) + { + for (int i = 0; i < 4; ++i) + { + val[i] = ptr[i]; + } + } +}; +struct vint8mf4_t +{ + schar val[4] = {0}; + vint8mf4_t() {} + vint8mf4_t(const schar* ptr) + { + for (int i = 0; i < 4; ++i) + { + val[i] = ptr[i]; + } + } +}; + +#define OPENCV_HAL_IMPL_RVV_NATIVE_LOADSTORE_MF2(_Tpvec, _Tp, suffix, width, n) \ +inline _Tpvec vle##width##_v_##suffix##mf2(const _Tp* ptr, size_t vl) \ +{ \ + CV_UNUSED(vl); \ + return _Tpvec(ptr); \ +} \ +inline void vse##width##_v_##suffix##mf2(_Tp* ptr, _Tpvec v, size_t vl) \ +{ \ + CV_UNUSED(vl); \ + for (int i = 0; i < n; ++i) \ + { \ + ptr[i] = v.val[i]; \ + } \ +} + +OPENCV_HAL_IMPL_RVV_NATIVE_LOADSTORE_MF2(vuint8mf2_t, uint8_t, u8, 8, 8) +OPENCV_HAL_IMPL_RVV_NATIVE_LOADSTORE_MF2(vint8mf2_t, int8_t, i8, 8, 8) +OPENCV_HAL_IMPL_RVV_NATIVE_LOADSTORE_MF2(vuint16mf2_t, uint16_t, u16, 16, 4) +OPENCV_HAL_IMPL_RVV_NATIVE_LOADSTORE_MF2(vint16mf2_t, int16_t, i16, 16, 4) +OPENCV_HAL_IMPL_RVV_NATIVE_LOADSTORE_MF2(vuint32mf2_t, uint32_t, u32, 32, 2) +OPENCV_HAL_IMPL_RVV_NATIVE_LOADSTORE_MF2(vint32mf2_t, int32_t, i32, 32, 2) +OPENCV_HAL_IMPL_RVV_NATIVE_LOADSTORE_MF2(vfloat32mf2_t, float32_t, f32, 32, 2) +OPENCV_HAL_IMPL_RVV_NATIVE_LOADSTORE_MF2(vuint64mf2_t, uint64_t, u64, 64, 1) +OPENCV_HAL_IMPL_RVV_NATIVE_LOADSTORE_MF2(vint64mf2_t, int64_t, i64, 64, 1) +OPENCV_HAL_IMPL_RVV_NATIVE_LOADSTORE_MF2(vfloat64mf2_t, float64_t, f64, 64, 1) + + +#define OPENCV_HAL_IMPL_RVV_NATIVE_WCVT(_Tpwvec, _Tpvec, _wTp, wcvt, suffix, width, n) \ +inline _Tpwvec wcvt (_Tpvec v, size_t vl) \ +{ \ + _wTp tmp[n]; \ + for (int i = 0; i < n; ++i) \ + { \ + tmp[i] = (_wTp)v.val[i]; \ + } \ + return vle##width##_v_##suffix##m1(tmp, vl); \ +} + +OPENCV_HAL_IMPL_RVV_NATIVE_WCVT(vuint16m1_t, vuint8mf2_t, ushort, vwcvtu_x_x_v_u16m1, u16, 16, 8) +OPENCV_HAL_IMPL_RVV_NATIVE_WCVT(vint16m1_t, vint8mf2_t, short, vwcvt_x_x_v_i16m1, i16, 16, 8) +OPENCV_HAL_IMPL_RVV_NATIVE_WCVT(vuint32m1_t, vuint16mf2_t, unsigned, vwcvtu_x_x_v_u32m1, u32, 32, 4) +OPENCV_HAL_IMPL_RVV_NATIVE_WCVT(vint32m1_t, vint16mf2_t, int, vwcvt_x_x_v_i32m1, i32, 32, 4) +OPENCV_HAL_IMPL_RVV_NATIVE_WCVT(vuint64m1_t, vuint32mf2_t, uint64, vwcvtu_x_x_v_u64m1, u64, 64, 2) +OPENCV_HAL_IMPL_RVV_NATIVE_WCVT(vint64m1_t, vint32mf2_t, int64, vwcvt_x_x_v_i64m1, i64, 64, 2) + +inline vuint8mf4_t vle8_v_u8mf4 (const uint8_t *base, size_t vl) +{ + CV_UNUSED(vl); + return vuint8mf4_t(base); +} +inline vint8mf4_t vle8_v_i8mf4 (const int8_t *base, size_t vl) +{ + CV_UNUSED(vl); + return vint8mf4_t(base); +} + +inline vuint16mf2_t vwcvtu_x_x_v_u16mf2 (vuint8mf4_t src, size_t vl) +{ + ushort tmp[4]; + for (int i = 0; i < 4; ++i) + { + tmp[i] = (ushort)src.val[i]; + } + return vle16_v_u16mf2(tmp, vl); +} +inline vint16mf2_t vwcvt_x_x_v_i16mf2 (vint8mf4_t src, size_t vl) +{ + short tmp[4]; + for (int i = 0; i < 4; ++i) + { + tmp[i] = (short)src.val[i]; + } + return vle16_v_i16mf2(tmp, vl); +} +#endif + +//////////// Types //////////// + +#ifndef __clang__ +struct v_uint8x16 +{ + typedef uchar lane_type; + enum { nlanes = 16 }; + + v_uint8x16() {} + explicit v_uint8x16(vuint8m1_t v) + { + vse8_v_u8m1(val, v, nlanes); + } + v_uint8x16(uchar v0, uchar v1, uchar v2, uchar v3, uchar v4, uchar v5, uchar v6, uchar v7, + uchar v8, uchar v9, uchar v10, uchar v11, uchar v12, uchar v13, uchar v14, uchar v15) + { + uchar v[] = {v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15}; + for (int i = 0; i < nlanes; ++i) + { + val[i] = v[i]; + } + } + operator vuint8m1_t() const + { + return vle8_v_u8m1(val, nlanes); + } + uchar get0() const + { + return val[0]; + } + + uchar val[16]; +}; + +struct v_int8x16 +{ + typedef schar lane_type; + enum { nlanes = 16 }; + + v_int8x16() {} + explicit v_int8x16(vint8m1_t v) + { + vse8_v_i8m1(val, v, nlanes); + } + v_int8x16(schar v0, schar v1, schar v2, schar v3, schar v4, schar v5, schar v6, schar v7, + schar v8, schar v9, schar v10, schar v11, schar v12, schar v13, schar v14, schar v15) + { + schar v[] = {v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15}; + for (int i = 0; i < nlanes; ++i) + { + val[i] = v[i]; + } + } + operator vint8m1_t() const + { + return vle8_v_i8m1(val, nlanes); + } + schar get0() const + { + return val[0]; + } + + schar val[16]; +}; + +struct v_uint16x8 +{ + typedef ushort lane_type; + enum { nlanes = 8 }; + + v_uint16x8() {} + explicit v_uint16x8(vuint16m1_t v) + { + vse16_v_u16m1(val, v, nlanes); + } + v_uint16x8(ushort v0, ushort v1, ushort v2, ushort v3, ushort v4, ushort v5, ushort v6, ushort v7) + { + ushort v[] = {v0, v1, v2, v3, v4, v5, v6, v7}; + for (int i = 0; i < nlanes; ++i) + { + val[i] = v[i]; + } + } + operator vuint16m1_t() const + { + return vle16_v_u16m1(val, nlanes); + } + ushort get0() const + { + return val[0]; + } + + ushort val[8]; +}; + +struct v_int16x8 +{ + typedef short lane_type; + enum { nlanes = 8 }; + + v_int16x8() {} + explicit v_int16x8(vint16m1_t v) + { + vse16_v_i16m1(val, v, nlanes); + } + v_int16x8(short v0, short v1, short v2, short v3, short v4, short v5, short v6, short v7) + { + short v[] = {v0, v1, v2, v3, v4, v5, v6, v7}; + for (int i = 0; i < nlanes; ++i) + { + val[i] = v[i]; + } + } + operator vint16m1_t() const + { + return vle16_v_i16m1(val, nlanes); + } + short get0() const + { + return val[0]; + } + + short val[8]; +}; + +struct v_uint32x4 +{ + typedef unsigned lane_type; + enum { nlanes = 4 }; + + v_uint32x4() {} + explicit v_uint32x4(vuint32m1_t v) + { + vse32_v_u32m1(val, v, nlanes); + } + v_uint32x4(unsigned v0, unsigned v1, unsigned v2, unsigned v3) + { + unsigned v[] = {v0, v1, v2, v3}; + for (int i = 0; i < nlanes; ++i) + { + val[i] = v[i]; + } + } + operator vuint32m1_t() const + { + return vle32_v_u32m1(val, nlanes); + } + unsigned get0() const + { + return val[0]; + } + + unsigned val[4]; +}; + +struct v_int32x4 +{ + typedef int lane_type; + enum { nlanes = 4 }; + + v_int32x4() {} + explicit v_int32x4(vint32m1_t v) + { + vse32_v_i32m1(val, v, nlanes); + } + v_int32x4(int v0, int v1, int v2, int v3) + { + int v[] = {v0, v1, v2, v3}; + for (int i = 0; i < nlanes; ++i) + { + val[i] = v[i]; + } + } + operator vint32m1_t() const + { + return vle32_v_i32m1(val, nlanes); + } + int get0() const + { + return val[0]; + } + int val[4]; +}; + +struct v_float32x4 +{ + typedef float lane_type; + enum { nlanes = 4 }; + + v_float32x4() {} + explicit v_float32x4(vfloat32m1_t v) + { + vse32_v_f32m1(val, v, nlanes); + } + v_float32x4(float v0, float v1, float v2, float v3) + { + float v[] = {v0, v1, v2, v3}; + for (int i = 0; i < nlanes; ++i) + { + val[i] = v[i]; + } + } + operator vfloat32m1_t() const + { + return vle32_v_f32m1(val, nlanes); + } + float get0() const + { + return val[0]; + } + float val[4]; +}; + +struct v_uint64x2 +{ + typedef uint64 lane_type; + enum { nlanes = 2 }; + + v_uint64x2() {} + explicit v_uint64x2(vuint64m1_t v) + { + vse64_v_u64m1(val, v, nlanes); + } + v_uint64x2(uint64 v0, uint64 v1) + { + uint64 v[] = {v0, v1}; + for (int i = 0; i < nlanes; ++i) + { + val[i] = v[i]; + } + } + operator vuint64m1_t() const + { + return vle64_v_u64m1(val, nlanes); + } + uint64 get0() const + { + return val[0]; + } + + uint64 val[2]; +}; + +struct v_int64x2 +{ + typedef int64 lane_type; + enum { nlanes = 2 }; + + v_int64x2() {} + explicit v_int64x2(vint64m1_t v) + { + vse64_v_i64m1(val, v, nlanes); + } + v_int64x2(int64 v0, int64 v1) + { + int64 v[] = {v0, v1}; + for (int i = 0; i < nlanes; ++i) + { + val[i] = v[i]; + } + } + operator vint64m1_t() const + { + return vle64_v_i64m1(val, nlanes); + } + int64 get0() const + { + return val[0]; + } + + int64 val[2]; +}; + +#if CV_SIMD128_64F +struct v_float64x2 +{ + typedef double lane_type; + enum { nlanes = 2 }; + + v_float64x2() {} + explicit v_float64x2(vfloat64m1_t v) + { + vse64_v_f64m1(val, v, nlanes); + } + v_float64x2(double v0, double v1) + { + double v[] = {v0, v1}; + for (int i = 0; i < nlanes; ++i) + { + val[i] = v[i]; + } + } + operator vfloat64m1_t() const + { + return vle64_v_f64m1(val, nlanes); + } + double get0() const + { + return val[0]; + } + + double val[2]; +}; +#endif +#else +struct v_uint8x16 +{ + typedef uchar lane_type; + enum { nlanes = 16 }; + + v_uint8x16() {} + explicit v_uint8x16(vuint8m1_t v) + { + *pval = v; + } + v_uint8x16(uchar v0, uchar v1, uchar v2, uchar v3, uchar v4, uchar v5, uchar v6, uchar v7, + uchar v8, uchar v9, uchar v10, uchar v11, uchar v12, uchar v13, uchar v14, uchar v15) + { + uchar v[] = {v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15}; + *pval = vle8_v_u8m1(v, nlanes); + } + operator vuint8m1_t() const + { + return *pval; + } + uchar get0() const + { + return vmv_x(*pval); + } + inline v_uint8x16& operator=(const v_uint8x16& vec) { + *pval = *(vec.pval); + return *this; + } + inline v_uint8x16(const v_uint8x16& vec) { + *pval = *(vec.pval); + } + uchar val[16]; + vuint8m1_t* pval = (vuint8m1_t*)val; +}; + +struct v_int8x16 +{ + typedef schar lane_type; + enum { nlanes = 16 }; + + v_int8x16() {} + explicit v_int8x16(vint8m1_t v) + { + *pval = v; + } + v_int8x16(schar v0, schar v1, schar v2, schar v3, schar v4, schar v5, schar v6, schar v7, + schar v8, schar v9, schar v10, schar v11, schar v12, schar v13, schar v14, schar v15) + { + schar v[] = {v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15}; + *pval = vle8_v_i8m1(v, nlanes); + } + operator vint8m1_t() const + { + return *pval; + } + schar get0() const + { + return vmv_x(*pval); + } + inline v_int8x16& operator=(const v_int8x16& vec) { + *pval = *(vec.pval); + return *this; + } + inline v_int8x16(const v_int8x16& vec) { + *pval = *(vec.pval); + } + schar val[16]; + vint8m1_t* pval = (vint8m1_t*)val; +}; + +struct v_uint16x8 +{ + typedef ushort lane_type; + enum { nlanes = 8 }; + + v_uint16x8() {} + explicit v_uint16x8(vuint16m1_t v) + { + *pval = v; + } + v_uint16x8(ushort v0, ushort v1, ushort v2, ushort v3, ushort v4, ushort v5, ushort v6, ushort v7) + { + ushort v[] = {v0, v1, v2, v3, v4, v5, v6, v7}; + *pval = vle16_v_u16m1(v, nlanes); + } + operator vuint16m1_t() const + { + return *pval; + } + ushort get0() const + { + return vmv_x(*pval); + } + + inline v_uint16x8& operator=(const v_uint16x8& vec) { + *pval = *(vec.pval); + return *this; + } + inline v_uint16x8(const v_uint16x8& vec) { + *pval = *(vec.pval); + } + ushort val[8]; + vuint16m1_t* pval = (vuint16m1_t*)val; +}; + +struct v_int16x8 +{ + typedef short lane_type; + enum { nlanes = 8 }; + + v_int16x8() {} + explicit v_int16x8(vint16m1_t v) + { + *pval = v; + } + v_int16x8(short v0, short v1, short v2, short v3, short v4, short v5, short v6, short v7) + { + short v[] = {v0, v1, v2, v3, v4, v5, v6, v7}; + *pval = vle16_v_i16m1(v, nlanes); + } + operator vint16m1_t() const + { + return *pval; + } + short get0() const + { + return vmv_x(*pval); + } + + inline v_int16x8& operator=(const v_int16x8& vec) { + *pval = *(vec.pval); + return *this; + } + inline v_int16x8(const v_int16x8& vec) { + *pval = *(vec.pval); + } + short val[8]; + vint16m1_t* pval = (vint16m1_t*)val; +}; + +struct v_uint32x4 +{ + typedef unsigned lane_type; + enum { nlanes = 4 }; + + v_uint32x4() {} + explicit v_uint32x4(vuint32m1_t v) + { + *pval = v; + } + v_uint32x4(unsigned v0, unsigned v1, unsigned v2, unsigned v3) + { + unsigned v[] = {v0, v1, v2, v3}; + *pval = vle32_v_u32m1(v, nlanes); + } + operator vuint32m1_t() const + { + return *pval; + } + unsigned get0() const + { + return vmv_x(*pval); + } + + inline v_uint32x4& operator=(const v_uint32x4& vec) { + *pval = *(vec.pval); + return *this; + } + inline v_uint32x4(const v_uint32x4& vec) { + *pval = *(vec.pval); + } + unsigned val[4]; + vuint32m1_t* pval = (vuint32m1_t*)val; +}; + +struct v_int32x4 +{ + typedef int lane_type; + enum { nlanes = 4 }; + + v_int32x4() {} + explicit v_int32x4(vint32m1_t v) + { + *pval = v; + } + v_int32x4(int v0, int v1, int v2, int v3) + { + int v[] = {v0, v1, v2, v3}; + *pval = vle32_v_i32m1(v, nlanes); + } + operator vint32m1_t() const + { + return *pval; + } + int get0() const + { + return vmv_x(*pval); + } + + inline v_int32x4& operator=(const v_int32x4& vec) { + *pval = *(vec.pval); + return *this; + } + inline v_int32x4(const v_int32x4& vec) { + *pval = *(vec.pval); + } + int val[4]; + vint32m1_t* pval = (vint32m1_t*)val; +}; + +struct v_float32x4 +{ + typedef float lane_type; + enum { nlanes = 4 }; + + v_float32x4() {} + explicit v_float32x4(vfloat32m1_t v) + { + *pval = v; + } + v_float32x4(float v0, float v1, float v2, float v3) + { + float v[] = {v0, v1, v2, v3}; + *pval = vle32_v_f32m1(v, nlanes); + } + operator vfloat32m1_t() const + { + return *pval; + } + float get0() const + { + return vfmv_f(*pval); + } + inline v_float32x4& operator=(const v_float32x4& vec) { + *pval = *(vec.pval); + return *this; + } + inline v_float32x4(const v_float32x4& vec) { + *pval = *(vec.pval); + } + float val[4]; + vfloat32m1_t* pval = (vfloat32m1_t*)val; +}; + +struct v_uint64x2 +{ + typedef uint64 lane_type; + enum { nlanes = 2 }; + + v_uint64x2() {} + explicit v_uint64x2(vuint64m1_t v) + { + *pval = v; + } + v_uint64x2(uint64 v0, uint64 v1) + { + uint64 v[] = {v0, v1}; + *pval = vle64_v_u64m1(v, nlanes); + } + operator vuint64m1_t() const + { + return *pval; + } + uint64 get0() const + { + return vmv_x(*pval); + } + + inline v_uint64x2& operator=(const v_uint64x2& vec) { + *pval = *(vec.pval); + return *this; + } + inline v_uint64x2(const v_uint64x2& vec) { + *pval = *(vec.pval); + } + uint64 val[2]; + vuint64m1_t* pval = (vuint64m1_t*)val; +}; + +struct v_int64x2 +{ + typedef int64 lane_type; + enum { nlanes = 2 }; + + v_int64x2() {} + explicit v_int64x2(vint64m1_t v) + { + *pval = v; + } + v_int64x2(int64 v0, int64 v1) + { + int64 v[] = {v0, v1}; + *pval = vle64_v_i64m1(v, nlanes); + } + operator vint64m1_t() const + { + return *pval; + } + int64 get0() const + { + return vmv_x(*pval); + } + + inline v_int64x2& operator=(const v_int64x2& vec) { + *pval = *(vec.pval); + return *this; + } + inline v_int64x2(const v_int64x2& vec) { + *pval = *(vec.pval); + } + int64 val[2]; + vint64m1_t* pval = (vint64m1_t*)val; +}; + +#if CV_SIMD128_64F +struct v_float64x2 +{ + typedef double lane_type; + enum { nlanes = 2 }; + + v_float64x2() {} + explicit v_float64x2(vfloat64m1_t v) + { + *pval = v; + } + v_float64x2(double v0, double v1) + { + double v[] = {v0, v1}; + *pval = vle64_v_f64m1(v, nlanes); + } + operator vfloat64m1_t() const + { + return *pval; + } + double get0() const + { + return vfmv_f(*pval); + } + + inline v_float64x2& operator=(const v_float64x2& vec) { + *pval = *(vec.pval); + return *this; + } + inline v_float64x2(const v_float64x2& vec) { + *pval = *(vec.pval); + } + double val[2]; + vfloat64m1_t* pval = (vfloat64m1_t*)val; +}; +#endif // CV_SIMD128_64F +#endif // __clang__ + +//////////// Initial //////////// + +#define OPENCV_HAL_IMPL_RVV_INIT_INTEGER(_Tpvec, _Tp, suffix1, suffix2, vl) \ +inline v_##_Tpvec v_setzero_##suffix1() \ +{ \ + return v_##_Tpvec(vmv_v_x_##suffix2##m1(0, vl)); \ +} \ +inline v_##_Tpvec v_setall_##suffix1(_Tp v) \ +{ \ + return v_##_Tpvec(vmv_v_x_##suffix2##m1(v, vl)); \ +} + +OPENCV_HAL_IMPL_RVV_INIT_INTEGER(uint8x16, uchar, u8, u8, 16) +OPENCV_HAL_IMPL_RVV_INIT_INTEGER(int8x16, schar, s8, i8, 16) +OPENCV_HAL_IMPL_RVV_INIT_INTEGER(uint16x8, ushort, u16, u16, 8) +OPENCV_HAL_IMPL_RVV_INIT_INTEGER(int16x8, short, s16, i16, 8) +OPENCV_HAL_IMPL_RVV_INIT_INTEGER(uint32x4, unsigned, u32, u32, 4) +OPENCV_HAL_IMPL_RVV_INIT_INTEGER(int32x4, int, s32, i32, 4) +OPENCV_HAL_IMPL_RVV_INIT_INTEGER(uint64x2, uint64, u64, u64, 2) +OPENCV_HAL_IMPL_RVV_INIT_INTEGER(int64x2, int64, s64, i64, 2) + +#define OPENCV_HAL_IMPL_RVV_INIT_FP(_Tpv, _Tp, suffix, vl) \ +inline v_##_Tpv v_setzero_##suffix() \ +{ \ + return v_##_Tpv(vfmv_v_f_##suffix##m1(0, vl)); \ +} \ +inline v_##_Tpv v_setall_##suffix(_Tp v) \ +{ \ + return v_##_Tpv(vfmv_v_f_##suffix##m1(v, vl)); \ +} + +OPENCV_HAL_IMPL_RVV_INIT_FP(float32x4, float, f32, 4) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_RVV_INIT_FP(float64x2, double, f64, 2) +#endif + +//////////// Reinterpret //////////// + +#define OPENCV_HAL_IMPL_RVV_SELF_REINTERPRET(_Tpvec, suffix) \ +inline v_##_Tpvec v_reinterpret_as_##suffix(const v_##_Tpvec& v) { return v; } + +OPENCV_HAL_IMPL_RVV_SELF_REINTERPRET(uint8x16, u8) +OPENCV_HAL_IMPL_RVV_SELF_REINTERPRET(int8x16, s8) +OPENCV_HAL_IMPL_RVV_SELF_REINTERPRET(uint16x8, u16) +OPENCV_HAL_IMPL_RVV_SELF_REINTERPRET(int16x8, s16) +OPENCV_HAL_IMPL_RVV_SELF_REINTERPRET(uint32x4, u32) +OPENCV_HAL_IMPL_RVV_SELF_REINTERPRET(int32x4, s32) +OPENCV_HAL_IMPL_RVV_SELF_REINTERPRET(float32x4, f32) +OPENCV_HAL_IMPL_RVV_SELF_REINTERPRET(uint64x2, u64) +OPENCV_HAL_IMPL_RVV_SELF_REINTERPRET(int64x2, s64) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_RVV_SELF_REINTERPRET(float64x2, f64) +#endif + +#define OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(_Tpvec1, _Tpvec2, suffix1, suffix2, nsuffix1, nsuffix2) \ +inline v_##_Tpvec1 v_reinterpret_as_##suffix1(const v_##_Tpvec2& v) \ +{ \ + return v_##_Tpvec1(vreinterpret_v_##nsuffix2##m1_##nsuffix1##m1(v));\ +} \ +inline v_##_Tpvec2 v_reinterpret_as_##suffix2(const v_##_Tpvec1& v) \ +{ \ + return v_##_Tpvec2(vreinterpret_v_##nsuffix1##m1_##nsuffix2##m1(v));\ +} + +OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(uint8x16, int8x16, u8, s8, u8, i8) +OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(uint16x8, int16x8, u16, s16, u16, i16) +OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(uint32x4, int32x4, u32, s32, u32, i32) +OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(uint32x4, float32x4, u32, f32, u32, f32) +OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(int32x4, float32x4, s32, f32, i32, f32) +OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(uint64x2, int64x2, u64, s64, u64, i64) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(uint64x2, float64x2, u64, f64, u64, f64) +OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(int64x2, float64x2, s64, f64, i64, f64) +#endif +OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(uint8x16, uint16x8, u8, u16, u8, u16) +OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(uint8x16, uint32x4, u8, u32, u8, u32) +OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(uint8x16, uint64x2, u8, u64, u8, u64) +OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(uint16x8, uint32x4, u16, u32, u16, u32) +OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(uint16x8, uint64x2, u16, u64, u16, u64) +OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(uint32x4, uint64x2, u32, u64, u32, u64) +OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(int8x16, int16x8, s8, s16, i8, i16) +OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(int8x16, int32x4, s8, s32, i8, i32) +OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(int8x16, int64x2, s8, s64, i8, i64) +OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(int16x8, int32x4, s16, s32, i16, i32) +OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(int16x8, int64x2, s16, s64, i16, i64) +OPENCV_HAL_IMPL_RVV_NATIVE_REINTERPRET(int32x4, int64x2, s32, s64, i32, i64) + + +#define OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(_Tpvec1, _Tpvec2, suffix1, suffix2, nsuffix1, nsuffix2, width1, width2) \ +inline v_##_Tpvec1 v_reinterpret_as_##suffix1(const v_##_Tpvec2& v) \ +{ \ + return v_##_Tpvec1(vreinterpret_v_##nsuffix1##width2##m1_##nsuffix1##width1##m1(vreinterpret_v_##nsuffix2##width2##m1_##nsuffix1##width2##m1(v)));\ +} \ +inline v_##_Tpvec2 v_reinterpret_as_##suffix2(const v_##_Tpvec1& v) \ +{ \ + return v_##_Tpvec2(vreinterpret_v_##nsuffix1##width2##m1_##nsuffix2##width2##m1(vreinterpret_v_##nsuffix1##width1##m1_##nsuffix1##width2##m1(v)));\ +} + +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(uint8x16, int16x8, u8, s16, u, i, 8, 16) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(uint8x16, int32x4, u8, s32, u, i, 8, 32) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(uint8x16, int64x2, u8, s64, u, i, 8, 64) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(uint16x8, int8x16, u16, s8, u, i, 16, 8) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(uint16x8, int32x4, u16, s32, u, i, 16, 32) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(uint16x8, int64x2, u16, s64, u, i, 16, 64) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(uint32x4, int8x16, u32, s8, u, i, 32, 8) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(uint32x4, int16x8, u32, s16, u, i, 32, 16) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(uint32x4, int64x2, u32, s64, u, i, 32, 64) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(uint64x2, int8x16, u64, s8, u, i, 64, 8) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(uint64x2, int16x8, u64, s16, u, i, 64, 16) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(uint64x2, int32x4, u64, s32, u, i, 64, 32) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(uint8x16, float32x4, u8, f32, u, f, 8, 32) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(uint16x8, float32x4, u16, f32, u, f, 16, 32) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(uint64x2, float32x4, u64, f32, u, f, 64, 32) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(int8x16, float32x4, s8, f32, i, f, 8, 32) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(int16x8, float32x4, s16, f32, i, f, 16, 32) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(int64x2, float32x4, s64, f32, i, f, 64, 32) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(uint8x16, float64x2, u8, f64, u, f, 8, 64) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(uint16x8, float64x2, u16, f64, u, f, 16, 64) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(uint32x4, float64x2, u32, f64, u, f, 32, 64) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(int8x16, float64x2, s8, f64, i, f, 8, 64) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(int16x8, float64x2, s16, f64, i, f, 16, 64) +OPENCV_HAL_IMPL_RVV_TWO_TIMES_REINTERPRET(int32x4, float64x2, s32, f64, i, f, 32, 64) + +// Three times reinterpret +inline v_float32x4 v_reinterpret_as_f32(const v_float64x2& v) \ +{ \ + return v_float32x4(vreinterpret_v_u32m1_f32m1(vreinterpret_v_u64m1_u32m1(vreinterpret_v_f64m1_u64m1(v))));\ +} \ +inline v_float64x2 v_reinterpret_as_f64(const v_float32x4& v) \ +{ \ + return v_float64x2(vreinterpret_v_u64m1_f64m1(vreinterpret_v_u32m1_u64m1(vreinterpret_v_f32m1_u32m1(v))));\ +} + +////////////// Extract ////////////// + +#define OPENCV_HAL_IMPL_RVV_EXTRACT_INTEGER(_Tpvec, _Tp, suffix, vmv, vl) \ +template \ +inline _Tpvec v_extract(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(vslideup_vx_##suffix##m1(vslidedown_vx_##suffix##m1(vmv_v_x_##suffix##m1(0, vl), a, s, vl), b, _Tpvec::nlanes - s, vl)); \ +} \ +template inline _Tp v_extract_n(_Tpvec v) \ +{ \ + return _Tp(vmv(vslidedown_vx_##suffix##m1(vmv_v_x_##suffix##m1(0, vl), v, i, vl))); \ +} + + +OPENCV_HAL_IMPL_RVV_EXTRACT_INTEGER(v_uint8x16, uchar, u8, vmv_x_s_u8m1_u8, 16) +OPENCV_HAL_IMPL_RVV_EXTRACT_INTEGER(v_int8x16, schar, i8, vmv_x_s_i8m1_i8, 16) +OPENCV_HAL_IMPL_RVV_EXTRACT_INTEGER(v_uint16x8, ushort, u16, vmv_x_s_u16m1_u16, 8) +OPENCV_HAL_IMPL_RVV_EXTRACT_INTEGER(v_int16x8, short, i16, vmv_x_s_i16m1_i16, 8) +OPENCV_HAL_IMPL_RVV_EXTRACT_INTEGER(v_uint32x4, uint, u32, vmv_x_s_u32m1_u32, 4) +OPENCV_HAL_IMPL_RVV_EXTRACT_INTEGER(v_int32x4, int, i32, vmv_x_s_i32m1_i32, 4) +OPENCV_HAL_IMPL_RVV_EXTRACT_INTEGER(v_uint64x2, uint64, u64, vmv_x_s_u64m1_u64, 2) +OPENCV_HAL_IMPL_RVV_EXTRACT_INTEGER(v_int64x2, int64, i64, vmv_x_s_i64m1_i64, 2) + +#define OPENCV_HAL_IMPL_RVV_EXTRACT_FP(_Tpvec, _Tp, suffix, vmv, vl) \ +template \ +inline _Tpvec v_extract(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(vslideup_vx_##suffix##m1(vslidedown_vx_##suffix##m1(vfmv_v_f_##suffix##m1(0, vl), a, s, vl), b, _Tpvec::nlanes - s, vl)); \ +} \ +template inline _Tp v_extract_n(_Tpvec v) \ +{ \ + return _Tp(vmv(vslidedown_vx_##suffix##m1(vfmv_v_f_##suffix##m1(0, vl), v, i, vl))); \ +} + +OPENCV_HAL_IMPL_RVV_EXTRACT_FP(v_float32x4, float, f32, vfmv_f_s_f32m1_f32, 4) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_RVV_EXTRACT_FP(v_float64x2, double, f64, vfmv_f_s_f64m1_f64, 2) +#endif + +////////////// Load/Store ////////////// + +#define OPENCV_HAL_IMPL_RVV_LOADSTORE_OP(_Tpvec, _nTpvec, _Tp, hvl, vl, width, suffix, vmv) \ +inline _Tpvec v_load(const _Tp* ptr) \ +{ \ + return _Tpvec(vle##width##_v_##suffix##m1(ptr, vl)); \ +} \ +inline _Tpvec v_load_aligned(const _Tp* ptr) \ +{ \ + return _Tpvec(vle##width##_v_##suffix##m1(ptr, vl)); \ +} \ +inline _Tpvec v_load_low(const _Tp* ptr) \ +{ \ + _Tpvec res = _Tpvec(vle##width##_v_##suffix##m1(ptr, hvl)); \ + return res; \ +} \ +inline void v_store(_Tp* ptr, const _Tpvec& a) \ +{ \ + vse##width##_v_##suffix##m1(ptr, a, vl); \ +} \ +inline void v_store_aligned(_Tp* ptr, const _Tpvec& a) \ +{ \ + vse##width##_v_##suffix##m1(ptr, a, vl); \ +} \ +inline void v_store_aligned_nocache(_Tp* ptr, const _Tpvec& a) \ +{ \ + vse##width##_v_##suffix##m1(ptr, a, vl); \ +} \ +inline void v_store(_Tp* ptr, const _Tpvec& a, hal::StoreMode /*mode*/) \ +{ \ + vse##width##_v_##suffix##m1(ptr, a, vl); \ +} \ +inline void v_store_low(_Tp* ptr, const _Tpvec& a) \ +{ \ + vse##width##_v_##suffix##m1(ptr, a, hvl); \ +} \ +inline void v_store_high(_Tp* ptr, const _Tpvec& a) \ +{ \ + vse##width##_v_##suffix##m1(ptr, vslidedown_vx_##suffix##m1(vmv(0, vl), a, hvl, vl), hvl); \ +} + +OPENCV_HAL_IMPL_RVV_LOADSTORE_OP(v_uint8x16, vuint8m1_t, uchar, 8, 16, 8, u8, vmv_v_x_u8m1) +OPENCV_HAL_IMPL_RVV_LOADSTORE_OP(v_int8x16, vint8m1_t, schar, 8, 16, 8, i8, vmv_v_x_i8m1) +OPENCV_HAL_IMPL_RVV_LOADSTORE_OP(v_uint16x8, vuint16m1_t, ushort, 4, 8, 16, u16, vmv_v_x_u16m1) +OPENCV_HAL_IMPL_RVV_LOADSTORE_OP(v_int16x8, vint16m1_t, short, 4, 8, 16, i16, vmv_v_x_i16m1) +OPENCV_HAL_IMPL_RVV_LOADSTORE_OP(v_uint32x4, vuint32m1_t, unsigned, 2, 4, 32, u32, vmv_v_x_u32m1) +OPENCV_HAL_IMPL_RVV_LOADSTORE_OP(v_int32x4, vint32m1_t, int, 2, 4, 32, i32, vmv_v_x_i32m1) +OPENCV_HAL_IMPL_RVV_LOADSTORE_OP(v_uint64x2, vuint64m1_t, uint64, 1, 2, 64, u64, vmv_v_x_u64m1) +OPENCV_HAL_IMPL_RVV_LOADSTORE_OP(v_int64x2, vint64m1_t, int64, 1, 2, 64, i64, vmv_v_x_i64m1) +OPENCV_HAL_IMPL_RVV_LOADSTORE_OP(v_float32x4, vfloat32m1_t, float, 2, 4, 32, f32, vfmv_v_f_f32m1) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_RVV_LOADSTORE_OP(v_float64x2, vfloat64m1_t, double, 1, 2, 64, f64, vfmv_v_f_f64m1) +#endif + +inline v_int8x16 v_load_halves(const schar* ptr0, const schar* ptr1) +{ + schar elems[16] = + { + ptr0[0], ptr0[1], ptr0[2], ptr0[3], ptr0[4], ptr0[5], ptr0[6], ptr0[7], + ptr1[0], ptr1[1], ptr1[2], ptr1[3], ptr1[4], ptr1[5], ptr1[6], ptr1[7] + }; + return v_int8x16(vle8_v_i8m1(elems, 16)); +} +inline v_uint8x16 v_load_halves(const uchar* ptr0, const uchar* ptr1) { return v_reinterpret_as_u8(v_load_halves((schar*)ptr0, (schar*)ptr1)); } + +inline v_int16x8 v_load_halves(const short* ptr0, const short* ptr1) +{ + short elems[8] = + { + ptr0[0], ptr0[1], ptr0[2], ptr0[3], ptr1[0], ptr1[1], ptr1[2], ptr1[3] + }; + return v_int16x8(vle16_v_i16m1(elems, 8)); +} +inline v_uint16x8 v_load_halves(const ushort* ptr0, const ushort* ptr1) { return v_reinterpret_as_u16(v_load_halves((short*)ptr0, (short*)ptr1)); } + +inline v_int32x4 v_load_halves(const int* ptr0, const int* ptr1) +{ + int elems[4] = + { + ptr0[0], ptr0[1], ptr1[0], ptr1[1] + }; + return v_int32x4(vle32_v_i32m1(elems, 4)); +} +inline v_float32x4 v_load_halves(const float* ptr0, const float* ptr1) +{ + float elems[4] = + { + ptr0[0], ptr0[1], ptr1[0], ptr1[1] + }; + return v_float32x4(vle32_v_f32m1(elems, 4)); +} +inline v_uint32x4 v_load_halves(const unsigned* ptr0, const unsigned* ptr1) { return v_reinterpret_as_u32(v_load_halves((int*)ptr0, (int*)ptr1)); } + +inline v_int64x2 v_load_halves(const int64* ptr0, const int64* ptr1) +{ + int64 elems[2] = + { + ptr0[0], ptr1[0] + }; + return v_int64x2(vle64_v_i64m1(elems, 2)); +} +inline v_uint64x2 v_load_halves(const uint64* ptr0, const uint64* ptr1) { return v_reinterpret_as_u64(v_load_halves((int64*)ptr0, (int64*)ptr1)); } + +#if CV_SIMD128_64F +inline v_float64x2 v_load_halves(const double* ptr0, const double* ptr1) +{ + double elems[2] = + { + ptr0[0], ptr1[0] + }; + return v_float64x2(vle64_v_f64m1(elems, 2)); +} +#endif + + +////////////// Lookup table access //////////////////// + +inline v_int8x16 v_lut(const schar* tab, const int* idx) +{ + schar elems[16] = + { + tab[idx[ 0]], + tab[idx[ 1]], + tab[idx[ 2]], + tab[idx[ 3]], + tab[idx[ 4]], + tab[idx[ 5]], + tab[idx[ 6]], + tab[idx[ 7]], + tab[idx[ 8]], + tab[idx[ 9]], + tab[idx[10]], + tab[idx[11]], + tab[idx[12]], + tab[idx[13]], + tab[idx[14]], + tab[idx[15]] + }; + return v_int8x16(vle8_v_i8m1(elems, 16)); +} +inline v_int8x16 v_lut_pairs(const schar* tab, const int* idx) +{ + schar elems[16] = + { + tab[idx[0]], + tab[idx[0] + 1], + tab[idx[1]], + tab[idx[1] + 1], + tab[idx[2]], + tab[idx[2] + 1], + tab[idx[3]], + tab[idx[3] + 1], + tab[idx[4]], + tab[idx[4] + 1], + tab[idx[5]], + tab[idx[5] + 1], + tab[idx[6]], + tab[idx[6] + 1], + tab[idx[7]], + tab[idx[7] + 1] + }; + return v_int8x16(vle8_v_i8m1(elems, 16)); +} +inline v_int8x16 v_lut_quads(const schar* tab, const int* idx) +{ + schar elems[16] = + { + tab[idx[0]], + tab[idx[0] + 1], + tab[idx[0] + 2], + tab[idx[0] + 3], + tab[idx[1]], + tab[idx[1] + 1], + tab[idx[1] + 2], + tab[idx[1] + 3], + tab[idx[2]], + tab[idx[2] + 1], + tab[idx[2] + 2], + tab[idx[2] + 3], + tab[idx[3]], + tab[idx[3] + 1], + tab[idx[3] + 2], + tab[idx[3] + 3] + }; + return v_int8x16(vle8_v_i8m1(elems, 16)); +} +inline v_uint8x16 v_lut(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut((schar*)tab, idx)); } +inline v_uint8x16 v_lut_pairs(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut_pairs((schar*)tab, idx)); } +inline v_uint8x16 v_lut_quads(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut_quads((schar*)tab, idx)); } + +inline v_int16x8 v_lut(const short* tab, const int* idx) +{ + short elems[8] = + { + tab[idx[0]], + tab[idx[1]], + tab[idx[2]], + tab[idx[3]], + tab[idx[4]], + tab[idx[5]], + tab[idx[6]], + tab[idx[7]] + }; + return v_int16x8(vle16_v_i16m1(elems, 8)); +} +inline v_int16x8 v_lut_pairs(const short* tab, const int* idx) +{ + short elems[8] = + { + tab[idx[0]], + tab[idx[0] + 1], + tab[idx[1]], + tab[idx[1] + 1], + tab[idx[2]], + tab[idx[2] + 1], + tab[idx[3]], + tab[idx[3] + 1] + }; + return v_int16x8(vle16_v_i16m1(elems, 8)); +} +inline v_int16x8 v_lut_quads(const short* tab, const int* idx) +{ + short elems[8] = + { + tab[idx[0]], + tab[idx[0] + 1], + tab[idx[0] + 2], + tab[idx[0] + 3], + tab[idx[1]], + tab[idx[1] + 1], + tab[idx[1] + 2], + tab[idx[1] + 3] + }; + return v_int16x8(vle16_v_i16m1(elems, 8)); +} +inline v_uint16x8 v_lut(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut((short*)tab, idx)); } +inline v_uint16x8 v_lut_pairs(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut_pairs((short*)tab, idx)); } +inline v_uint16x8 v_lut_quads(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut_quads((short*)tab, idx)); } + +inline v_int32x4 v_lut(const int* tab, const int* idx) +{ + int elems[4] = + { + tab[idx[0]], + tab[idx[1]], + tab[idx[2]], + tab[idx[3]] + }; + return v_int32x4(vle32_v_i32m1(elems, 4)); +} +inline v_int32x4 v_lut_pairs(const int* tab, const int* idx) +{ + int elems[4] = + { + tab[idx[0]], + tab[idx[0] + 1], + tab[idx[1]], + tab[idx[1] + 1] + }; + return v_int32x4(vle32_v_i32m1(elems, 4)); +} +inline v_int32x4 v_lut_quads(const int* tab, const int* idx) +{ + return v_int32x4(vle32_v_i32m1(tab + idx[0], 4)); +} + +inline v_uint32x4 v_lut(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut((int*)tab, idx)); } +inline v_uint32x4 v_lut_pairs(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut_pairs((int*)tab, idx)); } +inline v_uint32x4 v_lut_quads(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut_quads((int*)tab, idx)); } + +inline v_int64x2 v_lut(const int64_t* tab, const int* idx) +{ + int64_t elems[2] = + { + tab[idx[0]], + tab[idx[1]] + }; + return v_int64x2(vle64_v_i64m1(elems, 2)); +} +inline v_int64x2 v_lut_pairs(const int64* tab, const int* idx) +{ + return v_int64x2(vle64_v_i64m1(tab + idx[0], 2)); +} +inline v_uint64x2 v_lut(const uint64* tab, const int* idx) { return v_reinterpret_as_u64(v_lut((const int64_t *)tab, idx)); } +inline v_uint64x2 v_lut_pairs(const uint64* tab, const int* idx) { return v_reinterpret_as_u64(v_lut_pairs((const int64_t *)tab, idx)); } + +inline v_float32x4 v_lut(const float* tab, const int* idx) +{ + float elems[4] = + { + tab[idx[0]], + tab[idx[1]], + tab[idx[2]], + tab[idx[3]] + }; + return v_float32x4(vle32_v_f32m1(elems, 4)); +} +inline v_float32x4 v_lut_pairs(const float* tab, const int* idx) +{ + float elems[4] = + { + tab[idx[0]], + tab[idx[0] + 1], + tab[idx[1]], + tab[idx[1] + 1] + }; + return v_float32x4(vle32_v_f32m1(elems, 4)); +} +inline v_float32x4 v_lut_quads(const float* tab, const int* idx) +{ + return v_float32x4(vle32_v_f32m1(tab + idx[0], 4)); +} + +inline v_int32x4 v_lut(const int* tab, const v_int32x4& idxvec) +{ + int elems[4] = + { + tab[v_extract_n<0>(idxvec)], + tab[v_extract_n<1>(idxvec)], + tab[v_extract_n<2>(idxvec)], + tab[v_extract_n<3>(idxvec)] + }; + return v_int32x4(vle32_v_i32m1(elems, 4)); +} + +inline v_uint32x4 v_lut(const unsigned* tab, const v_int32x4& idxvec) +{ + unsigned elems[4] = + { + tab[v_extract_n<0>(idxvec)], + tab[v_extract_n<1>(idxvec)], + tab[v_extract_n<2>(idxvec)], + tab[v_extract_n<3>(idxvec)] + }; + return v_uint32x4(vle32_v_u32m1(elems, 4)); +} + +inline v_float32x4 v_lut(const float* tab, const v_int32x4& idxvec) +{ + float elems[4] = + { + tab[v_extract_n<0>(idxvec)], + tab[v_extract_n<1>(idxvec)], + tab[v_extract_n<2>(idxvec)], + tab[v_extract_n<3>(idxvec)] + }; + return v_float32x4(vle32_v_f32m1(elems, 4)); +} + +inline void v_lut_deinterleave(const float* tab, const v_int32x4& idxvec, v_float32x4& x, v_float32x4& y) +{ + int idx[4]; + v_store_aligned(idx, idxvec); + + x = v_float32x4(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]]); + y = v_float32x4(tab[idx[0]+1], tab[idx[1]+1], tab[idx[2]+1], tab[idx[3]+1]); +} + +#if CV_SIMD128_64F +inline v_float64x2 v_lut(const double* tab, const int* idx) +{ + double elems[2] = + { + tab[idx[0]], + tab[idx[1]] + }; + return v_float64x2(vle64_v_f64m1(elems, 2)); +} + +inline v_float64x2 v_lut_pairs(const double* tab, const int* idx) +{ + return v_float64x2(vle64_v_f64m1(tab + idx[0], 2)); +} + +inline v_float64x2 v_lut(const double* tab, const v_int32x4& idxvec) +{ + double elems[2] = + { + tab[v_extract_n<0>(idxvec)], + tab[v_extract_n<1>(idxvec)] + }; + return v_float64x2(vle64_v_f64m1(elems, 2)); +} + +inline void v_lut_deinterleave(const double* tab, const v_int32x4& idxvec, v_float64x2& x, v_float64x2& y) +{ + int idx[4] = {0}; + v_store_aligned(idx, idxvec); + + x = v_float64x2(tab[idx[0]], tab[idx[1]]); + y = v_float64x2(tab[idx[0]+1], tab[idx[1]+1]); +} +#endif + +////////////// Pack boolean //////////////////// + +inline v_uint8x16 v_pack_b(const v_uint16x8& a, const v_uint16x8& b) +{ + ushort ptr[16] = {0}; + v_store(ptr, a); + v_store(ptr + 8, b); + return v_uint8x16(vnsrl_wx_u8m1(vle16_v_u16m2(ptr, 16), 0, 16)); +} + +inline v_uint8x16 v_pack_b(const v_uint32x4& a, const v_uint32x4& b, + const v_uint32x4& c, const v_uint32x4& d) +{ + unsigned ptr[16] = {0}; + v_store(ptr, a); + v_store(ptr + 4, b); + v_store(ptr + 8, c); + v_store(ptr + 12, d); + return v_uint8x16(vnsrl_wx_u8m1(vnsrl_wx_u16m2(vle32_v_u32m4(ptr, 16), 0, 16), 0, 16)); +} + +inline v_uint8x16 v_pack_b(const v_uint64x2& a, const v_uint64x2& b, const v_uint64x2& c, + const v_uint64x2& d, const v_uint64x2& e, const v_uint64x2& f, + const v_uint64x2& g, const v_uint64x2& h) +{ + uint64 ptr[16] = {0}; + v_store(ptr, a); + v_store(ptr + 2, b); + v_store(ptr + 4, c); + v_store(ptr + 6, d); + v_store(ptr + 8, e); + v_store(ptr + 10, f); + v_store(ptr + 12, g); + v_store(ptr + 14, h); + return v_uint8x16(vnsrl_wx_u8m1(vnsrl_wx_u16m2(vnsrl_wx_u32m4(vle64_v_u64m8(ptr, 16), 0, 16), 0, 16), 0, 16)); +} + +////////////// Arithmetics ////////////// +#define OPENCV_HAL_IMPL_RVV_BIN_OP(bin_op, _Tpvec, intrin, vl) \ +inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(intrin(a, b, vl)); \ +} \ +inline _Tpvec& operator bin_op##= (_Tpvec& a, const _Tpvec& b) \ +{ \ + a = _Tpvec(intrin(a, b, vl)); \ + return a; \ +} + +OPENCV_HAL_IMPL_RVV_BIN_OP(+, v_uint8x16, vsaddu_vv_u8m1, 16) +OPENCV_HAL_IMPL_RVV_BIN_OP(-, v_uint8x16, vssubu_vv_u8m1, 16) +OPENCV_HAL_IMPL_RVV_BIN_OP(/, v_uint8x16, vdivu_vv_u8m1, 16) +OPENCV_HAL_IMPL_RVV_BIN_OP(+, v_int8x16, vsadd_vv_i8m1, 16) +OPENCV_HAL_IMPL_RVV_BIN_OP(-, v_int8x16, vssub_vv_i8m1, 16) +OPENCV_HAL_IMPL_RVV_BIN_OP(/, v_int8x16, vdiv_vv_i8m1, 16) +OPENCV_HAL_IMPL_RVV_BIN_OP(+, v_uint16x8, vsaddu_vv_u16m1, 8) +OPENCV_HAL_IMPL_RVV_BIN_OP(-, v_uint16x8, vssubu_vv_u16m1, 8) +OPENCV_HAL_IMPL_RVV_BIN_OP(/, v_uint16x8, vdivu_vv_u16m1, 8) +OPENCV_HAL_IMPL_RVV_BIN_OP(+, v_int16x8, vsadd_vv_i16m1, 8) +OPENCV_HAL_IMPL_RVV_BIN_OP(-, v_int16x8, vssub_vv_i16m1, 8) +OPENCV_HAL_IMPL_RVV_BIN_OP(/, v_int16x8, vdiv_vv_i16m1, 8) +OPENCV_HAL_IMPL_RVV_BIN_OP(+, v_uint32x4, vadd_vv_u32m1, 4) +OPENCV_HAL_IMPL_RVV_BIN_OP(-, v_uint32x4, vsub_vv_u32m1, 4) +OPENCV_HAL_IMPL_RVV_BIN_OP(*, v_uint32x4, vmul_vv_u32m1, 4) +OPENCV_HAL_IMPL_RVV_BIN_OP(/, v_uint32x4, vdivu_vv_u32m1, 4) +OPENCV_HAL_IMPL_RVV_BIN_OP(+, v_int32x4, vadd_vv_i32m1, 4) +OPENCV_HAL_IMPL_RVV_BIN_OP(-, v_int32x4, vsub_vv_i32m1, 4) +OPENCV_HAL_IMPL_RVV_BIN_OP(*, v_int32x4, vmul_vv_i32m1, 4) +OPENCV_HAL_IMPL_RVV_BIN_OP(/, v_int32x4, vdiv_vv_i32m1, 4) +OPENCV_HAL_IMPL_RVV_BIN_OP(+, v_float32x4, vfadd_vv_f32m1, 4) +OPENCV_HAL_IMPL_RVV_BIN_OP(-, v_float32x4, vfsub_vv_f32m1, 4) +OPENCV_HAL_IMPL_RVV_BIN_OP(*, v_float32x4, vfmul_vv_f32m1, 4) +OPENCV_HAL_IMPL_RVV_BIN_OP(/, v_float32x4, vfdiv_vv_f32m1, 4) +OPENCV_HAL_IMPL_RVV_BIN_OP(+, v_uint64x2, vadd_vv_u64m1, 2) +OPENCV_HAL_IMPL_RVV_BIN_OP(-, v_uint64x2, vsub_vv_u64m1, 2) +OPENCV_HAL_IMPL_RVV_BIN_OP(*, v_uint64x2, vmul_vv_u64m1, 2) +OPENCV_HAL_IMPL_RVV_BIN_OP(/, v_uint64x2, vdivu_vv_u64m1, 2) +OPENCV_HAL_IMPL_RVV_BIN_OP(+, v_int64x2, vadd_vv_i64m1, 2) +OPENCV_HAL_IMPL_RVV_BIN_OP(-, v_int64x2, vsub_vv_i64m1, 2) +OPENCV_HAL_IMPL_RVV_BIN_OP(*, v_int64x2, vmul_vv_i64m1, 2) +OPENCV_HAL_IMPL_RVV_BIN_OP(/, v_int64x2, vdiv_vv_i64m1, 2) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_RVV_BIN_OP(+, v_float64x2, vfadd_vv_f64m1, 2) +OPENCV_HAL_IMPL_RVV_BIN_OP(-, v_float64x2, vfsub_vv_f64m1, 2) +OPENCV_HAL_IMPL_RVV_BIN_OP(*, v_float64x2, vfmul_vv_f64m1, 2) +OPENCV_HAL_IMPL_RVV_BIN_OP(/, v_float64x2, vfdiv_vv_f64m1, 2) +#endif + + +////////////// Bitwise logic ////////////// + +#define OPENCV_HAL_IMPL_RVV_LOGIC_OP(_Tpvec, suffix, vl) \ +OPENCV_HAL_IMPL_RVV_BIN_OP(&, _Tpvec, vand_vv_##suffix##m1, vl) \ +OPENCV_HAL_IMPL_RVV_BIN_OP(|, _Tpvec, vor_vv_##suffix##m1, vl) \ +OPENCV_HAL_IMPL_RVV_BIN_OP(^, _Tpvec, vxor_vv_##suffix##m1, vl) \ +inline _Tpvec operator ~ (const _Tpvec& a) \ +{ \ + return _Tpvec(vnot_v_##suffix##m1(a, vl)); \ +} + +OPENCV_HAL_IMPL_RVV_LOGIC_OP(v_uint8x16, u8, 16) +OPENCV_HAL_IMPL_RVV_LOGIC_OP(v_int8x16, i8, 16) +OPENCV_HAL_IMPL_RVV_LOGIC_OP(v_uint16x8, u16, 8) +OPENCV_HAL_IMPL_RVV_LOGIC_OP(v_int16x8, i16, 8) +OPENCV_HAL_IMPL_RVV_LOGIC_OP(v_uint32x4, u32, 4) +OPENCV_HAL_IMPL_RVV_LOGIC_OP(v_int32x4, i32, 4) +OPENCV_HAL_IMPL_RVV_LOGIC_OP(v_uint64x2, u64, 2) +OPENCV_HAL_IMPL_RVV_LOGIC_OP(v_int64x2, i64, 2) + +#define OPENCV_HAL_IMPL_RVV_FLT_BIT_OP(bin_op, intrin) \ +inline v_float32x4 operator bin_op (const v_float32x4& a, const v_float32x4& b) \ +{ \ + return v_float32x4(vreinterpret_v_i32m1_f32m1(intrin(vreinterpret_v_f32m1_i32m1(a), vreinterpret_v_f32m1_i32m1(b), 4))); \ +} \ +inline v_float32x4& operator bin_op##= (v_float32x4& a, const v_float32x4& b) \ +{ \ + a = v_float32x4(vreinterpret_v_i32m1_f32m1(intrin(vreinterpret_v_f32m1_i32m1(a), vreinterpret_v_f32m1_i32m1(b), 4))); \ + return a; \ +} + +OPENCV_HAL_IMPL_RVV_FLT_BIT_OP(&, vand_vv_i32m1) +OPENCV_HAL_IMPL_RVV_FLT_BIT_OP(|, vor_vv_i32m1) +OPENCV_HAL_IMPL_RVV_FLT_BIT_OP(^, vxor_vv_i32m1) + +inline v_float32x4 operator ~ (const v_float32x4& a) +{ + return v_float32x4(vreinterpret_v_i32m1_f32m1(vnot_v_i32m1(vreinterpret_v_f32m1_i32m1(a), 4))); +} + +#if CV_SIMD128_64F +#define OPENCV_HAL_IMPL_RVV_FLT64_BIT_OP(bin_op, intrin) \ +inline v_float64x2 operator bin_op (const v_float64x2& a, const v_float64x2& b) \ +{ \ + return v_float64x2(vreinterpret_v_i64m1_f64m1(intrin(vreinterpret_v_f64m1_i64m1(a), vreinterpret_v_f64m1_i64m1(b), 2))); \ +} \ +inline v_float64x2& operator bin_op##= (v_float64x2& a, const v_float64x2& b) \ +{ \ + a = v_float64x2(vreinterpret_v_i64m1_f64m1(intrin(vreinterpret_v_f64m1_i64m1(a), vreinterpret_v_f64m1_i64m1(b), 2))); \ + return a; \ +} + +OPENCV_HAL_IMPL_RVV_FLT64_BIT_OP(&, vand_vv_i64m1) +OPENCV_HAL_IMPL_RVV_FLT64_BIT_OP(|, vor_vv_i64m1) +OPENCV_HAL_IMPL_RVV_FLT64_BIT_OP(^, vxor_vv_i64m1) + +inline v_float64x2 operator ~ (const v_float64x2& a) +{ + return v_float64x2(vreinterpret_v_i64m1_f64m1(vnot_v_i64m1(vreinterpret_v_f64m1_i64m1(a), 2))); +} +#endif + +////////////// Bitwise shifts ////////////// + +#define OPENCV_HAL_IMPL_RVV_UNSIGNED_SHIFT_OP(_Tpvec, suffix, vl) \ +inline _Tpvec operator << (const _Tpvec& a, int n) \ +{ \ + return _Tpvec(vsll_vx_##suffix##m1(a, uint8_t(n), vl)); \ +} \ +inline _Tpvec operator >> (const _Tpvec& a, int n) \ +{ \ + return _Tpvec(vsrl_vx_##suffix##m1(a, uint8_t(n), vl)); \ +} \ +template inline _Tpvec v_shl(const _Tpvec& a) \ +{ \ + return _Tpvec(vsll_vx_##suffix##m1(a, uint8_t(n), vl)); \ +} \ +template inline _Tpvec v_shr(const _Tpvec& a) \ +{ \ + return _Tpvec(vsrl_vx_##suffix##m1(a, uint8_t(n), vl)); \ +} + +#define OPENCV_HAL_IMPL_RVV_SIGNED_SHIFT_OP(_Tpvec, suffix, vl) \ +inline _Tpvec operator << (const _Tpvec& a, int n) \ +{ \ + return _Tpvec(vsll_vx_##suffix##m1(a, uint8_t(n), vl)); \ +} \ +inline _Tpvec operator >> (const _Tpvec& a, int n) \ +{ \ + return _Tpvec(vsra_vx_##suffix##m1(a, uint8_t(n), vl)); \ +} \ +template inline _Tpvec v_shl(const _Tpvec& a) \ +{ \ + return _Tpvec(vsll_vx_##suffix##m1(a, uint8_t(n), vl)); \ +} \ +template inline _Tpvec v_shr(const _Tpvec& a) \ +{ \ + return _Tpvec(vsra_vx_##suffix##m1(a, uint8_t(n), vl)); \ +} + +OPENCV_HAL_IMPL_RVV_UNSIGNED_SHIFT_OP(v_uint8x16, u8, 16) +OPENCV_HAL_IMPL_RVV_UNSIGNED_SHIFT_OP(v_uint16x8, u16, 8) +OPENCV_HAL_IMPL_RVV_UNSIGNED_SHIFT_OP(v_uint32x4, u32, 4) +OPENCV_HAL_IMPL_RVV_UNSIGNED_SHIFT_OP(v_uint64x2, u64, 2) +OPENCV_HAL_IMPL_RVV_SIGNED_SHIFT_OP(v_int8x16, i8, 16) +OPENCV_HAL_IMPL_RVV_SIGNED_SHIFT_OP(v_int16x8, i16, 8) +OPENCV_HAL_IMPL_RVV_SIGNED_SHIFT_OP(v_int32x4, i32, 4) +OPENCV_HAL_IMPL_RVV_SIGNED_SHIFT_OP(v_int64x2, i64, 2) + + +////////////// Comparison ////////////// + +#define OPENCV_HAL_IMPL_RVV_INT_CMP_OP(_Tpvec, op, intrin, suffix, vl) \ +inline _Tpvec operator op (const _Tpvec& a, const _Tpvec& b) \ +{ \ + uint64_t ones = -1; \ + return _Tpvec(vmerge_vxm_##suffix##m1(intrin(a, b, vl), vmv_v_x_##suffix##m1(0, vl), ones, vl)); \ +} + +#define OPENCV_HAL_IMPL_RVV_FLOAT_CMP_OP(_Tpvec, op, intrin, suffix, vl) \ +inline _Tpvec operator op (const _Tpvec& a, const _Tpvec& b) \ +{ \ + union { uint64 u; double d; } ones; ones.u = -1; \ + return _Tpvec(vfmerge_vfm_##suffix##m1(intrin(a, b, vl), vfmv_v_f_##suffix##m1(0, vl), ones.d, vl)); \ +} + +#define OPENCV_HAL_IMPL_RVV_UNSIGNED_CMP(_Tpvec, suffix, width, vl) \ +OPENCV_HAL_IMPL_RVV_INT_CMP_OP(_Tpvec, ==, vmseq_vv_##suffix##m1_b##width, suffix, vl) \ +OPENCV_HAL_IMPL_RVV_INT_CMP_OP(_Tpvec, !=, vmsne_vv_##suffix##m1_b##width, suffix, vl) \ +OPENCV_HAL_IMPL_RVV_INT_CMP_OP(_Tpvec, <, vmsltu_vv_##suffix##m1_b##width, suffix, vl) \ +OPENCV_HAL_IMPL_RVV_INT_CMP_OP(_Tpvec, >, vmsgtu_vv_##suffix##m1_b##width, suffix, vl) \ +OPENCV_HAL_IMPL_RVV_INT_CMP_OP(_Tpvec, <=, vmsleu_vv_##suffix##m1_b##width, suffix, vl) \ +OPENCV_HAL_IMPL_RVV_INT_CMP_OP(_Tpvec, >=, vmsgeu_vv_##suffix##m1_b##width, suffix, vl) + +#define OPENCV_HAL_IMPL_RVV_SIGNED_CMP(_Tpvec, suffix, width, vl) \ +OPENCV_HAL_IMPL_RVV_INT_CMP_OP(_Tpvec, ==, vmseq_vv_##suffix##m1_b##width, suffix, vl) \ +OPENCV_HAL_IMPL_RVV_INT_CMP_OP(_Tpvec, !=, vmsne_vv_##suffix##m1_b##width, suffix, vl) \ +OPENCV_HAL_IMPL_RVV_INT_CMP_OP(_Tpvec, <, vmslt_vv_##suffix##m1_b##width, suffix, vl) \ +OPENCV_HAL_IMPL_RVV_INT_CMP_OP(_Tpvec, >, vmsgt_vv_##suffix##m1_b##width, suffix, vl) \ +OPENCV_HAL_IMPL_RVV_INT_CMP_OP(_Tpvec, <=, vmsle_vv_##suffix##m1_b##width, suffix, vl) \ +OPENCV_HAL_IMPL_RVV_INT_CMP_OP(_Tpvec, >=, vmsge_vv_##suffix##m1_b##width, suffix, vl) + +#define OPENCV_HAL_IMPL_RVV_FLOAT_CMP(_Tpvec, suffix, width, vl) \ +OPENCV_HAL_IMPL_RVV_FLOAT_CMP_OP(_Tpvec, ==, vmfeq_vv_##suffix##m1_b##width, suffix, vl) \ +OPENCV_HAL_IMPL_RVV_FLOAT_CMP_OP(_Tpvec, !=, vmfne_vv_##suffix##m1_b##width, suffix, vl) \ +OPENCV_HAL_IMPL_RVV_FLOAT_CMP_OP(_Tpvec, <, vmflt_vv_##suffix##m1_b##width, suffix, vl) \ +OPENCV_HAL_IMPL_RVV_FLOAT_CMP_OP(_Tpvec, >, vmfgt_vv_##suffix##m1_b##width, suffix, vl) \ +OPENCV_HAL_IMPL_RVV_FLOAT_CMP_OP(_Tpvec, <=, vmfle_vv_##suffix##m1_b##width, suffix, vl) \ +OPENCV_HAL_IMPL_RVV_FLOAT_CMP_OP(_Tpvec, >=, vmfge_vv_##suffix##m1_b##width, suffix, vl) + + +OPENCV_HAL_IMPL_RVV_UNSIGNED_CMP(v_uint8x16, u8, 8, 16) +OPENCV_HAL_IMPL_RVV_UNSIGNED_CMP(v_uint16x8, u16, 16, 8) +OPENCV_HAL_IMPL_RVV_UNSIGNED_CMP(v_uint32x4, u32, 32, 4) +OPENCV_HAL_IMPL_RVV_UNSIGNED_CMP(v_uint64x2, u64, 64, 2) +OPENCV_HAL_IMPL_RVV_SIGNED_CMP(v_int8x16, i8, 8, 16) +OPENCV_HAL_IMPL_RVV_SIGNED_CMP(v_int16x8, i16, 16, 8) +OPENCV_HAL_IMPL_RVV_SIGNED_CMP(v_int32x4, i32, 32, 4) +OPENCV_HAL_IMPL_RVV_SIGNED_CMP(v_int64x2, i64, 64, 2) +OPENCV_HAL_IMPL_RVV_FLOAT_CMP(v_float32x4, f32, 32, 4) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_RVV_FLOAT_CMP(v_float64x2, f64, 64, 2) +#endif + +inline v_float32x4 v_not_nan(const v_float32x4& a) +{ return a == a; } + +#if CV_SIMD128_64F +inline v_float64x2 v_not_nan(const v_float64x2& a) +{ return a == a; } +#endif + +////////////// Min/Max ////////////// + +#define OPENCV_HAL_IMPL_RVV_BIN_FUNC(_Tpvec, func, intrin, vl) \ +inline _Tpvec func(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(intrin(a, b, vl)); \ +} + +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_uint8x16, v_min, vminu_vv_u8m1, 16) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_uint8x16, v_max, vmaxu_vv_u8m1, 16) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_int8x16, v_min, vmin_vv_i8m1, 16) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_int8x16, v_max, vmax_vv_i8m1, 16) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_uint16x8, v_min, vminu_vv_u16m1, 8) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_uint16x8, v_max, vmaxu_vv_u16m1, 8) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_int16x8, v_min, vmin_vv_i16m1, 8) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_int16x8, v_max, vmax_vv_i16m1, 8) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_uint32x4, v_min, vminu_vv_u32m1, 4) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_uint32x4, v_max, vmaxu_vv_u32m1, 4) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_int32x4, v_min, vmin_vv_i32m1, 4) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_int32x4, v_max, vmax_vv_i32m1, 4) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_float32x4, v_min, vfmin_vv_f32m1, 4) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_float32x4, v_max, vfmax_vv_f32m1, 4) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_uint64x2, v_min, vminu_vv_u64m1, 2) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_uint64x2, v_max, vmaxu_vv_u64m1, 2) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_int64x2, v_min, vmin_vv_i64m1, 2) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_int64x2, v_max, vmax_vv_i64m1, 2) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_float64x2, v_min, vfmin_vv_f64m1, 2) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_float64x2, v_max, vfmax_vv_f64m1, 2) +#endif + +////////////// Arithmetics wrap ////////////// + +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_uint8x16, v_add_wrap, vadd_vv_u8m1, 16) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_int8x16, v_add_wrap, vadd_vv_i8m1, 16) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_uint16x8, v_add_wrap, vadd_vv_u16m1, 8) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_int16x8, v_add_wrap, vadd_vv_i16m1, 8) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_uint8x16, v_sub_wrap, vsub_vv_u8m1, 16) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_int8x16, v_sub_wrap, vsub_vv_i8m1, 16) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_uint16x8, v_sub_wrap, vsub_vv_u16m1, 8) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_int16x8, v_sub_wrap, vsub_vv_i16m1, 8) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_uint8x16, v_mul_wrap, vmul_vv_u8m1, 16) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_int8x16, v_mul_wrap, vmul_vv_i8m1, 16) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_uint16x8, v_mul_wrap, vmul_vv_u16m1, 8) +OPENCV_HAL_IMPL_RVV_BIN_FUNC(v_int16x8, v_mul_wrap, vmul_vv_i16m1, 8) + +////////////// Reduce ////////////// + +#define OPENCV_HAL_IMPL_RVV_REDUCE_SUM(_Tpvec, _wTpvec, _nwTpvec, scalartype, suffix, wsuffix, vl, red) \ +inline scalartype v_reduce_sum(const _Tpvec& a) \ +{ \ + _nwTpvec zero = vmv_v_x_##wsuffix##m1(0, vl); \ + _nwTpvec res = vmv_v_x_##wsuffix##m1(0, vl); \ + res = v##red##_vs_##suffix##m1_##wsuffix##m1(res, a, zero, vl); \ + return (scalartype)(_wTpvec(res).get0()); \ +} + +OPENCV_HAL_IMPL_RVV_REDUCE_SUM(v_uint8x16, v_uint16x8, vuint16m1_t, unsigned, u8, u16, 16, wredsumu) +OPENCV_HAL_IMPL_RVV_REDUCE_SUM(v_int8x16, v_int16x8, vint16m1_t, int, i8, i16, 16, wredsum) +OPENCV_HAL_IMPL_RVV_REDUCE_SUM(v_uint16x8, v_uint32x4, vuint32m1_t, unsigned, u16, u32, 8, wredsumu) +OPENCV_HAL_IMPL_RVV_REDUCE_SUM(v_int16x8, v_int32x4, vint32m1_t, int, i16, i32, 8, wredsum) +OPENCV_HAL_IMPL_RVV_REDUCE_SUM(v_uint32x4, v_uint64x2, vuint64m1_t, unsigned, u32, u64, 4, wredsumu) +OPENCV_HAL_IMPL_RVV_REDUCE_SUM(v_int32x4, v_int64x2, vint64m1_t, int, i32, i64, 4, wredsum) +OPENCV_HAL_IMPL_RVV_REDUCE_SUM(v_uint64x2, v_uint64x2, vuint64m1_t, uint64, u64, u64, 2, redsum) +OPENCV_HAL_IMPL_RVV_REDUCE_SUM(v_int64x2, v_int64x2, vint64m1_t, int64, i64, i64, 2, redsum) + +#define OPENCV_HAL_IMPL_RVV_REDUCE_SUM_FP(_Tpvec, _wTpvec, _nwTpvec, scalartype, suffix, wsuffix, vl, red) \ +inline scalartype v_reduce_sum(const _Tpvec& a) \ +{ \ + _nwTpvec zero = vfmv_v_f_##wsuffix##m1(0, vl); \ + _nwTpvec res = vfmv_v_f_##wsuffix##m1(0, vl); \ + res = v##red##_vs_##suffix##m1_##wsuffix##m1(res, a, zero, vl); \ + return (scalartype)(_wTpvec(res).get0()); \ +} + +// vfredsum for float has renamed to fredosum, also updated in GNU. +OPENCV_HAL_IMPL_RVV_REDUCE_SUM_FP(v_float32x4, v_float32x4, vfloat32m1_t, float, f32, f32, 4, fredosum) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_RVV_REDUCE_SUM_FP(v_float64x2, v_float64x2, vfloat64m1_t, double, f64, f64, 2, fredosum) +#endif + + +#define OPENCV_HAL_IMPL_RVV_REDUCE(_Tpvec, func, scalartype, suffix, vl, red) \ +inline scalartype v_reduce_##func(const _Tpvec& a) \ +{ \ + _Tpvec res = _Tpvec(v##red##_vs_##suffix##m1_##suffix##m1(a, a, a, vl)); \ + return scalartype(res.get0()); \ +} + +OPENCV_HAL_IMPL_RVV_REDUCE(v_uint8x16, min, uchar, u8, 16, redminu) +OPENCV_HAL_IMPL_RVV_REDUCE(v_int8x16, min, schar, i8, 16, redmin) +OPENCV_HAL_IMPL_RVV_REDUCE(v_uint16x8, min, ushort, u16, 8, redminu) +OPENCV_HAL_IMPL_RVV_REDUCE(v_int16x8, min, short, i16, 8, redmin) +OPENCV_HAL_IMPL_RVV_REDUCE(v_uint32x4, min, unsigned, u32, 4, redminu) +OPENCV_HAL_IMPL_RVV_REDUCE(v_int32x4, min, int, i32, 4, redmin) +OPENCV_HAL_IMPL_RVV_REDUCE(v_float32x4, min, float, f32, 4, fredmin) +OPENCV_HAL_IMPL_RVV_REDUCE(v_uint8x16, max, uchar, u8, 16, redmaxu) +OPENCV_HAL_IMPL_RVV_REDUCE(v_int8x16, max, schar, i8, 16, redmax) +OPENCV_HAL_IMPL_RVV_REDUCE(v_uint16x8, max, ushort, u16, 8, redmaxu) +OPENCV_HAL_IMPL_RVV_REDUCE(v_int16x8, max, short, i16, 8, redmax) +OPENCV_HAL_IMPL_RVV_REDUCE(v_uint32x4, max, unsigned, u32, 4, redmaxu) +OPENCV_HAL_IMPL_RVV_REDUCE(v_int32x4, max, int, i32, 4, redmax) +OPENCV_HAL_IMPL_RVV_REDUCE(v_float32x4, max, float, f32, 4, fredmax) + + +inline v_float32x4 v_reduce_sum4(const v_float32x4& a, const v_float32x4& b, + const v_float32x4& c, const v_float32x4& d) +{ + float elems[4] = + { + v_reduce_sum(a), + v_reduce_sum(b), + v_reduce_sum(c), + v_reduce_sum(d) + }; + return v_float32x4(vle32_v_f32m1(elems, 4)); +} + +////////////// Square-Root ////////////// + +inline v_float32x4 v_sqrt(const v_float32x4& x) +{ + return v_float32x4(vfsqrt_v_f32m1(x, 4)); +} + +inline v_float32x4 v_invsqrt(const v_float32x4& x) +{ + v_float32x4 one = v_setall_f32(1.0f); + return one / v_sqrt(x); +} + +#if CV_SIMD128_64F +inline v_float64x2 v_sqrt(const v_float64x2& x) +{ + return v_float64x2(vfsqrt_v_f64m1(x, 4)); +} + +inline v_float64x2 v_invsqrt(const v_float64x2& x) +{ + v_float64x2 one = v_setall_f64(1.0f); + return one / v_sqrt(x); +} +#endif + +inline v_float32x4 v_magnitude(const v_float32x4& a, const v_float32x4& b) +{ + v_float32x4 x(vfmacc_vv_f32m1(vfmul_vv_f32m1(a, a, 4), b, b, 4)); + return v_sqrt(x); +} + +inline v_float32x4 v_sqr_magnitude(const v_float32x4& a, const v_float32x4& b) +{ + return v_float32x4(vfmacc_vv_f32m1(vfmul_vv_f32m1(a, a, 4), b, b, 4)); +} + +#if CV_SIMD128_64F +inline v_float64x2 v_magnitude(const v_float64x2& a, const v_float64x2& b) +{ + v_float64x2 x(vfmacc_vv_f64m1(vfmul_vv_f64m1(a, a, 2), b, b, 2)); + return v_sqrt(x); +} + +inline v_float64x2 v_sqr_magnitude(const v_float64x2& a, const v_float64x2& b) +{ + return v_float64x2(vfmacc_vv_f64m1(vfmul_vv_f64m1(a, a, 2), b, b, 2)); +} +#endif + +////////////// Multiply-Add ////////////// + +inline v_float32x4 v_fma(const v_float32x4& a, const v_float32x4& b, const v_float32x4& c) +{ + return v_float32x4(vfmacc_vv_f32m1(c, a, b, 4)); +} +inline v_int32x4 v_fma(const v_int32x4& a, const v_int32x4& b, const v_int32x4& c) +{ + return v_int32x4(vmacc_vv_i32m1(c, a, b, 4)); +} + +inline v_float32x4 v_muladd(const v_float32x4& a, const v_float32x4& b, const v_float32x4& c) +{ + return v_fma(a, b, c); +} + +inline v_int32x4 v_muladd(const v_int32x4& a, const v_int32x4& b, const v_int32x4& c) +{ + return v_fma(a, b, c); +} + +#if CV_SIMD128_64F +inline v_float64x2 v_fma(const v_float64x2& a, const v_float64x2& b, const v_float64x2& c) +{ + return v_float64x2(vfmacc_vv_f64m1(c, a, b, 2)); +} + +inline v_float64x2 v_muladd(const v_float64x2& a, const v_float64x2& b, const v_float64x2& c) +{ + return v_fma(a, b, c); +} +#endif + +////////////// Check all/any ////////////// + +// use overloaded vcpop in clang, no casting like (vuint64m1_t) is needed. +#ifndef __clang__ +#define OPENCV_HAL_IMPL_RVV_CHECK_ALLANY(_Tpvec, suffix, shift, vl) \ +inline bool v_check_all(const _Tpvec& a) \ +{ \ + v_uint64x2 v = v_uint64x2((vuint64m1_t)vsrl_vx_##suffix##m1(vnot_v_##suffix##m1(a, vl), shift, vl)); \ + return (v.val[0] | v.val[1]) == 0; \ +} \ +inline bool v_check_any(const _Tpvec& a) \ +{ \ + v_uint64x2 v = v_uint64x2((vuint64m1_t)vsrl_vx_##suffix##m1(a, shift, vl)); \ + return (v.val[0] | v.val[1]) != 0; \ +} + +OPENCV_HAL_IMPL_RVV_CHECK_ALLANY(v_uint8x16, u8, 7, 16) +OPENCV_HAL_IMPL_RVV_CHECK_ALLANY(v_uint16x8, u16, 15, 8) +OPENCV_HAL_IMPL_RVV_CHECK_ALLANY(v_uint32x4, u32, 31, 4) +OPENCV_HAL_IMPL_RVV_CHECK_ALLANY(v_uint64x2, u64, 63, 2) + + +inline bool v_check_all(const v_int8x16& a) +{ return v_check_all(v_reinterpret_as_u8(a)); } +inline bool v_check_any(const v_int8x16& a) +{ return v_check_any(v_reinterpret_as_u8(a)); } + +inline bool v_check_all(const v_int16x8& a) +{ return v_check_all(v_reinterpret_as_u16(a)); } +inline bool v_check_any(const v_int16x8& a) +{ return v_check_any(v_reinterpret_as_u16(a)); } + +inline bool v_check_all(const v_int32x4& a) +{ return v_check_all(v_reinterpret_as_u32(a)); } +inline bool v_check_any(const v_int32x4& a) +{ return v_check_any(v_reinterpret_as_u32(a)); } + +inline bool v_check_all(const v_float32x4& a) +{ return v_check_all(v_reinterpret_as_u32(a)); } +inline bool v_check_any(const v_float32x4& a) +{ return v_check_any(v_reinterpret_as_u32(a)); } + +inline bool v_check_all(const v_int64x2& a) +{ return v_check_all(v_reinterpret_as_u64(a)); } +inline bool v_check_any(const v_int64x2& a) +{ return v_check_any(v_reinterpret_as_u64(a)); } + +#if CV_SIMD128_64F +inline bool v_check_all(const v_float64x2& a) +{ return v_check_all(v_reinterpret_as_u64(a)); } +inline bool v_check_any(const v_float64x2& a) +{ return v_check_any(v_reinterpret_as_u64(a)); } +#endif +#else +#define OPENCV_HAL_IMPL_RVV_CHECK_ALLANY(_Tpvec, vl) \ +inline bool v_check_all(const _Tpvec& a) \ +{ \ + return vcpop(vmslt(a, 0, vl), vl) == vl; \ +} \ +inline bool v_check_any(const _Tpvec& a) \ +{ \ + return vcpop(vmslt(a, 0, vl), vl) != 0; \ +} + +OPENCV_HAL_IMPL_RVV_CHECK_ALLANY(v_int8x16, 16) +OPENCV_HAL_IMPL_RVV_CHECK_ALLANY(v_int16x8, 8) +OPENCV_HAL_IMPL_RVV_CHECK_ALLANY(v_int32x4, 4) +OPENCV_HAL_IMPL_RVV_CHECK_ALLANY(v_int64x2, 2) + + +inline bool v_check_all(const v_uint8x16& a) +{ return v_check_all(v_reinterpret_as_s8(a)); } +inline bool v_check_any(const v_uint8x16& a) +{ return v_check_any(v_reinterpret_as_s8(a)); } + +inline bool v_check_all(const v_uint16x8& a) +{ return v_check_all(v_reinterpret_as_s16(a)); } +inline bool v_check_any(const v_uint16x8& a) +{ return v_check_any(v_reinterpret_as_s16(a)); } + +inline bool v_check_all(const v_uint32x4& a) +{ return v_check_all(v_reinterpret_as_s32(a)); } +inline bool v_check_any(const v_uint32x4& a) +{ return v_check_any(v_reinterpret_as_s32(a)); } + +inline bool v_check_all(const v_float32x4& a) +{ return v_check_all(v_reinterpret_as_s32(a)); } +inline bool v_check_any(const v_float32x4& a) +{ return v_check_any(v_reinterpret_as_s32(a)); } + +inline bool v_check_all(const v_uint64x2& a) +{ return v_check_all(v_reinterpret_as_s64(a)); } +inline bool v_check_any(const v_uint64x2& a) +{ return v_check_any(v_reinterpret_as_s64(a)); } + +#if CV_SIMD128_64F +inline bool v_check_all(const v_float64x2& a) +{ return v_check_all(v_reinterpret_as_s64(a)); } +inline bool v_check_any(const v_float64x2& a) +{ return v_check_any(v_reinterpret_as_s64(a)); } +#endif +#endif +////////////// abs ////////////// + +#define OPENCV_HAL_IMPL_RVV_ABSDIFF(_Tpvec, abs) \ +inline _Tpvec v_##abs(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return v_max(a, b) - v_min(a, b); \ +} + +OPENCV_HAL_IMPL_RVV_ABSDIFF(v_uint8x16, absdiff) +OPENCV_HAL_IMPL_RVV_ABSDIFF(v_uint16x8, absdiff) +OPENCV_HAL_IMPL_RVV_ABSDIFF(v_uint32x4, absdiff) +OPENCV_HAL_IMPL_RVV_ABSDIFF(v_float32x4, absdiff) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_RVV_ABSDIFF(v_float64x2, absdiff) +#endif +OPENCV_HAL_IMPL_RVV_ABSDIFF(v_int8x16, absdiffs) +OPENCV_HAL_IMPL_RVV_ABSDIFF(v_int16x8, absdiffs) + +// use reinterpret instead of c-style casting. +#ifndef __clang__ +#define OPENCV_HAL_IMPL_RVV_ABSDIFF_S(_Tpvec, _rTpvec, _nwTpvec, sub, rshr, vl) \ +inline _rTpvec v_absdiff(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _rTpvec(rshr((_nwTpvec)sub(v_max(a, b), v_min(a, b), vl), 0, vl)); \ +} + +OPENCV_HAL_IMPL_RVV_ABSDIFF_S(v_int8x16, v_uint8x16, vuint16m2_t, vwsub_vv_i16m2, vnclipu_wx_u8m1, 16) +OPENCV_HAL_IMPL_RVV_ABSDIFF_S(v_int16x8, v_uint16x8, vuint32m2_t, vwsub_vv_i32m2, vnclipu_wx_u16m1, 8) +OPENCV_HAL_IMPL_RVV_ABSDIFF_S(v_int32x4, v_uint32x4, vuint64m2_t, vwsub_vv_i64m2, vnclipu_wx_u32m1, 4) +#else +#define OPENCV_HAL_IMPL_RVV_ABSDIFF_S(_Tpvec, _rTpvec, _nwTpvec, sub, rshr, width, vl) \ +inline _rTpvec v_absdiff(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _rTpvec(rshr(vreinterpret_u##width##m2(sub(v_max(a, b), v_min(a, b), vl)), 0, vl)); \ +} + +OPENCV_HAL_IMPL_RVV_ABSDIFF_S(v_int8x16, v_uint8x16, vuint16m2_t, vwsub_vv_i16m2, vnclipu_wx_u8m1, 16, 16) +OPENCV_HAL_IMPL_RVV_ABSDIFF_S(v_int16x8, v_uint16x8, vuint32m2_t, vwsub_vv_i32m2, vnclipu_wx_u16m1, 32, 8) +OPENCV_HAL_IMPL_RVV_ABSDIFF_S(v_int32x4, v_uint32x4, vuint64m2_t, vwsub_vv_i64m2, vnclipu_wx_u32m1, 64, 4) +#endif +#define OPENCV_HAL_IMPL_RVV_ABS(_Tprvec, _Tpvec, suffix) \ +inline _Tprvec v_abs(const _Tpvec& a) \ +{ \ + return v_absdiff(a, v_setzero_##suffix()); \ +} + +OPENCV_HAL_IMPL_RVV_ABS(v_uint8x16, v_int8x16, s8) +OPENCV_HAL_IMPL_RVV_ABS(v_uint16x8, v_int16x8, s16) +OPENCV_HAL_IMPL_RVV_ABS(v_uint32x4, v_int32x4, s32) +OPENCV_HAL_IMPL_RVV_ABS(v_float32x4, v_float32x4, f32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_RVV_ABS(v_float64x2, v_float64x2, f64) +#endif + + +#define OPENCV_HAL_IMPL_RVV_REDUCE_SAD(_Tpvec, scalartype) \ +inline scalartype v_reduce_sad(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return v_reduce_sum(v_absdiff(a, b)); \ +} + +OPENCV_HAL_IMPL_RVV_REDUCE_SAD(v_uint8x16, unsigned) +OPENCV_HAL_IMPL_RVV_REDUCE_SAD(v_int8x16, unsigned) +OPENCV_HAL_IMPL_RVV_REDUCE_SAD(v_uint16x8, unsigned) +OPENCV_HAL_IMPL_RVV_REDUCE_SAD(v_int16x8, unsigned) +OPENCV_HAL_IMPL_RVV_REDUCE_SAD(v_uint32x4, unsigned) +OPENCV_HAL_IMPL_RVV_REDUCE_SAD(v_int32x4, unsigned) +OPENCV_HAL_IMPL_RVV_REDUCE_SAD(v_float32x4, float) + +////////////// Select ////////////// + +#define OPENCV_HAL_IMPL_RVV_SELECT(_Tpvec, merge, ne, vl) \ +inline _Tpvec v_select(const _Tpvec& mask, const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(merge(ne(mask, 0, vl), b, a, vl)); \ +} + +OPENCV_HAL_IMPL_RVV_SELECT(v_uint8x16, vmerge_vvm_u8m1, vmsne_vx_u8m1_b8, 16) +OPENCV_HAL_IMPL_RVV_SELECT(v_int8x16, vmerge_vvm_i8m1, vmsne_vx_i8m1_b8, 16) +OPENCV_HAL_IMPL_RVV_SELECT(v_uint16x8, vmerge_vvm_u16m1, vmsne_vx_u16m1_b16, 8) +OPENCV_HAL_IMPL_RVV_SELECT(v_int16x8, vmerge_vvm_i16m1, vmsne_vx_i16m1_b16, 8) +OPENCV_HAL_IMPL_RVV_SELECT(v_uint32x4, vmerge_vvm_u32m1, vmsne_vx_u32m1_b32, 4) +OPENCV_HAL_IMPL_RVV_SELECT(v_int32x4, vmerge_vvm_i32m1, vmsne_vx_i32m1_b32, 4) +OPENCV_HAL_IMPL_RVV_SELECT(v_float32x4, vmerge_vvm_f32m1, vmfne_vf_f32m1_b32, 4) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_RVV_SELECT(v_float64x2, vmerge_vvm_f64m1, vmfne_vf_f64m1_b64, 2) +#endif + +////////////// Rotate shift ////////////// + +#define OPENCV_HAL_IMPL_RVV_ROTATE_INTEGER(_Tpvec, suffix, vl) \ +template inline _Tpvec v_rotate_right(const _Tpvec& a) \ +{ \ + return _Tpvec(vslidedown_vx_##suffix##m1(vmv_v_x_##suffix##m1(0, vl), a, n, vl)); \ +} \ +template inline _Tpvec v_rotate_left(const _Tpvec& a) \ +{ \ + return _Tpvec(vslideup_vx_##suffix##m1(vmv_v_x_##suffix##m1(0, vl), a, n, vl)); \ +} \ +template<> inline _Tpvec v_rotate_left<0>(const _Tpvec& a) \ +{ return a; } \ +template inline _Tpvec v_rotate_right(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(vslideup_vx_##suffix##m1(vslidedown_vx_##suffix##m1(vmv_v_x_##suffix##m1(0, vl), a, n, vl), b, _Tpvec::nlanes - n, vl)); \ +} \ +template inline _Tpvec v_rotate_left(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(vslideup_vx_##suffix##m1(vslidedown_vx_##suffix##m1(vmv_v_x_##suffix##m1(0, vl), b, _Tpvec::nlanes - n, vl), a, n, vl)); \ +} \ +template<> inline _Tpvec v_rotate_left<0>(const _Tpvec& a, const _Tpvec& b) \ +{ CV_UNUSED(b); return a; } + +OPENCV_HAL_IMPL_RVV_ROTATE_INTEGER(v_uint8x16, u8, 16) +OPENCV_HAL_IMPL_RVV_ROTATE_INTEGER(v_int8x16, i8, 16) +OPENCV_HAL_IMPL_RVV_ROTATE_INTEGER(v_uint16x8, u16, 8) +OPENCV_HAL_IMPL_RVV_ROTATE_INTEGER(v_int16x8, i16, 8) +OPENCV_HAL_IMPL_RVV_ROTATE_INTEGER(v_uint32x4, u32, 4) +OPENCV_HAL_IMPL_RVV_ROTATE_INTEGER(v_int32x4, i32, 4) +OPENCV_HAL_IMPL_RVV_ROTATE_INTEGER(v_uint64x2, u64, 2) +OPENCV_HAL_IMPL_RVV_ROTATE_INTEGER(v_int64x2, i64, 2) + +#define OPENCV_HAL_IMPL_RVV_ROTATE_FP(_Tpvec, suffix, vl) \ +template inline _Tpvec v_rotate_right(const _Tpvec& a) \ +{ \ + return _Tpvec(vslidedown_vx_##suffix##m1(vfmv_v_f_##suffix##m1(0, vl), a, n, vl)); \ +} \ +template inline _Tpvec v_rotate_left(const _Tpvec& a) \ +{ \ + return _Tpvec(vslideup_vx_##suffix##m1(vfmv_v_f_##suffix##m1(0, vl), a, n, vl)); \ +} \ +template<> inline _Tpvec v_rotate_left<0>(const _Tpvec& a) \ +{ return a; } \ +template inline _Tpvec v_rotate_right(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(vslideup_vx_##suffix##m1(vslidedown_vx_##suffix##m1(vfmv_v_f_##suffix##m1(0, vl), a, n, vl), b, _Tpvec::nlanes - n, vl)); \ +} \ +template inline _Tpvec v_rotate_left(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(vslideup_vx_##suffix##m1(vslidedown_vx_##suffix##m1(vfmv_v_f_##suffix##m1(0, vl), b, _Tpvec::nlanes - n, vl), a, n, vl)); \ +} \ +template<> inline _Tpvec v_rotate_left<0>(const _Tpvec& a, const _Tpvec& b) \ +{ CV_UNUSED(b); return a; } + +OPENCV_HAL_IMPL_RVV_ROTATE_FP(v_float32x4, f32, 4) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_RVV_ROTATE_FP(v_float64x2, f64, 2) +#endif + +////////////// Convert to float ////////////// + +inline v_float32x4 v_cvt_f32(const v_int32x4& a) +{ + return v_float32x4(vfcvt_f_x_v_f32m1(a, 4)); +} + +#if CV_SIMD128_64F +#ifndef __clang__ +inline v_float32x4 v_cvt_f32(const v_float64x2& a) +{ + double arr[4] = {a.val[0], a.val[1], 0, 0}; + vfloat64m2_t tmp = vle64_v_f64m2(arr, 4); + return v_float32x4(vfncvt_f_f_w_f32m1(tmp, 4)); +} + +inline v_float32x4 v_cvt_f32(const v_float64x2& a, const v_float64x2& b) +{ + double arr[4] = {a.val[0], a.val[1], b.val[0], b.val[1]}; + vfloat64m2_t tmp = vle64_v_f64m2(arr, 4); + return v_float32x4(vfncvt_f_f_w_f32m1(tmp, 4)); +} +#else +inline v_float32x4 v_cvt_f32(const v_float64x2& a) +{ + vfloat64m2_t zero = vfmv_v_f_f64m2(0, 4); + return v_float32x4(vfncvt_f_f_w_f32m1(vset_v_f64m1_f64m2(zero, 0, a), 4)); +} +inline v_float32x4 v_cvt_f32(const v_float64x2& a, const v_float64x2& b) +{ + vfloat64m2_t dst = vlmul_ext_v_f64m1_f64m2(a); + return v_float32x4(vfncvt_f_f_w_f32m1(vset_v_f64m1_f64m2(dst, 1, b), 4)); +} +#endif + +inline v_float64x2 v_cvt_f64(const v_int32x4& a) +{ + double ptr[4] = {0}; + vse64_v_f64m2(ptr, vfwcvt_f_x_v_f64m2(a, 4), 4); + double elems[2] = + { + ptr[0], ptr[1] + }; + return v_float64x2(vle64_v_f64m1(elems, 2)); +} + +inline v_float64x2 v_cvt_f64_high(const v_int32x4& a) +{ + double ptr[4] = {0}; + vse64_v_f64m2(ptr, vfwcvt_f_x_v_f64m2(a, 4), 4); + double elems[2] = + { + ptr[2], ptr[3] + }; + return v_float64x2(vle64_v_f64m1(elems, 2)); +} + +inline v_float64x2 v_cvt_f64(const v_float32x4& a) +{ + double ptr[4] = {0}; + vse64_v_f64m2(ptr, vfwcvt_f_f_v_f64m2(a, 4), 4); + double elems[2] = + { + ptr[0], ptr[1] + }; + return v_float64x2(vle64_v_f64m1(elems, 2)); +} + +inline v_float64x2 v_cvt_f64_high(const v_float32x4& a) +{ + double ptr[4] = {0}; + vse64_v_f64m2(ptr, vfwcvt_f_f_v_f64m2(a, 4), 4); + double elems[2] = + { + ptr[2], ptr[3] + }; + return v_float64x2(vle64_v_f64m1(elems, 2)); +} + +inline v_float64x2 v_cvt_f64(const v_int64x2& a) +{ + return v_float64x2(vfcvt_f_x_v_f64m1(a, 2)); +} +#endif + +////////////// Broadcast ////////////// + +#define OPENCV_HAL_IMPL_RVV_BROADCAST(_Tpvec, suffix) \ +template inline _Tpvec v_broadcast_element(_Tpvec v) \ +{ \ + return v_setall_##suffix(v_extract_n(v)); \ +} + +OPENCV_HAL_IMPL_RVV_BROADCAST(v_uint8x16, u8) +OPENCV_HAL_IMPL_RVV_BROADCAST(v_int8x16, s8) +OPENCV_HAL_IMPL_RVV_BROADCAST(v_uint16x8, u16) +OPENCV_HAL_IMPL_RVV_BROADCAST(v_int16x8, s16) +OPENCV_HAL_IMPL_RVV_BROADCAST(v_uint32x4, u32) +OPENCV_HAL_IMPL_RVV_BROADCAST(v_int32x4, s32) +OPENCV_HAL_IMPL_RVV_BROADCAST(v_uint64x2, u64) +OPENCV_HAL_IMPL_RVV_BROADCAST(v_int64x2, s64) +OPENCV_HAL_IMPL_RVV_BROADCAST(v_float32x4, f32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_RVV_BROADCAST(v_float64x2, f64) +#endif + +////////////// Transpose4x4 ////////////// + +#define OPENCV_HAL_IMPL_RVV_TRANSPOSE4x4(_Tpvec, _Tp, suffix) \ +inline void v_transpose4x4(const v_##_Tpvec& a0, const v_##_Tpvec& a1, \ + const v_##_Tpvec& a2, const v_##_Tpvec& a3, \ + v_##_Tpvec& b0, v_##_Tpvec& b1, \ + v_##_Tpvec& b2, v_##_Tpvec& b3) \ +{ \ + _Tp elems0[4] = \ + { \ + v_extract_n<0>(a0), \ + v_extract_n<0>(a1), \ + v_extract_n<0>(a2), \ + v_extract_n<0>(a3) \ + }; \ + b0 = v_load(elems0); \ + _Tp elems1[4] = \ + { \ + v_extract_n<1>(a0), \ + v_extract_n<1>(a1), \ + v_extract_n<1>(a2), \ + v_extract_n<1>(a3) \ + }; \ + b1 = v_load(elems1); \ + _Tp elems2[4] = \ + { \ + v_extract_n<2>(a0), \ + v_extract_n<2>(a1), \ + v_extract_n<2>(a2), \ + v_extract_n<2>(a3) \ + }; \ + b2 = v_load(elems2); \ + _Tp elems3[4] = \ + { \ + v_extract_n<3>(a0), \ + v_extract_n<3>(a1), \ + v_extract_n<3>(a2), \ + v_extract_n<3>(a3) \ + }; \ + b3 = v_load(elems3); \ +} + +OPENCV_HAL_IMPL_RVV_TRANSPOSE4x4(uint32x4, unsigned, u32) +OPENCV_HAL_IMPL_RVV_TRANSPOSE4x4(int32x4, int, i32) +OPENCV_HAL_IMPL_RVV_TRANSPOSE4x4(float32x4, float, f32) + +////////////// Reverse ////////////// + +#define OPENCV_HAL_IMPL_RVV_REVERSE(_Tpvec, _Tp, suffix) \ +inline _Tpvec v_reverse(const _Tpvec& a) \ +{ \ + _Tp ptr[_Tpvec::nlanes] = {0}; \ + _Tp ptra[_Tpvec::nlanes] = {0}; \ + v_store(ptra, a); \ + for (int i = 0; i < _Tpvec::nlanes; i++) \ + { \ + ptr[i] = ptra[_Tpvec::nlanes-i-1]; \ + } \ + return v_load(ptr); \ +} + +OPENCV_HAL_IMPL_RVV_REVERSE(v_uint8x16, uchar, u8) +OPENCV_HAL_IMPL_RVV_REVERSE(v_int8x16, schar, i8) +OPENCV_HAL_IMPL_RVV_REVERSE(v_uint16x8, ushort, u16) +OPENCV_HAL_IMPL_RVV_REVERSE(v_int16x8, short, i16) +OPENCV_HAL_IMPL_RVV_REVERSE(v_uint32x4, unsigned, u32) +OPENCV_HAL_IMPL_RVV_REVERSE(v_int32x4, int, i32) +OPENCV_HAL_IMPL_RVV_REVERSE(v_float32x4, float, f32) +OPENCV_HAL_IMPL_RVV_REVERSE(v_uint64x2, uint64, u64) +OPENCV_HAL_IMPL_RVV_REVERSE(v_int64x2, int64, i64) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_RVV_REVERSE(v_float64x2, double, f64) +#endif + +//////////// Value reordering //////////// + +#define OPENCV_HAL_IMPL_RVV_EXPAND(_Tpwvec, _Tp, _Tpvec, width, suffix, wcvt, vl) \ +inline void v_expand(const _Tpvec& a, _Tpwvec& b0, _Tpwvec& b1) \ +{ \ + _Tp lptr[_Tpvec::nlanes/2] = {0}; \ + _Tp hptr[_Tpvec::nlanes/2] = {0}; \ + v_store_low(lptr, a); \ + v_store_high(hptr, a); \ + b0 = _Tpwvec(wcvt(vle##width##_v_##suffix##mf2(lptr, vl), vl)); \ + b1 = _Tpwvec(wcvt(vle##width##_v_##suffix##mf2(hptr, vl), vl)); \ +} \ +inline _Tpwvec v_expand_low(const _Tpvec& a) \ +{ \ + _Tp lptr[_Tpvec::nlanes/2] = {0}; \ + v_store_low(lptr, a); \ + return _Tpwvec(wcvt(vle##width##_v_##suffix##mf2(lptr, vl), vl)); \ +} \ +inline _Tpwvec v_expand_high(const _Tpvec& a) \ +{ \ + _Tp hptr[_Tpvec::nlanes/2] = {0}; \ + v_store_high(hptr, a); \ + return _Tpwvec(wcvt(vle##width##_v_##suffix##mf2(hptr, vl), vl)); \ +} \ +inline _Tpwvec v_load_expand(const _Tp* ptr) \ +{ \ + return _Tpwvec(wcvt(vle##width##_v_##suffix##mf2(ptr, vl), vl)); \ +} + +OPENCV_HAL_IMPL_RVV_EXPAND(v_uint16x8, uchar, v_uint8x16, 8, u8, vwcvtu_x_x_v_u16m1, 8) +OPENCV_HAL_IMPL_RVV_EXPAND(v_int16x8, schar, v_int8x16, 8, i8, vwcvt_x_x_v_i16m1, 8) +OPENCV_HAL_IMPL_RVV_EXPAND(v_uint32x4, ushort, v_uint16x8, 16, u16, vwcvtu_x_x_v_u32m1, 4) +OPENCV_HAL_IMPL_RVV_EXPAND(v_int32x4, short, v_int16x8, 16, i16, vwcvt_x_x_v_i32m1, 4) +OPENCV_HAL_IMPL_RVV_EXPAND(v_uint64x2, uint, v_uint32x4, 32, u32, vwcvtu_x_x_v_u64m1, 2) +OPENCV_HAL_IMPL_RVV_EXPAND(v_int64x2, int, v_int32x4, 32, i32, vwcvt_x_x_v_i64m1, 2) + +inline v_uint32x4 v_load_expand_q(const uchar* ptr) +{ + return v_uint32x4(vwcvtu_x_x_v_u32m1(vwcvtu_x_x_v_u16mf2(vle8_v_u8mf4(ptr, 4), 4), 4)); +} + +inline v_int32x4 v_load_expand_q(const schar* ptr) +{ + return v_int32x4(vwcvt_x_x_v_i32m1(vwcvt_x_x_v_i16mf2(vle8_v_i8mf4(ptr, 4), 4), 4)); +} + + +#define OPENCV_HAL_IMPL_RVV_PACK(_Tpvec, _Tp, _wTpvec, _wTp, hwidth, width, hsuffix, suffix, rshr, shr, hvl, vl) \ +inline _Tpvec v_pack(const _wTpvec& a, const _wTpvec& b) \ +{ \ + _wTp arr[_Tpvec::nlanes] = {0}; \ + v_store(arr, a); \ + v_store(arr + _wTpvec::nlanes, b); \ + return _Tpvec(shr(vle##width##_v_##suffix##m2(arr, vl), 0, vl)); \ +} \ +inline void v_pack_store(_Tp* ptr, const _wTpvec& a) \ +{ \ + _wTp arr[_Tpvec::nlanes] = {0}; \ + v_store(arr, a); \ + v_store(arr + _wTpvec::nlanes, _wTpvec(vmv_v_x_##suffix##m1(0, hvl))); \ + vse##hwidth##_v_##hsuffix##m1(ptr, shr(vle##width##_v_##suffix##m2(arr, vl), 0, vl), hvl); \ +} \ +template inline \ +_Tpvec v_rshr_pack(const _wTpvec& a, const _wTpvec& b) \ +{ \ + _wTp arr[_Tpvec::nlanes] = {0}; \ + v_store(arr, a); \ + v_store(arr + _wTpvec::nlanes, b); \ + return _Tpvec(rshr(vle##width##_v_##suffix##m2(arr, vl), n, vl)); \ +} \ +template inline \ +void v_rshr_pack_store(_Tp* ptr, const _wTpvec& a) \ +{ \ + _wTp arr[_Tpvec::nlanes] = {0}; \ + v_store(arr, a); \ + v_store(arr + _wTpvec::nlanes, _wTpvec(vmv_v_x_##suffix##m1(0, hvl))); \ + vse##hwidth##_v_##hsuffix##m1(ptr, _Tpvec(rshr(vle##width##_v_##suffix##m2(arr, vl), n, vl)), hvl); \ +} + +OPENCV_HAL_IMPL_RVV_PACK(v_uint8x16, uchar, v_uint16x8, ushort, 8, 16, u8, u16, vnclipu_wx_u8m1, vnclipu_wx_u8m1, 8, 16) +OPENCV_HAL_IMPL_RVV_PACK(v_int8x16, schar, v_int16x8, short, 8, 16, i8, i16, vnclip_wx_i8m1, vnclip_wx_i8m1, 8, 16) +OPENCV_HAL_IMPL_RVV_PACK(v_uint16x8, ushort, v_uint32x4, unsigned, 16, 32, u16, u32, vnclipu_wx_u16m1, vnclipu_wx_u16m1, 4, 8) +OPENCV_HAL_IMPL_RVV_PACK(v_int16x8, short, v_int32x4, int, 16, 32, i16, i32, vnclip_wx_i16m1, vnclip_wx_i16m1, 4, 8) +OPENCV_HAL_IMPL_RVV_PACK(v_uint32x4, unsigned, v_uint64x2, uint64, 32, 64, u32, u64, vnclipu_wx_u32m1, vnsrl_wx_u32m1, 2, 4) +OPENCV_HAL_IMPL_RVV_PACK(v_int32x4, int, v_int64x2, int64, 32, 64, i32, i64, vnclip_wx_i32m1, vnsra_wx_i32m1, 2, 4) + + +#define OPENCV_HAL_IMPL_RVV_PACK_U(_Tpvec, _Tp, _wTpvec, _wTp, hwidth, width, hsuffix, suffix, rshr, cast, hvl, vl) \ +inline _Tpvec v_pack_u(const _wTpvec& a, const _wTpvec& b) \ +{ \ + _wTp arr[_Tpvec::nlanes] = {0}; \ + v_store(arr, a); \ + v_store(arr + _wTpvec::nlanes, b); \ + return _Tpvec(rshr(cast(vmax_vx_##suffix##m2(vle##width##_v_##suffix##m2(arr, vl), 0, vl)), 0, vl)); \ +} \ +inline void v_pack_u_store(_Tp* ptr, const _wTpvec& a) \ +{ \ + _wTp arr[_Tpvec::nlanes] = {0}; \ + v_store(arr, a); \ + v_store(arr + _wTpvec::nlanes, _wTpvec(vmv_v_x_##suffix##m1(0, hvl))); \ + vse##hwidth##_v_##hsuffix##m1(ptr, rshr(cast(vmax_vx_##suffix##m2(vle##width##_v_##suffix##m2(arr, vl), 0, vl)), 0, vl), hvl); \ +} \ +template inline \ +_Tpvec v_rshr_pack_u(const _wTpvec& a, const _wTpvec& b) \ +{ \ + _wTp arr[_Tpvec::nlanes] = {0}; \ + v_store(arr, a); \ + v_store(arr + _wTpvec::nlanes, b); \ + return _Tpvec(rshr(cast(vmax_vx_##suffix##m2(vle##width##_v_##suffix##m2(arr, vl), 0, vl)), n, vl)); \ +} \ +template inline \ +void v_rshr_pack_u_store(_Tp* ptr, const _wTpvec& a) \ +{ \ + _wTp arr[_Tpvec::nlanes] = {0}; \ + v_store(arr, a); \ + v_store(arr + _wTpvec::nlanes, _wTpvec(vmv_v_x_##suffix##m1(0, hvl))); \ + v_store(ptr, _Tpvec(rshr(cast(vmax_vx_##suffix##m2(vle##width##_v_##suffix##m2(arr, vl), 0, vl)), n, vl))); \ +} + +OPENCV_HAL_IMPL_RVV_PACK_U(v_uint8x16, uchar, v_int16x8, short, 8, 16, u8, i16, vnclipu_wx_u8m1, vreinterpret_v_i16m2_u16m2, 8, 16) +OPENCV_HAL_IMPL_RVV_PACK_U(v_uint16x8, ushort, v_int32x4, int, 16, 32, u16, i32, vnclipu_wx_u16m1, vreinterpret_v_i32m2_u32m2, 4, 8) + + +#define OPENCV_HAL_IMPL_RVV_UNPACKS(_Tpvec, _Tp, suffix) \ +inline void v_zip(const v_##_Tpvec& a0, const v_##_Tpvec& a1, v_##_Tpvec& b0, v_##_Tpvec& b1) \ +{ \ + _Tp ptra0[v_##_Tpvec::nlanes] = {0}; \ + _Tp ptra1[v_##_Tpvec::nlanes] = {0}; \ + _Tp ptrb0[v_##_Tpvec::nlanes] = {0}; \ + _Tp ptrb1[v_##_Tpvec::nlanes] = {0}; \ + v_store(ptra0, a0); \ + v_store(ptra1, a1); \ + int i; \ + for( i = 0; i < v_##_Tpvec::nlanes/2; i++ ) \ + { \ + ptrb0[i*2] = ptra0[i]; \ + ptrb0[i*2+1] = ptra1[i]; \ + } \ + for( ; i < v_##_Tpvec::nlanes; i++ ) \ + { \ + ptrb1[i*2-v_##_Tpvec::nlanes] = ptra0[i]; \ + ptrb1[i*2-v_##_Tpvec::nlanes+1] = ptra1[i]; \ + } \ + b0 = v_load(ptrb0); \ + b1 = v_load(ptrb1); \ +} \ +inline v_##_Tpvec v_combine_low(const v_##_Tpvec& a, const v_##_Tpvec& b) \ +{ \ + _Tp ptra[v_##_Tpvec::nlanes/2] = {0}; \ + _Tp ptrb[v_##_Tpvec::nlanes/2] = {0}; \ + v_store_low(ptra, a); \ + v_store_low(ptrb, b); \ + return v_load_halves(ptra, ptrb); \ +} \ +inline v_##_Tpvec v_combine_high(const v_##_Tpvec& a, const v_##_Tpvec& b) \ +{ \ + _Tp ptra[v_##_Tpvec::nlanes/2] = {0}; \ + _Tp ptrb[v_##_Tpvec::nlanes/2] = {0}; \ + v_store_high(ptra, a); \ + v_store_high(ptrb, b); \ + return v_load_halves(ptra, ptrb); \ +} \ +inline void v_recombine(const v_##_Tpvec& a, const v_##_Tpvec& b, v_##_Tpvec& c, v_##_Tpvec& d) \ +{ \ + c = v_combine_low(a, b); \ + d = v_combine_high(a, b); \ +} + +OPENCV_HAL_IMPL_RVV_UNPACKS(uint8x16, uchar, u8) +OPENCV_HAL_IMPL_RVV_UNPACKS(int8x16, schar, i8) +OPENCV_HAL_IMPL_RVV_UNPACKS(uint16x8, ushort, u16) +OPENCV_HAL_IMPL_RVV_UNPACKS(int16x8, short, i16) +OPENCV_HAL_IMPL_RVV_UNPACKS(uint32x4, unsigned, u32) +OPENCV_HAL_IMPL_RVV_UNPACKS(int32x4, int, i32) +OPENCV_HAL_IMPL_RVV_UNPACKS(float32x4, float, f32) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_RVV_UNPACKS(float64x2, double, f64) +#endif + + +#define OPENCV_HAL_IMPL_RVV_INTERLEAVED(_Tpvec, _Tp) \ +inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec& a, v_##_Tpvec& b) \ +{ \ + _Tp ptra[v_##_Tpvec::nlanes] = {0}; \ + _Tp ptrb[v_##_Tpvec::nlanes] = {0}; \ + int i, i2; \ + for( i = i2 = 0; i < v_##_Tpvec::nlanes; i++, i2 += 2 ) \ + { \ + ptra[i] = ptr[i2]; \ + ptrb[i] = ptr[i2+1]; \ + } \ + a = v_load(ptra); \ + b = v_load(ptrb); \ +} \ +inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec& a, v_##_Tpvec& b, v_##_Tpvec& c) \ +{ \ + _Tp ptra[v_##_Tpvec::nlanes] = {0}; \ + _Tp ptrb[v_##_Tpvec::nlanes] = {0}; \ + _Tp ptrc[v_##_Tpvec::nlanes] = {0}; \ + int i, i3; \ + for( i = i3 = 0; i < v_##_Tpvec::nlanes; i++, i3 += 3 ) \ + { \ + ptra[i] = ptr[i3]; \ + ptrb[i] = ptr[i3+1]; \ + ptrc[i] = ptr[i3+2]; \ + } \ + a = v_load(ptra); \ + b = v_load(ptrb); \ + c = v_load(ptrc); \ +} \ +inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec& a, v_##_Tpvec& b, \ + v_##_Tpvec& c, v_##_Tpvec& d) \ +{ \ + _Tp ptra[v_##_Tpvec::nlanes] = {0}; \ + _Tp ptrb[v_##_Tpvec::nlanes] = {0}; \ + _Tp ptrc[v_##_Tpvec::nlanes] = {0}; \ + _Tp ptrd[v_##_Tpvec::nlanes] = {0}; \ + int i, i4; \ + for( i = i4 = 0; i < v_##_Tpvec::nlanes; i++, i4 += 4 ) \ + { \ + ptra[i] = ptr[i4]; \ + ptrb[i] = ptr[i4+1]; \ + ptrc[i] = ptr[i4+2]; \ + ptrd[i] = ptr[i4+3]; \ + } \ + a = v_load(ptra); \ + b = v_load(ptrb); \ + c = v_load(ptrc); \ + d = v_load(ptrd); \ +} \ +inline void v_store_interleave( _Tp* ptr, const v_##_Tpvec& a, const v_##_Tpvec& b, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ \ + int i, i2; \ + _Tp ptra[v_##_Tpvec::nlanes] = {0}; \ + _Tp ptrb[v_##_Tpvec::nlanes] = {0}; \ + v_store(ptra, a); \ + v_store(ptrb, b); \ + for( i = i2 = 0; i < v_##_Tpvec::nlanes; i++, i2 += 2 ) \ + { \ + ptr[i2] = ptra[i]; \ + ptr[i2+1] = ptrb[i]; \ + } \ +} \ +inline void v_store_interleave( _Tp* ptr, const v_##_Tpvec& a, const v_##_Tpvec& b, \ + const v_##_Tpvec& c, hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ \ + int i, i3; \ + _Tp ptra[v_##_Tpvec::nlanes] = {0}; \ + _Tp ptrb[v_##_Tpvec::nlanes] = {0}; \ + _Tp ptrc[v_##_Tpvec::nlanes] = {0}; \ + v_store(ptra, a); \ + v_store(ptrb, b); \ + v_store(ptrc, c); \ + for( i = i3 = 0; i < v_##_Tpvec::nlanes; i++, i3 += 3 ) \ + { \ + ptr[i3] = ptra[i]; \ + ptr[i3+1] = ptrb[i]; \ + ptr[i3+2] = ptrc[i]; \ + } \ +} \ +inline void v_store_interleave( _Tp* ptr, const v_##_Tpvec& a, const v_##_Tpvec& b, \ + const v_##_Tpvec& c, const v_##_Tpvec& d, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED ) \ +{ \ + int i, i4; \ + _Tp ptra[v_##_Tpvec::nlanes] = {0}; \ + _Tp ptrb[v_##_Tpvec::nlanes] = {0}; \ + _Tp ptrc[v_##_Tpvec::nlanes] = {0}; \ + _Tp ptrd[v_##_Tpvec::nlanes] = {0}; \ + v_store(ptra, a); \ + v_store(ptrb, b); \ + v_store(ptrc, c); \ + v_store(ptrd, d); \ + for( i = i4 = 0; i < v_##_Tpvec::nlanes; i++, i4 += 4 ) \ + { \ + ptr[i4] = ptra[i]; \ + ptr[i4+1] = ptrb[i]; \ + ptr[i4+2] = ptrc[i]; \ + ptr[i4+3] = ptrd[i]; \ + } \ +} \ +inline v_##_Tpvec v_interleave_pairs(const v_##_Tpvec& vec) \ +{ \ + _Tp ptr[v_##_Tpvec::nlanes] = {0}; \ + _Tp ptrvec[v_##_Tpvec::nlanes] = {0}; \ + v_store(ptrvec, vec); \ + for (int i = 0; i < v_##_Tpvec::nlanes/4; i++) \ + { \ + ptr[4*i ] = ptrvec[4*i ]; \ + ptr[4*i+1] = ptrvec[4*i+2]; \ + ptr[4*i+2] = ptrvec[4*i+1]; \ + ptr[4*i+3] = ptrvec[4*i+3]; \ + } \ + return v_load(ptr); \ +} \ +inline v_##_Tpvec v_interleave_quads(const v_##_Tpvec& vec) \ +{ \ + _Tp ptr[v_##_Tpvec::nlanes] = {0}; \ + _Tp ptrvec[v_##_Tpvec::nlanes] = {0}; \ + v_store(ptrvec, vec); \ + for (int i = 0; i < v_##_Tpvec::nlanes/8; i++) \ + { \ + ptr[8*i ] = ptrvec[4*i ]; \ + ptr[8*i+1] = ptrvec[4*i+4]; \ + ptr[8*i+2] = ptrvec[4*i+1]; \ + ptr[8*i+3] = ptrvec[4*i+5]; \ + ptr[8*i+4] = ptrvec[4*i+2]; \ + ptr[8*i+5] = ptrvec[4*i+6]; \ + ptr[8*i+6] = ptrvec[4*i+3]; \ + ptr[8*i+7] = ptrvec[4*i+7]; \ + } \ + return v_load(ptr); \ +} + +OPENCV_HAL_IMPL_RVV_INTERLEAVED(uint8x16, uchar) +OPENCV_HAL_IMPL_RVV_INTERLEAVED(int8x16, schar) +OPENCV_HAL_IMPL_RVV_INTERLEAVED(uint16x8, ushort) +OPENCV_HAL_IMPL_RVV_INTERLEAVED(int16x8, short) +OPENCV_HAL_IMPL_RVV_INTERLEAVED(uint32x4, unsigned) +OPENCV_HAL_IMPL_RVV_INTERLEAVED(int32x4, int) +OPENCV_HAL_IMPL_RVV_INTERLEAVED(float32x4, float) +OPENCV_HAL_IMPL_RVV_INTERLEAVED(uint64x2, uint64) +OPENCV_HAL_IMPL_RVV_INTERLEAVED(int64x2, int64) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_RVV_INTERLEAVED(float64x2, double) +#endif + +//////////// PopCount //////////// + +static const unsigned char popCountTable[] = +{ + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, +}; + +#define OPENCV_HAL_IMPL_RVV_POPCOUNT_OP(_rTpvec, _Tpvec, _rTp, _Tp, suffix) \ +inline _rTpvec v_popcount(const _Tpvec& a) \ +{ \ + uchar ptra[16] = {0}; \ + v_store(ptra, v_reinterpret_as_u8(a)); \ + _rTp ptr[_Tpvec::nlanes] = {0}; \ + v_store(ptr, v_setzero_##suffix()); \ + for (int i = 0; i < _Tpvec::nlanes*(int)sizeof(_Tp); i++) \ + ptr[i/sizeof(_Tp)] += popCountTable[ptra[i]]; \ + return v_load(ptr); \ +} + +OPENCV_HAL_IMPL_RVV_POPCOUNT_OP(v_uint8x16, v_uint8x16, uchar, uchar, u8) +OPENCV_HAL_IMPL_RVV_POPCOUNT_OP(v_uint8x16, v_int8x16, uchar, schar, u8) +OPENCV_HAL_IMPL_RVV_POPCOUNT_OP(v_uint16x8, v_uint16x8, ushort, ushort, u16) +OPENCV_HAL_IMPL_RVV_POPCOUNT_OP(v_uint16x8, v_int16x8, ushort, short, u16) +OPENCV_HAL_IMPL_RVV_POPCOUNT_OP(v_uint32x4, v_uint32x4, unsigned, unsigned, u32) +OPENCV_HAL_IMPL_RVV_POPCOUNT_OP(v_uint32x4, v_int32x4, unsigned, int, u32) +OPENCV_HAL_IMPL_RVV_POPCOUNT_OP(v_uint64x2, v_uint64x2, uint64, uint64, u64) +OPENCV_HAL_IMPL_RVV_POPCOUNT_OP(v_uint64x2, v_int64x2, uint64, int64, u64) + +//////////// SignMask //////////// + +#ifndef __clang__ +#define OPENCV_HAL_IMPL_RVV_SIGNMASK_OP(_Tpvec, _Tp, suffix, vl, shift) \ +inline int v_signmask(const _Tpvec& a) \ +{ \ + int mask = 0; \ + _Tpvec tmp = _Tpvec(vsrl_vx_##suffix##m1(a, shift, vl)); \ + for( int i = 0; i < _Tpvec::nlanes; i++ ) \ + mask |= (int)(tmp.val[i]) << i; \ + return mask; \ +} + +OPENCV_HAL_IMPL_RVV_SIGNMASK_OP(v_uint8x16, uchar, u8, 16, 7) +OPENCV_HAL_IMPL_RVV_SIGNMASK_OP(v_uint16x8, ushort, u16, 8, 15) +OPENCV_HAL_IMPL_RVV_SIGNMASK_OP(v_uint32x4, unsigned, u32, 4, 31) +OPENCV_HAL_IMPL_RVV_SIGNMASK_OP(v_uint64x2, uint64, u64, 2, 63) + +inline int v_signmask(const v_int8x16& a) +{ return v_signmask(v_reinterpret_as_u8(a)); } +inline int v_signmask(const v_int16x8& a) +{ return v_signmask(v_reinterpret_as_u16(a)); } +inline int v_signmask(const v_int32x4& a) +{ return v_signmask(v_reinterpret_as_u32(a)); } +inline int v_signmask(const v_float32x4& a) +{ return v_signmask(v_reinterpret_as_u32(a)); } +inline int v_signmask(const v_int64x2& a) +{ return v_signmask(v_reinterpret_as_u64(a)); } +#if CV_SIMD128_64F +inline int v_signmask(const v_float64x2& a) +{ return v_signmask(v_reinterpret_as_u64(a)); } +#endif + +#else +#define OPENCV_HAL_IMPL_RVV_SIGNMASK_OP(_Tpvec, width, vl) \ +inline int v_signmask(const _Tpvec& a) \ +{ \ + uint8_t ans[16] = {0};\ + vsm(ans, vmslt(a, 0, vl), vl);\ + return reinterpret_cast(ans)[0];\ +} + +OPENCV_HAL_IMPL_RVV_SIGNMASK_OP(v_int8x16, 8, 16) +OPENCV_HAL_IMPL_RVV_SIGNMASK_OP(v_int16x8, 16, 8) +OPENCV_HAL_IMPL_RVV_SIGNMASK_OP(v_int32x4, 32, 4) +OPENCV_HAL_IMPL_RVV_SIGNMASK_OP(v_int64x2, 64, 2) + +inline int v_signmask(const v_uint8x16& a) +{ return v_signmask(v_reinterpret_as_s8(a)); } +inline int v_signmask(const v_uint16x8& a) +{ return v_signmask(v_reinterpret_as_s16(a)); } +inline int v_signmask(const v_uint32x4& a) +{ return v_signmask(v_reinterpret_as_s32(a)); } +inline int v_signmask(const v_float32x4& a) +{ return v_signmask(v_reinterpret_as_s32(a)); } +inline int v_signmask(const v_uint64x2& a) +{ return v_signmask(v_reinterpret_as_s64(a)); } +#if CV_SIMD128_64F +inline int v_signmask(const v_float64x2& a) +{ return v_signmask(v_reinterpret_as_s64(a)); } +#endif + +#endif + +//////////// Scan forward //////////// + +#define OPENCV_HAL_IMPL_RVV_SCAN_FORWOARD_OP(_Tpvec, _Tp, suffix) \ +inline int v_scan_forward(const _Tpvec& a) \ +{ \ + _Tp ptr[_Tpvec::nlanes] = {0}; \ + v_store(ptr, v_reinterpret_as_##suffix(a)); \ + for (int i = 0; i < _Tpvec::nlanes; i++) \ + if(int(ptr[i]) < 0) \ + return i; \ + return 0; \ +} + +OPENCV_HAL_IMPL_RVV_SCAN_FORWOARD_OP(v_uint8x16, uchar, u8) +OPENCV_HAL_IMPL_RVV_SCAN_FORWOARD_OP(v_int8x16, schar, s8) +OPENCV_HAL_IMPL_RVV_SCAN_FORWOARD_OP(v_uint16x8, ushort, u16) +OPENCV_HAL_IMPL_RVV_SCAN_FORWOARD_OP(v_int16x8, short, s16) +OPENCV_HAL_IMPL_RVV_SCAN_FORWOARD_OP(v_uint32x4, unsigned, u32) +OPENCV_HAL_IMPL_RVV_SCAN_FORWOARD_OP(v_int32x4, int, s32) +OPENCV_HAL_IMPL_RVV_SCAN_FORWOARD_OP(v_float32x4, float, f32) +OPENCV_HAL_IMPL_RVV_SCAN_FORWOARD_OP(v_uint64x2, uint64, u64) +OPENCV_HAL_IMPL_RVV_SCAN_FORWOARD_OP(v_int64x2, int64, s64) +#if CV_SIMD128_64F +OPENCV_HAL_IMPL_RVV_SCAN_FORWOARD_OP(v_float64x2, double, f64) +#endif + +//////////// Pack triplets //////////// + +// use reinterpret instead of c-style casting. +#ifndef __clang__ +inline v_int8x16 v_pack_triplets(const v_int8x16& vec) +{ + uint64 ptr[2] = {0x0908060504020100, 0xFFFFFFFF0E0D0C0A}; + return v_int8x16((vint8m1_t)vrgather_vv_u8m1((vuint8m1_t)vint8m1_t(vec), (vuint8m1_t)vle64_v_u64m1(ptr, 2), 16)); +} +inline v_uint8x16 v_pack_triplets(const v_uint8x16& vec) +{ + return v_reinterpret_as_u8(v_pack_triplets(v_reinterpret_as_s8(vec))); +} + +inline v_int16x8 v_pack_triplets(const v_int16x8& vec) +{ + uint64 ptr[2] = {0x0908060504020100, 0xFFFFFFFF0E0D0C0A}; + return v_int16x8((vint16m1_t)vrgather_vv_u8m1((vuint8m1_t)vint16m1_t(vec), (vuint8m1_t)vle64_v_u64m1(ptr, 2), 16)); +} +inline v_uint16x8 v_pack_triplets(const v_uint16x8& vec) +{ + return v_reinterpret_as_u16(v_pack_triplets(v_reinterpret_as_s16(vec))); +} + +inline v_int32x4 v_pack_triplets(const v_int32x4& vec) { return vec; } +inline v_uint32x4 v_pack_triplets(const v_uint32x4& vec) { return vec; } +inline v_float32x4 v_pack_triplets(const v_float32x4& vec) { return vec; } + +#else + +inline v_int8x16 v_pack_triplets(const v_int8x16& vec) +{ + uint64 ptr[2] = {0x0908060504020100, 0xFFFFFFFF0E0D0C0A}; + return v_int8x16(vreinterpret_i8m1(vrgather_vv_u8m1(v_reinterpret_as_u8(vec), vreinterpret_u8m1(vle64_v_u64m1(ptr, 2)), 16))); +} +inline v_uint8x16 v_pack_triplets(const v_uint8x16& vec) +{ + return v_reinterpret_as_u8(v_pack_triplets(v_reinterpret_as_s8(vec))); +} + +inline v_int16x8 v_pack_triplets(const v_int16x8& vec) +{ + uint64 ptr[2] = {0x0908060504020100, 0xFFFFFFFF0E0D0C0A}; + return v_int16x8(v_reinterpret_as_s16(v_uint8x16(vrgather_vv_u8m1(v_reinterpret_as_u8(vec), vreinterpret_u8m1(vle64_v_u64m1(ptr, 2)), 16)))); +} +inline v_uint16x8 v_pack_triplets(const v_uint16x8& vec) +{ + return v_reinterpret_as_u16(v_pack_triplets(v_reinterpret_as_s16(vec))); +} + +inline v_int32x4 v_pack_triplets(const v_int32x4& vec) { return vec; } +inline v_uint32x4 v_pack_triplets(const v_uint32x4& vec) { return vec; } +inline v_float32x4 v_pack_triplets(const v_float32x4& vec) { return vec; } + +#endif + +////// FP16 support /////// + +#if CV_FP16 +inline v_float32x4 v_load_expand(const float16_t* ptr) +{ + return v_float32x4(vfwcvt_f_f_v_f32m1(vle16_v_f16mf2(ptr, 4), 4)); +} + +inline void v_pack_store(float16_t* ptr, const v_float32x4& v) +{ + vse16_v_f16mf2(ptr, vfncvt_f_f_w_f16mf2(v, 4), 4); +} +#else +inline v_float32x4 v_load_expand(const float16_t* ptr) +{ + const int N = 4; + float buf[N]; + for( int i = 0; i < N; i++ ) buf[i] = (float)ptr[i]; + return v_load(buf); +} + +inline void v_pack_store(float16_t* ptr, const v_float32x4& v) +{ + const int N = 4; + float buf[N]; + v_store(buf, v); + for( int i = 0; i < N; i++ ) ptr[i] = float16_t(buf[i]); +} +#endif + +////////////// Rounding ////////////// + +inline v_int32x4 v_round(const v_float32x4& a) +{ + return v_int32x4(vfcvt_x_f_v_i32m1(a, 4)); +} + +inline v_int32x4 v_floor(const v_float32x4& a) +{ + v_float32x4 ZP5 = v_setall_f32(0.5f); + v_float32x4 t = a - ZP5; + return v_int32x4(vfcvt_x_f_v_i32m1(t, 4)); +} + +inline v_int32x4 v_ceil(const v_float32x4& a) +{ + v_float32x4 ZP5 = v_setall_f32(0.5f); + v_float32x4 t = a + ZP5; + return v_int32x4(vfcvt_x_f_v_i32m1(t, 4)); +} + +inline v_int32x4 v_trunc(const v_float32x4& a) +{ + return v_int32x4(vfcvt_rtz_x_f_v_i32m1(a, 4)); +} +#if CV_SIMD128_64F +#ifndef __clang__ +inline v_int32x4 v_round(const v_float64x2& a) +{ + double arr[4] = {a.val[0], a.val[1], 0, 0}; + vfloat64m2_t tmp = vle64_v_f64m2(arr, 4); + return v_int32x4(vfncvt_x_f_w_i32m1(tmp, 4)); +} + +inline v_int32x4 v_round(const v_float64x2& a, const v_float64x2& b) +{ + double arr[4] = {a.val[0], a.val[1], b.val[0], b.val[1]}; + vfloat64m2_t tmp = vle64_v_f64m2(arr, 4); + return v_int32x4(vfncvt_x_f_w_i32m1(tmp, 4)); +} + +inline v_int32x4 v_floor(const v_float64x2& a) +{ + double arr[4] = {a.val[0]-0.5f, a.val[1]-0.5f, 0, 0}; + vfloat64m2_t tmp = vle64_v_f64m2(arr, 4); + return v_int32x4(vfncvt_x_f_w_i32m1(tmp, 4)); +} + +inline v_int32x4 v_ceil(const v_float64x2& a) +{ + double arr[4] = {a.val[0]+0.5f, a.val[1]+0.5f, 0, 0}; + vfloat64m2_t tmp = vle64_v_f64m2(arr, 4); + return v_int32x4(vfncvt_x_f_w_i32m1(tmp, 4)); +} + +inline v_int32x4 v_trunc(const v_float64x2& a) +{ + double arr[4] = {a.val[0], a.val[1], 0, 0}; + vfloat64m2_t tmp = vle64_v_f64m2(arr, 4); + return v_int32x4(vfncvt_rtz_x_f_w_i32m1(tmp, 4)); +} + +#else +inline v_int32x4 v_round(const v_float64x2& a) +{ + vfloat64m2_t zero = vfmv_v_f_f64m2(0, 4); + return v_int32x4(vfncvt_x_f_w_i32m1(vset_v_f64m1_f64m2(zero, 0, a), 4)); +} + +inline v_int32x4 v_round(const v_float64x2& a, const v_float64x2& b) +{ + vfloat64m2_t dst = vlmul_ext_v_f64m1_f64m2(a); + return v_int32x4(vfncvt_x_f_w_i32m1(vset_v_f64m1_f64m2(dst, 1, b), 4)); +} + +inline v_int32x4 v_floor(const v_float64x2& a) +{ + vfloat64m2_t dst = vfmv_v_f_f64m2(0, 4); + dst = vset_v_f64m1_f64m2(dst, 0, a); + dst = vfsub_vf_f64m2(dst, 0.5, 2); + return v_int32x4(vfncvt_x_f_w_i32m1(dst, 4)); +} + +inline v_int32x4 v_ceil(const v_float64x2& a) +{ + vfloat64m2_t dst = vfmv_v_f_f64m2(0, 4); + dst = vset_v_f64m1_f64m2(dst, 0, a); + dst = vfadd_vf_f64m2(dst, 0.5, 2); + return v_int32x4(vfncvt_x_f_w_i32m1(dst, 4)); +} + +inline v_int32x4 v_trunc(const v_float64x2& a) +{ + vfloat64m2_t zero = vfmv_v_f_f64m2(0, 4); + return v_int32x4(vfncvt_rtz_x_f_w_i32m1(vset_v_f64m1_f64m2(zero, 0, a), 4)); +} +#endif +#endif + + +//////// Dot Product //////// + +// 16 >> 32 +inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b) +{ + int ptr[8] = {0}; + v_int32x4 t1, t2; + vse32_v_i32m2(ptr, vwmul_vv_i32m2(a, b, 8), 8); + v_load_deinterleave(ptr, t1, t2); + return t1 + t2; +} +inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b, const v_int32x4& c) +{ + int ptr[8] = {0}; + v_int32x4 t1, t2; + vse32_v_i32m2(ptr, vwmul_vv_i32m2(a, b, 8), 8); + v_load_deinterleave(ptr, t1, t2); + return t1 + t2 + c; +} + +// 32 >> 64 +inline v_int64x2 v_dotprod(const v_int32x4& a, const v_int32x4& b) +{ + int64 ptr[4] = {0}; + v_int64x2 t1, t2; + vse64_v_i64m2(ptr, vwmul_vv_i64m2(a, b, 4), 4); + v_load_deinterleave(ptr, t1, t2); + return t1 + t2; +} +inline v_int64x2 v_dotprod(const v_int32x4& a, const v_int32x4& b, const v_int64x2& c) +{ + int64 ptr[4] = {0}; + v_int64x2 t1, t2; + vse64_v_i64m2(ptr, vwmul_vv_i64m2(a, b, 4), 4); + v_load_deinterleave(ptr, t1, t2); + return t1 + t2 + c; +} + +// 8 >> 32 +inline v_uint32x4 v_dotprod_expand(const v_uint8x16& a, const v_uint8x16& b) +{ + unsigned ptr[16] = {0}; + v_uint32x4 t1, t2, t3, t4; + vse32_v_u32m4(ptr, vwcvtu_x_x_v_u32m4(vwmulu_vv_u16m2(a, b, 16), 16), 16); + v_load_deinterleave(ptr, t1, t2, t3, t4); + return t1 + t2 + t3 + t4; +} +inline v_uint32x4 v_dotprod_expand(const v_uint8x16& a, const v_uint8x16& b, + const v_uint32x4& c) +{ + unsigned ptr[16] = {0}; + v_uint32x4 t1, t2, t3, t4; + vse32_v_u32m4(ptr, vwcvtu_x_x_v_u32m4(vwmulu_vv_u16m2(a, b, 16), 16), 16); + v_load_deinterleave(ptr, t1, t2, t3, t4); + return t1 + t2 + t3 + t4 + c; +} + +inline v_int32x4 v_dotprod_expand(const v_int8x16& a, const v_int8x16& b) +{ + int ptr[16] = {0}; + v_int32x4 t1, t2, t3, t4; + vse32_v_i32m4(ptr, vwcvt_x_x_v_i32m4(vwmul_vv_i16m2(a, b, 16), 16), 16); + v_load_deinterleave(ptr, t1, t2, t3, t4); + return t1 + t2 + t3 + t4; +} +inline v_int32x4 v_dotprod_expand(const v_int8x16& a, const v_int8x16& b, + const v_int32x4& c) +{ + int ptr[16] = {0}; + v_int32x4 t1, t2, t3, t4; + vse32_v_i32m4(ptr, vwcvt_x_x_v_i32m4(vwmul_vv_i16m2(a, b, 16), 16), 16); + v_load_deinterleave(ptr, t1, t2, t3, t4); + return t1 + t2 + t3 + t4 + c; +} + +// 16 >> 64 +inline v_uint64x2 v_dotprod_expand(const v_uint16x8& a, const v_uint16x8& b) +{ + uint64 ptr[8] = {0}; + v_uint64x2 t1, t2, t3, t4; + vse64_v_u64m4(ptr, vwcvtu_x_x_v_u64m4(vwmulu_vv_u32m2(a, b, 8), 8), 8); + v_load_deinterleave(ptr, t1, t2, t3, t4); + return t1 + t2 + t3 + t4; +} +inline v_uint64x2 v_dotprod_expand(const v_uint16x8& a, const v_uint16x8& b, const v_uint64x2& c) +{ + uint64 ptr[8] = {0}; + v_uint64x2 t1, t2, t3, t4; + vse64_v_u64m4(ptr, vwcvtu_x_x_v_u64m4(vwmulu_vv_u32m2(a, b, 8), 8), 8); + v_load_deinterleave(ptr, t1, t2, t3, t4); + return t1 + t2 + t3 + t4 + c; +} + +inline v_int64x2 v_dotprod_expand(const v_int16x8& a, const v_int16x8& b) +{ + int64 ptr[8] = {0}; + v_int64x2 t1, t2, t3, t4; + vse64_v_i64m4(ptr, vwcvt_x_x_v_i64m4(vwmul_vv_i32m2(a, b, 8), 8), 8); + v_load_deinterleave(ptr, t1, t2, t3, t4); + return t1 + t2 + t3 + t4; +} +inline v_int64x2 v_dotprod_expand(const v_int16x8& a, const v_int16x8& b, + const v_int64x2& c) +{ + int64 ptr[8] = {0}; + v_int64x2 t1, t2, t3, t4; + vse64_v_i64m4(ptr, vwcvt_x_x_v_i64m4(vwmul_vv_i32m2(a, b, 8), 8), 8); + v_load_deinterleave(ptr, t1, t2, t3, t4); + return t1 + t2 + t3 + t4 + c; +} + +// 32 >> 64f +#if CV_SIMD128_64F +inline v_float64x2 v_dotprod_expand(const v_int32x4& a, const v_int32x4& b) +{ return v_cvt_f64(v_dotprod(a, b)); } +inline v_float64x2 v_dotprod_expand(const v_int32x4& a, const v_int32x4& b, + const v_float64x2& c) +{ return v_dotprod_expand(a, b) + c; } +#endif + +//////// Fast Dot Product //////// + +// 16 >> 32 +inline v_int32x4 v_dotprod_fast(const v_int16x8& a, const v_int16x8& b) +{ + int ptr[8] = {0}; + vse32_v_i32m2(ptr, vwmul_vv_i32m2(a, b, 8), 8); + v_int32x4 t1 = v_load(ptr); + v_int32x4 t2 = v_load(ptr+4); + return t1 + t2; +} +inline v_int32x4 v_dotprod_fast(const v_int16x8& a, const v_int16x8& b, const v_int32x4& c) +{ + int ptr[8] = {0}; + vse32_v_i32m2(ptr, vwmul_vv_i32m2(a, b, 8), 8); + v_int32x4 t1 = v_load(ptr); + v_int32x4 t2 = v_load(ptr+4); + return t1 + t2 + c; +} + +// 32 >> 64 +inline v_int64x2 v_dotprod_fast(const v_int32x4& a, const v_int32x4& b) +{ + int64 ptr[4] = {0}; + vse64_v_i64m2(ptr, vwmul_vv_i64m2(a, b, 4), 4); + v_int64x2 t1 = v_load(ptr); + v_int64x2 t2 = v_load(ptr+2); + return t1 + t2; +} +inline v_int64x2 v_dotprod_fast(const v_int32x4& a, const v_int32x4& b, const v_int64x2& c) +{ + int64 ptr[4] = {0}; + vse64_v_i64m2(ptr, vwmul_vv_i64m2(a, b, 4), 4); + v_int64x2 t1 = v_load(ptr); + v_int64x2 t2 = v_load(ptr+2); + return t1 + t2 + c; +} + + +// 8 >> 32 +inline v_uint32x4 v_dotprod_expand_fast(const v_uint8x16& a, const v_uint8x16& b) +{ + unsigned ptr[16] = {0}; + vse32_v_u32m4(ptr, vwcvtu_x_x_v_u32m4(vwmulu_vv_u16m2(a, b, 16), 16), 16); + v_uint32x4 t1 = v_load(ptr); + v_uint32x4 t2 = v_load(ptr+4); + v_uint32x4 t3 = v_load(ptr+8); + v_uint32x4 t4 = v_load(ptr+12); + return t1 + t2 + t3 + t4; +} +inline v_uint32x4 v_dotprod_expand_fast(const v_uint8x16& a, const v_uint8x16& b, const v_uint32x4& c) +{ + unsigned ptr[16] = {0}; + vse32_v_u32m4(ptr, vwcvtu_x_x_v_u32m4(vwmulu_vv_u16m2(a, b, 16), 16), 16); + v_uint32x4 t1 = v_load(ptr); + v_uint32x4 t2 = v_load(ptr+4); + v_uint32x4 t3 = v_load(ptr+8); + v_uint32x4 t4 = v_load(ptr+12); + return t1 + t2 + t3 + t4 + c; +} +inline v_int32x4 v_dotprod_expand_fast(const v_int8x16& a, const v_int8x16& b) +{ + int ptr[16] = {0}; + vse32_v_i32m4(ptr, vwcvt_x_x_v_i32m4(vwmul_vv_i16m2(a, b, 16), 16), 16); + v_int32x4 t1 = v_load(ptr); + v_int32x4 t2 = v_load(ptr+4); + v_int32x4 t3 = v_load(ptr+8); + v_int32x4 t4 = v_load(ptr+12); + return t1 + t2 + t3 + t4; +} +inline v_int32x4 v_dotprod_expand_fast(const v_int8x16& a, const v_int8x16& b, const v_int32x4& c) +{ + int ptr[16] = {0}; + vse32_v_i32m4(ptr, vwcvt_x_x_v_i32m4(vwmul_vv_i16m2(a, b, 16), 16), 16); + v_int32x4 t1 = v_load(ptr); + v_int32x4 t2 = v_load(ptr+4); + v_int32x4 t3 = v_load(ptr+8); + v_int32x4 t4 = v_load(ptr+12); + return t1 + t2 + t3 + t4 + c; +} + +// 16 >> 64 +inline v_uint64x2 v_dotprod_expand_fast(const v_uint16x8& a, const v_uint16x8& b) +{ + uint64 ptr[8] = {0}; + vse64_v_u64m4(ptr, vwcvtu_x_x_v_u64m4(vwmulu_vv_u32m2(a, b, 8), 8), 8); + v_uint64x2 t1 = v_load(ptr); + v_uint64x2 t2 = v_load(ptr+2); + v_uint64x2 t3 = v_load(ptr+4); + v_uint64x2 t4 = v_load(ptr+6); + return t1 + t2 + t3 + t4; +} +inline v_uint64x2 v_dotprod_expand_fast(const v_uint16x8& a, const v_uint16x8& b, const v_uint64x2& c) +{ + uint64 ptr[8] = {0}; + vse64_v_u64m4(ptr, vwcvtu_x_x_v_u64m4(vwmulu_vv_u32m2(a, b, 8), 8), 8); + v_uint64x2 t1 = v_load(ptr); + v_uint64x2 t2 = v_load(ptr+2); + v_uint64x2 t3 = v_load(ptr+4); + v_uint64x2 t4 = v_load(ptr+6); + return t1 + t2 + t3 + t4 + c; +} +inline v_int64x2 v_dotprod_expand_fast(const v_int16x8& a, const v_int16x8& b) +{ + int64 ptr[8] = {0}; + vse64_v_i64m4(ptr, vwcvt_x_x_v_i64m4(vwmul_vv_i32m2(a, b, 8), 8), 8); + v_int64x2 t1 = v_load(ptr); + v_int64x2 t2 = v_load(ptr+2); + v_int64x2 t3 = v_load(ptr+4); + v_int64x2 t4 = v_load(ptr+6); + return t1 + t2 + t3 + t4; +} +inline v_int64x2 v_dotprod_expand_fast(const v_int16x8& a, const v_int16x8& b, const v_int64x2& c) +{ + int64 ptr[8] = {0}; + vse64_v_i64m4(ptr, vwcvt_x_x_v_i64m4(vwmul_vv_i32m2(a, b, 8), 8), 8); + v_int64x2 t1 = v_load(ptr); + v_int64x2 t2 = v_load(ptr+2); + v_int64x2 t3 = v_load(ptr+4); + v_int64x2 t4 = v_load(ptr+6); + return t1 + t2 + t3 + t4 + c; +} + +// 32 >> 64f +#if CV_SIMD128_64F +inline v_float64x2 v_dotprod_expand_fast(const v_int32x4& a, const v_int32x4& b) +{ return v_cvt_f64(v_dotprod_fast(a, b)); } +inline v_float64x2 v_dotprod_expand_fast(const v_int32x4& a, const v_int32x4& b, const v_float64x2& c) +{ return v_dotprod_expand_fast(a, b) + c; } +#endif + + +inline v_float32x4 v_matmul(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& m3) +{ + vfloat32m1_t res = vfmul_vf_f32m1(m0, v_extract_n<0>(v), 4); + res = vfmacc_vf_f32m1(res, v_extract_n<1>(v), m1, 4); + res = vfmacc_vf_f32m1(res, v_extract_n<2>(v), m2, 4); + res = vfmacc_vf_f32m1(res, v_extract_n<3>(v), m3, 4); + return v_float32x4(res); +} + +inline v_float32x4 v_matmuladd(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& a) +{ + vfloat32m1_t res = vfmul_vf_f32m1(m0, v_extract_n<0>(v), 4); + res = vfmacc_vf_f32m1(res, v_extract_n<1>(v), m1, 4); + res = vfmacc_vf_f32m1(res, v_extract_n<2>(v), m2, 4); + return v_float32x4(res) + a; +} + +#define OPENCV_HAL_IMPL_RVV_MUL_EXPAND(_Tpvec, _Tpwvec, _Tpw, suffix, wmul, width, vl, hvl) \ +inline void v_mul_expand(const _Tpvec& a, const _Tpvec& b, _Tpwvec& c, _Tpwvec& d) \ +{ \ + _Tpw ptr[_Tpwvec::nlanes*2] = {0}; \ + vse##width##_v_##suffix##m2(ptr, wmul(a, b, vl), vl); \ + c = _Tpwvec(vle##width##_v_##suffix##m1(ptr, hvl)); \ + d = _Tpwvec(vle##width##_v_##suffix##m1(ptr+_Tpwvec::nlanes, hvl)); \ +} + +OPENCV_HAL_IMPL_RVV_MUL_EXPAND(v_uint8x16, v_uint16x8, ushort, u16, vwmulu_vv_u16m2, 16, 16, 8) +OPENCV_HAL_IMPL_RVV_MUL_EXPAND(v_int8x16, v_int16x8, short, i16, vwmul_vv_i16m2, 16, 16, 8) +OPENCV_HAL_IMPL_RVV_MUL_EXPAND(v_uint16x8, v_uint32x4, unsigned, u32, vwmulu_vv_u32m2, 32, 8, 4) +OPENCV_HAL_IMPL_RVV_MUL_EXPAND(v_int16x8, v_int32x4, int, i32, vwmul_vv_i32m2, 32, 8, 4) +OPENCV_HAL_IMPL_RVV_MUL_EXPAND(v_uint32x4, v_uint64x2, uint64, u64, vwmulu_vv_u64m2, 64, 4, 2) + + +inline v_int16x8 v_mul_hi(const v_int16x8& a, const v_int16x8& b) +{ + return v_int16x8(vnsra_wx_i16m1(vwmul_vv_i32m2(a, b, 8), 16, 8)); +} +inline v_uint16x8 v_mul_hi(const v_uint16x8& a, const v_uint16x8& b) +{ + return v_uint16x8(vnsrl_wx_u16m1(vwmulu_vv_u32m2(a, b, 8), 16, 8)); +} + + +//////// Saturating Multiply //////// + +#define OPENCV_HAL_IMPL_RVV_MUL_SAT(_Tpvec, _wTpvec) \ +inline _Tpvec operator * (const _Tpvec& a, const _Tpvec& b) \ +{ \ + _wTpvec c, d; \ + v_mul_expand(a, b, c, d); \ + return v_pack(c, d); \ +} \ +inline _Tpvec& operator *= (_Tpvec& a, const _Tpvec& b) \ +{ \ + a = a * b; \ + return a; \ +} + +OPENCV_HAL_IMPL_RVV_MUL_SAT(v_uint8x16, v_uint16x8) +OPENCV_HAL_IMPL_RVV_MUL_SAT(v_int8x16, v_int16x8) +OPENCV_HAL_IMPL_RVV_MUL_SAT(v_uint16x8, v_uint32x4) +OPENCV_HAL_IMPL_RVV_MUL_SAT(v_int16x8, v_int32x4) + + +inline void v_cleanup() {} + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END + + +} + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_rvv071.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_rvv071.hpp new file mode 100644 index 0000000..2bdc622 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_rvv071.hpp @@ -0,0 +1,2545 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + +// Copyright (C) 2015, PingTouGe Semiconductor Co., Ltd., all rights reserved. + +#ifndef OPENCV_HAL_INTRIN_RISCVV_HPP +#define OPENCV_HAL_INTRIN_RISCVV_HPP + +#include +#include +#include "opencv2/core/utility.hpp" + +namespace cv +{ + +//! @cond IGNORED + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN + +#define CV_SIMD128 1 +#define CV_SIMD128_64F 1 +//////////// Types //////////// +struct v_uint8x16 +{ + typedef uchar lane_type; + enum { nlanes = 16 }; + + v_uint8x16() {} + explicit v_uint8x16(vuint8m1_t v) : val(v) {} + v_uint8x16(uchar v0, uchar v1, uchar v2, uchar v3, uchar v4, uchar v5, uchar v6, uchar v7, + uchar v8, uchar v9, uchar v10, uchar v11, uchar v12, uchar v13, uchar v14, uchar v15) + { + uchar v[] = {v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15}; + val = (vuint8m1_t)vle_v_u8m1((unsigned char*)v, 16); + } + uchar get0() const + { + return vmv_x_s_u8m1_u8(val, 16); + } + + vuint8m1_t val; +}; + +struct v_int8x16 +{ + typedef schar lane_type; + enum { nlanes = 16 }; + + v_int8x16() {} + explicit v_int8x16(vint8m1_t v) : val(v) {} + v_int8x16(schar v0, schar v1, schar v2, schar v3, schar v4, schar v5, schar v6, schar v7, + schar v8, schar v9, schar v10, schar v11, schar v12, schar v13, schar v14, schar v15) + { + schar v[] = {v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15}; + val = (vint8m1_t)vle_v_i8m1((schar*)v, 16); + } + schar get0() const + { + return vmv_x_s_i8m1_i8(val, 16); + } + + vint8m1_t val; +}; + +struct v_uint16x8 +{ + typedef ushort lane_type; + enum { nlanes = 8 }; + + v_uint16x8() {} + explicit v_uint16x8(vuint16m1_t v) : val(v) {} + v_uint16x8(ushort v0, ushort v1, ushort v2, ushort v3, ushort v4, ushort v5, ushort v6, ushort v7) + { + ushort v[] = {v0, v1, v2, v3, v4, v5, v6, v7}; + val = (vuint16m1_t)vle_v_u16m1((unsigned short*)v, 8); + } + ushort get0() const + { + return vmv_x_s_u16m1_u16(val, 8); + } + + vuint16m1_t val; +}; + +struct v_int16x8 +{ + typedef short lane_type; + enum { nlanes = 8 }; + + v_int16x8() {} + explicit v_int16x8(vint16m1_t v) : val(v) {} + v_int16x8(short v0, short v1, short v2, short v3, short v4, short v5, short v6, short v7) + { + short v[] = {v0, v1, v2, v3, v4, v5, v6, v7}; + val = (vint16m1_t)vle_v_i16m1((signed short*)v, 8); + } + short get0() const + { + return vmv_x_s_i16m1_i16(val, 8); + } + + vint16m1_t val; +}; + +struct v_uint32x4 +{ + typedef unsigned lane_type; + enum { nlanes = 4 }; + + v_uint32x4() {} + explicit v_uint32x4(vuint32m1_t v) : val(v) {} + v_uint32x4(unsigned v0, unsigned v1, unsigned v2, unsigned v3) + { + unsigned v[] = {v0, v1, v2, v3}; + val = (vuint32m1_t)vle_v_u32m1((unsigned int*)v, 4); + } + unsigned get0() const + { + return vmv_x_s_u32m1_u32(val, 4); + } + + vuint32m1_t val; +}; + +struct v_int32x4 +{ + typedef int lane_type; + enum { nlanes = 4 }; + + v_int32x4() {} + explicit v_int32x4(vint32m1_t v) : val(v) {} + v_int32x4(int v0, int v1, int v2, int v3) + { + int v[] = {v0, v1, v2, v3}; + val = (vint32m1_t)vle_v_i32m1((signed int*)v, 4); + } + int get0() const + { + return vmv_x_s_i32m1_i32(val, 4); + } + vint32m1_t val; +}; + +struct v_float32x4 +{ + typedef float lane_type; + enum { nlanes = 4 }; + + v_float32x4() {} + explicit v_float32x4(vfloat32m1_t v) : val(v) {} + v_float32x4(float v0, float v1, float v2, float v3) + { + float v[] = {v0, v1, v2, v3}; + val = (vfloat32m1_t)vle_v_f32m1((float*)v, 4); + } + float get0() const + { + return vfmv_f_s_f32m1_f32(val, 4); + } + vfloat32m1_t val; +}; + +struct v_uint64x2 +{ + typedef uint64 lane_type; + enum { nlanes = 2 }; + + v_uint64x2() {} + explicit v_uint64x2(vuint64m1_t v) : val(v) {} + v_uint64x2(uint64 v0, uint64 v1) + { + uint64 v[] = {v0, v1}; + val = (vuint64m1_t)vle_v_u64m1((unsigned long*)v, 2); + } + uint64 get0() const + { + return vmv_x_s_u64m1_u64(val, 2); + } + vuint64m1_t val; +}; + +struct v_int64x2 +{ + typedef int64 lane_type; + enum { nlanes = 2 }; + + v_int64x2() {} + explicit v_int64x2(vint64m1_t v) : val(v) {} + v_int64x2(int64 v0, int64 v1) + { + int64 v[] = {v0, v1}; + val = (vint64m1_t)vle_v_i64m1((long*)v, 2); + } + int64 get0() const + { + return vmv_x_s_i64m1_i64(val, 2); + } + vint64m1_t val; +}; + +struct v_float64x2 +{ + typedef double lane_type; + enum { nlanes = 2 }; + + v_float64x2() {} + explicit v_float64x2(vfloat64m1_t v) : val(v) {} + v_float64x2(double v0, double v1) + { + double v[] = {v0, v1}; + val = (vfloat64m1_t)vle_v_f64m1((double*)v, 2); + } + double get0() const + { + return vfmv_f_s_f64m1_f64(val, 2); + } + vfloat64m1_t val; +}; + +#define OPENCV_HAL_IMPL_RISCVV_INIT(_Tpv, _Tp, suffix) \ +inline _Tp##m1_t vreinterpretq_##suffix##_##suffix(_Tp##m1_t v) { return v; } \ +inline v_uint8x16 v_reinterpret_as_u8(const v_##_Tpv& v) { return v_uint8x16((vuint8m1_t)(v.val)); } \ +inline v_int8x16 v_reinterpret_as_s8(const v_##_Tpv& v) { return v_int8x16((vint8m1_t)(v.val)); } \ +inline v_uint16x8 v_reinterpret_as_u16(const v_##_Tpv& v) { return v_uint16x8((vuint16m1_t)(v.val)); } \ +inline v_int16x8 v_reinterpret_as_s16(const v_##_Tpv& v) { return v_int16x8((vint16m1_t)(v.val)); } \ +inline v_uint32x4 v_reinterpret_as_u32(const v_##_Tpv& v) { return v_uint32x4((vuint32m1_t)(v.val)); } \ +inline v_int32x4 v_reinterpret_as_s32(const v_##_Tpv& v) { return v_int32x4((vint32m1_t)(v.val)); } \ +inline v_uint64x2 v_reinterpret_as_u64(const v_##_Tpv& v) { return v_uint64x2((vuint64m1_t)(v.val)); } \ +inline v_int64x2 v_reinterpret_as_s64(const v_##_Tpv& v) { return v_int64x2((vint64m1_t)(v.val)); } \ +inline v_float32x4 v_reinterpret_as_f32(const v_##_Tpv& v) { return v_float32x4((vfloat32m1_t)(v.val)); }\ +inline v_float64x2 v_reinterpret_as_f64(const v_##_Tpv& v) { return v_float64x2((vfloat64m1_t)(v.val)); } + + +OPENCV_HAL_IMPL_RISCVV_INIT(uint8x16, vuint8, u8) +OPENCV_HAL_IMPL_RISCVV_INIT(int8x16, vint8, s8) +OPENCV_HAL_IMPL_RISCVV_INIT(uint16x8, vuint16, u16) +OPENCV_HAL_IMPL_RISCVV_INIT(int16x8, vint16, s16) +OPENCV_HAL_IMPL_RISCVV_INIT(uint32x4, vuint32, u32) +OPENCV_HAL_IMPL_RISCVV_INIT(int32x4, vint32, s32) +OPENCV_HAL_IMPL_RISCVV_INIT(uint64x2, vuint64, u64) +OPENCV_HAL_IMPL_RISCVV_INIT(int64x2, vint64, s64) +OPENCV_HAL_IMPL_RISCVV_INIT(float64x2, vfloat64, f64) +OPENCV_HAL_IMPL_RISCVV_INIT(float32x4, vfloat32, f32) +#define OPENCV_HAL_IMPL_RISCVV_INIT_SET(__Tp, _Tp, suffix, len, num) \ +inline v_##_Tp##x##num v_setzero_##suffix() { return v_##_Tp##x##num((v##_Tp##m1_t){0}); } \ +inline v_##_Tp##x##num v_setall_##suffix(__Tp v) { return v_##_Tp##x##num(vmv_v_x_##len##m1(v, num)); } + +OPENCV_HAL_IMPL_RISCVV_INIT_SET(uchar, uint8, u8, u8, 16) +OPENCV_HAL_IMPL_RISCVV_INIT_SET(char, int8, s8, i8, 16) +OPENCV_HAL_IMPL_RISCVV_INIT_SET(ushort, uint16, u16, u16, 8) +OPENCV_HAL_IMPL_RISCVV_INIT_SET(short, int16, s16, i16, 8) +OPENCV_HAL_IMPL_RISCVV_INIT_SET(unsigned int, uint32, u32, u32, 4) +OPENCV_HAL_IMPL_RISCVV_INIT_SET(int, int32, s32, i32, 4) +OPENCV_HAL_IMPL_RISCVV_INIT_SET(unsigned long, uint64, u64, u64, 2) +OPENCV_HAL_IMPL_RISCVV_INIT_SET(long, int64, s64, i64, 2) +inline v_float32x4 v_setzero_f32() { return v_float32x4((vfloat32m1_t){0}); } +inline v_float32x4 v_setall_f32(float v) { return v_float32x4(vfmv_v_f_f32m1(v, 4)); } + +inline v_float64x2 v_setzero_f64() { return v_float64x2(vfmv_v_f_f64m1(0, 2)); } +inline v_float64x2 v_setall_f64(double v) { return v_float64x2(vfmv_v_f_f64m1(v, 2)); } + + +#define OPENCV_HAL_IMPL_RISCVV_BIN_OP(bin_op, _Tpvec, intrin) \ +inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(intrin(a.val, b.val)); \ +} \ +inline _Tpvec& operator bin_op##= (_Tpvec& a, const _Tpvec& b) \ +{ \ + a.val = intrin(a.val, b.val); \ + return a; \ +} + +#define OPENCV_HAL_IMPL_RISCVV_BIN_OPN(bin_op, _Tpvec, intrin, num) \ +inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(intrin(a.val, b.val, num)); \ +} \ +inline _Tpvec& operator bin_op##= (_Tpvec& a, const _Tpvec& b) \ +{ \ + a.val = intrin(a.val, b.val, num); \ + return a; \ +} + +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(+, v_uint8x16, vsaddu_vv_u8m1, 16) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(-, v_uint8x16, vssubu_vv_u8m1, 16) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(+, v_int8x16, vsadd_vv_i8m1, 16) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(-, v_int8x16, vssub_vv_i8m1, 16) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(+, v_uint16x8, vsaddu_vv_u16m1, 8) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(-, v_uint16x8, vssubu_vv_u16m1, 8) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(+, v_int16x8, vsadd_vv_i16m1, 8) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(-, v_int16x8, vssub_vv_i16m1, 8) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(+, v_int32x4, vsadd_vv_i32m1, 4) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(-, v_int32x4, vssub_vv_i32m1, 4) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(*, v_int32x4, vmul_vv_i32m1, 4) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(+, v_uint32x4, vadd_vv_u32m1, 4) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(-, v_uint32x4, vsub_vv_u32m1, 4) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(*, v_uint32x4, vmul_vv_u32m1, 4) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(+, v_int64x2, vsadd_vv_i64m1, 2) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(-, v_int64x2, vssub_vv_i64m1, 2) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(+, v_uint64x2, vadd_vv_u64m1, 2) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(-, v_uint64x2, vsub_vv_u64m1, 2) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(+, v_float32x4, vfadd_vv_f32m1, 4) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(-, v_float32x4, vfsub_vv_f32m1, 4) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(*, v_float32x4, vfmul_vv_f32m1, 4) +inline v_float32x4 operator / (const v_float32x4& a, const v_float32x4& b) +{ + return v_float32x4(vfdiv_vv_f32m1(a.val, b.val, 4)); +} +inline v_float32x4& operator /= (v_float32x4& a, const v_float32x4& b) +{ + a.val = vfdiv_vv_f32m1(a.val, b.val, 4); + return a; +} + +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(+, v_float64x2, vfadd_vv_f64m1, 2) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(-, v_float64x2, vfsub_vv_f64m1, 2) +OPENCV_HAL_IMPL_RISCVV_BIN_OPN(*, v_float64x2, vfmul_vv_f64m1, 2) +inline v_float64x2 operator / (const v_float64x2& a, const v_float64x2& b) +{ + return v_float64x2(vfdiv_vv_f64m1(a.val, b.val, 2)); +} +inline v_float64x2& operator /= (v_float64x2& a, const v_float64x2& b) +{ + a.val = vfdiv_vv_f64m1(a.val, b.val, 2); + return a; +} +// TODO: exp, log, sin, cos + +#define OPENCV_HAL_IMPL_RISCVV_BIN_FUNC(_Tpvec, func, intrin) \ +inline _Tpvec func(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(intrin(a.val, b.val)); \ +} + +#define OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(_Tpvec, func, intrin, num) \ +inline _Tpvec func(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(intrin(a.val, b.val, num)); \ +} +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_uint8x16, v_min, vminu_vv_u8m1, 16) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_uint8x16, v_max, vmaxu_vv_u8m1, 16) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_int8x16, v_min, vmin_vv_i8m1, 16) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_int8x16, v_max, vmax_vv_i8m1, 16) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_uint16x8, v_min, vminu_vv_u16m1, 8) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_uint16x8, v_max, vmaxu_vv_u16m1, 8) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_int16x8, v_min, vmin_vv_i16m1, 8) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_int16x8, v_max, vmax_vv_i16m1, 8) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_uint32x4, v_min, vminu_vv_u32m1, 4) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_uint32x4, v_max, vmaxu_vv_u32m1, 4) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_int32x4, v_min, vmin_vv_i32m1, 4) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_int32x4, v_max, vmax_vv_i32m1, 4) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_float32x4, v_min, vfmin_vv_f32m1, 4) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_float32x4, v_max, vfmax_vv_f32m1, 4) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_float64x2, v_min, vfmin_vv_f64m1, 2) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_float64x2, v_max, vfmax_vv_f64m1, 2) + +inline v_float32x4 v_sqrt(const v_float32x4& x) +{ + return v_float32x4(vfsqrt_v_f32m1(x.val, 4)); +} + +inline v_float32x4 v_invsqrt(const v_float32x4& x) +{ + return v_float32x4(vfrdiv_vf_f32m1(vfsqrt_v_f32m1(x.val, 4), 1, 4)); +} + +inline v_float32x4 v_magnitude(const v_float32x4& a, const v_float32x4& b) +{ + v_float32x4 x(vfmacc_vv_f32m1(vfmul_vv_f32m1(a.val, a.val, 4), b.val, b.val, 4)); + return v_sqrt(x); +} + +inline v_float32x4 v_sqr_magnitude(const v_float32x4& a, const v_float32x4& b) +{ + return v_float32x4(vfmacc_vv_f32m1(vfmul_vv_f32m1(a.val, a.val, 4), b.val, b.val, 4)); +} + +inline v_float32x4 v_fma(const v_float32x4& a, const v_float32x4& b, const v_float32x4& c) +{ + return v_float32x4(vfmacc_vv_f32m1(c.val, a.val, b.val, 4)); +} + +inline v_int32x4 v_fma(const v_int32x4& a, const v_int32x4& b, const v_int32x4& c) +{ + return v_int32x4(vmacc_vv_i32m1(c.val, a.val, b.val, 4)); +} + +inline v_float32x4 v_muladd(const v_float32x4& a, const v_float32x4& b, const v_float32x4& c) +{ + return v_fma(a, b, c); +} + +inline v_int32x4 v_muladd(const v_int32x4& a, const v_int32x4& b, const v_int32x4& c) +{ + return v_fma(a, b, c); +} + +inline v_float32x4 v_matmul(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& m3) +{ + vfloat32m1_t res = vfmul_vf_f32m1(m0.val, v.val[0], 4);//vmuli_f32(m0.val, v.val, 0); + res = vfmacc_vf_f32m1(res, v.val[1], m1.val, 4);//vmulai_f32(res, m1.val, v.val, 1); + res = vfmacc_vf_f32m1(res, v.val[2], m2.val, 4);//vmulai_f32(res, m1.val, v.val, 1); + res = vfmacc_vf_f32m1(res, v.val[3], m3.val, 4);//vmulai_f32(res, m1.val, v.val, 1); + return v_float32x4(res); +} + +inline v_float32x4 v_matmuladd(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& a) +{ + vfloat32m1_t res = vfmul_vf_f32m1(m0.val, v.val[0], 4);//vmuli_f32(m0.val, v.val, 0); + res = vfmacc_vf_f32m1(res, v.val[1], m1.val, 4);//vmulai_f32(res, m1.val, v.val, 1); + res = vfmacc_vf_f32m1(res, v.val[2], m2.val, 4);//vmulai_f32(res, m1.val, v.val, 1); + res = vfadd_vv_f32m1(res, a.val, 4);//vmulai_f32(res, m1.val, v.val, 1); + return v_float32x4(res); +} + +inline v_float64x2 v_sqrt(const v_float64x2& x) +{ + return v_float64x2(vfsqrt_v_f64m1(x.val, 2)); +} + +inline v_float64x2 v_invsqrt(const v_float64x2& x) +{ + return v_float64x2(vfrdiv_vf_f64m1(vfsqrt_v_f64m1(x.val, 2), 1, 2)); +} + +inline v_float64x2 v_magnitude(const v_float64x2& a, const v_float64x2& b) +{ + v_float64x2 x(vfmacc_vv_f64m1(vfmul_vv_f64m1(a.val, a.val, 2), b.val, b.val, 2)); + return v_sqrt(x); +} + +inline v_float64x2 v_sqr_magnitude(const v_float64x2& a, const v_float64x2& b) +{ + return v_float64x2(vfmacc_vv_f64m1(vfmul_vv_f64m1(a.val, a.val, 2), b.val, b.val, 2)); +} + +inline v_float64x2 v_fma(const v_float64x2& a, const v_float64x2& b, const v_float64x2& c) +{ + return v_float64x2(vfmacc_vv_f64m1(c.val, a.val, b.val, 2)); +} + +inline v_float64x2 v_muladd(const v_float64x2& a, const v_float64x2& b, const v_float64x2& c) +{ + return v_fma(a, b, c); +} + +#define OPENCV_HAL_IMPL_RISCVV_LOGIC_OPN(_Tpvec, suffix, num) \ + OPENCV_HAL_IMPL_RISCVV_BIN_OPN(&, _Tpvec, vand_vv_##suffix, num) \ + OPENCV_HAL_IMPL_RISCVV_BIN_OPN(|, _Tpvec, vor_vv_##suffix, num) \ + OPENCV_HAL_IMPL_RISCVV_BIN_OPN(^, _Tpvec, vxor_vv_##suffix, num) \ + inline _Tpvec operator ~ (const _Tpvec & a) \ + { \ + return _Tpvec(vnot_v_##suffix(a.val, num)); \ + } + +OPENCV_HAL_IMPL_RISCVV_LOGIC_OPN(v_uint8x16, u8m1, 16) +OPENCV_HAL_IMPL_RISCVV_LOGIC_OPN(v_uint16x8, u16m1, 8) +OPENCV_HAL_IMPL_RISCVV_LOGIC_OPN(v_uint32x4, u32m1, 4) +OPENCV_HAL_IMPL_RISCVV_LOGIC_OPN(v_uint64x2, u64m1, 2) +OPENCV_HAL_IMPL_RISCVV_LOGIC_OPN(v_int8x16, i8m1, 16) +OPENCV_HAL_IMPL_RISCVV_LOGIC_OPN(v_int16x8, i16m1, 8) +OPENCV_HAL_IMPL_RISCVV_LOGIC_OPN(v_int32x4, i32m1, 4) +OPENCV_HAL_IMPL_RISCVV_LOGIC_OPN(v_int64x2, i64m1, 2) + +#define OPENCV_HAL_IMPL_RISCVV_FLT_BIT_OP(bin_op, intrin) \ +inline v_float32x4 operator bin_op (const v_float32x4& a, const v_float32x4& b) \ +{ \ + return v_float32x4(vfloat32m1_t(intrin(vint32m1_t(a.val), vint32m1_t(b.val), 4))); \ +} \ +inline v_float32x4& operator bin_op##= (v_float32x4& a, const v_float32x4& b) \ +{ \ + a.val = vfloat32m1_t(intrin(vint32m1_t(a.val), vint32m1_t(b.val), 4)); \ + return a; \ +} + +OPENCV_HAL_IMPL_RISCVV_FLT_BIT_OP(&, vand_vv_i32m1) +OPENCV_HAL_IMPL_RISCVV_FLT_BIT_OP(|, vor_vv_i32m1) +OPENCV_HAL_IMPL_RISCVV_FLT_BIT_OP(^, vxor_vv_i32m1) + +inline v_float32x4 operator ~ (const v_float32x4& a) +{ + return v_float32x4((vfloat32m1_t)(vnot_v_i32m1((vint32m1_t)(a.val), 4))); +} + +#define OPENCV_HAL_IMPL_RISCVV_FLT_64BIT_OP(bin_op, intrin) \ +inline v_float64x2 operator bin_op (const v_float64x2& a, const v_float64x2& b) \ +{ \ + return v_float64x2(vfloat64m1_t(intrin(vint64m1_t(a.val), vint64m1_t(b.val), 2))); \ +} \ +inline v_float64x2& operator bin_op##= (v_float64x2& a, const v_float64x2& b) \ +{ \ + a.val = vfloat64m1_t(intrin(vint64m1_t(a.val), vint64m1_t(b.val), 2)); \ + return a; \ +} + +OPENCV_HAL_IMPL_RISCVV_FLT_64BIT_OP(&, vand_vv_i64m1) +OPENCV_HAL_IMPL_RISCVV_FLT_64BIT_OP(|, vor_vv_i64m1) +OPENCV_HAL_IMPL_RISCVV_FLT_64BIT_OP(^, vxor_vv_i64m1) + +inline v_float64x2 operator ~ (const v_float64x2& a) +{ + return v_float64x2((vfloat64m1_t)(vnot_v_i64m1((vint64m1_t)(a.val), 2))); +} +inline v_int16x8 v_mul_hi(const v_int16x8& a, const v_int16x8& b) +{ + return v_int16x8(vmulh_vv_i16m1(a.val, b.val, 8)); +} +inline v_uint16x8 v_mul_hi(const v_uint16x8& a, const v_uint16x8& b) +{ + return v_uint16x8(vmulhu_vv_u16m1(a.val, b.val, 8)); +} + +//#define OPENCV_HAL_IMPL_RISCVV_ABS(_Tpuvec, _Tpsvec, usuffix, ssuffix) \ +//inline _Tpuvec v_abs(const _Tpsvec& a) { \ +// E##xm1_t mask=vmflt_vf_e32xm1_f32m1(x.val, 0.0, 4); + +//OPENCV_HAL_IMPL_RISCVV_ABS(v_uint8x16, v_int8x16, u8, s8) +//OPENCV_HAL_IMPL_RISCVV_ABS(v_uint16x8, v_int16x8, u16, s16) +//OPENCV_HAL_IMPL_RISCVV_ABS(v_uint32x4, v_int32x4, u32, s32) + +inline v_uint32x4 v_abs(v_int32x4 x) +{ + vbool32_t mask=vmslt_vx_i32m1_b32(x.val, 0, 4); + return v_uint32x4((vuint32m1_t)vrsub_vx_i32m1_m(mask, x.val, x.val, 0, 4)); +} + +inline v_uint16x8 v_abs(v_int16x8 x) +{ + vbool16_t mask=vmslt_vx_i16m1_b16(x.val, 0, 8); + return v_uint16x8((vuint16m1_t)vrsub_vx_i16m1_m(mask, x.val, x.val, 0, 8)); +} + +inline v_uint8x16 v_abs(v_int8x16 x) +{ + vbool8_t mask=vmslt_vx_i8m1_b8(x.val, 0, 16); + return v_uint8x16((vuint8m1_t)vrsub_vx_i8m1_m(mask, x.val, x.val, 0, 16)); +} + +inline v_float32x4 v_abs(v_float32x4 x) +{ + return (v_float32x4)vfsgnjx_vv_f32m1(x.val, x.val, 4); +} + +inline v_float64x2 v_abs(v_float64x2 x) +{ + return (v_float64x2)vfsgnjx_vv_f64m1(x.val, x.val, 2); +} + +inline v_float32x4 v_absdiff(const v_float32x4& a, const v_float32x4& b) +{ + vfloat32m1_t ret = vfsub_vv_f32m1(a.val, b.val, 4); + return (v_float32x4)vfsgnjx_vv_f32m1(ret, ret, 4); +} + +inline v_float64x2 v_absdiff(const v_float64x2& a, const v_float64x2& b) +{ + vfloat64m1_t ret = vfsub_vv_f64m1(a.val, b.val, 2); + return (v_float64x2)vfsgnjx_vv_f64m1(ret, ret, 2); +} + +#define OPENCV_HAL_IMPL_RISCVV_ABSDIFF_U(bit, num) \ +inline v_uint##bit##x##num v_absdiff(v_uint##bit##x##num a, v_uint##bit##x##num b){ \ + vuint##bit##m1_t vmax = vmaxu_vv_u##bit##m1(a.val, b.val, num); \ + vuint##bit##m1_t vmin = vminu_vv_u##bit##m1(a.val, b.val, num); \ + return v_uint##bit##x##num(vsub_vv_u##bit##m1(vmax, vmin, num));\ +} + +OPENCV_HAL_IMPL_RISCVV_ABSDIFF_U(8, 16) +OPENCV_HAL_IMPL_RISCVV_ABSDIFF_U(16, 8) +OPENCV_HAL_IMPL_RISCVV_ABSDIFF_U(32, 4) + +/** Saturating absolute difference **/ +inline v_int8x16 v_absdiffs(v_int8x16 a, v_int8x16 b){ + vint8m1_t vmax = vmax_vv_i8m1(a.val, b.val, 16); + vint8m1_t vmin = vmin_vv_i8m1(a.val, b.val, 16); + return v_int8x16(vssub_vv_i8m1(vmax, vmin, 16)); +} +inline v_int16x8 v_absdiffs(v_int16x8 a, v_int16x8 b){ + vint16m1_t vmax = vmax_vv_i16m1(a.val, b.val, 8); + vint16m1_t vmin = vmin_vv_i16m1(a.val, b.val, 8); + return v_int16x8(vssub_vv_i16m1(vmax, vmin, 8)); +} + +#define OPENCV_HAL_IMPL_RISCVV_ABSDIFF(_Tpvec, _Tpv, num) \ +inline v_uint##_Tpvec v_absdiff(v_int##_Tpvec a, v_int##_Tpvec b){ \ + vint##_Tpv##_t max = vmax_vv_i##_Tpv(a.val, b.val, num);\ + vint##_Tpv##_t min = vmin_vv_i##_Tpv(a.val, b.val, num);\ + return v_uint##_Tpvec((vuint##_Tpv##_t)vsub_vv_i##_Tpv(max, min, num)); \ +} + +OPENCV_HAL_IMPL_RISCVV_ABSDIFF(8x16, 8m1, 16) +OPENCV_HAL_IMPL_RISCVV_ABSDIFF(16x8, 16m1, 8) +OPENCV_HAL_IMPL_RISCVV_ABSDIFF(32x4, 32m1, 4) + +// Multiply and expand +inline void v_mul_expand(const v_int8x16& a, const v_int8x16& b, + v_int16x8& c, v_int16x8& d) +{ + vint16m2_t res = vundefined_i16m2(); + res = vwmul_vv_i16m2(a.val, b.val, 16); + c.val = vget_i16m2_i16m1(res, 0); + d.val = vget_i16m2_i16m1(res, 1); +} + +inline void v_mul_expand(const v_uint8x16& a, const v_uint8x16& b, + v_uint16x8& c, v_uint16x8& d) +{ + vuint16m2_t res = vundefined_u16m2(); + res = vwmulu_vv_u16m2(a.val, b.val, 16); + c.val = vget_u16m2_u16m1(res, 0); + d.val = vget_u16m2_u16m1(res, 1); +} + +inline void v_mul_expand(const v_int16x8& a, const v_int16x8& b, + v_int32x4& c, v_int32x4& d) +{ + vint32m2_t res = vundefined_i32m2(); + res = vwmul_vv_i32m2(a.val, b.val, 8); + c.val = vget_i32m2_i32m1(res, 0); + d.val = vget_i32m2_i32m1(res, 1); +} + +inline void v_mul_expand(const v_uint16x8& a, const v_uint16x8& b, + v_uint32x4& c, v_uint32x4& d) +{ + vuint32m2_t res = vundefined_u32m2(); + res = vwmulu_vv_u32m2(a.val, b.val, 8); + c.val = vget_u32m2_u32m1(res, 0); + d.val = vget_u32m2_u32m1(res, 1); +} + +inline void v_mul_expand(const v_int32x4& a, const v_int32x4& b, + v_int64x2& c, v_int64x2& d) +{ + vint64m2_t res = vundefined_i64m2(); + res = vwmul_vv_i64m2(a.val, b.val, 4); + c.val = vget_i64m2_i64m1(res, 0); + d.val = vget_i64m2_i64m1(res, 1); +} + +inline void v_mul_expand(const v_uint32x4& a, const v_uint32x4& b, + v_uint64x2& c, v_uint64x2& d) +{ + vuint64m2_t res = vundefined_u64m2(); + res = vwmulu_vv_u64m2(a.val, b.val, 4); + c.val = vget_u64m2_u64m1(res, 0); + d.val = vget_u64m2_u64m1(res, 1); +} + +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_uint8x16, v_add_wrap, vadd_vv_u8m1, 16) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_int8x16, v_add_wrap, vadd_vv_i8m1, 16) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_uint16x8, v_add_wrap, vadd_vv_u16m1, 8) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_int16x8, v_add_wrap, vadd_vv_i16m1, 8) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_uint8x16, v_sub_wrap, vsub_vv_u8m1, 16) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_int8x16, v_sub_wrap, vsub_vv_i8m1, 16) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_uint16x8, v_sub_wrap, vsub_vv_u16m1, 8) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_int16x8, v_sub_wrap, vsub_vv_i16m1, 8) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_uint8x16, v_mul_wrap, vmul_vv_u8m1, 16) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_int8x16, v_mul_wrap, vmul_vv_i8m1, 16) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_uint16x8, v_mul_wrap, vmul_vv_u16m1, 8) +OPENCV_HAL_IMPL_RISCVV_BINN_FUNC(v_int16x8, v_mul_wrap, vmul_vv_i16m1, 8) +//////// Dot Product //////// +// 16 >> 32 +inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b) +{ + vint32m2_t res = vundefined_i32m2(); + res = vwmul_vv_i32m2(a.val, b.val, 8); + res = vrgather_vv_i32m2(res, (vuint32m2_t){0, 2, 4, 6, 1, 3, 5, 7}, 8); + return v_int32x4(vadd_vv_i32m1(vget_i32m2_i32m1(res, 0), vget_i32m2_i32m1(res, 1), 4)); +} +inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b, const v_int32x4& c) +{ + vint32m2_t res = vundefined_i32m2(); + res = vwmul_vv_i32m2(a.val, b.val, 8); + res = vrgather_vv_i32m2(res, (vuint32m2_t){0, 2, 4, 6, 1, 3, 5, 7}, 8); + return v_int32x4(vadd_vv_i32m1(vadd_vv_i32m1(vget_i32m2_i32m1(res, 0),vget_i32m2_i32m1(res, 1), 4), c.val, 4)); +} + +// 32 >> 64 +inline v_int64x2 v_dotprod(const v_int32x4& a, const v_int32x4& b) +{ + vint64m2_t res = vundefined_i64m2(); + res = vwmul_vv_i64m2(a.val, b.val, 4); + res = vrgather_vv_i64m2(res, (vuint64m2_t){0, 2, 1, 3}, 4); + return v_int64x2(vadd_vv_i64m1(vget_i64m2_i64m1(res, 0), vget_i64m2_i64m1(res, 1), 2)); +} +inline v_int64x2 v_dotprod(const v_int32x4& a, const v_int32x4& b, const v_int64x2& c) +{ + vint64m2_t res = vundefined_i64m2(); + res = vwmul_vv_i64m2(a.val, b.val, 4); + res = vrgather_vv_i64m2(res, (vuint64m2_t){0, 2, 1, 3}, 4); + return v_int64x2(vadd_vv_i64m1(vadd_vv_i64m1(vget_i64m2_i64m1(res, 0), vget_i64m2_i64m1(res, 1), 2), c.val, 2)); +} + +// 8 >> 32 +inline v_uint32x4 v_dotprod_expand(const v_uint8x16& a, const v_uint8x16& b) +{ + vuint16m2_t v1 = vundefined_u16m2(); + vuint32m2_t v2 = vundefined_u32m2(); + v1 = vwmulu_vv_u16m2(a.val, b.val, 16); + v1 = vrgather_vv_u16m2(v1, (vuint16m2_t){0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15}, 16); + v2 = vwaddu_vv_u32m2(vget_u16m2_u16m1(v1, 0), vget_u16m2_u16m1(v1, 1), 8); + return v_uint32x4(vadd_vv_u32m1(vget_u32m2_u32m1(v2, 0), vget_u32m2_u32m1(v2, 1), 4)); +} + +inline v_uint32x4 v_dotprod_expand(const v_uint8x16& a, const v_uint8x16& b, + const v_uint32x4& c) +{ + vuint16m2_t v1 = vundefined_u16m2(); + vuint32m2_t v2 = vundefined_u32m2(); + v1 = vwmulu_vv_u16m2(a.val, b.val, 16); + v1 = vrgather_vv_u16m2(v1, (vuint16m2_t){0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15}, 16); + v2 = vwaddu_vv_u32m2(vget_u16m2_u16m1(v1, 0), vget_u16m2_u16m1(v1, 1), 8); + return v_uint32x4(vadd_vv_u32m1(vadd_vv_u32m1(vget_u32m2_u32m1(v2, 0), vget_u32m2_u32m1(v2, 1), 4), c.val, 4)); +} + +inline v_int32x4 v_dotprod_expand(const v_int8x16& a, const v_int8x16& b) +{ + vint16m2_t v1 = vundefined_i16m2(); + vint32m2_t v2 = vundefined_i32m2(); + v1 = vwmul_vv_i16m2(a.val, b.val, 16); + v1 = vrgather_vv_i16m2(v1, (vuint16m2_t){0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15}, 16); + v2 = vwadd_vv_i32m2(vget_i16m2_i16m1(v1, 0), vget_i16m2_i16m1(v1, 1), 8); + return v_int32x4(vadd_vv_i32m1(vget_i32m2_i32m1(v2, 0), vget_i32m2_i32m1(v2, 1), 4)); +} + +inline v_int32x4 v_dotprod_expand(const v_int8x16& a, const v_int8x16& b, + const v_int32x4& c) +{ + vint16m2_t v1 = vundefined_i16m2(); + vint32m2_t v2 = vundefined_i32m2(); + v1 = vwmul_vv_i16m2(a.val, b.val, 16); + v1 = vrgather_vv_i16m2(v1, (vuint16m2_t){0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15}, 16); + v2 = vwadd_vv_i32m2(vget_i16m2_i16m1(v1, 0), vget_i16m2_i16m1(v1, 1), 8); + return v_int32x4(vadd_vv_i32m1(vadd_vv_i32m1(vget_i32m2_i32m1(v2, 0), vget_i32m2_i32m1(v2, 1), 4), c.val, 4)); +} + +inline v_uint64x2 v_dotprod_expand(const v_uint16x8& a, const v_uint16x8& b) +{ + vuint32m2_t v1 = vundefined_u32m2(); + vuint64m2_t v2 = vundefined_u64m2(); + v1 = vwmulu_vv_u32m2(a.val, b.val, 8); + v1 = vrgather_vv_u32m2(v1, (vuint32m2_t){0, 4, 1, 5, 2, 6, 3, 7}, 8); + v2 = vwaddu_vv_u64m2(vget_u32m2_u32m1(v1, 0), vget_u32m2_u32m1(v1, 1), 4); + return v_uint64x2(vadd_vv_u64m1(vget_u64m2_u64m1(v2, 0), vget_u64m2_u64m1(v2, 1), 2)); +} + +inline v_uint64x2 v_dotprod_expand(const v_uint16x8& a, const v_uint16x8& b, + const v_uint64x2& c) +{ + vuint32m2_t v1 = vundefined_u32m2(); + vuint64m2_t v2 = vundefined_u64m2(); + v1 = vwmulu_vv_u32m2(a.val, b.val, 8); + v1 = vrgather_vv_u32m2(v1, (vuint32m2_t){0, 4, 1, 5, 2, 6, 3, 7}, 8); + v2 = vwaddu_vv_u64m2(vget_u32m2_u32m1(v1, 0), vget_u32m2_u32m1(v1, 1), 4); + return v_uint64x2(vadd_vv_u64m1(vadd_vv_u64m1(vget_u64m2_u64m1(v2, 0), vget_u64m2_u64m1(v2, 1), 2), c.val, 2)); +} + +inline v_int64x2 v_dotprod_expand(const v_int16x8& a, const v_int16x8& b) +{ + vint32m2_t v1 = vundefined_i32m2(); + vint64m2_t v2 = vundefined_i64m2(); + v1 = vwmul_vv_i32m2(a.val, b.val, 8); + v1 = vrgather_vv_i32m2(v1, (vuint32m2_t){0, 4, 1, 5, 2, 6, 3, 7}, 8); + v2 = vwadd_vv_i64m2(vget_i32m2_i32m1(v1, 0), vget_i32m2_i32m1(v1, 1), 4); + return v_int64x2(vadd_vv_i64m1(vget_i64m2_i64m1(v2, 0), vget_i64m2_i64m1(v2, 1), 2)); +} + +inline v_int64x2 v_dotprod_expand(const v_int16x8& a, const v_int16x8& b, + const v_int64x2& c) +{ + vint32m2_t v1 = vundefined_i32m2(); + vint64m2_t v2 = vundefined_i64m2(); + v1 = vwmul_vv_i32m2(a.val, b.val, 8); + v1 = vrgather_vv_i32m2(v1, (vuint32m2_t){0, 4, 1, 5, 2, 6, 3, 7}, 8); + v2 = vwadd_vv_i64m2(vget_i32m2_i32m1(v1, 0), vget_i32m2_i32m1(v1, 1), 4); + return v_int64x2(vadd_vv_i64m1(vadd_vv_i64m1(vget_i64m2_i64m1(v2, 0), vget_i64m2_i64m1(v2, 1), 2), c.val, 2)); +} + +//////// Fast Dot Product //////// +// 16 >> 32 +inline v_int32x4 v_dotprod_fast(const v_int16x8& a, const v_int16x8& b) +{ + vint32m2_t v1 = vundefined_i32m2(); + v1 = vwmul_vv_i32m2(a.val, b.val, 8); + return v_int32x4(vadd_vv_i32m1(vget_i32m2_i32m1(v1, 0), vget_i32m2_i32m1(v1, 1), 4)); +} + +inline v_int32x4 v_dotprod_fast(const v_int16x8& a, const v_int16x8& b, const v_int32x4& c) +{ + vint32m2_t v1 = vundefined_i32m2(); + v1 = vwmul_vv_i32m2(a.val, b.val, 8); + return v_int32x4(vadd_vv_i32m1(vadd_vv_i32m1(vget_i32m2_i32m1(v1, 0), vget_i32m2_i32m1(v1, 1), 4), c.val, 4)); +} + +// 32 >> 64 +inline v_int64x2 v_dotprod_fast(const v_int32x4& a, const v_int32x4& b) +{ + vint64m2_t v1 = vundefined_i64m2(); + v1 = vwmul_vv_i64m2(a.val, b.val, 4); + return v_int64x2(vadd_vv_i64m1(vget_i64m2_i64m1(v1, 0), vget_i64m2_i64m1(v1, 1), 2)); +} +inline v_int64x2 v_dotprod_fast(const v_int32x4& a, const v_int32x4& b, const v_int64x2& c) +{ + vint64m2_t v1 = vundefined_i64m2(); + v1 = vwmul_vv_i64m2(a.val, b.val, 8); + return v_int64x2(vadd_vv_i64m1(vadd_vv_i64m1(vget_i64m2_i64m1(v1, 0), vget_i64m2_i64m1(v1, 1), 4), c.val, 4)); +} + +// 8 >> 32 +inline v_uint32x4 v_dotprod_expand_fast(const v_uint8x16& a, const v_uint8x16& b) +{ + vuint16m2_t v1 = vundefined_u16m2(); + vuint32m2_t v2 = vundefined_u32m2(); + v1 = vwmulu_vv_u16m2(a.val, b.val, 16); + v2 = vwaddu_vv_u32m2(vget_u16m2_u16m1(v1, 0), vget_u16m2_u16m1(v1, 1), 8); + return v_uint32x4(vadd_vv_u32m1(vget_u32m2_u32m1(v2, 0), vget_u32m2_u32m1(v2, 1), 4)); +} + +inline v_uint32x4 v_dotprod_expand_fast(const v_uint8x16& a, const v_uint8x16& b, const v_uint32x4& c) +{ + vuint16m2_t v1 = vundefined_u16m2(); + vuint32m2_t v2 = vundefined_u32m2(); + v1 = vwmulu_vv_u16m2(a.val, b.val, 16); + v2 = vwaddu_vv_u32m2(vget_u16m2_u16m1(v1, 0), vget_u16m2_u16m1(v1, 1), 8); + return v_uint32x4(vadd_vv_u32m1(vadd_vv_u32m1(vget_u32m2_u32m1(v2, 0), vget_u32m2_u32m1(v2, 1), 4), c.val, 4)); +} + +inline v_int32x4 v_dotprod_expand_fast(const v_int8x16& a, const v_int8x16& b) +{ + vint16m2_t v1 = vundefined_i16m2(); + vint32m2_t v2 = vundefined_i32m2(); + v1 = vwmul_vv_i16m2(a.val, b.val, 16); + v2 = vwadd_vv_i32m2(vget_i16m2_i16m1(v1, 0), vget_i16m2_i16m1(v1, 1), 8); + return v_int32x4(vadd_vv_i32m1(vget_i32m2_i32m1(v2, 0), vget_i32m2_i32m1(v2, 1), 4)); +} +inline v_int32x4 v_dotprod_expand_fast(const v_int8x16& a, const v_int8x16& b, const v_int32x4& c) +{ + vint16m2_t v1 = vundefined_i16m2(); + vint32m2_t v2 = vundefined_i32m2(); + v1 = vwmul_vv_i16m2(a.val, b.val, 16); + v2 = vwadd_vv_i32m2(vget_i16m2_i16m1(v1, 0), vget_i16m2_i16m1(v1, 1), 8); + return v_int32x4(vadd_vv_i32m1(vadd_vv_i32m1(vget_i32m2_i32m1(v2, 0), vget_i32m2_i32m1(v2, 1), 4), c.val, 4)); +} + +// 16 >> 64 +inline v_uint64x2 v_dotprod_expand_fast(const v_uint16x8& a, const v_uint16x8& b) +{ + vuint32m2_t v1 = vundefined_u32m2(); + vuint64m2_t v2 = vundefined_u64m2(); + v1 = vwmulu_vv_u32m2(a.val, b.val, 8); + v2 = vwaddu_vv_u64m2(vget_u32m2_u32m1(v1, 0), vget_u32m2_u32m1(v1, 1), 4); + return v_uint64x2(vadd_vv_u64m1(vget_u64m2_u64m1(v2, 0), vget_u64m2_u64m1(v2, 1), 2)); +} +inline v_uint64x2 v_dotprod_expand_fast(const v_uint16x8& a, const v_uint16x8& b, const v_uint64x2& c) +{ + vuint32m2_t v1 = vundefined_u32m2(); + vuint64m2_t v2 = vundefined_u64m2(); + v1 = vwmulu_vv_u32m2(a.val, b.val, 8); + v2 = vwaddu_vv_u64m2(vget_u32m2_u32m1(v1, 0), vget_u32m2_u32m1(v1, 1), 4); + return v_uint64x2(vadd_vv_u64m1(vadd_vv_u64m1(vget_u64m2_u64m1(v2, 0), vget_u64m2_u64m1(v2, 1), 2), c.val, 2)); +} + +inline v_int64x2 v_dotprod_expand_fast(const v_int16x8& a, const v_int16x8& b) +{ + vint32m2_t v1 = vundefined_i32m2(); + vint64m2_t v2 = vundefined_i64m2(); + v1 = vwmul_vv_i32m2(a.val, b.val, 8); + v2 = vwadd_vv_i64m2(vget_i32m2_i32m1(v1, 0), vget_i32m2_i32m1(v1, 1), 4); + return v_int64x2(vadd_vv_i64m1(vget_i64m2_i64m1(v2, 0), vget_i64m2_i64m1(v2, 1), 2)); +} +inline v_int64x2 v_dotprod_expand_fast(const v_int16x8& a, const v_int16x8& b, const v_int64x2& c) +{ + vint32m2_t v1 = vundefined_i32m2(); + vint64m2_t v2 = vundefined_i64m2(); + v1 = vwmul_vv_i32m2(a.val, b.val, 8); + v2 = vwadd_vv_i64m2(vget_i32m2_i32m1(v1, 0), vget_i32m2_i32m1(v1, 1), 4); + return v_int64x2(vadd_vv_i64m1(vadd_vv_i64m1(vget_i64m2_i64m1(v2, 0), vget_i64m2_i64m1(v2, 1), 2), c.val, 2)); +} + + +#define OPENCV_HAL_IMPL_RISCVV_REDUCE_OP_W(_Tpvec, _Tpvec2, len, scalartype, func, intrin, num) \ +inline scalartype v_reduce_##func(const v_##_Tpvec##x##num& a) \ +{\ + v##_Tpvec2##m1_t val = vmv_v_x_##len##m1(0, num); \ + val = intrin(val, a.val, val, num); \ + return vmv_x_s_##len##m1_##len(val, num); \ +} + + +#define OPENCV_HAL_IMPL_RISCVV_REDUCE_OP_(_Tpvec, _Tpvec2, scalartype, func, funcu, num) \ +inline scalartype v_reduce_##func(const v_##_Tpvec##x##num& a) \ +{\ + v##_Tpvec##m1_t val = (v##_Tpvec##m1_t)vmv_v_x_i8m1(0, num); \ + val = v##funcu##_vs_##_Tpvec2##m1_##_Tpvec2##m1(val, a.val, a.val, num); \ + return val[0]; \ +} +OPENCV_HAL_IMPL_RISCVV_REDUCE_OP_W(int8, int16, i16, int, sum, vwredsum_vs_i8m1_i16m1, 16) +OPENCV_HAL_IMPL_RISCVV_REDUCE_OP_W(int16, int32, i32, int, sum, vwredsum_vs_i16m1_i32m1, 8) +OPENCV_HAL_IMPL_RISCVV_REDUCE_OP_W(int32, int64, i64, int, sum, vwredsum_vs_i32m1_i64m1, 4) +OPENCV_HAL_IMPL_RISCVV_REDUCE_OP_W(uint8, uint16, u16, unsigned, sum, vwredsumu_vs_u8m1_u16m1, 16) +OPENCV_HAL_IMPL_RISCVV_REDUCE_OP_W(uint16, uint32, u32, unsigned, sum, vwredsumu_vs_u16m1_u32m1, 8) +OPENCV_HAL_IMPL_RISCVV_REDUCE_OP_W(uint32, uint64, u64, unsigned, sum, vwredsumu_vs_u32m1_u64m1, 4) +inline float v_reduce_sum(const v_float32x4& a) \ +{\ + vfloat32m1_t val = vfmv_v_f_f32m1(0.0, 4); \ + val = vfredsum_vs_f32m1_f32m1(val, a.val, val, 4); \ + return vfmv_f_s_f32m1_f32(val, 4); \ +} +inline double v_reduce_sum(const v_float64x2& a) \ +{\ + vfloat64m1_t val = vfmv_v_f_f64m1(0.0, 2); \ + val = vfredsum_vs_f64m1_f64m1(val, a.val, val, 2); \ + return vfmv_f_s_f64m1_f64(val, 2); \ +} +inline uint64 v_reduce_sum(const v_uint64x2& a) +{ return vext_x_v_u64m1_u64((vuint64m1_t)a.val, 0, 2)+vext_x_v_u64m1_u64((vuint64m1_t)a.val, 1, 2); } + +inline int64 v_reduce_sum(const v_int64x2& a) +{ return vext_x_v_i64m1_i64((vint64m1_t)a.val, 0, 2)+vext_x_v_i64m1_i64((vint64m1_t)a.val, 1, 2); } + +#define OPENCV_HAL_IMPL_RISCVV_REDUCE_OP(func) \ +OPENCV_HAL_IMPL_RISCVV_REDUCE_OP_(int8, i8, int, func, red##func, 16) \ +OPENCV_HAL_IMPL_RISCVV_REDUCE_OP_(int16, i16, int, func, red##func, 8) \ +OPENCV_HAL_IMPL_RISCVV_REDUCE_OP_(int32, i32, int, func, red##func, 4) \ +OPENCV_HAL_IMPL_RISCVV_REDUCE_OP_(int64, i64, int, func, red##func, 2) \ +OPENCV_HAL_IMPL_RISCVV_REDUCE_OP_(uint8, u8, unsigned, func, red##func##u, 16) \ +OPENCV_HAL_IMPL_RISCVV_REDUCE_OP_(uint16, u16, unsigned, func, red##func##u, 8) \ +OPENCV_HAL_IMPL_RISCVV_REDUCE_OP_(uint32, u32, unsigned, func, red##func##u, 4) \ +OPENCV_HAL_IMPL_RISCVV_REDUCE_OP_(float32, f32, float, func, fred##func, 4) +OPENCV_HAL_IMPL_RISCVV_REDUCE_OP(max) +OPENCV_HAL_IMPL_RISCVV_REDUCE_OP(min) + +inline v_float32x4 v_reduce_sum4(const v_float32x4& a, const v_float32x4& b, + const v_float32x4& c, const v_float32x4& d) +{ + vfloat32m1_t a0 = vfmv_v_f_f32m1(0.0, 4); + vfloat32m1_t b0 = vfmv_v_f_f32m1(0.0, 4); + vfloat32m1_t c0 = vfmv_v_f_f32m1(0.0, 4); + vfloat32m1_t d0 = vfmv_v_f_f32m1(0.0, 4); + a0 = vfredsum_vs_f32m1_f32m1(a0, a.val, a0, 4); + b0 = vfredsum_vs_f32m1_f32m1(b0, b.val, b0, 4); + c0 = vfredsum_vs_f32m1_f32m1(c0, c.val, c0, 4); + d0 = vfredsum_vs_f32m1_f32m1(d0, d.val, d0, 4); + return v_float32x4(a0[0], b0[0], c0[0], d0[0]); +} + +inline float v_reduce_sad(const v_float32x4& a, const v_float32x4& b) +{ + vfloat32m1_t a0 = vfmv_v_f_f32m1(0.0, 4); + vfloat32m1_t x = vfsub_vv_f32m1(a.val, b.val, 4); + vbool32_t mask=vmflt_vf_f32m1_b32(x, 0, 4); + vfloat32m1_t val = vfrsub_vf_f32m1_m(mask, x, x, 0, 4); + a0 = vfredsum_vs_f32m1_f32m1(a0, val, a0, 4); + return a0[0]; +} + +#define OPENCV_HAL_IMPL_RISCVV_REDUCE_SAD(_Tpvec, _Tpvec2) \ +inline unsigned v_reduce_sad(const _Tpvec& a, const _Tpvec&b){ \ + _Tpvec2 x = v_absdiff(a, b); \ + return v_reduce_sum(x); \ +} + +OPENCV_HAL_IMPL_RISCVV_REDUCE_SAD(v_int8x16, v_uint8x16) +OPENCV_HAL_IMPL_RISCVV_REDUCE_SAD(v_uint8x16, v_uint8x16) +OPENCV_HAL_IMPL_RISCVV_REDUCE_SAD(v_int16x8, v_uint16x8) +OPENCV_HAL_IMPL_RISCVV_REDUCE_SAD(v_uint16x8, v_uint16x8) +OPENCV_HAL_IMPL_RISCVV_REDUCE_SAD(v_int32x4, v_uint32x4) +OPENCV_HAL_IMPL_RISCVV_REDUCE_SAD(v_uint32x4, v_uint32x4) + +#define OPENCV_HAL_IMPL_RISCVV_INT_CMP_OP(_Tpvec, _Tp, _T, num, uv) \ +inline _Tpvec operator == (const _Tpvec& a, const _Tpvec& b) \ +{ \ + vbool##_T##_t mask = vmseq_vv_##_Tp##_b##_T(a.val, b.val, num); \ + return _Tpvec(vmerge_vxm_##_Tp(mask, vmv_v_x_##_Tp(0, num), -1, num)); \ +} \ +inline _Tpvec operator != (const _Tpvec& a, const _Tpvec& b) \ +{ \ + vbool##_T##_t mask = vmsne_vv_##_Tp##_b##_T(a.val, b.val, num); \ + return _Tpvec(vmerge_vxm_##_Tp(mask, vmv_v_x_##_Tp(0, num), -1, num)); \ +} \ +inline _Tpvec operator < (const _Tpvec& a, const _Tpvec& b) \ +{ \ + vbool##_T##_t mask = vmslt##uv##_Tp##_b##_T(a.val, b.val, num); \ + return _Tpvec(vmerge_vxm_##_Tp(mask, vmv_v_x_##_Tp(0, num), -1, num)); \ +} \ +inline _Tpvec operator > (const _Tpvec& a, const _Tpvec& b) \ +{ \ + vbool##_T##_t mask = vmslt##uv##_Tp##_b##_T(b.val, a.val, num); \ + return _Tpvec(vmerge_vxm_##_Tp(mask, vmv_v_x_##_Tp(0, num), -1, num)); \ +} \ +inline _Tpvec operator <= (const _Tpvec& a, const _Tpvec& b) \ +{ \ + vbool##_T##_t mask = vmsle##uv##_Tp##_b##_T(a.val, b.val, num); \ + return _Tpvec(vmerge_vxm_##_Tp(mask, vmv_v_x_##_Tp(0, num), -1, num)); \ +} \ +inline _Tpvec operator >= (const _Tpvec& a, const _Tpvec& b) \ +{ \ + vbool##_T##_t mask = vmsle##uv##_Tp##_b##_T(b.val, a.val, num); \ + return _Tpvec(vmerge_vxm_##_Tp(mask, vmv_v_x_##_Tp(0, num), -1, num)); \ +} \ + +OPENCV_HAL_IMPL_RISCVV_INT_CMP_OP(v_int8x16, i8m1, 8, 16, _vv_) +OPENCV_HAL_IMPL_RISCVV_INT_CMP_OP(v_int16x8, i16m1, 16, 8, _vv_) +OPENCV_HAL_IMPL_RISCVV_INT_CMP_OP(v_int32x4, i32m1, 32, 4, _vv_) +OPENCV_HAL_IMPL_RISCVV_INT_CMP_OP(v_int64x2, i64m1, 64, 2, _vv_) +OPENCV_HAL_IMPL_RISCVV_INT_CMP_OP(v_uint8x16, u8m1, 8, 16, u_vv_) +OPENCV_HAL_IMPL_RISCVV_INT_CMP_OP(v_uint16x8, u16m1, 16, 8, u_vv_) +OPENCV_HAL_IMPL_RISCVV_INT_CMP_OP(v_uint32x4, u32m1, 32, 4, u_vv_) +OPENCV_HAL_IMPL_RISCVV_INT_CMP_OP(v_uint64x2, u64m1, 64, 2, u_vv_) + +//TODO: == +inline v_float32x4 operator == (const v_float32x4& a, const v_float32x4& b) +{ + vbool32_t mask = vmfeq_vv_f32m1_b32(a.val, b.val, 4); + vint32m1_t res = vmerge_vxm_i32m1(mask, vmv_v_x_i32m1(0.0, 4), -1, 4); + return v_float32x4((vfloat32m1_t)res); +} +inline v_float32x4 operator != (const v_float32x4& a, const v_float32x4& b) +{ + vbool32_t mask = vmfne_vv_f32m1_b32(a.val, b.val, 4); + vint32m1_t res = vmerge_vxm_i32m1(mask, vmv_v_x_i32m1(0.0, 4), -1, 4); + return v_float32x4((vfloat32m1_t)res); +} +inline v_float32x4 operator < (const v_float32x4& a, const v_float32x4& b) +{ + vbool32_t mask = vmflt_vv_f32m1_b32(a.val, b.val, 4); + vint32m1_t res = vmerge_vxm_i32m1(mask, vmv_v_x_i32m1(0.0, 4), -1, 4); + return v_float32x4((vfloat32m1_t)res); +} +inline v_float32x4 operator <= (const v_float32x4& a, const v_float32x4& b) +{ + vbool32_t mask = vmfle_vv_f32m1_b32(a.val, b.val, 4); + vint32m1_t res = vmerge_vxm_i32m1(mask, vmv_v_x_i32m1(0.0, 4), -1, 4); + return v_float32x4((vfloat32m1_t)res); +} +inline v_float32x4 operator > (const v_float32x4& a, const v_float32x4& b) +{ + vbool32_t mask = vmfgt_vv_f32m1_b32(a.val, b.val, 4); + vint32m1_t res = vmerge_vxm_i32m1(mask, vmv_v_x_i32m1(0.0, 4), -1, 4); + return v_float32x4((vfloat32m1_t)res); +} +inline v_float32x4 operator >= (const v_float32x4& a, const v_float32x4& b) +{ + vbool32_t mask = vmfge_vv_f32m1_b32(a.val, b.val, 4); + vint32m1_t res = vmerge_vxm_i32m1(mask, vmv_v_x_i32m1(0.0, 4), -1, 4); + return v_float32x4((vfloat32m1_t)res); +} +inline v_float32x4 v_not_nan(const v_float32x4& a) +{ + vbool32_t mask = vmford_vv_f32m1_b32(a.val, a.val, 4); + vint32m1_t res = vmerge_vxm_i32m1(mask, vmv_v_x_i32m1(0.0, 4), -1, 4); + return v_float32x4((vfloat32m1_t)res); +} + +//TODO: == +inline v_float64x2 operator == (const v_float64x2& a, const v_float64x2& b) +{ + vbool64_t mask = vmfeq_vv_f64m1_b64(a.val, b.val, 2); + vint64m1_t res = vmerge_vxm_i64m1(mask, vmv_v_x_i64m1(0.0, 2), -1, 2); + return v_float64x2((vfloat64m1_t)res); +} +inline v_float64x2 operator != (const v_float64x2& a, const v_float64x2& b) +{ + vbool64_t mask = vmfne_vv_f64m1_b64(a.val, b.val, 2); + vint64m1_t res = vmerge_vxm_i64m1(mask, vmv_v_x_i64m1(0.0, 2), -1, 2); + return v_float64x2((vfloat64m1_t)res); +} +inline v_float64x2 operator < (const v_float64x2& a, const v_float64x2& b) +{ + vbool64_t mask = vmflt_vv_f64m1_b64(a.val, b.val, 2); + vint64m1_t res = vmerge_vxm_i64m1(mask, vmv_v_x_i64m1(0.0, 2), -1, 2); + return v_float64x2((vfloat64m1_t)res); +} +inline v_float64x2 operator <= (const v_float64x2& a, const v_float64x2& b) +{ + vbool64_t mask = vmfle_vv_f64m1_b64(a.val, b.val, 2); + vint64m1_t res = vmerge_vxm_i64m1(mask, vmv_v_x_i64m1(0.0, 2), -1, 2); + return v_float64x2((vfloat64m1_t)res); +} +inline v_float64x2 operator > (const v_float64x2& a, const v_float64x2& b) +{ + vbool64_t mask = vmfgt_vv_f64m1_b64(a.val, b.val, 2); + vint64m1_t res = vmerge_vxm_i64m1(mask, vmv_v_x_i64m1(0.0, 2), -1, 2); + return v_float64x2((vfloat64m1_t)res); +} +inline v_float64x2 operator >= (const v_float64x2& a, const v_float64x2& b) +{ + vbool64_t mask = vmfge_vv_f64m1_b64(a.val, b.val, 2); + vint64m1_t res = vmerge_vxm_i64m1(mask, vmv_v_x_i64m1(0.0, 2), -1, 2); + return v_float64x2((vfloat64m1_t)res); +} +inline v_float64x2 v_not_nan(const v_float64x2& a) +{ + vbool64_t mask = vmford_vv_f64m1_b64(a.val, a.val, 2); + vint64m1_t res = vmerge_vxm_i64m1(mask, vmv_v_x_i64m1(0.0, 2), -1, 2); + return v_float64x2((vfloat64m1_t)res); +} +#define OPENCV_HAL_IMPL_RISCVV_TRANSPOSE4x4(_Tp, _T) \ +inline void v_transpose4x4(const v_##_Tp##32x4& a0, const v_##_Tp##32x4& a1, \ + const v_##_Tp##32x4& a2, const v_##_Tp##32x4& a3, \ + v_##_Tp##32x4& b0, v_##_Tp##32x4& b1, \ + v_##_Tp##32x4& b2, v_##_Tp##32x4& b3) \ +{ \ + v##_Tp##32m4_t val = vundefined_##_T##m4(); \ + val = vset_##_T##m4(val, 0, a0.val); \ + val = vset_##_T##m4(val, 1, a1.val); \ + val = vset_##_T##m4(val, 2, a2.val); \ + val = vset_##_T##m4(val, 3, a3.val); \ + val = vrgather_vv_##_T##m4(val, (vuint32m4_t){0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15}, 16); \ + b0.val = vget_##_T##m4_##_T##m1(val, 0); \ + b1.val = vget_##_T##m4_##_T##m1(val, 1); \ + b2.val = vget_##_T##m4_##_T##m1(val, 2); \ + b3.val = vget_##_T##m4_##_T##m1(val, 3); \ +} +OPENCV_HAL_IMPL_RISCVV_TRANSPOSE4x4(uint, u32) +OPENCV_HAL_IMPL_RISCVV_TRANSPOSE4x4(int, i32) +OPENCV_HAL_IMPL_RISCVV_TRANSPOSE4x4(float, f32) + + +#define OPENCV_HAL_IMPL_RISCVV_SHIFT_LEFT(_Tpvec, suffix, _T, num) \ +inline _Tpvec operator << (const _Tpvec& a, int n) \ +{ return _Tpvec((vsll_vx_##_T##m1(a.val, n, num))); } \ +template inline _Tpvec v_shl(const _Tpvec& a) \ +{ return _Tpvec((vsll_vx_##_T##m1(a.val, n, num))); } + +#define OPENCV_HAL_IMPL_RISCVV_SHIFT_RIGHT(_Tpvec, suffix, _T, num, intric) \ +inline _Tpvec operator >> (const _Tpvec& a, int n) \ +{ return _Tpvec((v##intric##_vx_##_T##m1(a.val, n, num))); } \ +template inline _Tpvec v_shr(const _Tpvec& a) \ +{ return _Tpvec((v##intric##_vx_##_T##m1(a.val, n, num))); }\ +template inline _Tpvec v_rshr(const _Tpvec& a) \ +{ return _Tpvec((v##intric##_vx_##_T##m1(vadd_vx_##_T##m1(a.val, 1<<(n-1), num), n, num))); } + +// trade efficiency for convenience +#define OPENCV_HAL_IMPL_RISCVV_SHIFT_OP(suffix, _T, num, intrin) \ +OPENCV_HAL_IMPL_RISCVV_SHIFT_LEFT(v_##suffix##x##num, suffix, _T, num) \ +OPENCV_HAL_IMPL_RISCVV_SHIFT_RIGHT(v_##suffix##x##num, suffix, _T, num, intrin) + +OPENCV_HAL_IMPL_RISCVV_SHIFT_OP(uint8, u8, 16, srl) +OPENCV_HAL_IMPL_RISCVV_SHIFT_OP(uint16, u16, 8, srl) +OPENCV_HAL_IMPL_RISCVV_SHIFT_OP(uint32, u32, 4, srl) +OPENCV_HAL_IMPL_RISCVV_SHIFT_OP(uint64, u64, 2, srl) +OPENCV_HAL_IMPL_RISCVV_SHIFT_OP(int8, i8, 16, sra) +OPENCV_HAL_IMPL_RISCVV_SHIFT_OP(int16, i16, 8, sra) +OPENCV_HAL_IMPL_RISCVV_SHIFT_OP(int32, i32, 4, sra) +OPENCV_HAL_IMPL_RISCVV_SHIFT_OP(int64, i64, 2, sra) + +#if 0 +#define VUP4(n) {0, 1, 2, 3} +#define VUP8(n) {0, 1, 2, 3, 4, 5, 6, 7} +#define VUP16(n) {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} +#define VUP2(n) {0, 1} +#endif +#define OPENCV_HAL_IMPL_RISCVV_ROTATE_OP(_Tpvec, suffix, _T, num, num2, vmv, len) \ +template inline _Tpvec v_rotate_left(const _Tpvec& a) \ +{ \ + suffix##m1_t tmp = vmv##_##_T##m1(0, num);\ + tmp = vslideup_vx_##_T##m1_m(vmset_m_##len(num), tmp, a.val, n, num);\ + return _Tpvec(tmp);\ +} \ +template inline _Tpvec v_rotate_right(const _Tpvec& a) \ +{ \ + return _Tpvec(vslidedown_vx_##_T##m1(a.val, n, num));\ +} \ +template<> inline _Tpvec v_rotate_left<0>(const _Tpvec& a) \ +{ return a; } \ +template inline _Tpvec v_rotate_right(const _Tpvec& a, const _Tpvec& b) \ +{ \ + suffix##m2_t tmp = vundefined_##_T##m2(); \ + tmp = vset_##_T##m2(tmp, 0, a.val); \ + tmp = vset_##_T##m2(tmp, 1, b.val); \ + tmp = vslidedown_vx_##_T##m2(tmp, n, num2);\ + return _Tpvec(vget_##_T##m2_##_T##m1(tmp, 0));\ +} \ +template inline _Tpvec v_rotate_left(const _Tpvec& a, const _Tpvec& b) \ +{ \ + suffix##m2_t tmp = vundefined_##_T##m2(); \ + tmp = vset_##_T##m2(tmp, 0, b.val); \ + tmp = vset_##_T##m2(tmp, 1, a.val); \ + tmp = vslideup_vx_##_T##m2(tmp, n, num2);\ + return _Tpvec(vget_##_T##m2_##_T##m1(tmp, 1));\ +} \ +template<> inline _Tpvec v_rotate_left<0>(const _Tpvec& a, const _Tpvec& b) \ +{ \ + CV_UNUSED(b); return a; \ +} + +OPENCV_HAL_IMPL_RISCVV_ROTATE_OP(v_uint8x16, vuint8, u8, 16, 32, vmv_v_x, b8) +OPENCV_HAL_IMPL_RISCVV_ROTATE_OP(v_int8x16, vint8, i8, 16, 32, vmv_v_x, b8) +OPENCV_HAL_IMPL_RISCVV_ROTATE_OP(v_uint16x8, vuint16, u16, 8, 16, vmv_v_x, b16) +OPENCV_HAL_IMPL_RISCVV_ROTATE_OP(v_int16x8, vint16, i16, 8, 16, vmv_v_x, b16) +OPENCV_HAL_IMPL_RISCVV_ROTATE_OP(v_uint32x4, vuint32, u32, 4, 8, vmv_v_x, b32) +OPENCV_HAL_IMPL_RISCVV_ROTATE_OP(v_int32x4, vint32, i32, 4, 8, vmv_v_x, b32) +OPENCV_HAL_IMPL_RISCVV_ROTATE_OP(v_uint64x2, vuint64, u64, 2, 4, vmv_v_x, b64) +OPENCV_HAL_IMPL_RISCVV_ROTATE_OP(v_int64x2, vint64, i64, 2, 4, vmv_v_x, b64) +OPENCV_HAL_IMPL_RISCVV_ROTATE_OP(v_float32x4, vfloat32, f32, 4, 8, vfmv_v_f, b32) +OPENCV_HAL_IMPL_RISCVV_ROTATE_OP(v_float64x2, vfloat64, f64, 2, 4, vfmv_v_f, b64) + +#define OPENCV_HAL_IMPL_RISCVV_LOADSTORE_OP(_Tpvec, _Tp, _Tp2, len, hnum, num) \ +inline _Tpvec v_load_halves(const _Tp* ptr0, const _Tp* ptr1) \ +{ \ + typedef uint64 CV_DECL_ALIGNED(1) unaligned_uint64; \ + vuint64m1_t tmp = {*(unaligned_uint64*)ptr0, *(unaligned_uint64*)ptr1};\ + return _Tpvec(_Tp2##_t(tmp)); } \ +inline _Tpvec v_load_low(const _Tp* ptr) \ +{ return _Tpvec(vle_v_##len(ptr, hnum)); }\ +inline _Tpvec v_load_aligned(const _Tp* ptr) \ +{ return _Tpvec(vle_v_##len(ptr, num)); } \ +inline _Tpvec v_load(const _Tp* ptr) \ +{ return _Tpvec((_Tp2##_t)vle_v_##len((const _Tp *)ptr, num)); } \ +inline void v_store_low(_Tp* ptr, const _Tpvec& a) \ +{ vse_v_##len(ptr, a.val, hnum);}\ +inline void v_store_high(_Tp* ptr, const _Tpvec& a) \ +{ \ + _Tp2##_t a0 = vslidedown_vx_##len(a.val, hnum, num); \ + vse_v_##len(ptr, a0, hnum);}\ +inline void v_store(_Tp* ptr, const _Tpvec& a) \ +{ vse_v_##len(ptr, a.val, num); } \ +inline void v_store_aligned(_Tp* ptr, const _Tpvec& a) \ +{ vse_v_##len(ptr, a.val, num); } \ +inline void v_store_aligned_nocache(_Tp* ptr, const _Tpvec& a) \ +{ vse_v_##len(ptr, a.val, num); } \ +inline void v_store(_Tp* ptr, const _Tpvec& a, hal::StoreMode /*mode*/) \ +{ vse_v_##len(ptr, a.val, num); } + +OPENCV_HAL_IMPL_RISCVV_LOADSTORE_OP(v_uint8x16, uchar, vuint8m1, u8m1, 8, 16) +OPENCV_HAL_IMPL_RISCVV_LOADSTORE_OP(v_int8x16, schar, vint8m1, i8m1, 8, 16) +OPENCV_HAL_IMPL_RISCVV_LOADSTORE_OP(v_uint16x8, ushort, vuint16m1, u16m1, 4, 8) +OPENCV_HAL_IMPL_RISCVV_LOADSTORE_OP(v_int16x8, short, vint16m1, i16m1, 4, 8) +OPENCV_HAL_IMPL_RISCVV_LOADSTORE_OP(v_uint32x4, unsigned, vuint32m1, u32m1, 2, 4) +OPENCV_HAL_IMPL_RISCVV_LOADSTORE_OP(v_int32x4, int, vint32m1, i32m1, 2, 4) +OPENCV_HAL_IMPL_RISCVV_LOADSTORE_OP(v_uint64x2, unsigned long, vuint64m1, u64m1, 1, 2) +OPENCV_HAL_IMPL_RISCVV_LOADSTORE_OP(v_int64x2, long, vint64m1, i64m1, 1, 2) +OPENCV_HAL_IMPL_RISCVV_LOADSTORE_OP(v_float32x4, float, vfloat32m1, f32m1, 2, 4) +OPENCV_HAL_IMPL_RISCVV_LOADSTORE_OP(v_float64x2, double, vfloat64m1, f64m1, 1, 2) + + +////////////// Lookup table access //////////////////// + +inline v_int8x16 v_lut(const schar* tab, const int* idx) +{ +#if 1 + schar CV_DECL_ALIGNED(32) elems[16] = + { + tab[idx[ 0]], + tab[idx[ 1]], + tab[idx[ 2]], + tab[idx[ 3]], + tab[idx[ 4]], + tab[idx[ 5]], + tab[idx[ 6]], + tab[idx[ 7]], + tab[idx[ 8]], + tab[idx[ 9]], + tab[idx[10]], + tab[idx[11]], + tab[idx[12]], + tab[idx[13]], + tab[idx[14]], + tab[idx[15]] + }; + return v_int8x16(vle_v_i8m1(elems, 16)); +#else + int32xm4_t index32 = vlev_int32xm4(idx, 16); + vint16m2_t index16 = vnsra_vx_i16m2_int32xm4(index32, 0, 16); + vint8m1_t index = vnsra_vx_i8m1_i16m2(index16, 0, 16); + return v_int8x16(vlxbv_i8m1(tab, index, 16)); +#endif +} + +inline v_int8x16 v_lut_pairs(const schar* tab, const int* idx){ + schar CV_DECL_ALIGNED(32) elems[16] = + { + tab[idx[0]], + tab[idx[0] + 1], + tab[idx[1]], + tab[idx[1] + 1], + tab[idx[2]], + tab[idx[2] + 1], + tab[idx[3]], + tab[idx[3] + 1], + tab[idx[4]], + tab[idx[4] + 1], + tab[idx[5]], + tab[idx[5] + 1], + tab[idx[6]], + tab[idx[6] + 1], + tab[idx[7]], + tab[idx[7] + 1] + }; + return v_int8x16(vle_v_i8m1(elems, 16)); +} +inline v_int8x16 v_lut_quads(const schar* tab, const int* idx) +{ + schar CV_DECL_ALIGNED(32) elems[16] = + { + tab[idx[0]], + tab[idx[0] + 1], + tab[idx[0] + 2], + tab[idx[0] + 3], + tab[idx[1]], + tab[idx[1] + 1], + tab[idx[1] + 2], + tab[idx[1] + 3], + tab[idx[2]], + tab[idx[2] + 1], + tab[idx[2] + 2], + tab[idx[2] + 3], + tab[idx[3]], + tab[idx[3] + 1], + tab[idx[3] + 2], + tab[idx[3] + 3] + }; + return v_int8x16(vle_v_i8m1(elems, 16)); +} + +inline v_uint8x16 v_lut(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut((schar*)tab, idx)); } +inline v_uint8x16 v_lut_pairs(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut_pairs((schar*)tab, idx)); } +inline v_uint8x16 v_lut_quads(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut_quads((schar*)tab, idx)); } + +inline v_int16x8 v_lut(const short* tab, const int* idx) +{ + short CV_DECL_ALIGNED(32) elems[8] = + { + tab[idx[0]], + tab[idx[1]], + tab[idx[2]], + tab[idx[3]], + tab[idx[4]], + tab[idx[5]], + tab[idx[6]], + tab[idx[7]] + }; + return v_int16x8(vle_v_i16m1(elems, 8)); +} +inline v_int16x8 v_lut_pairs(const short* tab, const int* idx) +{ + short CV_DECL_ALIGNED(32) elems[8] = + { + tab[idx[0]], + tab[idx[0] + 1], + tab[idx[1]], + tab[idx[1] + 1], + tab[idx[2]], + tab[idx[2] + 1], + tab[idx[3]], + tab[idx[3] + 1] + }; + return v_int16x8(vle_v_i16m1(elems, 8)); +} +inline v_int16x8 v_lut_quads(const short* tab, const int* idx) +{ + short CV_DECL_ALIGNED(32) elems[8] = + { + tab[idx[0]], + tab[idx[0] + 1], + tab[idx[0] + 2], + tab[idx[0] + 3], + tab[idx[1]], + tab[idx[1] + 1], + tab[idx[1] + 2], + tab[idx[1] + 3] + }; + return v_int16x8(vle_v_i16m1(elems, 8)); +} +inline v_uint16x8 v_lut(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut((short*)tab, idx)); } +inline v_uint16x8 v_lut_pairs(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut_pairs((short*)tab, idx)); } +inline v_uint16x8 v_lut_quads(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut_quads((short*)tab, idx)); } + +inline v_int32x4 v_lut(const int* tab, const int* idx) +{ + int CV_DECL_ALIGNED(32) elems[4] = + { + tab[idx[0]], + tab[idx[1]], + tab[idx[2]], + tab[idx[3]] + }; + return v_int32x4(vle_v_i32m1(elems, 4)); +} +inline v_int32x4 v_lut_pairs(const int* tab, const int* idx) +{ + int CV_DECL_ALIGNED(32) elems[4] = + { + tab[idx[0]], + tab[idx[0] + 1], + tab[idx[1]], + tab[idx[1] + 1] + }; + return v_int32x4(vle_v_i32m1(elems, 4)); +} +inline v_int32x4 v_lut_quads(const int* tab, const int* idx) +{ + return v_int32x4(vle_v_i32m1(tab+idx[0], 4)); +} +inline v_uint32x4 v_lut(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut((int*)tab, idx)); } +inline v_uint32x4 v_lut_pairs(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut_pairs((int*)tab, idx)); } +inline v_uint32x4 v_lut_quads(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut_quads((int*)tab, idx)); } + +inline v_int64x2 v_lut(const int64_t* tab, const int* idx) +{ + vint64m1_t res = {tab[idx[0]], tab[idx[1]]}; + return v_int64x2(res); +} +inline v_int64x2 v_lut_pairs(const int64_t* tab, const int* idx) +{ + return v_int64x2(vle_v_i64m1(tab+idx[0], 2)); +} + +inline v_uint64x2 v_lut(const uint64_t* tab, const int* idx) +{ + vuint64m1_t res = {tab[idx[0]], tab[idx[1]]}; + return v_uint64x2(res); +} +inline v_uint64x2 v_lut_pairs(const uint64_t* tab, const int* idx) +{ + return v_uint64x2(vle_v_u64m1(tab+idx[0], 2)); +} + +inline v_float32x4 v_lut(const float* tab, const int* idx) +{ + float CV_DECL_ALIGNED(32) elems[4] = + { + tab[idx[0]], + tab[idx[1]], + tab[idx[2]], + tab[idx[3]] + }; + return v_float32x4(vle_v_f32m1(elems, 4)); +} +inline v_float32x4 v_lut_pairs(const float* tab, const int* idx) +{ + float CV_DECL_ALIGNED(32) elems[4] = + { + tab[idx[0]], + tab[idx[0]+1], + tab[idx[1]], + tab[idx[1]+1] + }; + return v_float32x4(vle_v_f32m1(elems, 4)); +} +inline v_float32x4 v_lut_quads(const float* tab, const int* idx) +{ + return v_float32x4(vle_v_f32m1(tab + idx[0], 4)); +} +inline v_float64x2 v_lut(const double* tab, const int* idx) +{ + vfloat64m1_t res = {tab[idx[0]], tab[idx[1]]}; + return v_float64x2(res); +} +inline v_float64x2 v_lut_pairs(const double* tab, const int* idx) +{ + return v_float64x2(vle_v_f64m1(tab+idx[0], 2)); +} + +inline v_int32x4 v_lut(const int* tab, const v_int32x4& idxvec) +{ + int CV_DECL_ALIGNED(32) elems[4] = + { + tab[idxvec.val[0]], + tab[idxvec.val[1]], + tab[idxvec.val[2]], + tab[idxvec.val[3]] + }; + return v_int32x4(vle_v_i32m1(elems, 4)); +} + +inline v_uint32x4 v_lut(const unsigned* tab, const v_int32x4& idxvec) +{ + unsigned CV_DECL_ALIGNED(32) elems[4] = + { + tab[idxvec.val[0]], + tab[idxvec.val[1]], + tab[idxvec.val[2]], + tab[idxvec.val[3]] + }; + return v_uint32x4(vle_v_u32m1(elems, 4)); +} + +inline v_float32x4 v_lut(const float* tab, const v_int32x4& idxvec) +{ + float CV_DECL_ALIGNED(32) elems[4] = + { + tab[idxvec.val[0]], + tab[idxvec.val[1]], + tab[idxvec.val[2]], + tab[idxvec.val[3]] + }; + return v_float32x4(vle_v_f32m1(elems, 4)); +} +inline v_float64x2 v_lut(const double* tab, const v_int32x4& idxvec) +{ + vfloat64m1_t res = {tab[idxvec.val[0]], tab[idxvec.val[1]]}; + return v_float64x2(res); +} +inline void v_lut_deinterleave(const float* tab, const v_int32x4& idxvec, v_float32x4& x, v_float32x4& y) +{ + vint32m1_t index_x = vmul_vx_i32m1(idxvec.val, 4, 4); + vint32m1_t index_y = vadd_vx_i32m1(index_x, 4, 4); + + x.val = vlxe_v_f32m1(tab, index_x, 4); + y.val = vlxe_v_f32m1(tab, index_y, 4); +} + +inline void v_lut_deinterleave(const double* tab, const v_int32x4& idxvec, v_float64x2& x, v_float64x2& y) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + + x = v_float64x2(tab[idx[0]], tab[idx[1]]); + y = v_float64x2(tab[idx[0]+1], tab[idx[1]+1]); +} + +#define OPENCV_HAL_IMPL_RISCVV_PACKS(_Tp, _Tp2, _T2, num2, _T1, num, intrin, shr, _Type) \ +inline v_##_Tp##x##num v_pack(const v_##_Tp2##x##num2& a, const v_##_Tp2##x##num2& b) \ +{ \ + v##_Tp2##m2_t tmp = vundefined_##_T2##m2(); \ + tmp = vset_##_T2##m2(tmp, 0, a.val); \ + tmp = vset_##_T2##m2(tmp, 1, b.val); \ + return v_##_Tp##x##num(shr##_##_T1##m1(tmp, 0, num)); \ +}\ +template inline \ +v_##_Tp##x##num v_rshr_pack(const v_##_Tp2##x##num2& a, const v_##_Tp2##x##num2& b) \ +{ \ + v##_Tp2##m2_t tmp = vundefined_##_T2##m2(); \ + tmp = vset_##_T2##m2(tmp, 0, a.val); \ + tmp = vset_##_T2##m2(tmp, 1, b.val); \ + return v_##_Tp##x##num(intrin##_##_T1##m1(tmp, n, num)); \ +}\ +inline void v_pack_store(_Type* ptr, const v_##_Tp2##x##num2& a) \ +{ \ + v##_Tp2##m2_t tmp = vundefined_##_T2##m2(); \ + tmp = vset_##_T2##m2(tmp, 0, a.val); \ + tmp = vset_##_T2##m2(tmp, 1, vmv_v_x_##_T2##m1(0, num2)); \ + asm("" ::: "memory"); \ + vse_v_##_T1##m1(ptr, shr##_##_T1##m1(tmp, 0, num), num2); \ +}\ +template inline \ +void v_rshr_pack_store(_Type* ptr, const v_##_Tp2##x##num2& a) \ +{ \ + v##_Tp2##m2_t tmp = vundefined_##_T2##m2(); \ + tmp = vset_##_T2##m2(tmp, 0, a.val); \ + tmp = vset_##_T2##m2(tmp, 1, vmv_v_x_##_T2##m1(0, num2)); \ + vse_v_##_T1##m1(ptr, intrin##_##_T1##m1(tmp, n, num), num2); \ +} +OPENCV_HAL_IMPL_RISCVV_PACKS(int8, int16, i16, 8, i8, 16, vnclip_vx, vnclip_vx, signed char) +OPENCV_HAL_IMPL_RISCVV_PACKS(int16, int32, i32, 4, i16, 8, vnclip_vx, vnclip_vx, signed short) +OPENCV_HAL_IMPL_RISCVV_PACKS(int32, int64, i64, 2, i32, 4, vnclip_vx, vnsra_vx, int) +OPENCV_HAL_IMPL_RISCVV_PACKS(uint8, uint16, u16, 8, u8, 16, vnclipu_vx, vnclipu_vx, unsigned char) +OPENCV_HAL_IMPL_RISCVV_PACKS(uint16, uint32, u32, 4, u16, 8, vnclipu_vx, vnclipu_vx, unsigned short) +OPENCV_HAL_IMPL_RISCVV_PACKS(uint32, uint64, u64, 2, u32, 4, vnclipu_vx, vnsrl_vx, unsigned int) + +// pack boolean +inline v_uint8x16 v_pack_b(const v_uint16x8& a, const v_uint16x8& b) +{ + vuint16m2_t tmp = vundefined_u16m2(); \ + tmp = vset_u16m2(tmp, 0, a.val); \ + tmp = vset_u16m2(tmp, 1, b.val); \ + return v_uint8x16(vnsrl_vx_u8m1(tmp, 0, 16)); +} + +inline v_uint8x16 v_pack_b(const v_uint32x4& a, const v_uint32x4& b, + const v_uint32x4& c, const v_uint32x4& d) +{ + vuint32m4_t vabcd = vundefined_u32m4(); \ + vuint16m2_t v16 = vundefined_u16m2(); \ + vabcd = vset_u32m4(vabcd, 0, a.val); \ + vabcd = vset_u32m4(vabcd, 1, b.val); \ + vabcd = vset_u32m4(vabcd, 2, c.val); \ + vabcd = vset_u32m4(vabcd, 3, d.val); \ + v16 = vnsrl_vx_u16m2(vabcd, 0, 16); + return v_uint8x16(vnsrl_vx_u8m1(v16, 0, 16)); +} + +inline v_uint8x16 v_pack_b(const v_uint64x2& a, const v_uint64x2& b, const v_uint64x2& c, + const v_uint64x2& d, const v_uint64x2& e, const v_uint64x2& f, + const v_uint64x2& g, const v_uint64x2& h) +{ + vuint64m8_t v64 = vundefined_u64m8(); \ + vuint32m4_t v32 = vundefined_u32m4(); \ + vuint16m2_t v16 = vundefined_u16m2(); \ + v64 = vset_u64m8(v64, 0, a.val); \ + v64 = vset_u64m8(v64, 1, b.val); \ + v64 = vset_u64m8(v64, 2, c.val); \ + v64 = vset_u64m8(v64, 3, d.val); \ + v64 = vset_u64m8(v64, 4, e.val); \ + v64 = vset_u64m8(v64, 5, f.val); \ + v64 = vset_u64m8(v64, 6, g.val); \ + v64 = vset_u64m8(v64, 7, h.val); \ + v32 = vnsrl_vx_u32m4(v64, 0, 16); + v16 = vnsrl_vx_u16m2(v32, 0, 16); + return v_uint8x16(vnsrl_vx_u8m1(v16, 0, 16)); +} + +//inline v_uint8x16 v_pack_u(const v_int16x8& a, const v_int16x8& b) \ +//{ \ +// int16xm2_u tmp; \ +// tmp.m1[0] = (vint16m1_t)a.val; \ +// tmp.m1[1] = (vint16m1_t)b.val; \ +// e8xm1_t mask = (e8xm1_t)vmsge_vx_e16xm2_i16m2(tmp.v, 0, 16);\ +// return v_uint8x16(vnclipuvi_mask_u8m1_u16m2(vmv_v_x_u8m1(0, 16), (vuint16m2_t)tmp.v, 0, mask, 16)); +//} + +#define OPENCV_HAL_IMPL_RISCVV_PACK_U(tp1, num1, tp2, num2, _Tp) \ +inline v_uint##tp1##x##num1 v_pack_u(const v_int##tp2##x##num2& a, const v_int##tp2##x##num2& b) \ +{ \ + vint##tp2##m2_t tmp = vundefined_##i##tp2##m2(); \ + tmp = vset_##i##tp2##m2(tmp, 0, a.val); \ + tmp = vset_##i##tp2##m2(tmp, 1, b.val); \ + vint##tp2##m2_t val = vmax_vx_i##tp2##m2(tmp, 0, num1);\ + return v_uint##tp1##x##num1(vnclipu_vx_u##tp1##m1((vuint##tp2##m2_t)val, 0, num1)); \ +} \ +inline void v_pack_u_store(_Tp* ptr, const v_int##tp2##x##num2& a) \ +{ \ + vint##tp2##m2_t tmp = vundefined_##i##tp2##m2(); \ + tmp = vset_##i##tp2##m2(tmp, 0, a.val); \ + vint##tp2##m2_t val = vmax_vx_i##tp2##m2(tmp, 0, num1);\ + return vse_v_u##tp1##m1(ptr, vnclipu_vx_u##tp1##m1((vuint##tp2##m2_t)val, 0, num1), num2); \ +} \ +template inline \ +v_uint##tp1##x##num1 v_rshr_pack_u(const v_int##tp2##x##num2& a, const v_int##tp2##x##num2& b) \ +{ \ + vint##tp2##m2_t tmp = vundefined_##i##tp2##m2(); \ + tmp = vset_##i##tp2##m2(tmp, 0, a.val); \ + tmp = vset_##i##tp2##m2(tmp, 1, b.val); \ + vint##tp2##m2_t val = vmax_vx_i##tp2##m2(tmp, 0, num1);\ + return v_uint##tp1##x##num1(vnclipu_vx_u##tp1##m1((vuint##tp2##m2_t)val, n, num1)); \ +} \ +template inline \ +void v_rshr_pack_u_store(_Tp* ptr, const v_int##tp2##x##num2& a) \ +{ \ + vint##tp2##m2_t tmp = vundefined_##i##tp2##m2(); \ + tmp = vset_##i##tp2##m2(tmp, 0, a.val); \ + vint##tp2##m2_t val_ = vmax_vx_i##tp2##m2(tmp, 0, num1);\ + vuint##tp1##m1_t val = vnclipu_vx_u##tp1##m1((vuint##tp2##m2_t)val_, n, num1); \ + return vse_v_u##tp1##m1(ptr, val, num2);\ +} +OPENCV_HAL_IMPL_RISCVV_PACK_U(8, 16, 16, 8, unsigned char ) +OPENCV_HAL_IMPL_RISCVV_PACK_U(16, 8, 32, 4, unsigned short) + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuninitialized" +#endif + +// saturating multiply 8-bit, 16-bit +#define OPENCV_HAL_IMPL_RISCVV_MUL_SAT(_Tpvec, _Tpwvec) \ + inline _Tpvec operator * (const _Tpvec& a, const _Tpvec& b) \ + { \ + _Tpwvec c, d; \ + v_mul_expand(a, b, c, d); \ + return v_pack(c, d); \ + } \ + inline _Tpvec& operator *= (_Tpvec& a, const _Tpvec& b) \ + { a = a * b; return a; } + +OPENCV_HAL_IMPL_RISCVV_MUL_SAT(v_int8x16, v_int16x8) +OPENCV_HAL_IMPL_RISCVV_MUL_SAT(v_uint8x16, v_uint16x8) +OPENCV_HAL_IMPL_RISCVV_MUL_SAT(v_int16x8, v_int32x4) +OPENCV_HAL_IMPL_RISCVV_MUL_SAT(v_uint16x8, v_uint32x4) + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif +static const signed char popCountTable[256] = +{ + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, +}; + +inline vuint8m1_t vcnt_u8(vuint8m1_t val){ + vuint8m1_t v0 = val & 1; + return vlxe_v_u8m1((unsigned char*)popCountTable, val >> 1, 16)+v0; +} + +inline v_uint8x16 +v_popcount(const v_uint8x16& a) +{ + return v_uint8x16(vcnt_u8(a.val)); +} + +inline v_uint8x16 +v_popcount(const v_int8x16& a) +{ + return v_uint8x16(vcnt_u8((vuint8m1_t)a.val)); +} + +inline v_uint16x8 +v_popcount(const v_uint16x8& a) +{ + vuint8m2_t tmp = vundefined_u8m2(); + tmp = vset_u8m2(tmp, 0, vcnt_u8((vuint8m1_t)a.val)); + vuint64m2_t mask = (vuint64m2_t){0x0E0C0A0806040200, 0, 0x0F0D0B0907050301, 0}; + tmp = vrgather_vv_u8m2(tmp, (vuint8m2_t)mask, 32); \ + vuint16m2_t res = vwaddu_vv_u16m2(vget_u8m2_u8m1(tmp, 0), vget_u8m2_u8m1(tmp, 1), 8); + return v_uint16x8(vget_u16m2_u16m1(res, 0)); +} + +inline v_uint16x8 +v_popcount(const v_int16x8& a) +{ + vuint8m2_t tmp = vundefined_u8m2(); + tmp = vset_u8m2(tmp, 0, vcnt_u8((vuint8m1_t)a.val)); + vuint64m2_t mask = (vuint64m2_t){0x0E0C0A0806040200, 0, 0x0F0D0B0907050301, 0}; + tmp = vrgather_vv_u8m2(tmp, (vuint8m2_t)mask, 32); \ + vuint16m2_t res = vwaddu_vv_u16m2(vget_u8m2_u8m1(tmp, 0), vget_u8m2_u8m1(tmp, 1), 8); + return v_uint16x8(vget_u16m2_u16m1(res, 0)); +} + +inline v_uint32x4 +v_popcount(const v_uint32x4& a) +{ + vuint8m2_t tmp = vundefined_u8m2(); + tmp = vset_u8m2(tmp, 0, vcnt_u8((vuint8m1_t)a.val)); + vuint64m2_t mask = (vuint64m2_t){0xFFFFFFFF0C080400, 0xFFFFFFFF0D090501, + 0xFFFFFFFF0E0A0602, 0xFFFFFFFF0F0B0703}; + tmp = vrgather_vv_u8m2(tmp, (vuint8m2_t)mask, 32); \ + vuint16m2_t res_ = vwaddu_vv_u16m2(vget_u8m2_u8m1(tmp, 0), vget_u8m2_u8m1(tmp, 1), 16); + vuint32m2_t res = vwaddu_vv_u32m2(vget_u16m2_u16m1(res_, 0), vget_u16m2_u16m1(res_, 1), 8); + return v_uint32x4(vget_u32m2_u32m1(res, 0)); +} + +inline v_uint32x4 +v_popcount(const v_int32x4& a) +{ + vuint8m2_t tmp = vundefined_u8m2(); + tmp = vset_u8m2(tmp, 0, vcnt_u8((vuint8m1_t)a.val)); + vuint64m2_t mask = (vuint64m2_t){0xFFFFFFFF0C080400, 0xFFFFFFFF0D090501, + 0xFFFFFFFF0E0A0602, 0xFFFFFFFF0F0B0703}; + tmp = vrgather_vv_u8m2(tmp, (vuint8m2_t)mask, 32); \ + vuint16m2_t res_ = vwaddu_vv_u16m2(vget_u8m2_u8m1(tmp, 0), vget_u8m2_u8m1(tmp, 1), 16); + vuint32m2_t res = vwaddu_vv_u32m2(vget_u16m2_u16m1(res_, 0), vget_u16m2_u16m1(res_, 1), 8); + return v_uint32x4(vget_u32m2_u32m1(res, 0)); +} + +inline v_uint64x2 +v_popcount(const v_uint64x2& a) +{ + vuint8m2_t tmp = vundefined_u8m2(); + tmp = vset_u8m2(tmp, 0, vcnt_u8((vuint8m1_t)a.val)); + vuint64m2_t mask = (vuint64m2_t){0x0706050403020100, 0x0000000000000000, + 0x0F0E0D0C0B0A0908, 0x0000000000000000}; + tmp = vrgather_vv_u8m2(tmp, (vuint8m2_t)mask, 32); \ + vuint8m1_t zero = vmv_v_x_u8m1(0, 16); + vuint8m1_t res1 = zero; + vuint8m1_t res2 = zero; + res1 = vredsum_vs_u8m1_u8m1(res1, vget_u8m2_u8m1(tmp, 0), zero, 8); + res2 = vredsum_vs_u8m1_u8m1(res2, vget_u8m2_u8m1(tmp, 1), zero, 8); + + return v_uint64x2((unsigned long)vmv_x_s_u8m1_u8(res1, 8), (unsigned long)vmv_x_s_u8m1_u8(res2, 8)); +} + +inline v_uint64x2 +v_popcount(const v_int64x2& a) +{ + vuint8m2_t tmp = vundefined_u8m2(); + tmp = vset_u8m2(tmp, 0, vcnt_u8((vuint8m1_t)a.val)); + vuint64m2_t mask = (vuint64m2_t){0x0706050403020100, 0x0000000000000000, + 0x0F0E0D0C0B0A0908, 0x0000000000000000}; + tmp = vrgather_vv_u8m2(tmp, (vuint8m2_t)mask, 32); \ + vuint8m1_t zero = vmv_v_x_u8m1(0, 16); + vuint8m1_t res1 = zero; + vuint8m1_t res2 = zero; + res1 = vredsum_vs_u8m1_u8m1(res1, vget_u8m2_u8m1(tmp, 0), zero, 8); + res2 = vredsum_vs_u8m1_u8m1(res2, vget_u8m2_u8m1(tmp, 1), zero, 8); + + return v_uint64x2((unsigned long)vmv_x_s_u8m1_u8(res1, 8), (unsigned long)vmv_x_s_u8m1_u8(res2, 8)); +} + +#define SMASK 1, 2, 4, 8, 16, 32, 64, 128 +inline int v_signmask(const v_uint8x16& a) +{ + vuint8m1_t t0 = vsrl_vx_u8m1(a.val, 7, 16); + vuint8m1_t m1 = (vuint8m1_t){SMASK, SMASK}; + vuint16m2_t t1 = vwmulu_vv_u16m2(t0, m1, 16); + vuint32m1_t res = vmv_v_x_u32m1(0, 4); + vuint32m2_t t2 = vwmulu_vx_u32m2(vget_u16m2_u16m1(t1, 1), 256, 8); + res = vredsum_vs_u32m2_u32m1(res, t2, res, 8); + res = vwredsumu_vs_u16m1_u32m1(res, vget_u16m2_u16m1(t1, 0), res, 8); + return vmv_x_s_u32m1_u32(res, 8); +} +inline int v_signmask(const v_int8x16& a) +{ + vuint8m1_t t0 = vsrl_vx_u8m1((vuint8m1_t)a.val, 7, 16); + vuint8m1_t m1 = (vuint8m1_t){SMASK, SMASK}; + vint16m2_t t1 = (vint16m2_t)vwmulu_vv_u16m2(t0, m1, 16); + vint32m1_t res = vmv_v_x_i32m1(0, 4); + vint32m2_t t2 = vwmul_vx_i32m2(vget_i16m2_i16m1(t1, 1), 256, 8); + res = vredsum_vs_i32m2_i32m1(res, t2, res, 8); + res = vwredsum_vs_i16m1_i32m1(res, vget_i16m2_i16m1(t1, 0), res, 8); + return vmv_x_s_i32m1_i32(res, 8); +} + +inline int v_signmask(const v_int16x8& a) +{ + vint16m1_t t0 = (vint16m1_t)vsrl_vx_u16m1((vuint16m1_t)a.val, 15, 8); + vint16m1_t m1 = (vint16m1_t){SMASK}; + vint16m1_t t1 = vmul_vv_i16m1(t0, m1, 8); + vint16m1_t res = vmv_v_x_i16m1(0, 8); + res = vredsum_vs_i16m1_i16m1(res, t1, res, 8); + return vmv_x_s_i16m1_i16(res, 8); +} +inline int v_signmask(const v_uint16x8& a) +{ + vint16m1_t t0 = (vint16m1_t)vsrl_vx_u16m1((vuint16m1_t)a.val, 15, 8); + vint16m1_t m1 = (vint16m1_t){SMASK}; + vint16m1_t t1 = vmul_vv_i16m1(t0, m1, 8); + vint16m1_t res = vmv_v_x_i16m1(0, 8); + res = vredsum_vs_i16m1_i16m1(res, t1, res, 8); + return vmv_x_s_i16m1_i16(res, 8); +} +inline int v_signmask(const v_int32x4& a) +{ + vint32m1_t t0 = (vint32m1_t)vsrl_vx_u32m1((vuint32m1_t)a.val, 31, 4); + vint32m1_t m1 = (vint32m1_t){1, 2, 4, 8}; + vint32m1_t res = vmv_v_x_i32m1(0, 4); + vint32m1_t t1 = vmul_vv_i32m1(t0, m1, 4); + res = vredsum_vs_i32m1_i32m1(res, t1, res, 4); + return vmv_x_s_i32m1_i32(res, 4); +} +inline int v_signmask(const v_uint32x4& a) +{ + vint32m1_t t0 = (vint32m1_t)vsrl_vx_u32m1(a.val, 31, 4); + vint32m1_t m1 = (vint32m1_t){1, 2, 4, 8}; + vint32m1_t res = vmv_v_x_i32m1(0, 4); + vint32m1_t t1 = vmul_vv_i32m1(t0, m1, 4); + res = vredsum_vs_i32m1_i32m1(res, t1, res, 4); + return vmv_x_s_i32m1_i32(res, 4); +} +inline int v_signmask(const v_uint64x2& a) +{ + vuint64m1_t v0 = vsrl_vx_u64m1(a.val, 63, 2); + int res = (int)vext_x_v_u64m1_u64(v0, 0, 2) + ((int)vext_x_v_u64m1_u64(v0, 1, 2) << 1); + return res; +} +inline int v_signmask(const v_int64x2& a) +{ return v_signmask(v_reinterpret_as_u64(a)); } +inline int v_signmask(const v_float64x2& a) +{ return v_signmask(v_reinterpret_as_u64(a)); } +inline int v_signmask(const v_float32x4& a) +{ + vint32m1_t t0 = (vint32m1_t)vsrl_vx_u32m1((vuint32m1_t)a.val, 31, 4); + vint32m1_t m1 = (vint32m1_t){1, 2, 4, 8}; + vint32m1_t res = vmv_v_x_i32m1(0, 4); + vint32m1_t t1 = vmul_vv_i32m1(t0, m1, 4); + res = vredsum_vs_i32m1_i32m1(res, t1, res, 4); + return vmv_x_s_i32m1_i32(res, 4); +} + +inline int v_scan_forward(const v_int8x16& a) { +int val = v_signmask(a); +if(val==0) return 0; +else return trailingZeros32(val); } +inline int v_scan_forward(const v_uint8x16& a) { +int val = v_signmask(a); +if(val==0) return 0; +else return trailingZeros32(val); } +inline int v_scan_forward(const v_int16x8& a) { +int val = v_signmask(a); +if(val==0) return 0; +else return trailingZeros32(val); } +inline int v_scan_forward(const v_uint16x8& a) { +int val = v_signmask(a); +if(val==0) return 0; +else return trailingZeros32(val); } +inline int v_scan_forward(const v_int32x4& a) { +int val = v_signmask(a); +if(val==0) return 0; +else return trailingZeros32(val); } +inline int v_scan_forward(const v_uint32x4& a) { +int val = v_signmask(a); +if(val==0) return 0; +else return trailingZeros32(val); } +inline int v_scan_forward(const v_float32x4& a) { +int val = v_signmask(a); +if(val==0) return 0; +else return trailingZeros32(val); } +inline int v_scan_forward(const v_int64x2& a) { +int val = v_signmask(a); +if(val==0) return 0; +else return trailingZeros32(val); } +inline int v_scan_forward(const v_uint64x2& a) { +int val = v_signmask(a); +if(val==0) return 0; +else return trailingZeros32(val); } + +#define OPENCV_HAL_IMPL_RISCVV_CHECK_ALLANY(_Tpvec, suffix, _T, shift, num) \ +inline bool v_check_all(const v_##_Tpvec& a) \ +{ \ + suffix##m1_t v0 = vsrl_vx_##_T(vnot_v_##_T(a.val, num), shift, num); \ + vuint64m1_t v1 = vuint64m1_t(v0); \ + return (v1[0] | v1[1]) == 0; \ +} \ +inline bool v_check_any(const v_##_Tpvec& a) \ +{ \ + suffix##m1_t v0 = vsrl_vx_##_T(a.val, shift, num); \ + vuint64m1_t v1 = vuint64m1_t(v0); \ + return (v1[0] | v1[1]) != 0; \ +} + +OPENCV_HAL_IMPL_RISCVV_CHECK_ALLANY(uint8x16, vuint8, u8m1, 7, 16) +OPENCV_HAL_IMPL_RISCVV_CHECK_ALLANY(uint16x8, vuint16, u16m1, 15, 8) +OPENCV_HAL_IMPL_RISCVV_CHECK_ALLANY(uint32x4, vuint32, u32m1, 31, 4) +OPENCV_HAL_IMPL_RISCVV_CHECK_ALLANY(uint64x2, vuint64, u64m1, 63, 2) + +inline bool v_check_all(const v_int8x16& a) +{ return v_check_all(v_reinterpret_as_u8(a)); } +inline bool v_check_all(const v_int16x8& a) +{ return v_check_all(v_reinterpret_as_u16(a)); } +inline bool v_check_all(const v_int32x4& a) +{ return v_check_all(v_reinterpret_as_u32(a)); } +inline bool v_check_all(const v_float32x4& a) +{ return v_check_all(v_reinterpret_as_u32(a)); } +inline bool v_check_all(const v_int64x2& a) +{ return v_check_all(v_reinterpret_as_u64(a)); } +inline bool v_check_all(const v_float64x2& a) +{ return v_check_all(v_reinterpret_as_u64(a)); } + +inline bool v_check_any(const v_int8x16& a) +{ return v_check_any(v_reinterpret_as_u8(a)); } +inline bool v_check_any(const v_int16x8& a) +{ return v_check_any(v_reinterpret_as_u16(a)); } +inline bool v_check_any(const v_int32x4& a) +{ return v_check_any(v_reinterpret_as_u32(a)); } +inline bool v_check_any(const v_float32x4& a) +{ return v_check_any(v_reinterpret_as_u32(a)); } +inline bool v_check_any(const v_int64x2& a) +{ return v_check_any(v_reinterpret_as_u64(a)); } +inline bool v_check_any(const v_float64x2& a) +{ return v_check_any(v_reinterpret_as_u64(a)); } + +#define OPENCV_HAL_IMPL_RISCVV_SELECT(_Tpvec, suffix, _Tpvec2, num) \ +inline _Tpvec v_select(const _Tpvec& mask, const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(vmerge_vvm_##suffix(_Tpvec2(mask.val), b.val, a.val, num)); \ +} + +OPENCV_HAL_IMPL_RISCVV_SELECT(v_int8x16, i8m1, vbool8_t, 16) +OPENCV_HAL_IMPL_RISCVV_SELECT(v_int16x8, i16m1, vbool16_t, 8) +OPENCV_HAL_IMPL_RISCVV_SELECT(v_int32x4, i32m1, vbool32_t, 4) +OPENCV_HAL_IMPL_RISCVV_SELECT(v_uint8x16, u8m1, vbool8_t, 16) +OPENCV_HAL_IMPL_RISCVV_SELECT(v_uint16x8, u16m1, vbool16_t, 8) +OPENCV_HAL_IMPL_RISCVV_SELECT(v_uint32x4, u32m1, vbool32_t, 4) +inline v_float32x4 v_select(const v_float32x4& mask, const v_float32x4& a, const v_float32x4& b) +{ + return v_float32x4((vfloat32m1_t)vmerge_vvm_u32m1((vbool32_t)mask.val, (vuint32m1_t)b.val, (vuint32m1_t)a.val, 4)); +} +inline v_float64x2 v_select(const v_float64x2& mask, const v_float64x2& a, const v_float64x2& b) +{ + return v_float64x2((vfloat64m1_t)vmerge_vvm_u64m1((vbool64_t)mask.val, (vuint64m1_t)b.val, (vuint64m1_t)a.val, 2)); +} + +#define OPENCV_HAL_IMPL_RISCVV_EXPAND(add, _Tpvec, _Tpwvec, _Tp, _Tp1, num1, _Tp2, num2, _T1, _T2) \ +inline void v_expand(const _Tpvec& a, v_##_Tpwvec& b0, v_##_Tpwvec& b1) \ +{ \ + _T1##_t b = vw##add##_vv_##_Tp2##m2(a.val, vmv_v_x_##_Tp1(0, num1), num1); \ + b0.val = vget_##_Tp2##m2_##_Tp2##m1(b, 0); \ + b1.val = vget_##_Tp2##m2_##_Tp2##m1(b, 1); \ +} \ +inline v_##_Tpwvec v_expand_low(const _Tpvec& a) \ +{ \ + _T1##_t b = vw##add##_vv_##_Tp2##m2(a.val, vmv_v_x_##_Tp1(0, num2), num2); \ + return v_##_Tpwvec(vget_##_Tp2##m2_##_Tp2##m1(b, 0)); \ +} \ +inline v_##_Tpwvec v_expand_high(const _Tpvec& a) \ +{ \ + _T1##_t b = vw##add##_vv_##_Tp2##m2(a.val, vmv_v_x_##_Tp1(0, num1), num1); \ + return v_##_Tpwvec(vget_##_Tp2##m2_##_Tp2##m1(b, 1)); \ +} \ +inline v_##_Tpwvec v_load_expand(const _Tp* ptr) \ +{ \ + _T2##_t val = vle##_v_##_Tp1(ptr, num2); \ + _T1##_t b = vw##add##_vv_##_Tp2##m2(val, vmv_v_x_##_Tp1(0, num2), num2); \ + return v_##_Tpwvec(vget_##_Tp2##m2_##_Tp2##m1(b, 0)); \ +} + +OPENCV_HAL_IMPL_RISCVV_EXPAND(addu, v_uint8x16, uint16x8, uchar, u8m1, 16, u16, 8, vuint16m2, vuint8m1) +OPENCV_HAL_IMPL_RISCVV_EXPAND(addu, v_uint16x8, uint32x4, ushort, u16m1, 8, u32, 4, vuint32m2, vuint16m1) +OPENCV_HAL_IMPL_RISCVV_EXPAND(addu, v_uint32x4, uint64x2, uint, u32m1, 4, u64, 2, vuint64m2, vuint32m1) +OPENCV_HAL_IMPL_RISCVV_EXPAND(add, v_int8x16, int16x8, schar, i8m1, 16, i16, 8, vint16m2, vint8m1) +OPENCV_HAL_IMPL_RISCVV_EXPAND(add, v_int16x8, int32x4, short, i16m1, 8, i32, 4, vint32m2, vint16m1) +OPENCV_HAL_IMPL_RISCVV_EXPAND(add, v_int32x4, int64x2, int, i32m1, 4, i64, 2, vint64m2, vint32m1) + +inline v_uint32x4 v_load_expand_q(const uchar* ptr) +{ + vuint16m2_t b = vundefined_u16m2(); + vuint32m2_t c = vundefined_u32m2(); + vuint8m1_t val = vle_v_u8m1(ptr, 4); \ + b = vwaddu_vv_u16m2(val, vmv_v_x_u8m1(0, 4), 4); \ + c = vwaddu_vv_u32m2(vget_u16m2_u16m1(b, 0), vmv_v_x_u16m1(0, 4), 4); \ + return v_uint32x4(vget_u32m2_u32m1(c, 0)); +} + +inline v_int32x4 v_load_expand_q(const schar* ptr) +{ + vint16m2_t b = vundefined_i16m2(); + vint32m2_t c = vundefined_i32m2(); + vint8m1_t val = vle_v_i8m1(ptr, 4); \ + b = vwadd_vv_i16m2(val, vmv_v_x_i8m1(0, 4), 4); \ + c = vwadd_vv_i32m2(vget_i16m2_i16m1(b, 0), vmv_v_x_i16m1(0, 4), 4); \ + return v_int32x4(vget_i32m2_i32m1(c, 0)); +} +#define VITL_16 (vuint64m2_t){0x1303120211011000, 0x1707160615051404, 0x1B0B1A0A19091808, 0x1F0F1E0E1D0D1C0C} +#define VITL_8 (vuint64m2_t){0x0009000100080000, 0x000B0003000A0002, 0x000D0005000C0004, 0x000F0007000E0006} +#define VITL_4 (vuint64m2_t){0x0000000400000000, 0x0000000500000001, 0x0000000600000002, 0x0000000700000003} +#define VITL_2 (vuint64m2_t){0, 2, 1, 3} +#define LOW_4 0x0000000100000000, 0x0000000500000004 +#define LOW_8 0x0003000200010000, 0x000B000A00090008 +#define LOW_16 0x0706050403020100, 0x1716151413121110 +#define HIGH_4 0x0000000300000002, 0x0000000700000006 +#define HIGH_8 0x0007000600050004, 0x000F000E000D000C +#define HIGH_16 0x0F0E0D0C0B0A0908, 0x1F1E1D1C1B1A1918 +#define OPENCV_HAL_IMPL_RISCVV_UNPACKS(_Tpvec, _Tp, _T, _UTp, _UT, num, num2, len, numh) \ +inline void v_zip(const v_##_Tpvec& a0, const v_##_Tpvec& a1, v_##_Tpvec& b0, v_##_Tpvec& b1) \ +{ \ + v##_Tp##m2_t tmp = vundefined_##_T##m2();\ + tmp = vset_##_T##m2(tmp, 0, a0.val); \ + tmp = vset_##_T##m2(tmp, 1, a1.val); \ + vuint64m2_t mask = VITL_##num; \ + tmp = (v##_Tp##m2_t)vrgather_vv_##_T##m2((v##_Tp##m2_t)tmp, (v##_UTp##m2_t)mask, num2); \ + b0.val = vget_##_T##m2_##_T##m1(tmp, 0); \ + b1.val = vget_##_T##m2_##_T##m1(tmp, 1); \ +} \ +inline v_##_Tpvec v_combine_low(const v_##_Tpvec& a, const v_##_Tpvec& b) \ +{ \ + v##_Tp##m1_t b0 = vslideup_vx_##_T##m1_m(vmset_m_##len(num), a.val, b.val, numh, num); \ + return v_##_Tpvec(b0);\ +} \ +inline v_##_Tpvec v_combine_high(const v_##_Tpvec& a, const v_##_Tpvec& b) \ +{ \ + v##_Tp##m1_t b0 = vslidedown_vx_##_T##m1(b.val, numh, num); \ + v##_Tp##m1_t a0 = vslidedown_vx_##_T##m1(a.val, numh, num); \ + v##_Tp##m1_t b1 = vslideup_vx_##_T##m1_m(vmset_m_##len(num), a0, b0, numh, num); \ + return v_##_Tpvec(b1);\ +} \ +inline void v_recombine(const v_##_Tpvec& a, const v_##_Tpvec& b, v_##_Tpvec& c, v_##_Tpvec& d) \ +{ \ + c.val = vslideup_vx_##_T##m1_m(vmset_m_##len(num), a.val, b.val, numh, num); \ + v##_Tp##m1_t b0 = vslidedown_vx_##_T##m1(b.val, numh, num); \ + v##_Tp##m1_t a0 = vslidedown_vx_##_T##m1(a.val, numh, num); \ + d.val = vslideup_vx_##_T##m1_m(vmset_m_##len(num), a0, b0, numh, num); \ +} + +OPENCV_HAL_IMPL_RISCVV_UNPACKS(uint8x16, uint8, u8, uint8, u8, 16, 32, b8, 8) +OPENCV_HAL_IMPL_RISCVV_UNPACKS(int8x16, int8, i8, uint8, u8, 16, 32, b8, 8) +OPENCV_HAL_IMPL_RISCVV_UNPACKS(uint16x8, uint16, u16, uint16, u16, 8, 16, b16, 4) +OPENCV_HAL_IMPL_RISCVV_UNPACKS(int16x8, int16, i16, uint16, u16, 8, 16, b16, 4) +OPENCV_HAL_IMPL_RISCVV_UNPACKS(uint32x4, uint32, u32, uint32, u32, 4, 8, b32, 2) +OPENCV_HAL_IMPL_RISCVV_UNPACKS(int32x4, int32, i32, uint32, u32, 4, 8, b32, 2) +OPENCV_HAL_IMPL_RISCVV_UNPACKS(float32x4, float32, f32, uint32, u32, 4, 8, b32, 2) +OPENCV_HAL_IMPL_RISCVV_UNPACKS(float64x2, float64, f64, uint64, u64, 2, 4, b64, 1) + +inline v_uint8x16 v_reverse(const v_uint8x16 &a) +{ + vuint64m1_t mask = (vuint64m1_t){0x08090A0B0C0D0E0F, 0x0001020304050607}; + return v_uint8x16(vrgather_vv_u8m1(a.val, (vuint8m1_t)mask, 16)); +} +inline v_int8x16 v_reverse(const v_int8x16 &a) +{ + vint64m1_t mask = (vint64m1_t){0x08090A0B0C0D0E0F, 0x0001020304050607}; + return v_int8x16(vrgather_vv_i8m1(a.val, (vuint8m1_t)mask, 16)); +} + +inline v_uint16x8 v_reverse(const v_uint16x8 &a) +{ + vuint64m1_t mask = (vuint64m1_t){0x0004000500060007, 0x000000100020003}; + return v_uint16x8(vrgather_vv_u16m1(a.val, (vuint16m1_t)mask, 8)); +} + +inline v_int16x8 v_reverse(const v_int16x8 &a) +{ + vint64m1_t mask = (vint64m1_t){0x0004000500060007, 0x000000100020003}; + return v_int16x8(vrgather_vv_i16m1(a.val, (vuint16m1_t)mask, 8)); +} +inline v_uint32x4 v_reverse(const v_uint32x4 &a) +{ + return v_uint32x4(vrgather_vv_u32m1(a.val, (vuint32m1_t){3, 2, 1, 0}, 4)); +} + +inline v_int32x4 v_reverse(const v_int32x4 &a) +{ + return v_int32x4(vrgather_vv_i32m1(a.val, (vuint32m1_t){3, 2, 1, 0}, 4)); +} + +inline v_float32x4 v_reverse(const v_float32x4 &a) +{ return v_reinterpret_as_f32(v_reverse(v_reinterpret_as_u32(a))); } + +inline v_uint64x2 v_reverse(const v_uint64x2 &a) +{ + return v_uint64x2(a.val[1], a.val[0]); +} + +inline v_int64x2 v_reverse(const v_int64x2 &a) +{ + return v_int64x2(a.val[1], a.val[0]); +} + +inline v_float64x2 v_reverse(const v_float64x2 &a) +{ + return v_float64x2(a.val[1], a.val[0]); +} + +#define OPENCV_HAL_IMPL_RISCVV_EXTRACT(_Tpvec, suffix, size) \ +template \ +inline _Tpvec v_extract(const _Tpvec& a, const _Tpvec& b) \ +{ return v_rotate_right(a, b);} +OPENCV_HAL_IMPL_RISCVV_EXTRACT(v_uint8x16, u8, 0) +OPENCV_HAL_IMPL_RISCVV_EXTRACT(v_int8x16, s8, 0) +OPENCV_HAL_IMPL_RISCVV_EXTRACT(v_uint16x8, u16, 1) +OPENCV_HAL_IMPL_RISCVV_EXTRACT(v_int16x8, s16, 1) +OPENCV_HAL_IMPL_RISCVV_EXTRACT(v_uint32x4, u32, 2) +OPENCV_HAL_IMPL_RISCVV_EXTRACT(v_int32x4, s32, 2) +OPENCV_HAL_IMPL_RISCVV_EXTRACT(v_uint64x2, u64, 3) +OPENCV_HAL_IMPL_RISCVV_EXTRACT(v_int64x2, s64, 3) +OPENCV_HAL_IMPL_RISCVV_EXTRACT(v_float32x4, f32, 2) +OPENCV_HAL_IMPL_RISCVV_EXTRACT(v_float64x2, f64, 3) + + +#define OPENCV_HAL_IMPL_RISCVV_EXTRACT_N(_Tpvec, _Tp, suffix) \ +template inline _Tp v_extract_n(_Tpvec v) { return v.val[i]; } + +OPENCV_HAL_IMPL_RISCVV_EXTRACT_N(v_uint8x16, uchar, u8) +OPENCV_HAL_IMPL_RISCVV_EXTRACT_N(v_int8x16, schar, s8) +OPENCV_HAL_IMPL_RISCVV_EXTRACT_N(v_uint16x8, ushort, u16) +OPENCV_HAL_IMPL_RISCVV_EXTRACT_N(v_int16x8, short, s16) +OPENCV_HAL_IMPL_RISCVV_EXTRACT_N(v_uint32x4, uint, u32) +OPENCV_HAL_IMPL_RISCVV_EXTRACT_N(v_int32x4, int, s32) +OPENCV_HAL_IMPL_RISCVV_EXTRACT_N(v_uint64x2, uint64, u64) +OPENCV_HAL_IMPL_RISCVV_EXTRACT_N(v_int64x2, int64, s64) +OPENCV_HAL_IMPL_RISCVV_EXTRACT_N(v_float32x4, float, f32) +OPENCV_HAL_IMPL_RISCVV_EXTRACT_N(v_float64x2, double, f64) + +#define OPENCV_HAL_IMPL_RISCVV_BROADCAST(_Tpvec, _Tp, num) \ +template inline _Tpvec v_broadcast_element(_Tpvec v) { return _Tpvec(vrgather_vx_##_Tp##m1(v.val, i, num)); } + +OPENCV_HAL_IMPL_RISCVV_BROADCAST(v_uint8x16, u8, 16) +OPENCV_HAL_IMPL_RISCVV_BROADCAST(v_int8x16, i8, 16) +OPENCV_HAL_IMPL_RISCVV_BROADCAST(v_uint16x8, u16, 8) +OPENCV_HAL_IMPL_RISCVV_BROADCAST(v_int16x8, i16, 8) +OPENCV_HAL_IMPL_RISCVV_BROADCAST(v_uint32x4, u32, 4) +OPENCV_HAL_IMPL_RISCVV_BROADCAST(v_int32x4, i32, 4) +OPENCV_HAL_IMPL_RISCVV_BROADCAST(v_uint64x2, u64, 2) +OPENCV_HAL_IMPL_RISCVV_BROADCAST(v_int64x2, i64, 2) +OPENCV_HAL_IMPL_RISCVV_BROADCAST(v_float32x4, f32, 4) +inline v_int32x4 v_round(const v_float32x4& a) +{ + __builtin_riscv_fsrm(0); + vint32m1_t nan = vand_vx_i32m1((vint32m1_t)a.val, 0x7f800000, 4); + vbool32_t mask = vmsne_vx_i32m1_b32(nan, 0x7f800000, 4); + vint32m1_t val = vfcvt_x_f_v_i32m1_m(mask, vmv_v_x_i32m1(0, 4), a.val, 4); + __builtin_riscv_fsrm(0); + return v_int32x4(val); +} +inline v_int32x4 v_floor(const v_float32x4& a) +{ + __builtin_riscv_fsrm(2); + vint32m1_t nan = vand_vx_i32m1((vint32m1_t)a.val, 0x7f800000, 4); + vbool32_t mask = vmsne_vx_i32m1_b32(nan, 0x7f800000, 4); + vint32m1_t val = vfcvt_x_f_v_i32m1_m(mask, vmv_v_x_i32m1(0, 4), a.val, 4); + __builtin_riscv_fsrm(0); + return v_int32x4(val); +} + +inline v_int32x4 v_ceil(const v_float32x4& a) +{ + __builtin_riscv_fsrm(3); + vint32m1_t nan = vand_vx_i32m1((vint32m1_t)a.val, 0x7f800000, 4); + vbool32_t mask = vmsne_vx_i32m1_b32(nan, 0x7f800000, 4); + vint32m1_t val = vfcvt_x_f_v_i32m1_m(mask, vmv_v_x_i32m1(0, 4), a.val, 4); + __builtin_riscv_fsrm(0); + return v_int32x4(val); +} + +inline v_int32x4 v_trunc(const v_float32x4& a) +{ + __builtin_riscv_fsrm(1); + vint32m1_t nan = vand_vx_i32m1((vint32m1_t)a.val, 0x7f800000, 4); + vbool32_t mask = vmsne_vx_i32m1_b32(nan, 0x7f800000, 4); + vint32m1_t val = vfcvt_x_f_v_i32m1_m(mask, vmv_v_x_i32m1(0, 4), a.val, 4); + __builtin_riscv_fsrm(0); + return v_int32x4(val); +} + +inline v_int32x4 v_round(const v_float64x2& a) +{ + __builtin_riscv_fsrm(0); + vfloat64m2_t _val = vundefined_f64m2(); + _val = vset_f64m2(_val, 0, a.val); + //_val = vset_f64m2(_val, 1, a.val); + _val = vset_f64m2(_val, 1, vfmv_v_f_f64m1(0, 2)); + vint32m1_t val = vfncvt_x_f_v_i32m1(_val, 4); + __builtin_riscv_fsrm(0); + return v_int32x4(val); +} +inline v_int32x4 v_round(const v_float64x2& a, const v_float64x2& b) +{ + __builtin_riscv_fsrm(0); + vfloat64m2_t _val = vundefined_f64m2(); + _val = vset_f64m2(_val, 0, a.val); + _val = vset_f64m2(_val, 1, b.val); + vint32m1_t val = vfncvt_x_f_v_i32m1(_val, 4); + __builtin_riscv_fsrm(0); + return v_int32x4(val); +} +inline v_int32x4 v_floor(const v_float64x2& a) +{ + __builtin_riscv_fsrm(2); + vfloat64m2_t _val = vundefined_f64m2(); + _val = vset_f64m2(_val, 0, a.val); + vfloat32m1_t aval = vfncvt_f_f_v_f32m1(_val, 2); + + vint32m1_t nan = vand_vx_i32m1((vint32m1_t)aval, 0x7f800000, 4); + vbool32_t mask = vmsne_vx_i32m1_b32(nan, 0x7f800000, 4); + vint32m1_t val = vfcvt_x_f_v_i32m1_m(mask, vmv_v_x_i32m1(0, 4), aval, 4); + __builtin_riscv_fsrm(0); + return v_int32x4(val); +} + +inline v_int32x4 v_ceil(const v_float64x2& a) +{ + __builtin_riscv_fsrm(3); + vfloat64m2_t _val = vundefined_f64m2(); + _val = vset_f64m2(_val, 0, a.val); + vfloat32m1_t aval = vfncvt_f_f_v_f32m1(_val, 2); + + vint32m1_t nan = vand_vx_i32m1((vint32m1_t)aval, 0x7f800000, 4); + vbool32_t mask = vmsne_vx_i32m1_b32(nan, 0x7f800000, 4); + vint32m1_t val = vfcvt_x_f_v_i32m1_m(mask, vmv_v_x_i32m1(0, 4), aval, 4); + __builtin_riscv_fsrm(0); + return v_int32x4(val); +} + +inline v_int32x4 v_trunc(const v_float64x2& a) +{ + __builtin_riscv_fsrm(1); + vfloat64m2_t _val = vundefined_f64m2(); + _val = vset_f64m2(_val, 0, a.val); + vfloat32m1_t aval = vfncvt_f_f_v_f32m1(_val, 2); + + vint32m1_t nan = vand_vx_i32m1((vint32m1_t)aval, 0x7f800000, 4); + vbool32_t mask = vmsne_vx_i32m1_b32(nan, 0x7f800000, 4); + vint32m1_t val = vfcvt_x_f_v_i32m1_m(mask, vmv_v_x_i32m1(0, 4), aval, 4); + __builtin_riscv_fsrm(0); + return v_int32x4(val); +} + +#define OPENCV_HAL_IMPL_RISCVV_LOAD_DEINTERLEAVED(intrin, _Tpvec, num, _Tp, _T) \ +inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec##x##num& a, v_##_Tpvec##x##num& b) \ +{ \ + v##_Tpvec##m1x2_t ret = intrin##2e_v_##_T##m1x2(ptr, num);\ + a.val = vget_##_T##m1x2_##_T##m1(ret, 0); \ + b.val = vget_##_T##m1x2_##_T##m1(ret, 1); \ +} \ +inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec##x##num& a, v_##_Tpvec##x##num& b, v_##_Tpvec##x##num& c) \ +{ \ + v##_Tpvec##m1x3_t ret = intrin##3e_v_##_T##m1x3(ptr, num);\ + a.val = vget_##_T##m1x3_##_T##m1(ret, 0); \ + b.val = vget_##_T##m1x3_##_T##m1(ret, 1); \ + c.val = vget_##_T##m1x3_##_T##m1(ret, 2); \ +}\ +inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec##x##num& a, v_##_Tpvec##x##num& b, \ + v_##_Tpvec##x##num& c, v_##_Tpvec##x##num& d) \ +{ \ + v##_Tpvec##m1x4_t ret = intrin##4e_v_##_T##m1x4(ptr, num);\ + a.val = vget_##_T##m1x4_##_T##m1(ret, 0); \ + b.val = vget_##_T##m1x4_##_T##m1(ret, 1); \ + c.val = vget_##_T##m1x4_##_T##m1(ret, 2); \ + d.val = vget_##_T##m1x4_##_T##m1(ret, 3); \ +} \ + +#define OPENCV_HAL_IMPL_RISCVV_STORE_INTERLEAVED(intrin, _Tpvec, num, _Tp, _T) \ +inline void v_store_interleave( _Tp* ptr, const v_##_Tpvec##x##num& a, const v_##_Tpvec##x##num& b, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ \ + v##_Tpvec##m1x2_t ret = vundefined_##_T##m1x2(); \ + ret = vset_##_T##m1x2(ret, 0, a.val); \ + ret = vset_##_T##m1x2(ret, 1, b.val); \ + intrin##2e_v_##_T##m1x2(ptr, ret, num); \ +} \ +inline void v_store_interleave( _Tp* ptr, const v_##_Tpvec##x##num& a, const v_##_Tpvec##x##num& b, \ + const v_##_Tpvec##x##num& c, hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ \ + v##_Tpvec##m1x3_t ret = vundefined_##_T##m1x3(); \ + ret = vset_##_T##m1x3(ret, 0, a.val); \ + ret = vset_##_T##m1x3(ret, 1, b.val); \ + ret = vset_##_T##m1x3(ret, 2, c.val); \ + intrin##3e_v_##_T##m1x3(ptr, ret, num); \ +} \ +inline void v_store_interleave( _Tp* ptr, const v_##_Tpvec##x##num& a, const v_##_Tpvec##x##num& b, \ + const v_##_Tpvec##x##num& c, const v_##_Tpvec##x##num& d, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED ) \ +{ \ + v##_Tpvec##m1x4_t ret = vundefined_##_T##m1x4(); \ + ret = vset_##_T##m1x4(ret, 0, a.val); \ + ret = vset_##_T##m1x4(ret, 1, b.val); \ + ret = vset_##_T##m1x4(ret, 2, c.val); \ + ret = vset_##_T##m1x4(ret, 3, d.val); \ + intrin##4e_v_##_T##m1x4(ptr, ret, num); \ +} + +#define OPENCV_HAL_IMPL_RISCVV_INTERLEAVED(_Tpvec, _Tp, num, ld, st, _T) \ +OPENCV_HAL_IMPL_RISCVV_LOAD_DEINTERLEAVED(ld, _Tpvec, num, _Tp, _T) \ +OPENCV_HAL_IMPL_RISCVV_STORE_INTERLEAVED(st, _Tpvec, num, _Tp, _T) + +//OPENCV_HAL_IMPL_RISCVV_INTERLEAVED(uint8, uchar, ) +OPENCV_HAL_IMPL_RISCVV_INTERLEAVED(int8, schar, 16, vlseg, vsseg, i8) +OPENCV_HAL_IMPL_RISCVV_INTERLEAVED(int16, short, 8, vlseg, vsseg, i16) +OPENCV_HAL_IMPL_RISCVV_INTERLEAVED(int32, int, 4, vlseg, vsseg, i32) + +OPENCV_HAL_IMPL_RISCVV_INTERLEAVED(uint8, unsigned char, 16, vlseg, vsseg, u8) +OPENCV_HAL_IMPL_RISCVV_INTERLEAVED(uint16, unsigned short, 8, vlseg, vsseg, u16) +OPENCV_HAL_IMPL_RISCVV_INTERLEAVED(uint32, unsigned int, 4, vlseg, vsseg, u32) + +#define OPENCV_HAL_IMPL_RISCVV_INTERLEAVED_(_Tpvec, _Tp, num, _T) \ +inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec##x##num& a, v_##_Tpvec##x##num& b) \ +{ \ + v##_Tpvec##m1x2_t ret = vlseg2e_v_##_T##m1x2(ptr, num); \ + a.val = vget_##_T##m1x2_##_T##m1(ret, 0); \ + b.val = vget_##_T##m1x2_##_T##m1(ret, 1); \ +} \ +inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec##x##num& a, v_##_Tpvec##x##num& b, v_##_Tpvec##x##num& c) \ +{ \ + v##_Tpvec##m1x3_t ret = vlseg3e_v_##_T##m1x3(ptr, num); \ + a.val = vget_##_T##m1x3_##_T##m1(ret, 0); \ + b.val = vget_##_T##m1x3_##_T##m1(ret, 1); \ + c.val = vget_##_T##m1x3_##_T##m1(ret, 2); \ +}\ +inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec##x##num& a, v_##_Tpvec##x##num& b, \ + v_##_Tpvec##x##num& c, v_##_Tpvec##x##num& d) \ +{ \ + v##_Tpvec##m1x4_t ret = vlseg4e_v_##_T##m1x4(ptr, num); \ + a.val = vget_##_T##m1x4_##_T##m1(ret, 0); \ + b.val = vget_##_T##m1x4_##_T##m1(ret, 1); \ + c.val = vget_##_T##m1x4_##_T##m1(ret, 2); \ + d.val = vget_##_T##m1x4_##_T##m1(ret, 3); \ +} \ +inline void v_store_interleave( _Tp* ptr, const v_##_Tpvec##x##num& a, const v_##_Tpvec##x##num& b, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ \ + v##_Tpvec##m1x2_t ret = vundefined_##_T##m1x2(); \ + ret = vset_##_T##m1x2(ret, 0, a.val); \ + ret = vset_##_T##m1x2(ret, 1, b.val); \ + vsseg2e_v_##_T##m1x2(ptr, ret, num); \ +} \ +inline void v_store_interleave( _Tp* ptr, const v_##_Tpvec##x##num& a, const v_##_Tpvec##x##num& b, \ + const v_##_Tpvec##x##num& c, hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ \ + v##_Tpvec##m1x3_t ret = vundefined_##_T##m1x3(); \ + ret = vset_##_T##m1x3(ret, 0, a.val); \ + ret = vset_##_T##m1x3(ret, 1, b.val); \ + ret = vset_##_T##m1x3(ret, 2, c.val); \ + vsseg3e_v_##_T##m1x3(ptr, ret, num); \ +} \ +inline void v_store_interleave( _Tp* ptr, const v_##_Tpvec##x##num& a, const v_##_Tpvec##x##num& b, \ + const v_##_Tpvec##x##num& c, const v_##_Tpvec##x##num& d, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED ) \ +{ \ + v##_Tpvec##m1x4_t ret = vundefined_##_T##m1x4(); \ + ret = vset_##_T##m1x4(ret, 0, a.val); \ + ret = vset_##_T##m1x4(ret, 1, b.val); \ + ret = vset_##_T##m1x4(ret, 2, c.val); \ + ret = vset_##_T##m1x4(ret, 3, d.val); \ + vsseg4e_v_##_T##m1x4(ptr, ret, num); \ +} +OPENCV_HAL_IMPL_RISCVV_INTERLEAVED_(float32, float, 4, f32) +OPENCV_HAL_IMPL_RISCVV_INTERLEAVED_(float64, double, 2, f64) + +OPENCV_HAL_IMPL_RISCVV_INTERLEAVED_(uint64, unsigned long, 2, u64) +OPENCV_HAL_IMPL_RISCVV_INTERLEAVED_(int64, long, 2, i64) + +inline v_float32x4 v_cvt_f32(const v_int32x4& a) +{ + return v_float32x4(vfcvt_f_x_v_f32m1(a.val, 4)); +} + +#if CV_SIMD128_64F +inline v_float32x4 v_cvt_f32(const v_float64x2& a) +{ + vfloat64m2_t _val = vundefined_f64m2(); + _val = vset_f64m2(_val, 0, a.val); + vfloat32m1_t aval = vfncvt_f_f_v_f32m1(_val, 2); + return v_float32x4(aval); +} + +inline v_float32x4 v_cvt_f32(const v_float64x2& a, const v_float64x2& b) +{ + vfloat64m2_t _val = vundefined_f64m2(); + _val = vset_f64m2(_val, 0, a.val); + _val = vset_f64m2(_val, 1, b.val); + vfloat32m1_t aval = vfncvt_f_f_v_f32m1(_val, 4); + return v_float32x4(aval); +} + +inline v_float64x2 v_cvt_f64(const v_int32x4& a) +{ + vfloat32m1_t val = vfcvt_f_x_v_f32m1(a.val, 4); + vfloat64m2_t _val = vfwcvt_f_f_v_f64m2(val, 4); + return v_float64x2(vget_f64m2_f64m1(_val, 0)); +} + +inline v_float64x2 v_cvt_f64_high(const v_int32x4& a) +{ + vfloat32m1_t val = vfcvt_f_x_v_f32m1(a.val, 4); + vfloat64m2_t _val = vfwcvt_f_f_v_f64m2(val, 4); + return v_float64x2(vget_f64m2_f64m1(_val, 1)); +} + +inline v_float64x2 v_cvt_f64(const v_float32x4& a) +{ + vfloat64m2_t _val = vfwcvt_f_f_v_f64m2(a.val, 4); + return v_float64x2(vget_f64m2_f64m1(_val, 0)); +} + +inline v_float64x2 v_cvt_f64_high(const v_float32x4& a) +{ + vfloat64m2_t _val = vfwcvt_f_f_v_f64m2(a.val, 4); + return v_float64x2(vget_f64m2_f64m1(_val, 1)); +} + +inline v_float64x2 v_cvt_f64(const v_int64x2& a) +{ + return v_float64x2(vfcvt_f_x_v_f64m1(a.val, 2)); +} + +#endif +inline v_int8x16 v_interleave_pairs(const v_int8x16& vec) +{ + vuint64m1_t m0 = {0x0705060403010200, 0x0F0D0E0C0B090A08}; + return v_int8x16(vrgather_vv_i8m1(vec.val, (vuint8m1_t)m0, 16)); +} +inline v_uint8x16 v_interleave_pairs(const v_uint8x16& vec) +{ + return v_reinterpret_as_u8(v_interleave_pairs(v_reinterpret_as_s8(vec))); +} + +inline v_int8x16 v_interleave_quads(const v_int8x16& vec) +{ + vuint64m1_t m0 = {0x0703060205010400, 0x0F0B0E0A0D090C08}; + return v_int8x16(vrgather_vv_i8m1(vec.val, (vuint8m1_t)m0, 16)); +} +inline v_uint8x16 v_interleave_quads(const v_uint8x16& vec) +{ + return v_reinterpret_as_u8(v_interleave_quads(v_reinterpret_as_s8(vec))); +} + +inline v_int16x8 v_interleave_pairs(const v_int16x8& vec) +{ + vuint64m1_t m0 = {0x0706030205040100, 0x0F0E0B0A0D0C0908}; + return v_int16x8((vint16m1_t)vrgather_vv_u8m1((vuint8m1_t)vec.val, (vuint8m1_t)m0, 16)); +} +inline v_uint16x8 v_interleave_pairs(const v_uint16x8& vec) { return v_reinterpret_as_u16(v_interleave_pairs(v_reinterpret_as_s16(vec))); } +inline v_int16x8 v_interleave_quads(const v_int16x8& vec) +{ + vuint64m1_t m0 = {0x0B0A030209080100, 0x0F0E07060D0C0504}; + return v_int16x8((vint16m1_t)vrgather_vv_u8m1((vuint8m1_t)(vec.val), (vuint8m1_t)m0, 16)); +} +inline v_uint16x8 v_interleave_quads(const v_uint16x8& vec) { return v_reinterpret_as_u16(v_interleave_quads(v_reinterpret_as_s16(vec))); } + +inline v_int32x4 v_interleave_pairs(const v_int32x4& vec) +{ + vuint64m1_t m0 = {0x0B0A090803020100, 0x0F0E0D0C07060504}; + return v_int32x4((vint32m1_t)vrgather_vv_u8m1((vuint8m1_t)(vec.val), (vuint8m1_t)m0, 16)); +} +inline v_uint32x4 v_interleave_pairs(const v_uint32x4& vec) { return v_reinterpret_as_u32(v_interleave_pairs(v_reinterpret_as_s32(vec))); } +inline v_float32x4 v_interleave_pairs(const v_float32x4& vec) { return v_reinterpret_as_f32(v_interleave_pairs(v_reinterpret_as_s32(vec))); } +inline v_int8x16 v_pack_triplets(const v_int8x16& vec) +{ + vuint64m1_t m0 = {0x0908060504020100, 0xFFFFFFFF0E0D0C0A}; + return v_int8x16((vint8m1_t)vrgather_vv_u8m1((vuint8m1_t)(vec.val), (vuint8m1_t)m0, 16)); +} +inline v_uint8x16 v_pack_triplets(const v_uint8x16& vec) { return v_reinterpret_as_u8(v_pack_triplets(v_reinterpret_as_s8(vec))); } + +inline v_int16x8 v_pack_triplets(const v_int16x8& vec) +{ + vuint64m1_t m0 = {0x0908050403020100, 0xFFFFFFFF0D0C0B0A}; + return v_int16x8((vint16m1_t)vrgather_vv_u8m1((vuint8m1_t)(vec.val), (vuint8m1_t)m0, 16)); +} +inline v_uint16x8 v_pack_triplets(const v_uint16x8& vec) { return v_reinterpret_as_u16(v_pack_triplets(v_reinterpret_as_s16(vec))); } + +inline v_int32x4 v_pack_triplets(const v_int32x4& vec) { return vec; } +inline v_uint32x4 v_pack_triplets(const v_uint32x4& vec) { return vec; } +inline v_float32x4 v_pack_triplets(const v_float32x4& vec) { return vec; } + +#if CV_SIMD128_64F +inline v_float64x2 v_dotprod_expand(const v_int32x4& a, const v_int32x4& b) +{ return v_cvt_f64(v_dotprod(a, b)); } +inline v_float64x2 v_dotprod_expand(const v_int32x4& a, const v_int32x4& b, + const v_float64x2& c) +{ return v_dotprod_expand(a, b) + c; } +inline v_float64x2 v_dotprod_expand_fast(const v_int32x4& a, const v_int32x4& b) +{ + vint64m2_t v1 = vwmul_vv_i64m2(a.val, b.val, 4); + vfloat64m1_t res = vfcvt_f_x_v_f64m1(vadd_vv_i64m1(vget_i64m2_i64m1(v1, 0), vget_i64m2_i64m1(v1, 1), 2), 2); + return v_float64x2(res); +} +inline v_float64x2 v_dotprod_expand_fast(const v_int32x4& a, const v_int32x4& b, const v_float64x2& c) +{ v_float64x2 res = v_dotprod_expand_fast(a, b); + return res + c; } +#endif +////// FP16 support /////// +inline v_float32x4 v_load_expand(const float16_t* ptr) +{ + vfloat16m1_t v = vle_v_f16m1((__fp16*)ptr, 4); + vfloat32m2_t v32 = vfwcvt_f_f_v_f32m2(v, 4); + return v_float32x4(vget_f32m2_f32m1(v32, 0)); +} + +inline void v_pack_store(float16_t* ptr, const v_float32x4& v) +{ + vfloat32m2_t v32 = vundefined_f32m2(); + v32 = vset_f32m2(v32, 0, v.val); + vfloat16m1_t hv = vfncvt_f_f_v_f16m1(v32, 4); + vse_v_f16m1((__fp16*)ptr, hv, 4); +} + + +inline void v_cleanup() {} + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END + +//! @endcond + +} +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_sse.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_sse.hpp new file mode 100644 index 0000000..443ee16 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_sse.hpp @@ -0,0 +1,3467 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_HAL_SSE_HPP +#define OPENCV_HAL_SSE_HPP + +#include +#include "opencv2/core/utility.hpp" + +#define CV_SIMD128 1 +#define CV_SIMD128_64F 1 +#define CV_SIMD128_FP16 0 // no native operations with FP16 type. + +namespace cv +{ + +//! @cond IGNORED + +// +// Compilation troubleshooting: +// - MSVC: error C2719: 'a': formal parameter with requested alignment of 16 won't be aligned +// Replace parameter declaration to const reference: +// -v_int32x4 a +// +const v_int32x4& a +// + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN + +///////// Types //////////// + +struct v_uint8x16 +{ + typedef uchar lane_type; + typedef __m128i vector_type; + enum { nlanes = 16 }; + + /* coverity[uninit_ctor]: suppress warning */ + v_uint8x16() {} + explicit v_uint8x16(__m128i v) : val(v) {} + v_uint8x16(uchar v0, uchar v1, uchar v2, uchar v3, uchar v4, uchar v5, uchar v6, uchar v7, + uchar v8, uchar v9, uchar v10, uchar v11, uchar v12, uchar v13, uchar v14, uchar v15) + { + val = _mm_setr_epi8((char)v0, (char)v1, (char)v2, (char)v3, + (char)v4, (char)v5, (char)v6, (char)v7, + (char)v8, (char)v9, (char)v10, (char)v11, + (char)v12, (char)v13, (char)v14, (char)v15); + } + + uchar get0() const + { + return (uchar)_mm_cvtsi128_si32(val); + } + + __m128i val; +}; + +struct v_int8x16 +{ + typedef schar lane_type; + typedef __m128i vector_type; + enum { nlanes = 16 }; + + /* coverity[uninit_ctor]: suppress warning */ + v_int8x16() {} + explicit v_int8x16(__m128i v) : val(v) {} + v_int8x16(schar v0, schar v1, schar v2, schar v3, schar v4, schar v5, schar v6, schar v7, + schar v8, schar v9, schar v10, schar v11, schar v12, schar v13, schar v14, schar v15) + { + val = _mm_setr_epi8((char)v0, (char)v1, (char)v2, (char)v3, + (char)v4, (char)v5, (char)v6, (char)v7, + (char)v8, (char)v9, (char)v10, (char)v11, + (char)v12, (char)v13, (char)v14, (char)v15); + } + + schar get0() const + { + return (schar)_mm_cvtsi128_si32(val); + } + + __m128i val; +}; + +struct v_uint16x8 +{ + typedef ushort lane_type; + typedef __m128i vector_type; + enum { nlanes = 8 }; + + /* coverity[uninit_ctor]: suppress warning */ + v_uint16x8() {} + explicit v_uint16x8(__m128i v) : val(v) {} + v_uint16x8(ushort v0, ushort v1, ushort v2, ushort v3, ushort v4, ushort v5, ushort v6, ushort v7) + { + val = _mm_setr_epi16((short)v0, (short)v1, (short)v2, (short)v3, + (short)v4, (short)v5, (short)v6, (short)v7); + } + + ushort get0() const + { + return (ushort)_mm_cvtsi128_si32(val); + } + + __m128i val; +}; + +struct v_int16x8 +{ + typedef short lane_type; + typedef __m128i vector_type; + enum { nlanes = 8 }; + + /* coverity[uninit_ctor]: suppress warning */ + v_int16x8() {} + explicit v_int16x8(__m128i v) : val(v) {} + v_int16x8(short v0, short v1, short v2, short v3, short v4, short v5, short v6, short v7) + { + val = _mm_setr_epi16((short)v0, (short)v1, (short)v2, (short)v3, + (short)v4, (short)v5, (short)v6, (short)v7); + } + + short get0() const + { + return (short)_mm_cvtsi128_si32(val); + } + + __m128i val; +}; + +struct v_uint32x4 +{ + typedef unsigned lane_type; + typedef __m128i vector_type; + enum { nlanes = 4 }; + + /* coverity[uninit_ctor]: suppress warning */ + v_uint32x4() {} + explicit v_uint32x4(__m128i v) : val(v) {} + v_uint32x4(unsigned v0, unsigned v1, unsigned v2, unsigned v3) + { + val = _mm_setr_epi32((int)v0, (int)v1, (int)v2, (int)v3); + } + + unsigned get0() const + { + return (unsigned)_mm_cvtsi128_si32(val); + } + + __m128i val; +}; + +struct v_int32x4 +{ + typedef int lane_type; + typedef __m128i vector_type; + enum { nlanes = 4 }; + + /* coverity[uninit_ctor]: suppress warning */ + v_int32x4() {} + explicit v_int32x4(__m128i v) : val(v) {} + v_int32x4(int v0, int v1, int v2, int v3) + { + val = _mm_setr_epi32(v0, v1, v2, v3); + } + + int get0() const + { + return _mm_cvtsi128_si32(val); + } + + __m128i val; +}; + +struct v_float32x4 +{ + typedef float lane_type; + typedef __m128 vector_type; + enum { nlanes = 4 }; + + /* coverity[uninit_ctor]: suppress warning */ + v_float32x4() {} + explicit v_float32x4(__m128 v) : val(v) {} + v_float32x4(float v0, float v1, float v2, float v3) + { + val = _mm_setr_ps(v0, v1, v2, v3); + } + + float get0() const + { + return _mm_cvtss_f32(val); + } + + __m128 val; +}; + +struct v_uint64x2 +{ + typedef uint64 lane_type; + typedef __m128i vector_type; + enum { nlanes = 2 }; + + /* coverity[uninit_ctor]: suppress warning */ + v_uint64x2() {} + explicit v_uint64x2(__m128i v) : val(v) {} + v_uint64x2(uint64 v0, uint64 v1) + { +#if defined(_MSC_VER) && _MSC_VER >= 1920/*MSVS 2019*/ && defined(_M_X64) && !defined(__clang__) + val = _mm_setr_epi64x((int64_t)v0, (int64_t)v1); +#elif defined(__GNUC__) + val = _mm_setr_epi64((__m64)v0, (__m64)v1); +#else + val = _mm_setr_epi32((int)v0, (int)(v0 >> 32), (int)v1, (int)(v1 >> 32)); +#endif + } + + uint64 get0() const + { + #if !defined(__x86_64__) && !defined(_M_X64) + int a = _mm_cvtsi128_si32(val); + int b = _mm_cvtsi128_si32(_mm_srli_epi64(val, 32)); + return (unsigned)a | ((uint64)(unsigned)b << 32); + #else + return (uint64)_mm_cvtsi128_si64(val); + #endif + } + + __m128i val; +}; + +struct v_int64x2 +{ + typedef int64 lane_type; + typedef __m128i vector_type; + enum { nlanes = 2 }; + + /* coverity[uninit_ctor]: suppress warning */ + v_int64x2() {} + explicit v_int64x2(__m128i v) : val(v) {} + v_int64x2(int64 v0, int64 v1) + { +#if defined(_MSC_VER) && _MSC_VER >= 1920/*MSVS 2019*/ && defined(_M_X64) && !defined(__clang__) + val = _mm_setr_epi64x((int64_t)v0, (int64_t)v1); +#elif defined(__GNUC__) + val = _mm_setr_epi64((__m64)v0, (__m64)v1); +#else + val = _mm_setr_epi32((int)v0, (int)(v0 >> 32), (int)v1, (int)(v1 >> 32)); +#endif + } + + int64 get0() const + { + #if !defined(__x86_64__) && !defined(_M_X64) + int a = _mm_cvtsi128_si32(val); + int b = _mm_cvtsi128_si32(_mm_srli_epi64(val, 32)); + return (int64)((unsigned)a | ((uint64)(unsigned)b << 32)); + #else + return _mm_cvtsi128_si64(val); + #endif + } + + __m128i val; +}; + +struct v_float64x2 +{ + typedef double lane_type; + typedef __m128d vector_type; + enum { nlanes = 2 }; + + /* coverity[uninit_ctor]: suppress warning */ + v_float64x2() {} + explicit v_float64x2(__m128d v) : val(v) {} + v_float64x2(double v0, double v1) + { + val = _mm_setr_pd(v0, v1); + } + + double get0() const + { + return _mm_cvtsd_f64(val); + } + + __m128d val; +}; + +namespace hal_sse_internal +{ + template + to_sse_type v_sse_reinterpret_as(const from_sse_type& val); + +#define OPENCV_HAL_IMPL_SSE_REINTERPRET_RAW(to_sse_type, from_sse_type, sse_cast_intrin) \ + template<> inline \ + to_sse_type v_sse_reinterpret_as(const from_sse_type& a) \ + { return sse_cast_intrin(a); } + + OPENCV_HAL_IMPL_SSE_REINTERPRET_RAW(__m128i, __m128i, OPENCV_HAL_NOP) + OPENCV_HAL_IMPL_SSE_REINTERPRET_RAW(__m128i, __m128, _mm_castps_si128) + OPENCV_HAL_IMPL_SSE_REINTERPRET_RAW(__m128i, __m128d, _mm_castpd_si128) + OPENCV_HAL_IMPL_SSE_REINTERPRET_RAW(__m128, __m128i, _mm_castsi128_ps) + OPENCV_HAL_IMPL_SSE_REINTERPRET_RAW(__m128, __m128, OPENCV_HAL_NOP) + OPENCV_HAL_IMPL_SSE_REINTERPRET_RAW(__m128, __m128d, _mm_castpd_ps) + OPENCV_HAL_IMPL_SSE_REINTERPRET_RAW(__m128d, __m128i, _mm_castsi128_pd) + OPENCV_HAL_IMPL_SSE_REINTERPRET_RAW(__m128d, __m128, _mm_castps_pd) + OPENCV_HAL_IMPL_SSE_REINTERPRET_RAW(__m128d, __m128d, OPENCV_HAL_NOP) +} + +#define OPENCV_HAL_IMPL_SSE_INITVEC(_Tpvec, _Tp, suffix, zsuffix, ssuffix, _Tps, cast) \ +inline _Tpvec v_setzero_##suffix() { return _Tpvec(_mm_setzero_##zsuffix()); } \ +inline _Tpvec v_setall_##suffix(_Tp v) { return _Tpvec(_mm_set1_##ssuffix((_Tps)v)); } \ +template inline _Tpvec v_reinterpret_as_##suffix(const _Tpvec0& a) \ +{ return _Tpvec(cast(a.val)); } + +OPENCV_HAL_IMPL_SSE_INITVEC(v_uint8x16, uchar, u8, si128, epi8, schar, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_INITVEC(v_int8x16, schar, s8, si128, epi8, schar, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_INITVEC(v_uint16x8, ushort, u16, si128, epi16, short, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_INITVEC(v_int16x8, short, s16, si128, epi16, short, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_INITVEC(v_uint32x4, unsigned, u32, si128, epi32, int, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_INITVEC(v_int32x4, int, s32, si128, epi32, int, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_INITVEC(v_float32x4, float, f32, ps, ps, float, _mm_castsi128_ps) +OPENCV_HAL_IMPL_SSE_INITVEC(v_float64x2, double, f64, pd, pd, double, _mm_castsi128_pd) + +inline v_uint64x2 v_setzero_u64() { return v_uint64x2(_mm_setzero_si128()); } +inline v_int64x2 v_setzero_s64() { return v_int64x2(_mm_setzero_si128()); } +inline v_uint64x2 v_setall_u64(uint64 val) { return v_uint64x2(val, val); } +inline v_int64x2 v_setall_s64(int64 val) { return v_int64x2(val, val); } + +template inline +v_uint64x2 v_reinterpret_as_u64(const _Tpvec& a) { return v_uint64x2(a.val); } +template inline +v_int64x2 v_reinterpret_as_s64(const _Tpvec& a) { return v_int64x2(a.val); } +inline v_float32x4 v_reinterpret_as_f32(const v_uint64x2& a) +{ return v_float32x4(_mm_castsi128_ps(a.val)); } +inline v_float32x4 v_reinterpret_as_f32(const v_int64x2& a) +{ return v_float32x4(_mm_castsi128_ps(a.val)); } +inline v_float64x2 v_reinterpret_as_f64(const v_uint64x2& a) +{ return v_float64x2(_mm_castsi128_pd(a.val)); } +inline v_float64x2 v_reinterpret_as_f64(const v_int64x2& a) +{ return v_float64x2(_mm_castsi128_pd(a.val)); } + +#define OPENCV_HAL_IMPL_SSE_INIT_FROM_FLT(_Tpvec, suffix) \ +inline _Tpvec v_reinterpret_as_##suffix(const v_float32x4& a) \ +{ return _Tpvec(_mm_castps_si128(a.val)); } \ +inline _Tpvec v_reinterpret_as_##suffix(const v_float64x2& a) \ +{ return _Tpvec(_mm_castpd_si128(a.val)); } + +OPENCV_HAL_IMPL_SSE_INIT_FROM_FLT(v_uint8x16, u8) +OPENCV_HAL_IMPL_SSE_INIT_FROM_FLT(v_int8x16, s8) +OPENCV_HAL_IMPL_SSE_INIT_FROM_FLT(v_uint16x8, u16) +OPENCV_HAL_IMPL_SSE_INIT_FROM_FLT(v_int16x8, s16) +OPENCV_HAL_IMPL_SSE_INIT_FROM_FLT(v_uint32x4, u32) +OPENCV_HAL_IMPL_SSE_INIT_FROM_FLT(v_int32x4, s32) +OPENCV_HAL_IMPL_SSE_INIT_FROM_FLT(v_uint64x2, u64) +OPENCV_HAL_IMPL_SSE_INIT_FROM_FLT(v_int64x2, s64) + +inline v_float32x4 v_reinterpret_as_f32(const v_float32x4& a) {return a; } +inline v_float64x2 v_reinterpret_as_f64(const v_float64x2& a) {return a; } +inline v_float32x4 v_reinterpret_as_f32(const v_float64x2& a) {return v_float32x4(_mm_castpd_ps(a.val)); } +inline v_float64x2 v_reinterpret_as_f64(const v_float32x4& a) {return v_float64x2(_mm_castps_pd(a.val)); } + +//////////////// PACK /////////////// +inline v_uint8x16 v_pack(const v_uint16x8& a, const v_uint16x8& b) +{ + __m128i delta = _mm_set1_epi16(255); + return v_uint8x16(_mm_packus_epi16(_mm_subs_epu16(a.val, _mm_subs_epu16(a.val, delta)), + _mm_subs_epu16(b.val, _mm_subs_epu16(b.val, delta)))); +} + +inline void v_pack_store(uchar* ptr, const v_uint16x8& a) +{ + __m128i delta = _mm_set1_epi16(255); + __m128i a1 = _mm_subs_epu16(a.val, _mm_subs_epu16(a.val, delta)); + _mm_storel_epi64((__m128i*)ptr, _mm_packus_epi16(a1, a1)); +} + +inline v_uint8x16 v_pack_u(const v_int16x8& a, const v_int16x8& b) +{ return v_uint8x16(_mm_packus_epi16(a.val, b.val)); } + +inline void v_pack_u_store(uchar* ptr, const v_int16x8& a) +{ _mm_storel_epi64((__m128i*)ptr, _mm_packus_epi16(a.val, a.val)); } + +template inline +v_uint8x16 v_rshr_pack(const v_uint16x8& a, const v_uint16x8& b) +{ + // we assume that n > 0, and so the shifted 16-bit values can be treated as signed numbers. + __m128i delta = _mm_set1_epi16((short)(1 << (n-1))); + return v_uint8x16(_mm_packus_epi16(_mm_srli_epi16(_mm_adds_epu16(a.val, delta), n), + _mm_srli_epi16(_mm_adds_epu16(b.val, delta), n))); +} + +template inline +void v_rshr_pack_store(uchar* ptr, const v_uint16x8& a) +{ + __m128i delta = _mm_set1_epi16((short)(1 << (n-1))); + __m128i a1 = _mm_srli_epi16(_mm_adds_epu16(a.val, delta), n); + _mm_storel_epi64((__m128i*)ptr, _mm_packus_epi16(a1, a1)); +} + +template inline +v_uint8x16 v_rshr_pack_u(const v_int16x8& a, const v_int16x8& b) +{ + __m128i delta = _mm_set1_epi16((short)(1 << (n-1))); + return v_uint8x16(_mm_packus_epi16(_mm_srai_epi16(_mm_adds_epi16(a.val, delta), n), + _mm_srai_epi16(_mm_adds_epi16(b.val, delta), n))); +} + +template inline +void v_rshr_pack_u_store(uchar* ptr, const v_int16x8& a) +{ + __m128i delta = _mm_set1_epi16((short)(1 << (n-1))); + __m128i a1 = _mm_srai_epi16(_mm_adds_epi16(a.val, delta), n); + _mm_storel_epi64((__m128i*)ptr, _mm_packus_epi16(a1, a1)); +} + +inline v_int8x16 v_pack(const v_int16x8& a, const v_int16x8& b) +{ return v_int8x16(_mm_packs_epi16(a.val, b.val)); } + +inline void v_pack_store(schar* ptr, const v_int16x8& a) +{ _mm_storel_epi64((__m128i*)ptr, _mm_packs_epi16(a.val, a.val)); } + +template inline +v_int8x16 v_rshr_pack(const v_int16x8& a, const v_int16x8& b) +{ + // we assume that n > 0, and so the shifted 16-bit values can be treated as signed numbers. + __m128i delta = _mm_set1_epi16((short)(1 << (n-1))); + return v_int8x16(_mm_packs_epi16(_mm_srai_epi16(_mm_adds_epi16(a.val, delta), n), + _mm_srai_epi16(_mm_adds_epi16(b.val, delta), n))); +} +template inline +void v_rshr_pack_store(schar* ptr, const v_int16x8& a) +{ + // we assume that n > 0, and so the shifted 16-bit values can be treated as signed numbers. + __m128i delta = _mm_set1_epi16((short)(1 << (n-1))); + __m128i a1 = _mm_srai_epi16(_mm_adds_epi16(a.val, delta), n); + _mm_storel_epi64((__m128i*)ptr, _mm_packs_epi16(a1, a1)); +} + + +// byte-wise "mask ? a : b" +inline __m128i v_select_si128(__m128i mask, __m128i a, __m128i b) +{ +#if CV_SSE4_1 + return _mm_blendv_epi8(b, a, mask); +#else + return _mm_xor_si128(b, _mm_and_si128(_mm_xor_si128(a, b), mask)); +#endif +} + +inline v_uint16x8 v_pack(const v_uint32x4& a, const v_uint32x4& b) +{ return v_uint16x8(_v128_packs_epu32(a.val, b.val)); } + +inline void v_pack_store(ushort* ptr, const v_uint32x4& a) +{ + __m128i z = _mm_setzero_si128(), maxval32 = _mm_set1_epi32(65535), delta32 = _mm_set1_epi32(32768); + __m128i a1 = _mm_sub_epi32(v_select_si128(_mm_cmpgt_epi32(z, a.val), maxval32, a.val), delta32); + __m128i r = _mm_packs_epi32(a1, a1); + _mm_storel_epi64((__m128i*)ptr, _mm_sub_epi16(r, _mm_set1_epi16(-32768))); +} + +template inline +v_uint16x8 v_rshr_pack(const v_uint32x4& a, const v_uint32x4& b) +{ + __m128i delta = _mm_set1_epi32(1 << (n-1)), delta32 = _mm_set1_epi32(32768); + __m128i a1 = _mm_sub_epi32(_mm_srli_epi32(_mm_add_epi32(a.val, delta), n), delta32); + __m128i b1 = _mm_sub_epi32(_mm_srli_epi32(_mm_add_epi32(b.val, delta), n), delta32); + return v_uint16x8(_mm_sub_epi16(_mm_packs_epi32(a1, b1), _mm_set1_epi16(-32768))); +} + +template inline +void v_rshr_pack_store(ushort* ptr, const v_uint32x4& a) +{ + __m128i delta = _mm_set1_epi32(1 << (n-1)), delta32 = _mm_set1_epi32(32768); + __m128i a1 = _mm_sub_epi32(_mm_srli_epi32(_mm_add_epi32(a.val, delta), n), delta32); + __m128i a2 = _mm_sub_epi16(_mm_packs_epi32(a1, a1), _mm_set1_epi16(-32768)); + _mm_storel_epi64((__m128i*)ptr, a2); +} + +inline v_uint16x8 v_pack_u(const v_int32x4& a, const v_int32x4& b) +{ +#if CV_SSE4_1 + return v_uint16x8(_mm_packus_epi32(a.val, b.val)); +#else + __m128i delta32 = _mm_set1_epi32(32768); + + // preliminary saturate negative values to zero + __m128i a1 = _mm_and_si128(a.val, _mm_cmpgt_epi32(a.val, _mm_set1_epi32(0))); + __m128i b1 = _mm_and_si128(b.val, _mm_cmpgt_epi32(b.val, _mm_set1_epi32(0))); + + __m128i r = _mm_packs_epi32(_mm_sub_epi32(a1, delta32), _mm_sub_epi32(b1, delta32)); + return v_uint16x8(_mm_sub_epi16(r, _mm_set1_epi16(-32768))); +#endif +} + +inline void v_pack_u_store(ushort* ptr, const v_int32x4& a) +{ +#if CV_SSE4_1 + _mm_storel_epi64((__m128i*)ptr, _mm_packus_epi32(a.val, a.val)); +#else + __m128i delta32 = _mm_set1_epi32(32768); + __m128i a1 = _mm_sub_epi32(a.val, delta32); + __m128i r = _mm_sub_epi16(_mm_packs_epi32(a1, a1), _mm_set1_epi16(-32768)); + _mm_storel_epi64((__m128i*)ptr, r); +#endif +} + +template inline +v_uint16x8 v_rshr_pack_u(const v_int32x4& a, const v_int32x4& b) +{ +#if CV_SSE4_1 + __m128i delta = _mm_set1_epi32(1 << (n - 1)); + return v_uint16x8(_mm_packus_epi32(_mm_srai_epi32(_mm_add_epi32(a.val, delta), n), + _mm_srai_epi32(_mm_add_epi32(b.val, delta), n))); +#else + __m128i delta = _mm_set1_epi32(1 << (n-1)), delta32 = _mm_set1_epi32(32768); + __m128i a1 = _mm_sub_epi32(_mm_srai_epi32(_mm_add_epi32(a.val, delta), n), delta32); + __m128i a2 = _mm_sub_epi16(_mm_packs_epi32(a1, a1), _mm_set1_epi16(-32768)); + __m128i b1 = _mm_sub_epi32(_mm_srai_epi32(_mm_add_epi32(b.val, delta), n), delta32); + __m128i b2 = _mm_sub_epi16(_mm_packs_epi32(b1, b1), _mm_set1_epi16(-32768)); + return v_uint16x8(_mm_unpacklo_epi64(a2, b2)); +#endif +} + +template inline +void v_rshr_pack_u_store(ushort* ptr, const v_int32x4& a) +{ +#if CV_SSE4_1 + __m128i delta = _mm_set1_epi32(1 << (n - 1)); + __m128i a1 = _mm_srai_epi32(_mm_add_epi32(a.val, delta), n); + _mm_storel_epi64((__m128i*)ptr, _mm_packus_epi32(a1, a1)); +#else + __m128i delta = _mm_set1_epi32(1 << (n-1)), delta32 = _mm_set1_epi32(32768); + __m128i a1 = _mm_sub_epi32(_mm_srai_epi32(_mm_add_epi32(a.val, delta), n), delta32); + __m128i a2 = _mm_sub_epi16(_mm_packs_epi32(a1, a1), _mm_set1_epi16(-32768)); + _mm_storel_epi64((__m128i*)ptr, a2); +#endif +} + +inline v_int16x8 v_pack(const v_int32x4& a, const v_int32x4& b) +{ return v_int16x8(_mm_packs_epi32(a.val, b.val)); } + +inline void v_pack_store(short* ptr, const v_int32x4& a) +{ + _mm_storel_epi64((__m128i*)ptr, _mm_packs_epi32(a.val, a.val)); +} + +template inline +v_int16x8 v_rshr_pack(const v_int32x4& a, const v_int32x4& b) +{ + __m128i delta = _mm_set1_epi32(1 << (n-1)); + return v_int16x8(_mm_packs_epi32(_mm_srai_epi32(_mm_add_epi32(a.val, delta), n), + _mm_srai_epi32(_mm_add_epi32(b.val, delta), n))); +} + +template inline +void v_rshr_pack_store(short* ptr, const v_int32x4& a) +{ + __m128i delta = _mm_set1_epi32(1 << (n-1)); + __m128i a1 = _mm_srai_epi32(_mm_add_epi32(a.val, delta), n); + _mm_storel_epi64((__m128i*)ptr, _mm_packs_epi32(a1, a1)); +} + + +// [a0 0 | b0 0] [a1 0 | b1 0] +inline v_uint32x4 v_pack(const v_uint64x2& a, const v_uint64x2& b) +{ + __m128i v0 = _mm_unpacklo_epi32(a.val, b.val); // a0 a1 0 0 + __m128i v1 = _mm_unpackhi_epi32(a.val, b.val); // b0 b1 0 0 + return v_uint32x4(_mm_unpacklo_epi32(v0, v1)); +} + +inline void v_pack_store(unsigned* ptr, const v_uint64x2& a) +{ + __m128i a1 = _mm_shuffle_epi32(a.val, _MM_SHUFFLE(0, 2, 2, 0)); + _mm_storel_epi64((__m128i*)ptr, a1); +} + +// [a0 0 | b0 0] [a1 0 | b1 0] +inline v_int32x4 v_pack(const v_int64x2& a, const v_int64x2& b) +{ + __m128i v0 = _mm_unpacklo_epi32(a.val, b.val); // a0 a1 0 0 + __m128i v1 = _mm_unpackhi_epi32(a.val, b.val); // b0 b1 0 0 + return v_int32x4(_mm_unpacklo_epi32(v0, v1)); +} + +inline void v_pack_store(int* ptr, const v_int64x2& a) +{ + __m128i a1 = _mm_shuffle_epi32(a.val, _MM_SHUFFLE(0, 2, 2, 0)); + _mm_storel_epi64((__m128i*)ptr, a1); +} + +template inline +v_uint32x4 v_rshr_pack(const v_uint64x2& a, const v_uint64x2& b) +{ + uint64 delta = (uint64)1 << (n-1); + v_uint64x2 delta2(delta, delta); + __m128i a1 = _mm_srli_epi64(_mm_add_epi64(a.val, delta2.val), n); + __m128i b1 = _mm_srli_epi64(_mm_add_epi64(b.val, delta2.val), n); + __m128i v0 = _mm_unpacklo_epi32(a1, b1); // a0 a1 0 0 + __m128i v1 = _mm_unpackhi_epi32(a1, b1); // b0 b1 0 0 + return v_uint32x4(_mm_unpacklo_epi32(v0, v1)); +} + +template inline +void v_rshr_pack_store(unsigned* ptr, const v_uint64x2& a) +{ + uint64 delta = (uint64)1 << (n-1); + v_uint64x2 delta2(delta, delta); + __m128i a1 = _mm_srli_epi64(_mm_add_epi64(a.val, delta2.val), n); + __m128i a2 = _mm_shuffle_epi32(a1, _MM_SHUFFLE(0, 2, 2, 0)); + _mm_storel_epi64((__m128i*)ptr, a2); +} + +inline __m128i v_sign_epi64(__m128i a) +{ + return _mm_shuffle_epi32(_mm_srai_epi32(a, 31), _MM_SHUFFLE(3, 3, 1, 1)); // x m0 | x m1 +} + +inline __m128i v_srai_epi64(__m128i a, int imm) +{ + __m128i smask = v_sign_epi64(a); + return _mm_xor_si128(_mm_srli_epi64(_mm_xor_si128(a, smask), imm), smask); +} + +template inline +v_int32x4 v_rshr_pack(const v_int64x2& a, const v_int64x2& b) +{ + int64 delta = (int64)1 << (n-1); + v_int64x2 delta2(delta, delta); + __m128i a1 = v_srai_epi64(_mm_add_epi64(a.val, delta2.val), n); + __m128i b1 = v_srai_epi64(_mm_add_epi64(b.val, delta2.val), n); + __m128i v0 = _mm_unpacklo_epi32(a1, b1); // a0 a1 0 0 + __m128i v1 = _mm_unpackhi_epi32(a1, b1); // b0 b1 0 0 + return v_int32x4(_mm_unpacklo_epi32(v0, v1)); +} + +template inline +void v_rshr_pack_store(int* ptr, const v_int64x2& a) +{ + int64 delta = (int64)1 << (n-1); + v_int64x2 delta2(delta, delta); + __m128i a1 = v_srai_epi64(_mm_add_epi64(a.val, delta2.val), n); + __m128i a2 = _mm_shuffle_epi32(a1, _MM_SHUFFLE(0, 2, 2, 0)); + _mm_storel_epi64((__m128i*)ptr, a2); +} + +// pack boolean +inline v_uint8x16 v_pack_b(const v_uint16x8& a, const v_uint16x8& b) +{ + __m128i ab = _mm_packs_epi16(a.val, b.val); + return v_uint8x16(ab); +} + +inline v_uint8x16 v_pack_b(const v_uint32x4& a, const v_uint32x4& b, + const v_uint32x4& c, const v_uint32x4& d) +{ + __m128i ab = _mm_packs_epi32(a.val, b.val); + __m128i cd = _mm_packs_epi32(c.val, d.val); + return v_uint8x16(_mm_packs_epi16(ab, cd)); +} + +inline v_uint8x16 v_pack_b(const v_uint64x2& a, const v_uint64x2& b, const v_uint64x2& c, + const v_uint64x2& d, const v_uint64x2& e, const v_uint64x2& f, + const v_uint64x2& g, const v_uint64x2& h) +{ + __m128i ab = _mm_packs_epi32(a.val, b.val); + __m128i cd = _mm_packs_epi32(c.val, d.val); + __m128i ef = _mm_packs_epi32(e.val, f.val); + __m128i gh = _mm_packs_epi32(g.val, h.val); + + __m128i abcd = _mm_packs_epi32(ab, cd); + __m128i efgh = _mm_packs_epi32(ef, gh); + return v_uint8x16(_mm_packs_epi16(abcd, efgh)); +} + +inline v_float32x4 v_matmul(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& m3) +{ + __m128 v0 = _mm_mul_ps(_mm_shuffle_ps(v.val, v.val, _MM_SHUFFLE(0, 0, 0, 0)), m0.val); + __m128 v1 = _mm_mul_ps(_mm_shuffle_ps(v.val, v.val, _MM_SHUFFLE(1, 1, 1, 1)), m1.val); + __m128 v2 = _mm_mul_ps(_mm_shuffle_ps(v.val, v.val, _MM_SHUFFLE(2, 2, 2, 2)), m2.val); + __m128 v3 = _mm_mul_ps(_mm_shuffle_ps(v.val, v.val, _MM_SHUFFLE(3, 3, 3, 3)), m3.val); + + return v_float32x4(_mm_add_ps(_mm_add_ps(v0, v1), _mm_add_ps(v2, v3))); +} + +inline v_float32x4 v_matmuladd(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& a) +{ + __m128 v0 = _mm_mul_ps(_mm_shuffle_ps(v.val, v.val, _MM_SHUFFLE(0, 0, 0, 0)), m0.val); + __m128 v1 = _mm_mul_ps(_mm_shuffle_ps(v.val, v.val, _MM_SHUFFLE(1, 1, 1, 1)), m1.val); + __m128 v2 = _mm_mul_ps(_mm_shuffle_ps(v.val, v.val, _MM_SHUFFLE(2, 2, 2, 2)), m2.val); + + return v_float32x4(_mm_add_ps(_mm_add_ps(v0, v1), _mm_add_ps(v2, a.val))); +} + +#define OPENCV_HAL_IMPL_SSE_BIN_OP(bin_op, _Tpvec, intrin) \ + inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \ + { \ + return _Tpvec(intrin(a.val, b.val)); \ + } \ + inline _Tpvec& operator bin_op##= (_Tpvec& a, const _Tpvec& b) \ + { \ + a.val = intrin(a.val, b.val); \ + return a; \ + } + +OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_uint8x16, _mm_adds_epu8) +OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_uint8x16, _mm_subs_epu8) +OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_int8x16, _mm_adds_epi8) +OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_int8x16, _mm_subs_epi8) +OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_uint16x8, _mm_adds_epu16) +OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_uint16x8, _mm_subs_epu16) +OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_int16x8, _mm_adds_epi16) +OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_int16x8, _mm_subs_epi16) +OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_uint32x4, _mm_add_epi32) +OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_uint32x4, _mm_sub_epi32) +OPENCV_HAL_IMPL_SSE_BIN_OP(*, v_uint32x4, _v128_mullo_epi32) +OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_int32x4, _mm_add_epi32) +OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_int32x4, _mm_sub_epi32) +OPENCV_HAL_IMPL_SSE_BIN_OP(*, v_int32x4, _v128_mullo_epi32) +OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_float32x4, _mm_add_ps) +OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_float32x4, _mm_sub_ps) +OPENCV_HAL_IMPL_SSE_BIN_OP(*, v_float32x4, _mm_mul_ps) +OPENCV_HAL_IMPL_SSE_BIN_OP(/, v_float32x4, _mm_div_ps) +OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_float64x2, _mm_add_pd) +OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_float64x2, _mm_sub_pd) +OPENCV_HAL_IMPL_SSE_BIN_OP(*, v_float64x2, _mm_mul_pd) +OPENCV_HAL_IMPL_SSE_BIN_OP(/, v_float64x2, _mm_div_pd) +OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_uint64x2, _mm_add_epi64) +OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_uint64x2, _mm_sub_epi64) +OPENCV_HAL_IMPL_SSE_BIN_OP(+, v_int64x2, _mm_add_epi64) +OPENCV_HAL_IMPL_SSE_BIN_OP(-, v_int64x2, _mm_sub_epi64) + +// saturating multiply 8-bit, 16-bit +#define OPENCV_HAL_IMPL_SSE_MUL_SAT(_Tpvec, _Tpwvec) \ + inline _Tpvec operator * (const _Tpvec& a, const _Tpvec& b) \ + { \ + _Tpwvec c, d; \ + v_mul_expand(a, b, c, d); \ + return v_pack(c, d); \ + } \ + inline _Tpvec& operator *= (_Tpvec& a, const _Tpvec& b) \ + { a = a * b; return a; } + +OPENCV_HAL_IMPL_SSE_MUL_SAT(v_uint8x16, v_uint16x8) +OPENCV_HAL_IMPL_SSE_MUL_SAT(v_int8x16, v_int16x8) +OPENCV_HAL_IMPL_SSE_MUL_SAT(v_uint16x8, v_uint32x4) +OPENCV_HAL_IMPL_SSE_MUL_SAT(v_int16x8, v_int32x4) + +// Multiply and expand +inline void v_mul_expand(const v_uint8x16& a, const v_uint8x16& b, + v_uint16x8& c, v_uint16x8& d) +{ + v_uint16x8 a0, a1, b0, b1; + v_expand(a, a0, a1); + v_expand(b, b0, b1); + c = v_mul_wrap(a0, b0); + d = v_mul_wrap(a1, b1); +} + +inline void v_mul_expand(const v_int8x16& a, const v_int8x16& b, + v_int16x8& c, v_int16x8& d) +{ + v_int16x8 a0, a1, b0, b1; + v_expand(a, a0, a1); + v_expand(b, b0, b1); + c = v_mul_wrap(a0, b0); + d = v_mul_wrap(a1, b1); +} + +inline void v_mul_expand(const v_int16x8& a, const v_int16x8& b, + v_int32x4& c, v_int32x4& d) +{ + __m128i v0 = _mm_mullo_epi16(a.val, b.val); + __m128i v1 = _mm_mulhi_epi16(a.val, b.val); + c.val = _mm_unpacklo_epi16(v0, v1); + d.val = _mm_unpackhi_epi16(v0, v1); +} + +inline void v_mul_expand(const v_uint16x8& a, const v_uint16x8& b, + v_uint32x4& c, v_uint32x4& d) +{ + __m128i v0 = _mm_mullo_epi16(a.val, b.val); + __m128i v1 = _mm_mulhi_epu16(a.val, b.val); + c.val = _mm_unpacklo_epi16(v0, v1); + d.val = _mm_unpackhi_epi16(v0, v1); +} + +inline void v_mul_expand(const v_uint32x4& a, const v_uint32x4& b, + v_uint64x2& c, v_uint64x2& d) +{ + __m128i c0 = _mm_mul_epu32(a.val, b.val); + __m128i c1 = _mm_mul_epu32(_mm_srli_epi64(a.val, 32), _mm_srli_epi64(b.val, 32)); + c.val = _mm_unpacklo_epi64(c0, c1); + d.val = _mm_unpackhi_epi64(c0, c1); +} + +inline v_int16x8 v_mul_hi(const v_int16x8& a, const v_int16x8& b) { return v_int16x8(_mm_mulhi_epi16(a.val, b.val)); } +inline v_uint16x8 v_mul_hi(const v_uint16x8& a, const v_uint16x8& b) { return v_uint16x8(_mm_mulhi_epu16(a.val, b.val)); } + +//////// Dot Product //////// + +// 16 >> 32 +inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b) +{ return v_int32x4(_mm_madd_epi16(a.val, b.val)); } +inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b, const v_int32x4& c) +{ return v_dotprod(a, b) + c; } + +// 32 >> 64 +inline v_int64x2 v_dotprod(const v_int32x4& a, const v_int32x4& b) +{ +#if CV_SSE4_1 + __m128i even = _mm_mul_epi32(a.val, b.val); + __m128i odd = _mm_mul_epi32(_mm_srli_epi64(a.val, 32), _mm_srli_epi64(b.val, 32)); + return v_int64x2(_mm_add_epi64(even, odd)); +#else + __m128i even_u = _mm_mul_epu32(a.val, b.val); + __m128i odd_u = _mm_mul_epu32(_mm_srli_epi64(a.val, 32), _mm_srli_epi64(b.val, 32)); + // convert unsigned to signed high multiplication (from: Agner Fog(veclib) and H S Warren: Hacker's delight, 2003, p. 132) + __m128i a_sign = _mm_srai_epi32(a.val, 31); + __m128i b_sign = _mm_srai_epi32(b.val, 31); + // |x * sign of x + __m128i axb = _mm_and_si128(a.val, b_sign); + __m128i bxa = _mm_and_si128(b.val, a_sign); + // sum of sign corrections + __m128i ssum = _mm_add_epi32(bxa, axb); + __m128i even_ssum = _mm_slli_epi64(ssum, 32); + __m128i odd_ssum = _mm_and_si128(ssum, _mm_set_epi32(-1, 0, -1, 0)); + // convert to signed and prod + return v_int64x2(_mm_add_epi64(_mm_sub_epi64(even_u, even_ssum), _mm_sub_epi64(odd_u, odd_ssum))); +#endif +} +inline v_int64x2 v_dotprod(const v_int32x4& a, const v_int32x4& b, const v_int64x2& c) +{ return v_dotprod(a, b) + c; } + +// 8 >> 32 +inline v_uint32x4 v_dotprod_expand(const v_uint8x16& a, const v_uint8x16& b) +{ + __m128i a0 = _mm_srli_epi16(_mm_slli_si128(a.val, 1), 8); // even + __m128i a1 = _mm_srli_epi16(a.val, 8); // odd + __m128i b0 = _mm_srli_epi16(_mm_slli_si128(b.val, 1), 8); + __m128i b1 = _mm_srli_epi16(b.val, 8); + __m128i p0 = _mm_madd_epi16(a0, b0); + __m128i p1 = _mm_madd_epi16(a1, b1); + return v_uint32x4(_mm_add_epi32(p0, p1)); +} +inline v_uint32x4 v_dotprod_expand(const v_uint8x16& a, const v_uint8x16& b, const v_uint32x4& c) +{ return v_dotprod_expand(a, b) + c; } + +inline v_int32x4 v_dotprod_expand(const v_int8x16& a, const v_int8x16& b) +{ + __m128i a0 = _mm_srai_epi16(_mm_slli_si128(a.val, 1), 8); // even + __m128i a1 = _mm_srai_epi16(a.val, 8); // odd + __m128i b0 = _mm_srai_epi16(_mm_slli_si128(b.val, 1), 8); + __m128i b1 = _mm_srai_epi16(b.val, 8); + __m128i p0 = _mm_madd_epi16(a0, b0); + __m128i p1 = _mm_madd_epi16(a1, b1); + return v_int32x4(_mm_add_epi32(p0, p1)); +} +inline v_int32x4 v_dotprod_expand(const v_int8x16& a, const v_int8x16& b, const v_int32x4& c) +{ return v_dotprod_expand(a, b) + c; } + +// 16 >> 64 +inline v_uint64x2 v_dotprod_expand(const v_uint16x8& a, const v_uint16x8& b) +{ + v_uint32x4 c, d; + v_mul_expand(a, b, c, d); + + v_uint64x2 c0, c1, d0, d1; + v_expand(c, c0, c1); + v_expand(d, d0, d1); + + c0 += c1; d0 += d1; + return v_uint64x2(_mm_add_epi64( + _mm_unpacklo_epi64(c0.val, d0.val), + _mm_unpackhi_epi64(c0.val, d0.val) + )); +} +inline v_uint64x2 v_dotprod_expand(const v_uint16x8& a, const v_uint16x8& b, const v_uint64x2& c) +{ return v_dotprod_expand(a, b) + c; } + +inline v_int64x2 v_dotprod_expand(const v_int16x8& a, const v_int16x8& b) +{ + v_int32x4 prod = v_dotprod(a, b); + v_int64x2 c, d; + v_expand(prod, c, d); + return v_int64x2(_mm_add_epi64( + _mm_unpacklo_epi64(c.val, d.val), + _mm_unpackhi_epi64(c.val, d.val) + )); +} +inline v_int64x2 v_dotprod_expand(const v_int16x8& a, const v_int16x8& b, const v_int64x2& c) +{ return v_dotprod_expand(a, b) + c; } + +// 32 >> 64f +inline v_float64x2 v_dotprod_expand(const v_int32x4& a, const v_int32x4& b) +{ +#if CV_SSE4_1 + return v_cvt_f64(v_dotprod(a, b)); +#else + v_float64x2 c = v_cvt_f64(a) * v_cvt_f64(b); + v_float64x2 d = v_cvt_f64_high(a) * v_cvt_f64_high(b); + + return v_float64x2(_mm_add_pd( + _mm_unpacklo_pd(c.val, d.val), + _mm_unpackhi_pd(c.val, d.val) + )); +#endif +} +inline v_float64x2 v_dotprod_expand(const v_int32x4& a, const v_int32x4& b, const v_float64x2& c) +{ return v_dotprod_expand(a, b) + c; } + +//////// Fast Dot Product //////// + +// 16 >> 32 +inline v_int32x4 v_dotprod_fast(const v_int16x8& a, const v_int16x8& b) +{ return v_dotprod(a, b); } +inline v_int32x4 v_dotprod_fast(const v_int16x8& a, const v_int16x8& b, const v_int32x4& c) +{ return v_dotprod(a, b) + c; } + +// 32 >> 64 +inline v_int64x2 v_dotprod_fast(const v_int32x4& a, const v_int32x4& b) +{ return v_dotprod(a, b); } +inline v_int64x2 v_dotprod_fast(const v_int32x4& a, const v_int32x4& b, const v_int64x2& c) +{ return v_dotprod_fast(a, b) + c; } + +// 8 >> 32 +inline v_uint32x4 v_dotprod_expand_fast(const v_uint8x16& a, const v_uint8x16& b) +{ + __m128i a0 = v_expand_low(a).val; + __m128i a1 = v_expand_high(a).val; + __m128i b0 = v_expand_low(b).val; + __m128i b1 = v_expand_high(b).val; + __m128i p0 = _mm_madd_epi16(a0, b0); + __m128i p1 = _mm_madd_epi16(a1, b1); + return v_uint32x4(_mm_add_epi32(p0, p1)); +} +inline v_uint32x4 v_dotprod_expand_fast(const v_uint8x16& a, const v_uint8x16& b, const v_uint32x4& c) +{ return v_dotprod_expand_fast(a, b) + c; } + +inline v_int32x4 v_dotprod_expand_fast(const v_int8x16& a, const v_int8x16& b) +{ +#if CV_SSE4_1 + __m128i a0 = _mm_cvtepi8_epi16(a.val); + __m128i a1 = v_expand_high(a).val; + __m128i b0 = _mm_cvtepi8_epi16(b.val); + __m128i b1 = v_expand_high(b).val; + __m128i p0 = _mm_madd_epi16(a0, b0); + __m128i p1 = _mm_madd_epi16(a1, b1); + return v_int32x4(_mm_add_epi32(p0, p1)); +#else + return v_dotprod_expand(a, b); +#endif +} +inline v_int32x4 v_dotprod_expand_fast(const v_int8x16& a, const v_int8x16& b, const v_int32x4& c) +{ return v_dotprod_expand_fast(a, b) + c; } + +// 16 >> 64 +inline v_uint64x2 v_dotprod_expand_fast(const v_uint16x8& a, const v_uint16x8& b) +{ + v_uint32x4 c, d; + v_mul_expand(a, b, c, d); + + v_uint64x2 c0, c1, d0, d1; + v_expand(c, c0, c1); + v_expand(d, d0, d1); + + c0 += c1; d0 += d1; + return c0 + d0; +} +inline v_uint64x2 v_dotprod_expand_fast(const v_uint16x8& a, const v_uint16x8& b, const v_uint64x2& c) +{ return v_dotprod_expand_fast(a, b) + c; } + +inline v_int64x2 v_dotprod_expand_fast(const v_int16x8& a, const v_int16x8& b) +{ + v_int32x4 prod = v_dotprod(a, b); + v_int64x2 c, d; + v_expand(prod, c, d); + return c + d; +} +inline v_int64x2 v_dotprod_expand_fast(const v_int16x8& a, const v_int16x8& b, const v_int64x2& c) +{ return v_dotprod_expand_fast(a, b) + c; } + +// 32 >> 64f +v_float64x2 v_fma(const v_float64x2& a, const v_float64x2& b, const v_float64x2& c); +inline v_float64x2 v_dotprod_expand_fast(const v_int32x4& a, const v_int32x4& b) +{ return v_fma(v_cvt_f64(a), v_cvt_f64(b), v_cvt_f64_high(a) * v_cvt_f64_high(b)); } +inline v_float64x2 v_dotprod_expand_fast(const v_int32x4& a, const v_int32x4& b, const v_float64x2& c) +{ return v_fma(v_cvt_f64(a), v_cvt_f64(b), v_fma(v_cvt_f64_high(a), v_cvt_f64_high(b), c)); } + +#define OPENCV_HAL_IMPL_SSE_LOGIC_OP(_Tpvec, suffix, not_const) \ + OPENCV_HAL_IMPL_SSE_BIN_OP(&, _Tpvec, _mm_and_##suffix) \ + OPENCV_HAL_IMPL_SSE_BIN_OP(|, _Tpvec, _mm_or_##suffix) \ + OPENCV_HAL_IMPL_SSE_BIN_OP(^, _Tpvec, _mm_xor_##suffix) \ + inline _Tpvec operator ~ (const _Tpvec& a) \ + { \ + return _Tpvec(_mm_xor_##suffix(a.val, not_const)); \ + } + +OPENCV_HAL_IMPL_SSE_LOGIC_OP(v_uint8x16, si128, _mm_set1_epi32(-1)) +OPENCV_HAL_IMPL_SSE_LOGIC_OP(v_int8x16, si128, _mm_set1_epi32(-1)) +OPENCV_HAL_IMPL_SSE_LOGIC_OP(v_uint16x8, si128, _mm_set1_epi32(-1)) +OPENCV_HAL_IMPL_SSE_LOGIC_OP(v_int16x8, si128, _mm_set1_epi32(-1)) +OPENCV_HAL_IMPL_SSE_LOGIC_OP(v_uint32x4, si128, _mm_set1_epi32(-1)) +OPENCV_HAL_IMPL_SSE_LOGIC_OP(v_int32x4, si128, _mm_set1_epi32(-1)) +OPENCV_HAL_IMPL_SSE_LOGIC_OP(v_uint64x2, si128, _mm_set1_epi32(-1)) +OPENCV_HAL_IMPL_SSE_LOGIC_OP(v_int64x2, si128, _mm_set1_epi32(-1)) +OPENCV_HAL_IMPL_SSE_LOGIC_OP(v_float32x4, ps, _mm_castsi128_ps(_mm_set1_epi32(-1))) +OPENCV_HAL_IMPL_SSE_LOGIC_OP(v_float64x2, pd, _mm_castsi128_pd(_mm_set1_epi32(-1))) + +inline v_float32x4 v_sqrt(const v_float32x4& x) +{ return v_float32x4(_mm_sqrt_ps(x.val)); } + +inline v_float32x4 v_invsqrt(const v_float32x4& x) +{ + const __m128 _0_5 = _mm_set1_ps(0.5f), _1_5 = _mm_set1_ps(1.5f); + __m128 t = x.val; + __m128 h = _mm_mul_ps(t, _0_5); + t = _mm_rsqrt_ps(t); + t = _mm_mul_ps(t, _mm_sub_ps(_1_5, _mm_mul_ps(_mm_mul_ps(t, t), h))); + return v_float32x4(t); +} + +inline v_float64x2 v_sqrt(const v_float64x2& x) +{ return v_float64x2(_mm_sqrt_pd(x.val)); } + +inline v_float64x2 v_invsqrt(const v_float64x2& x) +{ + const __m128d v_1 = _mm_set1_pd(1.); + return v_float64x2(_mm_div_pd(v_1, _mm_sqrt_pd(x.val))); +} + +#define OPENCV_HAL_IMPL_SSE_ABS_INT_FUNC(_Tpuvec, _Tpsvec, func, suffix, subWidth) \ +inline _Tpuvec v_abs(const _Tpsvec& x) \ +{ return _Tpuvec(_mm_##func##_ep##suffix(x.val, _mm_sub_ep##subWidth(_mm_setzero_si128(), x.val))); } + +OPENCV_HAL_IMPL_SSE_ABS_INT_FUNC(v_uint8x16, v_int8x16, min, u8, i8) +OPENCV_HAL_IMPL_SSE_ABS_INT_FUNC(v_uint16x8, v_int16x8, max, i16, i16) +inline v_uint32x4 v_abs(const v_int32x4& x) +{ + __m128i s = _mm_srli_epi32(x.val, 31); + __m128i f = _mm_srai_epi32(x.val, 31); + return v_uint32x4(_mm_add_epi32(_mm_xor_si128(x.val, f), s)); +} +inline v_float32x4 v_abs(const v_float32x4& x) +{ return v_float32x4(_mm_and_ps(x.val, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)))); } +inline v_float64x2 v_abs(const v_float64x2& x) +{ + return v_float64x2(_mm_and_pd(x.val, + _mm_castsi128_pd(_mm_srli_epi64(_mm_set1_epi32(-1), 1)))); +} + +// TODO: exp, log, sin, cos + +#define OPENCV_HAL_IMPL_SSE_BIN_FUNC(_Tpvec, func, intrin) \ +inline _Tpvec func(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(intrin(a.val, b.val)); \ +} + +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_uint8x16, v_min, _mm_min_epu8) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_uint8x16, v_max, _mm_max_epu8) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_int16x8, v_min, _mm_min_epi16) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_int16x8, v_max, _mm_max_epi16) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_float32x4, v_min, _mm_min_ps) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_float32x4, v_max, _mm_max_ps) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_float64x2, v_min, _mm_min_pd) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_float64x2, v_max, _mm_max_pd) + +inline v_int8x16 v_min(const v_int8x16& a, const v_int8x16& b) +{ +#if CV_SSE4_1 + return v_int8x16(_mm_min_epi8(a.val, b.val)); +#else + __m128i delta = _mm_set1_epi8((char)-128); + return v_int8x16(_mm_xor_si128(delta, _mm_min_epu8(_mm_xor_si128(a.val, delta), + _mm_xor_si128(b.val, delta)))); +#endif +} +inline v_int8x16 v_max(const v_int8x16& a, const v_int8x16& b) +{ +#if CV_SSE4_1 + return v_int8x16(_mm_max_epi8(a.val, b.val)); +#else + __m128i delta = _mm_set1_epi8((char)-128); + return v_int8x16(_mm_xor_si128(delta, _mm_max_epu8(_mm_xor_si128(a.val, delta), + _mm_xor_si128(b.val, delta)))); +#endif +} +inline v_uint16x8 v_min(const v_uint16x8& a, const v_uint16x8& b) +{ +#if CV_SSE4_1 + return v_uint16x8(_mm_min_epu16(a.val, b.val)); +#else + return v_uint16x8(_mm_subs_epu16(a.val, _mm_subs_epu16(a.val, b.val))); +#endif +} +inline v_uint16x8 v_max(const v_uint16x8& a, const v_uint16x8& b) +{ +#if CV_SSE4_1 + return v_uint16x8(_mm_max_epu16(a.val, b.val)); +#else + return v_uint16x8(_mm_adds_epu16(_mm_subs_epu16(a.val, b.val), b.val)); +#endif +} +inline v_uint32x4 v_min(const v_uint32x4& a, const v_uint32x4& b) +{ +#if CV_SSE4_1 + return v_uint32x4(_mm_min_epu32(a.val, b.val)); +#else + __m128i delta = _mm_set1_epi32((int)0x80000000); + __m128i mask = _mm_cmpgt_epi32(_mm_xor_si128(a.val, delta), _mm_xor_si128(b.val, delta)); + return v_uint32x4(v_select_si128(mask, b.val, a.val)); +#endif +} +inline v_uint32x4 v_max(const v_uint32x4& a, const v_uint32x4& b) +{ +#if CV_SSE4_1 + return v_uint32x4(_mm_max_epu32(a.val, b.val)); +#else + __m128i delta = _mm_set1_epi32((int)0x80000000); + __m128i mask = _mm_cmpgt_epi32(_mm_xor_si128(a.val, delta), _mm_xor_si128(b.val, delta)); + return v_uint32x4(v_select_si128(mask, a.val, b.val)); +#endif +} +inline v_int32x4 v_min(const v_int32x4& a, const v_int32x4& b) +{ +#if CV_SSE4_1 + return v_int32x4(_mm_min_epi32(a.val, b.val)); +#else + return v_int32x4(v_select_si128(_mm_cmpgt_epi32(a.val, b.val), b.val, a.val)); +#endif +} +inline v_int32x4 v_max(const v_int32x4& a, const v_int32x4& b) +{ +#if CV_SSE4_1 + return v_int32x4(_mm_max_epi32(a.val, b.val)); +#else + return v_int32x4(v_select_si128(_mm_cmpgt_epi32(a.val, b.val), a.val, b.val)); +#endif +} + +#define OPENCV_HAL_IMPL_SSE_INT_CMP_OP(_Tpuvec, _Tpsvec, suffix, sbit) \ +inline _Tpuvec operator == (const _Tpuvec& a, const _Tpuvec& b) \ +{ return _Tpuvec(_mm_cmpeq_##suffix(a.val, b.val)); } \ +inline _Tpuvec operator != (const _Tpuvec& a, const _Tpuvec& b) \ +{ \ + __m128i not_mask = _mm_set1_epi32(-1); \ + return _Tpuvec(_mm_xor_si128(_mm_cmpeq_##suffix(a.val, b.val), not_mask)); \ +} \ +inline _Tpsvec operator == (const _Tpsvec& a, const _Tpsvec& b) \ +{ return _Tpsvec(_mm_cmpeq_##suffix(a.val, b.val)); } \ +inline _Tpsvec operator != (const _Tpsvec& a, const _Tpsvec& b) \ +{ \ + __m128i not_mask = _mm_set1_epi32(-1); \ + return _Tpsvec(_mm_xor_si128(_mm_cmpeq_##suffix(a.val, b.val), not_mask)); \ +} \ +inline _Tpuvec operator < (const _Tpuvec& a, const _Tpuvec& b) \ +{ \ + __m128i smask = _mm_set1_##suffix(sbit); \ + return _Tpuvec(_mm_cmpgt_##suffix(_mm_xor_si128(b.val, smask), _mm_xor_si128(a.val, smask))); \ +} \ +inline _Tpuvec operator > (const _Tpuvec& a, const _Tpuvec& b) \ +{ \ + __m128i smask = _mm_set1_##suffix(sbit); \ + return _Tpuvec(_mm_cmpgt_##suffix(_mm_xor_si128(a.val, smask), _mm_xor_si128(b.val, smask))); \ +} \ +inline _Tpuvec operator <= (const _Tpuvec& a, const _Tpuvec& b) \ +{ \ + __m128i smask = _mm_set1_##suffix(sbit); \ + __m128i not_mask = _mm_set1_epi32(-1); \ + __m128i res = _mm_cmpgt_##suffix(_mm_xor_si128(a.val, smask), _mm_xor_si128(b.val, smask)); \ + return _Tpuvec(_mm_xor_si128(res, not_mask)); \ +} \ +inline _Tpuvec operator >= (const _Tpuvec& a, const _Tpuvec& b) \ +{ \ + __m128i smask = _mm_set1_##suffix(sbit); \ + __m128i not_mask = _mm_set1_epi32(-1); \ + __m128i res = _mm_cmpgt_##suffix(_mm_xor_si128(b.val, smask), _mm_xor_si128(a.val, smask)); \ + return _Tpuvec(_mm_xor_si128(res, not_mask)); \ +} \ +inline _Tpsvec operator < (const _Tpsvec& a, const _Tpsvec& b) \ +{ \ + return _Tpsvec(_mm_cmpgt_##suffix(b.val, a.val)); \ +} \ +inline _Tpsvec operator > (const _Tpsvec& a, const _Tpsvec& b) \ +{ \ + return _Tpsvec(_mm_cmpgt_##suffix(a.val, b.val)); \ +} \ +inline _Tpsvec operator <= (const _Tpsvec& a, const _Tpsvec& b) \ +{ \ + __m128i not_mask = _mm_set1_epi32(-1); \ + return _Tpsvec(_mm_xor_si128(_mm_cmpgt_##suffix(a.val, b.val), not_mask)); \ +} \ +inline _Tpsvec operator >= (const _Tpsvec& a, const _Tpsvec& b) \ +{ \ + __m128i not_mask = _mm_set1_epi32(-1); \ + return _Tpsvec(_mm_xor_si128(_mm_cmpgt_##suffix(b.val, a.val), not_mask)); \ +} + +OPENCV_HAL_IMPL_SSE_INT_CMP_OP(v_uint8x16, v_int8x16, epi8, (char)-128) +OPENCV_HAL_IMPL_SSE_INT_CMP_OP(v_uint16x8, v_int16x8, epi16, (short)-32768) +OPENCV_HAL_IMPL_SSE_INT_CMP_OP(v_uint32x4, v_int32x4, epi32, (int)0x80000000) + +#define OPENCV_HAL_IMPL_SSE_FLT_CMP_OP(_Tpvec, suffix) \ +inline _Tpvec operator == (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(_mm_cmpeq_##suffix(a.val, b.val)); } \ +inline _Tpvec operator != (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(_mm_cmpneq_##suffix(a.val, b.val)); } \ +inline _Tpvec operator < (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(_mm_cmplt_##suffix(a.val, b.val)); } \ +inline _Tpvec operator > (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(_mm_cmpgt_##suffix(a.val, b.val)); } \ +inline _Tpvec operator <= (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(_mm_cmple_##suffix(a.val, b.val)); } \ +inline _Tpvec operator >= (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(_mm_cmpge_##suffix(a.val, b.val)); } + +OPENCV_HAL_IMPL_SSE_FLT_CMP_OP(v_float32x4, ps) +OPENCV_HAL_IMPL_SSE_FLT_CMP_OP(v_float64x2, pd) + +#if CV_SSE4_1 +#define OPENCV_HAL_IMPL_SSE_64BIT_CMP_OP(_Tpvec) \ +inline _Tpvec operator == (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(_mm_cmpeq_epi64(a.val, b.val)); } \ +inline _Tpvec operator != (const _Tpvec& a, const _Tpvec& b) \ +{ return ~(a == b); } +#else +#define OPENCV_HAL_IMPL_SSE_64BIT_CMP_OP(_Tpvec) \ +inline _Tpvec operator == (const _Tpvec& a, const _Tpvec& b) \ +{ __m128i cmp = _mm_cmpeq_epi32(a.val, b.val); \ + return _Tpvec(_mm_and_si128(cmp, _mm_shuffle_epi32(cmp, _MM_SHUFFLE(2, 3, 0, 1)))); } \ +inline _Tpvec operator != (const _Tpvec& a, const _Tpvec& b) \ +{ return ~(a == b); } +#endif + +OPENCV_HAL_IMPL_SSE_64BIT_CMP_OP(v_uint64x2) +OPENCV_HAL_IMPL_SSE_64BIT_CMP_OP(v_int64x2) + +inline v_float32x4 v_not_nan(const v_float32x4& a) +{ return v_float32x4(_mm_cmpord_ps(a.val, a.val)); } +inline v_float64x2 v_not_nan(const v_float64x2& a) +{ return v_float64x2(_mm_cmpord_pd(a.val, a.val)); } + +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_uint8x16, v_add_wrap, _mm_add_epi8) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_int8x16, v_add_wrap, _mm_add_epi8) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_uint16x8, v_add_wrap, _mm_add_epi16) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_int16x8, v_add_wrap, _mm_add_epi16) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_uint8x16, v_sub_wrap, _mm_sub_epi8) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_int8x16, v_sub_wrap, _mm_sub_epi8) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_uint16x8, v_sub_wrap, _mm_sub_epi16) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_int16x8, v_sub_wrap, _mm_sub_epi16) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_uint16x8, v_mul_wrap, _mm_mullo_epi16) +OPENCV_HAL_IMPL_SSE_BIN_FUNC(v_int16x8, v_mul_wrap, _mm_mullo_epi16) + +inline v_uint8x16 v_mul_wrap(const v_uint8x16& a, const v_uint8x16& b) +{ + __m128i ad = _mm_srai_epi16(a.val, 8); + __m128i bd = _mm_srai_epi16(b.val, 8); + __m128i p0 = _mm_mullo_epi16(a.val, b.val); // even + __m128i p1 = _mm_slli_epi16(_mm_mullo_epi16(ad, bd), 8); // odd + const __m128i b01 = _mm_set1_epi32(0xFF00FF00); + return v_uint8x16(_v128_blendv_epi8(p0, p1, b01)); +} +inline v_int8x16 v_mul_wrap(const v_int8x16& a, const v_int8x16& b) +{ + return v_reinterpret_as_s8(v_mul_wrap(v_reinterpret_as_u8(a), v_reinterpret_as_u8(b))); +} + +/** Absolute difference **/ + +inline v_uint8x16 v_absdiff(const v_uint8x16& a, const v_uint8x16& b) +{ return v_add_wrap(a - b, b - a); } +inline v_uint16x8 v_absdiff(const v_uint16x8& a, const v_uint16x8& b) +{ return v_add_wrap(a - b, b - a); } +inline v_uint32x4 v_absdiff(const v_uint32x4& a, const v_uint32x4& b) +{ return v_max(a, b) - v_min(a, b); } + +inline v_uint8x16 v_absdiff(const v_int8x16& a, const v_int8x16& b) +{ + v_int8x16 d = v_sub_wrap(a, b); + v_int8x16 m = a < b; + return v_reinterpret_as_u8(v_sub_wrap(d ^ m, m)); +} +inline v_uint16x8 v_absdiff(const v_int16x8& a, const v_int16x8& b) +{ + return v_reinterpret_as_u16(v_sub_wrap(v_max(a, b), v_min(a, b))); +} +inline v_uint32x4 v_absdiff(const v_int32x4& a, const v_int32x4& b) +{ + v_int32x4 d = a - b; + v_int32x4 m = a < b; + return v_reinterpret_as_u32((d ^ m) - m); +} + +/** Saturating absolute difference **/ +inline v_int8x16 v_absdiffs(const v_int8x16& a, const v_int8x16& b) +{ + v_int8x16 d = a - b; + v_int8x16 m = a < b; + return (d ^ m) - m; + } +inline v_int16x8 v_absdiffs(const v_int16x8& a, const v_int16x8& b) +{ return v_max(a, b) - v_min(a, b); } + + +inline v_int32x4 v_fma(const v_int32x4& a, const v_int32x4& b, const v_int32x4& c) +{ + return a * b + c; +} + +inline v_int32x4 v_muladd(const v_int32x4& a, const v_int32x4& b, const v_int32x4& c) +{ + return v_fma(a, b, c); +} + +inline v_float32x4 v_fma(const v_float32x4& a, const v_float32x4& b, const v_float32x4& c) +{ +#if CV_FMA3 + return v_float32x4(_mm_fmadd_ps(a.val, b.val, c.val)); +#else + return v_float32x4(_mm_add_ps(_mm_mul_ps(a.val, b.val), c.val)); +#endif +} + +inline v_float64x2 v_fma(const v_float64x2& a, const v_float64x2& b, const v_float64x2& c) +{ +#if CV_FMA3 + return v_float64x2(_mm_fmadd_pd(a.val, b.val, c.val)); +#else + return v_float64x2(_mm_add_pd(_mm_mul_pd(a.val, b.val), c.val)); +#endif +} + +#define OPENCV_HAL_IMPL_SSE_MISC_FLT_OP(_Tpvec, _Tp, _Tpreg, suffix, absmask_vec) \ +inline _Tpvec v_absdiff(const _Tpvec& a, const _Tpvec& b) \ +{ \ + _Tpreg absmask = _mm_castsi128_##suffix(absmask_vec); \ + return _Tpvec(_mm_and_##suffix(_mm_sub_##suffix(a.val, b.val), absmask)); \ +} \ +inline _Tpvec v_magnitude(const _Tpvec& a, const _Tpvec& b) \ +{ \ + _Tpvec res = v_fma(a, a, b*b); \ + return _Tpvec(_mm_sqrt_##suffix(res.val)); \ +} \ +inline _Tpvec v_sqr_magnitude(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return v_fma(a, a, b*b); \ +} \ +inline _Tpvec v_muladd(const _Tpvec& a, const _Tpvec& b, const _Tpvec& c) \ +{ \ + return v_fma(a, b, c); \ +} + +OPENCV_HAL_IMPL_SSE_MISC_FLT_OP(v_float32x4, float, __m128, ps, _mm_set1_epi32((int)0x7fffffff)) +OPENCV_HAL_IMPL_SSE_MISC_FLT_OP(v_float64x2, double, __m128d, pd, _mm_srli_epi64(_mm_set1_epi32(-1), 1)) + +#define OPENCV_HAL_IMPL_SSE_SHIFT_OP(_Tpuvec, _Tpsvec, suffix, srai) \ +inline _Tpuvec operator << (const _Tpuvec& a, int imm) \ +{ \ + return _Tpuvec(_mm_slli_##suffix(a.val, imm)); \ +} \ +inline _Tpsvec operator << (const _Tpsvec& a, int imm) \ +{ \ + return _Tpsvec(_mm_slli_##suffix(a.val, imm)); \ +} \ +inline _Tpuvec operator >> (const _Tpuvec& a, int imm) \ +{ \ + return _Tpuvec(_mm_srli_##suffix(a.val, imm)); \ +} \ +inline _Tpsvec operator >> (const _Tpsvec& a, int imm) \ +{ \ + return _Tpsvec(srai(a.val, imm)); \ +} \ +template \ +inline _Tpuvec v_shl(const _Tpuvec& a) \ +{ \ + return _Tpuvec(_mm_slli_##suffix(a.val, imm)); \ +} \ +template \ +inline _Tpsvec v_shl(const _Tpsvec& a) \ +{ \ + return _Tpsvec(_mm_slli_##suffix(a.val, imm)); \ +} \ +template \ +inline _Tpuvec v_shr(const _Tpuvec& a) \ +{ \ + return _Tpuvec(_mm_srli_##suffix(a.val, imm)); \ +} \ +template \ +inline _Tpsvec v_shr(const _Tpsvec& a) \ +{ \ + return _Tpsvec(srai(a.val, imm)); \ +} + +OPENCV_HAL_IMPL_SSE_SHIFT_OP(v_uint16x8, v_int16x8, epi16, _mm_srai_epi16) +OPENCV_HAL_IMPL_SSE_SHIFT_OP(v_uint32x4, v_int32x4, epi32, _mm_srai_epi32) +OPENCV_HAL_IMPL_SSE_SHIFT_OP(v_uint64x2, v_int64x2, epi64, v_srai_epi64) + +namespace hal_sse_internal +{ + template 16)), + bool is_first = (imm == 0), + bool is_half = (imm == 8), + bool is_second = (imm == 16), + bool is_other = (((imm > 0) && (imm < 8)) || ((imm > 8) && (imm < 16)))> + class v_sse_palignr_u8_class; + + template + class v_sse_palignr_u8_class; + + template + class v_sse_palignr_u8_class + { + public: + inline __m128i operator()(const __m128i& a, const __m128i&) const + { + return a; + } + }; + + template + class v_sse_palignr_u8_class + { + public: + inline __m128i operator()(const __m128i& a, const __m128i& b) const + { + return _mm_unpacklo_epi64(_mm_unpackhi_epi64(a, a), b); + } + }; + + template + class v_sse_palignr_u8_class + { + public: + inline __m128i operator()(const __m128i&, const __m128i& b) const + { + return b; + } + }; + + template + class v_sse_palignr_u8_class + { +#if CV_SSSE3 + public: + inline __m128i operator()(const __m128i& a, const __m128i& b) const + { + return _mm_alignr_epi8(b, a, imm); + } +#else + public: + inline __m128i operator()(const __m128i& a, const __m128i& b) const + { + enum { imm2 = (sizeof(__m128i) - imm) }; + return _mm_or_si128(_mm_srli_si128(a, imm), _mm_slli_si128(b, imm2)); + } +#endif + }; + + template + inline __m128i v_sse_palignr_u8(const __m128i& a, const __m128i& b) + { + CV_StaticAssert((imm >= 0) && (imm <= 16), "Invalid imm for v_sse_palignr_u8."); + return v_sse_palignr_u8_class()(a, b); + } +} + +template +inline _Tpvec v_rotate_right(const _Tpvec &a) +{ + using namespace hal_sse_internal; + enum { imm2 = (imm * sizeof(typename _Tpvec::lane_type)) }; + return _Tpvec(v_sse_reinterpret_as( + _mm_srli_si128( + v_sse_reinterpret_as<__m128i>(a.val), imm2))); +} + +template +inline _Tpvec v_rotate_left(const _Tpvec &a) +{ + using namespace hal_sse_internal; + enum { imm2 = (imm * sizeof(typename _Tpvec::lane_type)) }; + return _Tpvec(v_sse_reinterpret_as( + _mm_slli_si128( + v_sse_reinterpret_as<__m128i>(a.val), imm2))); +} + +template +inline _Tpvec v_rotate_right(const _Tpvec &a, const _Tpvec &b) +{ + using namespace hal_sse_internal; + enum { imm2 = (imm * sizeof(typename _Tpvec::lane_type)) }; + return _Tpvec(v_sse_reinterpret_as( + v_sse_palignr_u8( + v_sse_reinterpret_as<__m128i>(a.val), + v_sse_reinterpret_as<__m128i>(b.val)))); +} + +template +inline _Tpvec v_rotate_left(const _Tpvec &a, const _Tpvec &b) +{ + using namespace hal_sse_internal; + enum { imm2 = ((_Tpvec::nlanes - imm) * sizeof(typename _Tpvec::lane_type)) }; + return _Tpvec(v_sse_reinterpret_as( + v_sse_palignr_u8( + v_sse_reinterpret_as<__m128i>(b.val), + v_sse_reinterpret_as<__m128i>(a.val)))); +} + +#define OPENCV_HAL_IMPL_SSE_LOADSTORE_INT_OP(_Tpvec, _Tp) \ +inline _Tpvec v_load(const _Tp* ptr) \ +{ return _Tpvec(_mm_loadu_si128((const __m128i*)ptr)); } \ +inline _Tpvec v_load_aligned(const _Tp* ptr) \ +{ return _Tpvec(_mm_load_si128((const __m128i*)ptr)); } \ +inline _Tpvec v_load_low(const _Tp* ptr) \ +{ return _Tpvec(_mm_loadl_epi64((const __m128i*)ptr)); } \ +inline _Tpvec v_load_halves(const _Tp* ptr0, const _Tp* ptr1) \ +{ \ + return _Tpvec(_mm_unpacklo_epi64(_mm_loadl_epi64((const __m128i*)ptr0), \ + _mm_loadl_epi64((const __m128i*)ptr1))); \ +} \ +inline void v_store(_Tp* ptr, const _Tpvec& a) \ +{ _mm_storeu_si128((__m128i*)ptr, a.val); } \ +inline void v_store_aligned(_Tp* ptr, const _Tpvec& a) \ +{ _mm_store_si128((__m128i*)ptr, a.val); } \ +inline void v_store_aligned_nocache(_Tp* ptr, const _Tpvec& a) \ +{ _mm_stream_si128((__m128i*)ptr, a.val); } \ +inline void v_store(_Tp* ptr, const _Tpvec& a, hal::StoreMode mode) \ +{ \ + if( mode == hal::STORE_UNALIGNED ) \ + _mm_storeu_si128((__m128i*)ptr, a.val); \ + else if( mode == hal::STORE_ALIGNED_NOCACHE ) \ + _mm_stream_si128((__m128i*)ptr, a.val); \ + else \ + _mm_store_si128((__m128i*)ptr, a.val); \ +} \ +inline void v_store_low(_Tp* ptr, const _Tpvec& a) \ +{ _mm_storel_epi64((__m128i*)ptr, a.val); } \ +inline void v_store_high(_Tp* ptr, const _Tpvec& a) \ +{ _mm_storel_epi64((__m128i*)ptr, _mm_unpackhi_epi64(a.val, a.val)); } + +OPENCV_HAL_IMPL_SSE_LOADSTORE_INT_OP(v_uint8x16, uchar) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INT_OP(v_int8x16, schar) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INT_OP(v_uint16x8, ushort) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INT_OP(v_int16x8, short) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INT_OP(v_uint32x4, unsigned) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INT_OP(v_int32x4, int) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INT_OP(v_uint64x2, uint64) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INT_OP(v_int64x2, int64) + +#define OPENCV_HAL_IMPL_SSE_LOADSTORE_FLT_OP(_Tpvec, _Tp, suffix) \ +inline _Tpvec v_load(const _Tp* ptr) \ +{ return _Tpvec(_mm_loadu_##suffix(ptr)); } \ +inline _Tpvec v_load_aligned(const _Tp* ptr) \ +{ return _Tpvec(_mm_load_##suffix(ptr)); } \ +inline _Tpvec v_load_low(const _Tp* ptr) \ +{ return _Tpvec(_mm_castsi128_##suffix(_mm_loadl_epi64((const __m128i*)ptr))); } \ +inline _Tpvec v_load_halves(const _Tp* ptr0, const _Tp* ptr1) \ +{ \ + return _Tpvec(_mm_castsi128_##suffix( \ + _mm_unpacklo_epi64(_mm_loadl_epi64((const __m128i*)ptr0), \ + _mm_loadl_epi64((const __m128i*)ptr1)))); \ +} \ +inline void v_store(_Tp* ptr, const _Tpvec& a) \ +{ _mm_storeu_##suffix(ptr, a.val); } \ +inline void v_store_aligned(_Tp* ptr, const _Tpvec& a) \ +{ _mm_store_##suffix(ptr, a.val); } \ +inline void v_store_aligned_nocache(_Tp* ptr, const _Tpvec& a) \ +{ _mm_stream_##suffix(ptr, a.val); } \ +inline void v_store(_Tp* ptr, const _Tpvec& a, hal::StoreMode mode) \ +{ \ + if( mode == hal::STORE_UNALIGNED ) \ + _mm_storeu_##suffix(ptr, a.val); \ + else if( mode == hal::STORE_ALIGNED_NOCACHE ) \ + _mm_stream_##suffix(ptr, a.val); \ + else \ + _mm_store_##suffix(ptr, a.val); \ +} \ +inline void v_store_low(_Tp* ptr, const _Tpvec& a) \ +{ _mm_storel_epi64((__m128i*)ptr, _mm_cast##suffix##_si128(a.val)); } \ +inline void v_store_high(_Tp* ptr, const _Tpvec& a) \ +{ \ + __m128i a1 = _mm_cast##suffix##_si128(a.val); \ + _mm_storel_epi64((__m128i*)ptr, _mm_unpackhi_epi64(a1, a1)); \ +} + +OPENCV_HAL_IMPL_SSE_LOADSTORE_FLT_OP(v_float32x4, float, ps) +OPENCV_HAL_IMPL_SSE_LOADSTORE_FLT_OP(v_float64x2, double, pd) + +inline unsigned v_reduce_sum(const v_uint8x16& a) +{ + __m128i half = _mm_sad_epu8(a.val, _mm_setzero_si128()); + return (unsigned)_mm_cvtsi128_si32(_mm_add_epi32(half, _mm_unpackhi_epi64(half, half))); +} +inline int v_reduce_sum(const v_int8x16& a) +{ + __m128i half = _mm_set1_epi8((schar)-128); + half = _mm_sad_epu8(_mm_xor_si128(a.val, half), _mm_setzero_si128()); + return _mm_cvtsi128_si32(_mm_add_epi32(half, _mm_unpackhi_epi64(half, half))) - 2048; +} +#define OPENCV_HAL_IMPL_SSE_REDUCE_OP_16(func) \ +inline schar v_reduce_##func(const v_int8x16& a) \ +{ \ + __m128i val = a.val; \ + __m128i smask = _mm_set1_epi8((schar)-128); \ + val = _mm_xor_si128(val, smask); \ + val = _mm_##func##_epu8(val, _mm_srli_si128(val,8)); \ + val = _mm_##func##_epu8(val, _mm_srli_si128(val,4)); \ + val = _mm_##func##_epu8(val, _mm_srli_si128(val,2)); \ + val = _mm_##func##_epu8(val, _mm_srli_si128(val,1)); \ + return (schar)_mm_cvtsi128_si32(val) ^ (schar)-128; \ +} \ +inline uchar v_reduce_##func(const v_uint8x16& a) \ +{ \ + __m128i val = a.val; \ + val = _mm_##func##_epu8(val, _mm_srli_si128(val,8)); \ + val = _mm_##func##_epu8(val, _mm_srli_si128(val,4)); \ + val = _mm_##func##_epu8(val, _mm_srli_si128(val,2)); \ + val = _mm_##func##_epu8(val, _mm_srli_si128(val,1)); \ + return (uchar)_mm_cvtsi128_si32(val); \ +} +OPENCV_HAL_IMPL_SSE_REDUCE_OP_16(max) +OPENCV_HAL_IMPL_SSE_REDUCE_OP_16(min) + +#define OPENCV_HAL_IMPL_SSE_REDUCE_OP_8(_Tpvec, scalartype, func, suffix, sbit) \ +inline scalartype v_reduce_##func(const v_##_Tpvec& a) \ +{ \ + __m128i val = a.val; \ + val = _mm_##func##_##suffix(val, _mm_srli_si128(val,8)); \ + val = _mm_##func##_##suffix(val, _mm_srli_si128(val,4)); \ + val = _mm_##func##_##suffix(val, _mm_srli_si128(val,2)); \ + return (scalartype)_mm_cvtsi128_si32(val); \ +} \ +inline unsigned scalartype v_reduce_##func(const v_u##_Tpvec& a) \ +{ \ + __m128i val = a.val; \ + __m128i smask = _mm_set1_epi16(sbit); \ + val = _mm_xor_si128(val, smask); \ + val = _mm_##func##_##suffix(val, _mm_srli_si128(val,8)); \ + val = _mm_##func##_##suffix(val, _mm_srli_si128(val,4)); \ + val = _mm_##func##_##suffix(val, _mm_srli_si128(val,2)); \ + return (unsigned scalartype)(_mm_cvtsi128_si32(val) ^ sbit); \ +} +OPENCV_HAL_IMPL_SSE_REDUCE_OP_8(int16x8, short, max, epi16, (short)-32768) +OPENCV_HAL_IMPL_SSE_REDUCE_OP_8(int16x8, short, min, epi16, (short)-32768) + +#define OPENCV_HAL_IMPL_SSE_REDUCE_OP_4_SUM(_Tpvec, scalartype, regtype, suffix, cast_from, cast_to, extract) \ +inline scalartype v_reduce_sum(const _Tpvec& a) \ +{ \ + regtype val = a.val; \ + val = _mm_add_##suffix(val, cast_to(_mm_srli_si128(cast_from(val), 8))); \ + val = _mm_add_##suffix(val, cast_to(_mm_srli_si128(cast_from(val), 4))); \ + return (scalartype)_mm_cvt##extract(val); \ +} + +#define OPENCV_HAL_IMPL_SSE_REDUCE_OP_4(_Tpvec, scalartype, func, scalar_func) \ +inline scalartype v_reduce_##func(const _Tpvec& a) \ +{ \ + scalartype CV_DECL_ALIGNED(16) buf[4]; \ + v_store_aligned(buf, a); \ + scalartype s0 = scalar_func(buf[0], buf[1]); \ + scalartype s1 = scalar_func(buf[2], buf[3]); \ + return scalar_func(s0, s1); \ +} + +OPENCV_HAL_IMPL_SSE_REDUCE_OP_4_SUM(v_uint32x4, unsigned, __m128i, epi32, OPENCV_HAL_NOP, OPENCV_HAL_NOP, si128_si32) +OPENCV_HAL_IMPL_SSE_REDUCE_OP_4_SUM(v_int32x4, int, __m128i, epi32, OPENCV_HAL_NOP, OPENCV_HAL_NOP, si128_si32) +OPENCV_HAL_IMPL_SSE_REDUCE_OP_4_SUM(v_float32x4, float, __m128, ps, _mm_castps_si128, _mm_castsi128_ps, ss_f32) + +inline int v_reduce_sum(const v_int16x8& a) +{ return v_reduce_sum(v_expand_low(a) + v_expand_high(a)); } +inline unsigned v_reduce_sum(const v_uint16x8& a) +{ return v_reduce_sum(v_expand_low(a) + v_expand_high(a)); } + +inline uint64 v_reduce_sum(const v_uint64x2& a) +{ + uint64 CV_DECL_ALIGNED(32) idx[2]; + v_store_aligned(idx, a); + return idx[0] + idx[1]; +} +inline int64 v_reduce_sum(const v_int64x2& a) +{ + int64 CV_DECL_ALIGNED(32) idx[2]; + v_store_aligned(idx, a); + return idx[0] + idx[1]; +} +inline double v_reduce_sum(const v_float64x2& a) +{ + double CV_DECL_ALIGNED(32) idx[2]; + v_store_aligned(idx, a); + return idx[0] + idx[1]; +} + +inline v_float32x4 v_reduce_sum4(const v_float32x4& a, const v_float32x4& b, + const v_float32x4& c, const v_float32x4& d) +{ +#if CV_SSE3 + __m128 ab = _mm_hadd_ps(a.val, b.val); + __m128 cd = _mm_hadd_ps(c.val, d.val); + return v_float32x4(_mm_hadd_ps(ab, cd)); +#else + __m128 ac = _mm_add_ps(_mm_unpacklo_ps(a.val, c.val), _mm_unpackhi_ps(a.val, c.val)); + __m128 bd = _mm_add_ps(_mm_unpacklo_ps(b.val, d.val), _mm_unpackhi_ps(b.val, d.val)); + return v_float32x4(_mm_add_ps(_mm_unpacklo_ps(ac, bd), _mm_unpackhi_ps(ac, bd))); +#endif +} + +OPENCV_HAL_IMPL_SSE_REDUCE_OP_4(v_uint32x4, unsigned, max, std::max) +OPENCV_HAL_IMPL_SSE_REDUCE_OP_4(v_uint32x4, unsigned, min, std::min) +OPENCV_HAL_IMPL_SSE_REDUCE_OP_4(v_int32x4, int, max, std::max) +OPENCV_HAL_IMPL_SSE_REDUCE_OP_4(v_int32x4, int, min, std::min) +OPENCV_HAL_IMPL_SSE_REDUCE_OP_4(v_float32x4, float, max, std::max) +OPENCV_HAL_IMPL_SSE_REDUCE_OP_4(v_float32x4, float, min, std::min) + +inline unsigned v_reduce_sad(const v_uint8x16& a, const v_uint8x16& b) +{ + __m128i half = _mm_sad_epu8(a.val, b.val); + return (unsigned)_mm_cvtsi128_si32(_mm_add_epi32(half, _mm_unpackhi_epi64(half, half))); +} +inline unsigned v_reduce_sad(const v_int8x16& a, const v_int8x16& b) +{ + __m128i half = _mm_set1_epi8(0x7f); + half = _mm_sad_epu8(_mm_add_epi8(a.val, half), _mm_add_epi8(b.val, half)); + return (unsigned)_mm_cvtsi128_si32(_mm_add_epi32(half, _mm_unpackhi_epi64(half, half))); +} +inline unsigned v_reduce_sad(const v_uint16x8& a, const v_uint16x8& b) +{ + v_uint32x4 l, h; + v_expand(v_absdiff(a, b), l, h); + return v_reduce_sum(l + h); +} +inline unsigned v_reduce_sad(const v_int16x8& a, const v_int16x8& b) +{ + v_uint32x4 l, h; + v_expand(v_absdiff(a, b), l, h); + return v_reduce_sum(l + h); +} +inline unsigned v_reduce_sad(const v_uint32x4& a, const v_uint32x4& b) +{ + return v_reduce_sum(v_absdiff(a, b)); +} +inline unsigned v_reduce_sad(const v_int32x4& a, const v_int32x4& b) +{ + return v_reduce_sum(v_absdiff(a, b)); +} +inline float v_reduce_sad(const v_float32x4& a, const v_float32x4& b) +{ + return v_reduce_sum(v_absdiff(a, b)); +} + +inline v_uint8x16 v_popcount(const v_uint8x16& a) +{ + __m128i m1 = _mm_set1_epi32(0x55555555); + __m128i m2 = _mm_set1_epi32(0x33333333); + __m128i m4 = _mm_set1_epi32(0x0f0f0f0f); + __m128i p = a.val; + p = _mm_add_epi32(_mm_and_si128(_mm_srli_epi32(p, 1), m1), _mm_and_si128(p, m1)); + p = _mm_add_epi32(_mm_and_si128(_mm_srli_epi32(p, 2), m2), _mm_and_si128(p, m2)); + p = _mm_add_epi32(_mm_and_si128(_mm_srli_epi32(p, 4), m4), _mm_and_si128(p, m4)); + return v_uint8x16(p); +} +inline v_uint16x8 v_popcount(const v_uint16x8& a) +{ + v_uint8x16 p = v_popcount(v_reinterpret_as_u8(a)); + p += v_rotate_right<1>(p); + return v_reinterpret_as_u16(p) & v_setall_u16(0x00ff); +} +inline v_uint32x4 v_popcount(const v_uint32x4& a) +{ + v_uint8x16 p = v_popcount(v_reinterpret_as_u8(a)); + p += v_rotate_right<1>(p); + p += v_rotate_right<2>(p); + return v_reinterpret_as_u32(p) & v_setall_u32(0x000000ff); +} +inline v_uint64x2 v_popcount(const v_uint64x2& a) +{ + return v_uint64x2(_mm_sad_epu8(v_popcount(v_reinterpret_as_u8(a)).val, _mm_setzero_si128())); +} +inline v_uint8x16 v_popcount(const v_int8x16& a) +{ return v_popcount(v_reinterpret_as_u8(a)); } +inline v_uint16x8 v_popcount(const v_int16x8& a) +{ return v_popcount(v_reinterpret_as_u16(a)); } +inline v_uint32x4 v_popcount(const v_int32x4& a) +{ return v_popcount(v_reinterpret_as_u32(a)); } +inline v_uint64x2 v_popcount(const v_int64x2& a) +{ return v_popcount(v_reinterpret_as_u64(a)); } + +#define OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(_Tpvec, suffix, cast_op, allmask) \ +inline int v_signmask(const _Tpvec& a) { return _mm_movemask_##suffix(cast_op(a.val)); } \ +inline bool v_check_all(const _Tpvec& a) { return _mm_movemask_##suffix(cast_op(a.val)) == allmask; } \ +inline bool v_check_any(const _Tpvec& a) { return _mm_movemask_##suffix(cast_op(a.val)) != 0; } +OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_uint8x16, epi8, OPENCV_HAL_NOP, 65535) +OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_int8x16, epi8, OPENCV_HAL_NOP, 65535) +OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_uint32x4, ps, _mm_castsi128_ps, 15) +OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_int32x4, ps, _mm_castsi128_ps, 15) +OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_uint64x2, pd, _mm_castsi128_pd, 3) +OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_int64x2, pd, _mm_castsi128_pd, 3) +OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_float32x4, ps, OPENCV_HAL_NOP, 15) +OPENCV_HAL_IMPL_SSE_CHECK_SIGNS(v_float64x2, pd, OPENCV_HAL_NOP, 3) + +#define OPENCV_HAL_IMPL_SSE_CHECK_SIGNS_SHORT(_Tpvec) \ +inline int v_signmask(const _Tpvec& a) { return _mm_movemask_epi8(_mm_packs_epi16(a.val, a.val)) & 255; } \ +inline bool v_check_all(const _Tpvec& a) { return (_mm_movemask_epi8(a.val) & 0xaaaa) == 0xaaaa; } \ +inline bool v_check_any(const _Tpvec& a) { return (_mm_movemask_epi8(a.val) & 0xaaaa) != 0; } +OPENCV_HAL_IMPL_SSE_CHECK_SIGNS_SHORT(v_uint16x8) +OPENCV_HAL_IMPL_SSE_CHECK_SIGNS_SHORT(v_int16x8) + +inline int v_scan_forward(const v_int8x16& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))); } +inline int v_scan_forward(const v_uint8x16& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))); } +inline int v_scan_forward(const v_int16x8& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 2; } +inline int v_scan_forward(const v_uint16x8& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 2; } +inline int v_scan_forward(const v_int32x4& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 4; } +inline int v_scan_forward(const v_uint32x4& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 4; } +inline int v_scan_forward(const v_float32x4& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 4; } +inline int v_scan_forward(const v_int64x2& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 8; } +inline int v_scan_forward(const v_uint64x2& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 8; } +inline int v_scan_forward(const v_float64x2& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 8; } + +#if CV_SSE4_1 +#define OPENCV_HAL_IMPL_SSE_SELECT(_Tpvec, cast_ret, cast, suffix) \ +inline _Tpvec v_select(const _Tpvec& mask, const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(cast_ret(_mm_blendv_##suffix(cast(b.val), cast(a.val), cast(mask.val)))); \ +} + +OPENCV_HAL_IMPL_SSE_SELECT(v_uint8x16, OPENCV_HAL_NOP, OPENCV_HAL_NOP, epi8) +OPENCV_HAL_IMPL_SSE_SELECT(v_int8x16, OPENCV_HAL_NOP, OPENCV_HAL_NOP, epi8) +OPENCV_HAL_IMPL_SSE_SELECT(v_uint16x8, OPENCV_HAL_NOP, OPENCV_HAL_NOP, epi8) +OPENCV_HAL_IMPL_SSE_SELECT(v_int16x8, OPENCV_HAL_NOP, OPENCV_HAL_NOP, epi8) +OPENCV_HAL_IMPL_SSE_SELECT(v_uint32x4, _mm_castps_si128, _mm_castsi128_ps, ps) +OPENCV_HAL_IMPL_SSE_SELECT(v_int32x4, _mm_castps_si128, _mm_castsi128_ps, ps) +// OPENCV_HAL_IMPL_SSE_SELECT(v_uint64x2, TBD, TBD, pd) +// OPENCV_HAL_IMPL_SSE_SELECT(v_int64x2, TBD, TBD, ps) +OPENCV_HAL_IMPL_SSE_SELECT(v_float32x4, OPENCV_HAL_NOP, OPENCV_HAL_NOP, ps) +OPENCV_HAL_IMPL_SSE_SELECT(v_float64x2, OPENCV_HAL_NOP, OPENCV_HAL_NOP, pd) + +#else // CV_SSE4_1 + +#define OPENCV_HAL_IMPL_SSE_SELECT(_Tpvec, suffix) \ +inline _Tpvec v_select(const _Tpvec& mask, const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(_mm_xor_##suffix(b.val, _mm_and_##suffix(_mm_xor_##suffix(b.val, a.val), mask.val))); \ +} + +OPENCV_HAL_IMPL_SSE_SELECT(v_uint8x16, si128) +OPENCV_HAL_IMPL_SSE_SELECT(v_int8x16, si128) +OPENCV_HAL_IMPL_SSE_SELECT(v_uint16x8, si128) +OPENCV_HAL_IMPL_SSE_SELECT(v_int16x8, si128) +OPENCV_HAL_IMPL_SSE_SELECT(v_uint32x4, si128) +OPENCV_HAL_IMPL_SSE_SELECT(v_int32x4, si128) +// OPENCV_HAL_IMPL_SSE_SELECT(v_uint64x2, si128) +// OPENCV_HAL_IMPL_SSE_SELECT(v_int64x2, si128) +OPENCV_HAL_IMPL_SSE_SELECT(v_float32x4, ps) +OPENCV_HAL_IMPL_SSE_SELECT(v_float64x2, pd) +#endif + +/* Expand */ +#define OPENCV_HAL_IMPL_SSE_EXPAND(_Tpvec, _Tpwvec, _Tp, intrin) \ + inline void v_expand(const _Tpvec& a, _Tpwvec& b0, _Tpwvec& b1) \ + { \ + b0.val = intrin(a.val); \ + b1.val = __CV_CAT(intrin, _high)(a.val); \ + } \ + inline _Tpwvec v_expand_low(const _Tpvec& a) \ + { return _Tpwvec(intrin(a.val)); } \ + inline _Tpwvec v_expand_high(const _Tpvec& a) \ + { return _Tpwvec(__CV_CAT(intrin, _high)(a.val)); } \ + inline _Tpwvec v_load_expand(const _Tp* ptr) \ + { \ + __m128i a = _mm_loadl_epi64((const __m128i*)ptr); \ + return _Tpwvec(intrin(a)); \ + } + +OPENCV_HAL_IMPL_SSE_EXPAND(v_uint8x16, v_uint16x8, uchar, _v128_cvtepu8_epi16) +OPENCV_HAL_IMPL_SSE_EXPAND(v_int8x16, v_int16x8, schar, _v128_cvtepi8_epi16) +OPENCV_HAL_IMPL_SSE_EXPAND(v_uint16x8, v_uint32x4, ushort, _v128_cvtepu16_epi32) +OPENCV_HAL_IMPL_SSE_EXPAND(v_int16x8, v_int32x4, short, _v128_cvtepi16_epi32) +OPENCV_HAL_IMPL_SSE_EXPAND(v_uint32x4, v_uint64x2, unsigned, _v128_cvtepu32_epi64) +OPENCV_HAL_IMPL_SSE_EXPAND(v_int32x4, v_int64x2, int, _v128_cvtepi32_epi64) + +#define OPENCV_HAL_IMPL_SSE_EXPAND_Q(_Tpvec, _Tp, intrin) \ + inline _Tpvec v_load_expand_q(const _Tp* ptr) \ + { \ + __m128i a = _mm_cvtsi32_si128(*(const int*)ptr); \ + return _Tpvec(intrin(a)); \ + } + +OPENCV_HAL_IMPL_SSE_EXPAND_Q(v_uint32x4, uchar, _v128_cvtepu8_epi32) +OPENCV_HAL_IMPL_SSE_EXPAND_Q(v_int32x4, schar, _v128_cvtepi8_epi32) + +#define OPENCV_HAL_IMPL_SSE_UNPACKS(_Tpvec, suffix, cast_from, cast_to) \ +inline void v_zip(const _Tpvec& a0, const _Tpvec& a1, _Tpvec& b0, _Tpvec& b1) \ +{ \ + b0.val = _mm_unpacklo_##suffix(a0.val, a1.val); \ + b1.val = _mm_unpackhi_##suffix(a0.val, a1.val); \ +} \ +inline _Tpvec v_combine_low(const _Tpvec& a, const _Tpvec& b) \ +{ \ + __m128i a1 = cast_from(a.val), b1 = cast_from(b.val); \ + return _Tpvec(cast_to(_mm_unpacklo_epi64(a1, b1))); \ +} \ +inline _Tpvec v_combine_high(const _Tpvec& a, const _Tpvec& b) \ +{ \ + __m128i a1 = cast_from(a.val), b1 = cast_from(b.val); \ + return _Tpvec(cast_to(_mm_unpackhi_epi64(a1, b1))); \ +} \ +inline void v_recombine(const _Tpvec& a, const _Tpvec& b, _Tpvec& c, _Tpvec& d) \ +{ \ + __m128i a1 = cast_from(a.val), b1 = cast_from(b.val); \ + c.val = cast_to(_mm_unpacklo_epi64(a1, b1)); \ + d.val = cast_to(_mm_unpackhi_epi64(a1, b1)); \ +} + +OPENCV_HAL_IMPL_SSE_UNPACKS(v_uint8x16, epi8, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_UNPACKS(v_int8x16, epi8, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_UNPACKS(v_uint16x8, epi16, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_UNPACKS(v_int16x8, epi16, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_UNPACKS(v_uint32x4, epi32, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_UNPACKS(v_int32x4, epi32, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_UNPACKS(v_float32x4, ps, _mm_castps_si128, _mm_castsi128_ps) +OPENCV_HAL_IMPL_SSE_UNPACKS(v_float64x2, pd, _mm_castpd_si128, _mm_castsi128_pd) + +inline v_uint8x16 v_reverse(const v_uint8x16 &a) +{ +#if CV_SSSE3 + static const __m128i perm = _mm_setr_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + return v_uint8x16(_mm_shuffle_epi8(a.val, perm)); +#else + uchar CV_DECL_ALIGNED(32) d[16]; + v_store_aligned(d, a); + return v_uint8x16(d[15], d[14], d[13], d[12], d[11], d[10], d[9], d[8], d[7], d[6], d[5], d[4], d[3], d[2], d[1], d[0]); +#endif +} + +inline v_int8x16 v_reverse(const v_int8x16 &a) +{ return v_reinterpret_as_s8(v_reverse(v_reinterpret_as_u8(a))); } + +inline v_uint16x8 v_reverse(const v_uint16x8 &a) +{ +#if CV_SSSE3 + static const __m128i perm = _mm_setr_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1); + return v_uint16x8(_mm_shuffle_epi8(a.val, perm)); +#else + __m128i r = _mm_shuffle_epi32(a.val, _MM_SHUFFLE(0, 1, 2, 3)); + r = _mm_shufflelo_epi16(r, _MM_SHUFFLE(2, 3, 0, 1)); + r = _mm_shufflehi_epi16(r, _MM_SHUFFLE(2, 3, 0, 1)); + return v_uint16x8(r); +#endif +} + +inline v_int16x8 v_reverse(const v_int16x8 &a) +{ return v_reinterpret_as_s16(v_reverse(v_reinterpret_as_u16(a))); } + +inline v_uint32x4 v_reverse(const v_uint32x4 &a) +{ + return v_uint32x4(_mm_shuffle_epi32(a.val, _MM_SHUFFLE(0, 1, 2, 3))); +} + +inline v_int32x4 v_reverse(const v_int32x4 &a) +{ return v_reinterpret_as_s32(v_reverse(v_reinterpret_as_u32(a))); } + +inline v_float32x4 v_reverse(const v_float32x4 &a) +{ return v_reinterpret_as_f32(v_reverse(v_reinterpret_as_u32(a))); } + +inline v_uint64x2 v_reverse(const v_uint64x2 &a) +{ + return v_uint64x2(_mm_shuffle_epi32(a.val, _MM_SHUFFLE(1, 0, 3, 2))); +} + +inline v_int64x2 v_reverse(const v_int64x2 &a) +{ return v_reinterpret_as_s64(v_reverse(v_reinterpret_as_u64(a))); } + +inline v_float64x2 v_reverse(const v_float64x2 &a) +{ return v_reinterpret_as_f64(v_reverse(v_reinterpret_as_u64(a))); } + +template +inline _Tpvec v_extract(const _Tpvec& a, const _Tpvec& b) +{ + return v_rotate_right(a, b); +} + +inline v_int32x4 v_round(const v_float32x4& a) +{ return v_int32x4(_mm_cvtps_epi32(a.val)); } + +inline v_int32x4 v_floor(const v_float32x4& a) +{ + __m128i a1 = _mm_cvtps_epi32(a.val); + __m128i mask = _mm_castps_si128(_mm_cmpgt_ps(_mm_cvtepi32_ps(a1), a.val)); + return v_int32x4(_mm_add_epi32(a1, mask)); +} + +inline v_int32x4 v_ceil(const v_float32x4& a) +{ + __m128i a1 = _mm_cvtps_epi32(a.val); + __m128i mask = _mm_castps_si128(_mm_cmpgt_ps(a.val, _mm_cvtepi32_ps(a1))); + return v_int32x4(_mm_sub_epi32(a1, mask)); +} + +inline v_int32x4 v_trunc(const v_float32x4& a) +{ return v_int32x4(_mm_cvttps_epi32(a.val)); } + +inline v_int32x4 v_round(const v_float64x2& a) +{ return v_int32x4(_mm_cvtpd_epi32(a.val)); } + +inline v_int32x4 v_round(const v_float64x2& a, const v_float64x2& b) +{ + __m128i ai = _mm_cvtpd_epi32(a.val), bi = _mm_cvtpd_epi32(b.val); + return v_int32x4(_mm_unpacklo_epi64(ai, bi)); +} + +inline v_int32x4 v_floor(const v_float64x2& a) +{ + __m128i a1 = _mm_cvtpd_epi32(a.val); + __m128i mask = _mm_castpd_si128(_mm_cmpgt_pd(_mm_cvtepi32_pd(a1), a.val)); + mask = _mm_srli_si128(_mm_slli_si128(mask, 4), 8); // m0 m0 m1 m1 => m0 m1 0 0 + return v_int32x4(_mm_add_epi32(a1, mask)); +} + +inline v_int32x4 v_ceil(const v_float64x2& a) +{ + __m128i a1 = _mm_cvtpd_epi32(a.val); + __m128i mask = _mm_castpd_si128(_mm_cmpgt_pd(a.val, _mm_cvtepi32_pd(a1))); + mask = _mm_srli_si128(_mm_slli_si128(mask, 4), 8); // m0 m0 m1 m1 => m0 m1 0 0 + return v_int32x4(_mm_sub_epi32(a1, mask)); +} + +inline v_int32x4 v_trunc(const v_float64x2& a) +{ return v_int32x4(_mm_cvttpd_epi32(a.val)); } + +#define OPENCV_HAL_IMPL_SSE_TRANSPOSE4x4(_Tpvec, suffix, cast_from, cast_to) \ +inline void v_transpose4x4(const _Tpvec& a0, const _Tpvec& a1, \ + const _Tpvec& a2, const _Tpvec& a3, \ + _Tpvec& b0, _Tpvec& b1, \ + _Tpvec& b2, _Tpvec& b3) \ +{ \ + __m128i t0 = cast_from(_mm_unpacklo_##suffix(a0.val, a1.val)); \ + __m128i t1 = cast_from(_mm_unpacklo_##suffix(a2.val, a3.val)); \ + __m128i t2 = cast_from(_mm_unpackhi_##suffix(a0.val, a1.val)); \ + __m128i t3 = cast_from(_mm_unpackhi_##suffix(a2.val, a3.val)); \ +\ + b0.val = cast_to(_mm_unpacklo_epi64(t0, t1)); \ + b1.val = cast_to(_mm_unpackhi_epi64(t0, t1)); \ + b2.val = cast_to(_mm_unpacklo_epi64(t2, t3)); \ + b3.val = cast_to(_mm_unpackhi_epi64(t2, t3)); \ +} + +OPENCV_HAL_IMPL_SSE_TRANSPOSE4x4(v_uint32x4, epi32, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_TRANSPOSE4x4(v_int32x4, epi32, OPENCV_HAL_NOP, OPENCV_HAL_NOP) +OPENCV_HAL_IMPL_SSE_TRANSPOSE4x4(v_float32x4, ps, _mm_castps_si128, _mm_castsi128_ps) + +// load deinterleave +inline void v_load_deinterleave(const uchar* ptr, v_uint8x16& a, v_uint8x16& b) +{ + __m128i t00 = _mm_loadu_si128((const __m128i*)ptr); + __m128i t01 = _mm_loadu_si128((const __m128i*)(ptr + 16)); + + __m128i t10 = _mm_unpacklo_epi8(t00, t01); + __m128i t11 = _mm_unpackhi_epi8(t00, t01); + + __m128i t20 = _mm_unpacklo_epi8(t10, t11); + __m128i t21 = _mm_unpackhi_epi8(t10, t11); + + __m128i t30 = _mm_unpacklo_epi8(t20, t21); + __m128i t31 = _mm_unpackhi_epi8(t20, t21); + + a.val = _mm_unpacklo_epi8(t30, t31); + b.val = _mm_unpackhi_epi8(t30, t31); +} + +inline void v_load_deinterleave(const uchar* ptr, v_uint8x16& a, v_uint8x16& b, v_uint8x16& c) +{ +#if CV_SSE4_1 + const __m128i m0 = _mm_setr_epi8(0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0); + const __m128i m1 = _mm_setr_epi8(0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0); + __m128i s0 = _mm_loadu_si128((const __m128i*)ptr); + __m128i s1 = _mm_loadu_si128((const __m128i*)(ptr + 16)); + __m128i s2 = _mm_loadu_si128((const __m128i*)(ptr + 32)); + __m128i a0 = _mm_blendv_epi8(_mm_blendv_epi8(s0, s1, m0), s2, m1); + __m128i b0 = _mm_blendv_epi8(_mm_blendv_epi8(s1, s2, m0), s0, m1); + __m128i c0 = _mm_blendv_epi8(_mm_blendv_epi8(s2, s0, m0), s1, m1); + const __m128i sh_b = _mm_setr_epi8(0, 3, 6, 9, 12, 15, 2, 5, 8, 11, 14, 1, 4, 7, 10, 13); + const __m128i sh_g = _mm_setr_epi8(1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, 5, 8, 11, 14); + const __m128i sh_r = _mm_setr_epi8(2, 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15); + a0 = _mm_shuffle_epi8(a0, sh_b); + b0 = _mm_shuffle_epi8(b0, sh_g); + c0 = _mm_shuffle_epi8(c0, sh_r); + a.val = a0; + b.val = b0; + c.val = c0; +#elif CV_SSSE3 + const __m128i m0 = _mm_setr_epi8(0, 3, 6, 9, 12, 15, 1, 4, 7, 10, 13, 2, 5, 8, 11, 14); + const __m128i m1 = _mm_alignr_epi8(m0, m0, 11); + const __m128i m2 = _mm_alignr_epi8(m0, m0, 6); + + __m128i t0 = _mm_loadu_si128((const __m128i*)ptr); + __m128i t1 = _mm_loadu_si128((const __m128i*)(ptr + 16)); + __m128i t2 = _mm_loadu_si128((const __m128i*)(ptr + 32)); + + __m128i s0 = _mm_shuffle_epi8(t0, m0); + __m128i s1 = _mm_shuffle_epi8(t1, m1); + __m128i s2 = _mm_shuffle_epi8(t2, m2); + + t0 = _mm_alignr_epi8(s1, _mm_slli_si128(s0, 10), 5); + a.val = _mm_alignr_epi8(s2, t0, 5); + + t1 = _mm_alignr_epi8(_mm_srli_si128(s1, 5), _mm_slli_si128(s0, 5), 6); + b.val = _mm_alignr_epi8(_mm_srli_si128(s2, 5), t1, 5); + + t2 = _mm_alignr_epi8(_mm_srli_si128(s2, 10), s1, 11); + c.val = _mm_alignr_epi8(t2, s0, 11); +#else + __m128i t00 = _mm_loadu_si128((const __m128i*)ptr); + __m128i t01 = _mm_loadu_si128((const __m128i*)(ptr + 16)); + __m128i t02 = _mm_loadu_si128((const __m128i*)(ptr + 32)); + + __m128i t10 = _mm_unpacklo_epi8(t00, _mm_unpackhi_epi64(t01, t01)); + __m128i t11 = _mm_unpacklo_epi8(_mm_unpackhi_epi64(t00, t00), t02); + __m128i t12 = _mm_unpacklo_epi8(t01, _mm_unpackhi_epi64(t02, t02)); + + __m128i t20 = _mm_unpacklo_epi8(t10, _mm_unpackhi_epi64(t11, t11)); + __m128i t21 = _mm_unpacklo_epi8(_mm_unpackhi_epi64(t10, t10), t12); + __m128i t22 = _mm_unpacklo_epi8(t11, _mm_unpackhi_epi64(t12, t12)); + + __m128i t30 = _mm_unpacklo_epi8(t20, _mm_unpackhi_epi64(t21, t21)); + __m128i t31 = _mm_unpacklo_epi8(_mm_unpackhi_epi64(t20, t20), t22); + __m128i t32 = _mm_unpacklo_epi8(t21, _mm_unpackhi_epi64(t22, t22)); + + a.val = _mm_unpacklo_epi8(t30, _mm_unpackhi_epi64(t31, t31)); + b.val = _mm_unpacklo_epi8(_mm_unpackhi_epi64(t30, t30), t32); + c.val = _mm_unpacklo_epi8(t31, _mm_unpackhi_epi64(t32, t32)); +#endif +} + +inline void v_load_deinterleave(const uchar* ptr, v_uint8x16& a, v_uint8x16& b, v_uint8x16& c, v_uint8x16& d) +{ + __m128i u0 = _mm_loadu_si128((const __m128i*)ptr); // a0 b0 c0 d0 a1 b1 c1 d1 ... + __m128i u1 = _mm_loadu_si128((const __m128i*)(ptr + 16)); // a4 b4 c4 d4 ... + __m128i u2 = _mm_loadu_si128((const __m128i*)(ptr + 32)); // a8 b8 c8 d8 ... + __m128i u3 = _mm_loadu_si128((const __m128i*)(ptr + 48)); // a12 b12 c12 d12 ... + + __m128i v0 = _mm_unpacklo_epi8(u0, u2); // a0 a8 b0 b8 ... + __m128i v1 = _mm_unpackhi_epi8(u0, u2); // a2 a10 b2 b10 ... + __m128i v2 = _mm_unpacklo_epi8(u1, u3); // a4 a12 b4 b12 ... + __m128i v3 = _mm_unpackhi_epi8(u1, u3); // a6 a14 b6 b14 ... + + u0 = _mm_unpacklo_epi8(v0, v2); // a0 a4 a8 a12 ... + u1 = _mm_unpacklo_epi8(v1, v3); // a2 a6 a10 a14 ... + u2 = _mm_unpackhi_epi8(v0, v2); // a1 a5 a9 a13 ... + u3 = _mm_unpackhi_epi8(v1, v3); // a3 a7 a11 a15 ... + + v0 = _mm_unpacklo_epi8(u0, u1); // a0 a2 a4 a6 ... + v1 = _mm_unpacklo_epi8(u2, u3); // a1 a3 a5 a7 ... + v2 = _mm_unpackhi_epi8(u0, u1); // c0 c2 c4 c6 ... + v3 = _mm_unpackhi_epi8(u2, u3); // c1 c3 c5 c7 ... + + a.val = _mm_unpacklo_epi8(v0, v1); + b.val = _mm_unpackhi_epi8(v0, v1); + c.val = _mm_unpacklo_epi8(v2, v3); + d.val = _mm_unpackhi_epi8(v2, v3); +} + +inline void v_load_deinterleave(const ushort* ptr, v_uint16x8& a, v_uint16x8& b) +{ + __m128i v0 = _mm_loadu_si128((__m128i*)(ptr)); // a0 b0 a1 b1 a2 b2 a3 b3 + __m128i v1 = _mm_loadu_si128((__m128i*)(ptr + 8)); // a4 b4 a5 b5 a6 b6 a7 b7 + + __m128i v2 = _mm_unpacklo_epi16(v0, v1); // a0 a4 b0 b4 a1 a5 b1 b5 + __m128i v3 = _mm_unpackhi_epi16(v0, v1); // a2 a6 b2 b6 a3 a7 b3 b7 + __m128i v4 = _mm_unpacklo_epi16(v2, v3); // a0 a2 a4 a6 b0 b2 b4 b6 + __m128i v5 = _mm_unpackhi_epi16(v2, v3); // a1 a3 a5 a7 b1 b3 b5 b7 + + a.val = _mm_unpacklo_epi16(v4, v5); // a0 a1 a2 a3 a4 a5 a6 a7 + b.val = _mm_unpackhi_epi16(v4, v5); // b0 b1 ab b3 b4 b5 b6 b7 +} + +inline void v_load_deinterleave(const ushort* ptr, v_uint16x8& a, v_uint16x8& b, v_uint16x8& c) +{ +#if CV_SSE4_1 + __m128i v0 = _mm_loadu_si128((__m128i*)(ptr)); + __m128i v1 = _mm_loadu_si128((__m128i*)(ptr + 8)); + __m128i v2 = _mm_loadu_si128((__m128i*)(ptr + 16)); + __m128i a0 = _mm_blend_epi16(_mm_blend_epi16(v0, v1, 0x92), v2, 0x24); + __m128i b0 = _mm_blend_epi16(_mm_blend_epi16(v2, v0, 0x92), v1, 0x24); + __m128i c0 = _mm_blend_epi16(_mm_blend_epi16(v1, v2, 0x92), v0, 0x24); + + const __m128i sh_a = _mm_setr_epi8(0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5, 10, 11); + const __m128i sh_b = _mm_setr_epi8(2, 3, 8, 9, 14, 15, 4, 5, 10, 11, 0, 1, 6, 7, 12, 13); + const __m128i sh_c = _mm_setr_epi8(4, 5, 10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15); + a0 = _mm_shuffle_epi8(a0, sh_a); + b0 = _mm_shuffle_epi8(b0, sh_b); + c0 = _mm_shuffle_epi8(c0, sh_c); + + a.val = a0; + b.val = b0; + c.val = c0; +#else + __m128i t00 = _mm_loadu_si128((const __m128i*)ptr); + __m128i t01 = _mm_loadu_si128((const __m128i*)(ptr + 8)); + __m128i t02 = _mm_loadu_si128((const __m128i*)(ptr + 16)); + + __m128i t10 = _mm_unpacklo_epi16(t00, _mm_unpackhi_epi64(t01, t01)); + __m128i t11 = _mm_unpacklo_epi16(_mm_unpackhi_epi64(t00, t00), t02); + __m128i t12 = _mm_unpacklo_epi16(t01, _mm_unpackhi_epi64(t02, t02)); + + __m128i t20 = _mm_unpacklo_epi16(t10, _mm_unpackhi_epi64(t11, t11)); + __m128i t21 = _mm_unpacklo_epi16(_mm_unpackhi_epi64(t10, t10), t12); + __m128i t22 = _mm_unpacklo_epi16(t11, _mm_unpackhi_epi64(t12, t12)); + + a.val = _mm_unpacklo_epi16(t20, _mm_unpackhi_epi64(t21, t21)); + b.val = _mm_unpacklo_epi16(_mm_unpackhi_epi64(t20, t20), t22); + c.val = _mm_unpacklo_epi16(t21, _mm_unpackhi_epi64(t22, t22)); +#endif +} + +inline void v_load_deinterleave(const ushort* ptr, v_uint16x8& a, v_uint16x8& b, v_uint16x8& c, v_uint16x8& d) +{ + __m128i u0 = _mm_loadu_si128((const __m128i*)ptr); // a0 b0 c0 d0 a1 b1 c1 d1 + __m128i u1 = _mm_loadu_si128((const __m128i*)(ptr + 8)); // a2 b2 c2 d2 ... + __m128i u2 = _mm_loadu_si128((const __m128i*)(ptr + 16)); // a4 b4 c4 d4 ... + __m128i u3 = _mm_loadu_si128((const __m128i*)(ptr + 24)); // a6 b6 c6 d6 ... + + __m128i v0 = _mm_unpacklo_epi16(u0, u2); // a0 a4 b0 b4 ... + __m128i v1 = _mm_unpackhi_epi16(u0, u2); // a1 a5 b1 b5 ... + __m128i v2 = _mm_unpacklo_epi16(u1, u3); // a2 a6 b2 b6 ... + __m128i v3 = _mm_unpackhi_epi16(u1, u3); // a3 a7 b3 b7 ... + + u0 = _mm_unpacklo_epi16(v0, v2); // a0 a2 a4 a6 ... + u1 = _mm_unpacklo_epi16(v1, v3); // a1 a3 a5 a7 ... + u2 = _mm_unpackhi_epi16(v0, v2); // c0 c2 c4 c6 ... + u3 = _mm_unpackhi_epi16(v1, v3); // c1 c3 c5 c7 ... + + a.val = _mm_unpacklo_epi16(u0, u1); + b.val = _mm_unpackhi_epi16(u0, u1); + c.val = _mm_unpacklo_epi16(u2, u3); + d.val = _mm_unpackhi_epi16(u2, u3); +} + +inline void v_load_deinterleave(const unsigned* ptr, v_uint32x4& a, v_uint32x4& b) +{ + __m128i v0 = _mm_loadu_si128((__m128i*)(ptr)); // a0 b0 a1 b1 + __m128i v1 = _mm_loadu_si128((__m128i*)(ptr + 4)); // a2 b2 a3 b3 + + __m128i v2 = _mm_unpacklo_epi32(v0, v1); // a0 a2 b0 b2 + __m128i v3 = _mm_unpackhi_epi32(v0, v1); // a1 a3 b1 b3 + + a.val = _mm_unpacklo_epi32(v2, v3); // a0 a1 a2 a3 + b.val = _mm_unpackhi_epi32(v2, v3); // b0 b1 ab b3 +} + +inline void v_load_deinterleave(const unsigned* ptr, v_uint32x4& a, v_uint32x4& b, v_uint32x4& c) +{ + __m128i t00 = _mm_loadu_si128((const __m128i*)ptr); + __m128i t01 = _mm_loadu_si128((const __m128i*)(ptr + 4)); + __m128i t02 = _mm_loadu_si128((const __m128i*)(ptr + 8)); + + __m128i t10 = _mm_unpacklo_epi32(t00, _mm_unpackhi_epi64(t01, t01)); + __m128i t11 = _mm_unpacklo_epi32(_mm_unpackhi_epi64(t00, t00), t02); + __m128i t12 = _mm_unpacklo_epi32(t01, _mm_unpackhi_epi64(t02, t02)); + + a.val = _mm_unpacklo_epi32(t10, _mm_unpackhi_epi64(t11, t11)); + b.val = _mm_unpacklo_epi32(_mm_unpackhi_epi64(t10, t10), t12); + c.val = _mm_unpacklo_epi32(t11, _mm_unpackhi_epi64(t12, t12)); +} + +inline void v_load_deinterleave(const unsigned* ptr, v_uint32x4& a, v_uint32x4& b, v_uint32x4& c, v_uint32x4& d) +{ + v_uint32x4 s0(_mm_loadu_si128((const __m128i*)ptr)); // a0 b0 c0 d0 + v_uint32x4 s1(_mm_loadu_si128((const __m128i*)(ptr + 4))); // a1 b1 c1 d1 + v_uint32x4 s2(_mm_loadu_si128((const __m128i*)(ptr + 8))); // a2 b2 c2 d2 + v_uint32x4 s3(_mm_loadu_si128((const __m128i*)(ptr + 12))); // a3 b3 c3 d3 + + v_transpose4x4(s0, s1, s2, s3, a, b, c, d); +} + +inline void v_load_deinterleave(const float* ptr, v_float32x4& a, v_float32x4& b) +{ + __m128 u0 = _mm_loadu_ps(ptr); // a0 b0 a1 b1 + __m128 u1 = _mm_loadu_ps((ptr + 4)); // a2 b2 a3 b3 + + a.val = _mm_shuffle_ps(u0, u1, _MM_SHUFFLE(2, 0, 2, 0)); // a0 a1 a2 a3 + b.val = _mm_shuffle_ps(u0, u1, _MM_SHUFFLE(3, 1, 3, 1)); // b0 b1 ab b3 +} + +inline void v_load_deinterleave(const float* ptr, v_float32x4& a, v_float32x4& b, v_float32x4& c) +{ + __m128 t0 = _mm_loadu_ps(ptr + 0); + __m128 t1 = _mm_loadu_ps(ptr + 4); + __m128 t2 = _mm_loadu_ps(ptr + 8); + + __m128 at12 = _mm_shuffle_ps(t1, t2, _MM_SHUFFLE(0, 1, 0, 2)); + a.val = _mm_shuffle_ps(t0, at12, _MM_SHUFFLE(2, 0, 3, 0)); + + __m128 bt01 = _mm_shuffle_ps(t0, t1, _MM_SHUFFLE(0, 0, 0, 1)); + __m128 bt12 = _mm_shuffle_ps(t1, t2, _MM_SHUFFLE(0, 2, 0, 3)); + b.val = _mm_shuffle_ps(bt01, bt12, _MM_SHUFFLE(2, 0, 2, 0)); + + __m128 ct01 = _mm_shuffle_ps(t0, t1, _MM_SHUFFLE(0, 1, 0, 2)); + c.val = _mm_shuffle_ps(ct01, t2, _MM_SHUFFLE(3, 0, 2, 0)); +} + +inline void v_load_deinterleave(const float* ptr, v_float32x4& a, v_float32x4& b, v_float32x4& c, v_float32x4& d) +{ + __m128 t0 = _mm_loadu_ps(ptr + 0); + __m128 t1 = _mm_loadu_ps(ptr + 4); + __m128 t2 = _mm_loadu_ps(ptr + 8); + __m128 t3 = _mm_loadu_ps(ptr + 12); + __m128 t02lo = _mm_unpacklo_ps(t0, t2); + __m128 t13lo = _mm_unpacklo_ps(t1, t3); + __m128 t02hi = _mm_unpackhi_ps(t0, t2); + __m128 t13hi = _mm_unpackhi_ps(t1, t3); + a.val = _mm_unpacklo_ps(t02lo, t13lo); + b.val = _mm_unpackhi_ps(t02lo, t13lo); + c.val = _mm_unpacklo_ps(t02hi, t13hi); + d.val = _mm_unpackhi_ps(t02hi, t13hi); +} + +inline void v_load_deinterleave(const uint64 *ptr, v_uint64x2& a, v_uint64x2& b) +{ + __m128i t0 = _mm_loadu_si128((const __m128i*)ptr); + __m128i t1 = _mm_loadu_si128((const __m128i*)(ptr + 2)); + + a = v_uint64x2(_mm_unpacklo_epi64(t0, t1)); + b = v_uint64x2(_mm_unpackhi_epi64(t0, t1)); +} + +inline void v_load_deinterleave(const uint64 *ptr, v_uint64x2& a, v_uint64x2& b, v_uint64x2& c) +{ + __m128i t0 = _mm_loadu_si128((const __m128i*)ptr); // a0, b0 + __m128i t1 = _mm_loadu_si128((const __m128i*)(ptr + 2)); // c0, a1 + __m128i t2 = _mm_loadu_si128((const __m128i*)(ptr + 4)); // b1, c1 + + t1 = _mm_shuffle_epi32(t1, 0x4e); // a1, c0 + + a = v_uint64x2(_mm_unpacklo_epi64(t0, t1)); + b = v_uint64x2(_mm_unpacklo_epi64(_mm_unpackhi_epi64(t0, t0), t2)); + c = v_uint64x2(_mm_unpackhi_epi64(t1, t2)); +} + +inline void v_load_deinterleave(const uint64 *ptr, v_uint64x2& a, + v_uint64x2& b, v_uint64x2& c, v_uint64x2& d) +{ + __m128i t0 = _mm_loadu_si128((const __m128i*)ptr); // a0 b0 + __m128i t1 = _mm_loadu_si128((const __m128i*)(ptr + 2)); // c0 d0 + __m128i t2 = _mm_loadu_si128((const __m128i*)(ptr + 4)); // a1 b1 + __m128i t3 = _mm_loadu_si128((const __m128i*)(ptr + 6)); // c1 d1 + + a = v_uint64x2(_mm_unpacklo_epi64(t0, t2)); + b = v_uint64x2(_mm_unpackhi_epi64(t0, t2)); + c = v_uint64x2(_mm_unpacklo_epi64(t1, t3)); + d = v_uint64x2(_mm_unpackhi_epi64(t1, t3)); +} + +// store interleave + +inline void v_store_interleave( uchar* ptr, const v_uint8x16& a, const v_uint8x16& b, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + __m128i v0 = _mm_unpacklo_epi8(a.val, b.val); + __m128i v1 = _mm_unpackhi_epi8(a.val, b.val); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 16), v1); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 16), v1); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 16), v1); + } +} + +inline void v_store_interleave( uchar* ptr, const v_uint8x16& a, const v_uint8x16& b, + const v_uint8x16& c, hal::StoreMode mode = hal::STORE_UNALIGNED) +{ +#if CV_SSE4_1 + const __m128i sh_a = _mm_setr_epi8(0, 11, 6, 1, 12, 7, 2, 13, 8, 3, 14, 9, 4, 15, 10, 5); + const __m128i sh_b = _mm_setr_epi8(5, 0, 11, 6, 1, 12, 7, 2, 13, 8, 3, 14, 9, 4, 15, 10); + const __m128i sh_c = _mm_setr_epi8(10, 5, 0, 11, 6, 1, 12, 7, 2, 13, 8, 3, 14, 9, 4, 15); + __m128i a0 = _mm_shuffle_epi8(a.val, sh_a); + __m128i b0 = _mm_shuffle_epi8(b.val, sh_b); + __m128i c0 = _mm_shuffle_epi8(c.val, sh_c); + + const __m128i m0 = _mm_setr_epi8(0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0); + const __m128i m1 = _mm_setr_epi8(0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0); + __m128i v0 = _mm_blendv_epi8(_mm_blendv_epi8(a0, b0, m1), c0, m0); + __m128i v1 = _mm_blendv_epi8(_mm_blendv_epi8(b0, c0, m1), a0, m0); + __m128i v2 = _mm_blendv_epi8(_mm_blendv_epi8(c0, a0, m1), b0, m0); +#elif CV_SSSE3 + const __m128i m0 = _mm_setr_epi8(0, 6, 11, 1, 7, 12, 2, 8, 13, 3, 9, 14, 4, 10, 15, 5); + const __m128i m1 = _mm_setr_epi8(5, 11, 0, 6, 12, 1, 7, 13, 2, 8, 14, 3, 9, 15, 4, 10); + const __m128i m2 = _mm_setr_epi8(10, 0, 5, 11, 1, 6, 12, 2, 7, 13, 3, 8, 14, 4, 9, 15); + + __m128i t0 = _mm_alignr_epi8(b.val, _mm_slli_si128(a.val, 10), 5); + t0 = _mm_alignr_epi8(c.val, t0, 5); + __m128i v0 = _mm_shuffle_epi8(t0, m0); + + __m128i t1 = _mm_alignr_epi8(_mm_srli_si128(b.val, 5), _mm_slli_si128(a.val, 5), 6); + t1 = _mm_alignr_epi8(_mm_srli_si128(c.val, 5), t1, 5); + __m128i v1 = _mm_shuffle_epi8(t1, m1); + + __m128i t2 = _mm_alignr_epi8(_mm_srli_si128(c.val, 10), b.val, 11); + t2 = _mm_alignr_epi8(t2, a.val, 11); + __m128i v2 = _mm_shuffle_epi8(t2, m2); +#else + __m128i z = _mm_setzero_si128(); + __m128i ab0 = _mm_unpacklo_epi8(a.val, b.val); + __m128i ab1 = _mm_unpackhi_epi8(a.val, b.val); + __m128i c0 = _mm_unpacklo_epi8(c.val, z); + __m128i c1 = _mm_unpackhi_epi8(c.val, z); + + __m128i p00 = _mm_unpacklo_epi16(ab0, c0); + __m128i p01 = _mm_unpackhi_epi16(ab0, c0); + __m128i p02 = _mm_unpacklo_epi16(ab1, c1); + __m128i p03 = _mm_unpackhi_epi16(ab1, c1); + + __m128i p10 = _mm_unpacklo_epi32(p00, p01); + __m128i p11 = _mm_unpackhi_epi32(p00, p01); + __m128i p12 = _mm_unpacklo_epi32(p02, p03); + __m128i p13 = _mm_unpackhi_epi32(p02, p03); + + __m128i p20 = _mm_unpacklo_epi64(p10, p11); + __m128i p21 = _mm_unpackhi_epi64(p10, p11); + __m128i p22 = _mm_unpacklo_epi64(p12, p13); + __m128i p23 = _mm_unpackhi_epi64(p12, p13); + + p20 = _mm_slli_si128(p20, 1); + p22 = _mm_slli_si128(p22, 1); + + __m128i p30 = _mm_slli_epi64(_mm_unpacklo_epi32(p20, p21), 8); + __m128i p31 = _mm_srli_epi64(_mm_unpackhi_epi32(p20, p21), 8); + __m128i p32 = _mm_slli_epi64(_mm_unpacklo_epi32(p22, p23), 8); + __m128i p33 = _mm_srli_epi64(_mm_unpackhi_epi32(p22, p23), 8); + + __m128i p40 = _mm_unpacklo_epi64(p30, p31); + __m128i p41 = _mm_unpackhi_epi64(p30, p31); + __m128i p42 = _mm_unpacklo_epi64(p32, p33); + __m128i p43 = _mm_unpackhi_epi64(p32, p33); + + __m128i v0 = _mm_or_si128(_mm_srli_si128(p40, 2), _mm_slli_si128(p41, 10)); + __m128i v1 = _mm_or_si128(_mm_srli_si128(p41, 6), _mm_slli_si128(p42, 6)); + __m128i v2 = _mm_or_si128(_mm_srli_si128(p42, 10), _mm_slli_si128(p43, 2)); +#endif + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 16), v1); + _mm_stream_si128((__m128i*)(ptr + 32), v2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 16), v1); + _mm_store_si128((__m128i*)(ptr + 32), v2); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 16), v1); + _mm_storeu_si128((__m128i*)(ptr + 32), v2); + } +} + +inline void v_store_interleave( uchar* ptr, const v_uint8x16& a, const v_uint8x16& b, + const v_uint8x16& c, const v_uint8x16& d, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + // a0 a1 a2 a3 .... + // b0 b1 b2 b3 .... + // c0 c1 c2 c3 .... + // d0 d1 d2 d3 .... + __m128i u0 = _mm_unpacklo_epi8(a.val, c.val); // a0 c0 a1 c1 ... + __m128i u1 = _mm_unpackhi_epi8(a.val, c.val); // a8 c8 a9 c9 ... + __m128i u2 = _mm_unpacklo_epi8(b.val, d.val); // b0 d0 b1 d1 ... + __m128i u3 = _mm_unpackhi_epi8(b.val, d.val); // b8 d8 b9 d9 ... + + __m128i v0 = _mm_unpacklo_epi8(u0, u2); // a0 b0 c0 d0 ... + __m128i v1 = _mm_unpackhi_epi8(u0, u2); // a4 b4 c4 d4 ... + __m128i v2 = _mm_unpacklo_epi8(u1, u3); // a8 b8 c8 d8 ... + __m128i v3 = _mm_unpackhi_epi8(u1, u3); // a12 b12 c12 d12 ... + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 16), v1); + _mm_stream_si128((__m128i*)(ptr + 32), v2); + _mm_stream_si128((__m128i*)(ptr + 48), v3); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 16), v1); + _mm_store_si128((__m128i*)(ptr + 32), v2); + _mm_store_si128((__m128i*)(ptr + 48), v3); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 16), v1); + _mm_storeu_si128((__m128i*)(ptr + 32), v2); + _mm_storeu_si128((__m128i*)(ptr + 48), v3); + } +} + +inline void v_store_interleave( ushort* ptr, const v_uint16x8& a, const v_uint16x8& b, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + __m128i v0 = _mm_unpacklo_epi16(a.val, b.val); + __m128i v1 = _mm_unpackhi_epi16(a.val, b.val); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 8), v1); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 8), v1); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 8), v1); + } +} + +inline void v_store_interleave( ushort* ptr, const v_uint16x8& a, + const v_uint16x8& b, const v_uint16x8& c, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ +#if CV_SSE4_1 + const __m128i sh_a = _mm_setr_epi8(0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5, 10, 11); + const __m128i sh_b = _mm_setr_epi8(10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5); + const __m128i sh_c = _mm_setr_epi8(4, 5, 10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15); + __m128i a0 = _mm_shuffle_epi8(a.val, sh_a); + __m128i b0 = _mm_shuffle_epi8(b.val, sh_b); + __m128i c0 = _mm_shuffle_epi8(c.val, sh_c); + + __m128i v0 = _mm_blend_epi16(_mm_blend_epi16(a0, b0, 0x92), c0, 0x24); + __m128i v1 = _mm_blend_epi16(_mm_blend_epi16(c0, a0, 0x92), b0, 0x24); + __m128i v2 = _mm_blend_epi16(_mm_blend_epi16(b0, c0, 0x92), a0, 0x24); +#else + __m128i z = _mm_setzero_si128(); + __m128i ab0 = _mm_unpacklo_epi16(a.val, b.val); + __m128i ab1 = _mm_unpackhi_epi16(a.val, b.val); + __m128i c0 = _mm_unpacklo_epi16(c.val, z); + __m128i c1 = _mm_unpackhi_epi16(c.val, z); + + __m128i p10 = _mm_unpacklo_epi32(ab0, c0); + __m128i p11 = _mm_unpackhi_epi32(ab0, c0); + __m128i p12 = _mm_unpacklo_epi32(ab1, c1); + __m128i p13 = _mm_unpackhi_epi32(ab1, c1); + + __m128i p20 = _mm_unpacklo_epi64(p10, p11); + __m128i p21 = _mm_unpackhi_epi64(p10, p11); + __m128i p22 = _mm_unpacklo_epi64(p12, p13); + __m128i p23 = _mm_unpackhi_epi64(p12, p13); + + p20 = _mm_slli_si128(p20, 2); + p22 = _mm_slli_si128(p22, 2); + + __m128i p30 = _mm_unpacklo_epi64(p20, p21); + __m128i p31 = _mm_unpackhi_epi64(p20, p21); + __m128i p32 = _mm_unpacklo_epi64(p22, p23); + __m128i p33 = _mm_unpackhi_epi64(p22, p23); + + __m128i v0 = _mm_or_si128(_mm_srli_si128(p30, 2), _mm_slli_si128(p31, 10)); + __m128i v1 = _mm_or_si128(_mm_srli_si128(p31, 6), _mm_slli_si128(p32, 6)); + __m128i v2 = _mm_or_si128(_mm_srli_si128(p32, 10), _mm_slli_si128(p33, 2)); +#endif + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 8), v1); + _mm_stream_si128((__m128i*)(ptr + 16), v2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 8), v1); + _mm_store_si128((__m128i*)(ptr + 16), v2); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 8), v1); + _mm_storeu_si128((__m128i*)(ptr + 16), v2); + } +} + +inline void v_store_interleave( ushort* ptr, const v_uint16x8& a, const v_uint16x8& b, + const v_uint16x8& c, const v_uint16x8& d, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + // a0 a1 a2 a3 .... + // b0 b1 b2 b3 .... + // c0 c1 c2 c3 .... + // d0 d1 d2 d3 .... + __m128i u0 = _mm_unpacklo_epi16(a.val, c.val); // a0 c0 a1 c1 ... + __m128i u1 = _mm_unpackhi_epi16(a.val, c.val); // a4 c4 a5 c5 ... + __m128i u2 = _mm_unpacklo_epi16(b.val, d.val); // b0 d0 b1 d1 ... + __m128i u3 = _mm_unpackhi_epi16(b.val, d.val); // b4 d4 b5 d5 ... + + __m128i v0 = _mm_unpacklo_epi16(u0, u2); // a0 b0 c0 d0 ... + __m128i v1 = _mm_unpackhi_epi16(u0, u2); // a2 b2 c2 d2 ... + __m128i v2 = _mm_unpacklo_epi16(u1, u3); // a4 b4 c4 d4 ... + __m128i v3 = _mm_unpackhi_epi16(u1, u3); // a6 b6 c6 d6 ... + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 8), v1); + _mm_stream_si128((__m128i*)(ptr + 16), v2); + _mm_stream_si128((__m128i*)(ptr + 24), v3); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 8), v1); + _mm_store_si128((__m128i*)(ptr + 16), v2); + _mm_store_si128((__m128i*)(ptr + 24), v3); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 8), v1); + _mm_storeu_si128((__m128i*)(ptr + 16), v2); + _mm_storeu_si128((__m128i*)(ptr + 24), v3); + } +} + +inline void v_store_interleave( unsigned* ptr, const v_uint32x4& a, const v_uint32x4& b, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + __m128i v0 = _mm_unpacklo_epi32(a.val, b.val); + __m128i v1 = _mm_unpackhi_epi32(a.val, b.val); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 4), v1); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 4), v1); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 4), v1); + } +} + +inline void v_store_interleave( unsigned* ptr, const v_uint32x4& a, const v_uint32x4& b, + const v_uint32x4& c, hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + v_uint32x4 z = v_setzero_u32(), u0, u1, u2, u3; + v_transpose4x4(a, b, c, z, u0, u1, u2, u3); + + __m128i v0 = _mm_or_si128(u0.val, _mm_slli_si128(u1.val, 12)); + __m128i v1 = _mm_or_si128(_mm_srli_si128(u1.val, 4), _mm_slli_si128(u2.val, 8)); + __m128i v2 = _mm_or_si128(_mm_srli_si128(u2.val, 8), _mm_slli_si128(u3.val, 4)); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 4), v1); + _mm_stream_si128((__m128i*)(ptr + 8), v2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 4), v1); + _mm_store_si128((__m128i*)(ptr + 8), v2); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 4), v1); + _mm_storeu_si128((__m128i*)(ptr + 8), v2); + } +} + +inline void v_store_interleave(unsigned* ptr, const v_uint32x4& a, const v_uint32x4& b, + const v_uint32x4& c, const v_uint32x4& d, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + v_uint32x4 v0, v1, v2, v3; + v_transpose4x4(a, b, c, d, v0, v1, v2, v3); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0.val); + _mm_stream_si128((__m128i*)(ptr + 4), v1.val); + _mm_stream_si128((__m128i*)(ptr + 8), v2.val); + _mm_stream_si128((__m128i*)(ptr + 12), v3.val); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0.val); + _mm_store_si128((__m128i*)(ptr + 4), v1.val); + _mm_store_si128((__m128i*)(ptr + 8), v2.val); + _mm_store_si128((__m128i*)(ptr + 12), v3.val); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0.val); + _mm_storeu_si128((__m128i*)(ptr + 4), v1.val); + _mm_storeu_si128((__m128i*)(ptr + 8), v2.val); + _mm_storeu_si128((__m128i*)(ptr + 12), v3.val); + } +} + +// 2-channel, float only +inline void v_store_interleave(float* ptr, const v_float32x4& a, const v_float32x4& b, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + __m128 v0 = _mm_unpacklo_ps(a.val, b.val); // a0 b0 a1 b1 + __m128 v1 = _mm_unpackhi_ps(a.val, b.val); // a2 b2 a3 b3 + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_ps(ptr, v0); + _mm_stream_ps(ptr + 4, v1); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_ps(ptr, v0); + _mm_store_ps(ptr + 4, v1); + } + else + { + _mm_storeu_ps(ptr, v0); + _mm_storeu_ps(ptr + 4, v1); + } +} + +inline void v_store_interleave(float* ptr, const v_float32x4& a, const v_float32x4& b, + const v_float32x4& c, hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + __m128 u0 = _mm_shuffle_ps(a.val, b.val, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 u1 = _mm_shuffle_ps(c.val, a.val, _MM_SHUFFLE(1, 1, 0, 0)); + __m128 v0 = _mm_shuffle_ps(u0, u1, _MM_SHUFFLE(2, 0, 2, 0)); + __m128 u2 = _mm_shuffle_ps(b.val, c.val, _MM_SHUFFLE(1, 1, 1, 1)); + __m128 u3 = _mm_shuffle_ps(a.val, b.val, _MM_SHUFFLE(2, 2, 2, 2)); + __m128 v1 = _mm_shuffle_ps(u2, u3, _MM_SHUFFLE(2, 0, 2, 0)); + __m128 u4 = _mm_shuffle_ps(c.val, a.val, _MM_SHUFFLE(3, 3, 2, 2)); + __m128 u5 = _mm_shuffle_ps(b.val, c.val, _MM_SHUFFLE(3, 3, 3, 3)); + __m128 v2 = _mm_shuffle_ps(u4, u5, _MM_SHUFFLE(2, 0, 2, 0)); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_ps(ptr, v0); + _mm_stream_ps(ptr + 4, v1); + _mm_stream_ps(ptr + 8, v2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_ps(ptr, v0); + _mm_store_ps(ptr + 4, v1); + _mm_store_ps(ptr + 8, v2); + } + else + { + _mm_storeu_ps(ptr, v0); + _mm_storeu_ps(ptr + 4, v1); + _mm_storeu_ps(ptr + 8, v2); + } +} + +inline void v_store_interleave(float* ptr, const v_float32x4& a, const v_float32x4& b, + const v_float32x4& c, const v_float32x4& d, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + __m128 u0 = _mm_unpacklo_ps(a.val, c.val); + __m128 u1 = _mm_unpacklo_ps(b.val, d.val); + __m128 u2 = _mm_unpackhi_ps(a.val, c.val); + __m128 u3 = _mm_unpackhi_ps(b.val, d.val); + __m128 v0 = _mm_unpacklo_ps(u0, u1); + __m128 v2 = _mm_unpacklo_ps(u2, u3); + __m128 v1 = _mm_unpackhi_ps(u0, u1); + __m128 v3 = _mm_unpackhi_ps(u2, u3); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_ps(ptr, v0); + _mm_stream_ps(ptr + 4, v1); + _mm_stream_ps(ptr + 8, v2); + _mm_stream_ps(ptr + 12, v3); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_ps(ptr, v0); + _mm_store_ps(ptr + 4, v1); + _mm_store_ps(ptr + 8, v2); + _mm_store_ps(ptr + 12, v3); + } + else + { + _mm_storeu_ps(ptr, v0); + _mm_storeu_ps(ptr + 4, v1); + _mm_storeu_ps(ptr + 8, v2); + _mm_storeu_ps(ptr + 12, v3); + } +} + +inline void v_store_interleave(uint64 *ptr, const v_uint64x2& a, const v_uint64x2& b, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + __m128i v0 = _mm_unpacklo_epi64(a.val, b.val); + __m128i v1 = _mm_unpackhi_epi64(a.val, b.val); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 2), v1); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 2), v1); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 2), v1); + } +} + +inline void v_store_interleave(uint64 *ptr, const v_uint64x2& a, const v_uint64x2& b, + const v_uint64x2& c, hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + __m128i v0 = _mm_unpacklo_epi64(a.val, b.val); + __m128i v1 = _mm_unpacklo_epi64(c.val, _mm_unpackhi_epi64(a.val, a.val)); + __m128i v2 = _mm_unpackhi_epi64(b.val, c.val); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 2), v1); + _mm_stream_si128((__m128i*)(ptr + 4), v2); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 2), v1); + _mm_store_si128((__m128i*)(ptr + 4), v2); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 2), v1); + _mm_storeu_si128((__m128i*)(ptr + 4), v2); + } +} + +inline void v_store_interleave(uint64 *ptr, const v_uint64x2& a, const v_uint64x2& b, + const v_uint64x2& c, const v_uint64x2& d, + hal::StoreMode mode = hal::STORE_UNALIGNED) +{ + __m128i v0 = _mm_unpacklo_epi64(a.val, b.val); + __m128i v1 = _mm_unpacklo_epi64(c.val, d.val); + __m128i v2 = _mm_unpackhi_epi64(a.val, b.val); + __m128i v3 = _mm_unpackhi_epi64(c.val, d.val); + + if( mode == hal::STORE_ALIGNED_NOCACHE ) + { + _mm_stream_si128((__m128i*)(ptr), v0); + _mm_stream_si128((__m128i*)(ptr + 2), v1); + _mm_stream_si128((__m128i*)(ptr + 4), v2); + _mm_stream_si128((__m128i*)(ptr + 6), v3); + } + else if( mode == hal::STORE_ALIGNED ) + { + _mm_store_si128((__m128i*)(ptr), v0); + _mm_store_si128((__m128i*)(ptr + 2), v1); + _mm_store_si128((__m128i*)(ptr + 4), v2); + _mm_store_si128((__m128i*)(ptr + 6), v3); + } + else + { + _mm_storeu_si128((__m128i*)(ptr), v0); + _mm_storeu_si128((__m128i*)(ptr + 2), v1); + _mm_storeu_si128((__m128i*)(ptr + 4), v2); + _mm_storeu_si128((__m128i*)(ptr + 6), v3); + } +} + +#define OPENCV_HAL_IMPL_SSE_LOADSTORE_INTERLEAVE(_Tpvec0, _Tp0, suffix0, _Tpvec1, _Tp1, suffix1) \ +inline void v_load_deinterleave( const _Tp0* ptr, _Tpvec0& a0, _Tpvec0& b0 ) \ +{ \ + _Tpvec1 a1, b1; \ + v_load_deinterleave((const _Tp1*)ptr, a1, b1); \ + a0 = v_reinterpret_as_##suffix0(a1); \ + b0 = v_reinterpret_as_##suffix0(b1); \ +} \ +inline void v_load_deinterleave( const _Tp0* ptr, _Tpvec0& a0, _Tpvec0& b0, _Tpvec0& c0 ) \ +{ \ + _Tpvec1 a1, b1, c1; \ + v_load_deinterleave((const _Tp1*)ptr, a1, b1, c1); \ + a0 = v_reinterpret_as_##suffix0(a1); \ + b0 = v_reinterpret_as_##suffix0(b1); \ + c0 = v_reinterpret_as_##suffix0(c1); \ +} \ +inline void v_load_deinterleave( const _Tp0* ptr, _Tpvec0& a0, _Tpvec0& b0, _Tpvec0& c0, _Tpvec0& d0 ) \ +{ \ + _Tpvec1 a1, b1, c1, d1; \ + v_load_deinterleave((const _Tp1*)ptr, a1, b1, c1, d1); \ + a0 = v_reinterpret_as_##suffix0(a1); \ + b0 = v_reinterpret_as_##suffix0(b1); \ + c0 = v_reinterpret_as_##suffix0(c1); \ + d0 = v_reinterpret_as_##suffix0(d1); \ +} \ +inline void v_store_interleave( _Tp0* ptr, const _Tpvec0& a0, const _Tpvec0& b0, \ + hal::StoreMode mode = hal::STORE_UNALIGNED ) \ +{ \ + _Tpvec1 a1 = v_reinterpret_as_##suffix1(a0); \ + _Tpvec1 b1 = v_reinterpret_as_##suffix1(b0); \ + v_store_interleave((_Tp1*)ptr, a1, b1, mode); \ +} \ +inline void v_store_interleave( _Tp0* ptr, const _Tpvec0& a0, const _Tpvec0& b0, \ + const _Tpvec0& c0, hal::StoreMode mode = hal::STORE_UNALIGNED ) \ +{ \ + _Tpvec1 a1 = v_reinterpret_as_##suffix1(a0); \ + _Tpvec1 b1 = v_reinterpret_as_##suffix1(b0); \ + _Tpvec1 c1 = v_reinterpret_as_##suffix1(c0); \ + v_store_interleave((_Tp1*)ptr, a1, b1, c1, mode); \ +} \ +inline void v_store_interleave( _Tp0* ptr, const _Tpvec0& a0, const _Tpvec0& b0, \ + const _Tpvec0& c0, const _Tpvec0& d0, \ + hal::StoreMode mode = hal::STORE_UNALIGNED ) \ +{ \ + _Tpvec1 a1 = v_reinterpret_as_##suffix1(a0); \ + _Tpvec1 b1 = v_reinterpret_as_##suffix1(b0); \ + _Tpvec1 c1 = v_reinterpret_as_##suffix1(c0); \ + _Tpvec1 d1 = v_reinterpret_as_##suffix1(d0); \ + v_store_interleave((_Tp1*)ptr, a1, b1, c1, d1, mode); \ +} + +OPENCV_HAL_IMPL_SSE_LOADSTORE_INTERLEAVE(v_int8x16, schar, s8, v_uint8x16, uchar, u8) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INTERLEAVE(v_int16x8, short, s16, v_uint16x8, ushort, u16) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INTERLEAVE(v_int32x4, int, s32, v_uint32x4, unsigned, u32) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INTERLEAVE(v_int64x2, int64, s64, v_uint64x2, uint64, u64) +OPENCV_HAL_IMPL_SSE_LOADSTORE_INTERLEAVE(v_float64x2, double, f64, v_uint64x2, uint64, u64) + +inline v_float32x4 v_cvt_f32(const v_int32x4& a) +{ + return v_float32x4(_mm_cvtepi32_ps(a.val)); +} + +inline v_float32x4 v_cvt_f32(const v_float64x2& a) +{ + return v_float32x4(_mm_cvtpd_ps(a.val)); +} + +inline v_float32x4 v_cvt_f32(const v_float64x2& a, const v_float64x2& b) +{ + return v_float32x4(_mm_movelh_ps(_mm_cvtpd_ps(a.val), _mm_cvtpd_ps(b.val))); +} + +inline v_float64x2 v_cvt_f64(const v_int32x4& a) +{ + return v_float64x2(_mm_cvtepi32_pd(a.val)); +} + +inline v_float64x2 v_cvt_f64_high(const v_int32x4& a) +{ + return v_float64x2(_mm_cvtepi32_pd(_mm_srli_si128(a.val,8))); +} + +inline v_float64x2 v_cvt_f64(const v_float32x4& a) +{ + return v_float64x2(_mm_cvtps_pd(a.val)); +} + +inline v_float64x2 v_cvt_f64_high(const v_float32x4& a) +{ + return v_float64x2(_mm_cvtps_pd(_mm_movehl_ps(a.val, a.val))); +} + +// from (Mysticial and wim) https://stackoverflow.com/q/41144668 +inline v_float64x2 v_cvt_f64(const v_int64x2& v) +{ + // constants encoded as floating-point + __m128i magic_i_hi32 = _mm_set1_epi64x(0x4530000080000000); // 2^84 + 2^63 + __m128i magic_i_all = _mm_set1_epi64x(0x4530000080100000); // 2^84 + 2^63 + 2^52 + __m128d magic_d_all = _mm_castsi128_pd(magic_i_all); + // Blend the 32 lowest significant bits of v with magic_int_lo +#if CV_SSE4_1 + __m128i magic_i_lo = _mm_set1_epi64x(0x4330000000000000); // 2^52 + __m128i v_lo = _mm_blend_epi16(v.val, magic_i_lo, 0xcc); +#else + __m128i magic_i_lo = _mm_set1_epi32(0x43300000); // 2^52 + __m128i v_lo = _mm_unpacklo_epi32(_mm_shuffle_epi32(v.val, _MM_SHUFFLE(0, 0, 2, 0)), magic_i_lo); +#endif + // Extract the 32 most significant bits of v + __m128i v_hi = _mm_srli_epi64(v.val, 32); + // Flip the msb of v_hi and blend with 0x45300000 + v_hi = _mm_xor_si128(v_hi, magic_i_hi32); + // Compute in double precision + __m128d v_hi_dbl = _mm_sub_pd(_mm_castsi128_pd(v_hi), magic_d_all); + // (v_hi - magic_d_all) + v_lo Do not assume associativity of floating point addition + __m128d result = _mm_add_pd(v_hi_dbl, _mm_castsi128_pd(v_lo)); + return v_float64x2(result); +} + +////////////// Lookup table access //////////////////// + +inline v_int8x16 v_lut(const schar* tab, const int* idx) +{ +#if defined(_MSC_VER) + return v_int8x16(_mm_setr_epi8(tab[idx[0]], tab[idx[1]], tab[idx[ 2]], tab[idx[ 3]], tab[idx[ 4]], tab[idx[ 5]], tab[idx[ 6]], tab[idx[ 7]], + tab[idx[8]], tab[idx[9]], tab[idx[10]], tab[idx[11]], tab[idx[12]], tab[idx[13]], tab[idx[14]], tab[idx[15]])); +#else + return v_int8x16(_mm_setr_epi64( + _mm_setr_pi8(tab[idx[0]], tab[idx[1]], tab[idx[ 2]], tab[idx[ 3]], tab[idx[ 4]], tab[idx[ 5]], tab[idx[ 6]], tab[idx[ 7]]), + _mm_setr_pi8(tab[idx[8]], tab[idx[9]], tab[idx[10]], tab[idx[11]], tab[idx[12]], tab[idx[13]], tab[idx[14]], tab[idx[15]]) + )); +#endif +} +inline v_int8x16 v_lut_pairs(const schar* tab, const int* idx) +{ +#if defined(_MSC_VER) + return v_int8x16(_mm_setr_epi16(*(const short*)(tab + idx[0]), *(const short*)(tab + idx[1]), *(const short*)(tab + idx[2]), *(const short*)(tab + idx[3]), + *(const short*)(tab + idx[4]), *(const short*)(tab + idx[5]), *(const short*)(tab + idx[6]), *(const short*)(tab + idx[7]))); +#else + return v_int8x16(_mm_setr_epi64( + _mm_setr_pi16(*(const short*)(tab + idx[0]), *(const short*)(tab + idx[1]), *(const short*)(tab + idx[2]), *(const short*)(tab + idx[3])), + _mm_setr_pi16(*(const short*)(tab + idx[4]), *(const short*)(tab + idx[5]), *(const short*)(tab + idx[6]), *(const short*)(tab + idx[7])) + )); +#endif +} +inline v_int8x16 v_lut_quads(const schar* tab, const int* idx) +{ +#if defined(_MSC_VER) + return v_int8x16(_mm_setr_epi32(*(const int*)(tab + idx[0]), *(const int*)(tab + idx[1]), + *(const int*)(tab + idx[2]), *(const int*)(tab + idx[3]))); +#else + return v_int8x16(_mm_setr_epi64( + _mm_setr_pi32(*(const int*)(tab + idx[0]), *(const int*)(tab + idx[1])), + _mm_setr_pi32(*(const int*)(tab + idx[2]), *(const int*)(tab + idx[3])) + )); +#endif +} +inline v_uint8x16 v_lut(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut((const schar *)tab, idx)); } +inline v_uint8x16 v_lut_pairs(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut_pairs((const schar *)tab, idx)); } +inline v_uint8x16 v_lut_quads(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut_quads((const schar *)tab, idx)); } + +inline v_int16x8 v_lut(const short* tab, const int* idx) +{ +#if defined(_MSC_VER) + return v_int16x8(_mm_setr_epi16(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]], + tab[idx[4]], tab[idx[5]], tab[idx[6]], tab[idx[7]])); +#else + return v_int16x8(_mm_setr_epi64( + _mm_setr_pi16(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]]), + _mm_setr_pi16(tab[idx[4]], tab[idx[5]], tab[idx[6]], tab[idx[7]]) + )); +#endif +} +inline v_int16x8 v_lut_pairs(const short* tab, const int* idx) +{ +#if defined(_MSC_VER) + return v_int16x8(_mm_setr_epi32(*(const int*)(tab + idx[0]), *(const int*)(tab + idx[1]), + *(const int*)(tab + idx[2]), *(const int*)(tab + idx[3]))); +#else + return v_int16x8(_mm_setr_epi64( + _mm_setr_pi32(*(const int*)(tab + idx[0]), *(const int*)(tab + idx[1])), + _mm_setr_pi32(*(const int*)(tab + idx[2]), *(const int*)(tab + idx[3])) + )); +#endif +} +inline v_int16x8 v_lut_quads(const short* tab, const int* idx) +{ + return v_int16x8(_mm_set_epi64x(*(const int64_t*)(tab + idx[1]), *(const int64_t*)(tab + idx[0]))); +} +inline v_uint16x8 v_lut(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut((const short *)tab, idx)); } +inline v_uint16x8 v_lut_pairs(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut_pairs((const short *)tab, idx)); } +inline v_uint16x8 v_lut_quads(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut_quads((const short *)tab, idx)); } + +inline v_int32x4 v_lut(const int* tab, const int* idx) +{ +#if defined(_MSC_VER) + return v_int32x4(_mm_setr_epi32(tab[idx[0]], tab[idx[1]], + tab[idx[2]], tab[idx[3]])); +#else + return v_int32x4(_mm_setr_epi64( + _mm_setr_pi32(tab[idx[0]], tab[idx[1]]), + _mm_setr_pi32(tab[idx[2]], tab[idx[3]]) + )); +#endif +} +inline v_int32x4 v_lut_pairs(const int* tab, const int* idx) +{ + return v_int32x4(_mm_set_epi64x(*(const int64_t*)(tab + idx[1]), *(const int64_t*)(tab + idx[0]))); +} +inline v_int32x4 v_lut_quads(const int* tab, const int* idx) +{ + return v_int32x4(_mm_loadu_si128((const __m128i*)(tab + idx[0]))); +} +inline v_uint32x4 v_lut(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut((const int *)tab, idx)); } +inline v_uint32x4 v_lut_pairs(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut_pairs((const int *)tab, idx)); } +inline v_uint32x4 v_lut_quads(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut_quads((const int *)tab, idx)); } + +inline v_int64x2 v_lut(const int64_t* tab, const int* idx) +{ + return v_int64x2(_mm_set_epi64x(tab[idx[1]], tab[idx[0]])); +} +inline v_int64x2 v_lut_pairs(const int64_t* tab, const int* idx) +{ + return v_int64x2(_mm_loadu_si128((const __m128i*)(tab + idx[0]))); +} +inline v_uint64x2 v_lut(const uint64_t* tab, const int* idx) { return v_reinterpret_as_u64(v_lut((const int64_t *)tab, idx)); } +inline v_uint64x2 v_lut_pairs(const uint64_t* tab, const int* idx) { return v_reinterpret_as_u64(v_lut_pairs((const int64_t *)tab, idx)); } + +inline v_float32x4 v_lut(const float* tab, const int* idx) +{ + return v_float32x4(_mm_setr_ps(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]])); +} +inline v_float32x4 v_lut_pairs(const float* tab, const int* idx) { return v_reinterpret_as_f32(v_lut_pairs((const int *)tab, idx)); } +inline v_float32x4 v_lut_quads(const float* tab, const int* idx) { return v_reinterpret_as_f32(v_lut_quads((const int *)tab, idx)); } + +inline v_float64x2 v_lut(const double* tab, const int* idx) +{ + return v_float64x2(_mm_setr_pd(tab[idx[0]], tab[idx[1]])); +} +inline v_float64x2 v_lut_pairs(const double* tab, const int* idx) { return v_float64x2(_mm_castsi128_pd(_mm_loadu_si128((const __m128i*)(tab + idx[0])))); } + +inline v_int32x4 v_lut(const int* tab, const v_int32x4& idxvec) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + return v_int32x4(_mm_setr_epi32(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]])); +} + +inline v_uint32x4 v_lut(const unsigned* tab, const v_int32x4& idxvec) +{ + return v_reinterpret_as_u32(v_lut((const int *)tab, idxvec)); +} + +inline v_float32x4 v_lut(const float* tab, const v_int32x4& idxvec) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + return v_float32x4(_mm_setr_ps(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]])); +} + +inline v_float64x2 v_lut(const double* tab, const v_int32x4& idxvec) +{ + int idx[2]; + v_store_low(idx, idxvec); + return v_float64x2(_mm_setr_pd(tab[idx[0]], tab[idx[1]])); +} + +// loads pairs from the table and deinterleaves them, e.g. returns: +// x = (tab[idxvec[0], tab[idxvec[1]], tab[idxvec[2]], tab[idxvec[3]]), +// y = (tab[idxvec[0]+1], tab[idxvec[1]+1], tab[idxvec[2]+1], tab[idxvec[3]+1]) +// note that the indices are float's indices, not the float-pair indices. +// in theory, this function can be used to implement bilinear interpolation, +// when idxvec are the offsets within the image. +inline void v_lut_deinterleave(const float* tab, const v_int32x4& idxvec, v_float32x4& x, v_float32x4& y) +{ + int CV_DECL_ALIGNED(32) idx[4]; + v_store_aligned(idx, idxvec); + __m128 z = _mm_setzero_ps(); + __m128 xy01 = _mm_loadl_pi(z, (__m64*)(tab + idx[0])); + __m128 xy23 = _mm_loadl_pi(z, (__m64*)(tab + idx[2])); + xy01 = _mm_loadh_pi(xy01, (__m64*)(tab + idx[1])); + xy23 = _mm_loadh_pi(xy23, (__m64*)(tab + idx[3])); + __m128 xxyy02 = _mm_unpacklo_ps(xy01, xy23); + __m128 xxyy13 = _mm_unpackhi_ps(xy01, xy23); + x = v_float32x4(_mm_unpacklo_ps(xxyy02, xxyy13)); + y = v_float32x4(_mm_unpackhi_ps(xxyy02, xxyy13)); +} + +inline void v_lut_deinterleave(const double* tab, const v_int32x4& idxvec, v_float64x2& x, v_float64x2& y) +{ + int idx[2]; + v_store_low(idx, idxvec); + __m128d xy0 = _mm_loadu_pd(tab + idx[0]); + __m128d xy1 = _mm_loadu_pd(tab + idx[1]); + x = v_float64x2(_mm_unpacklo_pd(xy0, xy1)); + y = v_float64x2(_mm_unpackhi_pd(xy0, xy1)); +} + +inline v_int8x16 v_interleave_pairs(const v_int8x16& vec) +{ +#if CV_SSSE3 + return v_int8x16(_mm_shuffle_epi8(vec.val, _mm_set_epi64x(0x0f0d0e0c0b090a08, 0x0705060403010200))); +#else + __m128i a = _mm_shufflelo_epi16(vec.val, _MM_SHUFFLE(3, 1, 2, 0)); + a = _mm_shufflehi_epi16(a, _MM_SHUFFLE(3, 1, 2, 0)); + a = _mm_shuffle_epi32(a, _MM_SHUFFLE(3, 1, 2, 0)); + return v_int8x16(_mm_unpacklo_epi8(a, _mm_unpackhi_epi64(a, a))); +#endif +} +inline v_uint8x16 v_interleave_pairs(const v_uint8x16& vec) { return v_reinterpret_as_u8(v_interleave_pairs(v_reinterpret_as_s8(vec))); } +inline v_int8x16 v_interleave_quads(const v_int8x16& vec) +{ +#if CV_SSSE3 + return v_int8x16(_mm_shuffle_epi8(vec.val, _mm_set_epi64x(0x0f0b0e0a0d090c08, 0x0703060205010400))); +#else + __m128i a = _mm_shuffle_epi32(vec.val, _MM_SHUFFLE(3, 1, 2, 0)); + return v_int8x16(_mm_unpacklo_epi8(a, _mm_unpackhi_epi64(a, a))); +#endif +} +inline v_uint8x16 v_interleave_quads(const v_uint8x16& vec) { return v_reinterpret_as_u8(v_interleave_quads(v_reinterpret_as_s8(vec))); } + +inline v_int16x8 v_interleave_pairs(const v_int16x8& vec) +{ +#if CV_SSSE3 + return v_int16x8(_mm_shuffle_epi8(vec.val, _mm_set_epi64x(0x0f0e0b0a0d0c0908, 0x0706030205040100))); +#else + __m128i a = _mm_shufflelo_epi16(vec.val, _MM_SHUFFLE(3, 1, 2, 0)); + return v_int16x8(_mm_shufflehi_epi16(a, _MM_SHUFFLE(3, 1, 2, 0))); +#endif +} +inline v_uint16x8 v_interleave_pairs(const v_uint16x8& vec) { return v_reinterpret_as_u16(v_interleave_pairs(v_reinterpret_as_s16(vec))); } +inline v_int16x8 v_interleave_quads(const v_int16x8& vec) +{ +#if CV_SSSE3 + return v_int16x8(_mm_shuffle_epi8(vec.val, _mm_set_epi64x(0x0f0e07060d0c0504, 0x0b0a030209080100))); +#else + return v_int16x8(_mm_unpacklo_epi16(vec.val, _mm_unpackhi_epi64(vec.val, vec.val))); +#endif +} +inline v_uint16x8 v_interleave_quads(const v_uint16x8& vec) { return v_reinterpret_as_u16(v_interleave_quads(v_reinterpret_as_s16(vec))); } + +inline v_int32x4 v_interleave_pairs(const v_int32x4& vec) +{ + return v_int32x4(_mm_shuffle_epi32(vec.val, _MM_SHUFFLE(3, 1, 2, 0))); +} +inline v_uint32x4 v_interleave_pairs(const v_uint32x4& vec) { return v_reinterpret_as_u32(v_interleave_pairs(v_reinterpret_as_s32(vec))); } +inline v_float32x4 v_interleave_pairs(const v_float32x4& vec) { return v_reinterpret_as_f32(v_interleave_pairs(v_reinterpret_as_s32(vec))); } + +inline v_int8x16 v_pack_triplets(const v_int8x16& vec) +{ +#if CV_SSSE3 + return v_int8x16(_mm_shuffle_epi8(vec.val, _mm_set_epi64x(0xffffff0f0e0d0c0a, 0x0908060504020100))); +#else + __m128i mask = _mm_set1_epi64x(0x00000000FFFFFFFF); + __m128i a = _mm_srli_si128(_mm_or_si128(_mm_andnot_si128(mask, vec.val), _mm_and_si128(mask, _mm_sll_epi32(vec.val, _mm_set_epi64x(0, 8)))), 1); + return v_int8x16(_mm_srli_si128(_mm_shufflelo_epi16(a, _MM_SHUFFLE(2, 1, 0, 3)), 2)); +#endif +} +inline v_uint8x16 v_pack_triplets(const v_uint8x16& vec) { return v_reinterpret_as_u8(v_pack_triplets(v_reinterpret_as_s8(vec))); } + +inline v_int16x8 v_pack_triplets(const v_int16x8& vec) +{ +#if CV_SSSE3 + return v_int16x8(_mm_shuffle_epi8(vec.val, _mm_set_epi64x(0xffff0f0e0d0c0b0a, 0x0908050403020100))); +#else + return v_int16x8(_mm_srli_si128(_mm_shufflelo_epi16(vec.val, _MM_SHUFFLE(2, 1, 0, 3)), 2)); +#endif +} +inline v_uint16x8 v_pack_triplets(const v_uint16x8& vec) { return v_reinterpret_as_u16(v_pack_triplets(v_reinterpret_as_s16(vec))); } + +inline v_int32x4 v_pack_triplets(const v_int32x4& vec) { return vec; } +inline v_uint32x4 v_pack_triplets(const v_uint32x4& vec) { return vec; } +inline v_float32x4 v_pack_triplets(const v_float32x4& vec) { return vec; } + +template +inline uchar v_extract_n(const v_uint8x16& v) +{ +#if CV_SSE4_1 + return (uchar)_mm_extract_epi8(v.val, i); +#else + return v_rotate_right(v).get0(); +#endif +} + +template +inline schar v_extract_n(const v_int8x16& v) +{ + return (schar)v_extract_n(v_reinterpret_as_u8(v)); +} + +template +inline ushort v_extract_n(const v_uint16x8& v) +{ + return (ushort)_mm_extract_epi16(v.val, i); +} + +template +inline short v_extract_n(const v_int16x8& v) +{ + return (short)v_extract_n(v_reinterpret_as_u16(v)); +} + +template +inline uint v_extract_n(const v_uint32x4& v) +{ +#if CV_SSE4_1 + return (uint)_mm_extract_epi32(v.val, i); +#else + return v_rotate_right(v).get0(); +#endif +} + +template +inline int v_extract_n(const v_int32x4& v) +{ + return (int)v_extract_n(v_reinterpret_as_u32(v)); +} + +template +inline uint64 v_extract_n(const v_uint64x2& v) +{ +#ifdef CV__SIMD_NATIVE_mm_extract_epi64 + return (uint64)_v128_extract_epi64(v.val); +#else + return v_rotate_right(v).get0(); +#endif +} + +template +inline int64 v_extract_n(const v_int64x2& v) +{ + return (int64)v_extract_n(v_reinterpret_as_u64(v)); +} + +template +inline float v_extract_n(const v_float32x4& v) +{ + union { uint iv; float fv; } d; + d.iv = v_extract_n(v_reinterpret_as_u32(v)); + return d.fv; +} + +template +inline double v_extract_n(const v_float64x2& v) +{ + union { uint64 iv; double dv; } d; + d.iv = v_extract_n(v_reinterpret_as_u64(v)); + return d.dv; +} + +template +inline v_int32x4 v_broadcast_element(const v_int32x4& v) +{ + return v_int32x4(_mm_shuffle_epi32(v.val, _MM_SHUFFLE(i,i,i,i))); +} + +template +inline v_uint32x4 v_broadcast_element(const v_uint32x4& v) +{ + return v_uint32x4(_mm_shuffle_epi32(v.val, _MM_SHUFFLE(i,i,i,i))); +} + +template +inline v_float32x4 v_broadcast_element(const v_float32x4& v) +{ + return v_float32x4(_mm_shuffle_ps(v.val, v.val, _MM_SHUFFLE((char)i,(char)i,(char)i,(char)i))); +} + +////////////// FP16 support /////////////////////////// + +inline v_float32x4 v_load_expand(const float16_t* ptr) +{ +#if CV_FP16 + return v_float32x4(_mm_cvtph_ps(_mm_loadu_si128((const __m128i*)ptr))); +#else + const __m128i z = _mm_setzero_si128(), delta = _mm_set1_epi32(0x38000000); + const __m128i signmask = _mm_set1_epi32(0x80000000), maxexp = _mm_set1_epi32(0x7c000000); + const __m128 deltaf = _mm_castsi128_ps(_mm_set1_epi32(0x38800000)); + __m128i bits = _mm_unpacklo_epi16(z, _mm_loadl_epi64((const __m128i*)ptr)); // h << 16 + __m128i e = _mm_and_si128(bits, maxexp), sign = _mm_and_si128(bits, signmask); + __m128i t = _mm_add_epi32(_mm_srli_epi32(_mm_xor_si128(bits, sign), 3), delta); // ((h & 0x7fff) << 13) + delta + __m128i zt = _mm_castps_si128(_mm_sub_ps(_mm_castsi128_ps(_mm_add_epi32(t, _mm_set1_epi32(1 << 23))), deltaf)); + + t = _mm_add_epi32(t, _mm_and_si128(delta, _mm_cmpeq_epi32(maxexp, e))); + __m128i zmask = _mm_cmpeq_epi32(e, z); + __m128i ft = v_select_si128(zmask, zt, t); + return v_float32x4(_mm_castsi128_ps(_mm_or_si128(ft, sign))); +#endif +} + +inline void v_pack_store(float16_t* ptr, const v_float32x4& v) +{ +#if CV_FP16 + __m128i fp16_value = _mm_cvtps_ph(v.val, 0); + _mm_storel_epi64((__m128i*)ptr, fp16_value); +#else + const __m128i signmask = _mm_set1_epi32(0x80000000); + const __m128i rval = _mm_set1_epi32(0x3f000000); + + __m128i t = _mm_castps_si128(v.val); + __m128i sign = _mm_srai_epi32(_mm_and_si128(t, signmask), 16); + t = _mm_andnot_si128(signmask, t); + + __m128i finitemask = _mm_cmpgt_epi32(_mm_set1_epi32(0x47800000), t); + __m128i isnan = _mm_cmpgt_epi32(t, _mm_set1_epi32(0x7f800000)); + __m128i naninf = v_select_si128(isnan, _mm_set1_epi32(0x7e00), _mm_set1_epi32(0x7c00)); + __m128i tinymask = _mm_cmpgt_epi32(_mm_set1_epi32(0x38800000), t); + __m128i tt = _mm_castps_si128(_mm_add_ps(_mm_castsi128_ps(t), _mm_castsi128_ps(rval))); + tt = _mm_sub_epi32(tt, rval); + __m128i odd = _mm_and_si128(_mm_srli_epi32(t, 13), _mm_set1_epi32(1)); + __m128i nt = _mm_add_epi32(t, _mm_set1_epi32(0xc8000fff)); + nt = _mm_srli_epi32(_mm_add_epi32(nt, odd), 13); + t = v_select_si128(tinymask, tt, nt); + t = v_select_si128(finitemask, t, naninf); + t = _mm_or_si128(t, sign); + t = _mm_packs_epi32(t, t); + _mm_storel_epi64((__m128i*)ptr, t); +#endif +} + +inline void v_cleanup() {} + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END + +//! @endcond + +} + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_sse_em.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_sse_em.hpp new file mode 100644 index 0000000..6fb0881 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_sse_em.hpp @@ -0,0 +1,180 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + +#ifndef OPENCV_HAL_INTRIN_SSE_EM_HPP +#define OPENCV_HAL_INTRIN_SSE_EM_HPP + +namespace cv +{ + +//! @cond IGNORED + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN + +#define OPENCV_HAL_SSE_WRAP_1(fun, tp) \ + inline tp _v128_##fun(const tp& a) \ + { return _mm_##fun(a); } + +#define OPENCV_HAL_SSE_WRAP_2(fun, tp) \ + inline tp _v128_##fun(const tp& a, const tp& b) \ + { return _mm_##fun(a, b); } + +#define OPENCV_HAL_SSE_WRAP_3(fun, tp) \ + inline tp _v128_##fun(const tp& a, const tp& b, const tp& c) \ + { return _mm_##fun(a, b, c); } + +///////////////////////////// XOP ///////////////////////////// + +// [todo] define CV_XOP +#if 1 // CV_XOP +inline __m128i _v128_comgt_epu32(const __m128i& a, const __m128i& b) +{ + const __m128i delta = _mm_set1_epi32((int)0x80000000); + return _mm_cmpgt_epi32(_mm_xor_si128(a, delta), _mm_xor_si128(b, delta)); +} +// wrapping XOP +#else +OPENCV_HAL_SSE_WRAP_2(_v128_comgt_epu32, __m128i) +#endif // !CV_XOP + +///////////////////////////// SSE4.1 ///////////////////////////// + +#if !CV_SSE4_1 + +/** Swizzle **/ +inline __m128i _v128_blendv_epi8(const __m128i& a, const __m128i& b, const __m128i& mask) +{ return _mm_xor_si128(a, _mm_and_si128(_mm_xor_si128(b, a), mask)); } + +/** Convert **/ +// 8 >> 16 +inline __m128i _v128_cvtepu8_epi16(const __m128i& a) +{ + const __m128i z = _mm_setzero_si128(); + return _mm_unpacklo_epi8(a, z); +} +inline __m128i _v128_cvtepi8_epi16(const __m128i& a) +{ return _mm_srai_epi16(_mm_unpacklo_epi8(a, a), 8); } +// 8 >> 32 +inline __m128i _v128_cvtepu8_epi32(const __m128i& a) +{ + const __m128i z = _mm_setzero_si128(); + return _mm_unpacklo_epi16(_mm_unpacklo_epi8(a, z), z); +} +inline __m128i _v128_cvtepi8_epi32(const __m128i& a) +{ + __m128i r = _mm_unpacklo_epi8(a, a); + r = _mm_unpacklo_epi8(r, r); + return _mm_srai_epi32(r, 24); +} +// 16 >> 32 +inline __m128i _v128_cvtepu16_epi32(const __m128i& a) +{ + const __m128i z = _mm_setzero_si128(); + return _mm_unpacklo_epi16(a, z); +} +inline __m128i _v128_cvtepi16_epi32(const __m128i& a) +{ return _mm_srai_epi32(_mm_unpacklo_epi16(a, a), 16); } +// 32 >> 64 +inline __m128i _v128_cvtepu32_epi64(const __m128i& a) +{ + const __m128i z = _mm_setzero_si128(); + return _mm_unpacklo_epi32(a, z); +} +inline __m128i _v128_cvtepi32_epi64(const __m128i& a) +{ return _mm_unpacklo_epi32(a, _mm_srai_epi32(a, 31)); } + +/** Arithmetic **/ +inline __m128i _v128_mullo_epi32(const __m128i& a, const __m128i& b) +{ + __m128i c0 = _mm_mul_epu32(a, b); + __m128i c1 = _mm_mul_epu32(_mm_srli_epi64(a, 32), _mm_srli_epi64(b, 32)); + __m128i d0 = _mm_unpacklo_epi32(c0, c1); + __m128i d1 = _mm_unpackhi_epi32(c0, c1); + return _mm_unpacklo_epi64(d0, d1); +} + +/** Math **/ +inline __m128i _v128_min_epu32(const __m128i& a, const __m128i& b) +{ return _v128_blendv_epi8(a, b, _v128_comgt_epu32(a, b)); } + +// wrapping SSE4.1 +#else +OPENCV_HAL_SSE_WRAP_1(cvtepu8_epi16, __m128i) +OPENCV_HAL_SSE_WRAP_1(cvtepi8_epi16, __m128i) +OPENCV_HAL_SSE_WRAP_1(cvtepu8_epi32, __m128i) +OPENCV_HAL_SSE_WRAP_1(cvtepi8_epi32, __m128i) +OPENCV_HAL_SSE_WRAP_1(cvtepu16_epi32, __m128i) +OPENCV_HAL_SSE_WRAP_1(cvtepi16_epi32, __m128i) +OPENCV_HAL_SSE_WRAP_1(cvtepu32_epi64, __m128i) +OPENCV_HAL_SSE_WRAP_1(cvtepi32_epi64, __m128i) +OPENCV_HAL_SSE_WRAP_2(min_epu32, __m128i) +OPENCV_HAL_SSE_WRAP_2(mullo_epi32, __m128i) +OPENCV_HAL_SSE_WRAP_3(blendv_epi8, __m128i) +#endif // !CV_SSE4_1 + +///////////////////////////// Revolutionary ///////////////////////////// + +/** Convert **/ +// 16 << 8 +inline __m128i _v128_cvtepu8_epi16_high(const __m128i& a) +{ + const __m128i z = _mm_setzero_si128(); + return _mm_unpackhi_epi8(a, z); +} +inline __m128i _v128_cvtepi8_epi16_high(const __m128i& a) +{ return _mm_srai_epi16(_mm_unpackhi_epi8(a, a), 8); } +// 32 << 16 +inline __m128i _v128_cvtepu16_epi32_high(const __m128i& a) +{ + const __m128i z = _mm_setzero_si128(); + return _mm_unpackhi_epi16(a, z); +} +inline __m128i _v128_cvtepi16_epi32_high(const __m128i& a) +{ return _mm_srai_epi32(_mm_unpackhi_epi16(a, a), 16); } +// 64 << 32 +inline __m128i _v128_cvtepu32_epi64_high(const __m128i& a) +{ + const __m128i z = _mm_setzero_si128(); + return _mm_unpackhi_epi32(a, z); +} +inline __m128i _v128_cvtepi32_epi64_high(const __m128i& a) +{ return _mm_unpackhi_epi32(a, _mm_srai_epi32(a, 31)); } + +/** Miscellaneous **/ +inline __m128i _v128_packs_epu32(const __m128i& a, const __m128i& b) +{ + const __m128i m = _mm_set1_epi32(65535); + __m128i am = _v128_min_epu32(a, m); + __m128i bm = _v128_min_epu32(b, m); +#if CV_SSE4_1 + return _mm_packus_epi32(am, bm); +#else + const __m128i d = _mm_set1_epi32(32768), nd = _mm_set1_epi16(-32768); + am = _mm_sub_epi32(am, d); + bm = _mm_sub_epi32(bm, d); + am = _mm_packs_epi32(am, bm); + return _mm_sub_epi16(am, nd); +#endif +} + +template +inline int64 _v128_extract_epi64(const __m128i& a) +{ +#if defined(CV__SIMD_HAVE_mm_extract_epi64) || (CV_SSE4_1 && (defined(__x86_64__)/*GCC*/ || defined(_M_X64)/*MSVC*/)) +#define CV__SIMD_NATIVE_mm_extract_epi64 1 + return _mm_extract_epi64(a, i); +#else + CV_DECL_ALIGNED(16) int64 tmp[2]; + _mm_store_si128((__m128i*)tmp, a); + return tmp[i]; +#endif +} + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END + +//! @endcond + +} // cv:: + +#endif // OPENCV_HAL_INTRIN_SSE_EM_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_vsx.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_vsx.hpp new file mode 100644 index 0000000..b198643 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_vsx.hpp @@ -0,0 +1,1608 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + +#ifndef OPENCV_HAL_VSX_HPP +#define OPENCV_HAL_VSX_HPP + +#include +#include "opencv2/core/utility.hpp" + +#define CV_SIMD128 1 +#define CV_SIMD128_64F 1 + +namespace cv +{ + +//! @cond IGNORED + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN + +///////// Types //////////// + +struct v_uint8x16 +{ + typedef uchar lane_type; + enum { nlanes = 16 }; + vec_uchar16 val; + + explicit v_uint8x16(const vec_uchar16& v) : val(v) + {} + v_uint8x16() + {} + v_uint8x16(vec_bchar16 v) : val(vec_uchar16_c(v)) + {} + v_uint8x16(uchar v0, uchar v1, uchar v2, uchar v3, uchar v4, uchar v5, uchar v6, uchar v7, + uchar v8, uchar v9, uchar v10, uchar v11, uchar v12, uchar v13, uchar v14, uchar v15) + : val(vec_uchar16_set(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)) + {} + + static inline v_uint8x16 zero() { return v_uint8x16(vec_uchar16_z); } + + uchar get0() const + { return vec_extract(val, 0); } +}; + +struct v_int8x16 +{ + typedef schar lane_type; + enum { nlanes = 16 }; + vec_char16 val; + + explicit v_int8x16(const vec_char16& v) : val(v) + {} + v_int8x16() + {} + v_int8x16(vec_bchar16 v) : val(vec_char16_c(v)) + {} + v_int8x16(schar v0, schar v1, schar v2, schar v3, schar v4, schar v5, schar v6, schar v7, + schar v8, schar v9, schar v10, schar v11, schar v12, schar v13, schar v14, schar v15) + : val(vec_char16_set(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)) + {} + + static inline v_int8x16 zero() { return v_int8x16(vec_char16_z); } + + schar get0() const + { return vec_extract(val, 0); } +}; + +struct v_uint16x8 +{ + typedef ushort lane_type; + enum { nlanes = 8 }; + vec_ushort8 val; + + explicit v_uint16x8(const vec_ushort8& v) : val(v) + {} + v_uint16x8() + {} + v_uint16x8(vec_bshort8 v) : val(vec_ushort8_c(v)) + {} + v_uint16x8(ushort v0, ushort v1, ushort v2, ushort v3, ushort v4, ushort v5, ushort v6, ushort v7) + : val(vec_ushort8_set(v0, v1, v2, v3, v4, v5, v6, v7)) + {} + + static inline v_uint16x8 zero() { return v_uint16x8(vec_ushort8_z); } + + ushort get0() const + { return vec_extract(val, 0); } +}; + +struct v_int16x8 +{ + typedef short lane_type; + enum { nlanes = 8 }; + vec_short8 val; + + explicit v_int16x8(const vec_short8& v) : val(v) + {} + v_int16x8() + {} + v_int16x8(vec_bshort8 v) : val(vec_short8_c(v)) + {} + v_int16x8(short v0, short v1, short v2, short v3, short v4, short v5, short v6, short v7) + : val(vec_short8_set(v0, v1, v2, v3, v4, v5, v6, v7)) + {} + + static inline v_int16x8 zero() { return v_int16x8(vec_short8_z); } + + short get0() const + { return vec_extract(val, 0); } +}; + +struct v_uint32x4 +{ + typedef unsigned lane_type; + enum { nlanes = 4 }; + vec_uint4 val; + + explicit v_uint32x4(const vec_uint4& v) : val(v) + {} + v_uint32x4() + {} + v_uint32x4(vec_bint4 v) : val(vec_uint4_c(v)) + {} + v_uint32x4(unsigned v0, unsigned v1, unsigned v2, unsigned v3) : val(vec_uint4_set(v0, v1, v2, v3)) + {} + + static inline v_uint32x4 zero() { return v_uint32x4(vec_uint4_z); } + + uint get0() const + { return vec_extract(val, 0); } +}; + +struct v_int32x4 +{ + typedef int lane_type; + enum { nlanes = 4 }; + vec_int4 val; + + explicit v_int32x4(const vec_int4& v) : val(v) + {} + v_int32x4() + {} + v_int32x4(vec_bint4 v) : val(vec_int4_c(v)) + {} + v_int32x4(int v0, int v1, int v2, int v3) : val(vec_int4_set(v0, v1, v2, v3)) + {} + + static inline v_int32x4 zero() { return v_int32x4(vec_int4_z); } + + int get0() const + { return vec_extract(val, 0); } +}; + +struct v_float32x4 +{ + typedef float lane_type; + enum { nlanes = 4 }; + vec_float4 val; + + explicit v_float32x4(const vec_float4& v) : val(v) + {} + v_float32x4() + {} + v_float32x4(vec_bint4 v) : val(vec_float4_c(v)) + {} + v_float32x4(float v0, float v1, float v2, float v3) : val(vec_float4_set(v0, v1, v2, v3)) + {} + + static inline v_float32x4 zero() { return v_float32x4(vec_float4_z); } + + float get0() const + { return vec_extract(val, 0); } +}; + +struct v_uint64x2 +{ + typedef uint64 lane_type; + enum { nlanes = 2 }; + vec_udword2 val; + + explicit v_uint64x2(const vec_udword2& v) : val(v) + {} + v_uint64x2() + {} + v_uint64x2(vec_bdword2 v) : val(vec_udword2_c(v)) + {} + v_uint64x2(uint64 v0, uint64 v1) : val(vec_udword2_set(v0, v1)) + {} + + static inline v_uint64x2 zero() { return v_uint64x2(vec_udword2_z); } + + uint64 get0() const + { return vec_extract(val, 0); } +}; + +struct v_int64x2 +{ + typedef int64 lane_type; + enum { nlanes = 2 }; + vec_dword2 val; + + explicit v_int64x2(const vec_dword2& v) : val(v) + {} + v_int64x2() + {} + v_int64x2(vec_bdword2 v) : val(vec_dword2_c(v)) + {} + v_int64x2(int64 v0, int64 v1) : val(vec_dword2_set(v0, v1)) + {} + + static inline v_int64x2 zero() { return v_int64x2(vec_dword2_z); } + + int64 get0() const + { return vec_extract(val, 0); } +}; + +struct v_float64x2 +{ + typedef double lane_type; + enum { nlanes = 2 }; + vec_double2 val; + + explicit v_float64x2(const vec_double2& v) : val(v) + {} + v_float64x2() + {} + v_float64x2(vec_bdword2 v) : val(vec_double2_c(v)) + {} + v_float64x2(double v0, double v1) : val(vec_double2_set(v0, v1)) + {} + + static inline v_float64x2 zero() { return v_float64x2(vec_double2_z); } + + double get0() const + { return vec_extract(val, 0); } +}; + +#define OPENCV_HAL_IMPL_VSX_EXTRACT_N(_Tpvec, _Tp) \ +template inline _Tp v_extract_n(VSX_UNUSED(_Tpvec v)) { return vec_extract(v.val, i); } + +OPENCV_HAL_IMPL_VSX_EXTRACT_N(v_uint8x16, uchar) +OPENCV_HAL_IMPL_VSX_EXTRACT_N(v_int8x16, schar) +OPENCV_HAL_IMPL_VSX_EXTRACT_N(v_uint16x8, ushort) +OPENCV_HAL_IMPL_VSX_EXTRACT_N(v_int16x8, short) +OPENCV_HAL_IMPL_VSX_EXTRACT_N(v_uint32x4, uint) +OPENCV_HAL_IMPL_VSX_EXTRACT_N(v_int32x4, int) +OPENCV_HAL_IMPL_VSX_EXTRACT_N(v_uint64x2, uint64) +OPENCV_HAL_IMPL_VSX_EXTRACT_N(v_int64x2, int64) +OPENCV_HAL_IMPL_VSX_EXTRACT_N(v_float32x4, float) +OPENCV_HAL_IMPL_VSX_EXTRACT_N(v_float64x2, double) + +//////////////// Load and store operations /////////////// + +/* + * clang-5 aborted during parse "vec_xxx_c" only if it's + * inside a function template which is defined by preprocessor macro. + * + * if vec_xxx_c defined as C++ cast, clang-5 will pass it +*/ +#define OPENCV_HAL_IMPL_VSX_INITVEC(_Tpvec, _Tp, suffix, cast) \ +inline _Tpvec v_setzero_##suffix() { return _Tpvec(vec_splats((_Tp)0)); } \ +inline _Tpvec v_setall_##suffix(_Tp v) { return _Tpvec(vec_splats((_Tp)v));} \ +template inline _Tpvec v_reinterpret_as_##suffix(const _Tpvec0 &a) \ +{ return _Tpvec((cast)a.val); } + +OPENCV_HAL_IMPL_VSX_INITVEC(v_uint8x16, uchar, u8, vec_uchar16) +OPENCV_HAL_IMPL_VSX_INITVEC(v_int8x16, schar, s8, vec_char16) +OPENCV_HAL_IMPL_VSX_INITVEC(v_uint16x8, ushort, u16, vec_ushort8) +OPENCV_HAL_IMPL_VSX_INITVEC(v_int16x8, short, s16, vec_short8) +OPENCV_HAL_IMPL_VSX_INITVEC(v_uint32x4, uint, u32, vec_uint4) +OPENCV_HAL_IMPL_VSX_INITVEC(v_int32x4, int, s32, vec_int4) +OPENCV_HAL_IMPL_VSX_INITVEC(v_uint64x2, uint64, u64, vec_udword2) +OPENCV_HAL_IMPL_VSX_INITVEC(v_int64x2, int64, s64, vec_dword2) +OPENCV_HAL_IMPL_VSX_INITVEC(v_float32x4, float, f32, vec_float4) +OPENCV_HAL_IMPL_VSX_INITVEC(v_float64x2, double, f64, vec_double2) + +#define OPENCV_HAL_IMPL_VSX_LOADSTORE_C(_Tpvec, _Tp, ld, ld_a, st, st_a) \ +inline _Tpvec v_load(const _Tp* ptr) \ +{ return _Tpvec(ld(0, ptr)); } \ +inline _Tpvec v_load_aligned(VSX_UNUSED(const _Tp* ptr)) \ +{ return _Tpvec(ld_a(0, ptr)); } \ +inline _Tpvec v_load_low(const _Tp* ptr) \ +{ return _Tpvec(vec_ld_l8(ptr)); } \ +inline _Tpvec v_load_halves(const _Tp* ptr0, const _Tp* ptr1) \ +{ return _Tpvec(vec_mergesqh(vec_ld_l8(ptr0), vec_ld_l8(ptr1))); } \ +inline void v_store(_Tp* ptr, const _Tpvec& a) \ +{ st(a.val, 0, ptr); } \ +inline void v_store_aligned(VSX_UNUSED(_Tp* ptr), const _Tpvec& a) \ +{ st_a(a.val, 0, ptr); } \ +inline void v_store_aligned_nocache(VSX_UNUSED(_Tp* ptr), const _Tpvec& a) \ +{ st_a(a.val, 0, ptr); } \ +inline void v_store(_Tp* ptr, const _Tpvec& a, hal::StoreMode mode) \ +{ if(mode == hal::STORE_UNALIGNED) st(a.val, 0, ptr); else st_a(a.val, 0, ptr); } \ +inline void v_store_low(_Tp* ptr, const _Tpvec& a) \ +{ vec_st_l8(a.val, ptr); } \ +inline void v_store_high(_Tp* ptr, const _Tpvec& a) \ +{ vec_st_h8(a.val, ptr); } + +// working around gcc bug for aligned ld/st +// if runtime check for vec_ld/st fail we failback to unaligned ld/st +// https://github.com/opencv/opencv/issues/13211 +#ifdef CV_COMPILER_VSX_BROKEN_ALIGNED + #define OPENCV_HAL_IMPL_VSX_LOADSTORE(_Tpvec, _Tp) \ + OPENCV_HAL_IMPL_VSX_LOADSTORE_C(_Tpvec, _Tp, vsx_ld, vsx_ld, vsx_st, vsx_st) +#else + #define OPENCV_HAL_IMPL_VSX_LOADSTORE(_Tpvec, _Tp) \ + OPENCV_HAL_IMPL_VSX_LOADSTORE_C(_Tpvec, _Tp, vsx_ld, vec_ld, vsx_st, vec_st) +#endif + +OPENCV_HAL_IMPL_VSX_LOADSTORE(v_uint8x16, uchar) +OPENCV_HAL_IMPL_VSX_LOADSTORE(v_int8x16, schar) +OPENCV_HAL_IMPL_VSX_LOADSTORE(v_uint16x8, ushort) +OPENCV_HAL_IMPL_VSX_LOADSTORE(v_int16x8, short) +OPENCV_HAL_IMPL_VSX_LOADSTORE(v_uint32x4, uint) +OPENCV_HAL_IMPL_VSX_LOADSTORE(v_int32x4, int) +OPENCV_HAL_IMPL_VSX_LOADSTORE(v_float32x4, float) + +OPENCV_HAL_IMPL_VSX_LOADSTORE_C(v_float64x2, double, vsx_ld, vsx_ld, vsx_st, vsx_st) +OPENCV_HAL_IMPL_VSX_LOADSTORE_C(v_uint64x2, uint64, vsx_ld2, vsx_ld2, vsx_st2, vsx_st2) +OPENCV_HAL_IMPL_VSX_LOADSTORE_C(v_int64x2, int64, vsx_ld2, vsx_ld2, vsx_st2, vsx_st2) + +//////////////// Value reordering /////////////// + +/* de&interleave */ +#define OPENCV_HAL_IMPL_VSX_INTERLEAVE(_Tp, _Tpvec) \ +inline void v_load_deinterleave(const _Tp* ptr, _Tpvec& a, _Tpvec& b) \ +{ vec_ld_deinterleave(ptr, a.val, b.val);} \ +inline void v_load_deinterleave(const _Tp* ptr, _Tpvec& a, \ + _Tpvec& b, _Tpvec& c) \ +{ vec_ld_deinterleave(ptr, a.val, b.val, c.val); } \ +inline void v_load_deinterleave(const _Tp* ptr, _Tpvec& a, _Tpvec& b, \ + _Tpvec& c, _Tpvec& d) \ +{ vec_ld_deinterleave(ptr, a.val, b.val, c.val, d.val); } \ +inline void v_store_interleave(_Tp* ptr, const _Tpvec& a, const _Tpvec& b, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ vec_st_interleave(a.val, b.val, ptr); } \ +inline void v_store_interleave(_Tp* ptr, const _Tpvec& a, \ + const _Tpvec& b, const _Tpvec& c, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ vec_st_interleave(a.val, b.val, c.val, ptr); } \ +inline void v_store_interleave(_Tp* ptr, const _Tpvec& a, const _Tpvec& b, \ + const _Tpvec& c, const _Tpvec& d, \ + hal::StoreMode /*mode*/=hal::STORE_UNALIGNED) \ +{ vec_st_interleave(a.val, b.val, c.val, d.val, ptr); } + +OPENCV_HAL_IMPL_VSX_INTERLEAVE(uchar, v_uint8x16) +OPENCV_HAL_IMPL_VSX_INTERLEAVE(schar, v_int8x16) +OPENCV_HAL_IMPL_VSX_INTERLEAVE(ushort, v_uint16x8) +OPENCV_HAL_IMPL_VSX_INTERLEAVE(short, v_int16x8) +OPENCV_HAL_IMPL_VSX_INTERLEAVE(uint, v_uint32x4) +OPENCV_HAL_IMPL_VSX_INTERLEAVE(int, v_int32x4) +OPENCV_HAL_IMPL_VSX_INTERLEAVE(float, v_float32x4) +OPENCV_HAL_IMPL_VSX_INTERLEAVE(double, v_float64x2) +OPENCV_HAL_IMPL_VSX_INTERLEAVE(int64, v_int64x2) +OPENCV_HAL_IMPL_VSX_INTERLEAVE(uint64, v_uint64x2) + +/* Expand */ +#define OPENCV_HAL_IMPL_VSX_EXPAND(_Tpvec, _Tpwvec, _Tp, fl, fh) \ +inline void v_expand(const _Tpvec& a, _Tpwvec& b0, _Tpwvec& b1) \ +{ \ + b0.val = fh(a.val); \ + b1.val = fl(a.val); \ +} \ +inline _Tpwvec v_expand_low(const _Tpvec& a) \ +{ return _Tpwvec(fh(a.val)); } \ +inline _Tpwvec v_expand_high(const _Tpvec& a) \ +{ return _Tpwvec(fl(a.val)); } \ +inline _Tpwvec v_load_expand(const _Tp* ptr) \ +{ return _Tpwvec(fh(vec_ld_l8(ptr))); } + +OPENCV_HAL_IMPL_VSX_EXPAND(v_uint8x16, v_uint16x8, uchar, vec_unpacklu, vec_unpackhu) +OPENCV_HAL_IMPL_VSX_EXPAND(v_int8x16, v_int16x8, schar, vec_unpackl, vec_unpackh) +OPENCV_HAL_IMPL_VSX_EXPAND(v_uint16x8, v_uint32x4, ushort, vec_unpacklu, vec_unpackhu) +OPENCV_HAL_IMPL_VSX_EXPAND(v_int16x8, v_int32x4, short, vec_unpackl, vec_unpackh) +OPENCV_HAL_IMPL_VSX_EXPAND(v_uint32x4, v_uint64x2, uint, vec_unpacklu, vec_unpackhu) +OPENCV_HAL_IMPL_VSX_EXPAND(v_int32x4, v_int64x2, int, vec_unpackl, vec_unpackh) + +/* Load and zero expand a 4 byte value into the second dword, first is don't care. */ +#if !defined(CV_COMPILER_VSX_BROKEN_ASM) + #define _LXSIWZX(out, ptr, T) __asm__ ("lxsiwzx %x0, 0, %1\r\n" : "=wa"(out) : "r" (ptr) : "memory"); +#else + /* This is compiler-agnostic, but will introduce an unneeded splat on the critical path. */ + #define _LXSIWZX(out, ptr, T) out = (T)vec_udword2_sp(*(uint32_t*)(ptr)); +#endif + +inline v_uint32x4 v_load_expand_q(const uchar* ptr) +{ + // Zero-extend the extra 24B instead of unpacking. Usually faster in small kernel + // Likewise note, value is zero extended and upper 4 bytes are zero'ed. + vec_uchar16 pmu = {8, 12, 12, 12, 9, 12, 12, 12, 10, 12, 12, 12, 11, 12, 12, 12}; + vec_uchar16 out; + + _LXSIWZX(out, ptr, vec_uchar16); + out = vec_perm(out, out, pmu); + return v_uint32x4((vec_uint4)out); +} + +inline v_int32x4 v_load_expand_q(const schar* ptr) +{ + vec_char16 out; + vec_short8 outs; + vec_int4 outw; + + _LXSIWZX(out, ptr, vec_char16); + outs = vec_unpackl(out); + outw = vec_unpackh(outs); + return v_int32x4(outw); +} + +/* pack */ +#define OPENCV_HAL_IMPL_VSX_PACK(_Tpvec, _Tp, _Tpwvec, _Tpvn, _Tpdel, sfnc, pkfnc, addfnc, pack) \ +inline _Tpvec v_##pack(const _Tpwvec& a, const _Tpwvec& b) \ +{ \ + return _Tpvec(pkfnc(a.val, b.val)); \ +} \ +inline void v_##pack##_store(_Tp* ptr, const _Tpwvec& a) \ +{ \ + vec_st_l8(pkfnc(a.val, a.val), ptr); \ +} \ +template \ +inline _Tpvec v_rshr_##pack(const _Tpwvec& a, const _Tpwvec& b) \ +{ \ + const __vector _Tpvn vn = vec_splats((_Tpvn)n); \ + const __vector _Tpdel delta = vec_splats((_Tpdel)((_Tpdel)1 << (n-1))); \ + return _Tpvec(pkfnc(sfnc(addfnc(a.val, delta), vn), sfnc(addfnc(b.val, delta), vn))); \ +} \ +template \ +inline void v_rshr_##pack##_store(_Tp* ptr, const _Tpwvec& a) \ +{ \ + const __vector _Tpvn vn = vec_splats((_Tpvn)n); \ + const __vector _Tpdel delta = vec_splats((_Tpdel)((_Tpdel)1 << (n-1))); \ + vec_st_l8(pkfnc(sfnc(addfnc(a.val, delta), vn), delta), ptr); \ +} + +OPENCV_HAL_IMPL_VSX_PACK(v_uint8x16, uchar, v_uint16x8, unsigned short, unsigned short, + vec_sr, vec_packs, vec_adds, pack) +OPENCV_HAL_IMPL_VSX_PACK(v_int8x16, schar, v_int16x8, unsigned short, short, + vec_sra, vec_packs, vec_adds, pack) + +OPENCV_HAL_IMPL_VSX_PACK(v_uint16x8, ushort, v_uint32x4, unsigned int, unsigned int, + vec_sr, vec_packs, vec_add, pack) +OPENCV_HAL_IMPL_VSX_PACK(v_int16x8, short, v_int32x4, unsigned int, int, + vec_sra, vec_packs, vec_add, pack) + +OPENCV_HAL_IMPL_VSX_PACK(v_uint32x4, uint, v_uint64x2, unsigned long long, unsigned long long, + vec_sr, vec_pack, vec_add, pack) +OPENCV_HAL_IMPL_VSX_PACK(v_int32x4, int, v_int64x2, unsigned long long, long long, + vec_sra, vec_pack, vec_add, pack) + +OPENCV_HAL_IMPL_VSX_PACK(v_uint8x16, uchar, v_int16x8, unsigned short, short, + vec_sra, vec_packsu, vec_adds, pack_u) +OPENCV_HAL_IMPL_VSX_PACK(v_uint16x8, ushort, v_int32x4, unsigned int, int, + vec_sra, vec_packsu, vec_add, pack_u) +// Following variant is not implemented on other platforms: +//OPENCV_HAL_IMPL_VSX_PACK(v_uint32x4, uint, v_int64x2, unsigned long long, long long, +// vec_sra, vec_packsu, vec_add, pack_u) + +// pack boolean +inline v_uint8x16 v_pack_b(const v_uint16x8& a, const v_uint16x8& b) +{ + vec_uchar16 ab = vec_pack(a.val, b.val); + return v_uint8x16(ab); +} + +inline v_uint8x16 v_pack_b(const v_uint32x4& a, const v_uint32x4& b, + const v_uint32x4& c, const v_uint32x4& d) +{ + vec_ushort8 ab = vec_pack(a.val, b.val); + vec_ushort8 cd = vec_pack(c.val, d.val); + return v_uint8x16(vec_pack(ab, cd)); +} + +inline v_uint8x16 v_pack_b(const v_uint64x2& a, const v_uint64x2& b, const v_uint64x2& c, + const v_uint64x2& d, const v_uint64x2& e, const v_uint64x2& f, + const v_uint64x2& g, const v_uint64x2& h) +{ + vec_uint4 ab = vec_pack(a.val, b.val); + vec_uint4 cd = vec_pack(c.val, d.val); + vec_uint4 ef = vec_pack(e.val, f.val); + vec_uint4 gh = vec_pack(g.val, h.val); + + vec_ushort8 abcd = vec_pack(ab, cd); + vec_ushort8 efgh = vec_pack(ef, gh); + return v_uint8x16(vec_pack(abcd, efgh)); +} + +/* Recombine */ +template +inline void v_zip(const _Tpvec& a0, const _Tpvec& a1, _Tpvec& b0, _Tpvec& b1) +{ + b0.val = vec_mergeh(a0.val, a1.val); + b1.val = vec_mergel(a0.val, a1.val); +} + +template +inline _Tpvec v_combine_high(const _Tpvec& a, const _Tpvec& b) +{ return _Tpvec(vec_mergesql(a.val, b.val)); } + +template +inline _Tpvec v_combine_low(const _Tpvec& a, const _Tpvec& b) +{ return _Tpvec(vec_mergesqh(a.val, b.val)); } + +template +inline void v_recombine(const _Tpvec& a, const _Tpvec& b, _Tpvec& c, _Tpvec& d) +{ + c.val = vec_mergesqh(a.val, b.val); + d.val = vec_mergesql(a.val, b.val); +} + +////////// Arithmetic, bitwise and comparison operations ///////// + +/* Element-wise binary and unary operations */ +/** Arithmetics **/ +#define OPENCV_HAL_IMPL_VSX_BIN_OP(bin_op, _Tpvec, intrin) \ +inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(intrin(a.val, b.val)); } \ +inline _Tpvec& operator bin_op##= (_Tpvec& a, const _Tpvec& b) \ +{ a.val = intrin(a.val, b.val); return a; } + +OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_uint8x16, vec_adds) +OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_uint8x16, vec_subs) +OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_int8x16, vec_adds) +OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_int8x16, vec_subs) +OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_uint16x8, vec_adds) +OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_uint16x8, vec_subs) +OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_int16x8, vec_adds) +OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_int16x8, vec_subs) +OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_uint32x4, vec_add) +OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_uint32x4, vec_sub) +OPENCV_HAL_IMPL_VSX_BIN_OP(*, v_uint32x4, vec_mul) +OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_int32x4, vec_add) +OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_int32x4, vec_sub) +OPENCV_HAL_IMPL_VSX_BIN_OP(*, v_int32x4, vec_mul) +OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_float32x4, vec_add) +OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_float32x4, vec_sub) +OPENCV_HAL_IMPL_VSX_BIN_OP(*, v_float32x4, vec_mul) +OPENCV_HAL_IMPL_VSX_BIN_OP(/, v_float32x4, vec_div) +OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_float64x2, vec_add) +OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_float64x2, vec_sub) +OPENCV_HAL_IMPL_VSX_BIN_OP(*, v_float64x2, vec_mul) +OPENCV_HAL_IMPL_VSX_BIN_OP(/, v_float64x2, vec_div) +OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_uint64x2, vec_add) +OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_uint64x2, vec_sub) +OPENCV_HAL_IMPL_VSX_BIN_OP(+, v_int64x2, vec_add) +OPENCV_HAL_IMPL_VSX_BIN_OP(-, v_int64x2, vec_sub) + +// saturating multiply +#define OPENCV_HAL_IMPL_VSX_MUL_SAT(_Tpvec, _Tpwvec) \ + inline _Tpvec operator * (const _Tpvec& a, const _Tpvec& b) \ + { \ + _Tpwvec c, d; \ + v_mul_expand(a, b, c, d); \ + return v_pack(c, d); \ + } \ + inline _Tpvec& operator *= (_Tpvec& a, const _Tpvec& b) \ + { a = a * b; return a; } + +OPENCV_HAL_IMPL_VSX_MUL_SAT(v_int8x16, v_int16x8) +OPENCV_HAL_IMPL_VSX_MUL_SAT(v_uint8x16, v_uint16x8) +OPENCV_HAL_IMPL_VSX_MUL_SAT(v_int16x8, v_int32x4) +OPENCV_HAL_IMPL_VSX_MUL_SAT(v_uint16x8, v_uint32x4) + +template +inline void v_mul_expand(const Tvec& a, const Tvec& b, Twvec& c, Twvec& d) +{ + Twvec p0 = Twvec(vec_mule(a.val, b.val)); + Twvec p1 = Twvec(vec_mulo(a.val, b.val)); + v_zip(p0, p1, c, d); +} + +inline v_int16x8 v_mul_hi(const v_int16x8& a, const v_int16x8& b) +{ + vec_int4 p0 = vec_mule(a.val, b.val); + vec_int4 p1 = vec_mulo(a.val, b.val); + static const vec_uchar16 perm = {2, 3, 18, 19, 6, 7, 22, 23, 10, 11, 26, 27, 14, 15, 30, 31}; + return v_int16x8(vec_perm(vec_short8_c(p0), vec_short8_c(p1), perm)); +} +inline v_uint16x8 v_mul_hi(const v_uint16x8& a, const v_uint16x8& b) +{ + vec_uint4 p0 = vec_mule(a.val, b.val); + vec_uint4 p1 = vec_mulo(a.val, b.val); + static const vec_uchar16 perm = {2, 3, 18, 19, 6, 7, 22, 23, 10, 11, 26, 27, 14, 15, 30, 31}; + return v_uint16x8(vec_perm(vec_ushort8_c(p0), vec_ushort8_c(p1), perm)); +} + +/** Non-saturating arithmetics **/ +#define OPENCV_HAL_IMPL_VSX_BIN_FUNC(func, intrin) \ +template \ +inline _Tpvec func(const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(intrin(a.val, b.val)); } + +OPENCV_HAL_IMPL_VSX_BIN_FUNC(v_add_wrap, vec_add) +OPENCV_HAL_IMPL_VSX_BIN_FUNC(v_sub_wrap, vec_sub) +OPENCV_HAL_IMPL_VSX_BIN_FUNC(v_mul_wrap, vec_mul) + +/** Bitwise shifts **/ +#define OPENCV_HAL_IMPL_VSX_SHIFT_OP(_Tpvec, shr, splfunc) \ +inline _Tpvec operator << (const _Tpvec& a, int imm) \ +{ return _Tpvec(vec_sl(a.val, splfunc(imm))); } \ +inline _Tpvec operator >> (const _Tpvec& a, int imm) \ +{ return _Tpvec(shr(a.val, splfunc(imm))); } \ +template inline _Tpvec v_shl(const _Tpvec& a) \ +{ return _Tpvec(vec_sl(a.val, splfunc(imm))); } \ +template inline _Tpvec v_shr(const _Tpvec& a) \ +{ return _Tpvec(shr(a.val, splfunc(imm))); } + +OPENCV_HAL_IMPL_VSX_SHIFT_OP(v_uint8x16, vec_sr, vec_uchar16_sp) +OPENCV_HAL_IMPL_VSX_SHIFT_OP(v_uint16x8, vec_sr, vec_ushort8_sp) +OPENCV_HAL_IMPL_VSX_SHIFT_OP(v_uint32x4, vec_sr, vec_uint4_sp) +OPENCV_HAL_IMPL_VSX_SHIFT_OP(v_uint64x2, vec_sr, vec_udword2_sp) +// algebraic right shift +OPENCV_HAL_IMPL_VSX_SHIFT_OP(v_int8x16, vec_sra, vec_uchar16_sp) +OPENCV_HAL_IMPL_VSX_SHIFT_OP(v_int16x8, vec_sra, vec_ushort8_sp) +OPENCV_HAL_IMPL_VSX_SHIFT_OP(v_int32x4, vec_sra, vec_uint4_sp) +OPENCV_HAL_IMPL_VSX_SHIFT_OP(v_int64x2, vec_sra, vec_udword2_sp) + +/** Bitwise logic **/ +#define OPENCV_HAL_IMPL_VSX_LOGIC_OP(_Tpvec) \ +OPENCV_HAL_IMPL_VSX_BIN_OP(&, _Tpvec, vec_and) \ +OPENCV_HAL_IMPL_VSX_BIN_OP(|, _Tpvec, vec_or) \ +OPENCV_HAL_IMPL_VSX_BIN_OP(^, _Tpvec, vec_xor) \ +inline _Tpvec operator ~ (const _Tpvec& a) \ +{ return _Tpvec(vec_not(a.val)); } + +OPENCV_HAL_IMPL_VSX_LOGIC_OP(v_uint8x16) +OPENCV_HAL_IMPL_VSX_LOGIC_OP(v_int8x16) +OPENCV_HAL_IMPL_VSX_LOGIC_OP(v_uint16x8) +OPENCV_HAL_IMPL_VSX_LOGIC_OP(v_int16x8) +OPENCV_HAL_IMPL_VSX_LOGIC_OP(v_uint32x4) +OPENCV_HAL_IMPL_VSX_LOGIC_OP(v_int32x4) +OPENCV_HAL_IMPL_VSX_LOGIC_OP(v_uint64x2) +OPENCV_HAL_IMPL_VSX_LOGIC_OP(v_int64x2) +OPENCV_HAL_IMPL_VSX_LOGIC_OP(v_float32x4) +OPENCV_HAL_IMPL_VSX_LOGIC_OP(v_float64x2) + +/** Bitwise select **/ +#define OPENCV_HAL_IMPL_VSX_SELECT(_Tpvec, cast) \ +inline _Tpvec v_select(const _Tpvec& mask, const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vec_sel(b.val, a.val, cast(mask.val))); } + +OPENCV_HAL_IMPL_VSX_SELECT(v_uint8x16, vec_bchar16_c) +OPENCV_HAL_IMPL_VSX_SELECT(v_int8x16, vec_bchar16_c) +OPENCV_HAL_IMPL_VSX_SELECT(v_uint16x8, vec_bshort8_c) +OPENCV_HAL_IMPL_VSX_SELECT(v_int16x8, vec_bshort8_c) +OPENCV_HAL_IMPL_VSX_SELECT(v_uint32x4, vec_bint4_c) +OPENCV_HAL_IMPL_VSX_SELECT(v_int32x4, vec_bint4_c) +OPENCV_HAL_IMPL_VSX_SELECT(v_float32x4, vec_bint4_c) +OPENCV_HAL_IMPL_VSX_SELECT(v_float64x2, vec_bdword2_c) + +/** Comparison **/ +#define OPENCV_HAL_IMPL_VSX_INT_CMP_OP(_Tpvec) \ +inline _Tpvec operator == (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vec_cmpeq(a.val, b.val)); } \ +inline _Tpvec operator != (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vec_cmpne(a.val, b.val)); } \ +inline _Tpvec operator < (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vec_cmplt(a.val, b.val)); } \ +inline _Tpvec operator > (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vec_cmpgt(a.val, b.val)); } \ +inline _Tpvec operator <= (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vec_cmple(a.val, b.val)); } \ +inline _Tpvec operator >= (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vec_cmpge(a.val, b.val)); } + +OPENCV_HAL_IMPL_VSX_INT_CMP_OP(v_uint8x16) +OPENCV_HAL_IMPL_VSX_INT_CMP_OP(v_int8x16) +OPENCV_HAL_IMPL_VSX_INT_CMP_OP(v_uint16x8) +OPENCV_HAL_IMPL_VSX_INT_CMP_OP(v_int16x8) +OPENCV_HAL_IMPL_VSX_INT_CMP_OP(v_uint32x4) +OPENCV_HAL_IMPL_VSX_INT_CMP_OP(v_int32x4) +OPENCV_HAL_IMPL_VSX_INT_CMP_OP(v_float32x4) +OPENCV_HAL_IMPL_VSX_INT_CMP_OP(v_float64x2) +OPENCV_HAL_IMPL_VSX_INT_CMP_OP(v_uint64x2) +OPENCV_HAL_IMPL_VSX_INT_CMP_OP(v_int64x2) + +inline v_float32x4 v_not_nan(const v_float32x4& a) +{ return v_float32x4(vec_cmpeq(a.val, a.val)); } +inline v_float64x2 v_not_nan(const v_float64x2& a) +{ return v_float64x2(vec_cmpeq(a.val, a.val)); } + +/** min/max **/ +OPENCV_HAL_IMPL_VSX_BIN_FUNC(v_min, vec_min) +OPENCV_HAL_IMPL_VSX_BIN_FUNC(v_max, vec_max) + +/** Rotate **/ +#define OPENCV_IMPL_VSX_ROTATE(_Tpvec, suffix, shf, cast) \ +template \ +inline _Tpvec v_rotate_##suffix(const _Tpvec& a) \ +{ \ + const int wd = imm * sizeof(typename _Tpvec::lane_type); \ + if (wd > 15) \ + return _Tpvec::zero(); \ + return _Tpvec((cast)shf(vec_uchar16_c(a.val), vec_uchar16_sp(wd << 3))); \ +} + +#define OPENCV_IMPL_VSX_ROTATE_LR(_Tpvec, cast) \ +OPENCV_IMPL_VSX_ROTATE(_Tpvec, left, vec_slo, cast) \ +OPENCV_IMPL_VSX_ROTATE(_Tpvec, right, vec_sro, cast) + +OPENCV_IMPL_VSX_ROTATE_LR(v_uint8x16, vec_uchar16) +OPENCV_IMPL_VSX_ROTATE_LR(v_int8x16, vec_char16) +OPENCV_IMPL_VSX_ROTATE_LR(v_uint16x8, vec_ushort8) +OPENCV_IMPL_VSX_ROTATE_LR(v_int16x8, vec_short8) +OPENCV_IMPL_VSX_ROTATE_LR(v_uint32x4, vec_uint4) +OPENCV_IMPL_VSX_ROTATE_LR(v_int32x4, vec_int4) +OPENCV_IMPL_VSX_ROTATE_LR(v_float32x4, vec_float4) +OPENCV_IMPL_VSX_ROTATE_LR(v_uint64x2, vec_udword2) +OPENCV_IMPL_VSX_ROTATE_LR(v_int64x2, vec_dword2) +OPENCV_IMPL_VSX_ROTATE_LR(v_float64x2, vec_double2) + +template +inline _Tpvec v_rotate_right(const _Tpvec& a, const _Tpvec& b) +{ + enum { CV_SHIFT = 16 - imm * (sizeof(typename _Tpvec::lane_type)) }; + if (CV_SHIFT == 16) + return a; +#ifdef __IBMCPP__ + return _Tpvec(vec_sld(b.val, a.val, CV_SHIFT & 15)); +#else + return _Tpvec(vec_sld(b.val, a.val, CV_SHIFT)); +#endif +} + +template +inline _Tpvec v_rotate_left(const _Tpvec& a, const _Tpvec& b) +{ + enum { CV_SHIFT = imm * (sizeof(typename _Tpvec::lane_type)) }; + if (CV_SHIFT == 16) + return b; + return _Tpvec(vec_sld(a.val, b.val, CV_SHIFT)); +} + +#define OPENCV_IMPL_VSX_ROTATE_64_2RG(_Tpvec, suffix, rg1, rg2) \ +template \ +inline _Tpvec v_rotate_##suffix(const _Tpvec& a, const _Tpvec& b) \ +{ \ + if (imm == 1) \ + return _Tpvec(vec_permi(rg1.val, rg2.val, 2)); \ + return imm ? b : a; \ +} + +#define OPENCV_IMPL_VSX_ROTATE_64_2RG_LR(_Tpvec) \ +OPENCV_IMPL_VSX_ROTATE_64_2RG(_Tpvec, left, b, a) \ +OPENCV_IMPL_VSX_ROTATE_64_2RG(_Tpvec, right, a, b) + +OPENCV_IMPL_VSX_ROTATE_64_2RG_LR(v_float64x2) +OPENCV_IMPL_VSX_ROTATE_64_2RG_LR(v_uint64x2) +OPENCV_IMPL_VSX_ROTATE_64_2RG_LR(v_int64x2) + +/* Reverse */ +inline v_uint8x16 v_reverse(const v_uint8x16 &a) +{ + static const vec_uchar16 perm = {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + vec_uchar16 vec = (vec_uchar16)a.val; + return v_uint8x16(vec_perm(vec, vec, perm)); +} + +inline v_int8x16 v_reverse(const v_int8x16 &a) +{ return v_reinterpret_as_s8(v_reverse(v_reinterpret_as_u8(a))); } + +inline v_uint16x8 v_reverse(const v_uint16x8 &a) +{ + static const vec_uchar16 perm = {14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1}; + vec_uchar16 vec = (vec_uchar16)a.val; + return v_reinterpret_as_u16(v_uint8x16(vec_perm(vec, vec, perm))); +} + +inline v_int16x8 v_reverse(const v_int16x8 &a) +{ return v_reinterpret_as_s16(v_reverse(v_reinterpret_as_u16(a))); } + +inline v_uint32x4 v_reverse(const v_uint32x4 &a) +{ + static const vec_uchar16 perm = {12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3}; + vec_uchar16 vec = (vec_uchar16)a.val; + return v_reinterpret_as_u32(v_uint8x16(vec_perm(vec, vec, perm))); +} + +inline v_int32x4 v_reverse(const v_int32x4 &a) +{ return v_reinterpret_as_s32(v_reverse(v_reinterpret_as_u32(a))); } + +inline v_float32x4 v_reverse(const v_float32x4 &a) +{ return v_reinterpret_as_f32(v_reverse(v_reinterpret_as_u32(a))); } + +inline v_uint64x2 v_reverse(const v_uint64x2 &a) +{ + static const vec_uchar16 perm = {8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7}; + vec_uchar16 vec = (vec_uchar16)a.val; + return v_reinterpret_as_u64(v_uint8x16(vec_perm(vec, vec, perm))); +} + +inline v_int64x2 v_reverse(const v_int64x2 &a) +{ return v_reinterpret_as_s64(v_reverse(v_reinterpret_as_u64(a))); } + +inline v_float64x2 v_reverse(const v_float64x2 &a) +{ return v_reinterpret_as_f64(v_reverse(v_reinterpret_as_u64(a))); } + +/* Extract */ +template +inline _Tpvec v_extract(const _Tpvec& a, const _Tpvec& b) +{ return v_rotate_right(a, b); } + +////////// Reduce and mask ///////// + +/** Reduce **/ +inline uint v_reduce_sum(const v_uint8x16& a) +{ + const vec_uint4 zero4 = vec_uint4_z; + vec_uint4 sum4 = vec_sum4s(a.val, zero4); + return (uint)vec_extract(vec_sums(vec_int4_c(sum4), vec_int4_c(zero4)), 3); +} +inline int v_reduce_sum(const v_int8x16& a) +{ + const vec_int4 zero4 = vec_int4_z; + vec_int4 sum4 = vec_sum4s(a.val, zero4); + return (int)vec_extract(vec_sums(sum4, zero4), 3); +} +inline int v_reduce_sum(const v_int16x8& a) +{ + const vec_int4 zero = vec_int4_z; + return saturate_cast(vec_extract(vec_sums(vec_sum4s(a.val, zero), zero), 3)); +} +inline uint v_reduce_sum(const v_uint16x8& a) +{ + const vec_int4 v4 = vec_int4_c(vec_unpackhu(vec_adds(a.val, vec_sld(a.val, a.val, 8)))); + return saturate_cast(vec_extract(vec_sums(v4, vec_int4_z), 3)); +} + +#define OPENCV_HAL_IMPL_VSX_REDUCE_OP_4(_Tpvec, _Tpvec2, scalartype, suffix, func) \ +inline scalartype v_reduce_##suffix(const _Tpvec& a) \ +{ \ + const _Tpvec2 rs = func(a.val, vec_sld(a.val, a.val, 8)); \ + return vec_extract(func(rs, vec_sld(rs, rs, 4)), 0); \ +} +OPENCV_HAL_IMPL_VSX_REDUCE_OP_4(v_uint32x4, vec_uint4, uint, sum, vec_add) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_4(v_uint32x4, vec_uint4, uint, max, vec_max) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_4(v_uint32x4, vec_uint4, uint, min, vec_min) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_4(v_int32x4, vec_int4, int, sum, vec_add) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_4(v_int32x4, vec_int4, int, max, vec_max) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_4(v_int32x4, vec_int4, int, min, vec_min) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_4(v_float32x4, vec_float4, float, sum, vec_add) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_4(v_float32x4, vec_float4, float, max, vec_max) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_4(v_float32x4, vec_float4, float, min, vec_min) + +inline uint64 v_reduce_sum(const v_uint64x2& a) +{ + return vec_extract(vec_add(a.val, vec_permi(a.val, a.val, 3)), 0); +} +inline int64 v_reduce_sum(const v_int64x2& a) +{ + return vec_extract(vec_add(a.val, vec_permi(a.val, a.val, 3)), 0); +} +inline double v_reduce_sum(const v_float64x2& a) +{ + return vec_extract(vec_add(a.val, vec_permi(a.val, a.val, 3)), 0); +} + +#define OPENCV_HAL_IMPL_VSX_REDUCE_OP_8(_Tpvec, _Tpvec2, scalartype, suffix, func) \ +inline scalartype v_reduce_##suffix(const _Tpvec& a) \ +{ \ + _Tpvec2 rs = func(a.val, vec_sld(a.val, a.val, 8)); \ + rs = func(rs, vec_sld(rs, rs, 4)); \ + return vec_extract(func(rs, vec_sld(rs, rs, 2)), 0); \ +} +OPENCV_HAL_IMPL_VSX_REDUCE_OP_8(v_uint16x8, vec_ushort8, ushort, max, vec_max) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_8(v_uint16x8, vec_ushort8, ushort, min, vec_min) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_8(v_int16x8, vec_short8, short, max, vec_max) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_8(v_int16x8, vec_short8, short, min, vec_min) + +#define OPENCV_HAL_IMPL_VSX_REDUCE_OP_16(_Tpvec, _Tpvec2, scalartype, suffix, func) \ +inline scalartype v_reduce_##suffix(const _Tpvec& a) \ +{ \ + _Tpvec2 rs = func(a.val, vec_sld(a.val, a.val, 8)); \ + rs = func(rs, vec_sld(rs, rs, 4)); \ + rs = func(rs, vec_sld(rs, rs, 2)); \ + return vec_extract(func(rs, vec_sld(rs, rs, 1)), 0); \ +} +OPENCV_HAL_IMPL_VSX_REDUCE_OP_16(v_uint8x16, vec_uchar16, uchar, max, vec_max) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_16(v_uint8x16, vec_uchar16, uchar, min, vec_min) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_16(v_int8x16, vec_char16, schar, max, vec_max) +OPENCV_HAL_IMPL_VSX_REDUCE_OP_16(v_int8x16, vec_char16, schar, min, vec_min) + +inline v_float32x4 v_reduce_sum4(const v_float32x4& a, const v_float32x4& b, + const v_float32x4& c, const v_float32x4& d) +{ + vec_float4 ac = vec_add(vec_mergel(a.val, c.val), vec_mergeh(a.val, c.val)); + ac = vec_add(ac, vec_sld(ac, ac, 8)); + + vec_float4 bd = vec_add(vec_mergel(b.val, d.val), vec_mergeh(b.val, d.val)); + bd = vec_add(bd, vec_sld(bd, bd, 8)); + return v_float32x4(vec_mergeh(ac, bd)); +} + +inline unsigned v_reduce_sad(const v_uint8x16& a, const v_uint8x16& b) +{ + const vec_uint4 zero4 = vec_uint4_z; + vec_uint4 sum4 = vec_sum4s(vec_absd(a.val, b.val), zero4); + return (unsigned)vec_extract(vec_sums(vec_int4_c(sum4), vec_int4_c(zero4)), 3); +} +inline unsigned v_reduce_sad(const v_int8x16& a, const v_int8x16& b) +{ + const vec_int4 zero4 = vec_int4_z; + vec_char16 ad = vec_abss(vec_subs(a.val, b.val)); + vec_int4 sum4 = vec_sum4s(ad, zero4); + return (unsigned)vec_extract(vec_sums(sum4, zero4), 3); +} +inline unsigned v_reduce_sad(const v_uint16x8& a, const v_uint16x8& b) +{ + vec_ushort8 ad = vec_absd(a.val, b.val); + VSX_UNUSED(vec_int4) sum = vec_sums(vec_int4_c(vec_unpackhu(ad)) + vec_int4_c(vec_unpacklu(ad)), vec_int4_z); + return (unsigned)vec_extract(sum, 3); +} +inline unsigned v_reduce_sad(const v_int16x8& a, const v_int16x8& b) +{ + const vec_int4 zero4 = vec_int4_z; + vec_short8 ad = vec_abss(vec_subs(a.val, b.val)); + vec_int4 sum4 = vec_sum4s(ad, zero4); + return (unsigned)vec_extract(vec_sums(sum4, zero4), 3); +} +inline unsigned v_reduce_sad(const v_uint32x4& a, const v_uint32x4& b) +{ + const vec_uint4 ad = vec_absd(a.val, b.val); + const vec_uint4 rd = vec_add(ad, vec_sld(ad, ad, 8)); + return vec_extract(vec_add(rd, vec_sld(rd, rd, 4)), 0); +} +inline unsigned v_reduce_sad(const v_int32x4& a, const v_int32x4& b) +{ + vec_int4 ad = vec_abss(vec_sub(a.val, b.val)); + return (unsigned)vec_extract(vec_sums(ad, vec_int4_z), 3); +} +inline float v_reduce_sad(const v_float32x4& a, const v_float32x4& b) +{ + const vec_float4 ad = vec_abs(vec_sub(a.val, b.val)); + const vec_float4 rd = vec_add(ad, vec_sld(ad, ad, 8)); + return vec_extract(vec_add(rd, vec_sld(rd, rd, 4)), 0); +} + +/** Popcount **/ +inline v_uint8x16 v_popcount(const v_uint8x16& a) +{ return v_uint8x16(vec_popcntu(a.val)); } +inline v_uint8x16 v_popcount(const v_int8x16& a) +{ return v_uint8x16(vec_popcntu(a.val)); } +inline v_uint16x8 v_popcount(const v_uint16x8& a) +{ return v_uint16x8(vec_popcntu(a.val)); } +inline v_uint16x8 v_popcount(const v_int16x8& a) +{ return v_uint16x8(vec_popcntu(a.val)); } +inline v_uint32x4 v_popcount(const v_uint32x4& a) +{ return v_uint32x4(vec_popcntu(a.val)); } +inline v_uint32x4 v_popcount(const v_int32x4& a) +{ return v_uint32x4(vec_popcntu(a.val)); } +inline v_uint64x2 v_popcount(const v_uint64x2& a) +{ return v_uint64x2(vec_popcntu(a.val)); } +inline v_uint64x2 v_popcount(const v_int64x2& a) +{ return v_uint64x2(vec_popcntu(a.val)); } + +/** Mask **/ +inline int v_signmask(const v_uint8x16& a) +{ + static const vec_uchar16 qperm = {120, 112, 104, 96, 88, 80, 72, 64, 56, 48, 40, 32, 24, 16, 8, 0}; + return vec_extract((vec_int4)vec_vbpermq(v_reinterpret_as_u8(a).val, qperm), 2); +} +inline int v_signmask(const v_int8x16& a) +{ return v_signmask(v_reinterpret_as_u8(a)); } + +inline int v_signmask(const v_int16x8& a) +{ + static const vec_uchar16 qperm = {112, 96, 80, 64, 48, 32, 16, 0, 128, 128, 128, 128, 128, 128, 128, 128}; + return vec_extract((vec_int4)vec_vbpermq(v_reinterpret_as_u8(a).val, qperm), 2); +} +inline int v_signmask(const v_uint16x8& a) +{ return v_signmask(v_reinterpret_as_s16(a)); } + +inline int v_signmask(const v_int32x4& a) +{ + static const vec_uchar16 qperm = {96, 64, 32, 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}; + return vec_extract((vec_int4)vec_vbpermq(v_reinterpret_as_u8(a).val, qperm), 2); +} +inline int v_signmask(const v_uint32x4& a) +{ return v_signmask(v_reinterpret_as_s32(a)); } +inline int v_signmask(const v_float32x4& a) +{ return v_signmask(v_reinterpret_as_s32(a)); } + +inline int v_signmask(const v_int64x2& a) +{ + VSX_UNUSED(const vec_dword2) sv = vec_sr(a.val, vec_udword2_sp(63)); + return (int)vec_extract(sv, 0) | (int)vec_extract(sv, 1) << 1; +} +inline int v_signmask(const v_uint64x2& a) +{ return v_signmask(v_reinterpret_as_s64(a)); } +inline int v_signmask(const v_float64x2& a) +{ return v_signmask(v_reinterpret_as_s64(a)); } + +inline int v_scan_forward(const v_int8x16& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_uint8x16& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_int16x8& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_uint16x8& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_int32x4& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_uint32x4& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_float32x4& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_int64x2& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_uint64x2& a) { return trailingZeros32(v_signmask(a)); } +inline int v_scan_forward(const v_float64x2& a) { return trailingZeros32(v_signmask(a)); } + +template +inline bool v_check_all(const _Tpvec& a) +{ return vec_all_lt(a.val, _Tpvec::zero().val); } +inline bool v_check_all(const v_uint8x16& a) +{ return v_check_all(v_reinterpret_as_s8(a)); } +inline bool v_check_all(const v_uint16x8& a) +{ return v_check_all(v_reinterpret_as_s16(a)); } +inline bool v_check_all(const v_uint32x4& a) +{ return v_check_all(v_reinterpret_as_s32(a)); } +inline bool v_check_all(const v_uint64x2& a) +{ return v_check_all(v_reinterpret_as_s64(a)); } +inline bool v_check_all(const v_float32x4& a) +{ return v_check_all(v_reinterpret_as_s32(a)); } +inline bool v_check_all(const v_float64x2& a) +{ return v_check_all(v_reinterpret_as_s64(a)); } + +template +inline bool v_check_any(const _Tpvec& a) +{ return vec_any_lt(a.val, _Tpvec::zero().val); } +inline bool v_check_any(const v_uint8x16& a) +{ return v_check_any(v_reinterpret_as_s8(a)); } +inline bool v_check_any(const v_uint16x8& a) +{ return v_check_any(v_reinterpret_as_s16(a)); } +inline bool v_check_any(const v_uint32x4& a) +{ return v_check_any(v_reinterpret_as_s32(a)); } +inline bool v_check_any(const v_uint64x2& a) +{ return v_check_any(v_reinterpret_as_s64(a)); } +inline bool v_check_any(const v_float32x4& a) +{ return v_check_any(v_reinterpret_as_s32(a)); } +inline bool v_check_any(const v_float64x2& a) +{ return v_check_any(v_reinterpret_as_s64(a)); } + +////////// Other math ///////// + +/** Some frequent operations **/ +inline v_float32x4 v_sqrt(const v_float32x4& x) +{ return v_float32x4(vec_sqrt(x.val)); } +inline v_float64x2 v_sqrt(const v_float64x2& x) +{ return v_float64x2(vec_sqrt(x.val)); } + +inline v_float32x4 v_invsqrt(const v_float32x4& x) +{ return v_float32x4(vec_rsqrt(x.val)); } +inline v_float64x2 v_invsqrt(const v_float64x2& x) +{ return v_float64x2(vec_rsqrt(x.val)); } + +#define OPENCV_HAL_IMPL_VSX_MULADD(_Tpvec) \ +inline _Tpvec v_magnitude(const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vec_sqrt(vec_madd(a.val, a.val, vec_mul(b.val, b.val)))); } \ +inline _Tpvec v_sqr_magnitude(const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(vec_madd(a.val, a.val, vec_mul(b.val, b.val))); } \ +inline _Tpvec v_fma(const _Tpvec& a, const _Tpvec& b, const _Tpvec& c) \ +{ return _Tpvec(vec_madd(a.val, b.val, c.val)); } \ +inline _Tpvec v_muladd(const _Tpvec& a, const _Tpvec& b, const _Tpvec& c) \ +{ return _Tpvec(vec_madd(a.val, b.val, c.val)); } + +OPENCV_HAL_IMPL_VSX_MULADD(v_float32x4) +OPENCV_HAL_IMPL_VSX_MULADD(v_float64x2) + +inline v_int32x4 v_muladd(const v_int32x4& a, const v_int32x4& b, const v_int32x4& c) +{ return a * b + c; } + +// TODO: exp, log, sin, cos + +/** Absolute values **/ +inline v_uint8x16 v_abs(const v_int8x16& x) +{ return v_uint8x16(vec_uchar16_c(vec_abs(x.val))); } + +inline v_uint16x8 v_abs(const v_int16x8& x) +{ return v_uint16x8(vec_ushort8_c(vec_abs(x.val))); } + +inline v_uint32x4 v_abs(const v_int32x4& x) +{ return v_uint32x4(vec_uint4_c(vec_abs(x.val))); } + +inline v_float32x4 v_abs(const v_float32x4& x) +{ return v_float32x4(vec_abs(x.val)); } + +inline v_float64x2 v_abs(const v_float64x2& x) +{ return v_float64x2(vec_abs(x.val)); } + +/** Absolute difference **/ +// unsigned +OPENCV_HAL_IMPL_VSX_BIN_FUNC(v_absdiff, vec_absd) + +inline v_uint8x16 v_absdiff(const v_int8x16& a, const v_int8x16& b) +{ return v_reinterpret_as_u8(v_sub_wrap(v_max(a, b), v_min(a, b))); } +inline v_uint16x8 v_absdiff(const v_int16x8& a, const v_int16x8& b) +{ return v_reinterpret_as_u16(v_sub_wrap(v_max(a, b), v_min(a, b))); } +inline v_uint32x4 v_absdiff(const v_int32x4& a, const v_int32x4& b) +{ return v_reinterpret_as_u32(v_max(a, b) - v_min(a, b)); } + +inline v_float32x4 v_absdiff(const v_float32x4& a, const v_float32x4& b) +{ return v_abs(a - b); } +inline v_float64x2 v_absdiff(const v_float64x2& a, const v_float64x2& b) +{ return v_abs(a - b); } + +/** Absolute difference for signed integers **/ +inline v_int8x16 v_absdiffs(const v_int8x16& a, const v_int8x16& b) +{ return v_int8x16(vec_abss(vec_subs(a.val, b.val))); } +inline v_int16x8 v_absdiffs(const v_int16x8& a, const v_int16x8& b) +{ return v_int16x8(vec_abss(vec_subs(a.val, b.val))); } + +////////// Conversions ///////// + +/** Rounding **/ +inline v_int32x4 v_round(const v_float32x4& a) +{ return v_int32x4(vec_cts(vec_rint(a.val))); } + +inline v_int32x4 v_round(const v_float64x2& a) +{ return v_int32x4(vec_mergesqo(vec_ctso(vec_rint(a.val)), vec_int4_z)); } + +inline v_int32x4 v_round(const v_float64x2& a, const v_float64x2& b) +{ return v_int32x4(vec_mergesqo(vec_ctso(vec_rint(a.val)), vec_ctso(vec_rint(b.val)))); } + +inline v_int32x4 v_floor(const v_float32x4& a) +{ return v_int32x4(vec_cts(vec_floor(a.val))); } + +inline v_int32x4 v_floor(const v_float64x2& a) +{ return v_int32x4(vec_mergesqo(vec_ctso(vec_floor(a.val)), vec_int4_z)); } + +inline v_int32x4 v_ceil(const v_float32x4& a) +{ return v_int32x4(vec_cts(vec_ceil(a.val))); } + +inline v_int32x4 v_ceil(const v_float64x2& a) +{ return v_int32x4(vec_mergesqo(vec_ctso(vec_ceil(a.val)), vec_int4_z)); } + +inline v_int32x4 v_trunc(const v_float32x4& a) +{ return v_int32x4(vec_cts(a.val)); } + +inline v_int32x4 v_trunc(const v_float64x2& a) +{ return v_int32x4(vec_mergesqo(vec_ctso(a.val), vec_int4_z)); } + +/** To float **/ +inline v_float32x4 v_cvt_f32(const v_int32x4& a) +{ return v_float32x4(vec_ctf(a.val)); } + +inline v_float32x4 v_cvt_f32(const v_float64x2& a) +{ return v_float32x4(vec_mergesqo(vec_cvfo(a.val), vec_float4_z)); } + +inline v_float32x4 v_cvt_f32(const v_float64x2& a, const v_float64x2& b) +{ return v_float32x4(vec_mergesqo(vec_cvfo(a.val), vec_cvfo(b.val))); } + +inline v_float64x2 v_cvt_f64(const v_int32x4& a) +{ return v_float64x2(vec_ctdo(vec_mergeh(a.val, a.val))); } + +inline v_float64x2 v_cvt_f64_high(const v_int32x4& a) +{ return v_float64x2(vec_ctdo(vec_mergel(a.val, a.val))); } + +inline v_float64x2 v_cvt_f64(const v_float32x4& a) +{ return v_float64x2(vec_cvfo(vec_mergeh(a.val, a.val))); } + +inline v_float64x2 v_cvt_f64_high(const v_float32x4& a) +{ return v_float64x2(vec_cvfo(vec_mergel(a.val, a.val))); } + +inline v_float64x2 v_cvt_f64(const v_int64x2& a) +{ return v_float64x2(vec_ctd(a.val)); } + +////////////// Lookup table access //////////////////// + +inline v_int8x16 v_lut(const schar* tab, const int* idx) +{ + return v_int8x16(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]], tab[idx[4]], tab[idx[5]], tab[idx[6]], tab[idx[7]], + tab[idx[8]], tab[idx[9]], tab[idx[10]], tab[idx[11]], tab[idx[12]], tab[idx[13]], tab[idx[14]], tab[idx[15]]); +} +inline v_int8x16 v_lut_pairs(const schar* tab, const int* idx) +{ + return v_reinterpret_as_s8(v_int16x8(*(const short*)(tab+idx[0]), *(const short*)(tab+idx[1]), *(const short*)(tab+idx[2]), *(const short*)(tab+idx[3]), + *(const short*)(tab+idx[4]), *(const short*)(tab+idx[5]), *(const short*)(tab+idx[6]), *(const short*)(tab+idx[7]))); +} +inline v_int8x16 v_lut_quads(const schar* tab, const int* idx) +{ + return v_reinterpret_as_s8(v_int32x4(*(const int*)(tab+idx[0]), *(const int*)(tab+idx[1]), *(const int*)(tab+idx[2]), *(const int*)(tab+idx[3]))); +} +inline v_uint8x16 v_lut(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut((const schar*)tab, idx)); } +inline v_uint8x16 v_lut_pairs(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut_pairs((const schar*)tab, idx)); } +inline v_uint8x16 v_lut_quads(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut_quads((const schar*)tab, idx)); } + +inline v_int16x8 v_lut(const short* tab, const int* idx) +{ + return v_int16x8(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]], tab[idx[4]], tab[idx[5]], tab[idx[6]], tab[idx[7]]); +} +inline v_int16x8 v_lut_pairs(const short* tab, const int* idx) +{ + return v_reinterpret_as_s16(v_int32x4(*(const int*)(tab + idx[0]), *(const int*)(tab + idx[1]), *(const int*)(tab + idx[2]), *(const int*)(tab + idx[3]))); +} +inline v_int16x8 v_lut_quads(const short* tab, const int* idx) +{ + return v_reinterpret_as_s16(v_int64x2(*(const int64*)(tab + idx[0]), *(const int64*)(tab + idx[1]))); +} +inline v_uint16x8 v_lut(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut((const short*)tab, idx)); } +inline v_uint16x8 v_lut_pairs(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut_pairs((const short*)tab, idx)); } +inline v_uint16x8 v_lut_quads(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut_quads((const short*)tab, idx)); } + +inline v_int32x4 v_lut(const int* tab, const int* idx) +{ + return v_int32x4(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]]); +} +inline v_int32x4 v_lut_pairs(const int* tab, const int* idx) +{ + return v_reinterpret_as_s32(v_int64x2(*(const int64*)(tab + idx[0]), *(const int64*)(tab + idx[1]))); +} +inline v_int32x4 v_lut_quads(const int* tab, const int* idx) +{ + return v_int32x4(vsx_ld(0, tab + idx[0])); +} +inline v_uint32x4 v_lut(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut((const int*)tab, idx)); } +inline v_uint32x4 v_lut_pairs(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut_pairs((const int*)tab, idx)); } +inline v_uint32x4 v_lut_quads(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut_quads((const int*)tab, idx)); } + +inline v_int64x2 v_lut(const int64_t* tab, const int* idx) +{ + return v_int64x2(tab[idx[0]], tab[idx[1]]); +} +inline v_int64x2 v_lut_pairs(const int64_t* tab, const int* idx) +{ + return v_int64x2(vsx_ld2(0, tab + idx[0])); +} +inline v_uint64x2 v_lut(const uint64_t* tab, const int* idx) { return v_reinterpret_as_u64(v_lut((const int64_t *)tab, idx)); } +inline v_uint64x2 v_lut_pairs(const uint64_t* tab, const int* idx) { return v_reinterpret_as_u64(v_lut_pairs((const int64_t *)tab, idx)); } + +inline v_float32x4 v_lut(const float* tab, const int* idx) +{ + return v_float32x4(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]]); +} +inline v_float32x4 v_lut_pairs(const float* tab, const int* idx) { return v_reinterpret_as_f32(v_lut_pairs((const int*)tab, idx)); } +inline v_float32x4 v_lut_quads(const float* tab, const int* idx) { return v_load(tab + *idx); } + +inline v_float64x2 v_lut(const double* tab, const int* idx) +{ + return v_float64x2(tab[idx[0]], tab[idx[1]]); +} +inline v_float64x2 v_lut_pairs(const double* tab, const int* idx) { return v_load(tab + *idx); } + +inline v_int32x4 v_lut(const int* tab, const v_int32x4& idxvec) +{ + const int idx[4] = { + vec_extract(idxvec.val, 0), + vec_extract(idxvec.val, 1), + vec_extract(idxvec.val, 2), + vec_extract(idxvec.val, 3) + }; + return v_int32x4(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]]); +} + +inline v_uint32x4 v_lut(const unsigned* tab, const v_int32x4& idxvec) +{ + const int idx[4] = { + vec_extract(idxvec.val, 0), + vec_extract(idxvec.val, 1), + vec_extract(idxvec.val, 2), + vec_extract(idxvec.val, 3) + }; + return v_uint32x4(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]]); +} + +inline v_float32x4 v_lut(const float* tab, const v_int32x4& idxvec) +{ + const int idx[4] = { + vec_extract(idxvec.val, 0), + vec_extract(idxvec.val, 1), + vec_extract(idxvec.val, 2), + vec_extract(idxvec.val, 3) + }; + return v_float32x4(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]]); +} + +inline v_float64x2 v_lut(const double* tab, const v_int32x4& idxvec) +{ + const int idx[2] = { + vec_extract(idxvec.val, 0), + vec_extract(idxvec.val, 1) + }; + return v_float64x2(tab[idx[0]], tab[idx[1]]); +} + +inline void v_lut_deinterleave(const float* tab, const v_int32x4& idxvec, v_float32x4& x, v_float32x4& y) +{ + vec_float4 xy0 = vec_ld_l8(tab + vec_extract(idxvec.val, 0)); + vec_float4 xy1 = vec_ld_l8(tab + vec_extract(idxvec.val, 1)); + vec_float4 xy2 = vec_ld_l8(tab + vec_extract(idxvec.val, 2)); + vec_float4 xy3 = vec_ld_l8(tab + vec_extract(idxvec.val, 3)); + vec_float4 xy02 = vec_mergeh(xy0, xy2); // x0, x2, y0, y2 + vec_float4 xy13 = vec_mergeh(xy1, xy3); // x1, x3, y1, y3 + x.val = vec_mergeh(xy02, xy13); + y.val = vec_mergel(xy02, xy13); +} +inline void v_lut_deinterleave(const double* tab, const v_int32x4& idxvec, v_float64x2& x, v_float64x2& y) +{ + vec_double2 xy0 = vsx_ld(vec_extract(idxvec.val, 0), tab); + vec_double2 xy1 = vsx_ld(vec_extract(idxvec.val, 1), tab); + x.val = vec_mergeh(xy0, xy1); + y.val = vec_mergel(xy0, xy1); +} + +inline v_int8x16 v_interleave_pairs(const v_int8x16& vec) +{ + static const vec_uchar16 perm = {0, 2, 1, 3, 4, 6, 5, 7, 8, 10, 9, 11, 12, 14, 13, 15}; + return v_int8x16(vec_perm(vec.val, vec.val, perm)); +} +inline v_uint8x16 v_interleave_pairs(const v_uint8x16& vec) +{ return v_reinterpret_as_u8(v_interleave_pairs(v_reinterpret_as_s8(vec))); } + +inline v_int8x16 v_interleave_quads(const v_int8x16& vec) +{ + static const vec_uchar16 perm = {0, 4, 1, 5, 2, 6, 3, 7, 8, 12, 9, 13, 10, 14, 11, 15}; + return v_int8x16(vec_perm(vec.val, vec.val, perm)); +} +inline v_uint8x16 v_interleave_quads(const v_uint8x16& vec) +{ return v_reinterpret_as_u8(v_interleave_quads(v_reinterpret_as_s8(vec))); } + +inline v_int16x8 v_interleave_pairs(const v_int16x8& vec) +{ + static const vec_uchar16 perm = {0,1, 4,5, 2,3, 6,7, 8,9, 12,13, 10,11, 14,15}; + return v_int16x8(vec_perm(vec.val, vec.val, perm)); +} +inline v_uint16x8 v_interleave_pairs(const v_uint16x8& vec) +{ return v_reinterpret_as_u16(v_interleave_pairs(v_reinterpret_as_s16(vec))); } + +inline v_int16x8 v_interleave_quads(const v_int16x8& vec) +{ + static const vec_uchar16 perm = {0,1, 8,9, 2,3, 10,11, 4,5, 12,13, 6,7, 14,15}; + return v_int16x8(vec_perm(vec.val, vec.val, perm)); +} +inline v_uint16x8 v_interleave_quads(const v_uint16x8& vec) +{ return v_reinterpret_as_u16(v_interleave_quads(v_reinterpret_as_s16(vec))); } + +inline v_int32x4 v_interleave_pairs(const v_int32x4& vec) +{ + static const vec_uchar16 perm = {0,1,2,3, 8,9,10,11, 4,5,6,7, 12,13,14,15}; + return v_int32x4(vec_perm(vec.val, vec.val, perm)); +} +inline v_uint32x4 v_interleave_pairs(const v_uint32x4& vec) +{ return v_reinterpret_as_u32(v_interleave_pairs(v_reinterpret_as_s32(vec))); } +inline v_float32x4 v_interleave_pairs(const v_float32x4& vec) +{ return v_reinterpret_as_f32(v_interleave_pairs(v_reinterpret_as_s32(vec))); } + +inline v_int8x16 v_pack_triplets(const v_int8x16& vec) +{ + static const vec_uchar16 perm = {0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 15, 15, 15, 15}; + return v_int8x16(vec_perm(vec.val, vec.val, perm)); +} +inline v_uint8x16 v_pack_triplets(const v_uint8x16& vec) +{ return v_reinterpret_as_u8(v_pack_triplets(v_reinterpret_as_s8(vec))); } + +inline v_int16x8 v_pack_triplets(const v_int16x8& vec) +{ + static const vec_uchar16 perm = {0,1, 2,3, 4,5, 8,9, 10,11, 12,13, 14,15, 14,15}; + return v_int16x8(vec_perm(vec.val, vec.val, perm)); +} +inline v_uint16x8 v_pack_triplets(const v_uint16x8& vec) +{ return v_reinterpret_as_u16(v_pack_triplets(v_reinterpret_as_s16(vec))); } + +inline v_int32x4 v_pack_triplets(const v_int32x4& vec) +{ return vec; } +inline v_uint32x4 v_pack_triplets(const v_uint32x4& vec) +{ return vec; } +inline v_float32x4 v_pack_triplets(const v_float32x4& vec) +{ return vec; } + +/////// FP16 support //////// + +inline v_float32x4 v_load_expand(const float16_t* ptr) +{ + vec_ushort8 vf16 = vec_ld_l8((const ushort*)ptr); +#if CV_VSX3 && defined(vec_extract_fp_from_shorth) + return v_float32x4(vec_extract_fp_from_shorth(vf16)); +#elif CV_VSX3 && !defined(CV_COMPILER_VSX_BROKEN_ASM) + vec_float4 vf32; + __asm__ __volatile__ ("xvcvhpsp %x0,%x1" : "=wa" (vf32) : "wa" (vec_mergeh(vf16, vf16))); + return v_float32x4(vf32); +#else + const vec_int4 z = vec_int4_z, delta = vec_int4_sp(0x38000000); + const vec_int4 signmask = vec_int4_sp(0x80000000); + const vec_int4 maxexp = vec_int4_sp(0x7c000000); + const vec_float4 deltaf = vec_float4_c(vec_int4_sp(0x38800000)); + + vec_int4 bits = vec_int4_c(vec_mergeh(vec_short8_c(z), vec_short8_c(vf16))); + vec_int4 e = vec_and(bits, maxexp), sign = vec_and(bits, signmask); + vec_int4 t = vec_add(vec_sr(vec_xor(bits, sign), vec_uint4_sp(3)), delta); // ((h & 0x7fff) << 13) + delta + vec_int4 zt = vec_int4_c(vec_sub(vec_float4_c(vec_add(t, vec_int4_sp(1 << 23))), deltaf)); + + t = vec_add(t, vec_and(delta, vec_cmpeq(maxexp, e))); + vec_bint4 zmask = vec_cmpeq(e, z); + vec_int4 ft = vec_sel(t, zt, zmask); + return v_float32x4(vec_float4_c(vec_or(ft, sign))); +#endif +} + +inline void v_pack_store(float16_t* ptr, const v_float32x4& v) +{ +// fixme: Is there any builtin op or intrinsic that cover "xvcvsphp"? +#if CV_VSX3 && !defined(CV_COMPILER_VSX_BROKEN_ASM) + vec_ushort8 vf16; + __asm__ __volatile__ ("xvcvsphp %x0,%x1" : "=wa" (vf16) : "wa" (v.val)); + vec_st_l8(vec_mergesqe(vf16, vf16), ptr); +#else + const vec_int4 signmask = vec_int4_sp(0x80000000); + const vec_int4 rval = vec_int4_sp(0x3f000000); + + vec_int4 t = vec_int4_c(v.val); + vec_int4 sign = vec_sra(vec_and(t, signmask), vec_uint4_sp(16)); + t = vec_and(vec_nor(signmask, signmask), t); + + vec_bint4 finitemask = vec_cmpgt(vec_int4_sp(0x47800000), t); + vec_bint4 isnan = vec_cmpgt(t, vec_int4_sp(0x7f800000)); + vec_int4 naninf = vec_sel(vec_int4_sp(0x7c00), vec_int4_sp(0x7e00), isnan); + vec_bint4 tinymask = vec_cmpgt(vec_int4_sp(0x38800000), t); + vec_int4 tt = vec_int4_c(vec_add(vec_float4_c(t), vec_float4_c(rval))); + tt = vec_sub(tt, rval); + vec_int4 odd = vec_and(vec_sr(t, vec_uint4_sp(13)), vec_int4_sp(1)); + vec_int4 nt = vec_add(t, vec_int4_sp(0xc8000fff)); + nt = vec_sr(vec_add(nt, odd), vec_uint4_sp(13)); + t = vec_sel(nt, tt, tinymask); + t = vec_sel(naninf, t, finitemask); + t = vec_or(t, sign); + vec_st_l8(vec_packs(t, t), ptr); +#endif +} + +inline void v_cleanup() {} + + +/** Reinterpret **/ +/** its up there with load and store operations **/ + +////////// Matrix operations ///////// + +//////// Dot Product //////// +// 16 >> 32 +inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b) +{ return v_int32x4(vec_msum(a.val, b.val, vec_int4_z)); } +inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b, const v_int32x4& c) +{ return v_int32x4(vec_msum(a.val, b.val, c.val)); } + +// 32 >> 64 +inline v_int64x2 v_dotprod(const v_int32x4& a, const v_int32x4& b) +{ + vec_dword2 even = vec_mule(a.val, b.val); + vec_dword2 odd = vec_mulo(a.val, b.val); + return v_int64x2(vec_add(even, odd)); +} +inline v_int64x2 v_dotprod(const v_int32x4& a, const v_int32x4& b, const v_int64x2& c) +{ return v_dotprod(a, b) + c; } + +// 8 >> 32 +inline v_uint32x4 v_dotprod_expand(const v_uint8x16& a, const v_uint8x16& b, const v_uint32x4& c) +{ return v_uint32x4(vec_msum(a.val, b.val, c.val)); } +inline v_uint32x4 v_dotprod_expand(const v_uint8x16& a, const v_uint8x16& b) +{ return v_uint32x4(vec_msum(a.val, b.val, vec_uint4_z)); } + +inline v_int32x4 v_dotprod_expand(const v_int8x16& a, const v_int8x16& b) +{ + const vec_ushort8 eight = vec_ushort8_sp(8); + vec_short8 a0 = vec_sra((vec_short8)vec_sld(a.val, a.val, 1), eight); // even + vec_short8 a1 = vec_sra((vec_short8)a.val, eight); // odd + vec_short8 b0 = vec_sra((vec_short8)vec_sld(b.val, b.val, 1), eight); + vec_short8 b1 = vec_sra((vec_short8)b.val, eight); + return v_int32x4(vec_msum(a0, b0, vec_msum(a1, b1, vec_int4_z))); +} + +inline v_int32x4 v_dotprod_expand(const v_int8x16& a, const v_int8x16& b, const v_int32x4& c) +{ + const vec_ushort8 eight = vec_ushort8_sp(8); + vec_short8 a0 = vec_sra((vec_short8)vec_sld(a.val, a.val, 1), eight); // even + vec_short8 a1 = vec_sra((vec_short8)a.val, eight); // odd + vec_short8 b0 = vec_sra((vec_short8)vec_sld(b.val, b.val, 1), eight); + vec_short8 b1 = vec_sra((vec_short8)b.val, eight); + return v_int32x4(vec_msum(a0, b0, vec_msum(a1, b1, c.val))); +} + +// 16 >> 64 +inline v_uint64x2 v_dotprod_expand(const v_uint16x8& a, const v_uint16x8& b) +{ + const vec_uint4 zero = vec_uint4_z; + vec_uint4 even = vec_mule(a.val, b.val); + vec_uint4 odd = vec_mulo(a.val, b.val); + vec_udword2 e0 = (vec_udword2)vec_mergee(even, zero); + vec_udword2 e1 = (vec_udword2)vec_mergeo(even, zero); + vec_udword2 o0 = (vec_udword2)vec_mergee(odd, zero); + vec_udword2 o1 = (vec_udword2)vec_mergeo(odd, zero); + vec_udword2 s0 = vec_add(e0, o0); + vec_udword2 s1 = vec_add(e1, o1); + return v_uint64x2(vec_add(s0, s1)); +} +inline v_uint64x2 v_dotprod_expand(const v_uint16x8& a, const v_uint16x8& b, const v_uint64x2& c) +{ return v_dotprod_expand(a, b) + c; } + +inline v_int64x2 v_dotprod_expand(const v_int16x8& a, const v_int16x8& b) +{ + v_int32x4 prod = v_dotprod(a, b); + v_int64x2 c, d; + v_expand(prod, c, d); + return v_int64x2(vec_add(vec_mergeh(c.val, d.val), vec_mergel(c.val, d.val))); +} +inline v_int64x2 v_dotprod_expand(const v_int16x8& a, const v_int16x8& b, const v_int64x2& c) +{ return v_dotprod_expand(a, b) + c; } + +// 32 >> 64f +inline v_float64x2 v_dotprod_expand(const v_int32x4& a, const v_int32x4& b) +{ return v_cvt_f64(v_dotprod(a, b)); } +inline v_float64x2 v_dotprod_expand(const v_int32x4& a, const v_int32x4& b, const v_float64x2& c) +{ return v_dotprod_expand(a, b) + c; } + +//////// Fast Dot Product //////// + +// 16 >> 32 +inline v_int32x4 v_dotprod_fast(const v_int16x8& a, const v_int16x8& b) +{ return v_dotprod(a, b); } +inline v_int32x4 v_dotprod_fast(const v_int16x8& a, const v_int16x8& b, const v_int32x4& c) +{ return v_int32x4(vec_msum(a.val, b.val, vec_int4_z)) + c; } +// 32 >> 64 +inline v_int64x2 v_dotprod_fast(const v_int32x4& a, const v_int32x4& b) +{ return v_dotprod(a, b); } +inline v_int64x2 v_dotprod_fast(const v_int32x4& a, const v_int32x4& b, const v_int64x2& c) +{ return v_dotprod(a, b, c); } + +// 8 >> 32 +inline v_uint32x4 v_dotprod_expand_fast(const v_uint8x16& a, const v_uint8x16& b) +{ return v_dotprod_expand(a, b); } +inline v_uint32x4 v_dotprod_expand_fast(const v_uint8x16& a, const v_uint8x16& b, const v_uint32x4& c) +{ return v_uint32x4(vec_msum(a.val, b.val, vec_uint4_z)) + c; } + +inline v_int32x4 v_dotprod_expand_fast(const v_int8x16& a, const v_int8x16& b) +{ + vec_short8 a0 = vec_unpackh(a.val); + vec_short8 a1 = vec_unpackl(a.val); + vec_short8 b0 = vec_unpackh(b.val); + vec_short8 b1 = vec_unpackl(b.val); + return v_int32x4(vec_msum(a0, b0, vec_msum(a1, b1, vec_int4_z))); +} +inline v_int32x4 v_dotprod_expand_fast(const v_int8x16& a, const v_int8x16& b, const v_int32x4& c) +{ return v_dotprod_expand_fast(a, b) + c; } + +// 16 >> 64 +inline v_uint64x2 v_dotprod_expand_fast(const v_uint16x8& a, const v_uint16x8& b) +{ return v_dotprod_expand(a, b); } +inline v_uint64x2 v_dotprod_expand_fast(const v_uint16x8& a, const v_uint16x8& b, const v_uint64x2& c) +{ return v_dotprod_expand(a, b, c); } + +inline v_int64x2 v_dotprod_expand_fast(const v_int16x8& a, const v_int16x8& b) +{ + v_int32x4 prod = v_dotprod(a, b); + v_int64x2 c, d; + v_expand(prod, c, d); + return c + d; +} +inline v_int64x2 v_dotprod_expand_fast(const v_int16x8& a, const v_int16x8& b, const v_int64x2& c) +{ return v_dotprod_expand_fast(a, b) + c; } + +// 32 >> 64f +inline v_float64x2 v_dotprod_expand_fast(const v_int32x4& a, const v_int32x4& b) +{ return v_dotprod_expand(a, b); } +inline v_float64x2 v_dotprod_expand_fast(const v_int32x4& a, const v_int32x4& b, const v_float64x2& c) +{ return v_dotprod_expand(a, b, c); } + +inline v_float32x4 v_matmul(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& m3) +{ + const vec_float4 v0 = vec_splat(v.val, 0); + const vec_float4 v1 = vec_splat(v.val, 1); + const vec_float4 v2 = vec_splat(v.val, 2); + VSX_UNUSED(const vec_float4) v3 = vec_splat(v.val, 3); + return v_float32x4(vec_madd(v0, m0.val, vec_madd(v1, m1.val, vec_madd(v2, m2.val, vec_mul(v3, m3.val))))); +} + +inline v_float32x4 v_matmuladd(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& a) +{ + const vec_float4 v0 = vec_splat(v.val, 0); + const vec_float4 v1 = vec_splat(v.val, 1); + const vec_float4 v2 = vec_splat(v.val, 2); + return v_float32x4(vec_madd(v0, m0.val, vec_madd(v1, m1.val, vec_madd(v2, m2.val, a.val)))); +} + +#define OPENCV_HAL_IMPL_VSX_TRANSPOSE4x4(_Tpvec, _Tpvec2) \ +inline void v_transpose4x4(const _Tpvec& a0, const _Tpvec& a1, \ + const _Tpvec& a2, const _Tpvec& a3, \ + _Tpvec& b0, _Tpvec& b1, _Tpvec& b2, _Tpvec& b3) \ +{ \ + _Tpvec2 a02 = vec_mergeh(a0.val, a2.val); \ + _Tpvec2 a13 = vec_mergeh(a1.val, a3.val); \ + b0.val = vec_mergeh(a02, a13); \ + b1.val = vec_mergel(a02, a13); \ + a02 = vec_mergel(a0.val, a2.val); \ + a13 = vec_mergel(a1.val, a3.val); \ + b2.val = vec_mergeh(a02, a13); \ + b3.val = vec_mergel(a02, a13); \ +} +OPENCV_HAL_IMPL_VSX_TRANSPOSE4x4(v_uint32x4, vec_uint4) +OPENCV_HAL_IMPL_VSX_TRANSPOSE4x4(v_int32x4, vec_int4) +OPENCV_HAL_IMPL_VSX_TRANSPOSE4x4(v_float32x4, vec_float4) + +template +inline Tvec v_broadcast_element(const Tvec& v) +{ return Tvec(vec_splat(v.val, i)); } + + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END + +//! @endcond + +} + +#endif // OPENCV_HAL_VSX_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_wasm.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_wasm.hpp new file mode 100644 index 0000000..b4178af --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/intrin_wasm.hpp @@ -0,0 +1,2782 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_HAL_INTRIN_WASM_HPP +#define OPENCV_HAL_INTRIN_WASM_HPP + +#include +#include +#include +#include "opencv2/core/saturate.hpp" + +#define CV_SIMD128 1 +#define CV_SIMD128_64F 0 // Now all implementation of f64 use fallback, so disable it. +#define CV_SIMD128_FP16 0 + +namespace cv +{ + +//! @cond IGNORED + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN + +#if (__EMSCRIPTEN_major__ * 1000000 + __EMSCRIPTEN_minor__ * 1000 + __EMSCRIPTEN_tiny__) < (1038046) +// handle renames: https://github.com/emscripten-core/emscripten/pull/9440 (https://github.com/emscripten-core/emscripten/commit/755d5b46cb84d0aa120c10981b11d05646c29673) +#define wasm_i32x4_trunc_saturate_f32x4 wasm_trunc_saturate_i32x4_f32x4 +#define wasm_u32x4_trunc_saturate_f32x4 wasm_trunc_saturate_u32x4_f32x4 +#define wasm_i64x2_trunc_saturate_f64x2 wasm_trunc_saturate_i64x2_f64x2 +#define wasm_u64x2_trunc_saturate_f64x2 wasm_trunc_saturate_u64x2_f64x2 +#define wasm_f32x4_convert_i32x4 wasm_convert_f32x4_i32x4 +#define wasm_f32x4_convert_u32x4 wasm_convert_f32x4_u32x4 +#define wasm_f64x2_convert_i64x2 wasm_convert_f64x2_i64x2 +#define wasm_f64x2_convert_u64x2 wasm_convert_f64x2_u64x2 +#endif // COMPATIBILITY: <1.38.46 + +///////// Types /////////// + +struct v_uint8x16 +{ + typedef uchar lane_type; + typedef v128_t vector_type; + enum { nlanes = 16 }; + + v_uint8x16() {} + explicit v_uint8x16(v128_t v) : val(v) {} + v_uint8x16(uchar v0, uchar v1, uchar v2, uchar v3, uchar v4, uchar v5, uchar v6, uchar v7, + uchar v8, uchar v9, uchar v10, uchar v11, uchar v12, uchar v13, uchar v14, uchar v15) + { + uchar v[] = {v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15}; + val = wasm_v128_load(v); + } + + uchar get0() const + { + return (uchar)wasm_i8x16_extract_lane(val, 0); + } + + v128_t val; +}; + +struct v_int8x16 +{ + typedef schar lane_type; + typedef v128_t vector_type; + enum { nlanes = 16 }; + + v_int8x16() {} + explicit v_int8x16(v128_t v) : val(v) {} + v_int8x16(schar v0, schar v1, schar v2, schar v3, schar v4, schar v5, schar v6, schar v7, + schar v8, schar v9, schar v10, schar v11, schar v12, schar v13, schar v14, schar v15) + { + schar v[] = {v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15}; + val = wasm_v128_load(v); + } + + schar get0() const + { + return wasm_i8x16_extract_lane(val, 0); + } + + v128_t val; +}; + +struct v_uint16x8 +{ + typedef ushort lane_type; + typedef v128_t vector_type; + enum { nlanes = 8 }; + + v_uint16x8() {} + explicit v_uint16x8(v128_t v) : val(v) {} + v_uint16x8(ushort v0, ushort v1, ushort v2, ushort v3, ushort v4, ushort v5, ushort v6, ushort v7) + { + ushort v[] = {v0, v1, v2, v3, v4, v5, v6, v7}; + val = wasm_v128_load(v); + } + + ushort get0() const + { + return (ushort)wasm_i16x8_extract_lane(val, 0); // wasm_u16x8_extract_lane() unimplemented yet + } + + v128_t val; +}; + +struct v_int16x8 +{ + typedef short lane_type; + typedef v128_t vector_type; + enum { nlanes = 8 }; + + v_int16x8() {} + explicit v_int16x8(v128_t v) : val(v) {} + v_int16x8(short v0, short v1, short v2, short v3, short v4, short v5, short v6, short v7) + { + short v[] = {v0, v1, v2, v3, v4, v5, v6, v7}; + val = wasm_v128_load(v); + } + + short get0() const + { + return wasm_i16x8_extract_lane(val, 0); + } + + v128_t val; +}; + +struct v_uint32x4 +{ + typedef unsigned lane_type; + typedef v128_t vector_type; + enum { nlanes = 4 }; + + v_uint32x4() {} + explicit v_uint32x4(v128_t v) : val(v) {} + v_uint32x4(unsigned v0, unsigned v1, unsigned v2, unsigned v3) + { + unsigned v[] = {v0, v1, v2, v3}; + val = wasm_v128_load(v); + } + + unsigned get0() const + { + return (unsigned)wasm_i32x4_extract_lane(val, 0); + } + + v128_t val; +}; + +struct v_int32x4 +{ + typedef int lane_type; + typedef v128_t vector_type; + enum { nlanes = 4 }; + + v_int32x4() {} + explicit v_int32x4(v128_t v) : val(v) {} + v_int32x4(int v0, int v1, int v2, int v3) + { + int v[] = {v0, v1, v2, v3}; + val = wasm_v128_load(v); + } + + int get0() const + { + return wasm_i32x4_extract_lane(val, 0); + } + + v128_t val; +}; + +struct v_float32x4 +{ + typedef float lane_type; + typedef v128_t vector_type; + enum { nlanes = 4 }; + + v_float32x4() {} + explicit v_float32x4(v128_t v) : val(v) {} + v_float32x4(float v0, float v1, float v2, float v3) + { + float v[] = {v0, v1, v2, v3}; + val = wasm_v128_load(v); + } + + float get0() const + { + return wasm_f32x4_extract_lane(val, 0); + } + + v128_t val; +}; + +struct v_uint64x2 +{ + typedef uint64 lane_type; + typedef v128_t vector_type; + enum { nlanes = 2 }; + + v_uint64x2() {} + explicit v_uint64x2(v128_t v) : val(v) {} + v_uint64x2(uint64 v0, uint64 v1) + { + uint64 v[] = {v0, v1}; + val = wasm_v128_load(v); + } + + uint64 get0() const + { + return (uint64)wasm_i64x2_extract_lane(val, 0); + } + + v128_t val; +}; + +struct v_int64x2 +{ + typedef int64 lane_type; + typedef v128_t vector_type; + enum { nlanes = 2 }; + + v_int64x2() {} + explicit v_int64x2(v128_t v) : val(v) {} + v_int64x2(int64 v0, int64 v1) + { + int64 v[] = {v0, v1}; + val = wasm_v128_load(v); + } + + int64 get0() const + { + return wasm_i64x2_extract_lane(val, 0); + } + + v128_t val; +}; + +struct v_float64x2 +{ + typedef double lane_type; + typedef v128_t vector_type; + enum { nlanes = 2 }; + + v_float64x2() {} + explicit v_float64x2(v128_t v) : val(v) {} + v_float64x2(double v0, double v1) + { + double v[] = {v0, v1}; + val = wasm_v128_load(v); + } + + double get0() const + { + return wasm_f64x2_extract_lane(val, 0); + } + + v128_t val; +}; + +namespace +{ +#define OPENCV_HAL_IMPL_REINTERPRET_INT(ft, tt) \ +inline tt reinterpret_int(ft x) { union { ft l; tt i; } v; v.l = x; return v.i; } +OPENCV_HAL_IMPL_REINTERPRET_INT(uchar, schar) +OPENCV_HAL_IMPL_REINTERPRET_INT(schar, schar) +OPENCV_HAL_IMPL_REINTERPRET_INT(ushort, short) +OPENCV_HAL_IMPL_REINTERPRET_INT(short, short) +OPENCV_HAL_IMPL_REINTERPRET_INT(unsigned, int) +OPENCV_HAL_IMPL_REINTERPRET_INT(int, int) +OPENCV_HAL_IMPL_REINTERPRET_INT(float, int) +OPENCV_HAL_IMPL_REINTERPRET_INT(uint64, int64) +OPENCV_HAL_IMPL_REINTERPRET_INT(int64, int64) +OPENCV_HAL_IMPL_REINTERPRET_INT(double, int64) + +static const unsigned char popCountTable[] = +{ + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, +}; +} // namespace + +static v128_t wasm_unpacklo_i8x16(v128_t a, v128_t b) { + return wasm_v8x16_shuffle(a, b, 0,16,1,17,2,18,3,19,4,20,5,21,6,22,7,23); +} + +static v128_t wasm_unpacklo_i16x8(v128_t a, v128_t b) { + return wasm_v8x16_shuffle(a, b, 0,1,16,17,2,3,18,19,4,5,20,21,6,7,22,23); +} + +static v128_t wasm_unpacklo_i32x4(v128_t a, v128_t b) { + return wasm_v8x16_shuffle(a, b, 0,1,2,3,16,17,18,19,4,5,6,7,20,21,22,23); +} + +static v128_t wasm_unpacklo_i64x2(v128_t a, v128_t b) { + return wasm_v8x16_shuffle(a, b, 0,1,2,3,4,5,6,7,16,17,18,19,20,21,22,23); +} + +static v128_t wasm_unpackhi_i8x16(v128_t a, v128_t b) { + return wasm_v8x16_shuffle(a, b, 8,24,9,25,10,26,11,27,12,28,13,29,14,30,15,31); +} + +static v128_t wasm_unpackhi_i16x8(v128_t a, v128_t b) { + return wasm_v8x16_shuffle(a, b, 8,9,24,25,10,11,26,27,12,13,28,29,14,15,30,31); +} + +static v128_t wasm_unpackhi_i32x4(v128_t a, v128_t b) { + return wasm_v8x16_shuffle(a, b, 8,9,10,11,24,25,26,27,12,13,14,15,28,29,30,31); +} + +static v128_t wasm_unpackhi_i64x2(v128_t a, v128_t b) { + return wasm_v8x16_shuffle(a, b, 8,9,10,11,12,13,14,15,24,25,26,27,28,29,30,31); +} + +/** Convert **/ +// 8 >> 16 +inline v128_t v128_cvtu8x16_i16x8(const v128_t& a) +{ + const v128_t z = wasm_i8x16_splat(0); + return wasm_unpacklo_i8x16(a, z); +} +inline v128_t v128_cvti8x16_i16x8(const v128_t& a) +{ return wasm_i16x8_shr(wasm_unpacklo_i8x16(a, a), 8); } +// 8 >> 32 +inline v128_t v128_cvtu8x16_i32x4(const v128_t& a) +{ + const v128_t z = wasm_i8x16_splat(0); + return wasm_unpacklo_i16x8(wasm_unpacklo_i8x16(a, z), z); +} +inline v128_t v128_cvti8x16_i32x4(const v128_t& a) +{ + v128_t r = wasm_unpacklo_i8x16(a, a); + r = wasm_unpacklo_i8x16(r, r); + return wasm_i32x4_shr(r, 24); +} +// 16 >> 32 +inline v128_t v128_cvtu16x8_i32x4(const v128_t& a) +{ + const v128_t z = wasm_i8x16_splat(0); + return wasm_unpacklo_i16x8(a, z); +} +inline v128_t v128_cvti16x8_i32x4(const v128_t& a) +{ return wasm_i32x4_shr(wasm_unpacklo_i16x8(a, a), 16); } +// 32 >> 64 +inline v128_t v128_cvtu32x4_i64x2(const v128_t& a) +{ + const v128_t z = wasm_i8x16_splat(0); + return wasm_unpacklo_i32x4(a, z); +} +inline v128_t v128_cvti32x4_i64x2(const v128_t& a) +{ return wasm_unpacklo_i32x4(a, wasm_i32x4_shr(a, 31)); } + +// 16 << 8 +inline v128_t v128_cvtu8x16_i16x8_high(const v128_t& a) +{ + const v128_t z = wasm_i8x16_splat(0); + return wasm_unpackhi_i8x16(a, z); +} +inline v128_t v128_cvti8x16_i16x8_high(const v128_t& a) +{ return wasm_i16x8_shr(wasm_unpackhi_i8x16(a, a), 8); } +// 32 << 16 +inline v128_t v128_cvtu16x8_i32x4_high(const v128_t& a) +{ + const v128_t z = wasm_i8x16_splat(0); + return wasm_unpackhi_i16x8(a, z); +} +inline v128_t v128_cvti16x8_i32x4_high(const v128_t& a) +{ return wasm_i32x4_shr(wasm_unpackhi_i16x8(a, a), 16); } +// 64 << 32 +inline v128_t v128_cvtu32x4_i64x2_high(const v128_t& a) +{ + const v128_t z = wasm_i8x16_splat(0); + return wasm_unpackhi_i32x4(a, z); +} +inline v128_t v128_cvti32x4_i64x2_high(const v128_t& a) +{ return wasm_unpackhi_i32x4(a, wasm_i32x4_shr(a, 31)); } + +#define OPENCV_HAL_IMPL_WASM_INITVEC(_Tpvec, _Tp, suffix, zsuffix, _Tps) \ +inline _Tpvec v_setzero_##suffix() { return _Tpvec(wasm_##zsuffix##_splat((_Tps)0)); } \ +inline _Tpvec v_setall_##suffix(_Tp v) { return _Tpvec(wasm_##zsuffix##_splat((_Tps)v)); } \ +template inline _Tpvec v_reinterpret_as_##suffix(const _Tpvec0& a) \ +{ return _Tpvec(a.val); } + +OPENCV_HAL_IMPL_WASM_INITVEC(v_uint8x16, uchar, u8, i8x16, schar) +OPENCV_HAL_IMPL_WASM_INITVEC(v_int8x16, schar, s8, i8x16, schar) +OPENCV_HAL_IMPL_WASM_INITVEC(v_uint16x8, ushort, u16, i16x8, short) +OPENCV_HAL_IMPL_WASM_INITVEC(v_int16x8, short, s16, i16x8, short) +OPENCV_HAL_IMPL_WASM_INITVEC(v_uint32x4, unsigned, u32, i32x4, int) +OPENCV_HAL_IMPL_WASM_INITVEC(v_int32x4, int, s32, i32x4, int) +OPENCV_HAL_IMPL_WASM_INITVEC(v_float32x4, float, f32, f32x4, float) +OPENCV_HAL_IMPL_WASM_INITVEC(v_uint64x2, uint64, u64, i64x2, int64) +OPENCV_HAL_IMPL_WASM_INITVEC(v_int64x2, int64, s64, i64x2, int64) +OPENCV_HAL_IMPL_WASM_INITVEC(v_float64x2, double, f64, f64x2, double) + +//////////////// PACK /////////////// +inline v_uint8x16 v_pack(const v_uint16x8& a, const v_uint16x8& b) +{ + v128_t maxval = wasm_i16x8_splat(255); + v128_t a1 = wasm_v128_bitselect(maxval, a.val, wasm_u16x8_gt(a.val, maxval)); + v128_t b1 = wasm_v128_bitselect(maxval, b.val, wasm_u16x8_gt(b.val, maxval)); + return v_uint8x16(wasm_v8x16_shuffle(a1, b1, 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30)); +} +inline v_int8x16 v_pack(const v_int16x8& a, const v_int16x8& b) +{ + v128_t maxval = wasm_i16x8_splat(127); + v128_t minval = wasm_i16x8_splat(-128); + v128_t a1 = wasm_v128_bitselect(maxval, a.val, wasm_i16x8_gt(a.val, maxval)); + v128_t b1 = wasm_v128_bitselect(maxval, b.val, wasm_i16x8_gt(b.val, maxval)); + v128_t a2 = wasm_v128_bitselect(minval, a1, wasm_i16x8_lt(a1, minval)); + v128_t b2 = wasm_v128_bitselect(minval, b1, wasm_i16x8_lt(b1, minval)); + return v_int8x16(wasm_v8x16_shuffle(a2, b2, 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30)); +} +inline v_uint16x8 v_pack(const v_uint32x4& a, const v_uint32x4& b) +{ + v128_t maxval = wasm_i32x4_splat(65535); + v128_t a1 = wasm_v128_bitselect(maxval, a.val, wasm_u32x4_gt(a.val, maxval)); + v128_t b1 = wasm_v128_bitselect(maxval, b.val, wasm_u32x4_gt(b.val, maxval)); + return v_uint16x8(wasm_v8x16_shuffle(a1, b1, 0,1,4,5,8,9,12,13,16,17,20,21,24,25,28,29)); +} +inline v_int16x8 v_pack(const v_int32x4& a, const v_int32x4& b) +{ + v128_t maxval = wasm_i32x4_splat(32767); + v128_t minval = wasm_i32x4_splat(-32768); + v128_t a1 = wasm_v128_bitselect(maxval, a.val, wasm_i32x4_gt(a.val, maxval)); + v128_t b1 = wasm_v128_bitselect(maxval, b.val, wasm_i32x4_gt(b.val, maxval)); + v128_t a2 = wasm_v128_bitselect(minval, a1, wasm_i32x4_lt(a1, minval)); + v128_t b2 = wasm_v128_bitselect(minval, b1, wasm_i32x4_lt(b1, minval)); + return v_int16x8(wasm_v8x16_shuffle(a2, b2, 0,1,4,5,8,9,12,13,16,17,20,21,24,25,28,29)); +} +inline v_uint32x4 v_pack(const v_uint64x2& a, const v_uint64x2& b) +{ + return v_uint32x4(wasm_v8x16_shuffle(a.val, b.val, 0,1,2,3,8,9,10,11,16,17,18,19,24,25,26,27)); +} +inline v_int32x4 v_pack(const v_int64x2& a, const v_int64x2& b) +{ + return v_int32x4(wasm_v8x16_shuffle(a.val, b.val, 0,1,2,3,8,9,10,11,16,17,18,19,24,25,26,27)); +} +inline v_uint8x16 v_pack_u(const v_int16x8& a, const v_int16x8& b) +{ + v128_t maxval = wasm_i16x8_splat(255); + v128_t minval = wasm_i16x8_splat(0); + v128_t a1 = wasm_v128_bitselect(maxval, a.val, wasm_i16x8_gt(a.val, maxval)); + v128_t b1 = wasm_v128_bitselect(maxval, b.val, wasm_i16x8_gt(b.val, maxval)); + v128_t a2 = wasm_v128_bitselect(minval, a1, wasm_i16x8_lt(a1, minval)); + v128_t b2 = wasm_v128_bitselect(minval, b1, wasm_i16x8_lt(b1, minval)); + return v_uint8x16(wasm_v8x16_shuffle(a2, b2, 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30)); +} +inline v_uint16x8 v_pack_u(const v_int32x4& a, const v_int32x4& b) +{ + v128_t maxval = wasm_i32x4_splat(65535); + v128_t minval = wasm_i32x4_splat(0); + v128_t a1 = wasm_v128_bitselect(maxval, a.val, wasm_i32x4_gt(a.val, maxval)); + v128_t b1 = wasm_v128_bitselect(maxval, b.val, wasm_i32x4_gt(b.val, maxval)); + v128_t a2 = wasm_v128_bitselect(minval, a1, wasm_i32x4_lt(a1, minval)); + v128_t b2 = wasm_v128_bitselect(minval, b1, wasm_i32x4_lt(b1, minval)); + return v_uint16x8(wasm_v8x16_shuffle(a2, b2, 0,1,4,5,8,9,12,13,16,17,20,21,24,25,28,29)); +} + +template +inline v_uint8x16 v_rshr_pack(const v_uint16x8& a, const v_uint16x8& b) +{ + v128_t delta = wasm_i16x8_splat(((short)1 << (n-1))); + v128_t a1 = wasm_u16x8_shr(wasm_i16x8_add(a.val, delta), n); + v128_t b1 = wasm_u16x8_shr(wasm_i16x8_add(b.val, delta), n); + v128_t maxval = wasm_i16x8_splat(255); + v128_t a2 = wasm_v128_bitselect(maxval, a1, wasm_u16x8_gt(a1, maxval)); + v128_t b2 = wasm_v128_bitselect(maxval, b1, wasm_u16x8_gt(b1, maxval)); + return v_uint8x16(wasm_v8x16_shuffle(a2, b2, 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30)); +} +template +inline v_int8x16 v_rshr_pack(const v_int16x8& a, const v_int16x8& b) +{ + v128_t delta = wasm_i16x8_splat(((short)1 << (n-1))); + v128_t a1 = wasm_i16x8_shr(wasm_i16x8_add(a.val, delta), n); + v128_t b1 = wasm_i16x8_shr(wasm_i16x8_add(b.val, delta), n); + v128_t maxval = wasm_i16x8_splat(127); + v128_t minval = wasm_i16x8_splat(-128); + v128_t a2 = wasm_v128_bitselect(maxval, a1, wasm_i16x8_gt(a1, maxval)); + v128_t b2 = wasm_v128_bitselect(maxval, b1, wasm_i16x8_gt(b1, maxval)); + v128_t a3 = wasm_v128_bitselect(minval, a2, wasm_i16x8_lt(a1, minval)); + v128_t b3 = wasm_v128_bitselect(minval, b2, wasm_i16x8_lt(b1, minval)); + return v_int8x16(wasm_v8x16_shuffle(a3, b3, 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30)); +} +template +inline v_uint16x8 v_rshr_pack(const v_uint32x4& a, const v_uint32x4& b) +{ + v128_t delta = wasm_i32x4_splat(((int)1 << (n-1))); + v128_t a1 = wasm_u32x4_shr(wasm_i32x4_add(a.val, delta), n); + v128_t b1 = wasm_u32x4_shr(wasm_i32x4_add(b.val, delta), n); + v128_t maxval = wasm_i32x4_splat(65535); + v128_t a2 = wasm_v128_bitselect(maxval, a1, wasm_u32x4_gt(a1, maxval)); + v128_t b2 = wasm_v128_bitselect(maxval, b1, wasm_u32x4_gt(b1, maxval)); + return v_uint16x8(wasm_v8x16_shuffle(a2, b2, 0,1,4,5,8,9,12,13,16,17,20,21,24,25,28,29)); +} +template +inline v_int16x8 v_rshr_pack(const v_int32x4& a, const v_int32x4& b) +{ + v128_t delta = wasm_i32x4_splat(((int)1 << (n-1))); + v128_t a1 = wasm_i32x4_shr(wasm_i32x4_add(a.val, delta), n); + v128_t b1 = wasm_i32x4_shr(wasm_i32x4_add(b.val, delta), n); + v128_t maxval = wasm_i32x4_splat(32767); + v128_t minval = wasm_i16x8_splat(-32768); + v128_t a2 = wasm_v128_bitselect(maxval, a1, wasm_i32x4_gt(a1, maxval)); + v128_t b2 = wasm_v128_bitselect(maxval, b1, wasm_i32x4_gt(b1, maxval)); + v128_t a3 = wasm_v128_bitselect(minval, a2, wasm_i32x4_lt(a1, minval)); + v128_t b3 = wasm_v128_bitselect(minval, b2, wasm_i32x4_lt(b1, minval)); + return v_int16x8(wasm_v8x16_shuffle(a3, b3, 0,1,4,5,8,9,12,13,16,17,20,21,24,25,28,29)); +} +template +inline v_uint32x4 v_rshr_pack(const v_uint64x2& a, const v_uint64x2& b) +{ + v128_t delta = wasm_i64x2_splat(((int64)1 << (n-1))); + v128_t a1 = wasm_u64x2_shr(wasm_i64x2_add(a.val, delta), n); + v128_t b1 = wasm_u64x2_shr(wasm_i64x2_add(b.val, delta), n); + return v_uint32x4(wasm_v8x16_shuffle(a1, b1, 0,1,2,3,8,9,10,11,16,17,18,19,24,25,26,27)); +} +template +inline v_int32x4 v_rshr_pack(const v_int64x2& a, const v_int64x2& b) +{ + v128_t delta = wasm_i64x2_splat(((int64)1 << (n-1))); + v128_t a1 = wasm_i64x2_shr(wasm_i64x2_add(a.val, delta), n); + v128_t b1 = wasm_i64x2_shr(wasm_i64x2_add(b.val, delta), n); + return v_int32x4(wasm_v8x16_shuffle(a1, b1, 0,1,2,3,8,9,10,11,16,17,18,19,24,25,26,27)); +} +template +inline v_uint8x16 v_rshr_pack_u(const v_int16x8& a, const v_int16x8& b) +{ + v128_t delta = wasm_i16x8_splat(((short)1 << (n-1))); + v128_t a1 = wasm_i16x8_shr(wasm_i16x8_add(a.val, delta), n); + v128_t b1 = wasm_i16x8_shr(wasm_i16x8_add(b.val, delta), n); + v128_t maxval = wasm_i16x8_splat(255); + v128_t minval = wasm_i16x8_splat(0); + v128_t a2 = wasm_v128_bitselect(maxval, a1, wasm_i16x8_gt(a1, maxval)); + v128_t b2 = wasm_v128_bitselect(maxval, b1, wasm_i16x8_gt(b1, maxval)); + v128_t a3 = wasm_v128_bitselect(minval, a2, wasm_i16x8_lt(a1, minval)); + v128_t b3 = wasm_v128_bitselect(minval, b2, wasm_i16x8_lt(b1, minval)); + return v_uint8x16(wasm_v8x16_shuffle(a3, b3, 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30)); +} +template +inline v_uint16x8 v_rshr_pack_u(const v_int32x4& a, const v_int32x4& b) +{ + v128_t delta = wasm_i32x4_splat(((int)1 << (n-1))); + v128_t a1 = wasm_i32x4_shr(wasm_i32x4_add(a.val, delta), n); + v128_t b1 = wasm_i32x4_shr(wasm_i32x4_add(b.val, delta), n); + v128_t maxval = wasm_i32x4_splat(65535); + v128_t minval = wasm_i16x8_splat(0); + v128_t a2 = wasm_v128_bitselect(maxval, a1, wasm_i32x4_gt(a1, maxval)); + v128_t b2 = wasm_v128_bitselect(maxval, b1, wasm_i32x4_gt(b1, maxval)); + v128_t a3 = wasm_v128_bitselect(minval, a2, wasm_i32x4_lt(a1, minval)); + v128_t b3 = wasm_v128_bitselect(minval, b2, wasm_i32x4_lt(b1, minval)); + return v_uint16x8(wasm_v8x16_shuffle(a3, b3, 0,1,4,5,8,9,12,13,16,17,20,21,24,25,28,29)); +} + +inline void v_pack_store(uchar* ptr, const v_uint16x8& a) +{ + v128_t maxval = wasm_i16x8_splat(255); + v128_t a1 = wasm_v128_bitselect(maxval, a.val, wasm_u16x8_gt(a.val, maxval)); + v128_t r = wasm_v8x16_shuffle(a1, a1, 0,2,4,6,8,10,12,14,0,2,4,6,8,10,12,14); + uchar t_ptr[16]; + wasm_v128_store(t_ptr, r); + for (int i=0; i<8; ++i) { + ptr[i] = t_ptr[i]; + } +} +inline void v_pack_store(schar* ptr, const v_int16x8& a) +{ + v128_t maxval = wasm_i16x8_splat(127); + v128_t minval = wasm_i16x8_splat(-128); + v128_t a1 = wasm_v128_bitselect(maxval, a.val, wasm_i16x8_gt(a.val, maxval)); + v128_t a2 = wasm_v128_bitselect(minval, a1, wasm_i16x8_lt(a1, minval)); + v128_t r = wasm_v8x16_shuffle(a2, a2, 0,2,4,6,8,10,12,14,0,2,4,6,8,10,12,14); + schar t_ptr[16]; + wasm_v128_store(t_ptr, r); + for (int i=0; i<8; ++i) { + ptr[i] = t_ptr[i]; + } +} +inline void v_pack_store(ushort* ptr, const v_uint32x4& a) +{ + v128_t maxval = wasm_i32x4_splat(65535); + v128_t a1 = wasm_v128_bitselect(maxval, a.val, wasm_u32x4_gt(a.val, maxval)); + v128_t r = wasm_v8x16_shuffle(a1, a1, 0,1,4,5,8,9,12,13,0,1,4,5,8,9,12,13); + ushort t_ptr[8]; + wasm_v128_store(t_ptr, r); + for (int i=0; i<4; ++i) { + ptr[i] = t_ptr[i]; + } +} +inline void v_pack_store(short* ptr, const v_int32x4& a) +{ + v128_t maxval = wasm_i32x4_splat(32767); + v128_t minval = wasm_i32x4_splat(-32768); + v128_t a1 = wasm_v128_bitselect(maxval, a.val, wasm_i32x4_gt(a.val, maxval)); + v128_t a2 = wasm_v128_bitselect(minval, a1, wasm_i32x4_lt(a1, minval)); + v128_t r = wasm_v8x16_shuffle(a2, a2, 0,1,4,5,8,9,12,13,0,1,4,5,8,9,12,13); + short t_ptr[8]; + wasm_v128_store(t_ptr, r); + for (int i=0; i<4; ++i) { + ptr[i] = t_ptr[i]; + } +} +inline void v_pack_store(unsigned* ptr, const v_uint64x2& a) +{ + v128_t r = wasm_v8x16_shuffle(a.val, a.val, 0,1,2,3,8,9,10,11,0,1,2,3,8,9,10,11); + unsigned t_ptr[4]; + wasm_v128_store(t_ptr, r); + for (int i=0; i<2; ++i) { + ptr[i] = t_ptr[i]; + } +} +inline void v_pack_store(int* ptr, const v_int64x2& a) +{ + v128_t r = wasm_v8x16_shuffle(a.val, a.val, 0,1,2,3,8,9,10,11,0,1,2,3,8,9,10,11); + int t_ptr[4]; + wasm_v128_store(t_ptr, r); + for (int i=0; i<2; ++i) { + ptr[i] = t_ptr[i]; + } +} +inline void v_pack_u_store(uchar* ptr, const v_int16x8& a) +{ + v128_t maxval = wasm_i16x8_splat(255); + v128_t minval = wasm_i16x8_splat(0); + v128_t a1 = wasm_v128_bitselect(maxval, a.val, wasm_i16x8_gt(a.val, maxval)); + v128_t a2 = wasm_v128_bitselect(minval, a1, wasm_i16x8_lt(a1, minval)); + v128_t r = wasm_v8x16_shuffle(a2, a2, 0,2,4,6,8,10,12,14,0,2,4,6,8,10,12,14); + uchar t_ptr[16]; + wasm_v128_store(t_ptr, r); + for (int i=0; i<8; ++i) { + ptr[i] = t_ptr[i]; + } +} +inline void v_pack_u_store(ushort* ptr, const v_int32x4& a) +{ + v128_t maxval = wasm_i32x4_splat(65535); + v128_t minval = wasm_i32x4_splat(0); + v128_t a1 = wasm_v128_bitselect(maxval, a.val, wasm_i32x4_gt(a.val, maxval)); + v128_t a2 = wasm_v128_bitselect(minval, a1, wasm_i32x4_lt(a1, minval)); + v128_t r = wasm_v8x16_shuffle(a2, a2, 0,1,4,5,8,9,12,13,0,1,4,5,8,9,12,13); + ushort t_ptr[8]; + wasm_v128_store(t_ptr, r); + for (int i=0; i<4; ++i) { + ptr[i] = t_ptr[i]; + } +} + +template +inline void v_rshr_pack_store(uchar* ptr, const v_uint16x8& a) +{ + v128_t delta = wasm_i16x8_splat((short)(1 << (n-1))); + v128_t a1 = wasm_u16x8_shr(wasm_i16x8_add(a.val, delta), n); + v128_t maxval = wasm_i16x8_splat(255); + v128_t a2 = wasm_v128_bitselect(maxval, a1, wasm_u16x8_gt(a1, maxval)); + v128_t r = wasm_v8x16_shuffle(a2, a2, 0,2,4,6,8,10,12,14,0,2,4,6,8,10,12,14); + uchar t_ptr[16]; + wasm_v128_store(t_ptr, r); + for (int i=0; i<8; ++i) { + ptr[i] = t_ptr[i]; + } +} +template +inline void v_rshr_pack_store(schar* ptr, const v_int16x8& a) +{ + v128_t delta = wasm_i16x8_splat(((short)1 << (n-1))); + v128_t a1 = wasm_i16x8_shr(wasm_i16x8_add(a.val, delta), n); + v128_t maxval = wasm_i16x8_splat(127); + v128_t minval = wasm_i16x8_splat(-128); + v128_t a2 = wasm_v128_bitselect(maxval, a1, wasm_i16x8_gt(a1, maxval)); + v128_t a3 = wasm_v128_bitselect(minval, a2, wasm_i16x8_lt(a1, minval)); + v128_t r = wasm_v8x16_shuffle(a3, a3, 0,2,4,6,8,10,12,14,0,2,4,6,8,10,12,14); + schar t_ptr[16]; + wasm_v128_store(t_ptr, r); + for (int i=0; i<8; ++i) { + ptr[i] = t_ptr[i]; + } +} +template +inline void v_rshr_pack_store(ushort* ptr, const v_uint32x4& a) +{ + v128_t delta = wasm_i32x4_splat(((int)1 << (n-1))); + v128_t a1 = wasm_u32x4_shr(wasm_i32x4_add(a.val, delta), n); + v128_t maxval = wasm_i32x4_splat(65535); + v128_t a2 = wasm_v128_bitselect(maxval, a1, wasm_u32x4_gt(a1, maxval)); + v128_t r = wasm_v8x16_shuffle(a2, a2, 0,1,4,5,8,9,12,13,0,1,4,5,8,9,12,13); + ushort t_ptr[8]; + wasm_v128_store(t_ptr, r); + for (int i=0; i<4; ++i) { + ptr[i] = t_ptr[i]; + } +} +template +inline void v_rshr_pack_store(short* ptr, const v_int32x4& a) +{ + v128_t delta = wasm_i32x4_splat(((int)1 << (n-1))); + v128_t a1 = wasm_i32x4_shr(wasm_i32x4_add(a.val, delta), n); + v128_t maxval = wasm_i32x4_splat(32767); + v128_t minval = wasm_i32x4_splat(-32768); + v128_t a2 = wasm_v128_bitselect(maxval, a1, wasm_i32x4_gt(a1, maxval)); + v128_t a3 = wasm_v128_bitselect(minval, a2, wasm_i32x4_lt(a1, minval)); + v128_t r = wasm_v8x16_shuffle(a3, a3, 0,1,4,5,8,9,12,13,0,1,4,5,8,9,12,13); + short t_ptr[8]; + wasm_v128_store(t_ptr, r); + for (int i=0; i<4; ++i) { + ptr[i] = t_ptr[i]; + } +} +template +inline void v_rshr_pack_store(unsigned* ptr, const v_uint64x2& a) +{ + v128_t delta = wasm_i64x2_splat(((int64)1 << (n-1))); + v128_t a1 = wasm_u64x2_shr(wasm_i64x2_add(a.val, delta), n); + v128_t r = wasm_v8x16_shuffle(a1, a1, 0,1,2,3,8,9,10,11,0,1,2,3,8,9,10,11); + unsigned t_ptr[4]; + wasm_v128_store(t_ptr, r); + for (int i=0; i<2; ++i) { + ptr[i] = t_ptr[i]; + } +} +template +inline void v_rshr_pack_store(int* ptr, const v_int64x2& a) +{ + v128_t delta = wasm_i64x2_splat(((int64)1 << (n-1))); + v128_t a1 = wasm_i64x2_shr(wasm_i64x2_add(a.val, delta), n); + v128_t r = wasm_v8x16_shuffle(a1, a1, 0,1,2,3,8,9,10,11,0,1,2,3,8,9,10,11); + int t_ptr[4]; + wasm_v128_store(t_ptr, r); + for (int i=0; i<2; ++i) { + ptr[i] = t_ptr[i]; + } +} +template +inline void v_rshr_pack_u_store(uchar* ptr, const v_int16x8& a) +{ + v128_t delta = wasm_i16x8_splat(((short)1 << (n-1))); + v128_t a1 = wasm_i16x8_shr(wasm_i16x8_add(a.val, delta), n); + v128_t maxval = wasm_i16x8_splat(255); + v128_t minval = wasm_i16x8_splat(0); + v128_t a2 = wasm_v128_bitselect(maxval, a1, wasm_i16x8_gt(a1, maxval)); + v128_t a3 = wasm_v128_bitselect(minval, a2, wasm_i16x8_lt(a1, minval)); + v128_t r = wasm_v8x16_shuffle(a3, a3, 0,2,4,6,8,10,12,14,0,2,4,6,8,10,12,14); + uchar t_ptr[16]; + wasm_v128_store(t_ptr, r); + for (int i=0; i<8; ++i) { + ptr[i] = t_ptr[i]; + } +} +template +inline void v_rshr_pack_u_store(ushort* ptr, const v_int32x4& a) +{ + v128_t delta = wasm_i32x4_splat(((int)1 << (n-1))); + v128_t a1 = wasm_i32x4_shr(wasm_i32x4_add(a.val, delta), n); + v128_t maxval = wasm_i32x4_splat(65535); + v128_t minval = wasm_i32x4_splat(0); + v128_t a2 = wasm_v128_bitselect(maxval, a1, wasm_i32x4_gt(a1, maxval)); + v128_t a3 = wasm_v128_bitselect(minval, a2, wasm_i32x4_lt(a1, minval)); + v128_t r = wasm_v8x16_shuffle(a3, a3, 0,1,4,5,8,9,12,13,0,1,4,5,8,9,12,13); + ushort t_ptr[8]; + wasm_v128_store(t_ptr, r); + for (int i=0; i<4; ++i) { + ptr[i] = t_ptr[i]; + } +} + +inline v_uint8x16 v_pack_b(const v_uint16x8& a, const v_uint16x8& b) +{ + v128_t maxval = wasm_i16x8_splat(255); + v128_t a1 = wasm_v128_bitselect(maxval, a.val, wasm_u16x8_gt(a.val, maxval)); + v128_t b1 = wasm_v128_bitselect(maxval, b.val, wasm_u16x8_gt(b.val, maxval)); + return v_uint8x16(wasm_v8x16_shuffle(a1, b1, 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30)); +} + +inline v_uint8x16 v_pack_b(const v_uint32x4& a, const v_uint32x4& b, + const v_uint32x4& c, const v_uint32x4& d) +{ + v128_t maxval = wasm_i32x4_splat(255); + v128_t a1 = wasm_v128_bitselect(maxval, a.val, wasm_u32x4_gt(a.val, maxval)); + v128_t b1 = wasm_v128_bitselect(maxval, b.val, wasm_u32x4_gt(b.val, maxval)); + v128_t c1 = wasm_v128_bitselect(maxval, c.val, wasm_u32x4_gt(c.val, maxval)); + v128_t d1 = wasm_v128_bitselect(maxval, d.val, wasm_u32x4_gt(d.val, maxval)); + v128_t ab = wasm_v8x16_shuffle(a1, b1, 0,4,8,12,16,20,24,28,0,4,8,12,16,20,24,28); + v128_t cd = wasm_v8x16_shuffle(c1, d1, 0,4,8,12,16,20,24,28,0,4,8,12,16,20,24,28); + return v_uint8x16(wasm_v8x16_shuffle(ab, cd, 0,1,2,3,4,5,6,7,16,17,18,19,20,21,22,23)); +} + +inline v_uint8x16 v_pack_b(const v_uint64x2& a, const v_uint64x2& b, const v_uint64x2& c, + const v_uint64x2& d, const v_uint64x2& e, const v_uint64x2& f, + const v_uint64x2& g, const v_uint64x2& h) +{ + v128_t maxval = wasm_i32x4_splat(255); + v128_t a1 = wasm_v128_bitselect(maxval, a.val, ((__u64x2)(a.val) > (__u64x2)maxval)); + v128_t b1 = wasm_v128_bitselect(maxval, b.val, ((__u64x2)(b.val) > (__u64x2)maxval)); + v128_t c1 = wasm_v128_bitselect(maxval, c.val, ((__u64x2)(c.val) > (__u64x2)maxval)); + v128_t d1 = wasm_v128_bitselect(maxval, d.val, ((__u64x2)(d.val) > (__u64x2)maxval)); + v128_t e1 = wasm_v128_bitselect(maxval, e.val, ((__u64x2)(e.val) > (__u64x2)maxval)); + v128_t f1 = wasm_v128_bitselect(maxval, f.val, ((__u64x2)(f.val) > (__u64x2)maxval)); + v128_t g1 = wasm_v128_bitselect(maxval, g.val, ((__u64x2)(g.val) > (__u64x2)maxval)); + v128_t h1 = wasm_v128_bitselect(maxval, h.val, ((__u64x2)(h.val) > (__u64x2)maxval)); + v128_t ab = wasm_v8x16_shuffle(a1, b1, 0,8,16,24,0,8,16,24,0,8,16,24,0,8,16,24); + v128_t cd = wasm_v8x16_shuffle(c1, d1, 0,8,16,24,0,8,16,24,0,8,16,24,0,8,16,24); + v128_t ef = wasm_v8x16_shuffle(e1, f1, 0,8,16,24,0,8,16,24,0,8,16,24,0,8,16,24); + v128_t gh = wasm_v8x16_shuffle(g1, h1, 0,8,16,24,0,8,16,24,0,8,16,24,0,8,16,24); + v128_t abcd = wasm_v8x16_shuffle(ab, cd, 0,1,2,3,16,17,18,19,0,1,2,3,16,17,18,19); + v128_t efgh = wasm_v8x16_shuffle(ef, gh, 0,1,2,3,16,17,18,19,0,1,2,3,16,17,18,19); + return v_uint8x16(wasm_v8x16_shuffle(abcd, efgh, 0,1,2,3,4,5,6,7,16,17,18,19,20,21,22,23)); +} + +inline v_float32x4 v_matmul(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& m3) +{ + v128_t v0 = wasm_f32x4_splat(wasm_f32x4_extract_lane(v.val, 0)); + v128_t v1 = wasm_f32x4_splat(wasm_f32x4_extract_lane(v.val, 1)); + v128_t v2 = wasm_f32x4_splat(wasm_f32x4_extract_lane(v.val, 2)); + v128_t v3 = wasm_f32x4_splat(wasm_f32x4_extract_lane(v.val, 3)); + v0 = wasm_f32x4_mul(v0, m0.val); + v1 = wasm_f32x4_mul(v1, m1.val); + v2 = wasm_f32x4_mul(v2, m2.val); + v3 = wasm_f32x4_mul(v3, m3.val); + + return v_float32x4(wasm_f32x4_add(wasm_f32x4_add(v0, v1), wasm_f32x4_add(v2, v3))); +} + +inline v_float32x4 v_matmuladd(const v_float32x4& v, const v_float32x4& m0, + const v_float32x4& m1, const v_float32x4& m2, + const v_float32x4& a) +{ + v128_t v0 = wasm_f32x4_splat(wasm_f32x4_extract_lane(v.val, 0)); + v128_t v1 = wasm_f32x4_splat(wasm_f32x4_extract_lane(v.val, 1)); + v128_t v2 = wasm_f32x4_splat(wasm_f32x4_extract_lane(v.val, 2)); + v0 = wasm_f32x4_mul(v0, m0.val); + v1 = wasm_f32x4_mul(v1, m1.val); + v2 = wasm_f32x4_mul(v2, m2.val); + + return v_float32x4(wasm_f32x4_add(wasm_f32x4_add(v0, v1), wasm_f32x4_add(v2, a.val))); +} + +#define OPENCV_HAL_IMPL_WASM_BIN_OP(bin_op, _Tpvec, intrin) \ +inline _Tpvec operator bin_op (const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(intrin(a.val, b.val)); \ +} \ +inline _Tpvec& operator bin_op##= (_Tpvec& a, const _Tpvec& b) \ +{ \ + a.val = intrin(a.val, b.val); \ + return a; \ +} + +OPENCV_HAL_IMPL_WASM_BIN_OP(+, v_uint8x16, wasm_u8x16_add_saturate) +OPENCV_HAL_IMPL_WASM_BIN_OP(-, v_uint8x16, wasm_u8x16_sub_saturate) +OPENCV_HAL_IMPL_WASM_BIN_OP(+, v_int8x16, wasm_i8x16_add_saturate) +OPENCV_HAL_IMPL_WASM_BIN_OP(-, v_int8x16, wasm_i8x16_sub_saturate) +OPENCV_HAL_IMPL_WASM_BIN_OP(+, v_uint16x8, wasm_u16x8_add_saturate) +OPENCV_HAL_IMPL_WASM_BIN_OP(-, v_uint16x8, wasm_u16x8_sub_saturate) +OPENCV_HAL_IMPL_WASM_BIN_OP(+, v_int16x8, wasm_i16x8_add_saturate) +OPENCV_HAL_IMPL_WASM_BIN_OP(-, v_int16x8, wasm_i16x8_sub_saturate) +OPENCV_HAL_IMPL_WASM_BIN_OP(+, v_uint32x4, wasm_i32x4_add) +OPENCV_HAL_IMPL_WASM_BIN_OP(-, v_uint32x4, wasm_i32x4_sub) +OPENCV_HAL_IMPL_WASM_BIN_OP(*, v_uint32x4, wasm_i32x4_mul) +OPENCV_HAL_IMPL_WASM_BIN_OP(+, v_int32x4, wasm_i32x4_add) +OPENCV_HAL_IMPL_WASM_BIN_OP(-, v_int32x4, wasm_i32x4_sub) +OPENCV_HAL_IMPL_WASM_BIN_OP(*, v_int32x4, wasm_i32x4_mul) +OPENCV_HAL_IMPL_WASM_BIN_OP(+, v_float32x4, wasm_f32x4_add) +OPENCV_HAL_IMPL_WASM_BIN_OP(-, v_float32x4, wasm_f32x4_sub) +OPENCV_HAL_IMPL_WASM_BIN_OP(*, v_float32x4, wasm_f32x4_mul) +OPENCV_HAL_IMPL_WASM_BIN_OP(/, v_float32x4, wasm_f32x4_div) +OPENCV_HAL_IMPL_WASM_BIN_OP(+, v_uint64x2, wasm_i64x2_add) +OPENCV_HAL_IMPL_WASM_BIN_OP(-, v_uint64x2, wasm_i64x2_sub) +OPENCV_HAL_IMPL_WASM_BIN_OP(+, v_int64x2, wasm_i64x2_add) +OPENCV_HAL_IMPL_WASM_BIN_OP(-, v_int64x2, wasm_i64x2_sub) +OPENCV_HAL_IMPL_WASM_BIN_OP(+, v_float64x2, wasm_f64x2_add) +OPENCV_HAL_IMPL_WASM_BIN_OP(-, v_float64x2, wasm_f64x2_sub) +OPENCV_HAL_IMPL_WASM_BIN_OP(*, v_float64x2, wasm_f64x2_mul) +OPENCV_HAL_IMPL_WASM_BIN_OP(/, v_float64x2, wasm_f64x2_div) + +// saturating multiply 8-bit, 16-bit +#define OPENCV_HAL_IMPL_WASM_MUL_SAT(_Tpvec, _Tpwvec) \ +inline _Tpvec operator * (const _Tpvec& a, const _Tpvec& b) \ +{ \ + _Tpwvec c, d; \ + v_mul_expand(a, b, c, d); \ + return v_pack(c, d); \ +} \ +inline _Tpvec& operator *= (_Tpvec& a, const _Tpvec& b) \ +{ a = a * b; return a; } + +OPENCV_HAL_IMPL_WASM_MUL_SAT(v_uint8x16, v_uint16x8) +OPENCV_HAL_IMPL_WASM_MUL_SAT(v_int8x16, v_int16x8) +OPENCV_HAL_IMPL_WASM_MUL_SAT(v_uint16x8, v_uint32x4) +OPENCV_HAL_IMPL_WASM_MUL_SAT(v_int16x8, v_int32x4) + +// Multiply and expand +inline void v_mul_expand(const v_uint8x16& a, const v_uint8x16& b, + v_uint16x8& c, v_uint16x8& d) +{ + v_uint16x8 a0, a1, b0, b1; + v_expand(a, a0, a1); + v_expand(b, b0, b1); + c = v_mul_wrap(a0, b0); + d = v_mul_wrap(a1, b1); +} + +inline void v_mul_expand(const v_int8x16& a, const v_int8x16& b, + v_int16x8& c, v_int16x8& d) +{ + v_int16x8 a0, a1, b0, b1; + v_expand(a, a0, a1); + v_expand(b, b0, b1); + c = v_mul_wrap(a0, b0); + d = v_mul_wrap(a1, b1); +} + +inline void v_mul_expand(const v_int16x8& a, const v_int16x8& b, + v_int32x4& c, v_int32x4& d) +{ + v_int32x4 a0, a1, b0, b1; + v_expand(a, a0, a1); + v_expand(b, b0, b1); + c.val = wasm_i32x4_mul(a0.val, b0.val); + d.val = wasm_i32x4_mul(a1.val, b1.val); +} + +inline void v_mul_expand(const v_uint16x8& a, const v_uint16x8& b, + v_uint32x4& c, v_uint32x4& d) +{ + v_uint32x4 a0, a1, b0, b1; + v_expand(a, a0, a1); + v_expand(b, b0, b1); + c.val = wasm_i32x4_mul(a0.val, b0.val); + d.val = wasm_i32x4_mul(a1.val, b1.val); +} + +inline void v_mul_expand(const v_uint32x4& a, const v_uint32x4& b, + v_uint64x2& c, v_uint64x2& d) +{ + v_uint64x2 a0, a1, b0, b1; + v_expand(a, a0, a1); + v_expand(b, b0, b1); + c.val = ((__u64x2)(a0.val) * (__u64x2)(b0.val)); + d.val = ((__u64x2)(a1.val) * (__u64x2)(b1.val)); +} + +inline v_int16x8 v_mul_hi(const v_int16x8& a, const v_int16x8& b) +{ + v_int32x4 a0, a1, b0, b1; + v_expand(a, a0, a1); + v_expand(b, b0, b1); + v128_t c = wasm_i32x4_mul(a0.val, b0.val); + v128_t d = wasm_i32x4_mul(a1.val, b1.val); + return v_int16x8(wasm_v8x16_shuffle(c, d, 2,3,6,7,10,11,14,15,18,19,22,23,26,27,30,31)); +} +inline v_uint16x8 v_mul_hi(const v_uint16x8& a, const v_uint16x8& b) +{ + v_uint32x4 a0, a1, b0, b1; + v_expand(a, a0, a1); + v_expand(b, b0, b1); + v128_t c = wasm_i32x4_mul(a0.val, b0.val); + v128_t d = wasm_i32x4_mul(a1.val, b1.val); + return v_uint16x8(wasm_v8x16_shuffle(c, d, 2,3,6,7,10,11,14,15,18,19,22,23,26,27,30,31)); +} + +//////// Dot Product //////// + +inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b) +{ + v128_t a0 = wasm_i32x4_shr(wasm_i32x4_shl(a.val, 16), 16); + v128_t a1 = wasm_i32x4_shr(a.val, 16); + v128_t b0 = wasm_i32x4_shr(wasm_i32x4_shl(b.val, 16), 16); + v128_t b1 = wasm_i32x4_shr(b.val, 16); + v128_t c = wasm_i32x4_mul(a0, b0); + v128_t d = wasm_i32x4_mul(a1, b1); + return v_int32x4(wasm_i32x4_add(c, d)); +} + +inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b, const v_int32x4& c) +{ return v_dotprod(a, b) + c; } + +inline v_int64x2 v_dotprod(const v_int32x4& a, const v_int32x4& b) +{ + v128_t a0 = wasm_i64x2_shr(wasm_i64x2_shl(a.val, 32), 32); + v128_t a1 = wasm_i64x2_shr(a.val, 32); + v128_t b0 = wasm_i64x2_shr(wasm_i64x2_shl(b.val, 32), 32); + v128_t b1 = wasm_i64x2_shr(b.val, 32); + v128_t c = (v128_t)((__i64x2)a0 * (__i64x2)b0); + v128_t d = (v128_t)((__i64x2)a1 * (__i64x2)b1); + return v_int64x2(wasm_i64x2_add(c, d)); +} +inline v_int64x2 v_dotprod(const v_int32x4& a, const v_int32x4& b, const v_int64x2& c) +{ + return v_dotprod(a, b) + c; +} + +// 8 >> 32 +inline v_uint32x4 v_dotprod_expand(const v_uint8x16& a, const v_uint8x16& b) +{ + v128_t a0 = wasm_u16x8_shr(wasm_i16x8_shl(a.val, 8), 8); + v128_t a1 = wasm_u16x8_shr(a.val, 8); + v128_t b0 = wasm_u16x8_shr(wasm_i16x8_shl(b.val, 8), 8); + v128_t b1 = wasm_u16x8_shr(b.val, 8); + return v_uint32x4(( + v_dotprod(v_int16x8(a0), v_int16x8(b0)) + + v_dotprod(v_int16x8(a1), v_int16x8(b1))).val + ); +} +inline v_uint32x4 v_dotprod_expand(const v_uint8x16& a, const v_uint8x16& b, const v_uint32x4& c) +{ return v_dotprod_expand(a, b) + c; } + +inline v_int32x4 v_dotprod_expand(const v_int8x16& a, const v_int8x16& b) +{ + v128_t a0 = wasm_i16x8_shr(wasm_i16x8_shl(a.val, 8), 8); + v128_t a1 = wasm_i16x8_shr(a.val, 8); + v128_t b0 = wasm_i16x8_shr(wasm_i16x8_shl(b.val, 8), 8); + v128_t b1 = wasm_i16x8_shr(b.val, 8); + return v_int32x4( + v_dotprod(v_int16x8(a0), v_int16x8(b0)) + + v_dotprod(v_int16x8(a1), v_int16x8(b1)) + ); +} +inline v_int32x4 v_dotprod_expand(const v_int8x16& a, const v_int8x16& b, const v_int32x4& c) +{ return v_dotprod_expand(a, b) + c; } + +// 16 >> 64 +inline v_uint64x2 v_dotprod_expand(const v_uint16x8& a, const v_uint16x8& b) +{ + v128_t a0 = wasm_u32x4_shr(wasm_i32x4_shl(a.val, 16), 16); + v128_t a1 = wasm_u32x4_shr(a.val, 16); + v128_t b0 = wasm_u32x4_shr(wasm_i32x4_shl(b.val, 16), 16); + v128_t b1 = wasm_u32x4_shr(b.val, 16); + return v_uint64x2(( + v_dotprod(v_int32x4(a0), v_int32x4(b0)) + + v_dotprod(v_int32x4(a1), v_int32x4(b1))).val + ); +} +inline v_uint64x2 v_dotprod_expand(const v_uint16x8& a, const v_uint16x8& b, const v_uint64x2& c) +{ return v_dotprod_expand(a, b) + c; } + +inline v_int64x2 v_dotprod_expand(const v_int16x8& a, const v_int16x8& b) +{ + v128_t a0 = wasm_i32x4_shr(wasm_i32x4_shl(a.val, 16), 16); + v128_t a1 = wasm_i32x4_shr(a.val, 16); + v128_t b0 = wasm_i32x4_shr(wasm_i32x4_shl(b.val, 16), 16); + v128_t b1 = wasm_i32x4_shr(b.val, 16); + return v_int64x2(( + v_dotprod(v_int32x4(a0), v_int32x4(b0)) + + v_dotprod(v_int32x4(a1), v_int32x4(b1))) + ); +} + +inline v_int64x2 v_dotprod_expand(const v_int16x8& a, const v_int16x8& b, const v_int64x2& c) +{ return v_dotprod_expand(a, b) + c; } + +// 32 >> 64f +inline v_float64x2 v_dotprod_expand(const v_int32x4& a, const v_int32x4& b) +{ return v_cvt_f64(v_dotprod(a, b)); } +inline v_float64x2 v_dotprod_expand(const v_int32x4& a, const v_int32x4& b, const v_float64x2& c) +{ return v_dotprod_expand(a, b) + c; } + +//////// Fast Dot Product //////// + +// 16 >> 32 +inline v_int32x4 v_dotprod_fast(const v_int16x8& a, const v_int16x8& b) +{ return v_dotprod(a, b); } +inline v_int32x4 v_dotprod_fast(const v_int16x8& a, const v_int16x8& b, const v_int32x4& c) +{ return v_dotprod(a, b, c); } + +// 32 >> 64 +inline v_int64x2 v_dotprod_fast(const v_int32x4& a, const v_int32x4& b) +{ return v_dotprod(a, b); } +inline v_int64x2 v_dotprod_fast(const v_int32x4& a, const v_int32x4& b, const v_int64x2& c) +{ return v_dotprod(a, b, c); } + +// 8 >> 32 +inline v_uint32x4 v_dotprod_expand_fast(const v_uint8x16& a, const v_uint8x16& b) +{ return v_dotprod_expand(a, b); } +inline v_uint32x4 v_dotprod_expand_fast(const v_uint8x16& a, const v_uint8x16& b, const v_uint32x4& c) +{ return v_dotprod_expand(a, b, c); } +inline v_int32x4 v_dotprod_expand_fast(const v_int8x16& a, const v_int8x16& b) +{ return v_dotprod_expand(a, b); } +inline v_int32x4 v_dotprod_expand_fast(const v_int8x16& a, const v_int8x16& b, const v_int32x4& c) +{ return v_dotprod_expand(a, b, c); } + +// 16 >> 64 +inline v_uint64x2 v_dotprod_expand_fast(const v_uint16x8& a, const v_uint16x8& b) +{ return v_dotprod_expand(a, b); } +inline v_uint64x2 v_dotprod_expand_fast(const v_uint16x8& a, const v_uint16x8& b, const v_uint64x2& c) +{ return v_dotprod_expand(a, b, c); } +inline v_int64x2 v_dotprod_expand_fast(const v_int16x8& a, const v_int16x8& b) +{ return v_dotprod_expand(a, b); } +inline v_int64x2 v_dotprod_expand_fast(const v_int16x8& a, const v_int16x8& b, const v_int64x2& c) +{ return v_dotprod_expand(a, b, c); } + +// 32 >> 64f +inline v_float64x2 v_dotprod_expand_fast(const v_int32x4& a, const v_int32x4& b) +{ return v_dotprod_expand(a, b); } +inline v_float64x2 v_dotprod_expand_fast(const v_int32x4& a, const v_int32x4& b, const v_float64x2& c) +{ return v_dotprod_expand(a, b, c); } + +#define OPENCV_HAL_IMPL_WASM_LOGIC_OP(_Tpvec) \ +OPENCV_HAL_IMPL_WASM_BIN_OP(&, _Tpvec, wasm_v128_and) \ +OPENCV_HAL_IMPL_WASM_BIN_OP(|, _Tpvec, wasm_v128_or) \ +OPENCV_HAL_IMPL_WASM_BIN_OP(^, _Tpvec, wasm_v128_xor) \ +inline _Tpvec operator ~ (const _Tpvec& a) \ +{ \ + return _Tpvec(wasm_v128_not(a.val)); \ +} + +OPENCV_HAL_IMPL_WASM_LOGIC_OP(v_uint8x16) +OPENCV_HAL_IMPL_WASM_LOGIC_OP(v_int8x16) +OPENCV_HAL_IMPL_WASM_LOGIC_OP(v_uint16x8) +OPENCV_HAL_IMPL_WASM_LOGIC_OP(v_int16x8) +OPENCV_HAL_IMPL_WASM_LOGIC_OP(v_uint32x4) +OPENCV_HAL_IMPL_WASM_LOGIC_OP(v_int32x4) +OPENCV_HAL_IMPL_WASM_LOGIC_OP(v_uint64x2) +OPENCV_HAL_IMPL_WASM_LOGIC_OP(v_int64x2) +OPENCV_HAL_IMPL_WASM_LOGIC_OP(v_float32x4) +OPENCV_HAL_IMPL_WASM_LOGIC_OP(v_float64x2) + +inline v_float32x4 v_sqrt(const v_float32x4& x) +{ + return v_float32x4(wasm_f32x4_sqrt(x.val)); +} + +inline v_float32x4 v_invsqrt(const v_float32x4& x) +{ + const v128_t _1_0 = wasm_f32x4_splat(1.0); + return v_float32x4(wasm_f32x4_div(_1_0, wasm_f32x4_sqrt(x.val))); +} + +inline v_float64x2 v_sqrt(const v_float64x2& x) +{ + return v_float64x2(wasm_f64x2_sqrt(x.val)); +} + +inline v_float64x2 v_invsqrt(const v_float64x2& x) +{ + const v128_t _1_0 = wasm_f64x2_splat(1.0); + return v_float64x2(wasm_f64x2_div(_1_0, wasm_f64x2_sqrt(x.val))); +} + +#define OPENCV_HAL_IMPL_WASM_ABS_INT_FUNC(_Tpuvec, _Tpsvec, suffix, zsuffix, shiftWidth) \ +inline _Tpuvec v_abs(const _Tpsvec& x) \ +{ \ + v128_t s = wasm_##suffix##_shr(x.val, shiftWidth); \ + v128_t f = wasm_##zsuffix##_shr(x.val, shiftWidth); \ + return _Tpuvec(wasm_##zsuffix##_add(wasm_v128_xor(x.val, f), s)); \ +} + +OPENCV_HAL_IMPL_WASM_ABS_INT_FUNC(v_uint8x16, v_int8x16, u8x16, i8x16, 7) +OPENCV_HAL_IMPL_WASM_ABS_INT_FUNC(v_uint16x8, v_int16x8, u16x8, i16x8, 15) +OPENCV_HAL_IMPL_WASM_ABS_INT_FUNC(v_uint32x4, v_int32x4, u32x4, i32x4, 31) + +inline v_float32x4 v_abs(const v_float32x4& x) +{ return v_float32x4(wasm_f32x4_abs(x.val)); } +inline v_float64x2 v_abs(const v_float64x2& x) +{ + return v_float64x2(wasm_f64x2_abs(x.val)); +} + +// TODO: exp, log, sin, cos + +#define OPENCV_HAL_IMPL_WASM_BIN_FUNC(_Tpvec, func, intrin) \ +inline _Tpvec func(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(intrin(a.val, b.val)); \ +} + +OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_float32x4, v_min, wasm_f32x4_min) +OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_float32x4, v_max, wasm_f32x4_max) +OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_float64x2, v_min, wasm_f64x2_min) +OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_float64x2, v_max, wasm_f64x2_max) + +#define OPENCV_HAL_IMPL_WASM_MINMAX_S_INIT_FUNC(_Tpvec, suffix) \ +inline _Tpvec v_min(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(wasm_v128_bitselect(b.val, a.val, wasm_##suffix##_gt(a.val, b.val))); \ +} \ +inline _Tpvec v_max(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(wasm_v128_bitselect(a.val, b.val, wasm_##suffix##_gt(a.val, b.val))); \ +} + +OPENCV_HAL_IMPL_WASM_MINMAX_S_INIT_FUNC(v_int8x16, i8x16) +OPENCV_HAL_IMPL_WASM_MINMAX_S_INIT_FUNC(v_int16x8, i16x8) +OPENCV_HAL_IMPL_WASM_MINMAX_S_INIT_FUNC(v_int32x4, i32x4) + +#define OPENCV_HAL_IMPL_WASM_MINMAX_U_INIT_FUNC(_Tpvec, suffix, deltaNum) \ +inline _Tpvec v_min(const _Tpvec& a, const _Tpvec& b) \ +{ \ + v128_t delta = wasm_##suffix##_splat(deltaNum); \ + v128_t mask = wasm_##suffix##_gt(wasm_v128_xor(a.val, delta), wasm_v128_xor(b.val, delta)); \ + return _Tpvec(wasm_v128_bitselect(b.val, a.val, mask)); \ +} \ +inline _Tpvec v_max(const _Tpvec& a, const _Tpvec& b) \ +{ \ + v128_t delta = wasm_##suffix##_splat(deltaNum); \ + v128_t mask = wasm_##suffix##_gt(wasm_v128_xor(a.val, delta), wasm_v128_xor(b.val, delta)); \ + return _Tpvec(wasm_v128_bitselect(a.val, b.val, mask)); \ +} + +OPENCV_HAL_IMPL_WASM_MINMAX_U_INIT_FUNC(v_uint8x16, i8x16, (schar)0x80) +OPENCV_HAL_IMPL_WASM_MINMAX_U_INIT_FUNC(v_uint16x8, i16x8, (short)0x8000) +OPENCV_HAL_IMPL_WASM_MINMAX_U_INIT_FUNC(v_uint32x4, i32x4, (int)0x80000000) + +#define OPENCV_HAL_IMPL_WASM_INIT_CMP_OP(_Tpvec, suffix, esuffix) \ +inline _Tpvec operator == (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(wasm_##esuffix##_eq(a.val, b.val)); } \ +inline _Tpvec operator != (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(wasm_##esuffix##_ne(a.val, b.val)); } \ +inline _Tpvec operator < (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(wasm_##suffix##_lt(a.val, b.val)); } \ +inline _Tpvec operator > (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(wasm_##suffix##_gt(a.val, b.val)); } \ +inline _Tpvec operator <= (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(wasm_##suffix##_le(a.val, b.val)); } \ +inline _Tpvec operator >= (const _Tpvec& a, const _Tpvec& b) \ +{ return _Tpvec(wasm_##suffix##_ge(a.val, b.val)); } + +OPENCV_HAL_IMPL_WASM_INIT_CMP_OP(v_uint8x16, u8x16, i8x16) +OPENCV_HAL_IMPL_WASM_INIT_CMP_OP(v_int8x16, i8x16, i8x16) +OPENCV_HAL_IMPL_WASM_INIT_CMP_OP(v_uint16x8, u16x8, i16x8) +OPENCV_HAL_IMPL_WASM_INIT_CMP_OP(v_int16x8, i16x8, i16x8) +OPENCV_HAL_IMPL_WASM_INIT_CMP_OP(v_uint32x4, u32x4, i32x4) +OPENCV_HAL_IMPL_WASM_INIT_CMP_OP(v_int32x4, i32x4, i32x4) +OPENCV_HAL_IMPL_WASM_INIT_CMP_OP(v_float32x4, f32x4, f32x4) +OPENCV_HAL_IMPL_WASM_INIT_CMP_OP(v_float64x2, f64x2, f64x2) + +#define OPENCV_HAL_IMPL_WASM_64BIT_CMP_OP(_Tpvec, cast) \ +inline _Tpvec operator == (const _Tpvec& a, const _Tpvec& b) \ +{ return cast(v_reinterpret_as_f64(a) == v_reinterpret_as_f64(b)); } \ +inline _Tpvec operator != (const _Tpvec& a, const _Tpvec& b) \ +{ return cast(v_reinterpret_as_f64(a) != v_reinterpret_as_f64(b)); } + +OPENCV_HAL_IMPL_WASM_64BIT_CMP_OP(v_uint64x2, v_reinterpret_as_u64) +OPENCV_HAL_IMPL_WASM_64BIT_CMP_OP(v_int64x2, v_reinterpret_as_s64) + +inline v_float32x4 v_not_nan(const v_float32x4& a) +{ + v128_t z = wasm_i32x4_splat(0x7fffffff); + v128_t t = wasm_i32x4_splat(0x7f800000); + return v_float32x4(wasm_u32x4_lt(wasm_v128_and(a.val, z), t)); +} +inline v_float64x2 v_not_nan(const v_float64x2& a) +{ + v128_t z = wasm_i64x2_splat(0x7fffffffffffffff); + v128_t t = wasm_i64x2_splat(0x7ff0000000000000); + return v_float64x2((__u64x2)(wasm_v128_and(a.val, z)) < (__u64x2)t); +} + +OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_uint8x16, v_add_wrap, wasm_i8x16_add) +OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_int8x16, v_add_wrap, wasm_i8x16_add) +OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_uint16x8, v_add_wrap, wasm_i16x8_add) +OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_int16x8, v_add_wrap, wasm_i16x8_add) +OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_uint8x16, v_sub_wrap, wasm_i8x16_sub) +OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_int8x16, v_sub_wrap, wasm_i8x16_sub) +OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_uint16x8, v_sub_wrap, wasm_i16x8_sub) +OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_int16x8, v_sub_wrap, wasm_i16x8_sub) +#if (__EMSCRIPTEN_major__ * 1000000 + __EMSCRIPTEN_minor__ * 1000 + __EMSCRIPTEN_tiny__) >= (1039012) +// details: https://github.com/opencv/opencv/issues/18097 ( https://github.com/emscripten-core/emscripten/issues/12018 ) +// 1.39.12: https://github.com/emscripten-core/emscripten/commit/cd801d0f110facfd694212a3c8b2ed2ffcd630e2 +inline v_uint8x16 v_mul_wrap(const v_uint8x16& a, const v_uint8x16& b) +{ + uchar a_[16], b_[16]; + wasm_v128_store(a_, a.val); + wasm_v128_store(b_, b.val); + for (int i = 0; i < 16; i++) + a_[i] = (uchar)(a_[i] * b_[i]); + return v_uint8x16(wasm_v128_load(a_)); +} +inline v_int8x16 v_mul_wrap(const v_int8x16& a, const v_int8x16& b) +{ + schar a_[16], b_[16]; + wasm_v128_store(a_, a.val); + wasm_v128_store(b_, b.val); + for (int i = 0; i < 16; i++) + a_[i] = (schar)(a_[i] * b_[i]); + return v_int8x16(wasm_v128_load(a_)); +} +#else +OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_uint8x16, v_mul_wrap, wasm_i8x16_mul) +OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_int8x16, v_mul_wrap, wasm_i8x16_mul) +#endif +OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_uint16x8, v_mul_wrap, wasm_i16x8_mul) +OPENCV_HAL_IMPL_WASM_BIN_FUNC(v_int16x8, v_mul_wrap, wasm_i16x8_mul) + + +/** Absolute difference **/ + +inline v_uint8x16 v_absdiff(const v_uint8x16& a, const v_uint8x16& b) +{ return v_add_wrap(a - b, b - a); } +inline v_uint16x8 v_absdiff(const v_uint16x8& a, const v_uint16x8& b) +{ return v_add_wrap(a - b, b - a); } +inline v_uint32x4 v_absdiff(const v_uint32x4& a, const v_uint32x4& b) +{ return v_max(a, b) - v_min(a, b); } + +inline v_uint8x16 v_absdiff(const v_int8x16& a, const v_int8x16& b) +{ + v_int8x16 d = v_sub_wrap(a, b); + v_int8x16 m = a < b; + return v_reinterpret_as_u8(v_sub_wrap(d ^ m, m)); +} +inline v_uint16x8 v_absdiff(const v_int16x8& a, const v_int16x8& b) +{ + return v_reinterpret_as_u16(v_sub_wrap(v_max(a, b), v_min(a, b))); +} +inline v_uint32x4 v_absdiff(const v_int32x4& a, const v_int32x4& b) +{ + v_int32x4 d = a - b; + v_int32x4 m = a < b; + return v_reinterpret_as_u32((d ^ m) - m); +} + +/** Saturating absolute difference **/ +inline v_int8x16 v_absdiffs(const v_int8x16& a, const v_int8x16& b) +{ + v_int8x16 d = a - b; + v_int8x16 m = a < b; + return (d ^ m) - m; + } +inline v_int16x8 v_absdiffs(const v_int16x8& a, const v_int16x8& b) +{ return v_max(a, b) - v_min(a, b); } + + +inline v_int32x4 v_fma(const v_int32x4& a, const v_int32x4& b, const v_int32x4& c) +{ + return a * b + c; +} + +inline v_int32x4 v_muladd(const v_int32x4& a, const v_int32x4& b, const v_int32x4& c) +{ + return v_fma(a, b, c); +} + +inline v_float32x4 v_fma(const v_float32x4& a, const v_float32x4& b, const v_float32x4& c) +{ + return a * b + c; +} + +inline v_float64x2 v_fma(const v_float64x2& a, const v_float64x2& b, const v_float64x2& c) +{ + return a * b + c; +} + +inline v_float32x4 v_absdiff(const v_float32x4& a, const v_float32x4& b) +{ + v128_t absmask_vec = wasm_i32x4_splat(0x7fffffff); + return v_float32x4(wasm_v128_and(wasm_f32x4_sub(a.val, b.val), absmask_vec)); +} +inline v_float64x2 v_absdiff(const v_float64x2& a, const v_float64x2& b) +{ + v128_t absmask_vec = wasm_u64x2_shr(wasm_i32x4_splat(-1), 1); + return v_float64x2(wasm_v128_and(wasm_f64x2_sub(a.val, b.val), absmask_vec)); +} + +#define OPENCV_HAL_IMPL_WASM_MISC_FLT_OP(_Tpvec, suffix) \ +inline _Tpvec v_magnitude(const _Tpvec& a, const _Tpvec& b) \ +{ \ + v128_t a_Square = wasm_##suffix##_mul(a.val, a.val); \ + v128_t b_Square = wasm_##suffix##_mul(b.val, b.val); \ + return _Tpvec(wasm_##suffix##_sqrt(wasm_##suffix##_add(a_Square, b_Square))); \ +} \ +inline _Tpvec v_sqr_magnitude(const _Tpvec& a, const _Tpvec& b) \ +{ \ + v128_t a_Square = wasm_##suffix##_mul(a.val, a.val); \ + v128_t b_Square = wasm_##suffix##_mul(b.val, b.val); \ + return _Tpvec(wasm_##suffix##_add(a_Square, b_Square)); \ +} \ +inline _Tpvec v_muladd(const _Tpvec& a, const _Tpvec& b, const _Tpvec& c) \ +{ \ + return _Tpvec(wasm_##suffix##_add(wasm_##suffix##_mul(a.val, b.val), c.val)); \ +} + +OPENCV_HAL_IMPL_WASM_MISC_FLT_OP(v_float32x4, f32x4) +OPENCV_HAL_IMPL_WASM_MISC_FLT_OP(v_float64x2, f64x2) + +#define OPENCV_HAL_IMPL_WASM_SHIFT_OP(_Tpuvec, _Tpsvec, suffix, ssuffix) \ +inline _Tpuvec operator << (const _Tpuvec& a, int imm) \ +{ \ + return _Tpuvec(wasm_##suffix##_shl(a.val, imm)); \ +} \ +inline _Tpsvec operator << (const _Tpsvec& a, int imm) \ +{ \ + return _Tpsvec(wasm_##suffix##_shl(a.val, imm)); \ +} \ +inline _Tpuvec operator >> (const _Tpuvec& a, int imm) \ +{ \ + return _Tpuvec(wasm_##ssuffix##_shr(a.val, imm)); \ +} \ +inline _Tpsvec operator >> (const _Tpsvec& a, int imm) \ +{ \ + return _Tpsvec(wasm_##suffix##_shr(a.val, imm)); \ +} \ +template \ +inline _Tpuvec v_shl(const _Tpuvec& a) \ +{ \ + return _Tpuvec(wasm_##suffix##_shl(a.val, imm)); \ +} \ +template \ +inline _Tpsvec v_shl(const _Tpsvec& a) \ +{ \ + return _Tpsvec(wasm_##suffix##_shl(a.val, imm)); \ +} \ +template \ +inline _Tpuvec v_shr(const _Tpuvec& a) \ +{ \ + return _Tpuvec(wasm_##ssuffix##_shr(a.val, imm)); \ +} \ +template \ +inline _Tpsvec v_shr(const _Tpsvec& a) \ +{ \ + return _Tpsvec(wasm_##suffix##_shr(a.val, imm)); \ +} + +OPENCV_HAL_IMPL_WASM_SHIFT_OP(v_uint8x16, v_int8x16, i8x16, u8x16) +OPENCV_HAL_IMPL_WASM_SHIFT_OP(v_uint16x8, v_int16x8, i16x8, u16x8) +OPENCV_HAL_IMPL_WASM_SHIFT_OP(v_uint32x4, v_int32x4, i32x4, u32x4) +OPENCV_HAL_IMPL_WASM_SHIFT_OP(v_uint64x2, v_int64x2, i64x2, u64x2) + +namespace hal_wasm_internal +{ + template 16)), + bool is_first = (imm == 0), + bool is_second = (imm == 16), + bool is_other = (((imm > 0) && (imm < 16)))> + class v_wasm_palignr_u8_class; + + template + class v_wasm_palignr_u8_class; + + template + class v_wasm_palignr_u8_class + { + public: + inline v128_t operator()(const v128_t& a, const v128_t&) const + { + return a; + } + }; + + template + class v_wasm_palignr_u8_class + { + public: + inline v128_t operator()(const v128_t&, const v128_t& b) const + { + return b; + } + }; + + template + class v_wasm_palignr_u8_class + { + public: + inline v128_t operator()(const v128_t& a, const v128_t& b) const + { + enum { imm2 = (sizeof(v128_t) - imm) }; + return wasm_v8x16_shuffle(a, b, + imm, imm+1, imm+2, imm+3, + imm+4, imm+5, imm+6, imm+7, + imm+8, imm+9, imm+10, imm+11, + imm+12, imm+13, imm+14, imm+15); + } + }; + + template + inline v128_t v_wasm_palignr_u8(const v128_t& a, const v128_t& b) + { + CV_StaticAssert((imm >= 0) && (imm <= 16), "Invalid imm for v_wasm_palignr_u8."); + return v_wasm_palignr_u8_class()(a, b); + } +} + +template +inline _Tpvec v_rotate_right(const _Tpvec &a) +{ + using namespace hal_wasm_internal; + enum { imm2 = (imm * sizeof(typename _Tpvec::lane_type)) }; + v128_t z = wasm_i8x16_splat(0); + return _Tpvec(v_wasm_palignr_u8(a.val, z)); +} + +template +inline _Tpvec v_rotate_left(const _Tpvec &a) +{ + using namespace hal_wasm_internal; + enum { imm2 = ((_Tpvec::nlanes - imm) * sizeof(typename _Tpvec::lane_type)) }; + v128_t z = wasm_i8x16_splat(0); + return _Tpvec(v_wasm_palignr_u8(z, a.val)); +} + +template +inline _Tpvec v_rotate_right(const _Tpvec &a, const _Tpvec &b) +{ + using namespace hal_wasm_internal; + enum { imm2 = (imm * sizeof(typename _Tpvec::lane_type)) }; + return _Tpvec(v_wasm_palignr_u8(a.val, b.val)); +} + +template +inline _Tpvec v_rotate_left(const _Tpvec &a, const _Tpvec &b) +{ + using namespace hal_wasm_internal; + enum { imm2 = ((_Tpvec::nlanes - imm) * sizeof(typename _Tpvec::lane_type)) }; + return _Tpvec(v_wasm_palignr_u8(b.val, a.val)); +} + +#define OPENCV_HAL_IMPL_WASM_LOADSTORE_INT_OP(_Tpvec, _Tp) \ +inline _Tpvec v_load(const _Tp* ptr) \ +{ return _Tpvec(wasm_v128_load(ptr)); } \ +inline _Tpvec v_load_aligned(const _Tp* ptr) \ +{ return _Tpvec(wasm_v128_load(ptr)); } \ +inline _Tpvec v_load_low(const _Tp* ptr) \ +{ \ + _Tp tmp[_Tpvec::nlanes] = {0}; \ + for (int i=0; i<_Tpvec::nlanes/2; ++i) { \ + tmp[i] = ptr[i]; \ + } \ + return _Tpvec(wasm_v128_load(tmp)); \ +} \ +inline _Tpvec v_load_halves(const _Tp* ptr0, const _Tp* ptr1) \ +{ \ + _Tp tmp[_Tpvec::nlanes]; \ + for (int i=0; i<_Tpvec::nlanes/2; ++i) { \ + tmp[i] = ptr0[i]; \ + tmp[i+_Tpvec::nlanes/2] = ptr1[i]; \ + } \ + return _Tpvec(wasm_v128_load(tmp)); \ +} \ +inline void v_store(_Tp* ptr, const _Tpvec& a) \ +{ wasm_v128_store(ptr, a.val); } \ +inline void v_store_aligned(_Tp* ptr, const _Tpvec& a) \ +{ wasm_v128_store(ptr, a.val); } \ +inline void v_store_aligned_nocache(_Tp* ptr, const _Tpvec& a) \ +{ wasm_v128_store(ptr, a.val); } \ +inline void v_store(_Tp* ptr, const _Tpvec& a, hal::StoreMode /*mode*/) \ +{ \ + wasm_v128_store(ptr, a.val); \ +} \ +inline void v_store_low(_Tp* ptr, const _Tpvec& a) \ +{ \ + _Tpvec::lane_type a_[_Tpvec::nlanes]; \ + wasm_v128_store(a_, a.val); \ + for (int i = 0; i < (_Tpvec::nlanes / 2); i++) \ + ptr[i] = a_[i]; \ +} \ +inline void v_store_high(_Tp* ptr, const _Tpvec& a) \ +{ \ + _Tpvec::lane_type a_[_Tpvec::nlanes]; \ + wasm_v128_store(a_, a.val); \ + for (int i = 0; i < (_Tpvec::nlanes / 2); i++) \ + ptr[i] = a_[i + (_Tpvec::nlanes / 2)]; \ +} + +OPENCV_HAL_IMPL_WASM_LOADSTORE_INT_OP(v_uint8x16, uchar) +OPENCV_HAL_IMPL_WASM_LOADSTORE_INT_OP(v_int8x16, schar) +OPENCV_HAL_IMPL_WASM_LOADSTORE_INT_OP(v_uint16x8, ushort) +OPENCV_HAL_IMPL_WASM_LOADSTORE_INT_OP(v_int16x8, short) +OPENCV_HAL_IMPL_WASM_LOADSTORE_INT_OP(v_uint32x4, unsigned) +OPENCV_HAL_IMPL_WASM_LOADSTORE_INT_OP(v_int32x4, int) +OPENCV_HAL_IMPL_WASM_LOADSTORE_INT_OP(v_uint64x2, uint64) +OPENCV_HAL_IMPL_WASM_LOADSTORE_INT_OP(v_int64x2, int64) +OPENCV_HAL_IMPL_WASM_LOADSTORE_INT_OP(v_float32x4, float) +OPENCV_HAL_IMPL_WASM_LOADSTORE_INT_OP(v_float64x2, double) + + +/** Reverse **/ +inline v_uint8x16 v_reverse(const v_uint8x16 &a) +{ return v_uint8x16(wasm_v8x16_shuffle(a.val, a.val, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)); } + +inline v_int8x16 v_reverse(const v_int8x16 &a) +{ return v_reinterpret_as_s8(v_reverse(v_reinterpret_as_u8(a))); } + +inline v_uint16x8 v_reverse(const v_uint16x8 &a) +{ return v_uint16x8(wasm_v8x16_shuffle(a.val, a.val, 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1)); } + +inline v_int16x8 v_reverse(const v_int16x8 &a) +{ return v_reinterpret_as_s16(v_reverse(v_reinterpret_as_u16(a))); } + +inline v_uint32x4 v_reverse(const v_uint32x4 &a) +{ return v_uint32x4(wasm_v8x16_shuffle(a.val, a.val, 12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3)); } + +inline v_int32x4 v_reverse(const v_int32x4 &a) +{ return v_reinterpret_as_s32(v_reverse(v_reinterpret_as_u32(a))); } + +inline v_float32x4 v_reverse(const v_float32x4 &a) +{ return v_reinterpret_as_f32(v_reverse(v_reinterpret_as_u32(a))); } + +inline v_uint64x2 v_reverse(const v_uint64x2 &a) +{ return v_uint64x2(wasm_v8x16_shuffle(a.val, a.val, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7)); } + +inline v_int64x2 v_reverse(const v_int64x2 &a) +{ return v_reinterpret_as_s64(v_reverse(v_reinterpret_as_u64(a))); } + +inline v_float64x2 v_reverse(const v_float64x2 &a) +{ return v_reinterpret_as_f64(v_reverse(v_reinterpret_as_u64(a))); } + + +#define OPENCV_HAL_IMPL_WASM_REDUCE_OP_4_SUM(_Tpvec, scalartype, regtype, suffix, esuffix) \ +inline scalartype v_reduce_sum(const _Tpvec& a) \ +{ \ + regtype val = a.val; \ + val = wasm_##suffix##_add(val, wasm_v8x16_shuffle(val, val, 8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7)); \ + val = wasm_##suffix##_add(val, wasm_v8x16_shuffle(val, val, 4,5,6,7,8,9,10,11,12,13,14,15,0,1,2,3)); \ + return (scalartype)wasm_##esuffix##_extract_lane(val, 0); \ +} + +OPENCV_HAL_IMPL_WASM_REDUCE_OP_4_SUM(v_uint32x4, unsigned, v128_t, i32x4, i32x4) +OPENCV_HAL_IMPL_WASM_REDUCE_OP_4_SUM(v_int32x4, int, v128_t, i32x4, i32x4) +OPENCV_HAL_IMPL_WASM_REDUCE_OP_4_SUM(v_float32x4, float, v128_t, f32x4, f32x4) + +// To do: Optimize v_reduce_sum with wasm intrin. +// Now use fallback implementation as there is no widening op in wasm intrin. + +#define OPENCV_HAL_IMPL_FALLBACK_REDUCE_OP_SUM(_Tpvec, scalartype) \ +inline scalartype v_reduce_sum(const _Tpvec& a) \ +{ \ + _Tpvec::lane_type a_[_Tpvec::nlanes]; \ + wasm_v128_store(a_, a.val); \ + scalartype c = a_[0]; \ + for (int i = 1; i < _Tpvec::nlanes; i++) \ + c += a_[i]; \ + return c; \ +} + +OPENCV_HAL_IMPL_FALLBACK_REDUCE_OP_SUM(v_uint8x16, unsigned) +OPENCV_HAL_IMPL_FALLBACK_REDUCE_OP_SUM(v_int8x16, int) +OPENCV_HAL_IMPL_FALLBACK_REDUCE_OP_SUM(v_uint16x8, unsigned) +OPENCV_HAL_IMPL_FALLBACK_REDUCE_OP_SUM(v_int16x8, int) + + +#define OPENCV_HAL_IMPL_WASM_REDUCE_OP_2_SUM(_Tpvec, scalartype, regtype, suffix, esuffix) \ +inline scalartype v_reduce_sum(const _Tpvec& a) \ +{ \ + regtype val = a.val; \ + val = wasm_##suffix##_add(val, wasm_v8x16_shuffle(val, val, 8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7)); \ + return (scalartype)wasm_##esuffix##_extract_lane(val, 0); \ +} +OPENCV_HAL_IMPL_WASM_REDUCE_OP_2_SUM(v_uint64x2, uint64, v128_t, i64x2, i64x2) +OPENCV_HAL_IMPL_WASM_REDUCE_OP_2_SUM(v_int64x2, int64, v128_t, i64x2, i64x2) +OPENCV_HAL_IMPL_WASM_REDUCE_OP_2_SUM(v_float64x2, double, v128_t, f64x2,f64x2) + +inline v_float32x4 v_reduce_sum4(const v_float32x4& a, const v_float32x4& b, + const v_float32x4& c, const v_float32x4& d) +{ + v128_t ac = wasm_f32x4_add(wasm_unpacklo_i32x4(a.val, c.val), wasm_unpackhi_i32x4(a.val, c.val)); + v128_t bd = wasm_f32x4_add(wasm_unpacklo_i32x4(b.val, d.val), wasm_unpackhi_i32x4(b.val, d.val)); + return v_float32x4(wasm_f32x4_add(wasm_unpacklo_i32x4(ac, bd), wasm_unpackhi_i32x4(ac, bd))); +} + +#define OPENCV_HAL_IMPL_WASM_REDUCE_OP(_Tpvec, scalartype, func, scalar_func) \ +inline scalartype v_reduce_##func(const _Tpvec& a) \ +{ \ + scalartype buf[_Tpvec::nlanes]; \ + v_store(buf, a); \ + scalartype tmp = buf[0]; \ + for (int i=1; i<_Tpvec::nlanes; ++i) { \ + tmp = scalar_func(tmp, buf[i]); \ + } \ + return tmp; \ +} + +OPENCV_HAL_IMPL_WASM_REDUCE_OP(v_uint8x16, uchar, max, std::max) +OPENCV_HAL_IMPL_WASM_REDUCE_OP(v_uint8x16, uchar, min, std::min) +OPENCV_HAL_IMPL_WASM_REDUCE_OP(v_int8x16, schar, max, std::max) +OPENCV_HAL_IMPL_WASM_REDUCE_OP(v_int8x16, schar, min, std::min) +OPENCV_HAL_IMPL_WASM_REDUCE_OP(v_uint16x8, ushort, max, std::max) +OPENCV_HAL_IMPL_WASM_REDUCE_OP(v_uint16x8, ushort, min, std::min) +OPENCV_HAL_IMPL_WASM_REDUCE_OP(v_int16x8, short, max, std::max) +OPENCV_HAL_IMPL_WASM_REDUCE_OP(v_int16x8, short, min, std::min) +OPENCV_HAL_IMPL_WASM_REDUCE_OP(v_uint32x4, unsigned, max, std::max) +OPENCV_HAL_IMPL_WASM_REDUCE_OP(v_uint32x4, unsigned, min, std::min) +OPENCV_HAL_IMPL_WASM_REDUCE_OP(v_int32x4, int, max, std::max) +OPENCV_HAL_IMPL_WASM_REDUCE_OP(v_int32x4, int, min, std::min) +OPENCV_HAL_IMPL_WASM_REDUCE_OP(v_float32x4, float, max, std::max) +OPENCV_HAL_IMPL_WASM_REDUCE_OP(v_float32x4, float, min, std::min) + +inline unsigned v_reduce_sad(const v_uint8x16& a, const v_uint8x16& b) +{ + v_uint16x8 l16, h16; + v_uint32x4 l16_l32, l16_h32, h16_l32, h16_h32; + v_expand(v_absdiff(a, b), l16, h16); + v_expand(l16, l16_l32, l16_h32); + v_expand(h16, h16_l32, h16_h32); + return v_reduce_sum(l16_l32+l16_h32+h16_l32+h16_h32); +} +inline unsigned v_reduce_sad(const v_int8x16& a, const v_int8x16& b) +{ + v_uint16x8 l16, h16; + v_uint32x4 l16_l32, l16_h32, h16_l32, h16_h32; + v_expand(v_absdiff(a, b), l16, h16); + v_expand(l16, l16_l32, l16_h32); + v_expand(h16, h16_l32, h16_h32); + return v_reduce_sum(l16_l32+l16_h32+h16_l32+h16_h32); +} +inline unsigned v_reduce_sad(const v_uint16x8& a, const v_uint16x8& b) +{ + v_uint32x4 l, h; + v_expand(v_absdiff(a, b), l, h); + return v_reduce_sum(l + h); +} +inline unsigned v_reduce_sad(const v_int16x8& a, const v_int16x8& b) +{ + v_uint32x4 l, h; + v_expand(v_absdiff(a, b), l, h); + return v_reduce_sum(l + h); +} +inline unsigned v_reduce_sad(const v_uint32x4& a, const v_uint32x4& b) +{ + return v_reduce_sum(v_absdiff(a, b)); +} +inline unsigned v_reduce_sad(const v_int32x4& a, const v_int32x4& b) +{ + return v_reduce_sum(v_absdiff(a, b)); +} +inline float v_reduce_sad(const v_float32x4& a, const v_float32x4& b) +{ + return v_reduce_sum(v_absdiff(a, b)); +} + +inline v_uint8x16 v_popcount(const v_uint8x16& a) +{ + v128_t m1 = wasm_i32x4_splat(0x55555555); + v128_t m2 = wasm_i32x4_splat(0x33333333); + v128_t m4 = wasm_i32x4_splat(0x0f0f0f0f); + v128_t p = a.val; + p = wasm_i32x4_add(wasm_v128_and(wasm_u32x4_shr(p, 1), m1), wasm_v128_and(p, m1)); + p = wasm_i32x4_add(wasm_v128_and(wasm_u32x4_shr(p, 2), m2), wasm_v128_and(p, m2)); + p = wasm_i32x4_add(wasm_v128_and(wasm_u32x4_shr(p, 4), m4), wasm_v128_and(p, m4)); + return v_uint8x16(p); +} +inline v_uint16x8 v_popcount(const v_uint16x8& a) +{ + v_uint8x16 p = v_popcount(v_reinterpret_as_u8(a)); + p += v_rotate_right<1>(p); + return v_reinterpret_as_u16(p) & v_setall_u16(0x00ff); +} +inline v_uint32x4 v_popcount(const v_uint32x4& a) +{ + v_uint8x16 p = v_popcount(v_reinterpret_as_u8(a)); + p += v_rotate_right<1>(p); + p += v_rotate_right<2>(p); + return v_reinterpret_as_u32(p) & v_setall_u32(0x000000ff); +} +inline v_uint64x2 v_popcount(const v_uint64x2& a) +{ + uint64 a_[2], b_[2] = { 0 }; + wasm_v128_store(a_, a.val); + for (int i = 0; i < 16; i++) + b_[i / 8] += popCountTable[((uint8_t*)a_)[i]]; + return v_uint64x2(wasm_v128_load(b_)); +} +inline v_uint8x16 v_popcount(const v_int8x16& a) +{ return v_popcount(v_reinterpret_as_u8(a)); } +inline v_uint16x8 v_popcount(const v_int16x8& a) +{ return v_popcount(v_reinterpret_as_u16(a)); } +inline v_uint32x4 v_popcount(const v_int32x4& a) +{ return v_popcount(v_reinterpret_as_u32(a)); } +inline v_uint64x2 v_popcount(const v_int64x2& a) +{ return v_popcount(v_reinterpret_as_u64(a)); } + +#define OPENCV_HAL_IMPL_WASM_CHECK_SIGNS(_Tpvec, suffix, scalarType) \ +inline int v_signmask(const _Tpvec& a) \ +{ \ + _Tpvec::lane_type a_[_Tpvec::nlanes]; \ + wasm_v128_store(a_, a.val); \ + int mask = 0; \ + for (int i = 0; i < _Tpvec::nlanes; i++) \ + mask |= (reinterpret_int(a_[i]) < 0) << i; \ + return mask; \ +} \ +inline bool v_check_all(const _Tpvec& a) \ +{ return wasm_i8x16_all_true(wasm_##suffix##_lt(a.val, wasm_##suffix##_splat(0))); } \ +inline bool v_check_any(const _Tpvec& a) \ +{ return wasm_i8x16_any_true(wasm_##suffix##_lt(a.val, wasm_##suffix##_splat(0)));; } + +OPENCV_HAL_IMPL_WASM_CHECK_SIGNS(v_uint8x16, i8x16, schar) +OPENCV_HAL_IMPL_WASM_CHECK_SIGNS(v_int8x16, i8x16, schar) +OPENCV_HAL_IMPL_WASM_CHECK_SIGNS(v_uint16x8, i16x8, short) +OPENCV_HAL_IMPL_WASM_CHECK_SIGNS(v_int16x8, i16x8, short) +OPENCV_HAL_IMPL_WASM_CHECK_SIGNS(v_uint32x4, i32x4, int) +OPENCV_HAL_IMPL_WASM_CHECK_SIGNS(v_int32x4, i32x4, int) +OPENCV_HAL_IMPL_WASM_CHECK_SIGNS(v_float32x4, i32x4, float) +OPENCV_HAL_IMPL_WASM_CHECK_SIGNS(v_float64x2, f64x2, double) + +#define OPENCV_HAL_IMPL_WASM_CHECK_ALL_ANY(_Tpvec, suffix, esuffix) \ +inline bool v_check_all(const _Tpvec& a) \ +{ \ + v128_t masked = v_reinterpret_as_##esuffix(a).val; \ + masked = wasm_i32x4_replace_lane(masked, 0, 0xffffffff); \ + masked = wasm_i32x4_replace_lane(masked, 2, 0xffffffff); \ + return wasm_i8x16_all_true(wasm_##suffix##_lt(masked, wasm_##suffix##_splat(0))); \ +} \ +inline bool v_check_any(const _Tpvec& a) \ +{ \ + v128_t masked = v_reinterpret_as_##esuffix(a).val; \ + masked = wasm_i32x4_replace_lane(masked, 0, 0x0); \ + masked = wasm_i32x4_replace_lane(masked, 2, 0x0); \ + return wasm_i8x16_any_true(wasm_##suffix##_lt(masked, wasm_##suffix##_splat(0))); \ +} \ + +OPENCV_HAL_IMPL_WASM_CHECK_ALL_ANY(v_int64x2, i32x4, s32) +OPENCV_HAL_IMPL_WASM_CHECK_ALL_ANY(v_uint64x2, i32x4, u32) + + +inline int v_scan_forward(const v_int8x16& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))); } +inline int v_scan_forward(const v_uint8x16& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))); } +inline int v_scan_forward(const v_int16x8& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 2; } +inline int v_scan_forward(const v_uint16x8& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 2; } +inline int v_scan_forward(const v_int32x4& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 4; } +inline int v_scan_forward(const v_uint32x4& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 4; } +inline int v_scan_forward(const v_float32x4& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 4; } +inline int v_scan_forward(const v_int64x2& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 8; } +inline int v_scan_forward(const v_uint64x2& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 8; } +inline int v_scan_forward(const v_float64x2& a) { return trailingZeros32(v_signmask(v_reinterpret_as_s8(a))) / 8; } + +#define OPENCV_HAL_IMPL_WASM_SELECT(_Tpvec) \ +inline _Tpvec v_select(const _Tpvec& mask, const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(wasm_v128_bitselect(a.val, b.val, mask.val)); \ +} + +OPENCV_HAL_IMPL_WASM_SELECT(v_uint8x16) +OPENCV_HAL_IMPL_WASM_SELECT(v_int8x16) +OPENCV_HAL_IMPL_WASM_SELECT(v_uint16x8) +OPENCV_HAL_IMPL_WASM_SELECT(v_int16x8) +OPENCV_HAL_IMPL_WASM_SELECT(v_uint32x4) +OPENCV_HAL_IMPL_WASM_SELECT(v_int32x4) +OPENCV_HAL_IMPL_WASM_SELECT(v_uint64x2) +OPENCV_HAL_IMPL_WASM_SELECT(v_int64x2) +OPENCV_HAL_IMPL_WASM_SELECT(v_float32x4) +OPENCV_HAL_IMPL_WASM_SELECT(v_float64x2) + +#define OPENCV_HAL_IMPL_WASM_EXPAND(_Tpvec, _Tpwvec, _Tp, intrin) \ +inline void v_expand(const _Tpvec& a, _Tpwvec& b0, _Tpwvec& b1) \ +{ \ + b0.val = intrin(a.val); \ + b1.val = __CV_CAT(intrin, _high)(a.val); \ +} \ +inline _Tpwvec v_expand_low(const _Tpvec& a) \ +{ return _Tpwvec(intrin(a.val)); } \ +inline _Tpwvec v_expand_high(const _Tpvec& a) \ +{ return _Tpwvec(__CV_CAT(intrin, _high)(a.val)); } \ +inline _Tpwvec v_load_expand(const _Tp* ptr) \ +{ \ + v128_t a = wasm_v128_load(ptr); \ + return _Tpwvec(intrin(a)); \ +} + +OPENCV_HAL_IMPL_WASM_EXPAND(v_uint8x16, v_uint16x8, uchar, v128_cvtu8x16_i16x8) +OPENCV_HAL_IMPL_WASM_EXPAND(v_int8x16, v_int16x8, schar, v128_cvti8x16_i16x8) +OPENCV_HAL_IMPL_WASM_EXPAND(v_uint16x8, v_uint32x4, ushort, v128_cvtu16x8_i32x4) +OPENCV_HAL_IMPL_WASM_EXPAND(v_int16x8, v_int32x4, short, v128_cvti16x8_i32x4) +OPENCV_HAL_IMPL_WASM_EXPAND(v_uint32x4, v_uint64x2, unsigned, v128_cvtu32x4_i64x2) +OPENCV_HAL_IMPL_WASM_EXPAND(v_int32x4, v_int64x2, int, v128_cvti32x4_i64x2) + +#define OPENCV_HAL_IMPL_WASM_EXPAND_Q(_Tpvec, _Tp, intrin) \ +inline _Tpvec v_load_expand_q(const _Tp* ptr) \ +{ \ + v128_t a = wasm_v128_load(ptr); \ + return _Tpvec(intrin(a)); \ +} + +OPENCV_HAL_IMPL_WASM_EXPAND_Q(v_uint32x4, uchar, v128_cvtu8x16_i32x4) +OPENCV_HAL_IMPL_WASM_EXPAND_Q(v_int32x4, schar, v128_cvti8x16_i32x4) + +#define OPENCV_HAL_IMPL_WASM_UNPACKS(_Tpvec, suffix) \ +inline void v_zip(const _Tpvec& a0, const _Tpvec& a1, _Tpvec& b0, _Tpvec& b1) \ +{ \ + b0.val = wasm_unpacklo_##suffix(a0.val, a1.val); \ + b1.val = wasm_unpackhi_##suffix(a0.val, a1.val); \ +} \ +inline _Tpvec v_combine_low(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(wasm_unpacklo_i64x2(a.val, b.val)); \ +} \ +inline _Tpvec v_combine_high(const _Tpvec& a, const _Tpvec& b) \ +{ \ + return _Tpvec(wasm_unpackhi_i64x2(a.val, b.val)); \ +} \ +inline void v_recombine(const _Tpvec& a, const _Tpvec& b, _Tpvec& c, _Tpvec& d) \ +{ \ + c.val = wasm_unpacklo_i64x2(a.val, b.val); \ + d.val = wasm_unpackhi_i64x2(a.val, b.val); \ +} + +OPENCV_HAL_IMPL_WASM_UNPACKS(v_uint8x16, i8x16) +OPENCV_HAL_IMPL_WASM_UNPACKS(v_int8x16, i8x16) +OPENCV_HAL_IMPL_WASM_UNPACKS(v_uint16x8, i16x8) +OPENCV_HAL_IMPL_WASM_UNPACKS(v_int16x8, i16x8) +OPENCV_HAL_IMPL_WASM_UNPACKS(v_uint32x4, i32x4) +OPENCV_HAL_IMPL_WASM_UNPACKS(v_int32x4, i32x4) +OPENCV_HAL_IMPL_WASM_UNPACKS(v_float32x4, i32x4) +OPENCV_HAL_IMPL_WASM_UNPACKS(v_float64x2, i64x2) + +template +inline _Tpvec v_extract(const _Tpvec& a, const _Tpvec& b) +{ + return v_rotate_right(a, b); +} + +inline v_int32x4 v_round(const v_float32x4& a) +{ + v128_t h = wasm_f32x4_splat(0.5); + return v_int32x4(wasm_i32x4_trunc_saturate_f32x4(wasm_f32x4_add(a.val, h))); +} + +inline v_int32x4 v_floor(const v_float32x4& a) +{ + v128_t a1 = wasm_i32x4_trunc_saturate_f32x4(a.val); + v128_t mask = wasm_f32x4_lt(a.val, wasm_f32x4_convert_i32x4(a1)); + return v_int32x4(wasm_i32x4_add(a1, mask)); +} + +inline v_int32x4 v_ceil(const v_float32x4& a) +{ + v128_t a1 = wasm_i32x4_trunc_saturate_f32x4(a.val); + v128_t mask = wasm_f32x4_gt(a.val, wasm_f32x4_convert_i32x4(a1)); + return v_int32x4(wasm_i32x4_sub(a1, mask)); +} + +inline v_int32x4 v_trunc(const v_float32x4& a) +{ return v_int32x4(wasm_i32x4_trunc_saturate_f32x4(a.val)); } + +#define OPENCV_HAL_IMPL_WASM_MATH_FUNC(func, cfunc) \ +inline v_int32x4 func(const v_float64x2& a) \ +{ \ + double a_[2]; \ + wasm_v128_store(a_, a.val); \ + int c_[4]; \ + c_[0] = cfunc(a_[0]); \ + c_[1] = cfunc(a_[1]); \ + c_[2] = 0; \ + c_[3] = 0; \ + return v_int32x4(wasm_v128_load(c_)); \ +} + +OPENCV_HAL_IMPL_WASM_MATH_FUNC(v_round, cvRound) +OPENCV_HAL_IMPL_WASM_MATH_FUNC(v_floor, cvFloor) +OPENCV_HAL_IMPL_WASM_MATH_FUNC(v_ceil, cvCeil) +OPENCV_HAL_IMPL_WASM_MATH_FUNC(v_trunc, int) + +inline v_int32x4 v_round(const v_float64x2& a, const v_float64x2& b) +{ + double a_[2], b_[2]; + wasm_v128_store(a_, a.val); + wasm_v128_store(b_, b.val); + int c_[4]; + c_[0] = cvRound(a_[0]); + c_[1] = cvRound(a_[1]); + c_[2] = cvRound(b_[0]); + c_[3] = cvRound(b_[1]); + return v_int32x4(wasm_v128_load(c_)); +} + +#define OPENCV_HAL_IMPL_WASM_TRANSPOSE4x4(_Tpvec, suffix) \ +inline void v_transpose4x4(const _Tpvec& a0, const _Tpvec& a1, \ + const _Tpvec& a2, const _Tpvec& a3, \ + _Tpvec& b0, _Tpvec& b1, \ + _Tpvec& b2, _Tpvec& b3) \ +{ \ + v128_t t0 = wasm_unpacklo_##suffix(a0.val, a1.val); \ + v128_t t1 = wasm_unpacklo_##suffix(a2.val, a3.val); \ + v128_t t2 = wasm_unpackhi_##suffix(a0.val, a1.val); \ + v128_t t3 = wasm_unpackhi_##suffix(a2.val, a3.val); \ +\ + b0.val = wasm_unpacklo_i64x2(t0, t1); \ + b1.val = wasm_unpackhi_i64x2(t0, t1); \ + b2.val = wasm_unpacklo_i64x2(t2, t3); \ + b3.val = wasm_unpackhi_i64x2(t2, t3); \ +} + +OPENCV_HAL_IMPL_WASM_TRANSPOSE4x4(v_uint32x4, i32x4) +OPENCV_HAL_IMPL_WASM_TRANSPOSE4x4(v_int32x4, i32x4) +OPENCV_HAL_IMPL_WASM_TRANSPOSE4x4(v_float32x4, i32x4) + +// load deinterleave +inline void v_load_deinterleave(const uchar* ptr, v_uint8x16& a, v_uint8x16& b) +{ + v128_t t00 = wasm_v128_load(ptr); + v128_t t01 = wasm_v128_load(ptr + 16); + + a.val = wasm_v8x16_shuffle(t00, t01, 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30); + b.val = wasm_v8x16_shuffle(t00, t01, 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31); +} + +inline void v_load_deinterleave(const uchar* ptr, v_uint8x16& a, v_uint8x16& b, v_uint8x16& c) +{ + v128_t t00 = wasm_v128_load(ptr); + v128_t t01 = wasm_v128_load(ptr + 16); + v128_t t02 = wasm_v128_load(ptr + 32); + + v128_t t10 = wasm_v8x16_shuffle(t00, t01, 0,3,6,9,12,15,18,21,24,27,30,1,2,4,5,7); + v128_t t11 = wasm_v8x16_shuffle(t00, t01, 1,4,7,10,13,16,19,22,25,28,31,0,2,3,5,6); + v128_t t12 = wasm_v8x16_shuffle(t00, t01, 2,5,8,11,14,17,20,23,26,29,0,1,3,4,6,7); + + a.val = wasm_v8x16_shuffle(t10, t02, 0,1,2,3,4,5,6,7,8,9,10,17,20,23,26,29); + b.val = wasm_v8x16_shuffle(t11, t02, 0,1,2,3,4,5,6,7,8,9,10,18,21,24,27,30); + c.val = wasm_v8x16_shuffle(t12, t02, 0,1,2,3,4,5,6,7,8,9,16,19,22,25,28,31); +} + +inline void v_load_deinterleave(const uchar* ptr, v_uint8x16& a, v_uint8x16& b, v_uint8x16& c, v_uint8x16& d) +{ + v128_t u0 = wasm_v128_load(ptr); // a0 b0 c0 d0 a1 b1 c1 d1 ... + v128_t u1 = wasm_v128_load(ptr + 16); // a4 b4 c4 d4 ... + v128_t u2 = wasm_v128_load(ptr + 32); // a8 b8 c8 d8 ... + v128_t u3 = wasm_v128_load(ptr + 48); // a12 b12 c12 d12 ... + + v128_t v0 = wasm_v8x16_shuffle(u0, u1, 0,4,8,12,16,20,24,28,1,5,9,13,17,21,25,29); + v128_t v1 = wasm_v8x16_shuffle(u2, u3, 0,4,8,12,16,20,24,28,1,5,9,13,17,21,25,29); + v128_t v2 = wasm_v8x16_shuffle(u0, u1, 2,6,10,14,18,22,26,30,3,7,11,15,19,23,27,31); + v128_t v3 = wasm_v8x16_shuffle(u2, u3, 2,6,10,14,18,22,26,30,3,7,11,15,19,23,27,31); + + a.val = wasm_v8x16_shuffle(v0, v1, 0,1,2,3,4,5,6,7,16,17,18,19,20,21,22,23); + b.val = wasm_v8x16_shuffle(v0, v1, 8,9,10,11,12,13,14,15,24,25,26,27,28,29,30,31); + c.val = wasm_v8x16_shuffle(v2, v3, 0,1,2,3,4,5,6,7,16,17,18,19,20,21,22,23); + d.val = wasm_v8x16_shuffle(v2, v3, 8,9,10,11,12,13,14,15,24,25,26,27,28,29,30,31); +} + +inline void v_load_deinterleave(const ushort* ptr, v_uint16x8& a, v_uint16x8& b) +{ + v128_t v0 = wasm_v128_load(ptr); // a0 b0 a1 b1 a2 b2 a3 b3 + v128_t v1 = wasm_v128_load(ptr + 8); // a4 b4 a5 b5 a6 b6 a7 b7 + + a.val = wasm_v8x16_shuffle(v0, v1, 0,1,4,5,8,9,12,13,16,17,20,21,24,25,28,29); // a0 a1 a2 a3 a4 a5 a6 a7 + b.val = wasm_v8x16_shuffle(v0, v1, 2,3,6,7,10,11,14,15,18,19,22,23,26,27,30,31); // b0 b1 ab b3 b4 b5 b6 b7 +} + +inline void v_load_deinterleave(const ushort* ptr, v_uint16x8& a, v_uint16x8& b, v_uint16x8& c) +{ + v128_t t00 = wasm_v128_load(ptr); // a0 b0 c0 a1 b1 c1 a2 b2 + v128_t t01 = wasm_v128_load(ptr + 8); // c2 a3 b3 c3 a4 b4 c4 a5 + v128_t t02 = wasm_v128_load(ptr + 16); // b5 c5 a6 b6 c6 a7 b7 c7 + + v128_t t10 = wasm_v8x16_shuffle(t00, t01, 0,1,6,7,12,13,18,19,24,25,30,31,2,3,4,5); + v128_t t11 = wasm_v8x16_shuffle(t00, t01, 2,3,8,9,14,15,20,21,26,27,0,1,4,5,6,7); + v128_t t12 = wasm_v8x16_shuffle(t00, t01, 4,5,10,11,16,17,22,23,28,29,0,1,2,3,6,7); + + a.val = wasm_v8x16_shuffle(t10, t02, 0,1,2,3,4,5,6,7,8,9,10,11,20,21,26,27); + b.val = wasm_v8x16_shuffle(t11, t02, 0,1,2,3,4,5,6,7,8,9,16,17,22,23,28,29); + c.val = wasm_v8x16_shuffle(t12, t02, 0,1,2,3,4,5,6,7,8,9,18,19,24,25,30,31); +} + +inline void v_load_deinterleave(const ushort* ptr, v_uint16x8& a, v_uint16x8& b, v_uint16x8& c, v_uint16x8& d) +{ + v128_t u0 = wasm_v128_load(ptr); // a0 b0 c0 d0 a1 b1 c1 d1 + v128_t u1 = wasm_v128_load(ptr + 8); // a2 b2 c2 d2 ... + v128_t u2 = wasm_v128_load(ptr + 16); // a4 b4 c4 d4 ... + v128_t u3 = wasm_v128_load(ptr + 24); // a6 b6 c6 d6 ... + + v128_t v0 = wasm_v8x16_shuffle(u0, u1, 0,1,8,9,16,17,24,25,2,3,10,11,18,19,26,27); // a0 a1 a2 a3 b0 b1 b2 b3 + v128_t v1 = wasm_v8x16_shuffle(u2, u3, 0,1,8,9,16,17,24,25,2,3,10,11,18,19,26,27); // a4 a5 a6 a7 b4 b5 b6 b7 + v128_t v2 = wasm_v8x16_shuffle(u0, u1, 4,5,12,13,20,21,28,29,6,7,14,15,22,23,30,31); // c0 c1 c2 c3 d0 d1 d2 d3 + v128_t v3 = wasm_v8x16_shuffle(u2, u3, 4,5,12,13,20,21,28,29,6,7,14,15,22,23,30,31); // c4 c5 c6 c7 d4 d5 d6 d7 + + a.val = wasm_v8x16_shuffle(v0, v1, 0,1,2,3,4,5,6,7,16,17,18,19,20,21,22,23); + b.val = wasm_v8x16_shuffle(v0, v1, 8,9,10,11,12,13,14,15,24,25,26,27,28,29,30,31); + c.val = wasm_v8x16_shuffle(v2, v3, 0,1,2,3,4,5,6,7,16,17,18,19,20,21,22,23); + d.val = wasm_v8x16_shuffle(v2, v3, 8,9,10,11,12,13,14,15,24,25,26,27,28,29,30,31); +} + +inline void v_load_deinterleave(const unsigned* ptr, v_uint32x4& a, v_uint32x4& b) +{ + v128_t v0 = wasm_v128_load(ptr); // a0 b0 a1 b1 + v128_t v1 = wasm_v128_load(ptr + 4); // a2 b2 a3 b3 + + a.val = wasm_v8x16_shuffle(v0, v1, 0,1,2,3,8,9,10,11,16,17,18,19,24,25,26,27); // a0 a1 a2 a3 + b.val = wasm_v8x16_shuffle(v0, v1, 4,5,6,7,12,13,14,15,20,21,22,23,28,29,30,31); // b0 b1 b2 b3 +} + +inline void v_load_deinterleave(const unsigned* ptr, v_uint32x4& a, v_uint32x4& b, v_uint32x4& c) +{ + v128_t t00 = wasm_v128_load(ptr); // a0 b0 c0 a1 + v128_t t01 = wasm_v128_load(ptr + 4); // b2 c2 a3 b3 + v128_t t02 = wasm_v128_load(ptr + 8); // c3 a4 b4 c4 + + v128_t t10 = wasm_v8x16_shuffle(t00, t01, 0,1,2,3,12,13,14,15,24,25,26,27,4,5,6,7); + v128_t t11 = wasm_v8x16_shuffle(t00, t01, 4,5,6,7,16,17,18,19,28,29,30,31,0,1,2,3); + v128_t t12 = wasm_v8x16_shuffle(t00, t01, 8,9,10,11,20,21,22,23,0,1,2,3,4,5,6,7); + + a.val = wasm_v8x16_shuffle(t10, t02, 0,1,2,3,4,5,6,7,8,9,10,11,20,21,22,23); + b.val = wasm_v8x16_shuffle(t11, t02, 0,1,2,3,4,5,6,7,8,9,10,11,24,25,26,27); + c.val = wasm_v8x16_shuffle(t12, t02, 0,1,2,3,4,5,6,7,16,17,18,19,28,29,30,31); +} + +inline void v_load_deinterleave(const unsigned* ptr, v_uint32x4& a, v_uint32x4& b, v_uint32x4& c, v_uint32x4& d) +{ + v_uint32x4 s0(wasm_v128_load(ptr)); // a0 b0 c0 d0 + v_uint32x4 s1(wasm_v128_load(ptr + 4)); // a1 b1 c1 d1 + v_uint32x4 s2(wasm_v128_load(ptr + 8)); // a2 b2 c2 d2 + v_uint32x4 s3(wasm_v128_load(ptr + 12)); // a3 b3 c3 d3 + + v_transpose4x4(s0, s1, s2, s3, a, b, c, d); +} + +inline void v_load_deinterleave(const float* ptr, v_float32x4& a, v_float32x4& b) +{ + v128_t v0 = wasm_v128_load(ptr); // a0 b0 a1 b1 + v128_t v1 = wasm_v128_load((ptr + 4)); // a2 b2 a3 b3 + + a.val = wasm_v8x16_shuffle(v0, v1, 0,1,2,3,8,9,10,11,16,17,18,19,24,25,26,27); // a0 a1 a2 a3 + b.val = wasm_v8x16_shuffle(v0, v1, 4,5,6,7,12,13,14,15,20,21,22,23,28,29,30,31); // b0 b1 b2 b3 +} + +inline void v_load_deinterleave(const float* ptr, v_float32x4& a, v_float32x4& b, v_float32x4& c) +{ + v128_t t00 = wasm_v128_load(ptr); // a0 b0 c0 a1 + v128_t t01 = wasm_v128_load(ptr + 4); // b2 c2 a3 b3 + v128_t t02 = wasm_v128_load(ptr + 8); // c3 a4 b4 c4 + + v128_t t10 = wasm_v8x16_shuffle(t00, t01, 0,1,2,3,12,13,14,15,24,25,26,27,4,5,6,7); + v128_t t11 = wasm_v8x16_shuffle(t00, t01, 4,5,6,7,16,17,18,19,28,29,30,31,0,1,2,3); + v128_t t12 = wasm_v8x16_shuffle(t00, t01, 8,9,10,11,20,21,22,23,0,1,2,3,4,5,6,7); + + a.val = wasm_v8x16_shuffle(t10, t02, 0,1,2,3,4,5,6,7,8,9,10,11,20,21,22,23); + b.val = wasm_v8x16_shuffle(t11, t02, 0,1,2,3,4,5,6,7,8,9,10,11,24,25,26,27); + c.val = wasm_v8x16_shuffle(t12, t02, 0,1,2,3,4,5,6,7,16,17,18,19,28,29,30,31); +} + +inline void v_load_deinterleave(const float* ptr, v_float32x4& a, v_float32x4& b, v_float32x4& c, v_float32x4& d) +{ + v_float32x4 s0(wasm_v128_load(ptr)); // a0 b0 c0 d0 + v_float32x4 s1(wasm_v128_load(ptr + 4)); // a1 b1 c1 d1 + v_float32x4 s2(wasm_v128_load(ptr + 8)); // a2 b2 c2 d2 + v_float32x4 s3(wasm_v128_load(ptr + 12)); // a3 b3 c3 d3 + + v_transpose4x4(s0, s1, s2, s3, a, b, c, d); +} + +inline void v_load_deinterleave(const uint64 *ptr, v_uint64x2& a, v_uint64x2& b) +{ + v128_t t0 = wasm_v128_load(ptr); // a0 b0 + v128_t t1 = wasm_v128_load(ptr + 2); // a1 b1 + + a.val = wasm_unpacklo_i64x2(t0, t1); + b.val = wasm_unpackhi_i64x2(t0, t1); +} + +inline void v_load_deinterleave(const uint64 *ptr, v_uint64x2& a, v_uint64x2& b, v_uint64x2& c) +{ + v128_t t0 = wasm_v128_load(ptr); // a0, b0 + v128_t t1 = wasm_v128_load(ptr + 2); // c0, a1 + v128_t t2 = wasm_v128_load(ptr + 4); // b1, c1 + + a.val = wasm_v8x16_shuffle(t0, t1, 0,1,2,3,4,5,6,7,24,25,26,27,28,29,30,31); + b.val = wasm_v8x16_shuffle(t0, t2, 8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23); + c.val = wasm_v8x16_shuffle(t1, t2, 0,1,2,3,4,5,6,7,24,25,26,27,28,29,30,31); +} + +inline void v_load_deinterleave(const uint64 *ptr, v_uint64x2& a, + v_uint64x2& b, v_uint64x2& c, v_uint64x2& d) +{ + v128_t t0 = wasm_v128_load(ptr); // a0 b0 + v128_t t1 = wasm_v128_load(ptr + 2); // c0 d0 + v128_t t2 = wasm_v128_load(ptr + 4); // a1 b1 + v128_t t3 = wasm_v128_load(ptr + 6); // c1 d1 + + a.val = wasm_unpacklo_i64x2(t0, t2); + b.val = wasm_unpackhi_i64x2(t0, t2); + c.val = wasm_unpacklo_i64x2(t1, t3); + d.val = wasm_unpackhi_i64x2(t1, t3); +} + +// store interleave + +inline void v_store_interleave( uchar* ptr, const v_uint8x16& a, const v_uint8x16& b, + hal::StoreMode /*mode*/ = hal::STORE_UNALIGNED) +{ + v128_t v0 = wasm_unpacklo_i8x16(a.val, b.val); + v128_t v1 = wasm_unpackhi_i8x16(a.val, b.val); + + wasm_v128_store(ptr, v0); + wasm_v128_store(ptr + 16, v1); +} + +inline void v_store_interleave( uchar* ptr, const v_uint8x16& a, const v_uint8x16& b, + const v_uint8x16& c, hal::StoreMode /*mode*/ = hal::STORE_UNALIGNED) +{ + v128_t t00 = wasm_v8x16_shuffle(a.val, b.val, 0,16,0,1,17,0,2,18,0,3,19,0,4,20,0,5); + v128_t t01 = wasm_v8x16_shuffle(a.val, b.val, 21,0,6,22,0,7,23,0,8,24,0,9,25,0,10,26); + v128_t t02 = wasm_v8x16_shuffle(a.val, b.val, 0,11,27,0,12,28,0,13,29,0,14,30,0,15,31,0); + + v128_t t10 = wasm_v8x16_shuffle(t00, c.val, 0,1,16,3,4,17,6,7,18,9,10,19,12,13,20,15); + v128_t t11 = wasm_v8x16_shuffle(t01, c.val, 0,21,2,3,22,5,6,23,8,9,24,11,12,25,14,15); + v128_t t12 = wasm_v8x16_shuffle(t02, c.val, 26,1,2,27,4,5,28,7,8,29,10,11,30,13,14,31); + + wasm_v128_store(ptr, t10); + wasm_v128_store(ptr + 16, t11); + wasm_v128_store(ptr + 32, t12); +} + +inline void v_store_interleave( uchar* ptr, const v_uint8x16& a, const v_uint8x16& b, + const v_uint8x16& c, const v_uint8x16& d, + hal::StoreMode /*mode*/ = hal::STORE_UNALIGNED) +{ + // a0 a1 a2 a3 .... + // b0 b1 b2 b3 .... + // c0 c1 c2 c3 .... + // d0 d1 d2 d3 .... + v128_t u0 = wasm_unpacklo_i8x16(a.val, c.val); // a0 c0 a1 c1 ... + v128_t u1 = wasm_unpackhi_i8x16(a.val, c.val); // a8 c8 a9 c9 ... + v128_t u2 = wasm_unpacklo_i8x16(b.val, d.val); // b0 d0 b1 d1 ... + v128_t u3 = wasm_unpackhi_i8x16(b.val, d.val); // b8 d8 b9 d9 ... + + v128_t v0 = wasm_unpacklo_i8x16(u0, u2); // a0 b0 c0 d0 ... + v128_t v1 = wasm_unpackhi_i8x16(u0, u2); // a4 b4 c4 d4 ... + v128_t v2 = wasm_unpacklo_i8x16(u1, u3); // a8 b8 c8 d8 ... + v128_t v3 = wasm_unpackhi_i8x16(u1, u3); // a12 b12 c12 d12 ... + + wasm_v128_store(ptr, v0); + wasm_v128_store(ptr + 16, v1); + wasm_v128_store(ptr + 32, v2); + wasm_v128_store(ptr + 48, v3); +} + +inline void v_store_interleave( ushort* ptr, const v_uint16x8& a, const v_uint16x8& b, + hal::StoreMode /*mode*/ = hal::STORE_UNALIGNED) +{ + v128_t v0 = wasm_unpacklo_i16x8(a.val, b.val); + v128_t v1 = wasm_unpackhi_i16x8(a.val, b.val); + + wasm_v128_store(ptr, v0); + wasm_v128_store(ptr + 8, v1); +} + +inline void v_store_interleave( ushort* ptr, const v_uint16x8& a, + const v_uint16x8& b, const v_uint16x8& c, + hal::StoreMode /*mode*/ = hal::STORE_UNALIGNED) +{ + v128_t t00 = wasm_v8x16_shuffle(a.val, b.val, 0,1,16,17,0,0,2,3,18,19,0,0,4,5,20,21); + v128_t t01 = wasm_v8x16_shuffle(a.val, b.val, 0,0,6,7,22,23,0,0,8,9,24,25,0,0,10,11); + v128_t t02 = wasm_v8x16_shuffle(a.val, b.val, 26,27,0,0,12,13,28,29,0,0,14,15,30,31,0,0); + + v128_t t10 = wasm_v8x16_shuffle(t00, c.val, 0,1,2,3,16,17,6,7,8,9,18,19,12,13,14,15); + v128_t t11 = wasm_v8x16_shuffle(t01, c.val, 20,21,2,3,4,5,22,23,8,9,10,11,24,25,14,15); + v128_t t12 = wasm_v8x16_shuffle(t02, c.val, 0,1,26,27,4,5,6,7,28,29,10,11,12,13,30,31); + + wasm_v128_store(ptr, t10); + wasm_v128_store(ptr + 8, t11); + wasm_v128_store(ptr + 16, t12); +} + +inline void v_store_interleave( ushort* ptr, const v_uint16x8& a, const v_uint16x8& b, + const v_uint16x8& c, const v_uint16x8& d, + hal::StoreMode /*mode*/ = hal::STORE_UNALIGNED) +{ + // a0 a1 a2 a3 .... + // b0 b1 b2 b3 .... + // c0 c1 c2 c3 .... + // d0 d1 d2 d3 .... + v128_t u0 = wasm_unpacklo_i16x8(a.val, c.val); // a0 c0 a1 c1 ... + v128_t u1 = wasm_unpackhi_i16x8(a.val, c.val); // a4 c4 a5 c5 ... + v128_t u2 = wasm_unpacklo_i16x8(b.val, d.val); // b0 d0 b1 d1 ... + v128_t u3 = wasm_unpackhi_i16x8(b.val, d.val); // b4 d4 b5 d5 ... + + v128_t v0 = wasm_unpacklo_i16x8(u0, u2); // a0 b0 c0 d0 ... + v128_t v1 = wasm_unpackhi_i16x8(u0, u2); // a2 b2 c2 d2 ... + v128_t v2 = wasm_unpacklo_i16x8(u1, u3); // a4 b4 c4 d4 ... + v128_t v3 = wasm_unpackhi_i16x8(u1, u3); // a6 b6 c6 d6 ... + + wasm_v128_store(ptr, v0); + wasm_v128_store(ptr + 8, v1); + wasm_v128_store(ptr + 16, v2); + wasm_v128_store(ptr + 24, v3); +} + +inline void v_store_interleave( unsigned* ptr, const v_uint32x4& a, const v_uint32x4& b, + hal::StoreMode /*mode*/ = hal::STORE_UNALIGNED) +{ + v128_t v0 = wasm_unpacklo_i32x4(a.val, b.val); + v128_t v1 = wasm_unpackhi_i32x4(a.val, b.val); + + wasm_v128_store(ptr, v0); + wasm_v128_store(ptr + 4, v1); +} + +inline void v_store_interleave( unsigned* ptr, const v_uint32x4& a, const v_uint32x4& b, + const v_uint32x4& c, hal::StoreMode /*mode*/ = hal::STORE_UNALIGNED) +{ + v128_t t00 = wasm_v8x16_shuffle(a.val, b.val, 0,1,2,3,16,17,18,19,0,0,0,0,4,5,6,7); + v128_t t01 = wasm_v8x16_shuffle(a.val, b.val, 20,21,22,23,0,0,0,0,8,9,10,11,24,25,26,27); + v128_t t02 = wasm_v8x16_shuffle(a.val, b.val, 0,0,0,0,12,13,14,15,28,29,30,31,0,0,0,0); + + v128_t t10 = wasm_v8x16_shuffle(t00, c.val, 0,1,2,3,4,5,6,7,16,17,18,19,12,13,14,15); + v128_t t11 = wasm_v8x16_shuffle(t01, c.val, 0,1,2,3,20,21,22,23,8,9,10,11,12,13,14,15); + v128_t t12 = wasm_v8x16_shuffle(t02, c.val, 24,25,26,27,4,5,6,7,8,9,10,11,28,29,30,31); + + wasm_v128_store(ptr, t10); + wasm_v128_store(ptr + 4, t11); + wasm_v128_store(ptr + 8, t12); +} + +inline void v_store_interleave(unsigned* ptr, const v_uint32x4& a, const v_uint32x4& b, + const v_uint32x4& c, const v_uint32x4& d, + hal::StoreMode /*mode*/ = hal::STORE_UNALIGNED) +{ + v_uint32x4 v0, v1, v2, v3; + v_transpose4x4(a, b, c, d, v0, v1, v2, v3); + + wasm_v128_store(ptr, v0.val); + wasm_v128_store(ptr + 4, v1.val); + wasm_v128_store(ptr + 8, v2.val); + wasm_v128_store(ptr + 12, v3.val); +} + +// 2-channel, float only +inline void v_store_interleave(float* ptr, const v_float32x4& a, const v_float32x4& b, + hal::StoreMode /*mode*/ = hal::STORE_UNALIGNED) +{ + v128_t v0 = wasm_unpacklo_i32x4(a.val, b.val); + v128_t v1 = wasm_unpackhi_i32x4(a.val, b.val); + + wasm_v128_store(ptr, v0); + wasm_v128_store(ptr + 4, v1); +} + +inline void v_store_interleave(float* ptr, const v_float32x4& a, const v_float32x4& b, + const v_float32x4& c, hal::StoreMode /*mode*/ = hal::STORE_UNALIGNED) +{ + v128_t t00 = wasm_v8x16_shuffle(a.val, b.val, 0,1,2,3,16,17,18,19,0,0,0,0,4,5,6,7); + v128_t t01 = wasm_v8x16_shuffle(a.val, b.val, 20,21,22,23,0,0,0,0,8,9,10,11,24,25,26,27); + v128_t t02 = wasm_v8x16_shuffle(a.val, b.val, 0,0,0,0,12,13,14,15,28,29,30,31,0,0,0,0); + + v128_t t10 = wasm_v8x16_shuffle(t00, c.val, 0,1,2,3,4,5,6,7,16,17,18,19,12,13,14,15); + v128_t t11 = wasm_v8x16_shuffle(t01, c.val, 0,1,2,3,20,21,22,23,8,9,10,11,12,13,14,15); + v128_t t12 = wasm_v8x16_shuffle(t02, c.val, 24,25,26,27,4,5,6,7,8,9,10,11,28,29,30,31); + + wasm_v128_store(ptr, t10); + wasm_v128_store(ptr + 4, t11); + wasm_v128_store(ptr + 8, t12); +} + +inline void v_store_interleave(float* ptr, const v_float32x4& a, const v_float32x4& b, + const v_float32x4& c, const v_float32x4& d, + hal::StoreMode /*mode*/ = hal::STORE_UNALIGNED) +{ + v_float32x4 v0, v1, v2, v3; + v_transpose4x4(a, b, c, d, v0, v1, v2, v3); + + wasm_v128_store(ptr, v0.val); + wasm_v128_store(ptr + 4, v1.val); + wasm_v128_store(ptr + 8, v2.val); + wasm_v128_store(ptr + 12, v3.val); +} + +inline void v_store_interleave(uint64 *ptr, const v_uint64x2& a, const v_uint64x2& b, + hal::StoreMode /*mode*/ = hal::STORE_UNALIGNED) +{ + v128_t v0 = wasm_unpacklo_i64x2(a.val, b.val); + v128_t v1 = wasm_unpackhi_i64x2(a.val, b.val); + + wasm_v128_store(ptr, v0); + wasm_v128_store(ptr + 2, v1); +} + +inline void v_store_interleave(uint64 *ptr, const v_uint64x2& a, const v_uint64x2& b, + const v_uint64x2& c, hal::StoreMode /*mode*/ = hal::STORE_UNALIGNED) +{ + v128_t v0 = wasm_v8x16_shuffle(a.val, b.val, 0,1,2,3,4,5,6,7,16,17,18,19,20,21,22,23); + v128_t v1 = wasm_v8x16_shuffle(a.val, c.val, 16,17,18,19,20,21,22,23,8,9,10,11,12,13,14,15); + v128_t v2 = wasm_v8x16_shuffle(b.val, c.val, 8,9,10,11,12,13,14,15,24,25,26,27,28,29,30,31); + + wasm_v128_store(ptr, v0); + wasm_v128_store(ptr + 2, v1); + wasm_v128_store(ptr + 4, v2); +} + +inline void v_store_interleave(uint64 *ptr, const v_uint64x2& a, const v_uint64x2& b, + const v_uint64x2& c, const v_uint64x2& d, + hal::StoreMode /*mode*/ = hal::STORE_UNALIGNED) +{ + v128_t v0 = wasm_unpacklo_i64x2(a.val, b.val); + v128_t v1 = wasm_unpacklo_i64x2(c.val, d.val); + v128_t v2 = wasm_unpackhi_i64x2(a.val, b.val); + v128_t v3 = wasm_unpackhi_i64x2(c.val, d.val); + + wasm_v128_store(ptr, v0); + wasm_v128_store(ptr + 2, v1); + wasm_v128_store(ptr + 4, v2); + wasm_v128_store(ptr + 6, v3); +} + +#define OPENCV_HAL_IMPL_WASM_LOADSTORE_INTERLEAVE(_Tpvec0, _Tp0, suffix0, _Tpvec1, _Tp1, suffix1) \ +inline void v_load_deinterleave( const _Tp0* ptr, _Tpvec0& a0, _Tpvec0& b0 ) \ +{ \ + _Tpvec1 a1, b1; \ + v_load_deinterleave((const _Tp1*)ptr, a1, b1); \ + a0 = v_reinterpret_as_##suffix0(a1); \ + b0 = v_reinterpret_as_##suffix0(b1); \ +} \ +inline void v_load_deinterleave( const _Tp0* ptr, _Tpvec0& a0, _Tpvec0& b0, _Tpvec0& c0 ) \ +{ \ + _Tpvec1 a1, b1, c1; \ + v_load_deinterleave((const _Tp1*)ptr, a1, b1, c1); \ + a0 = v_reinterpret_as_##suffix0(a1); \ + b0 = v_reinterpret_as_##suffix0(b1); \ + c0 = v_reinterpret_as_##suffix0(c1); \ +} \ +inline void v_load_deinterleave( const _Tp0* ptr, _Tpvec0& a0, _Tpvec0& b0, _Tpvec0& c0, _Tpvec0& d0 ) \ +{ \ + _Tpvec1 a1, b1, c1, d1; \ + v_load_deinterleave((const _Tp1*)ptr, a1, b1, c1, d1); \ + a0 = v_reinterpret_as_##suffix0(a1); \ + b0 = v_reinterpret_as_##suffix0(b1); \ + c0 = v_reinterpret_as_##suffix0(c1); \ + d0 = v_reinterpret_as_##suffix0(d1); \ +} \ +inline void v_store_interleave( _Tp0* ptr, const _Tpvec0& a0, const _Tpvec0& b0, \ + hal::StoreMode mode = hal::STORE_UNALIGNED ) \ +{ \ + _Tpvec1 a1 = v_reinterpret_as_##suffix1(a0); \ + _Tpvec1 b1 = v_reinterpret_as_##suffix1(b0); \ + v_store_interleave((_Tp1*)ptr, a1, b1, mode); \ +} \ +inline void v_store_interleave( _Tp0* ptr, const _Tpvec0& a0, const _Tpvec0& b0, \ + const _Tpvec0& c0, hal::StoreMode mode = hal::STORE_UNALIGNED ) \ +{ \ + _Tpvec1 a1 = v_reinterpret_as_##suffix1(a0); \ + _Tpvec1 b1 = v_reinterpret_as_##suffix1(b0); \ + _Tpvec1 c1 = v_reinterpret_as_##suffix1(c0); \ + v_store_interleave((_Tp1*)ptr, a1, b1, c1, mode); \ +} \ +inline void v_store_interleave( _Tp0* ptr, const _Tpvec0& a0, const _Tpvec0& b0, \ + const _Tpvec0& c0, const _Tpvec0& d0, \ + hal::StoreMode mode = hal::STORE_UNALIGNED ) \ +{ \ + _Tpvec1 a1 = v_reinterpret_as_##suffix1(a0); \ + _Tpvec1 b1 = v_reinterpret_as_##suffix1(b0); \ + _Tpvec1 c1 = v_reinterpret_as_##suffix1(c0); \ + _Tpvec1 d1 = v_reinterpret_as_##suffix1(d0); \ + v_store_interleave((_Tp1*)ptr, a1, b1, c1, d1, mode); \ +} + +OPENCV_HAL_IMPL_WASM_LOADSTORE_INTERLEAVE(v_int8x16, schar, s8, v_uint8x16, uchar, u8) +OPENCV_HAL_IMPL_WASM_LOADSTORE_INTERLEAVE(v_int16x8, short, s16, v_uint16x8, ushort, u16) +OPENCV_HAL_IMPL_WASM_LOADSTORE_INTERLEAVE(v_int32x4, int, s32, v_uint32x4, unsigned, u32) +OPENCV_HAL_IMPL_WASM_LOADSTORE_INTERLEAVE(v_int64x2, int64, s64, v_uint64x2, uint64, u64) +OPENCV_HAL_IMPL_WASM_LOADSTORE_INTERLEAVE(v_float64x2, double, f64, v_uint64x2, uint64, u64) + +inline v_float32x4 v_cvt_f32(const v_int32x4& a) +{ + return v_float32x4(wasm_f32x4_convert_i32x4(a.val)); +} + +inline v_float32x4 v_cvt_f32(const v_float64x2& a) +{ + double a_[2]; + wasm_v128_store(a_, a.val); + float c_[4]; + c_[0] = (float)(a_[0]); + c_[1] = (float)(a_[1]); + c_[2] = 0; + c_[3] = 0; + return v_float32x4(wasm_v128_load(c_)); +} + +inline v_float32x4 v_cvt_f32(const v_float64x2& a, const v_float64x2& b) +{ + double a_[2], b_[2]; + wasm_v128_store(a_, a.val); + wasm_v128_store(b_, b.val); + float c_[4]; + c_[0] = (float)(a_[0]); + c_[1] = (float)(a_[1]); + c_[2] = (float)(b_[0]); + c_[3] = (float)(b_[1]); + return v_float32x4(wasm_v128_load(c_)); +} + +inline v_float64x2 v_cvt_f64(const v_int32x4& a) +{ +#ifdef __wasm_unimplemented_simd128__ + v128_t p = v128_cvti32x4_i64x2(a.val); + return v_float64x2(wasm_f64x2_convert_i64x2(p)); +#else + int a_[4]; + wasm_v128_store(a_, a.val); + double c_[2]; + c_[0] = (double)(a_[0]); + c_[1] = (double)(a_[1]); + return v_float64x2(wasm_v128_load(c_)); +#endif +} + +inline v_float64x2 v_cvt_f64_high(const v_int32x4& a) +{ +#ifdef __wasm_unimplemented_simd128__ + v128_t p = v128_cvti32x4_i64x2_high(a.val); + return v_float64x2(wasm_f64x2_convert_i64x2(p)); +#else + int a_[4]; + wasm_v128_store(a_, a.val); + double c_[2]; + c_[0] = (double)(a_[2]); + c_[1] = (double)(a_[3]); + return v_float64x2(wasm_v128_load(c_)); +#endif +} + +inline v_float64x2 v_cvt_f64(const v_float32x4& a) +{ + float a_[4]; + wasm_v128_store(a_, a.val); + double c_[2]; + c_[0] = (double)(a_[0]); + c_[1] = (double)(a_[1]); + return v_float64x2(wasm_v128_load(c_)); +} + +inline v_float64x2 v_cvt_f64_high(const v_float32x4& a) +{ + float a_[4]; + wasm_v128_store(a_, a.val); + double c_[2]; + c_[0] = (double)(a_[2]); + c_[1] = (double)(a_[3]); + return v_float64x2(wasm_v128_load(c_)); +} + +inline v_float64x2 v_cvt_f64(const v_int64x2& a) +{ +#ifdef __wasm_unimplemented_simd128__ + return v_float64x2(wasm_f64x2_convert_i64x2(a.val)); +#else + int64 a_[2]; + wasm_v128_store(a_, a.val); + double c_[2]; + c_[0] = (double)(a_[0]); + c_[1] = (double)(a_[1]); + return v_float64x2(wasm_v128_load(c_)); +#endif +} + +////////////// Lookup table access //////////////////// + +inline v_int8x16 v_lut(const schar* tab, const int* idx) +{ + return v_int8x16(tab[idx[0]], tab[idx[1]], tab[idx[ 2]], tab[idx[ 3]], tab[idx[ 4]], tab[idx[ 5]], tab[idx[ 6]], tab[idx[ 7]], + tab[idx[8]], tab[idx[9]], tab[idx[10]], tab[idx[11]], tab[idx[12]], tab[idx[13]], tab[idx[14]], tab[idx[15]]); +} +inline v_int8x16 v_lut_pairs(const schar* tab, const int* idx) +{ + return v_int8x16(tab[idx[0]], tab[idx[0]+1], tab[idx[1]], tab[idx[1]+1], tab[idx[2]], tab[idx[2]+1], tab[idx[3]], tab[idx[3]+1], + tab[idx[4]], tab[idx[4]+1], tab[idx[5]], tab[idx[5]+1], tab[idx[6]], tab[idx[6]+1], tab[idx[7]], tab[idx[7]+1]); +} +inline v_int8x16 v_lut_quads(const schar* tab, const int* idx) +{ + return v_int8x16(tab[idx[0]], tab[idx[0]+1], tab[idx[0]+2], tab[idx[0]+3], tab[idx[1]], tab[idx[1]+1], tab[idx[1]+2], tab[idx[1]+3], + tab[idx[2]], tab[idx[2]+1], tab[idx[2]+2], tab[idx[2]+3], tab[idx[3]], tab[idx[3]+1], tab[idx[3]+2], tab[idx[3]+3]); +} +inline v_uint8x16 v_lut(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut((const schar *)tab, idx)); } +inline v_uint8x16 v_lut_pairs(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut_pairs((const schar *)tab, idx)); } +inline v_uint8x16 v_lut_quads(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut_quads((const schar *)tab, idx)); } + +inline v_int16x8 v_lut(const short* tab, const int* idx) +{ + return v_int16x8(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]], + tab[idx[4]], tab[idx[5]], tab[idx[6]], tab[idx[7]]); +} +inline v_int16x8 v_lut_pairs(const short* tab, const int* idx) +{ + return v_int16x8(tab[idx[0]], tab[idx[0]+1], tab[idx[1]], tab[idx[1]+1], + tab[idx[2]], tab[idx[2]+1], tab[idx[3]], tab[idx[3]+1]); +} +inline v_int16x8 v_lut_quads(const short* tab, const int* idx) +{ + return v_int16x8(tab[idx[0]], tab[idx[0]+1], tab[idx[0]+2], tab[idx[0]+3], + tab[idx[1]], tab[idx[1]+1], tab[idx[1]+2], tab[idx[1]+3]); +} +inline v_uint16x8 v_lut(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut((const short *)tab, idx)); } +inline v_uint16x8 v_lut_pairs(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut_pairs((const short *)tab, idx)); } +inline v_uint16x8 v_lut_quads(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut_quads((const short *)tab, idx)); } + +inline v_int32x4 v_lut(const int* tab, const int* idx) +{ + return v_int32x4(tab[idx[0]], tab[idx[1]], + tab[idx[2]], tab[idx[3]]); +} +inline v_int32x4 v_lut_pairs(const int* tab, const int* idx) +{ + return v_int32x4(tab[idx[0]], tab[idx[0]+1], + tab[idx[1]], tab[idx[1]+1]); +} +inline v_int32x4 v_lut_quads(const int* tab, const int* idx) +{ + return v_int32x4(wasm_v128_load(tab + idx[0])); +} +inline v_uint32x4 v_lut(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut((const int *)tab, idx)); } +inline v_uint32x4 v_lut_pairs(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut_pairs((const int *)tab, idx)); } +inline v_uint32x4 v_lut_quads(const unsigned* tab, const int* idx) { return v_reinterpret_as_u32(v_lut_quads((const int *)tab, idx)); } + +inline v_int64x2 v_lut(const int64_t* tab, const int* idx) +{ + return v_int64x2(tab[idx[0]], tab[idx[1]]); +} +inline v_int64x2 v_lut_pairs(const int64_t* tab, const int* idx) +{ + return v_int64x2(wasm_v128_load(tab + idx[0])); +} +inline v_uint64x2 v_lut(const uint64_t* tab, const int* idx) { return v_reinterpret_as_u64(v_lut((const int64_t *)tab, idx)); } +inline v_uint64x2 v_lut_pairs(const uint64_t* tab, const int* idx) { return v_reinterpret_as_u64(v_lut_pairs((const int64_t *)tab, idx)); } + +inline v_float32x4 v_lut(const float* tab, const int* idx) +{ + return v_float32x4(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]]); +} +inline v_float32x4 v_lut_pairs(const float* tab, const int* idx) { return v_reinterpret_as_f32(v_lut_pairs((const int *)tab, idx)); } +inline v_float32x4 v_lut_quads(const float* tab, const int* idx) { return v_reinterpret_as_f32(v_lut_quads((const int *)tab, idx)); } + +inline v_float64x2 v_lut(const double* tab, const int* idx) +{ + return v_float64x2(tab[idx[0]], tab[idx[1]]); +} +inline v_float64x2 v_lut_pairs(const double* tab, const int* idx) +{ + return v_float64x2(wasm_v128_load(tab + idx[0])); +} + +inline v_int32x4 v_lut(const int* tab, const v_int32x4& idxvec) +{ + return v_int32x4(tab[wasm_i32x4_extract_lane(idxvec.val, 0)], + tab[wasm_i32x4_extract_lane(idxvec.val, 1)], + tab[wasm_i32x4_extract_lane(idxvec.val, 2)], + tab[wasm_i32x4_extract_lane(idxvec.val, 3)]); +} + +inline v_uint32x4 v_lut(const unsigned* tab, const v_int32x4& idxvec) +{ + return v_reinterpret_as_u32(v_lut((const int *)tab, idxvec)); +} + +inline v_float32x4 v_lut(const float* tab, const v_int32x4& idxvec) +{ + return v_float32x4(tab[wasm_i32x4_extract_lane(idxvec.val, 0)], + tab[wasm_i32x4_extract_lane(idxvec.val, 1)], + tab[wasm_i32x4_extract_lane(idxvec.val, 2)], + tab[wasm_i32x4_extract_lane(idxvec.val, 3)]); +} + +inline v_float64x2 v_lut(const double* tab, const v_int32x4& idxvec) +{ + return v_float64x2(tab[wasm_i32x4_extract_lane(idxvec.val, 0)], + tab[wasm_i32x4_extract_lane(idxvec.val, 1)]); +} + +// loads pairs from the table and deinterleaves them, e.g. returns: +// x = (tab[idxvec[0], tab[idxvec[1]], tab[idxvec[2]], tab[idxvec[3]]), +// y = (tab[idxvec[0]+1], tab[idxvec[1]+1], tab[idxvec[2]+1], tab[idxvec[3]+1]) +// note that the indices are float's indices, not the float-pair indices. +// in theory, this function can be used to implement bilinear interpolation, +// when idxvec are the offsets within the image. +inline void v_lut_deinterleave(const float* tab, const v_int32x4& idxvec, v_float32x4& x, v_float32x4& y) +{ + x = v_float32x4(tab[wasm_i32x4_extract_lane(idxvec.val, 0)], + tab[wasm_i32x4_extract_lane(idxvec.val, 1)], + tab[wasm_i32x4_extract_lane(idxvec.val, 2)], + tab[wasm_i32x4_extract_lane(idxvec.val, 3)]); + y = v_float32x4(tab[wasm_i32x4_extract_lane(idxvec.val, 0)+1], + tab[wasm_i32x4_extract_lane(idxvec.val, 1)+1], + tab[wasm_i32x4_extract_lane(idxvec.val, 2)+1], + tab[wasm_i32x4_extract_lane(idxvec.val, 3)+1]); +} + +inline void v_lut_deinterleave(const double* tab, const v_int32x4& idxvec, v_float64x2& x, v_float64x2& y) +{ + v128_t xy0 = wasm_v128_load(tab + wasm_i32x4_extract_lane(idxvec.val, 0)); + v128_t xy1 = wasm_v128_load(tab + wasm_i32x4_extract_lane(idxvec.val, 1)); + x.val = wasm_unpacklo_i64x2(xy0, xy1); + y.val = wasm_unpacklo_i64x2(xy0, xy1); +} + +inline v_int8x16 v_interleave_pairs(const v_int8x16& vec) +{ + return v_int8x16(wasm_v8x16_shuffle(vec.val, vec.val, 0,2,1,3,4,6,5,7,8,10,9,11,12,14,13,15)); +} +inline v_uint8x16 v_interleave_pairs(const v_uint8x16& vec) { return v_reinterpret_as_u8(v_interleave_pairs(v_reinterpret_as_s8(vec))); } +inline v_int8x16 v_interleave_quads(const v_int8x16& vec) +{ + return v_int8x16(wasm_v8x16_shuffle(vec.val, vec.val, 0,4,1,5,2,6,3,7,8,12,9,13,10,14,11,15)); +} +inline v_uint8x16 v_interleave_quads(const v_uint8x16& vec) { return v_reinterpret_as_u8(v_interleave_quads(v_reinterpret_as_s8(vec))); } + +inline v_int16x8 v_interleave_pairs(const v_int16x8& vec) +{ + return v_int16x8(wasm_v8x16_shuffle(vec.val, vec.val, 0,1,4,5,2,3,6,7,8,9,12,13,10,11,14,15)); +} +inline v_uint16x8 v_interleave_pairs(const v_uint16x8& vec) { return v_reinterpret_as_u16(v_interleave_pairs(v_reinterpret_as_s16(vec))); } +inline v_int16x8 v_interleave_quads(const v_int16x8& vec) +{ + return v_int16x8(wasm_v8x16_shuffle(vec.val, vec.val, 0,1,8,9,2,3,10,11,4,5,12,13,6,7,14,15)); +} +inline v_uint16x8 v_interleave_quads(const v_uint16x8& vec) { return v_reinterpret_as_u16(v_interleave_quads(v_reinterpret_as_s16(vec))); } + +inline v_int32x4 v_interleave_pairs(const v_int32x4& vec) +{ + return v_int32x4(wasm_v8x16_shuffle(vec.val, vec.val, 0,1,2,3,8,9,10,11,4,5,6,7,12,13,14,15)); +} +inline v_uint32x4 v_interleave_pairs(const v_uint32x4& vec) { return v_reinterpret_as_u32(v_interleave_pairs(v_reinterpret_as_s32(vec))); } +inline v_float32x4 v_interleave_pairs(const v_float32x4& vec) +{ + return v_float32x4(wasm_v8x16_shuffle(vec.val, vec.val, 0,1,2,3,8,9,10,11,4,5,6,7,12,13,14,15)); +} + +inline v_int8x16 v_pack_triplets(const v_int8x16& vec) +{ + return v_int8x16(wasm_v8x16_shuffle(vec.val, vec.val, 0,1,2,4,5,6,8,9,10,12,13,14,16,16,16,16)); +} +inline v_uint8x16 v_pack_triplets(const v_uint8x16& vec) { return v_reinterpret_as_u8(v_pack_triplets(v_reinterpret_as_s8(vec))); } + +inline v_int16x8 v_pack_triplets(const v_int16x8& vec) +{ + return v_int16x8(wasm_v8x16_shuffle(vec.val, vec.val, 0,1,2,3,4,5,8,9,10,11,12,13,14,15,6,7)); +} +inline v_uint16x8 v_pack_triplets(const v_uint16x8& vec) { return v_reinterpret_as_u16(v_pack_triplets(v_reinterpret_as_s16(vec))); } + +inline v_int32x4 v_pack_triplets(const v_int32x4& vec) { return vec; } +inline v_uint32x4 v_pack_triplets(const v_uint32x4& vec) { return vec; } +inline v_float32x4 v_pack_triplets(const v_float32x4& vec) { return vec; } + +template +inline typename _Tp::lane_type v_extract_n(const _Tp& a) +{ + return v_rotate_right(a).get0(); +} + +template +inline v_uint32x4 v_broadcast_element(const v_uint32x4& a) +{ + return v_setall_u32(v_extract_n(a)); +} +template +inline v_int32x4 v_broadcast_element(const v_int32x4& a) +{ + return v_setall_s32(v_extract_n(a)); +} +template +inline v_float32x4 v_broadcast_element(const v_float32x4& a) +{ + return v_setall_f32(v_extract_n(a)); +} + + +////////////// FP16 support /////////////////////////// + +inline v_float32x4 v_load_expand(const float16_t* ptr) +{ + float a[4]; + for (int i = 0; i < 4; i++) + a[i] = ptr[i]; + return v_float32x4(wasm_v128_load(a)); +} + +inline void v_pack_store(float16_t* ptr, const v_float32x4& v) +{ + double v_[4]; + wasm_v128_store(v_, v.val); + ptr[0] = float16_t(v_[0]); + ptr[1] = float16_t(v_[1]); + ptr[2] = float16_t(v_[2]); + ptr[3] = float16_t(v_[3]); +} + +inline void v_cleanup() {} + +CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END + +//! @endcond + +} + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/msa_macros.h b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/msa_macros.h new file mode 100644 index 0000000..fad8c5a --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/msa_macros.h @@ -0,0 +1,1558 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_HAL_MSA_MACROS_H +#define OPENCV_CORE_HAL_MSA_MACROS_H + +#ifdef __mips_msa +#include "msa.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Define 64 bits vector types */ +typedef signed char v8i8 __attribute__ ((vector_size(8), aligned(8))); +typedef unsigned char v8u8 __attribute__ ((vector_size(8), aligned(8))); +typedef short v4i16 __attribute__ ((vector_size(8), aligned(8))); +typedef unsigned short v4u16 __attribute__ ((vector_size(8), aligned(8))); +typedef int v2i32 __attribute__ ((vector_size(8), aligned(8))); +typedef unsigned int v2u32 __attribute__ ((vector_size(8), aligned(8))); +typedef long long v1i64 __attribute__ ((vector_size(8), aligned(8))); +typedef unsigned long long v1u64 __attribute__ ((vector_size(8), aligned(8))); +typedef float v2f32 __attribute__ ((vector_size(8), aligned(8))); +typedef double v1f64 __attribute__ ((vector_size(8), aligned(8))); + + +/* Load values from the given memory a 64-bit vector. */ +#define msa_ld1_s8(__a) (*((v8i8*)(__a))) +#define msa_ld1_s16(__a) (*((v4i16*)(__a))) +#define msa_ld1_s32(__a) (*((v2i32*)(__a))) +#define msa_ld1_s64(__a) (*((v1i64*)(__a))) +#define msa_ld1_u8(__a) (*((v8u8*)(__a))) +#define msa_ld1_u16(__a) (*((v4u16*)(__a))) +#define msa_ld1_u32(__a) (*((v2u32*)(__a))) +#define msa_ld1_u64(__a) (*((v1u64*)(__a))) +#define msa_ld1_f32(__a) (*((v2f32*)(__a))) +#define msa_ld1_f64(__a) (*((v1f64*)(__a))) + +/* Load values from the given memory address to a 128-bit vector */ +#define msa_ld1q_s8(__a) ((v16i8)__builtin_msa_ld_b(__a, 0)) +#define msa_ld1q_s16(__a) ((v8i16)__builtin_msa_ld_h(__a, 0)) +#define msa_ld1q_s32(__a) ((v4i32)__builtin_msa_ld_w(__a, 0)) +#define msa_ld1q_s64(__a) ((v2i64)__builtin_msa_ld_d(__a, 0)) +#define msa_ld1q_u8(__a) ((v16u8)__builtin_msa_ld_b(__a, 0)) +#define msa_ld1q_u16(__a) ((v8u16)__builtin_msa_ld_h(__a, 0)) +#define msa_ld1q_u32(__a) ((v4u32)__builtin_msa_ld_w(__a, 0)) +#define msa_ld1q_u64(__a) ((v2u64)__builtin_msa_ld_d(__a, 0)) +#define msa_ld1q_f32(__a) ((v4f32)__builtin_msa_ld_w(__a, 0)) +#define msa_ld1q_f64(__a) ((v2f64)__builtin_msa_ld_d(__a, 0)) + +/* Store 64bits vector elements values to the given memory address. */ +#define msa_st1_s8(__a, __b) (*((v8i8*)(__a)) = __b) +#define msa_st1_s16(__a, __b) (*((v4i16*)(__a)) = __b) +#define msa_st1_s32(__a, __b) (*((v2i32*)(__a)) = __b) +#define msa_st1_s64(__a, __b) (*((v1i64*)(__a)) = __b) +#define msa_st1_u8(__a, __b) (*((v8u8*)(__a)) = __b) +#define msa_st1_u16(__a, __b) (*((v4u16*)(__a)) = __b) +#define msa_st1_u32(__a, __b) (*((v2u32*)(__a)) = __b) +#define msa_st1_u64(__a, __b) (*((v1u64*)(__a)) = __b) +#define msa_st1_f32(__a, __b) (*((v2f32*)(__a)) = __b) +#define msa_st1_f64(__a, __b) (*((v1f64*)(__a)) = __b) + +/* Store the values of elements in the 128 bits vector __a to the given memory address __a. */ +#define msa_st1q_s8(__a, __b) (__builtin_msa_st_b((v16i8)(__b), __a, 0)) +#define msa_st1q_s16(__a, __b) (__builtin_msa_st_h((v8i16)(__b), __a, 0)) +#define msa_st1q_s32(__a, __b) (__builtin_msa_st_w((v4i32)(__b), __a, 0)) +#define msa_st1q_s64(__a, __b) (__builtin_msa_st_d((v2i64)(__b), __a, 0)) +#define msa_st1q_u8(__a, __b) (__builtin_msa_st_b((v16i8)(__b), __a, 0)) +#define msa_st1q_u16(__a, __b) (__builtin_msa_st_h((v8i16)(__b), __a, 0)) +#define msa_st1q_u32(__a, __b) (__builtin_msa_st_w((v4i32)(__b), __a, 0)) +#define msa_st1q_u64(__a, __b) (__builtin_msa_st_d((v2i64)(__b), __a, 0)) +#define msa_st1q_f32(__a, __b) (__builtin_msa_st_w((v4i32)(__b), __a, 0)) +#define msa_st1q_f64(__a, __b) (__builtin_msa_st_d((v2i64)(__b), __a, 0)) + +/* Store the value of the element with the index __c in vector __a to the given memory address __a. */ +#define msa_st1_lane_s8(__a, __b, __c) (*((int8_t*)(__a)) = __b[__c]) +#define msa_st1_lane_s16(__a, __b, __c) (*((int16_t*)(__a)) = __b[__c]) +#define msa_st1_lane_s32(__a, __b, __c) (*((int32_t*)(__a)) = __b[__c]) +#define msa_st1_lane_s64(__a, __b, __c) (*((int64_t*)(__a)) = __b[__c]) +#define msa_st1_lane_u8(__a, __b, __c) (*((uint8_t*)(__a)) = __b[__c]) +#define msa_st1_lane_u16(__a, __b, __c) (*((uint16_t*)(__a)) = __b[__c]) +#define msa_st1_lane_u32(__a, __b, __c) (*((uint32_t*)(__a)) = __b[__c]) +#define msa_st1_lane_u64(__a, __b, __c) (*((uint64_t*)(__a)) = __b[__c]) +#define msa_st1_lane_f32(__a, __b, __c) (*((float*)(__a)) = __b[__c]) +#define msa_st1_lane_f64(__a, __b, __c) (*((double*)(__a)) = __b[__c]) +#define msa_st1q_lane_s8(__a, __b, __c) (*((int8_t*)(__a)) = (int8_t)__builtin_msa_copy_s_b(__b, __c)) +#define msa_st1q_lane_s16(__a, __b, __c) (*((int16_t*)(__a)) = (int16_t)__builtin_msa_copy_s_h(__b, __c)) +#define msa_st1q_lane_s32(__a, __b, __c) (*((int32_t*)(__a)) = __builtin_msa_copy_s_w(__b, __c)) +#define msa_st1q_lane_s64(__a, __b, __c) (*((int64_t*)(__a)) = __builtin_msa_copy_s_d(__b, __c)) +#define msa_st1q_lane_u8(__a, __b, __c) (*((uint8_t*)(__a)) = (uint8_t)__builtin_msa_copy_u_b((v16i8)(__b), __c)) +#define msa_st1q_lane_u16(__a, __b, __c) (*((uint16_t*)(__a)) = (uint16_t)__builtin_msa_copy_u_h((v8i16)(__b), __c)) +#define msa_st1q_lane_u32(__a, __b, __c) (*((uint32_t*)(__a)) = __builtin_msa_copy_u_w((v4i32)(__b), __c)) +#define msa_st1q_lane_u64(__a, __b, __c) (*((uint64_t*)(__a)) = __builtin_msa_copy_u_d((v2i64)(__b), __c)) +#define msa_st1q_lane_f32(__a, __b, __c) (*((float*)(__a)) = __b[__c]) +#define msa_st1q_lane_f64(__a, __b, __c) (*((double*)(__a)) = __b[__c]) + +/* Duplicate elements for 64-bit doubleword vectors */ +#define msa_dup_n_s8(__a) ((v8i8)__builtin_msa_copy_s_d((v2i64)__builtin_msa_fill_b((int32_t)(__a)), 0)) +#define msa_dup_n_s16(__a) ((v4i16)__builtin_msa_copy_s_d((v2i64)__builtin_msa_fill_h((int32_t)(__a)), 0)) +#define msa_dup_n_s32(__a) ((v2i32){__a, __a}) +#define msa_dup_n_s64(__a) ((v1i64){__a}) +#define msa_dup_n_u8(__a) ((v8u8)__builtin_msa_copy_u_d((v2i64)__builtin_msa_fill_b((int32_t)(__a)), 0)) +#define msa_dup_n_u16(__a) ((v4u16)__builtin_msa_copy_u_d((v2i64)__builtin_msa_fill_h((int32_t)(__a)), 0)) +#define msa_dup_n_u32(__a) ((v2u32){__a, __a}) +#define msa_dup_n_u64(__a) ((v1u64){__a}) +#define msa_dup_n_f32(__a) ((v2f32){__a, __a}) +#define msa_dup_n_f64(__a) ((v1f64){__a}) + +/* Duplicate elements for 128-bit quadword vectors */ +#define msa_dupq_n_s8(__a) (__builtin_msa_fill_b((int32_t)(__a))) +#define msa_dupq_n_s16(__a) (__builtin_msa_fill_h((int32_t)(__a))) +#define msa_dupq_n_s32(__a) (__builtin_msa_fill_w((int32_t)(__a))) +#define msa_dupq_n_s64(__a) (__builtin_msa_fill_d((int64_t)(__a))) +#define msa_dupq_n_u8(__a) ((v16u8)__builtin_msa_fill_b((int32_t)(__a))) +#define msa_dupq_n_u16(__a) ((v8u16)__builtin_msa_fill_h((int32_t)(__a))) +#define msa_dupq_n_u32(__a) ((v4u32)__builtin_msa_fill_w((int32_t)(__a))) +#define msa_dupq_n_u64(__a) ((v2u64)__builtin_msa_fill_d((int64_t)(__a))) +#define msa_dupq_n_f32(__a) ((v4f32){__a, __a, __a, __a}) +#define msa_dupq_n_f64(__a) ((v2f64){__a, __a}) +#define msa_dupq_lane_s8(__a, __b) (__builtin_msa_splat_b(__a, __b)) +#define msa_dupq_lane_s16(__a, __b) (__builtin_msa_splat_h(__a, __b)) +#define msa_dupq_lane_s32(__a, __b) (__builtin_msa_splat_w(__a, __b)) +#define msa_dupq_lane_s64(__a, __b) (__builtin_msa_splat_d(__a, __b)) +#define msa_dupq_lane_u8(__a, __b) ((v16u8)__builtin_msa_splat_b((v16i8)(__a), __b)) +#define msa_dupq_lane_u16(__a, __b) ((v8u16)__builtin_msa_splat_h((v8i16)(__a), __b)) +#define msa_dupq_lane_u32(__a, __b) ((v4u32)__builtin_msa_splat_w((v4i32)(__a), __b)) +#define msa_dupq_lane_u64(__a, __b) ((v2u64)__builtin_msa_splat_d((v2i64)(__a), __b)) + +/* Create a 64 bits vector */ +#define msa_create_s8(__a) ((v8i8)((uint64_t)(__a))) +#define msa_create_s16(__a) ((v4i16)((uint64_t)(__a))) +#define msa_create_s32(__a) ((v2i32)((uint64_t)(__a))) +#define msa_create_s64(__a) ((v1i64)((uint64_t)(__a))) +#define msa_create_u8(__a) ((v8u8)((uint64_t)(__a))) +#define msa_create_u16(__a) ((v4u16)((uint64_t)(__a))) +#define msa_create_u32(__a) ((v2u32)((uint64_t)(__a))) +#define msa_create_u64(__a) ((v1u64)((uint64_t)(__a))) +#define msa_create_f32(__a) ((v2f32)((uint64_t)(__a))) +#define msa_create_f64(__a) ((v1f64)((uint64_t)(__a))) + +/* Sign extends or zero extends each element in a 64 bits vector to twice its original length, and places the results in a 128 bits vector. */ +/*Transform v8i8 to v8i16*/ +#define msa_movl_s8(__a) \ +((v8i16){(__a)[0], (__a)[1], (__a)[2], (__a)[3], \ + (__a)[4], (__a)[5], (__a)[6], (__a)[7]}) + +/*Transform v8u8 to v8u16*/ +#define msa_movl_u8(__a) \ +((v8u16){(__a)[0], (__a)[1], (__a)[2], (__a)[3], \ + (__a)[4], (__a)[5], (__a)[6], (__a)[7]}) + +/*Transform v4i16 to v8i16*/ +#define msa_movl_s16(__a) ((v4i32){(__a)[0], (__a)[1], (__a)[2], (__a)[3]}) + +/*Transform v2i32 to v4i32*/ +#define msa_movl_s32(__a) ((v2i64){(__a)[0], (__a)[1]}) + +/*Transform v4u16 to v8u16*/ +#define msa_movl_u16(__a) ((v4u32){(__a)[0], (__a)[1], (__a)[2], (__a)[3]}) + +/*Transform v2u32 to v4u32*/ +#define msa_movl_u32(__a) ((v2u64){(__a)[0], (__a)[1]}) + +/* Copies the least significant half of each element of a 128 bits vector into the corresponding elements of a 64 bits vector. */ +#define msa_movn_s16(__a) \ +({ \ + v16i8 __d = __builtin_msa_pckev_b(__builtin_msa_fill_b(0), (v16i8)(__a)); \ + (v8i8)__builtin_msa_copy_s_d((v2i64)__d, 0); \ +}) + +#define msa_movn_s32(__a) \ +({ \ + v8i16 __d = __builtin_msa_pckev_h(__builtin_msa_fill_h(0), (v8i16)(__a)); \ + (v4i16)__builtin_msa_copy_s_d((v2i64)__d, 0); \ +}) + +#define msa_movn_s64(__a) \ +({ \ + v4i32 __d = __builtin_msa_pckev_w(__builtin_msa_fill_w(0), (v4i32)(__a)); \ + (v2i32)__builtin_msa_copy_s_d((v2i64)__d, 0); \ +}) + +#define msa_movn_u16(__a) \ +({ \ + v16i8 __d = __builtin_msa_pckev_b(__builtin_msa_fill_b(0), (v16i8)(__a)); \ + (v8u8)__builtin_msa_copy_u_d((v2i64)__d, 0); \ +}) + +#define msa_movn_u32(__a) \ +({ \ + v8i16 __d = __builtin_msa_pckev_h(__builtin_msa_fill_h(0), (v8i16)(__a)); \ + (v4u16)__builtin_msa_copy_u_d((v2i64)__d, 0); \ +}) + +#define msa_movn_u64(__a) \ +({ \ + v4i32 __d = __builtin_msa_pckev_w(__builtin_msa_fill_w(0), (v4i32)(__a)); \ + (v2u32)__builtin_msa_copy_u_d((v2i64)__d, 0); \ +}) + +/* qmovn */ +#define msa_qmovn_s16(__a) \ +({ \ + v16i8 __d = __builtin_msa_pckev_b(__builtin_msa_fill_b(0), (v16i8)__builtin_msa_sat_s_h((v8i16)(__a), 7)); \ + (v8i8)__builtin_msa_copy_s_d((v2i64)__d, 0); \ +}) + +#define msa_qmovn_s32(__a) \ +({ \ + v8i16 __d = __builtin_msa_pckev_h(__builtin_msa_fill_h(0), (v8i16)__builtin_msa_sat_s_w((v4i32)(__a), 15)); \ + (v4i16)__builtin_msa_copy_s_d((v2i64)__d, 0); \ +}) + +#define msa_qmovn_s64(__a) \ +({ \ + v4i32 __d = __builtin_msa_pckev_w(__builtin_msa_fill_w(0), (v4i32)__builtin_msa_sat_s_d((v2i64)(__a), 31)); \ + (v2i32)__builtin_msa_copy_s_d((v2i64)__d, 0); \ +}) + +#define msa_qmovn_u16(__a) \ +({ \ + v16i8 __d = __builtin_msa_pckev_b(__builtin_msa_fill_b(0), (v16i8)__builtin_msa_sat_u_h((v8u16)(__a), 7)); \ + (v8u8)__builtin_msa_copy_u_d((v2i64)__d, 0); \ +}) + +#define msa_qmovn_u32(__a) \ +({ \ + v8i16 __d = __builtin_msa_pckev_h(__builtin_msa_fill_h(0), (v8i16)__builtin_msa_sat_u_w((v4u32)(__a), 15)); \ + (v4u16)__builtin_msa_copy_u_d((v2i64)__d, 0); \ +}) + +#define msa_qmovn_u64(__a) \ +({ \ + v4i32 __d = __builtin_msa_pckev_w(__builtin_msa_fill_w(0), (v4i32)__builtin_msa_sat_u_d((v2u64)(__a), 31)); \ + (v2u32)__builtin_msa_copy_u_d((v2i64)__d, 0); \ +}) + +/* qmovun */ +#define msa_qmovun_s16(__a) \ +({ \ + v8i16 __d = __builtin_msa_max_s_h(__builtin_msa_fill_h(0), (v8i16)(__a)); \ + v16i8 __e = __builtin_msa_pckev_b(__builtin_msa_fill_b(0), (v16i8)__builtin_msa_sat_u_h((v8u16)__d, 7)); \ + (v8u8)__builtin_msa_copy_u_d((v2i64)__e, 0); \ +}) + +#define msa_qmovun_s32(__a) \ +({ \ + v4i32 __d = __builtin_msa_max_s_w(__builtin_msa_fill_w(0), (v4i32)(__a)); \ + v8i16 __e = __builtin_msa_pckev_h(__builtin_msa_fill_h(0), (v8i16)__builtin_msa_sat_u_w((v4u32)__d, 15)); \ + (v4u16)__builtin_msa_copy_u_d((v2i64)__e, 0); \ +}) + +#define msa_qmovun_s64(__a) \ +({ \ + v2i64 __d = __builtin_msa_max_s_d(__builtin_msa_fill_d(0), (v2i64)(__a)); \ + v4i32 __e = __builtin_msa_pckev_w(__builtin_msa_fill_w(0), (v4i32)__builtin_msa_sat_u_d((v2u64)__d, 31)); \ + (v2u32)__builtin_msa_copy_u_d((v2i64)__e, 0); \ +}) + +/* Right shift elements in a 128 bits vector by an immediate value, and places the results in a 64 bits vector. */ +#define msa_shrn_n_s16(__a, __b) \ +({ \ + v16i8 __d = __builtin_msa_pckev_b(__builtin_msa_fill_b(0), (v16i8)__builtin_msa_srai_h((v8i16)(__a), (int)(__b))); \ + (v8i8)__builtin_msa_copy_s_d((v2i64)__d, 0); \ +}) + +#define msa_shrn_n_s32(__a, __b) \ +({ \ + v8i16 __d = __builtin_msa_pckev_h(__builtin_msa_fill_h(0), (v8i16)__builtin_msa_srai_w((v4i32)(__a), (int)(__b))); \ + (v4i16)__builtin_msa_copy_s_d((v2i64)__d, 0); \ +}) + +#define msa_shrn_n_s64(__a, __b) \ +({ \ + v4i32 __d = __builtin_msa_pckev_w(__builtin_msa_fill_w(0), (v4i32)__builtin_msa_srai_d((v2i64)(__a), (int)(__b))); \ + (v2i32)__builtin_msa_copy_s_d((v2i64)__d, 0); \ +}) + +#define msa_shrn_n_u16(__a, __b) \ +({ \ + v16i8 __d = __builtin_msa_pckev_b(__builtin_msa_fill_b(0), (v16i8)__builtin_msa_srli_h((v8i16)(__a), (int)(__b))); \ + (v8u8)__builtin_msa_copy_u_d((v2i64)__d, 0); \ +}) + +#define msa_shrn_n_u32(__a, __b) \ +({ \ + v8i16 __d = __builtin_msa_pckev_h(__builtin_msa_fill_h(0), (v8i16)__builtin_msa_srli_w((v4i32)(__a), (int)(__b))); \ + (v4u16)__builtin_msa_copy_u_d((v2i64)__d, 0); \ +}) + +#define msa_shrn_n_u64(__a, __b) \ +({ \ + v4i32 __d = __builtin_msa_pckev_w(__builtin_msa_fill_w(0), (v4i32)__builtin_msa_srli_d((v2i64)(__a), (int)(__b))); \ + (v2u32)__builtin_msa_copy_u_d((v2i64)__d, 0); \ +}) + +/* Right shift elements in a 128 bits vector by an immediate value, and places the results in a 64 bits vector. */ +#define msa_rshrn_n_s16(__a, __b) \ +({ \ + v16i8 __d = __builtin_msa_pckev_b(__builtin_msa_fill_b(0), (v16i8)__builtin_msa_srari_h((v8i16)(__a), (int)__b)); \ + (v8i8)__builtin_msa_copy_s_d((v2i64)__d, 0); \ +}) + +#define msa_rshrn_n_s32(__a, __b) \ +({ \ + v8i16 __d = __builtin_msa_pckev_h(__builtin_msa_fill_h(0), (v8i16)__builtin_msa_srari_w((v4i32)(__a), (int)__b)); \ + (v4i16)__builtin_msa_copy_s_d((v2i64)__d, 0); \ +}) + +#define msa_rshrn_n_s64(__a, __b) \ +({ \ + v4i32 __d = __builtin_msa_pckev_w(__builtin_msa_fill_w(0), (v4i32)__builtin_msa_srari_d((v2i64)(__a), (int)__b)); \ + (v2i32)__builtin_msa_copy_s_d((v2i64)__d, 0); \ +}) + +#define msa_rshrn_n_u16(__a, __b) \ +({ \ + v16i8 __d = __builtin_msa_pckev_b(__builtin_msa_fill_b(0), (v16i8)__builtin_msa_srlri_h((v8i16)(__a), (int)__b)); \ + (v8u8)__builtin_msa_copy_u_d((v2i64)__d, 0); \ +}) + +#define msa_rshrn_n_u32(__a, __b) \ +({ \ + v8i16 __d = __builtin_msa_pckev_h(__builtin_msa_fill_h(0), (v8i16)__builtin_msa_srlri_w((v4i32)(__a), (int)__b)); \ + (v4u16)__builtin_msa_copy_u_d((v2i64)__d, 0); \ +}) + +#define msa_rshrn_n_u64(__a, __b) \ +({ \ + v4i32 __d = __builtin_msa_pckev_w(__builtin_msa_fill_w(0), (v4i32)__builtin_msa_srlri_d((v2i64)(__a), (int)__b)); \ + (v2u32)__builtin_msa_copy_u_d((v2i64)__d, 0); \ +}) + +/* Right shift elements in a 128 bits vector by an immediate value, saturate the results and them in a 64 bits vector. */ +#define msa_qrshrn_n_s16(__a, __b) \ +({ \ + v8i16 __d = __builtin_msa_sat_s_h(__builtin_msa_srari_h((v8i16)(__a), (int)(__b)), 7); \ + v16i8 __e = __builtin_msa_pckev_b(__builtin_msa_fill_b(0), (v16i8)__d); \ + (v8i8)__builtin_msa_copy_s_d((v2i64)__e, 0); \ +}) + +#define msa_qrshrn_n_s32(__a, __b) \ +({ \ + v4i32 __d = __builtin_msa_sat_s_w(__builtin_msa_srari_w((v4i32)(__a), (int)(__b)), 15); \ + v8i16 __e = __builtin_msa_pckev_h(__builtin_msa_fill_h(0), (v8i16)__d); \ + (v4i16)__builtin_msa_copy_s_d((v2i64)__e, 0); \ +}) + +#define msa_qrshrn_n_s64(__a, __b) \ +({ \ + v2i64 __d = __builtin_msa_sat_s_d(__builtin_msa_srari_d((v2i64)(__a), (int)(__b)), 31); \ + v4i32 __e = __builtin_msa_pckev_w(__builtin_msa_fill_w(0), (v4i32)__d); \ + (v2i32)__builtin_msa_copy_s_d((v2i64)__e, 0); \ +}) + +#define msa_qrshrn_n_u16(__a, __b) \ +({ \ + v8u16 __d = __builtin_msa_sat_u_h((v8u16)__builtin_msa_srlri_h((v8i16)(__a), (int)(__b)), 7); \ + v16i8 __e = __builtin_msa_pckev_b(__builtin_msa_fill_b(0), (v16i8)__d); \ + (v8u8)__builtin_msa_copy_u_d((v2i64)__e, 0); \ +}) + +#define msa_qrshrn_n_u32(__a, __b) \ +({ \ + v4u32 __d = __builtin_msa_sat_u_w((v4u32)__builtin_msa_srlri_w((v4i32)(__a), (int)(__b)), 15); \ + v8i16 __e = __builtin_msa_pckev_h(__builtin_msa_fill_h(0), (v8i16)__d); \ + (v4u16)__builtin_msa_copy_u_d((v2i64)__e, 0); \ +}) + +#define msa_qrshrn_n_u64(__a, __b) \ +({ \ + v2u64 __d = __builtin_msa_sat_u_d((v2u64)__builtin_msa_srlri_d((v2i64)(__a), (int)(__b)), 31); \ + v4i32 __e = __builtin_msa_pckev_w(__builtin_msa_fill_w(0), (v4i32)__d); \ + (v2u32)__builtin_msa_copy_u_d((v2i64)__e, 0); \ +}) + +/* Right shift elements in a 128 bits vector by an immediate value, saturate the results and them in a 64 bits vector. + Input is signed and output is unsigned. */ +#define msa_qrshrun_n_s16(__a, __b) \ +({ \ + v8i16 __d = __builtin_msa_srlri_h(__builtin_msa_max_s_h(__builtin_msa_fill_h(0), (v8i16)(__a)), (int)(__b)); \ + v16i8 __e = __builtin_msa_pckev_b(__builtin_msa_fill_b(0), (v16i8)__builtin_msa_sat_u_h((v8u16)__d, 7)); \ + (v8u8)__builtin_msa_copy_u_d((v2i64)__e, 0); \ +}) + +#define msa_qrshrun_n_s32(__a, __b) \ +({ \ + v4i32 __d = __builtin_msa_srlri_w(__builtin_msa_max_s_w(__builtin_msa_fill_w(0), (v4i32)(__a)), (int)(__b)); \ + v8i16 __e = __builtin_msa_pckev_h(__builtin_msa_fill_h(0), (v8i16)__builtin_msa_sat_u_w((v4u32)__d, 15)); \ + (v4u16)__builtin_msa_copy_u_d((v2i64)__e, 0); \ +}) + +#define msa_qrshrun_n_s64(__a, __b) \ +({ \ + v2i64 __d = __builtin_msa_srlri_d(__builtin_msa_max_s_d(__builtin_msa_fill_d(0), (v2i64)(__a)), (int)(__b)); \ + v4i32 __e = __builtin_msa_pckev_w(__builtin_msa_fill_w(0), (v4i32)__builtin_msa_sat_u_d((v2u64)__d, 31)); \ + (v2u32)__builtin_msa_copy_u_d((v2i64)__e, 0); \ +}) + +/* pack */ +#define msa_pack_s16(__a, __b) (__builtin_msa_pckev_b((v16i8)(__b), (v16i8)(__a))) +#define msa_pack_s32(__a, __b) (__builtin_msa_pckev_h((v8i16)(__b), (v8i16)(__a))) +#define msa_pack_s64(__a, __b) (__builtin_msa_pckev_w((v4i32)(__b), (v4i32)(__a))) +#define msa_pack_u16(__a, __b) ((v16u8)__builtin_msa_pckev_b((v16i8)(__b), (v16i8)(__a))) +#define msa_pack_u32(__a, __b) ((v8u16)__builtin_msa_pckev_h((v8i16)(__b), (v8i16)(__a))) +#define msa_pack_u64(__a, __b) ((v4u32)__builtin_msa_pckev_w((v4i32)(__b), (v4i32)(__a))) + +/* qpack */ +#define msa_qpack_s16(__a, __b) \ +(__builtin_msa_pckev_b((v16i8)__builtin_msa_sat_s_h((v8i16)(__b), 7), (v16i8)__builtin_msa_sat_s_h((v8i16)(__a), 7))) +#define msa_qpack_s32(__a, __b) \ +(__builtin_msa_pckev_h((v8i16)__builtin_msa_sat_s_w((v4i32)(__b), 15), (v8i16)__builtin_msa_sat_s_w((v4i32)(__a), 15))) +#define msa_qpack_s64(__a, __b) \ +(__builtin_msa_pckev_w((v4i32)__builtin_msa_sat_s_d((v2i64)(__b), 31), (v4i32)__builtin_msa_sat_s_d((v2i64)(__a), 31))) +#define msa_qpack_u16(__a, __b) \ +((v16u8)__builtin_msa_pckev_b((v16i8)__builtin_msa_sat_u_h((v8u16)(__b), 7), (v16i8)__builtin_msa_sat_u_h((v8u16)(__a), 7))) +#define msa_qpack_u32(__a, __b) \ +((v8u16)__builtin_msa_pckev_h((v8i16)__builtin_msa_sat_u_w((v4u32)(__b), 15), (v8i16)__builtin_msa_sat_u_w((v4u32)(__a), 15))) +#define msa_qpack_u64(__a, __b) \ +((v4u32)__builtin_msa_pckev_w((v4i32)__builtin_msa_sat_u_d((v2u64)(__b), 31), (v4i32)__builtin_msa_sat_u_d((v2u64)(__a), 31))) + +/* qpacku */ +#define msa_qpacku_s16(__a, __b) \ +((v16u8)__builtin_msa_pckev_b((v16i8)__builtin_msa_sat_u_h((v8u16)(__builtin_msa_max_s_h(__builtin_msa_fill_h(0), (v8i16)(__b))), 7), \ + (v16i8)__builtin_msa_sat_u_h((v8u16)(__builtin_msa_max_s_h(__builtin_msa_fill_h(0), (v8i16)(__a))), 7))) +#define msa_qpacku_s32(__a, __b) \ +((v8u16)__builtin_msa_pckev_h((v8i16)__builtin_msa_sat_u_w((v4u32)(__builtin_msa_max_s_w(__builtin_msa_fill_w(0), (v4i32)(__b))), 15), \ + (v8i16)__builtin_msa_sat_u_w((v4u32)(__builtin_msa_max_s_w(__builtin_msa_fill_w(0), (v4i32)(__a))), 15))) +#define msa_qpacku_s64(__a, __b) \ +((v4u32)__builtin_msa_pckev_w((v4i32)__builtin_msa_sat_u_d((v2u64)(__builtin_msa_max_s_d(__builtin_msa_fill_d(0), (v2i64)(__b))), 31), \ + (v4i32)__builtin_msa_sat_u_d((v2u64)(__builtin_msa_max_s_d(__builtin_msa_fill_d(0), (v2i64)(__a))), 31))) + +/* packr */ +#define msa_packr_s16(__a, __b, __c) \ +(__builtin_msa_pckev_b((v16i8)__builtin_msa_srai_h((v8i16)(__b), (int)(__c)), (v16i8)__builtin_msa_srai_h((v8i16)(__a), (int)(__c)))) +#define msa_packr_s32(__a, __b, __c) \ +(__builtin_msa_pckev_h((v8i16)__builtin_msa_srai_w((v4i32)(__b), (int)(__c)), (v8i16)__builtin_msa_srai_w((v4i32)(__a), (int)(__c)))) +#define msa_packr_s64(__a, __b, __c) \ +(__builtin_msa_pckev_w((v4i32)__builtin_msa_srai_d((v2i64)(__b), (int)(__c)), (v4i32)__builtin_msa_srai_d((v2i64)(__a), (int)(__c)))) +#define msa_packr_u16(__a, __b, __c) \ +((v16u8)__builtin_msa_pckev_b((v16i8)__builtin_msa_srli_h((v8i16)(__b), (int)(__c)), (v16i8)__builtin_msa_srli_h((v8i16)(__a), (int)(__c)))) +#define msa_packr_u32(__a, __b, __c) \ +((v8u16)__builtin_msa_pckev_h((v8i16)__builtin_msa_srli_w((v4i32)(__b), (int)(__c)), (v8i16)__builtin_msa_srli_w((v4i32)(__a), (int)(__c)))) +#define msa_packr_u64(__a, __b, __c) \ +((v4u32)__builtin_msa_pckev_w((v4i32)__builtin_msa_srli_d((v2i64)(__b), (int)(__c)), (v4i32)__builtin_msa_srli_d((v2i64)(__a), (int)(__c)))) + +/* rpackr */ +#define msa_rpackr_s16(__a, __b, __c) \ +(__builtin_msa_pckev_b((v16i8)__builtin_msa_srari_h((v8i16)(__b), (int)(__c)), (v16i8)__builtin_msa_srari_h((v8i16)(__a), (int)(__c)))) +#define msa_rpackr_s32(__a, __b, __c) \ +(__builtin_msa_pckev_h((v8i16)__builtin_msa_srari_w((v4i32)(__b), (int)(__c)), (v8i16)__builtin_msa_srari_w((v4i32)(__a), (int)(__c)))) +#define msa_rpackr_s64(__a, __b, __c) \ +(__builtin_msa_pckev_w((v4i32)__builtin_msa_srari_d((v2i64)(__b), (int)(__c)), (v4i32)__builtin_msa_srari_d((v2i64)(__a), (int)(__c)))) +#define msa_rpackr_u16(__a, __b, __c) \ +((v16u8)__builtin_msa_pckev_b((v16i8)__builtin_msa_srlri_h((v8i16)(__b), (int)(__c)), (v16i8)__builtin_msa_srlri_h((v8i16)(__a), (int)(__c)))) +#define msa_rpackr_u32(__a, __b, __c) \ +((v8u16)__builtin_msa_pckev_h((v8i16)__builtin_msa_srlri_w((v4i32)(__b), (int)(__c)), (v8i16)__builtin_msa_srlri_w((v4i32)(__a), (int)(__c)))) +#define msa_rpackr_u64(__a, __b, __c) \ +((v4u32)__builtin_msa_pckev_w((v4i32)__builtin_msa_srlri_d((v2i64)(__b), (int)(__c)), (v4i32)__builtin_msa_srlri_d((v2i64)(__a), (int)(__c)))) + +/* qrpackr */ +#define msa_qrpackr_s16(__a, __b, __c) \ +(__builtin_msa_pckev_b((v16i8)__builtin_msa_sat_s_h(__builtin_msa_srari_h((v8i16)(__b), (int)(__c)), 7), \ + (v16i8)__builtin_msa_sat_s_h(__builtin_msa_srari_h((v8i16)(__a), (int)(__c)), 7))) +#define msa_qrpackr_s32(__a, __b, __c) \ +(__builtin_msa_pckev_h((v8i16)__builtin_msa_sat_s_w(__builtin_msa_srari_w((v4i32)(__b), (int)(__c)), 15), \ + (v8i16)__builtin_msa_sat_s_w(__builtin_msa_srari_w((v4i32)(__a), (int)(__c)), 15))) +#define msa_qrpackr_s64(__a, __b, __c) \ +(__builtin_msa_pckev_w((v4i32)__builtin_msa_sat_s_d(__builtin_msa_srari_d((v2i64)(__b), (int)(__c)), 31), \ + (v4i32)__builtin_msa_sat_s_d(__builtin_msa_srari_d((v2i64)(__a), (int)(__c)), 31))) +#define msa_qrpackr_u16(__a, __b, __c) \ +((v16u8)__builtin_msa_pckev_b((v16i8)__builtin_msa_sat_u_h((v8u16)__builtin_msa_srlri_h((v8i16)(__b), (int)(__c)), 7), \ + (v16i8)__builtin_msa_sat_u_h((v8u16)__builtin_msa_srlri_h((v8i16)(__a), (int)(__c)), 7))) +#define msa_qrpackr_u32(__a, __b, __c) \ +((v8u16)__builtin_msa_pckev_h((v8i16)__builtin_msa_sat_u_w((v4u32)__builtin_msa_srlri_w((v4i32)(__b), (int)(__c)), 15), \ + (v8i16)__builtin_msa_sat_u_w((v4u32)__builtin_msa_srlri_w((v4i32)(__a), (int)(__c)), 15))) +#define msa_qrpackr_u64(__a, __b, __c) \ +((v4u32)__builtin_msa_pckev_w((v4i32)__builtin_msa_sat_u_d((v2u64)__builtin_msa_srlri_d((v2i64)(__b), (int)(__c)), 31), \ + (v4i32)__builtin_msa_sat_u_d((v2u64)__builtin_msa_srlri_d((v2i64)(__a), (int)(__c)), 31))) + +/* qrpackru */ +#define msa_qrpackru_s16(__a, __b, __c) \ +({ \ + v8i16 __d = __builtin_msa_srlri_h(__builtin_msa_max_s_h(__builtin_msa_fill_h(0), (v8i16)(__a)), (int)(__c)); \ + v8i16 __e = __builtin_msa_srlri_h(__builtin_msa_max_s_h(__builtin_msa_fill_h(0), (v8i16)(__b)), (int)(__c)); \ + (v16u8)__builtin_msa_pckev_b((v16i8)__builtin_msa_sat_u_h((v8u16)__e, 7), (v16i8)__builtin_msa_sat_u_h((v8u16)__d, 7)); \ +}) + +#define msa_qrpackru_s32(__a, __b, __c) \ +({ \ + v4i32 __d = __builtin_msa_srlri_w(__builtin_msa_max_s_w(__builtin_msa_fill_w(0), (v4i32)(__a)), (int)(__c)); \ + v4i32 __e = __builtin_msa_srlri_w(__builtin_msa_max_s_w(__builtin_msa_fill_w(0), (v4i32)(__b)), (int)(__c)); \ + (v8u16)__builtin_msa_pckev_h((v8i16)__builtin_msa_sat_u_w((v4u32)__e, 15), (v8i16)__builtin_msa_sat_u_w((v4u32)__d, 15)); \ +}) + +#define msa_qrpackru_s64(__a, __b, __c) \ +({ \ + v2i64 __d = __builtin_msa_srlri_d(__builtin_msa_max_s_d(__builtin_msa_fill_d(0), (v2i64)(__a)), (int)(__c)); \ + v2i64 __e = __builtin_msa_srlri_d(__builtin_msa_max_s_d(__builtin_msa_fill_d(0), (v2i64)(__b)), (int)(__c)); \ + (v4u32)__builtin_msa_pckev_w((v4i32)__builtin_msa_sat_u_d((v2u64)__e, 31), (v4i32)__builtin_msa_sat_u_d((v2u64)__d, 31)); \ +}) + +/* Minimum values between corresponding elements in the two vectors are written to the returned vector. */ +#define msa_minq_s8(__a, __b) (__builtin_msa_min_s_b(__a, __b)) +#define msa_minq_s16(__a, __b) (__builtin_msa_min_s_h(__a, __b)) +#define msa_minq_s32(__a, __b) (__builtin_msa_min_s_w(__a, __b)) +#define msa_minq_s64(__a, __b) (__builtin_msa_min_s_d(__a, __b)) +#define msa_minq_u8(__a, __b) ((v16u8)__builtin_msa_min_u_b(__a, __b)) +#define msa_minq_u16(__a, __b) ((v8u16)__builtin_msa_min_u_h(__a, __b)) +#define msa_minq_u32(__a, __b) ((v4u32)__builtin_msa_min_u_w(__a, __b)) +#define msa_minq_u64(__a, __b) ((v2u64)__builtin_msa_min_u_d(__a, __b)) +#define msa_minq_f32(__a, __b) (__builtin_msa_fmin_w(__a, __b)) +#define msa_minq_f64(__a, __b) (__builtin_msa_fmin_d(__a, __b)) + +/* Maximum values between corresponding elements in the two vectors are written to the returned vector. */ +#define msa_maxq_s8(__a, __b) (__builtin_msa_max_s_b(__a, __b)) +#define msa_maxq_s16(__a, __b) (__builtin_msa_max_s_h(__a, __b)) +#define msa_maxq_s32(__a, __b) (__builtin_msa_max_s_w(__a, __b)) +#define msa_maxq_s64(__a, __b) (__builtin_msa_max_s_d(__a, __b)) +#define msa_maxq_u8(__a, __b) ((v16u8)__builtin_msa_max_u_b(__a, __b)) +#define msa_maxq_u16(__a, __b) ((v8u16)__builtin_msa_max_u_h(__a, __b)) +#define msa_maxq_u32(__a, __b) ((v4u32)__builtin_msa_max_u_w(__a, __b)) +#define msa_maxq_u64(__a, __b) ((v2u64)__builtin_msa_max_u_d(__a, __b)) +#define msa_maxq_f32(__a, __b) (__builtin_msa_fmax_w(__a, __b)) +#define msa_maxq_f64(__a, __b) (__builtin_msa_fmax_d(__a, __b)) + +/* Vector type reinterpretion */ +#define MSA_TPV_REINTERPRET(_Tpv, Vec) ((_Tpv)(Vec)) + +/* Add the odd elements in vector __a with the even elements in vector __b to double width elements in the returned vector. */ +/* v8i16 msa_hadd_s16 ((v16i8)__a, (v16i8)__b) */ +#define msa_hadd_s16(__a, __b) (__builtin_msa_hadd_s_h((v16i8)(__a), (v16i8)(__b))) +/* v4i32 msa_hadd_s32 ((v8i16)__a, (v8i16)__b) */ +#define msa_hadd_s32(__a, __b) (__builtin_msa_hadd_s_w((v8i16)(__a), (v8i16)(__b))) +/* v2i64 msa_hadd_s64 ((v4i32)__a, (v4i32)__b) */ +#define msa_hadd_s64(__a, __b) (__builtin_msa_hadd_s_d((v4i32)(__a), (v4i32)(__b))) + +/* Copy even elements in __a to the left half and even elements in __b to the right half and return the result vector. */ +#define msa_pckev_s8(__a, __b) (__builtin_msa_pckev_b((v16i8)(__a), (v16i8)(__b))) +#define msa_pckev_s16(__a, __b) (__builtin_msa_pckev_h((v8i16)(__a), (v8i16)(__b))) +#define msa_pckev_s32(__a, __b) (__builtin_msa_pckev_w((v4i32)(__a), (v4i32)(__b))) +#define msa_pckev_s64(__a, __b) (__builtin_msa_pckev_d((v2i64)(__a), (v2i64)(__b))) + +/* Copy even elements in __a to the left half and even elements in __b to the right half and return the result vector. */ +#define msa_pckod_s8(__a, __b) (__builtin_msa_pckod_b((v16i8)(__a), (v16i8)(__b))) +#define msa_pckod_s16(__a, __b) (__builtin_msa_pckod_h((v8i16)(__a), (v8i16)(__b))) +#define msa_pckod_s32(__a, __b) (__builtin_msa_pckod_w((v4i32)(__a), (v4i32)(__b))) +#define msa_pckod_s64(__a, __b) (__builtin_msa_pckod_d((v2i64)(__a), (v2i64)(__b))) + +#ifdef _MIPSEB +#define LANE_IMM0_1(x) (0b1 - ((x) & 0b1)) +#define LANE_IMM0_3(x) (0b11 - ((x) & 0b11)) +#define LANE_IMM0_7(x) (0b111 - ((x) & 0b111)) +#define LANE_IMM0_15(x) (0b1111 - ((x) & 0b1111)) +#else +#define LANE_IMM0_1(x) ((x) & 0b1) +#define LANE_IMM0_3(x) ((x) & 0b11) +#define LANE_IMM0_7(x) ((x) & 0b111) +#define LANE_IMM0_15(x) ((x) & 0b1111) +#endif + +#define msa_get_lane_u8(__a, __b) ((uint8_t)(__a)[LANE_IMM0_7(__b)]) +#define msa_get_lane_s8(__a, __b) ((int8_t)(__a)[LANE_IMM0_7(__b)]) +#define msa_get_lane_u16(__a, __b) ((uint16_t)(__a)[LANE_IMM0_3(__b)]) +#define msa_get_lane_s16(__a, __b) ((int16_t)(__a)[LANE_IMM0_3(__b)]) +#define msa_get_lane_u32(__a, __b) ((uint32_t)(__a)[LANE_IMM0_1(__b)]) +#define msa_get_lane_s32(__a, __b) ((int32_t)(__a)[LANE_IMM0_1(__b)]) +#define msa_get_lane_f32(__a, __b) ((float)(__a)[LANE_IMM0_3(__b)]) +#define msa_get_lane_s64(__a, __b) ((int64_t)(__a)[LANE_IMM0_1(__b)]) +#define msa_get_lane_u64(__a, __b) ((uint64_t)(__a)[LANE_IMM0_1(__b)]) +#define msa_get_lane_f64(__a, __b) ((double)(__a)[LANE_IMM0_1(__b)]) +#define msa_getq_lane_u8(__a, imm0_15) ((uint8_t)__builtin_msa_copy_u_b((v16i8)(__a), imm0_15)) +#define msa_getq_lane_s8(__a, imm0_15) ((int8_t)__builtin_msa_copy_s_b(__a, imm0_15)) +#define msa_getq_lane_u16(__a, imm0_7) ((uint16_t)__builtin_msa_copy_u_h((v8i16)(__a), imm0_7)) +#define msa_getq_lane_s16(__a, imm0_7) ((int16_t)__builtin_msa_copy_s_h(__a, imm0_7)) +#define msa_getq_lane_u32(__a, imm0_3) __builtin_msa_copy_u_w((v4i32)(__a), imm0_3) +#define msa_getq_lane_s32 __builtin_msa_copy_s_w +#define msa_getq_lane_f32(__a, __b) ((float)(__a)[LANE_IMM0_3(__b)]) +#define msa_getq_lane_f64(__a, __b) ((double)(__a)[LANE_IMM0_1(__b)]) +#if (__mips == 64) +#define msa_getq_lane_u64(__a, imm0_1) __builtin_msa_copy_u_d((v2i64)(__a), imm0_1) +#define msa_getq_lane_s64 __builtin_msa_copy_s_d +#else +#define msa_getq_lane_u64(__a, imm0_1) ((uint64_t)(__a)[LANE_IMM0_1(imm0_1)]) +#define msa_getq_lane_s64(__a, imm0_1) ((int64_t)(__a)[LANE_IMM0_1(imm0_1)]) +#endif + +/* combine */ +#if (__mips == 64) +#define __COMBINE_64_64(__TYPE, a, b) ((__TYPE)((v2u64){((v1u64)(a))[0], ((v1u64)(b))[0]})) +#else +#define __COMBINE_64_64(__TYPE, a, b) ((__TYPE)((v4u32){((v2u32)(a))[0], ((v2u32)(a))[1], \ + ((v2u32)(b))[0], ((v2u32)(b))[1]})) +#endif + +/* v16i8 msa_combine_s8 (v8i8 __a, v8i8 __b) */ +#define msa_combine_s8(__a, __b) __COMBINE_64_64(v16i8, __a, __b) + +/* v8i16 msa_combine_s16(v4i16 __a, v4i16 __b) */ +#define msa_combine_s16(__a, __b) __COMBINE_64_64(v8i16, __a, __b) + +/* v4i32 msa_combine_s32(v2i32 __a, v2i32 __b) */ +#define msa_combine_s32(__a, __b) __COMBINE_64_64(v4i32, __a, __b) + +/* v2i64 msa_combine_s64(v1i64 __a, v1i64 __b) */ +#define msa_combine_s64(__a, __b) __COMBINE_64_64(v2i64, __a, __b) + +/* v4f32 msa_combine_f32(v2f32 __a, v2f32 __b) */ +#define msa_combine_f32(__a, __b) __COMBINE_64_64(v4f32, __a, __b) + +/* v16u8 msa_combine_u8(v8u8 __a, v8u8 __b) */ +#define msa_combine_u8(__a, __b) __COMBINE_64_64(v16u8, __a, __b) + +/* v8u16 msa_combine_u16(v4u16 __a, v4u16 __b) */ +#define msa_combine_u16(__a, __b) __COMBINE_64_64(v8u16, __a, __b) + +/* v4u32 msa_combine_u32(v2u32 __a, v2u32 __b) */ +#define msa_combine_u32(__a, __b) __COMBINE_64_64(v4u32, __a, __b) + +/* v2u64 msa_combine_u64(v1u64 __a, v1u64 __b) */ +#define msa_combine_u64(__a, __b) __COMBINE_64_64(v2u64, __a, __b) + +/* v2f64 msa_combine_f64(v1f64 __a, v1f64 __b) */ +#define msa_combine_f64(__a, __b) __COMBINE_64_64(v2f64, __a, __b) + +/* get_low, get_high */ +#if (__mips == 64) +#define __GET_LOW(__TYPE, a) ((__TYPE)((v1u64)(__builtin_msa_copy_u_d((v2i64)(a), 0)))) +#define __GET_HIGH(__TYPE, a) ((__TYPE)((v1u64)(__builtin_msa_copy_u_d((v2i64)(a), 1)))) +#else +#define __GET_LOW(__TYPE, a) ((__TYPE)(((v2u64)(a))[0])) +#define __GET_HIGH(__TYPE, a) ((__TYPE)(((v2u64)(a))[1])) +#endif + +/* v8i8 msa_get_low_s8(v16i8 __a) */ +#define msa_get_low_s8(__a) __GET_LOW(v8i8, __a) + +/* v4i16 msa_get_low_s16(v8i16 __a) */ +#define msa_get_low_s16(__a) __GET_LOW(v4i16, __a) + +/* v2i32 msa_get_low_s32(v4i32 __a) */ +#define msa_get_low_s32(__a) __GET_LOW(v2i32, __a) + +/* v1i64 msa_get_low_s64(v2i64 __a) */ +#define msa_get_low_s64(__a) __GET_LOW(v1i64, __a) + +/* v8u8 msa_get_low_u8(v16u8 __a) */ +#define msa_get_low_u8(__a) __GET_LOW(v8u8, __a) + +/* v4u16 msa_get_low_u16(v8u16 __a) */ +#define msa_get_low_u16(__a) __GET_LOW(v4u16, __a) + +/* v2u32 msa_get_low_u32(v4u32 __a) */ +#define msa_get_low_u32(__a) __GET_LOW(v2u32, __a) + +/* v1u64 msa_get_low_u64(v2u64 __a) */ +#define msa_get_low_u64(__a) __GET_LOW(v1u64, __a) + +/* v2f32 msa_get_low_f32(v4f32 __a) */ +#define msa_get_low_f32(__a) __GET_LOW(v2f32, __a) + +/* v1f64 msa_get_low_f64(v2f64 __a) */ +#define msa_get_low_f64(__a) __GET_LOW(v1f64, __a) + +/* v8i8 msa_get_high_s8(v16i8 __a) */ +#define msa_get_high_s8(__a) __GET_HIGH(v8i8, __a) + +/* v4i16 msa_get_high_s16(v8i16 __a) */ +#define msa_get_high_s16(__a) __GET_HIGH(v4i16, __a) + +/* v2i32 msa_get_high_s32(v4i32 __a) */ +#define msa_get_high_s32(__a) __GET_HIGH(v2i32, __a) + +/* v1i64 msa_get_high_s64(v2i64 __a) */ +#define msa_get_high_s64(__a) __GET_HIGH(v1i64, __a) + +/* v8u8 msa_get_high_u8(v16u8 __a) */ +#define msa_get_high_u8(__a) __GET_HIGH(v8u8, __a) + +/* v4u16 msa_get_high_u16(v8u16 __a) */ +#define msa_get_high_u16(__a) __GET_HIGH(v4u16, __a) + +/* v2u32 msa_get_high_u32(v4u32 __a) */ +#define msa_get_high_u32(__a) __GET_HIGH(v2u32, __a) + +/* v1u64 msa_get_high_u64(v2u64 __a) */ +#define msa_get_high_u64(__a) __GET_HIGH(v1u64, __a) + +/* v2f32 msa_get_high_f32(v4f32 __a) */ +#define msa_get_high_f32(__a) __GET_HIGH(v2f32, __a) + +/* v1f64 msa_get_high_f64(v2f64 __a) */ +#define msa_get_high_f64(__a) __GET_HIGH(v1f64, __a) + +/* ri = ai * b[lane] */ +/* v4f32 msa_mulq_lane_f32(v4f32 __a, v4f32 __b, const int __lane) */ +#define msa_mulq_lane_f32(__a, __b, __lane) ((__a) * msa_getq_lane_f32(__b, __lane)) + +/* ri = ai + bi * c[lane] */ +/* v4f32 msa_mlaq_lane_f32(v4f32 __a, v4f32 __b, v4f32 __c, const int __lane) */ +#define msa_mlaq_lane_f32(__a, __b, __c, __lane) ((__a) + ((__b) * msa_getq_lane_f32(__c, __lane))) + +/* uint16_t msa_sum_u16(v8u16 __a)*/ +#define msa_sum_u16(__a) \ +({ \ + v4u32 _b; \ + v2u64 _c; \ + _b = __builtin_msa_hadd_u_w(__a, __a); \ + _c = __builtin_msa_hadd_u_d(_b, _b); \ + (uint16_t)(_c[0] + _c[1]); \ +}) + +/* int16_t msa_sum_s16(v8i16 __a) */ +#define msa_sum_s16(__a) \ +({ \ + v4i32 _b; \ + v2i64 _c; \ + _b = __builtin_msa_hadd_s_w(__a, __a); \ + _c = __builtin_msa_hadd_s_d(_b, _b); \ + (int32_t)(_c[0] + _c[1]); \ +}) + + +/* uint32_t msa_sum_u32(v4u32 __a)*/ +#define msa_sum_u32(__a) \ +({ \ + v2u64 _b; \ + _b = __builtin_msa_hadd_u_d(__a, __a); \ + (uint32_t)(_b[0] + _b[1]); \ +}) + +/* int32_t msa_sum_s32(v4i32 __a)*/ +#define msa_sum_s32(__a) \ +({ \ + v2i64 _b; \ + _b = __builtin_msa_hadd_s_d(__a, __a); \ + (int64_t)(_b[0] + _b[1]); \ +}) + +/* uint8_t msa_sum_u8(v16u8 __a)*/ +#define msa_sum_u8(__a) \ +({ \ + v8u16 _b16; \ + v4u32 _c32; \ + _b16 = __builtin_msa_hadd_u_h(__a, __a); \ + _c32 = __builtin_msa_hadd_u_w(_b16, _b16); \ + (uint8_t)msa_sum_u32(_c32); \ +}) + +/* int8_t msa_sum_s8(v16s8 __a)*/ +#define msa_sum_s8(__a) \ +({ \ + v8i16 _b16; \ + v4i32 _c32; \ + _b16 = __builtin_msa_hadd_s_h(__a, __a); \ + _c32 = __builtin_msa_hadd_s_w(_b16, _b16); \ + (int16_t)msa_sum_s32(_c32); \ +}) + +/* float msa_sum_f32(v4f32 __a)*/ +#define msa_sum_f32(__a) ((__a)[0] + (__a)[1] + (__a)[2] + (__a)[3]) + +/* v8u16 msa_paddlq_u8(v16u8 __a) */ +#define msa_paddlq_u8(__a) (__builtin_msa_hadd_u_h(__a, __a)) + +/* v8i16 msa_paddlq_s8(v16i8 __a) */ +#define msa_paddlq_s8(__a) (__builtin_msa_hadd_s_h(__a, __a)) + +/* v4u32 msa_paddlq_u16 (v8u16 __a)*/ +#define msa_paddlq_u16(__a) (__builtin_msa_hadd_u_w(__a, __a)) + +/* v4i32 msa_paddlq_s16 (v8i16 __a)*/ +#define msa_paddlq_s16(__a) (__builtin_msa_hadd_s_w(__a, __a)) + +/* v2u64 msa_paddlq_u32(v4u32 __a) */ +#define msa_paddlq_u32(__a) (__builtin_msa_hadd_u_d(__a, __a)) + +/* v2i64 msa_paddlq_s32(v4i32 __a) */ +#define msa_paddlq_s32(__a) (__builtin_msa_hadd_s_d(__a, __a)) + +#define V8U8_2_V8U16(x) {(uint16_t)x[0], (uint16_t)x[1], (uint16_t)x[2], (uint16_t)x[3], \ + (uint16_t)x[4], (uint16_t)x[5], (uint16_t)x[6], (uint16_t)x[7]} +#define V8U8_2_V8I16(x) {(int16_t)x[0], (int16_t)x[1], (int16_t)x[2], (int16_t)x[3], \ + (int16_t)x[4], (int16_t)x[5], (int16_t)x[6], (int16_t)x[7]} +#define V8I8_2_V8I16(x) {(int16_t)x[0], (int16_t)x[1], (int16_t)x[2], (int16_t)x[3], \ + (int16_t)x[4], (int16_t)x[5], (int16_t)x[6], (int16_t)x[7]} +#define V4U16_2_V4U32(x) {(uint32_t)x[0], (uint32_t)x[1], (uint32_t)x[2], (uint32_t)x[3]} +#define V4U16_2_V4I32(x) {(int32_t)x[0], (int32_t)x[1], (int32_t)x[2], (int32_t)x[3]} +#define V4I16_2_V4I32(x) {(int32_t)x[0], (int32_t)x[1], (int32_t)x[2], (int32_t)x[3]} +#define V2U32_2_V2U64(x) {(uint64_t)x[0], (uint64_t)x[1]} +#define V2U32_2_V2I64(x) {(int64_t)x[0], (int64_t)x[1]} + +/* v8u16 msa_mull_u8(v8u8 __a, v8u8 __b) */ +#define msa_mull_u8(__a, __b) ((v8u16)__builtin_msa_mulv_h((v8i16)V8U8_2_V8I16(__a), (v8i16)V8U8_2_V8I16(__b))) + +/* v8i16 msa_mull_s8(v8i8 __a, v8i8 __b)*/ +#define msa_mull_s8(__a, __b) (__builtin_msa_mulv_h((v8i16)V8I8_2_V8I16(__a), (v8i16)V8I8_2_V8I16(__b))) + +/* v4u32 msa_mull_u16(v4u16 __a, v4u16 __b) */ +#define msa_mull_u16(__a, __b) ((v4u32)__builtin_msa_mulv_w((v4i32)V4U16_2_V4I32(__a), (v4i32)V4U16_2_V4I32(__b))) + +/* v4i32 msa_mull_s16(v4i16 __a, v4i16 __b) */ +#define msa_mull_s16(__a, __b) (__builtin_msa_mulv_w((v4i32)V4I16_2_V4I32(__a), (v4i32)V4I16_2_V4I32(__b))) + +/* v2u64 msa_mull_u32(v2u32 __a, v2u32 __b) */ +#define msa_mull_u32(__a, __b) ((v2u64)__builtin_msa_mulv_d((v2i64)V2U32_2_V2I64(__a), (v2i64)V2U32_2_V2I64(__b))) + +/* bitwise and: __builtin_msa_and_v */ +#define msa_andq_u8(__a, __b) ((v16u8)__builtin_msa_and_v((v16u8)(__a), (v16u8)(__b))) +#define msa_andq_s8(__a, __b) ((v16i8)__builtin_msa_and_v((v16u8)(__a), (v16u8)(__b))) +#define msa_andq_u16(__a, __b) ((v8u16)__builtin_msa_and_v((v16u8)(__a), (v16u8)(__b))) +#define msa_andq_s16(__a, __b) ((v8i16)__builtin_msa_and_v((v16u8)(__a), (v16u8)(__b))) +#define msa_andq_u32(__a, __b) ((v4u32)__builtin_msa_and_v((v16u8)(__a), (v16u8)(__b))) +#define msa_andq_s32(__a, __b) ((v4i32)__builtin_msa_and_v((v16u8)(__a), (v16u8)(__b))) +#define msa_andq_u64(__a, __b) ((v2u64)__builtin_msa_and_v((v16u8)(__a), (v16u8)(__b))) +#define msa_andq_s64(__a, __b) ((v2i64)__builtin_msa_and_v((v16u8)(__a), (v16u8)(__b))) + +/* bitwise or: __builtin_msa_or_v */ +#define msa_orrq_u8(__a, __b) ((v16u8)__builtin_msa_or_v((v16u8)(__a), (v16u8)(__b))) +#define msa_orrq_s8(__a, __b) ((v16i8)__builtin_msa_or_v((v16u8)(__a), (v16u8)(__b))) +#define msa_orrq_u16(__a, __b) ((v8u16)__builtin_msa_or_v((v16u8)(__a), (v16u8)(__b))) +#define msa_orrq_s16(__a, __b) ((v8i16)__builtin_msa_or_v((v16u8)(__a), (v16u8)(__b))) +#define msa_orrq_u32(__a, __b) ((v4u32)__builtin_msa_or_v((v16u8)(__a), (v16u8)(__b))) +#define msa_orrq_s32(__a, __b) ((v4i32)__builtin_msa_or_v((v16u8)(__a), (v16u8)(__b))) +#define msa_orrq_u64(__a, __b) ((v2u64)__builtin_msa_or_v((v16u8)(__a), (v16u8)(__b))) +#define msa_orrq_s64(__a, __b) ((v2i64)__builtin_msa_or_v((v16u8)(__a), (v16u8)(__b))) + +/* bitwise xor: __builtin_msa_xor_v */ +#define msa_eorq_u8(__a, __b) ((v16u8)__builtin_msa_xor_v((v16u8)(__a), (v16u8)(__b))) +#define msa_eorq_s8(__a, __b) ((v16i8)__builtin_msa_xor_v((v16u8)(__a), (v16u8)(__b))) +#define msa_eorq_u16(__a, __b) ((v8u16)__builtin_msa_xor_v((v16u8)(__a), (v16u8)(__b))) +#define msa_eorq_s16(__a, __b) ((v8i16)__builtin_msa_xor_v((v16u8)(__a), (v16u8)(__b))) +#define msa_eorq_u32(__a, __b) ((v4u32)__builtin_msa_xor_v((v16u8)(__a), (v16u8)(__b))) +#define msa_eorq_s32(__a, __b) ((v4i32)__builtin_msa_xor_v((v16u8)(__a), (v16u8)(__b))) +#define msa_eorq_u64(__a, __b) ((v2u64)__builtin_msa_xor_v((v16u8)(__a), (v16u8)(__b))) +#define msa_eorq_s64(__a, __b) ((v2i64)__builtin_msa_xor_v((v16u8)(__a), (v16u8)(__b))) + +/* bitwise not: v16u8 __builtin_msa_xori_b (v16u8, 0xff) */ +#define msa_mvnq_u8(__a) ((v16u8)__builtin_msa_xori_b((v16u8)(__a), 0xFF)) +#define msa_mvnq_s8(__a) ((v16i8)__builtin_msa_xori_b((v16u8)(__a), 0xFF)) +#define msa_mvnq_u16(__a) ((v8u16)__builtin_msa_xori_b((v16u8)(__a), 0xFF)) +#define msa_mvnq_s16(__a) ((v8i16)__builtin_msa_xori_b((v16u8)(__a), 0xFF)) +#define msa_mvnq_u32(__a) ((v4u32)__builtin_msa_xori_b((v16u8)(__a), 0xFF)) +#define msa_mvnq_s32(__a) ((v4i32)__builtin_msa_xori_b((v16u8)(__a), 0xFF)) +#define msa_mvnq_u64(__a) ((v2u64)__builtin_msa_xori_b((v16u8)(__a), 0xFF)) +#define msa_mvnq_s64(__a) ((v2i64)__builtin_msa_xori_b((v16u8)(__a), 0xFF)) + +/* compare equal: ceq -> ri = ai == bi ? 1...1:0...0 */ +#define msa_ceqq_u8(__a, __b) ((v16u8)__builtin_msa_ceq_b((v16i8)(__a), (v16i8)(__b))) +#define msa_ceqq_s8(__a, __b) ((v16u8)__builtin_msa_ceq_b((v16i8)(__a), (v16i8)(__b))) +#define msa_ceqq_u16(__a, __b) ((v8u16)__builtin_msa_ceq_h((v8i16)(__a), (v8i16)(__b))) +#define msa_ceqq_s16(__a, __b) ((v8u16)__builtin_msa_ceq_h((v8i16)(__a), (v8i16)(__b))) +#define msa_ceqq_u32(__a, __b) ((v4u32)__builtin_msa_ceq_w((v4i32)(__a), (v4i32)(__b))) +#define msa_ceqq_s32(__a, __b) ((v4u32)__builtin_msa_ceq_w((v4i32)(__a), (v4i32)(__b))) +#define msa_ceqq_f32(__a, __b) ((v4u32)__builtin_msa_fceq_w((v4f32)(__a), (v4f32)(__b))) +#define msa_ceqq_u64(__a, __b) ((v2u64)__builtin_msa_ceq_d((v2i64)(__a), (v2i64)(__b))) +#define msa_ceqq_s64(__a, __b) ((v2u64)__builtin_msa_ceq_d((v2i64)(__a), (v2i64)(__b))) +#define msa_ceqq_f64(__a, __b) ((v2u64)__builtin_msa_fceq_d((v2f64)(__a), (v2f64)(__b))) + +/* Compare less-than: clt -> ri = ai < bi ? 1...1:0...0 */ +#define msa_cltq_u8(__a, __b) ((v16u8)__builtin_msa_clt_u_b((v16u8)(__a), (v16u8)(__b))) +#define msa_cltq_s8(__a, __b) ((v16u8)__builtin_msa_clt_s_b((v16i8)(__a), (v16i8)(__b))) +#define msa_cltq_u16(__a, __b) ((v8u16)__builtin_msa_clt_u_h((v8u16)(__a), (v8u16)(__b))) +#define msa_cltq_s16(__a, __b) ((v8u16)__builtin_msa_clt_s_h((v8i16)(__a), (v8i16)(__b))) +#define msa_cltq_u32(__a, __b) ((v4u32)__builtin_msa_clt_u_w((v4u32)(__a), (v4u32)(__b))) +#define msa_cltq_s32(__a, __b) ((v4u32)__builtin_msa_clt_s_w((v4i32)(__a), (v4i32)(__b))) +#define msa_cltq_f32(__a, __b) ((v4u32)__builtin_msa_fclt_w((v4f32)(__a), (v4f32)(__b))) +#define msa_cltq_u64(__a, __b) ((v2u64)__builtin_msa_clt_u_d((v2u64)(__a), (v2u64)(__b))) +#define msa_cltq_s64(__a, __b) ((v2u64)__builtin_msa_clt_s_d((v2i64)(__a), (v2i64)(__b))) +#define msa_cltq_f64(__a, __b) ((v2u64)__builtin_msa_fclt_d((v2f64)(__a), (v2f64)(__b))) + +/* compare greater-than: cgt -> ri = ai > bi ? 1...1:0...0 */ +#define msa_cgtq_u8(__a, __b) ((v16u8)__builtin_msa_clt_u_b((v16u8)(__b), (v16u8)(__a))) +#define msa_cgtq_s8(__a, __b) ((v16u8)__builtin_msa_clt_s_b((v16i8)(__b), (v16i8)(__a))) +#define msa_cgtq_u16(__a, __b) ((v8u16)__builtin_msa_clt_u_h((v8u16)(__b), (v8u16)(__a))) +#define msa_cgtq_s16(__a, __b) ((v8u16)__builtin_msa_clt_s_h((v8i16)(__b), (v8i16)(__a))) +#define msa_cgtq_u32(__a, __b) ((v4u32)__builtin_msa_clt_u_w((v4u32)(__b), (v4u32)(__a))) +#define msa_cgtq_s32(__a, __b) ((v4u32)__builtin_msa_clt_s_w((v4i32)(__b), (v4i32)(__a))) +#define msa_cgtq_f32(__a, __b) ((v4u32)__builtin_msa_fclt_w((v4f32)(__b), (v4f32)(__a))) +#define msa_cgtq_u64(__a, __b) ((v2u64)__builtin_msa_clt_u_d((v2u64)(__b), (v2u64)(__a))) +#define msa_cgtq_s64(__a, __b) ((v2u64)__builtin_msa_clt_s_d((v2i64)(__b), (v2i64)(__a))) +#define msa_cgtq_f64(__a, __b) ((v2u64)__builtin_msa_fclt_d((v2f64)(__b), (v2f64)(__a))) + +/* compare less-equal: cle -> ri = ai <= bi ? 1...1:0...0 */ +#define msa_cleq_u8(__a, __b) ((v16u8)__builtin_msa_cle_u_b((v16u8)(__a), (v16u8)(__b))) +#define msa_cleq_s8(__a, __b) ((v16u8)__builtin_msa_cle_s_b((v16i8)(__a), (v16i8)(__b))) +#define msa_cleq_u16(__a, __b) ((v8u16)__builtin_msa_cle_u_h((v8u16)(__a), (v8u16)(__b))) +#define msa_cleq_s16(__a, __b) ((v8u16)__builtin_msa_cle_s_h((v8i16)(__a), (v8i16)(__b))) +#define msa_cleq_u32(__a, __b) ((v4u32)__builtin_msa_cle_u_w((v4u32)(__a), (v4u32)(__b))) +#define msa_cleq_s32(__a, __b) ((v4u32)__builtin_msa_cle_s_w((v4i32)(__a), (v4i32)(__b))) +#define msa_cleq_f32(__a, __b) ((v4u32)__builtin_msa_fcle_w((v4f32)(__a), (v4f32)(__b))) +#define msa_cleq_u64(__a, __b) ((v2u64)__builtin_msa_cle_u_d((v2u64)(__a), (v2u64)(__b))) +#define msa_cleq_s64(__a, __b) ((v2u64)__builtin_msa_cle_s_d((v2i64)(__a), (v2i64)(__b))) +#define msa_cleq_f64(__a, __b) ((v2u64)__builtin_msa_fcle_d((v2f64)(__a), (v2f64)(__b))) + +/* compare greater-equal: cge -> ri = ai >= bi ? 1...1:0...0 */ +#define msa_cgeq_u8(__a, __b) ((v16u8)__builtin_msa_cle_u_b((v16u8)(__b), (v16u8)(__a))) +#define msa_cgeq_s8(__a, __b) ((v16u8)__builtin_msa_cle_s_b((v16i8)(__b), (v16i8)(__a))) +#define msa_cgeq_u16(__a, __b) ((v8u16)__builtin_msa_cle_u_h((v8u16)(__b), (v8u16)(__a))) +#define msa_cgeq_s16(__a, __b) ((v8u16)__builtin_msa_cle_s_h((v8i16)(__b), (v8i16)(__a))) +#define msa_cgeq_u32(__a, __b) ((v4u32)__builtin_msa_cle_u_w((v4u32)(__b), (v4u32)(__a))) +#define msa_cgeq_s32(__a, __b) ((v4u32)__builtin_msa_cle_s_w((v4i32)(__b), (v4i32)(__a))) +#define msa_cgeq_f32(__a, __b) ((v4u32)__builtin_msa_fcle_w((v4f32)(__b), (v4f32)(__a))) +#define msa_cgeq_u64(__a, __b) ((v2u64)__builtin_msa_cle_u_d((v2u64)(__b), (v2u64)(__a))) +#define msa_cgeq_s64(__a, __b) ((v2u64)__builtin_msa_cle_s_d((v2i64)(__b), (v2i64)(__a))) +#define msa_cgeq_f64(__a, __b) ((v2u64)__builtin_msa_fcle_d((v2f64)(__b), (v2f64)(__a))) + +/* Shift Left Logical: shl -> ri = ai << bi; */ +#define msa_shlq_u8(__a, __b) ((v16u8)__builtin_msa_sll_b((v16i8)(__a), (v16i8)(__b))) +#define msa_shlq_s8(__a, __b) ((v16i8)__builtin_msa_sll_b((v16i8)(__a), (v16i8)(__b))) +#define msa_shlq_u16(__a, __b) ((v8u16)__builtin_msa_sll_h((v8i16)(__a), (v8i16)(__b))) +#define msa_shlq_s16(__a, __b) ((v8i16)__builtin_msa_sll_h((v8i16)(__a), (v8i16)(__b))) +#define msa_shlq_u32(__a, __b) ((v4u32)__builtin_msa_sll_w((v4i32)(__a), (v4i32)(__b))) +#define msa_shlq_s32(__a, __b) ((v4i32)__builtin_msa_sll_w((v4i32)(__a), (v4i32)(__b))) +#define msa_shlq_u64(__a, __b) ((v2u64)__builtin_msa_sll_d((v2i64)(__a), (v2i64)(__b))) +#define msa_shlq_s64(__a, __b) ((v2i64)__builtin_msa_sll_d((v2i64)(__a), (v2i64)(__b))) + +/* Immediate Shift Left Logical: shl -> ri = ai << imm; */ +#define msa_shlq_n_u8(__a, __imm) ((v16u8)__builtin_msa_slli_b((v16i8)(__a), __imm)) +#define msa_shlq_n_s8(__a, __imm) ((v16i8)__builtin_msa_slli_b((v16i8)(__a), __imm)) +#define msa_shlq_n_u16(__a, __imm) ((v8u16)__builtin_msa_slli_h((v8i16)(__a), __imm)) +#define msa_shlq_n_s16(__a, __imm) ((v8i16)__builtin_msa_slli_h((v8i16)(__a), __imm)) +#define msa_shlq_n_u32(__a, __imm) ((v4u32)__builtin_msa_slli_w((v4i32)(__a), __imm)) +#define msa_shlq_n_s32(__a, __imm) ((v4i32)__builtin_msa_slli_w((v4i32)(__a), __imm)) +#define msa_shlq_n_u64(__a, __imm) ((v2u64)__builtin_msa_slli_d((v2i64)(__a), __imm)) +#define msa_shlq_n_s64(__a, __imm) ((v2i64)__builtin_msa_slli_d((v2i64)(__a), __imm)) + +/* shift right: shrq -> ri = ai >> bi; */ +#define msa_shrq_u8(__a, __b) ((v16u8)__builtin_msa_srl_b((v16i8)(__a), (v16i8)(__b))) +#define msa_shrq_s8(__a, __b) ((v16i8)__builtin_msa_sra_b((v16i8)(__a), (v16i8)(__b))) +#define msa_shrq_u16(__a, __b) ((v8u16)__builtin_msa_srl_h((v8i16)(__a), (v8i16)(__b))) +#define msa_shrq_s16(__a, __b) ((v8i16)__builtin_msa_sra_h((v8i16)(__a), (v8i16)(__b))) +#define msa_shrq_u32(__a, __b) ((v4u32)__builtin_msa_srl_w((v4i32)(__a), (v4i32)(__b))) +#define msa_shrq_s32(__a, __b) ((v4i32)__builtin_msa_sra_w((v4i32)(__a), (v4i32)(__b))) +#define msa_shrq_u64(__a, __b) ((v2u64)__builtin_msa_srl_d((v2i64)(__a), (v2i64)(__b))) +#define msa_shrq_s64(__a, __b) ((v2i64)__builtin_msa_sra_d((v2i64)(__a), (v2i64)(__b))) + +/* Immediate Shift Right: shr -> ri = ai >> imm; */ +#define msa_shrq_n_u8(__a, __imm) ((v16u8)__builtin_msa_srli_b((v16i8)(__a), __imm)) +#define msa_shrq_n_s8(__a, __imm) ((v16i8)__builtin_msa_srai_b((v16i8)(__a), __imm)) +#define msa_shrq_n_u16(__a, __imm) ((v8u16)__builtin_msa_srli_h((v8i16)(__a), __imm)) +#define msa_shrq_n_s16(__a, __imm) ((v8i16)__builtin_msa_srai_h((v8i16)(__a), __imm)) +#define msa_shrq_n_u32(__a, __imm) ((v4u32)__builtin_msa_srli_w((v4i32)(__a), __imm)) +#define msa_shrq_n_s32(__a, __imm) ((v4i32)__builtin_msa_srai_w((v4i32)(__a), __imm)) +#define msa_shrq_n_u64(__a, __imm) ((v2u64)__builtin_msa_srli_d((v2i64)(__a), __imm)) +#define msa_shrq_n_s64(__a, __imm) ((v2i64)__builtin_msa_srai_d((v2i64)(__a), __imm)) + +/* Immediate Shift Right Rounded: shr -> ri = ai >> (rounded)imm; */ +#define msa_rshrq_n_u8(__a, __imm) ((v16u8)__builtin_msa_srlri_b((v16i8)(__a), __imm)) +#define msa_rshrq_n_s8(__a, __imm) ((v16i8)__builtin_msa_srari_b((v16i8)(__a), __imm)) +#define msa_rshrq_n_u16(__a, __imm) ((v8u16)__builtin_msa_srlri_h((v8i16)(__a), __imm)) +#define msa_rshrq_n_s16(__a, __imm) ((v8i16)__builtin_msa_srari_h((v8i16)(__a), __imm)) +#define msa_rshrq_n_u32(__a, __imm) ((v4u32)__builtin_msa_srlri_w((v4i32)(__a), __imm)) +#define msa_rshrq_n_s32(__a, __imm) ((v4i32)__builtin_msa_srari_w((v4i32)(__a), __imm)) +#define msa_rshrq_n_u64(__a, __imm) ((v2u64)__builtin_msa_srlri_d((v2i64)(__a), __imm)) +#define msa_rshrq_n_s64(__a, __imm) ((v2i64)__builtin_msa_srari_d((v2i64)(__a), __imm)) + +/* Vector saturating rounding shift left, qrshl -> ri = ai << bi; */ +#define msa_qrshrq_s32(a, b) ((v4i32)__msa_srar_w((v4i32)(a), (v4i32)(b))) + +/* Rename the msa builtin func to unify the name style for intrin_msa.hpp */ +#define msa_qaddq_u8 __builtin_msa_adds_u_b +#define msa_qaddq_s8 __builtin_msa_adds_s_b +#define msa_qaddq_u16 __builtin_msa_adds_u_h +#define msa_qaddq_s16 __builtin_msa_adds_s_h +#define msa_qaddq_u32 __builtin_msa_adds_u_w +#define msa_qaddq_s32 __builtin_msa_adds_s_w +#define msa_qaddq_u64 __builtin_msa_adds_u_d +#define msa_qaddq_s64 __builtin_msa_adds_s_d +#define msa_addq_u8(a, b) ((v16u8)__builtin_msa_addv_b((v16i8)(a), (v16i8)(b))) +#define msa_addq_s8 __builtin_msa_addv_b +#define msa_addq_u16(a, b) ((v8u16)__builtin_msa_addv_h((v8i16)(a), (v8i16)(b))) +#define msa_addq_s16 __builtin_msa_addv_h +#define msa_addq_u32(a, b) ((v4u32)__builtin_msa_addv_w((v4i32)(a), (v4i32)(b))) +#define msa_addq_s32 __builtin_msa_addv_w +#define msa_addq_f32 __builtin_msa_fadd_w +#define msa_addq_u64(a, b) ((v2u64)__builtin_msa_addv_d((v2i64)(a), (v2i64)(b))) +#define msa_addq_s64 __builtin_msa_addv_d +#define msa_addq_f64 __builtin_msa_fadd_d +#define msa_qsubq_u8 __builtin_msa_subs_u_b +#define msa_qsubq_s8 __builtin_msa_subs_s_b +#define msa_qsubq_u16 __builtin_msa_subs_u_h +#define msa_qsubq_s16 __builtin_msa_subs_s_h +#define msa_subq_u8(a, b) ((v16u8)__builtin_msa_subv_b((v16i8)(a), (v16i8)(b))) +#define msa_subq_s8 __builtin_msa_subv_b +#define msa_subq_u16(a, b) ((v8u16)__builtin_msa_subv_h((v8i16)(a), (v8i16)(b))) +#define msa_subq_s16 __builtin_msa_subv_h +#define msa_subq_u32(a, b) ((v4u32)__builtin_msa_subv_w((v4i32)(a), (v4i32)(b))) +#define msa_subq_s32 __builtin_msa_subv_w +#define msa_subq_f32 __builtin_msa_fsub_w +#define msa_subq_u64(a, b) ((v2u64)__builtin_msa_subv_d((v2i64)(a), (v2i64)(b))) +#define msa_subq_s64 __builtin_msa_subv_d +#define msa_subq_f64 __builtin_msa_fsub_d +#define msa_mulq_u8(a, b) ((v16u8)__builtin_msa_mulv_b((v16i8)(a), (v16i8)(b))) +#define msa_mulq_s8(a, b) ((v16i8)__builtin_msa_mulv_b((v16i8)(a), (v16i8)(b))) +#define msa_mulq_u16(a, b) ((v8u16)__builtin_msa_mulv_h((v8i16)(a), (v8i16)(b))) +#define msa_mulq_s16(a, b) ((v8i16)__builtin_msa_mulv_h((v8i16)(a), (v8i16)(b))) +#define msa_mulq_u32(a, b) ((v4u32)__builtin_msa_mulv_w((v4i32)(a), (v4i32)(b))) +#define msa_mulq_s32(a, b) ((v4i32)__builtin_msa_mulv_w((v4i32)(a), (v4i32)(b))) +#define msa_mulq_u64(a, b) ((v2u64)__builtin_msa_mulv_d((v2i64)(a), (v2i64)(b))) +#define msa_mulq_s64(a, b) ((v2i64)__builtin_msa_mulv_d((v2i64)(a), (v2i64)(b))) +#define msa_mulq_f32 __builtin_msa_fmul_w +#define msa_mulq_f64 __builtin_msa_fmul_d +#define msa_divq_f32 __builtin_msa_fdiv_w +#define msa_divq_f64 __builtin_msa_fdiv_d +#define msa_dotp_s_h __builtin_msa_dotp_s_h +#define msa_dotp_s_w __builtin_msa_dotp_s_w +#define msa_dotp_s_d __builtin_msa_dotp_s_d +#define msa_dotp_u_h __builtin_msa_dotp_u_h +#define msa_dotp_u_w __builtin_msa_dotp_u_w +#define msa_dotp_u_d __builtin_msa_dotp_u_d +#define msa_dpadd_s_h __builtin_msa_dpadd_s_h +#define msa_dpadd_s_w __builtin_msa_dpadd_s_w +#define msa_dpadd_s_d __builtin_msa_dpadd_s_d +#define msa_dpadd_u_h __builtin_msa_dpadd_u_h +#define msa_dpadd_u_w __builtin_msa_dpadd_u_w +#define msa_dpadd_u_d __builtin_msa_dpadd_u_d + +#define ILVRL_B2(RTYPE, in0, in1, low, hi) do { \ + low = (RTYPE)__builtin_msa_ilvr_b((v16i8)(in0), (v16i8)(in1)); \ + hi = (RTYPE)__builtin_msa_ilvl_b((v16i8)(in0), (v16i8)(in1)); \ + } while (0) +#define ILVRL_B2_UB(...) ILVRL_B2(v16u8, __VA_ARGS__) +#define ILVRL_B2_SB(...) ILVRL_B2(v16i8, __VA_ARGS__) +#define ILVRL_B2_UH(...) ILVRL_B2(v8u16, __VA_ARGS__) +#define ILVRL_B2_SH(...) ILVRL_B2(v8i16, __VA_ARGS__) +#define ILVRL_B2_SW(...) ILVRL_B2(v4i32, __VA_ARGS__) + +#define ILVRL_H2(RTYPE, in0, in1, low, hi) do { \ + low = (RTYPE)__builtin_msa_ilvr_h((v8i16)(in0), (v8i16)(in1)); \ + hi = (RTYPE)__builtin_msa_ilvl_h((v8i16)(in0), (v8i16)(in1)); \ + } while (0) +#define ILVRL_H2_UB(...) ILVRL_H2(v16u8, __VA_ARGS__) +#define ILVRL_H2_SB(...) ILVRL_H2(v16i8, __VA_ARGS__) +#define ILVRL_H2_UH(...) ILVRL_H2(v8u16, __VA_ARGS__) +#define ILVRL_H2_SH(...) ILVRL_H2(v8i16, __VA_ARGS__) +#define ILVRL_H2_SW(...) ILVRL_H2(v4i32, __VA_ARGS__) +#define ILVRL_H2_UW(...) ILVRL_H2(v4u32, __VA_ARGS__) + +#define ILVRL_W2(RTYPE, in0, in1, low, hi) do { \ + low = (RTYPE)__builtin_msa_ilvr_w((v4i32)(in0), (v4i32)(in1)); \ + hi = (RTYPE)__builtin_msa_ilvl_w((v4i32)(in0), (v4i32)(in1)); \ + } while (0) +#define ILVRL_W2_UB(...) ILVRL_W2(v16u8, __VA_ARGS__) +#define ILVRL_W2_SH(...) ILVRL_W2(v8i16, __VA_ARGS__) +#define ILVRL_W2_SW(...) ILVRL_W2(v4i32, __VA_ARGS__) +#define ILVRL_W2_UW(...) ILVRL_W2(v4u32, __VA_ARGS__) + +/* absq, qabsq (r = |a|;) */ +#define msa_absq_s8(a) __builtin_msa_add_a_b(a, __builtin_msa_fill_b(0)) +#define msa_absq_s16(a) __builtin_msa_add_a_h(a, __builtin_msa_fill_h(0)) +#define msa_absq_s32(a) __builtin_msa_add_a_w(a, __builtin_msa_fill_w(0)) +#define msa_absq_s64(a) __builtin_msa_add_a_d(a, __builtin_msa_fill_d(0)) +#define msa_absq_f32(a) ((v4f32)__builtin_msa_bclri_w((v4u32)(a), 31)) +#define msa_absq_f64(a) ((v2f64)__builtin_msa_bclri_d((v2u64)(a), 63)) +#define msa_qabsq_s8(a) __builtin_msa_adds_a_b(a, __builtin_msa_fill_b(0)) +#define msa_qabsq_s16(a) __builtin_msa_adds_a_h(a, __builtin_msa_fill_h(0)) +#define msa_qabsq_s32(a) __builtin_msa_adds_a_w(a, __builtin_msa_fill_w(0)) +#define msa_qabsq_s64(a) __builtin_msa_adds_a_d(a, __builtin_msa_fill_d(0)) + +/* abdq, qabdq (r = |a - b|;) */ +#define msa_abdq_u8 __builtin_msa_asub_u_b +#define msa_abdq_s8 __builtin_msa_asub_s_b +#define msa_abdq_u16 __builtin_msa_asub_u_h +#define msa_abdq_s16 __builtin_msa_asub_s_h +#define msa_abdq_u32 __builtin_msa_asub_u_w +#define msa_abdq_s32 __builtin_msa_asub_s_w +#define msa_abdq_u64 __builtin_msa_asub_u_d +#define msa_abdq_s64 __builtin_msa_asub_s_d +#define msa_abdq_f32(a, b) msa_absq_f32(__builtin_msa_fsub_w(a, b)) +#define msa_abdq_f64(a, b) msa_absq_f64(__builtin_msa_fsub_d(a, b)) +#define msa_qabdq_s8(a, b) msa_qabsq_s8(__builtin_msa_subs_s_b(a, b)) +#define msa_qabdq_s16(a, b) msa_qabsq_s16(__builtin_msa_subs_s_h(a, b)) +#define msa_qabdq_s32(a, b) msa_qabsq_s32(__builtin_msa_subs_s_w(a, b)) +#define msa_qabdq_s64(a, b) msa_qabsq_s64(__builtin_msa_subs_s_d(a, b)) + +/* sqrtq, rsqrtq */ +#define msa_sqrtq_f32 __builtin_msa_fsqrt_w +#define msa_sqrtq_f64 __builtin_msa_fsqrt_d +#define msa_rsqrtq_f32 __builtin_msa_frsqrt_w +#define msa_rsqrtq_f64 __builtin_msa_frsqrt_d + + +/* mlaq: r = a + b * c; */ +__extension__ extern __inline v4i32 +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +msa_mlaq_s32(v4i32 __a, v4i32 __b, v4i32 __c) +{ + __asm__ volatile("maddv.w %w[__a], %w[__b], %w[__c]\n" + // Outputs + : [__a] "+f"(__a) + // Inputs + : [__b] "f"(__b), [__c] "f"(__c)); + return __a; +} + +__extension__ extern __inline v2i64 +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +msa_mlaq_s64(v2i64 __a, v2i64 __b, v2i64 __c) +{ + __asm__ volatile("maddv.d %w[__a], %w[__b], %w[__c]\n" + // Outputs + : [__a] "+f"(__a) + // Inputs + : [__b] "f"(__b), [__c] "f"(__c)); + return __a; +} + +__extension__ extern __inline v4f32 +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +msa_mlaq_f32(v4f32 __a, v4f32 __b, v4f32 __c) +{ + __asm__ volatile("fmadd.w %w[__a], %w[__b], %w[__c]\n" + // Outputs + : [__a] "+f"(__a) + // Inputs + : [__b] "f"(__b), [__c] "f"(__c)); + return __a; +} + +__extension__ extern __inline v2f64 +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +msa_mlaq_f64(v2f64 __a, v2f64 __b, v2f64 __c) +{ + __asm__ volatile("fmadd.d %w[__a], %w[__b], %w[__c]\n" + // Outputs + : [__a] "+f"(__a) + // Inputs + : [__b] "f"(__b), [__c] "f"(__c)); + return __a; +} + +/* cntq */ +#define msa_cntq_s8 __builtin_msa_pcnt_b +#define msa_cntq_s16 __builtin_msa_pcnt_h +#define msa_cntq_s32 __builtin_msa_pcnt_w +#define msa_cntq_s64 __builtin_msa_pcnt_d + +/* bslq (a: mask; r = b(if a == 0); r = c(if a == 1);) */ +#define msa_bslq_u8 __builtin_msa_bsel_v + +/* ilvrq, ilvlq (For EL only, ilvrq: b0, a0, b1, a1; ilvlq: b2, a2, b3, a3;) */ +#define msa_ilvrq_s8 __builtin_msa_ilvr_b +#define msa_ilvrq_s16 __builtin_msa_ilvr_h +#define msa_ilvrq_s32 __builtin_msa_ilvr_w +#define msa_ilvrq_s64 __builtin_msa_ilvr_d +#define msa_ilvlq_s8 __builtin_msa_ilvl_b +#define msa_ilvlq_s16 __builtin_msa_ilvl_h +#define msa_ilvlq_s32 __builtin_msa_ilvl_w +#define msa_ilvlq_s64 __builtin_msa_ilvl_d + +/* ilvevq, ilvodq (ilvevq: b0, a0, b2, a2; ilvodq: b1, a1, b3, a3; ) */ +#define msa_ilvevq_s8 __builtin_msa_ilvev_b +#define msa_ilvevq_s16 __builtin_msa_ilvev_h +#define msa_ilvevq_s32 __builtin_msa_ilvev_w +#define msa_ilvevq_s64 __builtin_msa_ilvev_d +#define msa_ilvodq_s8 __builtin_msa_ilvod_b +#define msa_ilvodq_s16 __builtin_msa_ilvod_h +#define msa_ilvodq_s32 __builtin_msa_ilvod_w +#define msa_ilvodq_s64 __builtin_msa_ilvod_d + +/* extq (r = (a || b); a concatenation b and get elements from index c) */ +#ifdef _MIPSEB +#define msa_extq_s8(a, b, c) \ +(__builtin_msa_vshf_b(__builtin_msa_subv_b((v16i8)((v2i64){0x1716151413121110, 0x1F1E1D1C1B1A1918}), __builtin_msa_fill_b(c)), a, b)) +#define msa_extq_s16(a, b, c) \ +(__builtin_msa_vshf_h(__builtin_msa_subv_h((v8i16)((v2i64){0x000B000A00090008, 0x000F000E000D000C}), __builtin_msa_fill_h(c)), a, b)) +#define msa_extq_s32(a, b, c) \ +(__builtin_msa_vshf_w(__builtin_msa_subv_w((v4i32)((v2i64){0x0000000500000004, 0x0000000700000006}), __builtin_msa_fill_w(c)), a, b)) +#define msa_extq_s64(a, b, c) \ +(__builtin_msa_vshf_d(__builtin_msa_subv_d((v2i64){0x0000000000000002, 0x0000000000000003}, __builtin_msa_fill_d(c)), a, b)) +#else +#define msa_extq_s8(a, b, c) \ +(__builtin_msa_vshf_b(__builtin_msa_addv_b((v16i8)((v2i64){0x0706050403020100, 0x0F0E0D0C0B0A0908}), __builtin_msa_fill_b(c)), b, a)) +#define msa_extq_s16(a, b, c) \ +(__builtin_msa_vshf_h(__builtin_msa_addv_h((v8i16)((v2i64){0x0003000200010000, 0x0007000600050004}), __builtin_msa_fill_h(c)), b, a)) +#define msa_extq_s32(a, b, c) \ +(__builtin_msa_vshf_w(__builtin_msa_addv_w((v4i32)((v2i64){0x0000000100000000, 0x0000000300000002}), __builtin_msa_fill_w(c)), b, a)) +#define msa_extq_s64(a, b, c) \ +(__builtin_msa_vshf_d(__builtin_msa_addv_d((v2i64){0x0000000000000000, 0x0000000000000001}, __builtin_msa_fill_d(c)), b, a)) +#endif /* _MIPSEB */ + +/* cvttruncq, cvttintq, cvtrintq */ +#define msa_cvttruncq_u32_f32 __builtin_msa_ftrunc_u_w +#define msa_cvttruncq_s32_f32 __builtin_msa_ftrunc_s_w +#define msa_cvttruncq_u64_f64 __builtin_msa_ftrunc_u_d +#define msa_cvttruncq_s64_f64 __builtin_msa_ftrunc_s_d +#define msa_cvttintq_u32_f32 __builtin_msa_ftint_u_w +#define msa_cvttintq_s32_f32 __builtin_msa_ftint_s_w +#define msa_cvttintq_u64_f64 __builtin_msa_ftint_u_d +#define msa_cvttintq_s64_f64 __builtin_msa_ftint_s_d +#define msa_cvtrintq_f32 __builtin_msa_frint_w +#define msa_cvtrintq_f64 __builtin_msa_frint_d + +/* cvtfintq, cvtfq */ +#define msa_cvtfintq_f32_u32 __builtin_msa_ffint_u_w +#define msa_cvtfintq_f32_s32 __builtin_msa_ffint_s_w +#define msa_cvtfintq_f64_u64 __builtin_msa_ffint_u_d +#define msa_cvtfintq_f64_s64 __builtin_msa_ffint_s_d +#define msa_cvtfq_f32_f64 __builtin_msa_fexdo_w +#define msa_cvtflq_f64_f32 __builtin_msa_fexupr_d +#define msa_cvtfhq_f64_f32 __builtin_msa_fexupl_d + +#define msa_addl_u8(a, b) ((v8u16)__builtin_msa_addv_h((v8i16)V8U8_2_V8I16(a), (v8i16)V8U8_2_V8I16(b))) +#define msa_addl_s8(a, b) (__builtin_msa_addv_h((v8i16)V8I8_2_V8I16(a), (v8i16)V8I8_2_V8I16(b))) +#define msa_addl_u16(a, b) ((v4u32)__builtin_msa_addv_w((v4i32)V4U16_2_V4I32(a), (v4i32)V4U16_2_V4I32(b))) +#define msa_addl_s16(a, b) (__builtin_msa_addv_w((v4i32)V4I16_2_V4I32(a), (v4i32)V4I16_2_V4I32(b))) +#define msa_subl_s16(a, b) (__builtin_msa_subv_w((v4i32)V4I16_2_V4I32(a), (v4i32)V4I16_2_V4I32(b))) +#define msa_recpeq_f32 __builtin_msa_frcp_w +#define msa_recpsq_f32(a, b) (__builtin_msa_fsub_w(msa_dupq_n_f32(2.0f), __builtin_msa_fmul_w(a, b))) + +#define MSA_INTERLEAVED_IMPL_LOAD2_STORE2(_Tp, _Tpv, _Tpvs, suffix, df, nlanes) \ +__extension__ extern __inline void \ +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \ +msa_ld2q_##suffix(const _Tp* ptr, _Tpv* a, _Tpv* b) \ +{ \ + _Tpv v0 = msa_ld1q_##suffix(ptr); \ + _Tpv v1 = msa_ld1q_##suffix(ptr + nlanes); \ + *a = (_Tpv)__builtin_msa_pckev_##df((_Tpvs)v1, (_Tpvs)v0); \ + *b = (_Tpv)__builtin_msa_pckod_##df((_Tpvs)v1, (_Tpvs)v0); \ +} \ +__extension__ extern __inline void \ +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \ +msa_st2q_##suffix(_Tp* ptr, const _Tpv a, const _Tpv b) \ +{ \ + msa_st1q_##suffix(ptr, (_Tpv)__builtin_msa_ilvr_##df((_Tpvs)b, (_Tpvs)a)); \ + msa_st1q_##suffix(ptr + nlanes, (_Tpv)__builtin_msa_ilvl_##df((_Tpvs)b, (_Tpvs)a)); \ +} + +MSA_INTERLEAVED_IMPL_LOAD2_STORE2(uint8_t, v16u8, v16i8, u8, b, 16) +MSA_INTERLEAVED_IMPL_LOAD2_STORE2(int8_t, v16i8, v16i8, s8, b, 16) +MSA_INTERLEAVED_IMPL_LOAD2_STORE2(uint16_t, v8u16, v8i16, u16, h, 8) +MSA_INTERLEAVED_IMPL_LOAD2_STORE2(int16_t, v8i16, v8i16, s16, h, 8) +MSA_INTERLEAVED_IMPL_LOAD2_STORE2(uint32_t, v4u32, v4i32, u32, w, 4) +MSA_INTERLEAVED_IMPL_LOAD2_STORE2(int32_t, v4i32, v4i32, s32, w, 4) +MSA_INTERLEAVED_IMPL_LOAD2_STORE2(float, v4f32, v4i32, f32, w, 4) +MSA_INTERLEAVED_IMPL_LOAD2_STORE2(uint64_t, v2u64, v2i64, u64, d, 2) +MSA_INTERLEAVED_IMPL_LOAD2_STORE2(int64_t, v2i64, v2i64, s64, d, 2) +MSA_INTERLEAVED_IMPL_LOAD2_STORE2(double, v2f64, v2i64, f64, d, 2) + +#ifdef _MIPSEB +#define MSA_INTERLEAVED_IMPL_LOAD3_8(_Tp, _Tpv, _Tpvs, suffix) \ +__extension__ extern __inline void \ +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \ +msa_ld3q_##suffix(const _Tp* ptr, _Tpv* a, _Tpv* b, _Tpv* c) \ +{ \ + _Tpv v0 = msa_ld1q_##suffix(ptr); \ + _Tpv v1 = msa_ld1q_##suffix(ptr + 16); \ + _Tpv v2 = msa_ld1q_##suffix(ptr + 32); \ + _Tpvs v3 = __builtin_msa_vshf_b((_Tpvs)((v2i64){0x0704011F1F1F1F1F, 0x1F1C191613100D0A}), (_Tpvs)v0, (_Tpvs)v1); \ + *a = (_Tpv)__builtin_msa_vshf_b((_Tpvs)((v2i64){0x1716150E0B080502, 0x1F1E1D1C1B1A1918}), v3, (_Tpvs)v2); \ + v3 = __builtin_msa_vshf_b((_Tpvs)((v2i64){0x0603001F1F1F1F1F, 0x1E1B1815120F0C09}), (_Tpvs)v0, (_Tpvs)v1); \ + *b = (_Tpv)__builtin_msa_vshf_b((_Tpvs)((v2i64){0x1716150D0A070401, 0x1F1E1D1C1B1A1918}), v3, (_Tpvs)v2); \ + v3 = __builtin_msa_vshf_b((_Tpvs)((v2i64){0x05021F1F1F1F1F1F, 0x1D1A1714110E0B08}), (_Tpvs)v0, (_Tpvs)v1); \ + *c = (_Tpv)__builtin_msa_vshf_b((_Tpvs)((v2i64){0x17160F0C09060300, 0x1F1E1D1C1B1A1918}), v3, (_Tpvs)v2); \ +} +#else +#define MSA_INTERLEAVED_IMPL_LOAD3_8(_Tp, _Tpv, _Tpvs, suffix) \ +__extension__ extern __inline void \ +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \ +msa_ld3q_##suffix(const _Tp* ptr, _Tpv* a, _Tpv* b, _Tpv* c) \ +{ \ + _Tpv v0 = msa_ld1q_##suffix(ptr); \ + _Tpv v1 = msa_ld1q_##suffix(ptr + 16); \ + _Tpv v2 = msa_ld1q_##suffix(ptr + 32); \ + _Tpvs v3 = __builtin_msa_vshf_b((_Tpvs)((v2i64){0x15120F0C09060300, 0x00000000001E1B18}), (_Tpvs)v1, (_Tpvs)v0); \ + *a = (_Tpv)__builtin_msa_vshf_b((_Tpvs)((v2i64){0x0706050403020100, 0x1D1A1714110A0908}), (_Tpvs)v2, v3); \ + v3 = __builtin_msa_vshf_b((_Tpvs)((v2i64){0x1613100D0A070401, 0x00000000001F1C19}), (_Tpvs)v1, (_Tpvs)v0); \ + *b = (_Tpv)__builtin_msa_vshf_b((_Tpvs)((v2i64){0x0706050403020100, 0x1E1B1815120A0908}), (_Tpvs)v2, v3); \ + v3 = __builtin_msa_vshf_b((_Tpvs)((v2i64){0x1714110E0B080502, 0x0000000000001D1A}), (_Tpvs)v1, (_Tpvs)v0); \ + *c = (_Tpv)__builtin_msa_vshf_b((_Tpvs)((v2i64){0x0706050403020100, 0x1F1C191613100908}), (_Tpvs)v2, v3); \ +} +#endif + +MSA_INTERLEAVED_IMPL_LOAD3_8(uint8_t, v16u8, v16i8, u8) +MSA_INTERLEAVED_IMPL_LOAD3_8(int8_t, v16i8, v16i8, s8) + +#ifdef _MIPSEB +#define MSA_INTERLEAVED_IMPL_LOAD3_16(_Tp, _Tpv, _Tpvs, suffix) \ +__extension__ extern __inline void \ +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \ +msa_ld3q_##suffix(const _Tp* ptr, _Tpv* a, _Tpv* b, _Tpv* c) \ +{ \ + _Tpv v0 = msa_ld1q_##suffix(ptr); \ + _Tpv v1 = msa_ld1q_##suffix(ptr + 8); \ + _Tpv v2 = msa_ld1q_##suffix(ptr + 16); \ + _Tpvs v3 = __builtin_msa_vshf_h((_Tpvs)((v2i64){0x00030000000F000F, 0x000F000C00090006}), (_Tpvs)v1, (_Tpvs)v0); \ + *a = (_Tpv)__builtin_msa_vshf_h((_Tpvs)((v2i64){0x000B000A00050002, 0x000F000E000D000C}), (_Tpvs)v2, v3); \ + v3 = __builtin_msa_vshf_h((_Tpvs)((v2i64){0x0002000F000F000F, 0x000E000B00080005}), (_Tpvs)v1, (_Tpvs)v0); \ + *b = (_Tpv)__builtin_msa_vshf_h((_Tpvs)((v2i64){0x000B000700040001, 0x000F000E000D000C}), (_Tpvs)v2, v3); \ + v3 = __builtin_msa_vshf_h((_Tpvs)((v2i64){0x0001000F000F000F, 0x000D000A00070004}), (_Tpvs)v1, (_Tpvs)v0); \ + *c = (_Tpv)__builtin_msa_vshf_h((_Tpvs)((v2i64){0x000B000600030000, 0x000F000E000D000C}), (_Tpvs)v2, v3); \ +} +#else +#define MSA_INTERLEAVED_IMPL_LOAD3_16(_Tp, _Tpv, _Tpvs, suffix) \ +__extension__ extern __inline void \ +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \ +msa_ld3q_##suffix(const _Tp* ptr, _Tpv* a, _Tpv* b, _Tpv* c) \ +{ \ + _Tpv v0 = msa_ld1q_##suffix(ptr); \ + _Tpv v1 = msa_ld1q_##suffix(ptr + 8); \ + _Tpv v2 = msa_ld1q_##suffix(ptr + 16); \ + _Tpvs v3 = __builtin_msa_vshf_h((_Tpvs)((v2i64){0x0009000600030000, 0x00000000000F000C}), (_Tpvs)v1, (_Tpvs)v0); \ + *a = (_Tpv)__builtin_msa_vshf_h((_Tpvs)((v2i64){0x0003000200010000, 0x000D000A00050004}), (_Tpvs)v2, v3); \ + v3 = __builtin_msa_vshf_h((_Tpvs)((v2i64){0x000A000700040001, 0x000000000000000D}), (_Tpvs)v1, (_Tpvs)v0); \ + *b = (_Tpv)__builtin_msa_vshf_h((_Tpvs)((v2i64){0x0003000200010000, 0x000E000B00080004}), (_Tpvs)v2, v3); \ + v3 = __builtin_msa_vshf_h((_Tpvs)((v2i64){0x000B000800050002, 0x000000000000000E}), (_Tpvs)v1, (_Tpvs)v0); \ + *c = (_Tpv)__builtin_msa_vshf_h((_Tpvs)((v2i64){0x0003000200010000, 0x000F000C00090004}), (_Tpvs)v2, v3); \ +} +#endif + +MSA_INTERLEAVED_IMPL_LOAD3_16(uint16_t, v8u16, v8i16, u16) +MSA_INTERLEAVED_IMPL_LOAD3_16(int16_t, v8i16, v8i16, s16) + +#define MSA_INTERLEAVED_IMPL_LOAD3_32(_Tp, _Tpv, _Tpvs, suffix) \ +__extension__ extern __inline void \ +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \ +msa_ld3q_##suffix(const _Tp* ptr, _Tpv* a, _Tpv* b, _Tpv* c) \ +{ \ + _Tpv v00 = msa_ld1q_##suffix(ptr); \ + _Tpv v01 = msa_ld1q_##suffix(ptr + 4); \ + _Tpv v02 = msa_ld1q_##suffix(ptr + 8); \ + _Tpvs v10 = __builtin_msa_ilvr_w((_Tpvs)__builtin_msa_ilvl_d((v2i64)v01, (v2i64)v01), (_Tpvs)v00); \ + _Tpvs v11 = __builtin_msa_ilvr_w((_Tpvs)v02, (_Tpvs)__builtin_msa_ilvl_d((v2i64)v00, (v2i64)v00)); \ + _Tpvs v12 = __builtin_msa_ilvr_w((_Tpvs)__builtin_msa_ilvl_d((v2i64)v02, (v2i64)v02), (_Tpvs)v01); \ + *a = (_Tpv)__builtin_msa_ilvr_w((_Tpvs)__builtin_msa_ilvl_d((v2i64)v11, (v2i64)v11), v10); \ + *b = (_Tpv)__builtin_msa_ilvr_w(v12, (_Tpvs)__builtin_msa_ilvl_d((v2i64)v10, (v2i64)v10)); \ + *c = (_Tpv)__builtin_msa_ilvr_w((_Tpvs)__builtin_msa_ilvl_d((v2i64)v12, (v2i64)v12), v11); \ +} + +MSA_INTERLEAVED_IMPL_LOAD3_32(uint32_t, v4u32, v4i32, u32) +MSA_INTERLEAVED_IMPL_LOAD3_32(int32_t, v4i32, v4i32, s32) +MSA_INTERLEAVED_IMPL_LOAD3_32(float, v4f32, v4i32, f32) + +#define MSA_INTERLEAVED_IMPL_LOAD3_64(_Tp, _Tpv, suffix) \ +__extension__ extern __inline void \ +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \ +msa_ld3q_##suffix(const _Tp* ptr, _Tpv* a, _Tpv* b, _Tpv* c) \ +{ \ + *((_Tp*)a) = *ptr; *((_Tp*)b) = *(ptr + 1); *((_Tp*)c) = *(ptr + 2); \ + *((_Tp*)a + 1) = *(ptr + 3); *((_Tp*)b + 1) = *(ptr + 4); *((_Tp*)c + 1) = *(ptr + 5); \ +} + +MSA_INTERLEAVED_IMPL_LOAD3_64(uint64_t, v2u64, u64) +MSA_INTERLEAVED_IMPL_LOAD3_64(int64_t, v2i64, s64) +MSA_INTERLEAVED_IMPL_LOAD3_64(double, v2f64, f64) + +#ifdef _MIPSEB +#define MSA_INTERLEAVED_IMPL_STORE3_8(_Tp, _Tpv, _Tpvs, suffix) \ +__extension__ extern __inline void \ +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \ +msa_st3q_##suffix(_Tp* ptr, const _Tpv a, const _Tpv b, const _Tpv c) \ +{ \ + _Tpvs v0 = __builtin_msa_vshf_b((_Tpvs)((v2i64){0x0F0E0D0C0B1F1F1F, 0x1F1E1D1C1B1A1F1F}), (_Tpvs)b, (_Tpvs)a); \ + _Tpvs v1 = __builtin_msa_vshf_b((_Tpvs)((v2i64){0x0D1C140C1B130B1A, 0x1F170F1E160E1D15}), (_Tpvs)c, (_Tpvs)v0); \ + msa_st1q_##suffix(ptr, (_Tpv)v1); \ + v0 = __builtin_msa_vshf_b((_Tpvs)((v2i64){0x0A09080706051F1F, 0x19181716151F1F1F}), (_Tpvs)b, (_Tpvs)a); \ + v1 = __builtin_msa_vshf_b((_Tpvs)((v2i64){0x1D14071C13061B12, 0x170A1F16091E1508}), (_Tpvs)c, (_Tpvs)v0); \ + msa_st1q_##suffix(ptr + 16, (_Tpv)v1); \ + v0 = __builtin_msa_vshf_b((_Tpvs)((v2i64){0x04030201001F1F1F, 0x14131211101F1F1F}), (_Tpvs)b, (_Tpvs)a); \ + v1 = __builtin_msa_vshf_b((_Tpvs)((v2i64){0x15021C14011B1300, 0x051F17041E16031D}), (_Tpvs)c, (_Tpvs)v0); \ + msa_st1q_##suffix(ptr + 32, (_Tpv)v1); \ +} +#else +#define MSA_INTERLEAVED_IMPL_STORE3_8(_Tp, _Tpv, _Tpvs, suffix) \ +__extension__ extern __inline void \ +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \ +msa_st3q_##suffix(_Tp* ptr, const _Tpv a, const _Tpv b, const _Tpv c) \ +{ \ + _Tpvs v0 = __builtin_msa_vshf_b((_Tpvs)((v2i64){0x0000050403020100, 0x0000001413121110}), (_Tpvs)b, (_Tpvs)a); \ + _Tpvs v1 = __builtin_msa_vshf_b((_Tpvs)((v2i64){0x0A02110901100800, 0x05140C04130B0312}), (_Tpvs)c, (_Tpvs)v0); \ + msa_st1q_##suffix(ptr, (_Tpv)v1); \ + v0 = __builtin_msa_vshf_b((_Tpvs)((v2i64){0x0000000A09080706, 0x00001A1918171615}), (_Tpvs)b, (_Tpvs)a); \ + v1 = __builtin_msa_vshf_b((_Tpvs)((v2i64){0x170A011609001508, 0x0D04190C03180B02}), (_Tpvs)c, (_Tpvs)v0); \ + msa_st1q_##suffix(ptr + 16, (_Tpv)v1); \ + v0 = __builtin_msa_vshf_b((_Tpvs)((v2i64){0x0000000F0E0D0C0B, 0x0000001F1E1D1C1B}), (_Tpvs)b, (_Tpvs)a); \ + v1 = __builtin_msa_vshf_b((_Tpvs)((v2i64){0x021C09011B08001A, 0x1F0C041E0B031D0A}), (_Tpvs)c, (_Tpvs)v0); \ + msa_st1q_##suffix(ptr + 32, (_Tpv)v1); \ +} +#endif + +MSA_INTERLEAVED_IMPL_STORE3_8(uint8_t, v16u8, v16i8, u8) +MSA_INTERLEAVED_IMPL_STORE3_8(int8_t, v16i8, v16i8, s8) + +#ifdef _MIPSEB +#define MSA_INTERLEAVED_IMPL_STORE3_16(_Tp, _Tpv, _Tpvs, suffix) \ +__extension__ extern __inline void \ +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \ +msa_st3q_##suffix(_Tp* ptr, const _Tpv a, const _Tpv b, const _Tpv c) \ +{ \ + _Tpvs v0 = __builtin_msa_vshf_h((_Tpvs)((v2i64){0x000700060005000F, 0x000F000E000D000F}), (_Tpvs)b, (_Tpvs)a); \ + _Tpvs v1 = __builtin_msa_vshf_h((_Tpvs)((v2i64){0x000A0006000D0009, 0x000F000B0007000E}), (_Tpvs)c, (_Tpvs)v0); \ + msa_st1q_##suffix(ptr, (_Tpv)v1); \ + v0 = __builtin_msa_vshf_h((_Tpvs)((v2i64){0x00040003000F000F, 0x000C000B000A000F}), (_Tpvs)b, (_Tpvs)a); \ + v1 = __builtin_msa_vshf_h((_Tpvs)((v2i64){0x000E000A0003000D, 0x0005000F000B0004}), (_Tpvs)c, (_Tpvs)v0); \ + msa_st1q_##suffix(ptr + 8, (_Tpv)v1); \ + v0 = __builtin_msa_vshf_h((_Tpvs)((v2i64){0x000200010000000F, 0x00090008000F000F}), (_Tpvs)b, (_Tpvs)a); \ + v1 = __builtin_msa_vshf_h((_Tpvs)((v2i64){0x0001000E00090000, 0x000B0002000F000A}), (_Tpvs)c, (_Tpvs)v0); \ + msa_st1q_##suffix(ptr + 16, (_Tpv)v1); \ +} +#else +#define MSA_INTERLEAVED_IMPL_STORE3_16(_Tp, _Tpv, _Tpvs, suffix) \ +__extension__ extern __inline void \ +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \ +msa_st3q_##suffix(_Tp* ptr, const _Tpv a, const _Tpv b, const _Tpv c) \ +{ \ + _Tpvs v0 = __builtin_msa_vshf_h((_Tpvs)((v2i64){0x0000000200010000, 0x0000000A00090008}), (_Tpvs)b, (_Tpvs)a); \ + _Tpvs v1 = __builtin_msa_vshf_h((_Tpvs)((v2i64){0x0001000800040000, 0x0006000200090005}), (_Tpvs)c, (_Tpvs)v0); \ + msa_st1q_##suffix(ptr, (_Tpv)v1); \ + v0 = __builtin_msa_vshf_h((_Tpvs)((v2i64){0x0000000500040003, 0x00000000000C000B}), (_Tpvs)b, (_Tpvs)a); \ + v1 = __builtin_msa_vshf_h((_Tpvs)((v2i64){0x000B00040000000A, 0x0002000C00050001}), (_Tpvs)c, (_Tpvs)v0); \ + msa_st1q_##suffix(ptr + 8, (_Tpv)v1); \ + v0 = __builtin_msa_vshf_h((_Tpvs)((v2i64){0x0000000000070006, 0x0000000F000E000D}), (_Tpvs)b, (_Tpvs)a); \ + v1 = __builtin_msa_vshf_h((_Tpvs)((v2i64){0x00050000000D0004, 0x000F00060001000E}), (_Tpvs)c, (_Tpvs)v0); \ + msa_st1q_##suffix(ptr + 16, (_Tpv)v1); \ +} +#endif + +MSA_INTERLEAVED_IMPL_STORE3_16(uint16_t, v8u16, v8i16, u16) +MSA_INTERLEAVED_IMPL_STORE3_16(int16_t, v8i16, v8i16, s16) + +#ifdef _MIPSEB +#define MSA_INTERLEAVED_IMPL_STORE3_32(_Tp, _Tpv, _Tpvs, suffix) \ +__extension__ extern __inline void \ +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \ +msa_st3q_##suffix(_Tp* ptr, const _Tpv a, const _Tpv b, const _Tpv c) \ +{ \ + _Tpvs v0 = __builtin_msa_vshf_w((_Tpvs)((v2i64){0x0000000300000007, 0x0000000700000006}), (_Tpvs)b, (_Tpvs)a); \ + _Tpvs v1 = __builtin_msa_vshf_w((_Tpvs)((v2i64){0x0000000300000006, 0x0000000700000005}), (_Tpvs)c, (_Tpvs)v0); \ + msa_st1q_##suffix(ptr, (_Tpv)v1); \ + v0 = __builtin_msa_vshf_w((_Tpvs)((v2i64){0x0000000200000001, 0x0000000500000007}), (_Tpvs)b, (_Tpvs)a); \ + v1 = __builtin_msa_vshf_w((_Tpvs)((v2i64){0x0000000700000004, 0x0000000500000002}), (_Tpvs)c, (_Tpvs)v0); \ + msa_st1q_##suffix(ptr + 4, (_Tpv)v1); \ + v0 = __builtin_msa_vshf_w((_Tpvs)((v2i64){0x0000000000000007, 0x0000000400000007}), (_Tpvs)b, (_Tpvs)a); \ + v1 = __builtin_msa_vshf_w((_Tpvs)((v2i64){0x0000000500000000, 0x0000000100000007}), (_Tpvs)c, (_Tpvs)v0); \ + msa_st1q_##suffix(ptr + 8, (_Tpv)v1); \ +} +#else +#define MSA_INTERLEAVED_IMPL_STORE3_32(_Tp, _Tpv, _Tpvs, suffix) \ +__extension__ extern __inline void \ +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \ +msa_st3q_##suffix(_Tp* ptr, const _Tpv a, const _Tpv b, const _Tpv c) \ +{ \ + _Tpvs v0 = __builtin_msa_vshf_w((_Tpvs)((v2i64){0x0000000100000000, 0x0000000000000004}), (_Tpvs)b, (_Tpvs)a); \ + _Tpvs v1 = __builtin_msa_vshf_w((_Tpvs)((v2i64){0x0000000200000000, 0x0000000100000004}), (_Tpvs)c, (_Tpvs)v0); \ + msa_st1q_##suffix(ptr, (_Tpv)v1); \ + v0 = __builtin_msa_vshf_w((_Tpvs)((v2i64){0x0000000000000002, 0x0000000600000005}), (_Tpvs)b, (_Tpvs)a); \ + v1 = __builtin_msa_vshf_w((_Tpvs)((v2i64){0x0000000500000002, 0x0000000300000000}), (_Tpvs)c, (_Tpvs)v0); \ + msa_st1q_##suffix(ptr + 4, (_Tpv)v1); \ + v0 = __builtin_msa_vshf_w((_Tpvs)((v2i64){0x0000000000000003, 0x0000000000000007}), (_Tpvs)b, (_Tpvs)a); \ + v1 = __builtin_msa_vshf_w((_Tpvs)((v2i64){0x0000000000000006, 0x0000000700000002}), (_Tpvs)c, (_Tpvs)v0); \ + msa_st1q_##suffix(ptr + 8, (_Tpv)v1); \ +} +#endif + +MSA_INTERLEAVED_IMPL_STORE3_32(uint32_t, v4u32, v4i32, u32) +MSA_INTERLEAVED_IMPL_STORE3_32(int32_t, v4i32, v4i32, s32) +MSA_INTERLEAVED_IMPL_STORE3_32(float, v4f32, v4i32, f32) + +#define MSA_INTERLEAVED_IMPL_STORE3_64(_Tp, _Tpv, suffix) \ +__extension__ extern __inline void \ +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \ +msa_st3q_##suffix(_Tp* ptr, const _Tpv a, const _Tpv b, const _Tpv c) \ +{ \ + *ptr = a[0]; *(ptr + 1) = b[0]; *(ptr + 2) = c[0]; \ + *(ptr + 3) = a[1]; *(ptr + 4) = b[1]; *(ptr + 5) = c[1]; \ +} + +MSA_INTERLEAVED_IMPL_STORE3_64(uint64_t, v2u64, u64) +MSA_INTERLEAVED_IMPL_STORE3_64(int64_t, v2i64, s64) +MSA_INTERLEAVED_IMPL_STORE3_64(double, v2f64, f64) + +#define MSA_INTERLEAVED_IMPL_LOAD4_STORE4(_Tp, _Tpv, _Tpvs, suffix, df, nlanes) \ +__extension__ extern __inline void \ +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \ +msa_ld4q_##suffix(const _Tp* ptr, _Tpv* a, _Tpv* b, _Tpv* c, _Tpv* d) \ +{ \ + _Tpv v0 = msa_ld1q_##suffix(ptr); \ + _Tpv v1 = msa_ld1q_##suffix(ptr + nlanes); \ + _Tpv v2 = msa_ld1q_##suffix(ptr + nlanes * 2); \ + _Tpv v3 = msa_ld1q_##suffix(ptr + nlanes * 3); \ + _Tpvs t0 = __builtin_msa_pckev_##df((_Tpvs)v1, (_Tpvs)v0); \ + _Tpvs t1 = __builtin_msa_pckev_##df((_Tpvs)v3, (_Tpvs)v2); \ + _Tpvs t2 = __builtin_msa_pckod_##df((_Tpvs)v1, (_Tpvs)v0); \ + _Tpvs t3 = __builtin_msa_pckod_##df((_Tpvs)v3, (_Tpvs)v2); \ + *a = (_Tpv)__builtin_msa_pckev_##df(t1, t0); \ + *b = (_Tpv)__builtin_msa_pckev_##df(t3, t2); \ + *c = (_Tpv)__builtin_msa_pckod_##df(t1, t0); \ + *d = (_Tpv)__builtin_msa_pckod_##df(t3, t2); \ +} \ +__extension__ extern __inline void \ +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \ +msa_st4q_##suffix(_Tp* ptr, const _Tpv a, const _Tpv b, const _Tpv c, const _Tpv d) \ +{ \ + _Tpvs v0 = __builtin_msa_ilvr_##df((_Tpvs)c, (_Tpvs)a); \ + _Tpvs v1 = __builtin_msa_ilvr_##df((_Tpvs)d, (_Tpvs)b); \ + _Tpvs v2 = __builtin_msa_ilvl_##df((_Tpvs)c, (_Tpvs)a); \ + _Tpvs v3 = __builtin_msa_ilvl_##df((_Tpvs)d, (_Tpvs)b); \ + msa_st1q_##suffix(ptr, (_Tpv)__builtin_msa_ilvr_##df(v1, v0)); \ + msa_st1q_##suffix(ptr + nlanes, (_Tpv)__builtin_msa_ilvl_##df(v1, v0)); \ + msa_st1q_##suffix(ptr + 2 * nlanes, (_Tpv)__builtin_msa_ilvr_##df(v3, v2)); \ + msa_st1q_##suffix(ptr + 3 * nlanes, (_Tpv)__builtin_msa_ilvl_##df(v3, v2)); \ +} + +MSA_INTERLEAVED_IMPL_LOAD4_STORE4(uint8_t, v16u8, v16i8, u8, b, 16) +MSA_INTERLEAVED_IMPL_LOAD4_STORE4(int8_t, v16i8, v16i8, s8, b, 16) +MSA_INTERLEAVED_IMPL_LOAD4_STORE4(uint16_t, v8u16, v8i16, u16, h, 8) +MSA_INTERLEAVED_IMPL_LOAD4_STORE4(int16_t, v8i16, v8i16, s16, h, 8) +MSA_INTERLEAVED_IMPL_LOAD4_STORE4(uint32_t, v4u32, v4i32, u32, w, 4) +MSA_INTERLEAVED_IMPL_LOAD4_STORE4(int32_t, v4i32, v4i32, s32, w, 4) +MSA_INTERLEAVED_IMPL_LOAD4_STORE4(float, v4f32, v4i32, f32, w, 4) + +#define MSA_INTERLEAVED_IMPL_LOAD4_STORE4_64(_Tp, _Tpv, _Tpvs, suffix) \ +__extension__ extern __inline void \ +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \ +msa_ld4q_##suffix(const _Tp* ptr, _Tpv* a, _Tpv* b, _Tpv* c, _Tpv* d) \ +{ \ + _Tpv v0 = msa_ld1q_##suffix(ptr); \ + _Tpv v1 = msa_ld1q_##suffix(ptr + 2); \ + _Tpv v2 = msa_ld1q_##suffix(ptr + 4); \ + _Tpv v3 = msa_ld1q_##suffix(ptr + 6); \ + *a = (_Tpv)__builtin_msa_ilvr_d((_Tpvs)v2, (_Tpvs)v0); \ + *b = (_Tpv)__builtin_msa_ilvl_d((_Tpvs)v2, (_Tpvs)v0); \ + *c = (_Tpv)__builtin_msa_ilvr_d((_Tpvs)v3, (_Tpvs)v1); \ + *d = (_Tpv)__builtin_msa_ilvl_d((_Tpvs)v3, (_Tpvs)v1); \ +} \ +__extension__ extern __inline void \ +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \ +msa_st4q_##suffix(_Tp* ptr, const _Tpv a, const _Tpv b, const _Tpv c, const _Tpv d) \ +{ \ + msa_st1q_##suffix(ptr, (_Tpv)__builtin_msa_ilvr_d((_Tpvs)b, (_Tpvs)a)); \ + msa_st1q_##suffix(ptr + 2, (_Tpv)__builtin_msa_ilvr_d((_Tpvs)d, (_Tpvs)c)); \ + msa_st1q_##suffix(ptr + 4, (_Tpv)__builtin_msa_ilvl_d((_Tpvs)b, (_Tpvs)a)); \ + msa_st1q_##suffix(ptr + 6, (_Tpv)__builtin_msa_ilvl_d((_Tpvs)d, (_Tpvs)c)); \ +} + +MSA_INTERLEAVED_IMPL_LOAD4_STORE4_64(uint64_t, v2u64, v2i64, u64) +MSA_INTERLEAVED_IMPL_LOAD4_STORE4_64(int64_t, v2i64, v2i64, s64) +MSA_INTERLEAVED_IMPL_LOAD4_STORE4_64(double, v2f64, v2i64, f64) + +__extension__ extern __inline v8i16 +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +msa_qdmulhq_n_s16(v8i16 a, int16_t b) +{ + v8i16 a_lo, a_hi; + ILVRL_H2_SH(a, msa_dupq_n_s16(0), a_lo, a_hi); + return msa_packr_s32(msa_shlq_n_s32(msa_mulq_s32(msa_paddlq_s16(a_lo), msa_dupq_n_s32(b)), 1), + msa_shlq_n_s32(msa_mulq_s32(msa_paddlq_s16(a_hi), msa_dupq_n_s32(b)), 1), 16); +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /*__mips_msa*/ +#endif /* OPENCV_CORE_MSA_MACROS_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/simd_utils.impl.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/simd_utils.impl.hpp new file mode 100644 index 0000000..fff8f94 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/hal/simd_utils.impl.hpp @@ -0,0 +1,146 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + +// This header is not standalone. Don't include directly, use "intrin.hpp" instead. +#ifdef OPENCV_HAL_INTRIN_HPP // defined in intrin.hpp + + +#if CV_SIMD128 || CV_SIMD128_CPP + +template struct Type2Vec128_Traits; +#define CV_INTRIN_DEF_TYPE2VEC128_TRAITS(type_, vec_type_) \ + template<> struct Type2Vec128_Traits \ + { \ + typedef vec_type_ vec_type; \ + } + +CV_INTRIN_DEF_TYPE2VEC128_TRAITS(uchar, v_uint8x16); +CV_INTRIN_DEF_TYPE2VEC128_TRAITS(schar, v_int8x16); +CV_INTRIN_DEF_TYPE2VEC128_TRAITS(ushort, v_uint16x8); +CV_INTRIN_DEF_TYPE2VEC128_TRAITS(short, v_int16x8); +CV_INTRIN_DEF_TYPE2VEC128_TRAITS(unsigned, v_uint32x4); +CV_INTRIN_DEF_TYPE2VEC128_TRAITS(int, v_int32x4); +CV_INTRIN_DEF_TYPE2VEC128_TRAITS(float, v_float32x4); +CV_INTRIN_DEF_TYPE2VEC128_TRAITS(uint64, v_uint64x2); +CV_INTRIN_DEF_TYPE2VEC128_TRAITS(int64, v_int64x2); +#if CV_SIMD128_64F +CV_INTRIN_DEF_TYPE2VEC128_TRAITS(double, v_float64x2); +#endif + +template static inline +typename Type2Vec128_Traits<_T>::vec_type v_setall(const _T& a); + +template<> inline Type2Vec128_Traits< uchar>::vec_type v_setall< uchar>(const uchar& a) { return v_setall_u8(a); } +template<> inline Type2Vec128_Traits< schar>::vec_type v_setall< schar>(const schar& a) { return v_setall_s8(a); } +template<> inline Type2Vec128_Traits::vec_type v_setall(const ushort& a) { return v_setall_u16(a); } +template<> inline Type2Vec128_Traits< short>::vec_type v_setall< short>(const short& a) { return v_setall_s16(a); } +template<> inline Type2Vec128_Traits< uint>::vec_type v_setall< uint>(const uint& a) { return v_setall_u32(a); } +template<> inline Type2Vec128_Traits< int>::vec_type v_setall< int>(const int& a) { return v_setall_s32(a); } +template<> inline Type2Vec128_Traits::vec_type v_setall(const uint64& a) { return v_setall_u64(a); } +template<> inline Type2Vec128_Traits< int64>::vec_type v_setall< int64>(const int64& a) { return v_setall_s64(a); } +template<> inline Type2Vec128_Traits< float>::vec_type v_setall< float>(const float& a) { return v_setall_f32(a); } +#if CV_SIMD128_64F +template<> inline Type2Vec128_Traits::vec_type v_setall(const double& a) { return v_setall_f64(a); } +#endif + +#endif // SIMD128 + + +#if CV_SIMD256 + +template struct Type2Vec256_Traits; +#define CV_INTRIN_DEF_TYPE2VEC256_TRAITS(type_, vec_type_) \ + template<> struct Type2Vec256_Traits \ + { \ + typedef vec_type_ vec_type; \ + } + +CV_INTRIN_DEF_TYPE2VEC256_TRAITS(uchar, v_uint8x32); +CV_INTRIN_DEF_TYPE2VEC256_TRAITS(schar, v_int8x32); +CV_INTRIN_DEF_TYPE2VEC256_TRAITS(ushort, v_uint16x16); +CV_INTRIN_DEF_TYPE2VEC256_TRAITS(short, v_int16x16); +CV_INTRIN_DEF_TYPE2VEC256_TRAITS(unsigned, v_uint32x8); +CV_INTRIN_DEF_TYPE2VEC256_TRAITS(int, v_int32x8); +CV_INTRIN_DEF_TYPE2VEC256_TRAITS(float, v_float32x8); +CV_INTRIN_DEF_TYPE2VEC256_TRAITS(uint64, v_uint64x4); +CV_INTRIN_DEF_TYPE2VEC256_TRAITS(int64, v_int64x4); +#if CV_SIMD256_64F +CV_INTRIN_DEF_TYPE2VEC256_TRAITS(double, v_float64x4); +#endif + +template static inline +typename Type2Vec256_Traits<_T>::vec_type v256_setall(const _T& a); + +template<> inline Type2Vec256_Traits< uchar>::vec_type v256_setall< uchar>(const uchar& a) { return v256_setall_u8(a); } +template<> inline Type2Vec256_Traits< schar>::vec_type v256_setall< schar>(const schar& a) { return v256_setall_s8(a); } +template<> inline Type2Vec256_Traits::vec_type v256_setall(const ushort& a) { return v256_setall_u16(a); } +template<> inline Type2Vec256_Traits< short>::vec_type v256_setall< short>(const short& a) { return v256_setall_s16(a); } +template<> inline Type2Vec256_Traits< uint>::vec_type v256_setall< uint>(const uint& a) { return v256_setall_u32(a); } +template<> inline Type2Vec256_Traits< int>::vec_type v256_setall< int>(const int& a) { return v256_setall_s32(a); } +template<> inline Type2Vec256_Traits::vec_type v256_setall(const uint64& a) { return v256_setall_u64(a); } +template<> inline Type2Vec256_Traits< int64>::vec_type v256_setall< int64>(const int64& a) { return v256_setall_s64(a); } +template<> inline Type2Vec256_Traits< float>::vec_type v256_setall< float>(const float& a) { return v256_setall_f32(a); } +#if CV_SIMD256_64F +template<> inline Type2Vec256_Traits::vec_type v256_setall(const double& a) { return v256_setall_f64(a); } +#endif + +#endif // SIMD256 + + +#if CV_SIMD512 + +template struct Type2Vec512_Traits; +#define CV_INTRIN_DEF_TYPE2VEC512_TRAITS(type_, vec_type_) \ + template<> struct Type2Vec512_Traits \ + { \ + typedef vec_type_ vec_type; \ + } + +CV_INTRIN_DEF_TYPE2VEC512_TRAITS(uchar, v_uint8x64); +CV_INTRIN_DEF_TYPE2VEC512_TRAITS(schar, v_int8x64); +CV_INTRIN_DEF_TYPE2VEC512_TRAITS(ushort, v_uint16x32); +CV_INTRIN_DEF_TYPE2VEC512_TRAITS(short, v_int16x32); +CV_INTRIN_DEF_TYPE2VEC512_TRAITS(unsigned, v_uint32x16); +CV_INTRIN_DEF_TYPE2VEC512_TRAITS(int, v_int32x16); +CV_INTRIN_DEF_TYPE2VEC512_TRAITS(float, v_float32x16); +CV_INTRIN_DEF_TYPE2VEC512_TRAITS(uint64, v_uint64x8); +CV_INTRIN_DEF_TYPE2VEC512_TRAITS(int64, v_int64x8); +#if CV_SIMD512_64F +CV_INTRIN_DEF_TYPE2VEC512_TRAITS(double, v_float64x8); +#endif + +template static inline +typename Type2Vec512_Traits<_T>::vec_type v512_setall(const _T& a); + +template<> inline Type2Vec512_Traits< uchar>::vec_type v512_setall< uchar>(const uchar& a) { return v512_setall_u8(a); } +template<> inline Type2Vec512_Traits< schar>::vec_type v512_setall< schar>(const schar& a) { return v512_setall_s8(a); } +template<> inline Type2Vec512_Traits::vec_type v512_setall(const ushort& a) { return v512_setall_u16(a); } +template<> inline Type2Vec512_Traits< short>::vec_type v512_setall< short>(const short& a) { return v512_setall_s16(a); } +template<> inline Type2Vec512_Traits< uint>::vec_type v512_setall< uint>(const uint& a) { return v512_setall_u32(a); } +template<> inline Type2Vec512_Traits< int>::vec_type v512_setall< int>(const int& a) { return v512_setall_s32(a); } +template<> inline Type2Vec512_Traits::vec_type v512_setall(const uint64& a) { return v512_setall_u64(a); } +template<> inline Type2Vec512_Traits< int64>::vec_type v512_setall< int64>(const int64& a) { return v512_setall_s64(a); } +template<> inline Type2Vec512_Traits< float>::vec_type v512_setall< float>(const float& a) { return v512_setall_f32(a); } +#if CV_SIMD512_64F +template<> inline Type2Vec512_Traits::vec_type v512_setall(const double& a) { return v512_setall_f64(a); } +#endif + +#endif // SIMD512 + + +#if CV_SIMD_WIDTH == 16 +template static inline +typename Type2Vec128_Traits<_T>::vec_type vx_setall(const _T& a) { return v_setall(a); } +#elif CV_SIMD_WIDTH == 32 +template static inline +typename Type2Vec256_Traits<_T>::vec_type vx_setall(const _T& a) { return v256_setall(a); } +#elif CV_SIMD_WIDTH == 64 +template static inline +typename Type2Vec512_Traits<_T>::vec_type vx_setall(const _T& a) { return v512_setall(a); } +#else +#error "Build configuration error, unsupported CV_SIMD_WIDTH" +#endif + + +#endif // OPENCV_HAL_INTRIN_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/mat.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/mat.hpp new file mode 100644 index 0000000..2aba15c --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/mat.hpp @@ -0,0 +1,3775 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_MAT_HPP +#define OPENCV_CORE_MAT_HPP + +#ifndef __cplusplus +# error mat.hpp header must be compiled as C++ +#endif + +#include "opencv2/core/matx.hpp" +#include "opencv2/core/types.hpp" + +#include "opencv2/core/bufferpool.hpp" + +#include + +namespace cv +{ + +//! @addtogroup core_basic +//! @{ + +enum AccessFlag { ACCESS_READ=1<<24, ACCESS_WRITE=1<<25, + ACCESS_RW=3<<24, ACCESS_MASK=ACCESS_RW, ACCESS_FAST=1<<26 }; +CV_ENUM_FLAGS(AccessFlag) +__CV_ENUM_FLAGS_BITWISE_AND(AccessFlag, int, AccessFlag) + +CV__DEBUG_NS_BEGIN + +class CV_EXPORTS _OutputArray; + +//////////////////////// Input/Output Array Arguments ///////////////////////////////// + +/** @brief This is the proxy class for passing read-only input arrays into OpenCV functions. + +It is defined as: +@code + typedef const _InputArray& InputArray; +@endcode +where _InputArray is a class that can be constructed from `Mat`, `Mat_`, `Matx`, +`std::vector`, `std::vector >`, `std::vector`, `std::vector >`, +`UMat`, `std::vector` or `double`. It can also be constructed from a matrix expression. + +Since this is mostly implementation-level class, and its interface may change in future versions, we +do not describe it in details. There are a few key things, though, that should be kept in mind: + +- When you see in the reference manual or in OpenCV source code a function that takes + InputArray, it means that you can actually pass `Mat`, `Matx`, `vector` etc. (see above the + complete list). +- Optional input arguments: If some of the input arrays may be empty, pass cv::noArray() (or + simply cv::Mat() as you probably did before). +- The class is designed solely for passing parameters. That is, normally you *should not* + declare class members, local and global variables of this type. +- If you want to design your own function or a class method that can operate of arrays of + multiple types, you can use InputArray (or OutputArray) for the respective parameters. Inside + a function you should use _InputArray::getMat() method to construct a matrix header for the + array (without copying data). _InputArray::kind() can be used to distinguish Mat from + `vector<>` etc., but normally it is not needed. + +Here is how you can use a function that takes InputArray : +@code + std::vector vec; + // points or a circle + for( int i = 0; i < 30; i++ ) + vec.push_back(Point2f((float)(100 + 30*cos(i*CV_PI*2/5)), + (float)(100 - 30*sin(i*CV_PI*2/5)))); + cv::transform(vec, vec, cv::Matx23f(0.707, -0.707, 10, 0.707, 0.707, 20)); +@endcode +That is, we form an STL vector containing points, and apply in-place affine transformation to the +vector using the 2x3 matrix created inline as `Matx` instance. + +Here is how such a function can be implemented (for simplicity, we implement a very specific case of +it, according to the assertion statement inside) : +@code + void myAffineTransform(InputArray _src, OutputArray _dst, InputArray _m) + { + // get Mat headers for input arrays. This is O(1) operation, + // unless _src and/or _m are matrix expressions. + Mat src = _src.getMat(), m = _m.getMat(); + CV_Assert( src.type() == CV_32FC2 && m.type() == CV_32F && m.size() == Size(3, 2) ); + + // [re]create the output array so that it has the proper size and type. + // In case of Mat it calls Mat::create, in case of STL vector it calls vector::resize. + _dst.create(src.size(), src.type()); + Mat dst = _dst.getMat(); + + for( int i = 0; i < src.rows; i++ ) + for( int j = 0; j < src.cols; j++ ) + { + Point2f pt = src.at(i, j); + dst.at(i, j) = Point2f(m.at(0, 0)*pt.x + + m.at(0, 1)*pt.y + + m.at(0, 2), + m.at(1, 0)*pt.x + + m.at(1, 1)*pt.y + + m.at(1, 2)); + } + } +@endcode +There is another related type, InputArrayOfArrays, which is currently defined as a synonym for +InputArray: +@code + typedef InputArray InputArrayOfArrays; +@endcode +It denotes function arguments that are either vectors of vectors or vectors of matrices. A separate +synonym is needed to generate Python/Java etc. wrappers properly. At the function implementation +level their use is similar, but _InputArray::getMat(idx) should be used to get header for the +idx-th component of the outer vector and _InputArray::size().area() should be used to find the +number of components (vectors/matrices) of the outer vector. + +In general, type support is limited to cv::Mat types. Other types are forbidden. +But in some cases we need to support passing of custom non-general Mat types, like arrays of cv::KeyPoint, cv::DMatch, etc. +This data is not intended to be interpreted as an image data, or processed somehow like regular cv::Mat. +To pass such custom type use rawIn() / rawOut() / rawInOut() wrappers. +Custom type is wrapped as Mat-compatible `CV_8UC` values (N = sizeof(T), N <= CV_CN_MAX). + */ +class CV_EXPORTS _InputArray +{ +public: + enum KindFlag { + KIND_SHIFT = 16, + FIXED_TYPE = 0x8000 << KIND_SHIFT, + FIXED_SIZE = 0x4000 << KIND_SHIFT, + KIND_MASK = 31 << KIND_SHIFT, + + NONE = 0 << KIND_SHIFT, + MAT = 1 << KIND_SHIFT, + MATX = 2 << KIND_SHIFT, + STD_VECTOR = 3 << KIND_SHIFT, + STD_VECTOR_VECTOR = 4 << KIND_SHIFT, + STD_VECTOR_MAT = 5 << KIND_SHIFT, +#if OPENCV_ABI_COMPATIBILITY < 500 + EXPR = 6 << KIND_SHIFT, //!< removed: https://github.com/opencv/opencv/pull/17046 +#endif + OPENGL_BUFFER = 7 << KIND_SHIFT, + CUDA_HOST_MEM = 8 << KIND_SHIFT, + CUDA_GPU_MAT = 9 << KIND_SHIFT, + UMAT =10 << KIND_SHIFT, + STD_VECTOR_UMAT =11 << KIND_SHIFT, + STD_BOOL_VECTOR =12 << KIND_SHIFT, + STD_VECTOR_CUDA_GPU_MAT = 13 << KIND_SHIFT, +#if OPENCV_ABI_COMPATIBILITY < 500 + STD_ARRAY =14 << KIND_SHIFT, //!< removed: https://github.com/opencv/opencv/issues/18897 +#endif + STD_ARRAY_MAT =15 << KIND_SHIFT + }; + + _InputArray(); + _InputArray(int _flags, void* _obj); + _InputArray(const Mat& m); + _InputArray(const MatExpr& expr); + _InputArray(const std::vector& vec); + template _InputArray(const Mat_<_Tp>& m); + template _InputArray(const std::vector<_Tp>& vec); + _InputArray(const std::vector& vec); + template _InputArray(const std::vector >& vec); + _InputArray(const std::vector >&) = delete; // not supported + template _InputArray(const std::vector >& vec); + template _InputArray(const _Tp* vec, int n); + template _InputArray(const Matx<_Tp, m, n>& matx); + _InputArray(const double& val); + _InputArray(const cuda::GpuMat& d_mat); + _InputArray(const std::vector& d_mat_array); + _InputArray(const ogl::Buffer& buf); + _InputArray(const cuda::HostMem& cuda_mem); + template _InputArray(const cudev::GpuMat_<_Tp>& m); + _InputArray(const UMat& um); + _InputArray(const std::vector& umv); + + template _InputArray(const std::array<_Tp, _Nm>& arr); + template _InputArray(const std::array& arr); + + template static _InputArray rawIn(const std::vector<_Tp>& vec); + template static _InputArray rawIn(const std::array<_Tp, _Nm>& arr); + + Mat getMat(int idx=-1) const; + Mat getMat_(int idx=-1) const; + UMat getUMat(int idx=-1) const; + void getMatVector(std::vector& mv) const; + void getUMatVector(std::vector& umv) const; + void getGpuMatVector(std::vector& gpumv) const; + cuda::GpuMat getGpuMat() const; + ogl::Buffer getOGlBuffer() const; + + int getFlags() const; + void* getObj() const; + Size getSz() const; + + _InputArray::KindFlag kind() const; + int dims(int i=-1) const; + int cols(int i=-1) const; + int rows(int i=-1) const; + Size size(int i=-1) const; + int sizend(int* sz, int i=-1) const; + bool sameSize(const _InputArray& arr) const; + size_t total(int i=-1) const; + int type(int i=-1) const; + int depth(int i=-1) const; + int channels(int i=-1) const; + bool isContinuous(int i=-1) const; + bool isSubmatrix(int i=-1) const; + bool empty() const; + void copyTo(const _OutputArray& arr) const; + void copyTo(const _OutputArray& arr, const _InputArray & mask) const; + size_t offset(int i=-1) const; + size_t step(int i=-1) const; + bool isMat() const; + bool isUMat() const; + bool isMatVector() const; + bool isUMatVector() const; + bool isMatx() const; + bool isVector() const; + bool isGpuMat() const; + bool isGpuMatVector() const; + ~_InputArray(); + +protected: + int flags; + void* obj; + Size sz; + + void init(int _flags, const void* _obj); + void init(int _flags, const void* _obj, Size _sz); +}; +CV_ENUM_FLAGS(_InputArray::KindFlag) +__CV_ENUM_FLAGS_BITWISE_AND(_InputArray::KindFlag, int, _InputArray::KindFlag) + +/** @brief This type is very similar to InputArray except that it is used for input/output and output function +parameters. + +Just like with InputArray, OpenCV users should not care about OutputArray, they just pass `Mat`, +`vector` etc. to the functions. The same limitation as for `InputArray`: *Do not explicitly +create OutputArray instances* applies here too. + +If you want to make your function polymorphic (i.e. accept different arrays as output parameters), +it is also not very difficult. Take the sample above as the reference. Note that +_OutputArray::create() needs to be called before _OutputArray::getMat(). This way you guarantee +that the output array is properly allocated. + +Optional output parameters. If you do not need certain output array to be computed and returned to +you, pass cv::noArray(), just like you would in the case of optional input array. At the +implementation level, use _OutputArray::needed() to check if certain output array needs to be +computed or not. + +There are several synonyms for OutputArray that are used to assist automatic Python/Java/... wrapper +generators: +@code + typedef OutputArray OutputArrayOfArrays; + typedef OutputArray InputOutputArray; + typedef OutputArray InputOutputArrayOfArrays; +@endcode + */ +class CV_EXPORTS _OutputArray : public _InputArray +{ +public: + enum DepthMask + { + DEPTH_MASK_8U = 1 << CV_8U, + DEPTH_MASK_8S = 1 << CV_8S, + DEPTH_MASK_16U = 1 << CV_16U, + DEPTH_MASK_16S = 1 << CV_16S, + DEPTH_MASK_32S = 1 << CV_32S, + DEPTH_MASK_32F = 1 << CV_32F, + DEPTH_MASK_64F = 1 << CV_64F, + DEPTH_MASK_16F = 1 << CV_16F, + DEPTH_MASK_ALL = (DEPTH_MASK_64F<<1)-1, + DEPTH_MASK_ALL_BUT_8S = DEPTH_MASK_ALL & ~DEPTH_MASK_8S, + DEPTH_MASK_ALL_16F = (DEPTH_MASK_16F<<1)-1, + DEPTH_MASK_FLT = DEPTH_MASK_32F + DEPTH_MASK_64F + }; + + _OutputArray(); + _OutputArray(int _flags, void* _obj); + _OutputArray(Mat& m); + _OutputArray(std::vector& vec); + _OutputArray(cuda::GpuMat& d_mat); + _OutputArray(std::vector& d_mat); + _OutputArray(ogl::Buffer& buf); + _OutputArray(cuda::HostMem& cuda_mem); + template _OutputArray(cudev::GpuMat_<_Tp>& m); + template _OutputArray(std::vector<_Tp>& vec); + _OutputArray(std::vector& vec) = delete; // not supported + template _OutputArray(std::vector >& vec); + _OutputArray(std::vector >&) = delete; // not supported + template _OutputArray(std::vector >& vec); + template _OutputArray(Mat_<_Tp>& m); + template _OutputArray(_Tp* vec, int n); + template _OutputArray(Matx<_Tp, m, n>& matx); + _OutputArray(UMat& m); + _OutputArray(std::vector& vec); + + _OutputArray(const Mat& m); + _OutputArray(const std::vector& vec); + _OutputArray(const cuda::GpuMat& d_mat); + _OutputArray(const std::vector& d_mat); + _OutputArray(const ogl::Buffer& buf); + _OutputArray(const cuda::HostMem& cuda_mem); + template _OutputArray(const cudev::GpuMat_<_Tp>& m); + template _OutputArray(const std::vector<_Tp>& vec); + template _OutputArray(const std::vector >& vec); + template _OutputArray(const std::vector >& vec); + template _OutputArray(const Mat_<_Tp>& m); + template _OutputArray(const _Tp* vec, int n); + template _OutputArray(const Matx<_Tp, m, n>& matx); + _OutputArray(const UMat& m); + _OutputArray(const std::vector& vec); + + template _OutputArray(std::array<_Tp, _Nm>& arr); + template _OutputArray(const std::array<_Tp, _Nm>& arr); + template _OutputArray(std::array& arr); + template _OutputArray(const std::array& arr); + + template static _OutputArray rawOut(std::vector<_Tp>& vec); + template static _OutputArray rawOut(std::array<_Tp, _Nm>& arr); + + bool fixedSize() const; + bool fixedType() const; + bool needed() const; + Mat& getMatRef(int i=-1) const; + UMat& getUMatRef(int i=-1) const; + cuda::GpuMat& getGpuMatRef() const; + std::vector& getGpuMatVecRef() const; + ogl::Buffer& getOGlBufferRef() const; + cuda::HostMem& getHostMemRef() const; + void create(Size sz, int type, int i=-1, bool allowTransposed=false, _OutputArray::DepthMask fixedDepthMask=static_cast<_OutputArray::DepthMask>(0)) const; + void create(int rows, int cols, int type, int i=-1, bool allowTransposed=false, _OutputArray::DepthMask fixedDepthMask=static_cast<_OutputArray::DepthMask>(0)) const; + void create(int dims, const int* size, int type, int i=-1, bool allowTransposed=false, _OutputArray::DepthMask fixedDepthMask=static_cast<_OutputArray::DepthMask>(0)) const; + void createSameSize(const _InputArray& arr, int mtype) const; + void release() const; + void clear() const; + void setTo(const _InputArray& value, const _InputArray & mask = _InputArray()) const; + + void assign(const UMat& u) const; + void assign(const Mat& m) const; + + void assign(const std::vector& v) const; + void assign(const std::vector& v) const; + + void move(UMat& u) const; + void move(Mat& m) const; +}; + + +class CV_EXPORTS _InputOutputArray : public _OutputArray +{ +public: + _InputOutputArray(); + _InputOutputArray(int _flags, void* _obj); + _InputOutputArray(Mat& m); + _InputOutputArray(std::vector& vec); + _InputOutputArray(cuda::GpuMat& d_mat); + _InputOutputArray(ogl::Buffer& buf); + _InputOutputArray(cuda::HostMem& cuda_mem); + template _InputOutputArray(cudev::GpuMat_<_Tp>& m); + template _InputOutputArray(std::vector<_Tp>& vec); + _InputOutputArray(std::vector& vec) = delete; // not supported + template _InputOutputArray(std::vector >& vec); + template _InputOutputArray(std::vector >& vec); + template _InputOutputArray(Mat_<_Tp>& m); + template _InputOutputArray(_Tp* vec, int n); + template _InputOutputArray(Matx<_Tp, m, n>& matx); + _InputOutputArray(UMat& m); + _InputOutputArray(std::vector& vec); + + _InputOutputArray(const Mat& m); + _InputOutputArray(const std::vector& vec); + _InputOutputArray(const cuda::GpuMat& d_mat); + _InputOutputArray(const std::vector& d_mat); + _InputOutputArray(const ogl::Buffer& buf); + _InputOutputArray(const cuda::HostMem& cuda_mem); + template _InputOutputArray(const cudev::GpuMat_<_Tp>& m); + template _InputOutputArray(const std::vector<_Tp>& vec); + template _InputOutputArray(const std::vector >& vec); + template _InputOutputArray(const std::vector >& vec); + template _InputOutputArray(const Mat_<_Tp>& m); + template _InputOutputArray(const _Tp* vec, int n); + template _InputOutputArray(const Matx<_Tp, m, n>& matx); + _InputOutputArray(const UMat& m); + _InputOutputArray(const std::vector& vec); + + template _InputOutputArray(std::array<_Tp, _Nm>& arr); + template _InputOutputArray(const std::array<_Tp, _Nm>& arr); + template _InputOutputArray(std::array& arr); + template _InputOutputArray(const std::array& arr); + + template static _InputOutputArray rawInOut(std::vector<_Tp>& vec); + template _InputOutputArray rawInOut(std::array<_Tp, _Nm>& arr); + +}; + +/** Helper to wrap custom types. @see InputArray */ +template static inline _InputArray rawIn(_Tp& v); +/** Helper to wrap custom types. @see InputArray */ +template static inline _OutputArray rawOut(_Tp& v); +/** Helper to wrap custom types. @see InputArray */ +template static inline _InputOutputArray rawInOut(_Tp& v); + +CV__DEBUG_NS_END + +typedef const _InputArray& InputArray; +typedef InputArray InputArrayOfArrays; +typedef const _OutputArray& OutputArray; +typedef OutputArray OutputArrayOfArrays; +typedef const _InputOutputArray& InputOutputArray; +typedef InputOutputArray InputOutputArrayOfArrays; + +CV_EXPORTS InputOutputArray noArray(); + +/////////////////////////////////// MatAllocator ////////////////////////////////////// + +/** @brief Usage flags for allocator + + @warning All flags except `USAGE_DEFAULT` are experimental. + + @warning For the OpenCL allocator, `USAGE_ALLOCATE_SHARED_MEMORY` depends on + OpenCV's optional, experimental integration with OpenCL SVM. To enable this + integration, build OpenCV using the `WITH_OPENCL_SVM=ON` CMake option and, at + runtime, call `cv::ocl::Context::getDefault().setUseSVM(true);` or similar + code. Note that SVM is incompatible with OpenCL 1.x. +*/ +enum UMatUsageFlags +{ + USAGE_DEFAULT = 0, + + // buffer allocation policy is platform and usage specific + USAGE_ALLOCATE_HOST_MEMORY = 1 << 0, + USAGE_ALLOCATE_DEVICE_MEMORY = 1 << 1, + USAGE_ALLOCATE_SHARED_MEMORY = 1 << 2, // It is not equal to: USAGE_ALLOCATE_HOST_MEMORY | USAGE_ALLOCATE_DEVICE_MEMORY + + __UMAT_USAGE_FLAGS_32BIT = 0x7fffffff // Binary compatibility hint +}; + +struct CV_EXPORTS UMatData; + +/** @brief Custom array allocator +*/ +class CV_EXPORTS MatAllocator +{ +public: + MatAllocator() {} + virtual ~MatAllocator() {} + + // let's comment it off for now to detect and fix all the uses of allocator + //virtual void allocate(int dims, const int* sizes, int type, int*& refcount, + // uchar*& datastart, uchar*& data, size_t* step) = 0; + //virtual void deallocate(int* refcount, uchar* datastart, uchar* data) = 0; + virtual UMatData* allocate(int dims, const int* sizes, int type, + void* data, size_t* step, AccessFlag flags, UMatUsageFlags usageFlags) const = 0; + virtual bool allocate(UMatData* data, AccessFlag accessflags, UMatUsageFlags usageFlags) const = 0; + virtual void deallocate(UMatData* data) const = 0; + virtual void map(UMatData* data, AccessFlag accessflags) const; + virtual void unmap(UMatData* data) const; + virtual void download(UMatData* data, void* dst, int dims, const size_t sz[], + const size_t srcofs[], const size_t srcstep[], + const size_t dststep[]) const; + virtual void upload(UMatData* data, const void* src, int dims, const size_t sz[], + const size_t dstofs[], const size_t dststep[], + const size_t srcstep[]) const; + virtual void copy(UMatData* srcdata, UMatData* dstdata, int dims, const size_t sz[], + const size_t srcofs[], const size_t srcstep[], + const size_t dstofs[], const size_t dststep[], bool sync) const; + + // default implementation returns DummyBufferPoolController + virtual BufferPoolController* getBufferPoolController(const char* id = NULL) const; +}; + + +//////////////////////////////// MatCommaInitializer ////////////////////////////////// + +/** @brief Comma-separated Matrix Initializer + + The class instances are usually not created explicitly. + Instead, they are created on "matrix << firstValue" operator. + + The sample below initializes 2x2 rotation matrix: + + \code + double angle = 30, a = cos(angle*CV_PI/180), b = sin(angle*CV_PI/180); + Mat R = (Mat_(2,2) << a, -b, b, a); + \endcode +*/ +template class MatCommaInitializer_ +{ +public: + //! the constructor, created by "matrix << firstValue" operator, where matrix is cv::Mat + MatCommaInitializer_(Mat_<_Tp>* _m); + //! the operator that takes the next value and put it to the matrix + template MatCommaInitializer_<_Tp>& operator , (T2 v); + //! another form of conversion operator + operator Mat_<_Tp>() const; +protected: + MatIterator_<_Tp> it; +}; + + +/////////////////////////////////////// Mat /////////////////////////////////////////// + +// note that umatdata might be allocated together +// with the matrix data, not as a separate object. +// therefore, it does not have constructor or destructor; +// it should be explicitly initialized using init(). +struct CV_EXPORTS UMatData +{ + enum MemoryFlag { COPY_ON_MAP=1, HOST_COPY_OBSOLETE=2, + DEVICE_COPY_OBSOLETE=4, TEMP_UMAT=8, TEMP_COPIED_UMAT=24, + USER_ALLOCATED=32, DEVICE_MEM_MAPPED=64, + ASYNC_CLEANUP=128 + }; + UMatData(const MatAllocator* allocator); + ~UMatData(); + + // provide atomic access to the structure + void lock(); + void unlock(); + + bool hostCopyObsolete() const; + bool deviceCopyObsolete() const; + bool deviceMemMapped() const; + bool copyOnMap() const; + bool tempUMat() const; + bool tempCopiedUMat() const; + void markHostCopyObsolete(bool flag); + void markDeviceCopyObsolete(bool flag); + void markDeviceMemMapped(bool flag); + + const MatAllocator* prevAllocator; + const MatAllocator* currAllocator; + int urefcount; + int refcount; + uchar* data; + uchar* origdata; + size_t size; + + UMatData::MemoryFlag flags; + void* handle; + void* userdata; + int allocatorFlags_; + int mapcount; + UMatData* originalUMatData; + std::shared_ptr allocatorContext; +}; +CV_ENUM_FLAGS(UMatData::MemoryFlag) + + +struct CV_EXPORTS MatSize +{ + explicit MatSize(int* _p) CV_NOEXCEPT; + int dims() const CV_NOEXCEPT; + Size operator()() const; + const int& operator[](int i) const; + int& operator[](int i); + operator const int*() const CV_NOEXCEPT; // TODO OpenCV 4.0: drop this + bool operator == (const MatSize& sz) const CV_NOEXCEPT; + bool operator != (const MatSize& sz) const CV_NOEXCEPT; + + int* p; +}; + +struct CV_EXPORTS MatStep +{ + MatStep() CV_NOEXCEPT; + explicit MatStep(size_t s) CV_NOEXCEPT; + const size_t& operator[](int i) const CV_NOEXCEPT; + size_t& operator[](int i) CV_NOEXCEPT; + operator size_t() const; + MatStep& operator = (size_t s); + + size_t* p; + size_t buf[2]; +protected: + MatStep& operator = (const MatStep&); +}; + +/** @example samples/cpp/cout_mat.cpp +An example demonstrating the serial out capabilities of cv::Mat +*/ + + /** @brief n-dimensional dense array class \anchor CVMat_Details + +The class Mat represents an n-dimensional dense numerical single-channel or multi-channel array. It +can be used to store real or complex-valued vectors and matrices, grayscale or color images, voxel +volumes, vector fields, point clouds, tensors, histograms (though, very high-dimensional histograms +may be better stored in a SparseMat ). The data layout of the array `M` is defined by the array +`M.step[]`, so that the address of element \f$(i_0,...,i_{M.dims-1})\f$, where \f$0\leq i_k= M.step[i+1]` (in fact, `M.step[i] >= M.step[i+1]*M.size[i+1]` ). This means +that 2-dimensional matrices are stored row-by-row, 3-dimensional matrices are stored plane-by-plane, +and so on. M.step[M.dims-1] is minimal and always equal to the element size M.elemSize() . + +So, the data layout in Mat is compatible with the majority of dense array types from the standard +toolkits and SDKs, such as Numpy (ndarray), Win32 (independent device bitmaps), and others, +that is, with any array that uses *steps* (or *strides*) to compute the position of a pixel. +Due to this compatibility, it is possible to make a Mat header for user-allocated data and process +it in-place using OpenCV functions. + +There are many different ways to create a Mat object. The most popular options are listed below: + +- Use the create(nrows, ncols, type) method or the similar Mat(nrows, ncols, type[, fillValue]) +constructor. A new array of the specified size and type is allocated. type has the same meaning as +in the cvCreateMat method. For example, CV_8UC1 means a 8-bit single-channel array, CV_32FC2 +means a 2-channel (complex) floating-point array, and so on. +@code + // make a 7x7 complex matrix filled with 1+3j. + Mat M(7,7,CV_32FC2,Scalar(1,3)); + // and now turn M to a 100x60 15-channel 8-bit matrix. + // The old content will be deallocated + M.create(100,60,CV_8UC(15)); +@endcode +As noted in the introduction to this chapter, create() allocates only a new array when the shape +or type of the current array are different from the specified ones. + +- Create a multi-dimensional array: +@code + // create a 100x100x100 8-bit array + int sz[] = {100, 100, 100}; + Mat bigCube(3, sz, CV_8U, Scalar::all(0)); +@endcode +It passes the number of dimensions =1 to the Mat constructor but the created array will be +2-dimensional with the number of columns set to 1. So, Mat::dims is always \>= 2 (can also be 0 +when the array is empty). + +- Use a copy constructor or assignment operator where there can be an array or expression on the +right side (see below). As noted in the introduction, the array assignment is an O(1) operation +because it only copies the header and increases the reference counter. The Mat::clone() method can +be used to get a full (deep) copy of the array when you need it. + +- Construct a header for a part of another array. It can be a single row, single column, several +rows, several columns, rectangular region in the array (called a *minor* in algebra) or a +diagonal. Such operations are also O(1) because the new header references the same data. You can +actually modify a part of the array using this feature, for example: +@code + // add the 5-th row, multiplied by 3 to the 3rd row + M.row(3) = M.row(3) + M.row(5)*3; + // now copy the 7-th column to the 1-st column + // M.col(1) = M.col(7); // this will not work + Mat M1 = M.col(1); + M.col(7).copyTo(M1); + // create a new 320x240 image + Mat img(Size(320,240),CV_8UC3); + // select a ROI + Mat roi(img, Rect(10,10,100,100)); + // fill the ROI with (0,255,0) (which is green in RGB space); + // the original 320x240 image will be modified + roi = Scalar(0,255,0); +@endcode +Due to the additional datastart and dataend members, it is possible to compute a relative +sub-array position in the main *container* array using locateROI(): +@code + Mat A = Mat::eye(10, 10, CV_32S); + // extracts A columns, 1 (inclusive) to 3 (exclusive). + Mat B = A(Range::all(), Range(1, 3)); + // extracts B rows, 5 (inclusive) to 9 (exclusive). + // that is, C \~ A(Range(5, 9), Range(1, 3)) + Mat C = B(Range(5, 9), Range::all()); + Size size; Point ofs; + C.locateROI(size, ofs); + // size will be (width=10,height=10) and the ofs will be (x=1, y=5) +@endcode +As in case of whole matrices, if you need a deep copy, use the `clone()` method of the extracted +sub-matrices. + +- Make a header for user-allocated data. It can be useful to do the following: + -# Process "foreign" data using OpenCV (for example, when you implement a DirectShow\* filter or + a processing module for gstreamer, and so on). For example: + @code + Mat process_video_frame(const unsigned char* pixels, + int width, int height, int step) + { + // wrap input buffer + Mat img(height, width, CV_8UC3, (unsigned char*)pixels, step); + + Mat result; + GaussianBlur(img, result, Size(7, 7), 1.5, 1.5); + + return result; + } + @endcode + -# Quickly initialize small matrices and/or get a super-fast element access. + @code + double m[3][3] = {{a, b, c}, {d, e, f}, {g, h, i}}; + Mat M = Mat(3, 3, CV_64F, m).inv(); + @endcode + . + +- Use MATLAB-style array initializers, zeros(), ones(), eye(), for example: +@code + // create a double-precision identity matrix and add it to M. + M += Mat::eye(M.rows, M.cols, CV_64F); +@endcode + +- Use a comma-separated initializer: +@code + // create a 3x3 double-precision identity matrix + Mat M = (Mat_(3,3) << 1, 0, 0, 0, 1, 0, 0, 0, 1); +@endcode +With this approach, you first call a constructor of the Mat class with the proper parameters, and +then you just put `<< operator` followed by comma-separated values that can be constants, +variables, expressions, and so on. Also, note the extra parentheses required to avoid compilation +errors. + +Once the array is created, it is automatically managed via a reference-counting mechanism. If the +array header is built on top of user-allocated data, you should handle the data by yourself. The +array data is deallocated when no one points to it. If you want to release the data pointed by a +array header before the array destructor is called, use Mat::release(). + +The next important thing to learn about the array class is element access. This manual already +described how to compute an address of each array element. Normally, you are not required to use the +formula directly in the code. If you know the array element type (which can be retrieved using the +method Mat::type() ), you can access the element \f$M_{ij}\f$ of a 2-dimensional array as: +@code + M.at(i,j) += 1.f; +@endcode +assuming that `M` is a double-precision floating-point array. There are several variants of the method +at for a different number of dimensions. + +If you need to process a whole row of a 2D array, the most efficient way is to get the pointer to +the row first, and then just use the plain C operator [] : +@code + // compute sum of positive matrix elements + // (assuming that M is a double-precision matrix) + double sum=0; + for(int i = 0; i < M.rows; i++) + { + const double* Mi = M.ptr(i); + for(int j = 0; j < M.cols; j++) + sum += std::max(Mi[j], 0.); + } +@endcode +Some operations, like the one above, do not actually depend on the array shape. They just process +elements of an array one by one (or elements from multiple arrays that have the same coordinates, +for example, array addition). Such operations are called *element-wise*. It makes sense to check +whether all the input/output arrays are continuous, namely, have no gaps at the end of each row. If +yes, process them as a long single row: +@code + // compute the sum of positive matrix elements, optimized variant + double sum=0; + int cols = M.cols, rows = M.rows; + if(M.isContinuous()) + { + cols *= rows; + rows = 1; + } + for(int i = 0; i < rows; i++) + { + const double* Mi = M.ptr(i); + for(int j = 0; j < cols; j++) + sum += std::max(Mi[j], 0.); + } +@endcode +In case of the continuous matrix, the outer loop body is executed just once. So, the overhead is +smaller, which is especially noticeable in case of small matrices. + +Finally, there are STL-style iterators that are smart enough to skip gaps between successive rows: +@code + // compute sum of positive matrix elements, iterator-based variant + double sum=0; + MatConstIterator_ it = M.begin(), it_end = M.end(); + for(; it != it_end; ++it) + sum += std::max(*it, 0.); +@endcode +The matrix iterators are random-access iterators, so they can be passed to any STL algorithm, +including std::sort(). + +@note Matrix Expressions and arithmetic see MatExpr +*/ +class CV_EXPORTS Mat +{ +public: + /** + These are various constructors that form a matrix. As noted in the AutomaticAllocation, often + the default constructor is enough, and the proper matrix will be allocated by an OpenCV function. + The constructed matrix can further be assigned to another matrix or matrix expression or can be + allocated with Mat::create . In the former case, the old content is de-referenced. + */ + Mat() CV_NOEXCEPT; + + /** @overload + @param rows Number of rows in a 2D array. + @param cols Number of columns in a 2D array. + @param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or + CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices. + */ + Mat(int rows, int cols, int type); + + /** @overload + @param size 2D array size: Size(cols, rows) . In the Size() constructor, the number of rows and the + number of columns go in the reverse order. + @param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or + CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices. + */ + Mat(Size size, int type); + + /** @overload + @param rows Number of rows in a 2D array. + @param cols Number of columns in a 2D array. + @param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or + CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices. + @param s An optional value to initialize each matrix element with. To set all the matrix elements to + the particular value after the construction, use the assignment operator + Mat::operator=(const Scalar& value) . + */ + Mat(int rows, int cols, int type, const Scalar& s); + + /** @overload + @param size 2D array size: Size(cols, rows) . In the Size() constructor, the number of rows and the + number of columns go in the reverse order. + @param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or + CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices. + @param s An optional value to initialize each matrix element with. To set all the matrix elements to + the particular value after the construction, use the assignment operator + Mat::operator=(const Scalar& value) . + */ + Mat(Size size, int type, const Scalar& s); + + /** @overload + @param ndims Array dimensionality. + @param sizes Array of integers specifying an n-dimensional array shape. + @param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or + CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices. + */ + Mat(int ndims, const int* sizes, int type); + + /** @overload + @param sizes Array of integers specifying an n-dimensional array shape. + @param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or + CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices. + */ + Mat(const std::vector& sizes, int type); + + /** @overload + @param ndims Array dimensionality. + @param sizes Array of integers specifying an n-dimensional array shape. + @param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or + CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices. + @param s An optional value to initialize each matrix element with. To set all the matrix elements to + the particular value after the construction, use the assignment operator + Mat::operator=(const Scalar& value) . + */ + Mat(int ndims, const int* sizes, int type, const Scalar& s); + + /** @overload + @param sizes Array of integers specifying an n-dimensional array shape. + @param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or + CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices. + @param s An optional value to initialize each matrix element with. To set all the matrix elements to + the particular value after the construction, use the assignment operator + Mat::operator=(const Scalar& value) . + */ + Mat(const std::vector& sizes, int type, const Scalar& s); + + + /** @overload + @param m Array that (as a whole or partly) is assigned to the constructed matrix. No data is copied + by these constructors. Instead, the header pointing to m data or its sub-array is constructed and + associated with it. The reference counter, if any, is incremented. So, when you modify the matrix + formed using such a constructor, you also modify the corresponding elements of m . If you want to + have an independent copy of the sub-array, use Mat::clone() . + */ + Mat(const Mat& m); + + /** @overload + @param rows Number of rows in a 2D array. + @param cols Number of columns in a 2D array. + @param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or + CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices. + @param data Pointer to the user data. Matrix constructors that take data and step parameters do not + allocate matrix data. Instead, they just initialize the matrix header that points to the specified + data, which means that no data is copied. This operation is very efficient and can be used to + process external data using OpenCV functions. The external data is not automatically deallocated, so + you should take care of it. + @param step Number of bytes each matrix row occupies. The value should include the padding bytes at + the end of each row, if any. If the parameter is missing (set to AUTO_STEP ), no padding is assumed + and the actual step is calculated as cols*elemSize(). See Mat::elemSize. + */ + Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP); + + /** @overload + @param size 2D array size: Size(cols, rows) . In the Size() constructor, the number of rows and the + number of columns go in the reverse order. + @param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or + CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices. + @param data Pointer to the user data. Matrix constructors that take data and step parameters do not + allocate matrix data. Instead, they just initialize the matrix header that points to the specified + data, which means that no data is copied. This operation is very efficient and can be used to + process external data using OpenCV functions. The external data is not automatically deallocated, so + you should take care of it. + @param step Number of bytes each matrix row occupies. The value should include the padding bytes at + the end of each row, if any. If the parameter is missing (set to AUTO_STEP ), no padding is assumed + and the actual step is calculated as cols*elemSize(). See Mat::elemSize. + */ + Mat(Size size, int type, void* data, size_t step=AUTO_STEP); + + /** @overload + @param ndims Array dimensionality. + @param sizes Array of integers specifying an n-dimensional array shape. + @param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or + CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices. + @param data Pointer to the user data. Matrix constructors that take data and step parameters do not + allocate matrix data. Instead, they just initialize the matrix header that points to the specified + data, which means that no data is copied. This operation is very efficient and can be used to + process external data using OpenCV functions. The external data is not automatically deallocated, so + you should take care of it. + @param steps Array of ndims-1 steps in case of a multi-dimensional array (the last step is always + set to the element size). If not specified, the matrix is assumed to be continuous. + */ + Mat(int ndims, const int* sizes, int type, void* data, const size_t* steps=0); + + /** @overload + @param sizes Array of integers specifying an n-dimensional array shape. + @param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or + CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices. + @param data Pointer to the user data. Matrix constructors that take data and step parameters do not + allocate matrix data. Instead, they just initialize the matrix header that points to the specified + data, which means that no data is copied. This operation is very efficient and can be used to + process external data using OpenCV functions. The external data is not automatically deallocated, so + you should take care of it. + @param steps Array of ndims-1 steps in case of a multi-dimensional array (the last step is always + set to the element size). If not specified, the matrix is assumed to be continuous. + */ + Mat(const std::vector& sizes, int type, void* data, const size_t* steps=0); + + /** @overload + @param m Array that (as a whole or partly) is assigned to the constructed matrix. No data is copied + by these constructors. Instead, the header pointing to m data or its sub-array is constructed and + associated with it. The reference counter, if any, is incremented. So, when you modify the matrix + formed using such a constructor, you also modify the corresponding elements of m . If you want to + have an independent copy of the sub-array, use Mat::clone() . + @param rowRange Range of the m rows to take. As usual, the range start is inclusive and the range + end is exclusive. Use Range::all() to take all the rows. + @param colRange Range of the m columns to take. Use Range::all() to take all the columns. + */ + Mat(const Mat& m, const Range& rowRange, const Range& colRange=Range::all()); + + /** @overload + @param m Array that (as a whole or partly) is assigned to the constructed matrix. No data is copied + by these constructors. Instead, the header pointing to m data or its sub-array is constructed and + associated with it. The reference counter, if any, is incremented. So, when you modify the matrix + formed using such a constructor, you also modify the corresponding elements of m . If you want to + have an independent copy of the sub-array, use Mat::clone() . + @param roi Region of interest. + */ + Mat(const Mat& m, const Rect& roi); + + /** @overload + @param m Array that (as a whole or partly) is assigned to the constructed matrix. No data is copied + by these constructors. Instead, the header pointing to m data or its sub-array is constructed and + associated with it. The reference counter, if any, is incremented. So, when you modify the matrix + formed using such a constructor, you also modify the corresponding elements of m . If you want to + have an independent copy of the sub-array, use Mat::clone() . + @param ranges Array of selected ranges of m along each dimensionality. + */ + Mat(const Mat& m, const Range* ranges); + + /** @overload + @param m Array that (as a whole or partly) is assigned to the constructed matrix. No data is copied + by these constructors. Instead, the header pointing to m data or its sub-array is constructed and + associated with it. The reference counter, if any, is incremented. So, when you modify the matrix + formed using such a constructor, you also modify the corresponding elements of m . If you want to + have an independent copy of the sub-array, use Mat::clone() . + @param ranges Array of selected ranges of m along each dimensionality. + */ + Mat(const Mat& m, const std::vector& ranges); + + /** @overload + @param vec STL vector whose elements form the matrix. The matrix has a single column and the number + of rows equal to the number of vector elements. Type of the matrix matches the type of vector + elements. The constructor can handle arbitrary types, for which there is a properly declared + DataType . This means that the vector elements must be primitive numbers or uni-type numerical + tuples of numbers. Mixed-type structures are not supported. The corresponding constructor is + explicit. Since STL vectors are not automatically converted to Mat instances, you should write + Mat(vec) explicitly. Unless you copy the data into the matrix ( copyData=true ), no new elements + will be added to the vector because it can potentially yield vector data reallocation, and, thus, + the matrix data pointer will be invalid. + @param copyData Flag to specify whether the underlying data of the STL vector should be copied + to (true) or shared with (false) the newly constructed matrix. When the data is copied, the + allocated buffer is managed using Mat reference counting mechanism. While the data is shared, + the reference counter is NULL, and you should not deallocate the data until the matrix is + destructed. + */ + template explicit Mat(const std::vector<_Tp>& vec, bool copyData=false); + + /** @overload + */ + template::value>::type> + explicit Mat(const std::initializer_list<_Tp> list); + + /** @overload + */ + template explicit Mat(const std::initializer_list sizes, const std::initializer_list<_Tp> list); + + /** @overload + */ + template explicit Mat(const std::array<_Tp, _Nm>& arr, bool copyData=false); + + /** @overload + */ + template explicit Mat(const Vec<_Tp, n>& vec, bool copyData=true); + + /** @overload + */ + template explicit Mat(const Matx<_Tp, m, n>& mtx, bool copyData=true); + + /** @overload + */ + template explicit Mat(const Point_<_Tp>& pt, bool copyData=true); + + /** @overload + */ + template explicit Mat(const Point3_<_Tp>& pt, bool copyData=true); + + /** @overload + */ + template explicit Mat(const MatCommaInitializer_<_Tp>& commaInitializer); + + //! download data from GpuMat + explicit Mat(const cuda::GpuMat& m); + + //! destructor - calls release() + ~Mat(); + + /** @brief assignment operators + + These are available assignment operators. Since they all are very different, make sure to read the + operator parameters description. + @param m Assigned, right-hand-side matrix. Matrix assignment is an O(1) operation. This means that + no data is copied but the data is shared and the reference counter, if any, is incremented. Before + assigning new data, the old data is de-referenced via Mat::release . + */ + Mat& operator = (const Mat& m); + + /** @overload + @param expr Assigned matrix expression object. As opposite to the first form of the assignment + operation, the second form can reuse already allocated matrix if it has the right size and type to + fit the matrix expression result. It is automatically handled by the real function that the matrix + expressions is expanded to. For example, C=A+B is expanded to add(A, B, C), and add takes care of + automatic C reallocation. + */ + Mat& operator = (const MatExpr& expr); + + //! retrieve UMat from Mat + UMat getUMat(AccessFlag accessFlags, UMatUsageFlags usageFlags = USAGE_DEFAULT) const; + + /** @brief Creates a matrix header for the specified matrix row. + + The method makes a new header for the specified matrix row and returns it. This is an O(1) + operation, regardless of the matrix size. The underlying data of the new matrix is shared with the + original matrix. Here is the example of one of the classical basic matrix processing operations, + axpy, used by LU and many other algorithms: + @code + inline void matrix_axpy(Mat& A, int i, int j, double alpha) + { + A.row(i) += A.row(j)*alpha; + } + @endcode + @note In the current implementation, the following code does not work as expected: + @code + Mat A; + ... + A.row(i) = A.row(j); // will not work + @endcode + This happens because A.row(i) forms a temporary header that is further assigned to another header. + Remember that each of these operations is O(1), that is, no data is copied. Thus, the above + assignment is not true if you may have expected the j-th row to be copied to the i-th row. To + achieve that, you should either turn this simple assignment into an expression or use the + Mat::copyTo method: + @code + Mat A; + ... + // works, but looks a bit obscure. + A.row(i) = A.row(j) + 0; + // this is a bit longer, but the recommended method. + A.row(j).copyTo(A.row(i)); + @endcode + @param y A 0-based row index. + */ + Mat row(int y) const; + + /** @brief Creates a matrix header for the specified matrix column. + + The method makes a new header for the specified matrix column and returns it. This is an O(1) + operation, regardless of the matrix size. The underlying data of the new matrix is shared with the + original matrix. See also the Mat::row description. + @param x A 0-based column index. + */ + Mat col(int x) const; + + /** @brief Creates a matrix header for the specified row span. + + The method makes a new header for the specified row span of the matrix. Similarly to Mat::row and + Mat::col , this is an O(1) operation. + @param startrow An inclusive 0-based start index of the row span. + @param endrow An exclusive 0-based ending index of the row span. + */ + Mat rowRange(int startrow, int endrow) const; + + /** @overload + @param r Range structure containing both the start and the end indices. + */ + Mat rowRange(const Range& r) const; + + /** @brief Creates a matrix header for the specified column span. + + The method makes a new header for the specified column span of the matrix. Similarly to Mat::row and + Mat::col , this is an O(1) operation. + @param startcol An inclusive 0-based start index of the column span. + @param endcol An exclusive 0-based ending index of the column span. + */ + Mat colRange(int startcol, int endcol) const; + + /** @overload + @param r Range structure containing both the start and the end indices. + */ + Mat colRange(const Range& r) const; + + /** @brief Extracts a diagonal from a matrix + + The method makes a new header for the specified matrix diagonal. The new matrix is represented as a + single-column matrix. Similarly to Mat::row and Mat::col, this is an O(1) operation. + @param d index of the diagonal, with the following values: + - `d=0` is the main diagonal. + - `d<0` is a diagonal from the lower half. For example, d=-1 means the diagonal is set + immediately below the main one. + - `d>0` is a diagonal from the upper half. For example, d=1 means the diagonal is set + immediately above the main one. + For example: + @code + Mat m = (Mat_(3,3) << + 1,2,3, + 4,5,6, + 7,8,9); + Mat d0 = m.diag(0); + Mat d1 = m.diag(1); + Mat d_1 = m.diag(-1); + @endcode + The resulting matrices are + @code + d0 = + [1; + 5; + 9] + d1 = + [2; + 6] + d_1 = + [4; + 8] + @endcode + */ + Mat diag(int d=0) const; + + /** @brief creates a diagonal matrix + + The method creates a square diagonal matrix from specified main diagonal. + @param d One-dimensional matrix that represents the main diagonal. + */ + CV_NODISCARD_STD static Mat diag(const Mat& d); + + /** @brief Creates a full copy of the array and the underlying data. + + The method creates a full copy of the array. The original step[] is not taken into account. So, the + array copy is a continuous array occupying total()*elemSize() bytes. + */ + CV_NODISCARD_STD Mat clone() const; + + /** @brief Copies the matrix to another one. + + The method copies the matrix data to another matrix. Before copying the data, the method invokes : + @code + m.create(this->size(), this->type()); + @endcode + so that the destination matrix is reallocated if needed. While m.copyTo(m); works flawlessly, the + function does not handle the case of a partial overlap between the source and the destination + matrices. + + When the operation mask is specified, if the Mat::create call shown above reallocates the matrix, + the newly allocated matrix is initialized with all zeros before copying the data. + @param m Destination matrix. If it does not have a proper size or type before the operation, it is + reallocated. + */ + void copyTo( OutputArray m ) const; + + /** @overload + @param m Destination matrix. If it does not have a proper size or type before the operation, it is + reallocated. + @param mask Operation mask of the same size as \*this. Its non-zero elements indicate which matrix + elements need to be copied. The mask has to be of type CV_8U and can have 1 or multiple channels. + */ + void copyTo( OutputArray m, InputArray mask ) const; + + /** @brief Converts an array to another data type with optional scaling. + + The method converts source pixel values to the target data type. saturate_cast\<\> is applied at + the end to avoid possible overflows: + + \f[m(x,y) = saturate \_ cast( \alpha (*this)(x,y) + \beta )\f] + @param m output matrix; if it does not have a proper size or type before the operation, it is + reallocated. + @param rtype desired output matrix type or, rather, the depth since the number of channels are the + same as the input has; if rtype is negative, the output matrix will have the same type as the input. + @param alpha optional scale factor. + @param beta optional delta added to the scaled values. + */ + void convertTo( OutputArray m, int rtype, double alpha=1, double beta=0 ) const; + + /** @brief Provides a functional form of convertTo. + + This is an internally used method called by the @ref MatrixExpressions engine. + @param m Destination array. + @param type Desired destination array depth (or -1 if it should be the same as the source type). + */ + void assignTo( Mat& m, int type=-1 ) const; + + /** @brief Sets all or some of the array elements to the specified value. + @param s Assigned scalar converted to the actual array type. + */ + Mat& operator = (const Scalar& s); + + /** @brief Sets all or some of the array elements to the specified value. + + This is an advanced variant of the Mat::operator=(const Scalar& s) operator. + @param value Assigned scalar converted to the actual array type. + @param mask Operation mask of the same size as \*this. Its non-zero elements indicate which matrix + elements need to be copied. The mask has to be of type CV_8U and can have 1 or multiple channels + */ + Mat& setTo(InputArray value, InputArray mask=noArray()); + + /** @brief Changes the shape and/or the number of channels of a 2D matrix without copying the data. + + The method makes a new matrix header for \*this elements. The new matrix may have a different size + and/or different number of channels. Any combination is possible if: + - No extra elements are included into the new matrix and no elements are excluded. Consequently, + the product rows\*cols\*channels() must stay the same after the transformation. + - No data is copied. That is, this is an O(1) operation. Consequently, if you change the number of + rows, or the operation changes the indices of elements row in some other way, the matrix must be + continuous. See Mat::isContinuous . + + For example, if there is a set of 3D points stored as an STL vector, and you want to represent the + points as a 3xN matrix, do the following: + @code + std::vector vec; + ... + Mat pointMat = Mat(vec). // convert vector to Mat, O(1) operation + reshape(1). // make Nx3 1-channel matrix out of Nx1 3-channel. + // Also, an O(1) operation + t(); // finally, transpose the Nx3 matrix. + // This involves copying all the elements + @endcode + @param cn New number of channels. If the parameter is 0, the number of channels remains the same. + @param rows New number of rows. If the parameter is 0, the number of rows remains the same. + */ + Mat reshape(int cn, int rows=0) const; + + /** @overload */ + Mat reshape(int cn, int newndims, const int* newsz) const; + + /** @overload */ + Mat reshape(int cn, const std::vector& newshape) const; + + /** @brief Transposes a matrix. + + The method performs matrix transposition by means of matrix expressions. It does not perform the + actual transposition but returns a temporary matrix transposition object that can be further used as + a part of more complex matrix expressions or can be assigned to a matrix: + @code + Mat A1 = A + Mat::eye(A.size(), A.type())*lambda; + Mat C = A1.t()*A1; // compute (A + lambda*I)^t * (A + lamda*I) + @endcode + */ + MatExpr t() const; + + /** @brief Inverses a matrix. + + The method performs a matrix inversion by means of matrix expressions. This means that a temporary + matrix inversion object is returned by the method and can be used further as a part of more complex + matrix expressions or can be assigned to a matrix. + @param method Matrix inversion method. One of cv::DecompTypes + */ + MatExpr inv(int method=DECOMP_LU) const; + + /** @brief Performs an element-wise multiplication or division of the two matrices. + + The method returns a temporary object encoding per-element array multiplication, with optional + scale. Note that this is not a matrix multiplication that corresponds to a simpler "\*" operator. + + Example: + @code + Mat C = A.mul(5/B); // equivalent to divide(A, B, C, 5) + @endcode + @param m Another array of the same type and the same size as \*this, or a matrix expression. + @param scale Optional scale factor. + */ + MatExpr mul(InputArray m, double scale=1) const; + + /** @brief Computes a cross-product of two 3-element vectors. + + The method computes a cross-product of two 3-element vectors. The vectors must be 3-element + floating-point vectors of the same shape and size. The result is another 3-element vector of the + same shape and type as operands. + @param m Another cross-product operand. + */ + Mat cross(InputArray m) const; + + /** @brief Computes a dot-product of two vectors. + + The method computes a dot-product of two matrices. If the matrices are not single-column or + single-row vectors, the top-to-bottom left-to-right scan ordering is used to treat them as 1D + vectors. The vectors must have the same size and type. If the matrices have more than one channel, + the dot products from all the channels are summed together. + @param m another dot-product operand. + */ + double dot(InputArray m) const; + + /** @brief Returns a zero array of the specified size and type. + + The method returns a Matlab-style zero array initializer. It can be used to quickly form a constant + array as a function parameter, part of a matrix expression, or as a matrix initializer: + @code + Mat A; + A = Mat::zeros(3, 3, CV_32F); + @endcode + In the example above, a new matrix is allocated only if A is not a 3x3 floating-point matrix. + Otherwise, the existing matrix A is filled with zeros. + @param rows Number of rows. + @param cols Number of columns. + @param type Created matrix type. + */ + CV_NODISCARD_STD static MatExpr zeros(int rows, int cols, int type); + + /** @overload + @param size Alternative to the matrix size specification Size(cols, rows) . + @param type Created matrix type. + */ + CV_NODISCARD_STD static MatExpr zeros(Size size, int type); + + /** @overload + @param ndims Array dimensionality. + @param sz Array of integers specifying the array shape. + @param type Created matrix type. + */ + CV_NODISCARD_STD static MatExpr zeros(int ndims, const int* sz, int type); + + /** @brief Returns an array of all 1's of the specified size and type. + + The method returns a Matlab-style 1's array initializer, similarly to Mat::zeros. Note that using + this method you can initialize an array with an arbitrary value, using the following Matlab idiom: + @code + Mat A = Mat::ones(100, 100, CV_8U)*3; // make 100x100 matrix filled with 3. + @endcode + The above operation does not form a 100x100 matrix of 1's and then multiply it by 3. Instead, it + just remembers the scale factor (3 in this case) and use it when actually invoking the matrix + initializer. + @note In case of multi-channels type, only the first channel will be initialized with 1's, the + others will be set to 0's. + @param rows Number of rows. + @param cols Number of columns. + @param type Created matrix type. + */ + CV_NODISCARD_STD static MatExpr ones(int rows, int cols, int type); + + /** @overload + @param size Alternative to the matrix size specification Size(cols, rows) . + @param type Created matrix type. + */ + CV_NODISCARD_STD static MatExpr ones(Size size, int type); + + /** @overload + @param ndims Array dimensionality. + @param sz Array of integers specifying the array shape. + @param type Created matrix type. + */ + CV_NODISCARD_STD static MatExpr ones(int ndims, const int* sz, int type); + + /** @brief Returns an identity matrix of the specified size and type. + + The method returns a Matlab-style identity matrix initializer, similarly to Mat::zeros. Similarly to + Mat::ones, you can use a scale operation to create a scaled identity matrix efficiently: + @code + // make a 4x4 diagonal matrix with 0.1's on the diagonal. + Mat A = Mat::eye(4, 4, CV_32F)*0.1; + @endcode + @note In case of multi-channels type, identity matrix will be initialized only for the first channel, + the others will be set to 0's + @param rows Number of rows. + @param cols Number of columns. + @param type Created matrix type. + */ + CV_NODISCARD_STD static MatExpr eye(int rows, int cols, int type); + + /** @overload + @param size Alternative matrix size specification as Size(cols, rows) . + @param type Created matrix type. + */ + CV_NODISCARD_STD static MatExpr eye(Size size, int type); + + /** @brief Allocates new array data if needed. + + This is one of the key Mat methods. Most new-style OpenCV functions and methods that produce arrays + call this method for each output array. The method uses the following algorithm: + + -# If the current array shape and the type match the new ones, return immediately. Otherwise, + de-reference the previous data by calling Mat::release. + -# Initialize the new header. + -# Allocate the new data of total()\*elemSize() bytes. + -# Allocate the new, associated with the data, reference counter and set it to 1. + + Such a scheme makes the memory management robust and efficient at the same time and helps avoid + extra typing for you. This means that usually there is no need to explicitly allocate output arrays. + That is, instead of writing: + @code + Mat color; + ... + Mat gray(color.rows, color.cols, color.depth()); + cvtColor(color, gray, COLOR_BGR2GRAY); + @endcode + you can simply write: + @code + Mat color; + ... + Mat gray; + cvtColor(color, gray, COLOR_BGR2GRAY); + @endcode + because cvtColor, as well as the most of OpenCV functions, calls Mat::create() for the output array + internally. + @param rows New number of rows. + @param cols New number of columns. + @param type New matrix type. + */ + void create(int rows, int cols, int type); + + /** @overload + @param size Alternative new matrix size specification: Size(cols, rows) + @param type New matrix type. + */ + void create(Size size, int type); + + /** @overload + @param ndims New array dimensionality. + @param sizes Array of integers specifying a new array shape. + @param type New matrix type. + */ + void create(int ndims, const int* sizes, int type); + + /** @overload + @param sizes Array of integers specifying a new array shape. + @param type New matrix type. + */ + void create(const std::vector& sizes, int type); + + /** @brief Increments the reference counter. + + The method increments the reference counter associated with the matrix data. If the matrix header + points to an external data set (see Mat::Mat ), the reference counter is NULL, and the method has no + effect in this case. Normally, to avoid memory leaks, the method should not be called explicitly. It + is called implicitly by the matrix assignment operator. The reference counter increment is an atomic + operation on the platforms that support it. Thus, it is safe to operate on the same matrices + asynchronously in different threads. + */ + void addref(); + + /** @brief Decrements the reference counter and deallocates the matrix if needed. + + The method decrements the reference counter associated with the matrix data. When the reference + counter reaches 0, the matrix data is deallocated and the data and the reference counter pointers + are set to NULL's. If the matrix header points to an external data set (see Mat::Mat ), the + reference counter is NULL, and the method has no effect in this case. + + This method can be called manually to force the matrix data deallocation. But since this method is + automatically called in the destructor, or by any other method that changes the data pointer, it is + usually not needed. The reference counter decrement and check for 0 is an atomic operation on the + platforms that support it. Thus, it is safe to operate on the same matrices asynchronously in + different threads. + */ + void release(); + + //! internal use function, consider to use 'release' method instead; deallocates the matrix data + void deallocate(); + //! internal use function; properly re-allocates _size, _step arrays + void copySize(const Mat& m); + + /** @brief Reserves space for the certain number of rows. + + The method reserves space for sz rows. If the matrix already has enough space to store sz rows, + nothing happens. If the matrix is reallocated, the first Mat::rows rows are preserved. The method + emulates the corresponding method of the STL vector class. + @param sz Number of rows. + */ + void reserve(size_t sz); + + /** @brief Reserves space for the certain number of bytes. + + The method reserves space for sz bytes. If the matrix already has enough space to store sz bytes, + nothing happens. If matrix has to be reallocated its previous content could be lost. + @param sz Number of bytes. + */ + void reserveBuffer(size_t sz); + + /** @brief Changes the number of matrix rows. + + The methods change the number of matrix rows. If the matrix is reallocated, the first + min(Mat::rows, sz) rows are preserved. The methods emulate the corresponding methods of the STL + vector class. + @param sz New number of rows. + */ + void resize(size_t sz); + + /** @overload + @param sz New number of rows. + @param s Value assigned to the newly added elements. + */ + void resize(size_t sz, const Scalar& s); + + //! internal function + void push_back_(const void* elem); + + /** @brief Adds elements to the bottom of the matrix. + + The methods add one or more elements to the bottom of the matrix. They emulate the corresponding + method of the STL vector class. When elem is Mat , its type and the number of columns must be the + same as in the container matrix. + @param elem Added element(s). + */ + template void push_back(const _Tp& elem); + + /** @overload + @param elem Added element(s). + */ + template void push_back(const Mat_<_Tp>& elem); + + /** @overload + @param elem Added element(s). + */ + template void push_back(const std::vector<_Tp>& elem); + + /** @overload + @param m Added line(s). + */ + void push_back(const Mat& m); + + /** @brief Removes elements from the bottom of the matrix. + + The method removes one or more rows from the bottom of the matrix. + @param nelems Number of removed rows. If it is greater than the total number of rows, an exception + is thrown. + */ + void pop_back(size_t nelems=1); + + /** @brief Locates the matrix header within a parent matrix. + + After you extracted a submatrix from a matrix using Mat::row, Mat::col, Mat::rowRange, + Mat::colRange, and others, the resultant submatrix points just to the part of the original big + matrix. However, each submatrix contains information (represented by datastart and dataend + fields) that helps reconstruct the original matrix size and the position of the extracted + submatrix within the original matrix. The method locateROI does exactly that. + @param wholeSize Output parameter that contains the size of the whole matrix containing *this* + as a part. + @param ofs Output parameter that contains an offset of *this* inside the whole matrix. + */ + void locateROI( Size& wholeSize, Point& ofs ) const; + + /** @brief Adjusts a submatrix size and position within the parent matrix. + + The method is complimentary to Mat::locateROI . The typical use of these functions is to determine + the submatrix position within the parent matrix and then shift the position somehow. Typically, it + can be required for filtering operations when pixels outside of the ROI should be taken into + account. When all the method parameters are positive, the ROI needs to grow in all directions by the + specified amount, for example: + @code + A.adjustROI(2, 2, 2, 2); + @endcode + In this example, the matrix size is increased by 4 elements in each direction. The matrix is shifted + by 2 elements to the left and 2 elements up, which brings in all the necessary pixels for the + filtering with the 5x5 kernel. + + adjustROI forces the adjusted ROI to be inside of the parent matrix that is boundaries of the + adjusted ROI are constrained by boundaries of the parent matrix. For example, if the submatrix A is + located in the first row of a parent matrix and you called A.adjustROI(2, 2, 2, 2) then A will not + be increased in the upward direction. + + The function is used internally by the OpenCV filtering functions, like filter2D , morphological + operations, and so on. + @param dtop Shift of the top submatrix boundary upwards. + @param dbottom Shift of the bottom submatrix boundary downwards. + @param dleft Shift of the left submatrix boundary to the left. + @param dright Shift of the right submatrix boundary to the right. + @sa copyMakeBorder + */ + Mat& adjustROI( int dtop, int dbottom, int dleft, int dright ); + + /** @brief Extracts a rectangular submatrix. + + The operators make a new header for the specified sub-array of \*this . They are the most + generalized forms of Mat::row, Mat::col, Mat::rowRange, and Mat::colRange . For example, + `A(Range(0, 10), Range::all())` is equivalent to `A.rowRange(0, 10)`. Similarly to all of the above, + the operators are O(1) operations, that is, no matrix data is copied. + @param rowRange Start and end row of the extracted submatrix. The upper boundary is not included. To + select all the rows, use Range::all(). + @param colRange Start and end column of the extracted submatrix. The upper boundary is not included. + To select all the columns, use Range::all(). + */ + Mat operator()( Range rowRange, Range colRange ) const; + + /** @overload + @param roi Extracted submatrix specified as a rectangle. + */ + Mat operator()( const Rect& roi ) const; + + /** @overload + @param ranges Array of selected ranges along each array dimension. + */ + Mat operator()( const Range* ranges ) const; + + /** @overload + @param ranges Array of selected ranges along each array dimension. + */ + Mat operator()(const std::vector& ranges) const; + + template operator std::vector<_Tp>() const; + template operator Vec<_Tp, n>() const; + template operator Matx<_Tp, m, n>() const; + + template operator std::array<_Tp, _Nm>() const; + + /** @brief Reports whether the matrix is continuous or not. + + The method returns true if the matrix elements are stored continuously without gaps at the end of + each row. Otherwise, it returns false. Obviously, 1x1 or 1xN matrices are always continuous. + Matrices created with Mat::create are always continuous. But if you extract a part of the matrix + using Mat::col, Mat::diag, and so on, or constructed a matrix header for externally allocated data, + such matrices may no longer have this property. + + The continuity flag is stored as a bit in the Mat::flags field and is computed automatically when + you construct a matrix header. Thus, the continuity check is a very fast operation, though + theoretically it could be done as follows: + @code + // alternative implementation of Mat::isContinuous() + bool myCheckMatContinuity(const Mat& m) + { + //return (m.flags & Mat::CONTINUOUS_FLAG) != 0; + return m.rows == 1 || m.step == m.cols*m.elemSize(); + } + @endcode + The method is used in quite a few of OpenCV functions. The point is that element-wise operations + (such as arithmetic and logical operations, math functions, alpha blending, color space + transformations, and others) do not depend on the image geometry. Thus, if all the input and output + arrays are continuous, the functions can process them as very long single-row vectors. The example + below illustrates how an alpha-blending function can be implemented: + @code + template + void alphaBlendRGBA(const Mat& src1, const Mat& src2, Mat& dst) + { + const float alpha_scale = (float)std::numeric_limits::max(), + inv_scale = 1.f/alpha_scale; + + CV_Assert( src1.type() == src2.type() && + src1.type() == CV_MAKETYPE(traits::Depth::value, 4) && + src1.size() == src2.size()); + Size size = src1.size(); + dst.create(size, src1.type()); + + // here is the idiom: check the arrays for continuity and, + // if this is the case, + // treat the arrays as 1D vectors + if( src1.isContinuous() && src2.isContinuous() && dst.isContinuous() ) + { + size.width *= size.height; + size.height = 1; + } + size.width *= 4; + + for( int i = 0; i < size.height; i++ ) + { + // when the arrays are continuous, + // the outer loop is executed only once + const T* ptr1 = src1.ptr(i); + const T* ptr2 = src2.ptr(i); + T* dptr = dst.ptr(i); + + for( int j = 0; j < size.width; j += 4 ) + { + float alpha = ptr1[j+3]*inv_scale, beta = ptr2[j+3]*inv_scale; + dptr[j] = saturate_cast(ptr1[j]*alpha + ptr2[j]*beta); + dptr[j+1] = saturate_cast(ptr1[j+1]*alpha + ptr2[j+1]*beta); + dptr[j+2] = saturate_cast(ptr1[j+2]*alpha + ptr2[j+2]*beta); + dptr[j+3] = saturate_cast((1 - (1-alpha)*(1-beta))*alpha_scale); + } + } + } + @endcode + This approach, while being very simple, can boost the performance of a simple element-operation by + 10-20 percents, especially if the image is rather small and the operation is quite simple. + + Another OpenCV idiom in this function, a call of Mat::create for the destination array, that + allocates the destination array unless it already has the proper size and type. And while the newly + allocated arrays are always continuous, you still need to check the destination array because + Mat::create does not always allocate a new matrix. + */ + bool isContinuous() const; + + //! returns true if the matrix is a submatrix of another matrix + bool isSubmatrix() const; + + /** @brief Returns the matrix element size in bytes. + + The method returns the matrix element size in bytes. For example, if the matrix type is CV_16SC3 , + the method returns 3\*sizeof(short) or 6. + */ + size_t elemSize() const; + + /** @brief Returns the size of each matrix element channel in bytes. + + The method returns the matrix element channel size in bytes, that is, it ignores the number of + channels. For example, if the matrix type is CV_16SC3 , the method returns sizeof(short) or 2. + */ + size_t elemSize1() const; + + /** @brief Returns the type of a matrix element. + + The method returns a matrix element type. This is an identifier compatible with the CvMat type + system, like CV_16SC3 or 16-bit signed 3-channel array, and so on. + */ + int type() const; + + /** @brief Returns the depth of a matrix element. + + The method returns the identifier of the matrix element depth (the type of each individual channel). + For example, for a 16-bit signed element array, the method returns CV_16S . A complete list of + matrix types contains the following values: + - CV_8U - 8-bit unsigned integers ( 0..255 ) + - CV_8S - 8-bit signed integers ( -128..127 ) + - CV_16U - 16-bit unsigned integers ( 0..65535 ) + - CV_16S - 16-bit signed integers ( -32768..32767 ) + - CV_32S - 32-bit signed integers ( -2147483648..2147483647 ) + - CV_32F - 32-bit floating-point numbers ( -FLT_MAX..FLT_MAX, INF, NAN ) + - CV_64F - 64-bit floating-point numbers ( -DBL_MAX..DBL_MAX, INF, NAN ) + */ + int depth() const; + + /** @brief Returns the number of matrix channels. + + The method returns the number of matrix channels. + */ + int channels() const; + + /** @brief Returns a normalized step. + + The method returns a matrix step divided by Mat::elemSize1() . It can be useful to quickly access an + arbitrary matrix element. + */ + size_t step1(int i=0) const; + + /** @brief Returns true if the array has no elements. + + The method returns true if Mat::total() is 0 or if Mat::data is NULL. Because of pop_back() and + resize() methods `M.total() == 0` does not imply that `M.data == NULL`. + */ + bool empty() const; + + /** @brief Returns the total number of array elements. + + The method returns the number of array elements (a number of pixels if the array represents an + image). + */ + size_t total() const; + + /** @brief Returns the total number of array elements. + + The method returns the number of elements within a certain sub-array slice with startDim <= dim < endDim + */ + size_t total(int startDim, int endDim=INT_MAX) const; + + /** + * @param elemChannels Number of channels or number of columns the matrix should have. + * For a 2-D matrix, when the matrix has only 1 column, then it should have + * elemChannels channels; When the matrix has only 1 channel, + * then it should have elemChannels columns. + * For a 3-D matrix, it should have only one channel. Furthermore, + * if the number of planes is not one, then the number of rows + * within every plane has to be 1; if the number of rows within + * every plane is not 1, then the number of planes has to be 1. + * @param depth The depth the matrix should have. Set it to -1 when any depth is fine. + * @param requireContinuous Set it to true to require the matrix to be continuous + * @return -1 if the requirement is not satisfied. + * Otherwise, it returns the number of elements in the matrix. Note + * that an element may have multiple channels. + * + * The following code demonstrates its usage for a 2-d matrix: + * @snippet snippets/core_mat_checkVector.cpp example-2d + * + * The following code demonstrates its usage for a 3-d matrix: + * @snippet snippets/core_mat_checkVector.cpp example-3d + */ + int checkVector(int elemChannels, int depth=-1, bool requireContinuous=true) const; + + /** @brief Returns a pointer to the specified matrix row. + + The methods return `uchar*` or typed pointer to the specified matrix row. See the sample in + Mat::isContinuous to know how to use these methods. + @param i0 A 0-based row index. + */ + uchar* ptr(int i0=0); + /** @overload */ + const uchar* ptr(int i0=0) const; + + /** @overload + @param row Index along the dimension 0 + @param col Index along the dimension 1 + */ + uchar* ptr(int row, int col); + /** @overload + @param row Index along the dimension 0 + @param col Index along the dimension 1 + */ + const uchar* ptr(int row, int col) const; + + /** @overload */ + uchar* ptr(int i0, int i1, int i2); + /** @overload */ + const uchar* ptr(int i0, int i1, int i2) const; + + /** @overload */ + uchar* ptr(const int* idx); + /** @overload */ + const uchar* ptr(const int* idx) const; + /** @overload */ + template uchar* ptr(const Vec& idx); + /** @overload */ + template const uchar* ptr(const Vec& idx) const; + + /** @overload */ + template _Tp* ptr(int i0=0); + /** @overload */ + template const _Tp* ptr(int i0=0) const; + /** @overload + @param row Index along the dimension 0 + @param col Index along the dimension 1 + */ + template _Tp* ptr(int row, int col); + /** @overload + @param row Index along the dimension 0 + @param col Index along the dimension 1 + */ + template const _Tp* ptr(int row, int col) const; + /** @overload */ + template _Tp* ptr(int i0, int i1, int i2); + /** @overload */ + template const _Tp* ptr(int i0, int i1, int i2) const; + /** @overload */ + template _Tp* ptr(const int* idx); + /** @overload */ + template const _Tp* ptr(const int* idx) const; + /** @overload */ + template _Tp* ptr(const Vec& idx); + /** @overload */ + template const _Tp* ptr(const Vec& idx) const; + + /** @brief Returns a reference to the specified array element. + + The template methods return a reference to the specified array element. For the sake of higher + performance, the index range checks are only performed in the Debug configuration. + + Note that the variants with a single index (i) can be used to access elements of single-row or + single-column 2-dimensional arrays. That is, if, for example, A is a 1 x N floating-point matrix and + B is an M x 1 integer matrix, you can simply write `A.at(k+4)` and `B.at(2*i+1)` + instead of `A.at(0,k+4)` and `B.at(2*i+1,0)`, respectively. + + The example below initializes a Hilbert matrix: + @code + Mat H(100, 100, CV_64F); + for(int i = 0; i < H.rows; i++) + for(int j = 0; j < H.cols; j++) + H.at(i,j)=1./(i+j+1); + @endcode + + Keep in mind that the size identifier used in the at operator cannot be chosen at random. It depends + on the image from which you are trying to retrieve the data. The table below gives a better insight in this: + - If matrix is of type `CV_8U` then use `Mat.at(y,x)`. + - If matrix is of type `CV_8S` then use `Mat.at(y,x)`. + - If matrix is of type `CV_16U` then use `Mat.at(y,x)`. + - If matrix is of type `CV_16S` then use `Mat.at(y,x)`. + - If matrix is of type `CV_32S` then use `Mat.at(y,x)`. + - If matrix is of type `CV_32F` then use `Mat.at(y,x)`. + - If matrix is of type `CV_64F` then use `Mat.at(y,x)`. + + @param i0 Index along the dimension 0 + */ + template _Tp& at(int i0=0); + /** @overload + @param i0 Index along the dimension 0 + */ + template const _Tp& at(int i0=0) const; + /** @overload + @param row Index along the dimension 0 + @param col Index along the dimension 1 + */ + template _Tp& at(int row, int col); + /** @overload + @param row Index along the dimension 0 + @param col Index along the dimension 1 + */ + template const _Tp& at(int row, int col) const; + + /** @overload + @param i0 Index along the dimension 0 + @param i1 Index along the dimension 1 + @param i2 Index along the dimension 2 + */ + template _Tp& at(int i0, int i1, int i2); + /** @overload + @param i0 Index along the dimension 0 + @param i1 Index along the dimension 1 + @param i2 Index along the dimension 2 + */ + template const _Tp& at(int i0, int i1, int i2) const; + + /** @overload + @param idx Array of Mat::dims indices. + */ + template _Tp& at(const int* idx); + /** @overload + @param idx Array of Mat::dims indices. + */ + template const _Tp& at(const int* idx) const; + + /** @overload */ + template _Tp& at(const Vec& idx); + /** @overload */ + template const _Tp& at(const Vec& idx) const; + + /** @overload + special versions for 2D arrays (especially convenient for referencing image pixels) + @param pt Element position specified as Point(j,i) . + */ + template _Tp& at(Point pt); + /** @overload + special versions for 2D arrays (especially convenient for referencing image pixels) + @param pt Element position specified as Point(j,i) . + */ + template const _Tp& at(Point pt) const; + + /** @brief Returns the matrix iterator and sets it to the first matrix element. + + The methods return the matrix read-only or read-write iterators. The use of matrix iterators is very + similar to the use of bi-directional STL iterators. In the example below, the alpha blending + function is rewritten using the matrix iterators: + @code + template + void alphaBlendRGBA(const Mat& src1, const Mat& src2, Mat& dst) + { + typedef Vec VT; + + const float alpha_scale = (float)std::numeric_limits::max(), + inv_scale = 1.f/alpha_scale; + + CV_Assert( src1.type() == src2.type() && + src1.type() == traits::Type::value && + src1.size() == src2.size()); + Size size = src1.size(); + dst.create(size, src1.type()); + + MatConstIterator_ it1 = src1.begin(), it1_end = src1.end(); + MatConstIterator_ it2 = src2.begin(); + MatIterator_ dst_it = dst.begin(); + + for( ; it1 != it1_end; ++it1, ++it2, ++dst_it ) + { + VT pix1 = *it1, pix2 = *it2; + float alpha = pix1[3]*inv_scale, beta = pix2[3]*inv_scale; + *dst_it = VT(saturate_cast(pix1[0]*alpha + pix2[0]*beta), + saturate_cast(pix1[1]*alpha + pix2[1]*beta), + saturate_cast(pix1[2]*alpha + pix2[2]*beta), + saturate_cast((1 - (1-alpha)*(1-beta))*alpha_scale)); + } + } + @endcode + */ + template MatIterator_<_Tp> begin(); + template MatConstIterator_<_Tp> begin() const; + + /** @brief Same as begin() but for inverse traversal + */ + template std::reverse_iterator> rbegin(); + template std::reverse_iterator> rbegin() const; + + /** @brief Returns the matrix iterator and sets it to the after-last matrix element. + + The methods return the matrix read-only or read-write iterators, set to the point following the last + matrix element. + */ + template MatIterator_<_Tp> end(); + template MatConstIterator_<_Tp> end() const; + + /** @brief Same as end() but for inverse traversal + */ + template std::reverse_iterator< MatIterator_<_Tp>> rend(); + template std::reverse_iterator< MatConstIterator_<_Tp>> rend() const; + + + /** @brief Runs the given functor over all matrix elements in parallel. + + The operation passed as argument has to be a function pointer, a function object or a lambda(C++11). + + Example 1. All of the operations below put 0xFF the first channel of all matrix elements: + @code + Mat image(1920, 1080, CV_8UC3); + typedef cv::Point3_ Pixel; + + // first. raw pointer access. + for (int r = 0; r < image.rows; ++r) { + Pixel* ptr = image.ptr(r, 0); + const Pixel* ptr_end = ptr + image.cols; + for (; ptr != ptr_end; ++ptr) { + ptr->x = 255; + } + } + + // Using MatIterator. (Simple but there are a Iterator's overhead) + for (Pixel &p : cv::Mat_(image)) { + p.x = 255; + } + + // Parallel execution with function object. + struct Operator { + void operator ()(Pixel &pixel, const int * position) { + pixel.x = 255; + } + }; + image.forEach(Operator()); + + // Parallel execution using C++11 lambda. + image.forEach([](Pixel &p, const int * position) -> void { + p.x = 255; + }); + @endcode + Example 2. Using the pixel's position: + @code + // Creating 3D matrix (255 x 255 x 255) typed uint8_t + // and initialize all elements by the value which equals elements position. + // i.e. pixels (x,y,z) = (1,2,3) is (b,g,r) = (1,2,3). + + int sizes[] = { 255, 255, 255 }; + typedef cv::Point3_ Pixel; + + Mat_ image = Mat::zeros(3, sizes, CV_8UC3); + + image.forEach([](Pixel& pixel, const int position[]) -> void { + pixel.x = position[0]; + pixel.y = position[1]; + pixel.z = position[2]; + }); + @endcode + */ + template void forEach(const Functor& operation); + /** @overload */ + template void forEach(const Functor& operation) const; + + Mat(Mat&& m); + Mat& operator = (Mat&& m); + + enum { MAGIC_VAL = 0x42FF0000, AUTO_STEP = 0, CONTINUOUS_FLAG = CV_MAT_CONT_FLAG, SUBMATRIX_FLAG = CV_SUBMAT_FLAG }; + enum { MAGIC_MASK = 0xFFFF0000, TYPE_MASK = 0x00000FFF, DEPTH_MASK = 7 }; + + /*! includes several bit-fields: + - the magic signature + - continuity flag + - depth + - number of channels + */ + int flags; + //! the matrix dimensionality, >= 2 + int dims; + //! the number of rows and columns or (-1, -1) when the matrix has more than 2 dimensions + int rows, cols; + //! pointer to the data + uchar* data; + + //! helper fields used in locateROI and adjustROI + const uchar* datastart; + const uchar* dataend; + const uchar* datalimit; + + //! custom allocator + MatAllocator* allocator; + //! and the standard allocator + static MatAllocator* getStdAllocator(); + static MatAllocator* getDefaultAllocator(); + static void setDefaultAllocator(MatAllocator* allocator); + + //! internal use method: updates the continuity flag + void updateContinuityFlag(); + + //! interaction with UMat + UMatData* u; + + MatSize size; + MatStep step; + +protected: + template void forEach_impl(const Functor& operation); +}; + + +///////////////////////////////// Mat_<_Tp> //////////////////////////////////// + +/** @brief Template matrix class derived from Mat + +@code{.cpp} + template class Mat_ : public Mat + { + public: + // ... some specific methods + // and + // no new extra fields + }; +@endcode +The class `Mat_<_Tp>` is a *thin* template wrapper on top of the Mat class. It does not have any +extra data fields. Nor this class nor Mat has any virtual methods. Thus, references or pointers to +these two classes can be freely but carefully converted one to another. For example: +@code{.cpp} + // create a 100x100 8-bit matrix + Mat M(100,100,CV_8U); + // this will be compiled fine. no any data conversion will be done. + Mat_& M1 = (Mat_&)M; + // the program is likely to crash at the statement below + M1(99,99) = 1.f; +@endcode +While Mat is sufficient in most cases, Mat_ can be more convenient if you use a lot of element +access operations and if you know matrix type at the compilation time. Note that +`Mat::at(int y,int x)` and `Mat_::operator()(int y,int x)` do absolutely the same +and run at the same speed, but the latter is certainly shorter: +@code{.cpp} + Mat_ M(20,20); + for(int i = 0; i < M.rows; i++) + for(int j = 0; j < M.cols; j++) + M(i,j) = 1./(i+j+1); + Mat E, V; + eigen(M,E,V); + cout << E.at(0,0)/E.at(M.rows-1,0); +@endcode +To use Mat_ for multi-channel images/matrices, pass Vec as a Mat_ parameter: +@code{.cpp} + // allocate a 320x240 color image and fill it with green (in RGB space) + Mat_ img(240, 320, Vec3b(0,255,0)); + // now draw a diagonal white line + for(int i = 0; i < 100; i++) + img(i,i)=Vec3b(255,255,255); + // and now scramble the 2nd (red) channel of each pixel + for(int i = 0; i < img.rows; i++) + for(int j = 0; j < img.cols; j++) + img(i,j)[2] ^= (uchar)(i ^ j); +@endcode +Mat_ is fully compatible with C++11 range-based for loop. For example such loop +can be used to safely apply look-up table: +@code{.cpp} +void applyTable(Mat_& I, const uchar* const table) +{ + for(auto& pixel : I) + { + pixel = table[pixel]; + } +} +@endcode + */ +template class Mat_ : public Mat +{ +public: + typedef _Tp value_type; + typedef typename DataType<_Tp>::channel_type channel_type; + typedef MatIterator_<_Tp> iterator; + typedef MatConstIterator_<_Tp> const_iterator; + + //! default constructor + Mat_() CV_NOEXCEPT; + //! equivalent to Mat(_rows, _cols, DataType<_Tp>::type) + Mat_(int _rows, int _cols); + //! constructor that sets each matrix element to specified value + Mat_(int _rows, int _cols, const _Tp& value); + //! equivalent to Mat(_size, DataType<_Tp>::type) + explicit Mat_(Size _size); + //! constructor that sets each matrix element to specified value + Mat_(Size _size, const _Tp& value); + //! n-dim array constructor + Mat_(int _ndims, const int* _sizes); + //! n-dim array constructor that sets each matrix element to specified value + Mat_(int _ndims, const int* _sizes, const _Tp& value); + //! copy/conversion constructor. If m is of different type, it's converted + Mat_(const Mat& m); + //! copy constructor + Mat_(const Mat_& m); + //! constructs a matrix on top of user-allocated data. step is in bytes(!!!), regardless of the type + Mat_(int _rows, int _cols, _Tp* _data, size_t _step=AUTO_STEP); + //! constructs n-dim matrix on top of user-allocated data. steps are in bytes(!!!), regardless of the type + Mat_(int _ndims, const int* _sizes, _Tp* _data, const size_t* _steps=0); + //! selects a submatrix + Mat_(const Mat_& m, const Range& rowRange, const Range& colRange=Range::all()); + //! selects a submatrix + Mat_(const Mat_& m, const Rect& roi); + //! selects a submatrix, n-dim version + Mat_(const Mat_& m, const Range* ranges); + //! selects a submatrix, n-dim version + Mat_(const Mat_& m, const std::vector& ranges); + //! from a matrix expression + explicit Mat_(const MatExpr& e); + //! makes a matrix out of Vec, std::vector, Point_ or Point3_. The matrix will have a single column + explicit Mat_(const std::vector<_Tp>& vec, bool copyData=false); + template explicit Mat_(const Vec::channel_type, n>& vec, bool copyData=true); + template explicit Mat_(const Matx::channel_type, m, n>& mtx, bool copyData=true); + explicit Mat_(const Point_::channel_type>& pt, bool copyData=true); + explicit Mat_(const Point3_::channel_type>& pt, bool copyData=true); + explicit Mat_(const MatCommaInitializer_<_Tp>& commaInitializer); + + Mat_(std::initializer_list<_Tp> values); + explicit Mat_(const std::initializer_list sizes, const std::initializer_list<_Tp> values); + + template explicit Mat_(const std::array<_Tp, _Nm>& arr, bool copyData=false); + + Mat_& operator = (const Mat& m); + Mat_& operator = (const Mat_& m); + //! set all the elements to s. + Mat_& operator = (const _Tp& s); + //! assign a matrix expression + Mat_& operator = (const MatExpr& e); + + //! iterators; they are smart enough to skip gaps in the end of rows + iterator begin(); + iterator end(); + const_iterator begin() const; + const_iterator end() const; + + //reverse iterators + std::reverse_iterator rbegin(); + std::reverse_iterator rend(); + std::reverse_iterator rbegin() const; + std::reverse_iterator rend() const; + + //! template methods for operation over all matrix elements. + // the operations take care of skipping gaps in the end of rows (if any) + template void forEach(const Functor& operation); + template void forEach(const Functor& operation) const; + + //! equivalent to Mat::create(_rows, _cols, DataType<_Tp>::type) + void create(int _rows, int _cols); + //! equivalent to Mat::create(_size, DataType<_Tp>::type) + void create(Size _size); + //! equivalent to Mat::create(_ndims, _sizes, DatType<_Tp>::type) + void create(int _ndims, const int* _sizes); + //! equivalent to Mat::release() + void release(); + //! cross-product + Mat_ cross(const Mat_& m) const; + //! data type conversion + template operator Mat_() const; + //! overridden forms of Mat::row() etc. + Mat_ row(int y) const; + Mat_ col(int x) const; + Mat_ diag(int d=0) const; + CV_NODISCARD_STD Mat_ clone() const; + + //! overridden forms of Mat::elemSize() etc. + size_t elemSize() const; + size_t elemSize1() const; + int type() const; + int depth() const; + int channels() const; + size_t step1(int i=0) const; + //! returns step()/sizeof(_Tp) + size_t stepT(int i=0) const; + + //! overridden forms of Mat::zeros() etc. Data type is omitted, of course + CV_NODISCARD_STD static MatExpr zeros(int rows, int cols); + CV_NODISCARD_STD static MatExpr zeros(Size size); + CV_NODISCARD_STD static MatExpr zeros(int _ndims, const int* _sizes); + CV_NODISCARD_STD static MatExpr ones(int rows, int cols); + CV_NODISCARD_STD static MatExpr ones(Size size); + CV_NODISCARD_STD static MatExpr ones(int _ndims, const int* _sizes); + CV_NODISCARD_STD static MatExpr eye(int rows, int cols); + CV_NODISCARD_STD static MatExpr eye(Size size); + + //! some more overridden methods + Mat_& adjustROI( int dtop, int dbottom, int dleft, int dright ); + Mat_ operator()( const Range& rowRange, const Range& colRange ) const; + Mat_ operator()( const Rect& roi ) const; + Mat_ operator()( const Range* ranges ) const; + Mat_ operator()(const std::vector& ranges) const; + + //! more convenient forms of row and element access operators + _Tp* operator [](int y); + const _Tp* operator [](int y) const; + + //! returns reference to the specified element + _Tp& operator ()(const int* idx); + //! returns read-only reference to the specified element + const _Tp& operator ()(const int* idx) const; + + //! returns reference to the specified element + template _Tp& operator ()(const Vec& idx); + //! returns read-only reference to the specified element + template const _Tp& operator ()(const Vec& idx) const; + + //! returns reference to the specified element (1D case) + _Tp& operator ()(int idx0); + //! returns read-only reference to the specified element (1D case) + const _Tp& operator ()(int idx0) const; + //! returns reference to the specified element (2D case) + _Tp& operator ()(int row, int col); + //! returns read-only reference to the specified element (2D case) + const _Tp& operator ()(int row, int col) const; + //! returns reference to the specified element (3D case) + _Tp& operator ()(int idx0, int idx1, int idx2); + //! returns read-only reference to the specified element (3D case) + const _Tp& operator ()(int idx0, int idx1, int idx2) const; + + _Tp& operator ()(Point pt); + const _Tp& operator ()(Point pt) const; + + //! conversion to vector. + operator std::vector<_Tp>() const; + + //! conversion to array. + template operator std::array<_Tp, _Nm>() const; + + //! conversion to Vec + template operator Vec::channel_type, n>() const; + //! conversion to Matx + template operator Matx::channel_type, m, n>() const; + + Mat_(Mat_&& m); + Mat_& operator = (Mat_&& m); + + Mat_(Mat&& m); + Mat_& operator = (Mat&& m); + + Mat_(MatExpr&& e); +}; + +typedef Mat_ Mat1b; +typedef Mat_ Mat2b; +typedef Mat_ Mat3b; +typedef Mat_ Mat4b; + +typedef Mat_ Mat1s; +typedef Mat_ Mat2s; +typedef Mat_ Mat3s; +typedef Mat_ Mat4s; + +typedef Mat_ Mat1w; +typedef Mat_ Mat2w; +typedef Mat_ Mat3w; +typedef Mat_ Mat4w; + +typedef Mat_ Mat1i; +typedef Mat_ Mat2i; +typedef Mat_ Mat3i; +typedef Mat_ Mat4i; + +typedef Mat_ Mat1f; +typedef Mat_ Mat2f; +typedef Mat_ Mat3f; +typedef Mat_ Mat4f; + +typedef Mat_ Mat1d; +typedef Mat_ Mat2d; +typedef Mat_ Mat3d; +typedef Mat_ Mat4d; + +/** @todo document */ +class CV_EXPORTS UMat +{ +public: + //! default constructor + UMat(UMatUsageFlags usageFlags = USAGE_DEFAULT) CV_NOEXCEPT; + //! constructs 2D matrix of the specified size and type + // (_type is CV_8UC1, CV_64FC3, CV_32SC(12) etc.) + UMat(int rows, int cols, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT); + UMat(Size size, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT); + //! constructs 2D matrix and fills it with the specified value _s. + UMat(int rows, int cols, int type, const Scalar& s, UMatUsageFlags usageFlags = USAGE_DEFAULT); + UMat(Size size, int type, const Scalar& s, UMatUsageFlags usageFlags = USAGE_DEFAULT); + + //! constructs n-dimensional matrix + UMat(int ndims, const int* sizes, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT); + UMat(int ndims, const int* sizes, int type, const Scalar& s, UMatUsageFlags usageFlags = USAGE_DEFAULT); + + //! copy constructor + UMat(const UMat& m); + + //! creates a matrix header for a part of the bigger matrix + UMat(const UMat& m, const Range& rowRange, const Range& colRange=Range::all()); + UMat(const UMat& m, const Rect& roi); + UMat(const UMat& m, const Range* ranges); + UMat(const UMat& m, const std::vector& ranges); + + // FIXIT copyData=false is not implemented, drop this in favor of cv::Mat (OpenCV 5.0) + //! builds matrix from std::vector with or without copying the data + template explicit UMat(const std::vector<_Tp>& vec, bool copyData=false); + + //! destructor - calls release() + ~UMat(); + //! assignment operators + UMat& operator = (const UMat& m); + + Mat getMat(AccessFlag flags) const; + + //! returns a new matrix header for the specified row + UMat row(int y) const; + //! returns a new matrix header for the specified column + UMat col(int x) const; + //! ... for the specified row span + UMat rowRange(int startrow, int endrow) const; + UMat rowRange(const Range& r) const; + //! ... for the specified column span + UMat colRange(int startcol, int endcol) const; + UMat colRange(const Range& r) const; + //! ... for the specified diagonal + //! (d=0 - the main diagonal, + //! >0 - a diagonal from the upper half, + //! <0 - a diagonal from the lower half) + UMat diag(int d=0) const; + //! constructs a square diagonal matrix which main diagonal is vector "d" + CV_NODISCARD_STD static UMat diag(const UMat& d, UMatUsageFlags usageFlags /*= USAGE_DEFAULT*/); + CV_NODISCARD_STD static UMat diag(const UMat& d) { return diag(d, USAGE_DEFAULT); } // OpenCV 5.0: remove abi compatibility overload + + //! returns deep copy of the matrix, i.e. the data is copied + CV_NODISCARD_STD UMat clone() const; + //! copies the matrix content to "m". + // It calls m.create(this->size(), this->type()). + void copyTo( OutputArray m ) const; + //! copies those matrix elements to "m" that are marked with non-zero mask elements. + void copyTo( OutputArray m, InputArray mask ) const; + //! converts matrix to another datatype with optional scaling. See cvConvertScale. + void convertTo( OutputArray m, int rtype, double alpha=1, double beta=0 ) const; + + void assignTo( UMat& m, int type=-1 ) const; + + //! sets every matrix element to s + UMat& operator = (const Scalar& s); + //! sets some of the matrix elements to s, according to the mask + UMat& setTo(InputArray value, InputArray mask=noArray()); + //! creates alternative matrix header for the same data, with different + // number of channels and/or different number of rows. see cvReshape. + UMat reshape(int cn, int rows=0) const; + UMat reshape(int cn, int newndims, const int* newsz) const; + + //! matrix transposition by means of matrix expressions + UMat t() const; + //! matrix inversion by means of matrix expressions + UMat inv(int method=DECOMP_LU) const; + //! per-element matrix multiplication by means of matrix expressions + UMat mul(InputArray m, double scale=1) const; + + //! computes dot-product + double dot(InputArray m) const; + + //! Matlab-style matrix initialization + CV_NODISCARD_STD static UMat zeros(int rows, int cols, int type, UMatUsageFlags usageFlags /*= USAGE_DEFAULT*/); + CV_NODISCARD_STD static UMat zeros(Size size, int type, UMatUsageFlags usageFlags /*= USAGE_DEFAULT*/); + CV_NODISCARD_STD static UMat zeros(int ndims, const int* sz, int type, UMatUsageFlags usageFlags /*= USAGE_DEFAULT*/); + CV_NODISCARD_STD static UMat zeros(int rows, int cols, int type) { return zeros(rows, cols, type, USAGE_DEFAULT); } // OpenCV 5.0: remove abi compatibility overload + CV_NODISCARD_STD static UMat zeros(Size size, int type) { return zeros(size, type, USAGE_DEFAULT); } // OpenCV 5.0: remove abi compatibility overload + CV_NODISCARD_STD static UMat zeros(int ndims, const int* sz, int type) { return zeros(ndims, sz, type, USAGE_DEFAULT); } // OpenCV 5.0: remove abi compatibility overload + CV_NODISCARD_STD static UMat ones(int rows, int cols, int type, UMatUsageFlags usageFlags /*= USAGE_DEFAULT*/); + CV_NODISCARD_STD static UMat ones(Size size, int type, UMatUsageFlags usageFlags /*= USAGE_DEFAULT*/); + CV_NODISCARD_STD static UMat ones(int ndims, const int* sz, int type, UMatUsageFlags usageFlags /*= USAGE_DEFAULT*/); + CV_NODISCARD_STD static UMat ones(int rows, int cols, int type) { return ones(rows, cols, type, USAGE_DEFAULT); } // OpenCV 5.0: remove abi compatibility overload + CV_NODISCARD_STD static UMat ones(Size size, int type) { return ones(size, type, USAGE_DEFAULT); } // OpenCV 5.0: remove abi compatibility overload + CV_NODISCARD_STD static UMat ones(int ndims, const int* sz, int type) { return ones(ndims, sz, type, USAGE_DEFAULT); } // OpenCV 5.0: remove abi compatibility overload + CV_NODISCARD_STD static UMat eye(int rows, int cols, int type, UMatUsageFlags usageFlags /*= USAGE_DEFAULT*/); + CV_NODISCARD_STD static UMat eye(Size size, int type, UMatUsageFlags usageFlags /*= USAGE_DEFAULT*/); + CV_NODISCARD_STD static UMat eye(int rows, int cols, int type) { return eye(rows, cols, type, USAGE_DEFAULT); } // OpenCV 5.0: remove abi compatibility overload + CV_NODISCARD_STD static UMat eye(Size size, int type) { return eye(size, type, USAGE_DEFAULT); } // OpenCV 5.0: remove abi compatibility overload + + //! allocates new matrix data unless the matrix already has specified size and type. + // previous data is unreferenced if needed. + void create(int rows, int cols, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT); + void create(Size size, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT); + void create(int ndims, const int* sizes, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT); + void create(const std::vector& sizes, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT); + + //! increases the reference counter; use with care to avoid memleaks + void addref(); + //! decreases reference counter; + // deallocates the data when reference counter reaches 0. + void release(); + + //! deallocates the matrix data + void deallocate(); + //! internal use function; properly re-allocates _size, _step arrays + void copySize(const UMat& m); + + //! locates matrix header within a parent matrix. See below + void locateROI( Size& wholeSize, Point& ofs ) const; + //! moves/resizes the current matrix ROI inside the parent matrix. + UMat& adjustROI( int dtop, int dbottom, int dleft, int dright ); + //! extracts a rectangular sub-matrix + // (this is a generalized form of row, rowRange etc.) + UMat operator()( Range rowRange, Range colRange ) const; + UMat operator()( const Rect& roi ) const; + UMat operator()( const Range* ranges ) const; + UMat operator()(const std::vector& ranges) const; + + //! returns true iff the matrix data is continuous + // (i.e. when there are no gaps between successive rows). + // similar to CV_IS_MAT_CONT(cvmat->type) + bool isContinuous() const; + + //! returns true if the matrix is a submatrix of another matrix + bool isSubmatrix() const; + + //! returns element size in bytes, + // similar to CV_ELEM_SIZE(cvmat->type) + size_t elemSize() const; + //! returns the size of element channel in bytes. + size_t elemSize1() const; + //! returns element type, similar to CV_MAT_TYPE(cvmat->type) + int type() const; + //! returns element type, similar to CV_MAT_DEPTH(cvmat->type) + int depth() const; + //! returns element type, similar to CV_MAT_CN(cvmat->type) + int channels() const; + //! returns step/elemSize1() + size_t step1(int i=0) const; + //! returns true if matrix data is NULL + bool empty() const; + //! returns the total number of matrix elements + size_t total() const; + + //! returns N if the matrix is 1-channel (N x ptdim) or ptdim-channel (1 x N) or (N x 1); negative number otherwise + int checkVector(int elemChannels, int depth=-1, bool requireContinuous=true) const; + + UMat(UMat&& m); + UMat& operator = (UMat&& m); + + /*! Returns the OpenCL buffer handle on which UMat operates on. + The UMat instance should be kept alive during the use of the handle to prevent the buffer to be + returned to the OpenCV buffer pool. + */ + void* handle(AccessFlag accessFlags) const; + void ndoffset(size_t* ofs) const; + + enum { MAGIC_VAL = 0x42FF0000, AUTO_STEP = 0, CONTINUOUS_FLAG = CV_MAT_CONT_FLAG, SUBMATRIX_FLAG = CV_SUBMAT_FLAG }; + enum { MAGIC_MASK = 0xFFFF0000, TYPE_MASK = 0x00000FFF, DEPTH_MASK = 7 }; + + /*! includes several bit-fields: + - the magic signature + - continuity flag + - depth + - number of channels + */ + int flags; + + //! the matrix dimensionality, >= 2 + int dims; + + //! number of rows in the matrix; -1 when the matrix has more than 2 dimensions + int rows; + + //! number of columns in the matrix; -1 when the matrix has more than 2 dimensions + int cols; + + //! custom allocator + MatAllocator* allocator; + + //! usage flags for allocator; recommend do not set directly, instead set during construct/create/getUMat + UMatUsageFlags usageFlags; + + //! and the standard allocator + static MatAllocator* getStdAllocator(); + + //! internal use method: updates the continuity flag + void updateContinuityFlag(); + + //! black-box container of UMat data + UMatData* u; + + //! offset of the submatrix (or 0) + size_t offset; + + //! dimensional size of the matrix; accessible in various formats + MatSize size; + + //! number of bytes each matrix element/row/plane/dimension occupies + MatStep step; + +protected: +}; + + +/////////////////////////// multi-dimensional sparse matrix ////////////////////////// + +/** @brief The class SparseMat represents multi-dimensional sparse numerical arrays. + +Such a sparse array can store elements of any type that Mat can store. *Sparse* means that only +non-zero elements are stored (though, as a result of operations on a sparse matrix, some of its +stored elements can actually become 0. It is up to you to detect such elements and delete them +using SparseMat::erase ). The non-zero elements are stored in a hash table that grows when it is +filled so that the search time is O(1) in average (regardless of whether element is there or not). +Elements can be accessed using the following methods: +- Query operations (SparseMat::ptr and the higher-level SparseMat::ref, SparseMat::value and + SparseMat::find), for example: + @code + const int dims = 5; + int size[5] = {10, 10, 10, 10, 10}; + SparseMat sparse_mat(dims, size, CV_32F); + for(int i = 0; i < 1000; i++) + { + int idx[dims]; + for(int k = 0; k < dims; k++) + idx[k] = rand() % size[k]; + sparse_mat.ref(idx) += 1.f; + } + cout << "nnz = " << sparse_mat.nzcount() << endl; + @endcode +- Sparse matrix iterators. They are similar to MatIterator but different from NAryMatIterator. + That is, the iteration loop is familiar to STL users: + @code + // prints elements of a sparse floating-point matrix + // and the sum of elements. + SparseMatConstIterator_ + it = sparse_mat.begin(), + it_end = sparse_mat.end(); + double s = 0; + int dims = sparse_mat.dims(); + for(; it != it_end; ++it) + { + // print element indices and the element value + const SparseMat::Node* n = it.node(); + printf("("); + for(int i = 0; i < dims; i++) + printf("%d%s", n->idx[i], i < dims-1 ? ", " : ")"); + printf(": %g\n", it.value()); + s += *it; + } + printf("Element sum is %g\n", s); + @endcode + If you run this loop, you will notice that elements are not enumerated in a logical order + (lexicographical, and so on). They come in the same order as they are stored in the hash table + (semi-randomly). You may collect pointers to the nodes and sort them to get the proper ordering. + Note, however, that pointers to the nodes may become invalid when you add more elements to the + matrix. This may happen due to possible buffer reallocation. +- Combination of the above 2 methods when you need to process 2 or more sparse matrices + simultaneously. For example, this is how you can compute unnormalized cross-correlation of the 2 + floating-point sparse matrices: + @code + double cross_corr(const SparseMat& a, const SparseMat& b) + { + const SparseMat *_a = &a, *_b = &b; + // if b contains less elements than a, + // it is faster to iterate through b + if(_a->nzcount() > _b->nzcount()) + std::swap(_a, _b); + SparseMatConstIterator_ it = _a->begin(), + it_end = _a->end(); + double ccorr = 0; + for(; it != it_end; ++it) + { + // take the next element from the first matrix + float avalue = *it; + const Node* anode = it.node(); + // and try to find an element with the same index in the second matrix. + // since the hash value depends only on the element index, + // reuse the hash value stored in the node + float bvalue = _b->value(anode->idx,&anode->hashval); + ccorr += avalue*bvalue; + } + return ccorr; + } + @endcode + */ +class CV_EXPORTS SparseMat +{ +public: + typedef SparseMatIterator iterator; + typedef SparseMatConstIterator const_iterator; + + enum { MAGIC_VAL=0x42FD0000, MAX_DIM=32, HASH_SCALE=0x5bd1e995, HASH_BIT=0x80000000 }; + + //! the sparse matrix header + struct CV_EXPORTS Hdr + { + Hdr(int _dims, const int* _sizes, int _type); + void clear(); + int refcount; + int dims; + int valueOffset; + size_t nodeSize; + size_t nodeCount; + size_t freeList; + std::vector pool; + std::vector hashtab; + int size[MAX_DIM]; + }; + + //! sparse matrix node - element of a hash table + struct CV_EXPORTS Node + { + //! hash value + size_t hashval; + //! index of the next node in the same hash table entry + size_t next; + //! index of the matrix element + int idx[MAX_DIM]; + }; + + /** @brief Various SparseMat constructors. + */ + SparseMat(); + + /** @overload + @param dims Array dimensionality. + @param _sizes Sparce matrix size on all dementions. + @param _type Sparse matrix data type. + */ + SparseMat(int dims, const int* _sizes, int _type); + + /** @overload + @param m Source matrix for copy constructor. If m is dense matrix (ocvMat) then it will be converted + to sparse representation. + */ + SparseMat(const SparseMat& m); + + /** @overload + @param m Source matrix for copy constructor. If m is dense matrix (ocvMat) then it will be converted + to sparse representation. + */ + explicit SparseMat(const Mat& m); + + //! the destructor + ~SparseMat(); + + //! assignment operator. This is O(1) operation, i.e. no data is copied + SparseMat& operator = (const SparseMat& m); + //! equivalent to the corresponding constructor + SparseMat& operator = (const Mat& m); + + //! creates full copy of the matrix + CV_NODISCARD_STD SparseMat clone() const; + + //! copies all the data to the destination matrix. All the previous content of m is erased + void copyTo( SparseMat& m ) const; + //! converts sparse matrix to dense matrix. + void copyTo( Mat& m ) const; + //! multiplies all the matrix elements by the specified scale factor alpha and converts the results to the specified data type + void convertTo( SparseMat& m, int rtype, double alpha=1 ) const; + //! converts sparse matrix to dense n-dim matrix with optional type conversion and scaling. + /*! + @param [out] m - output matrix; if it does not have a proper size or type before the operation, + it is reallocated + @param [in] rtype - desired output matrix type or, rather, the depth since the number of channels + are the same as the input has; if rtype is negative, the output matrix will have the + same type as the input. + @param [in] alpha - optional scale factor + @param [in] beta - optional delta added to the scaled values + */ + void convertTo( Mat& m, int rtype, double alpha=1, double beta=0 ) const; + + // not used now + void assignTo( SparseMat& m, int type=-1 ) const; + + //! reallocates sparse matrix. + /*! + If the matrix already had the proper size and type, + it is simply cleared with clear(), otherwise, + the old matrix is released (using release()) and the new one is allocated. + */ + void create(int dims, const int* _sizes, int _type); + //! sets all the sparse matrix elements to 0, which means clearing the hash table. + void clear(); + //! manually increments the reference counter to the header. + void addref(); + // decrements the header reference counter. When the counter reaches 0, the header and all the underlying data are deallocated. + void release(); + + //! converts sparse matrix to the old-style representation; all the elements are copied. + //operator CvSparseMat*() const; + //! returns the size of each element in bytes (not including the overhead - the space occupied by SparseMat::Node elements) + size_t elemSize() const; + //! returns elemSize()/channels() + size_t elemSize1() const; + + //! returns type of sparse matrix elements + int type() const; + //! returns the depth of sparse matrix elements + int depth() const; + //! returns the number of channels + int channels() const; + + //! returns the array of sizes, or NULL if the matrix is not allocated + const int* size() const; + //! returns the size of i-th matrix dimension (or 0) + int size(int i) const; + //! returns the matrix dimensionality + int dims() const; + //! returns the number of non-zero elements (=the number of hash table nodes) + size_t nzcount() const; + + //! computes the element hash value (1D case) + size_t hash(int i0) const; + //! computes the element hash value (2D case) + size_t hash(int i0, int i1) const; + //! computes the element hash value (3D case) + size_t hash(int i0, int i1, int i2) const; + //! computes the element hash value (nD case) + size_t hash(const int* idx) const; + + //!@{ + /*! + specialized variants for 1D, 2D, 3D cases and the generic_type one for n-D case. + return pointer to the matrix element. + - if the element is there (it's non-zero), the pointer to it is returned + - if it's not there and createMissing=false, NULL pointer is returned + - if it's not there and createMissing=true, then the new element + is created and initialized with 0. Pointer to it is returned + - if the optional hashval pointer is not NULL, the element hash value is + not computed, but *hashval is taken instead. + */ + //! returns pointer to the specified element (1D case) + uchar* ptr(int i0, bool createMissing, size_t* hashval=0); + //! returns pointer to the specified element (2D case) + uchar* ptr(int i0, int i1, bool createMissing, size_t* hashval=0); + //! returns pointer to the specified element (3D case) + uchar* ptr(int i0, int i1, int i2, bool createMissing, size_t* hashval=0); + //! returns pointer to the specified element (nD case) + uchar* ptr(const int* idx, bool createMissing, size_t* hashval=0); + //!@} + + //!@{ + /*! + return read-write reference to the specified sparse matrix element. + + `ref<_Tp>(i0,...[,hashval])` is equivalent to `*(_Tp*)ptr(i0,...,true[,hashval])`. + The methods always return a valid reference. + If the element did not exist, it is created and initialized with 0. + */ + //! returns reference to the specified element (1D case) + template _Tp& ref(int i0, size_t* hashval=0); + //! returns reference to the specified element (2D case) + template _Tp& ref(int i0, int i1, size_t* hashval=0); + //! returns reference to the specified element (3D case) + template _Tp& ref(int i0, int i1, int i2, size_t* hashval=0); + //! returns reference to the specified element (nD case) + template _Tp& ref(const int* idx, size_t* hashval=0); + //!@} + + //!@{ + /*! + return value of the specified sparse matrix element. + + `value<_Tp>(i0,...[,hashval])` is equivalent to + @code + { const _Tp* p = find<_Tp>(i0,...[,hashval]); return p ? *p : _Tp(); } + @endcode + + That is, if the element did not exist, the methods return 0. + */ + //! returns value of the specified element (1D case) + template _Tp value(int i0, size_t* hashval=0) const; + //! returns value of the specified element (2D case) + template _Tp value(int i0, int i1, size_t* hashval=0) const; + //! returns value of the specified element (3D case) + template _Tp value(int i0, int i1, int i2, size_t* hashval=0) const; + //! returns value of the specified element (nD case) + template _Tp value(const int* idx, size_t* hashval=0) const; + //!@} + + //!@{ + /*! + Return pointer to the specified sparse matrix element if it exists + + `find<_Tp>(i0,...[,hashval])` is equivalent to `(_const Tp*)ptr(i0,...false[,hashval])`. + + If the specified element does not exist, the methods return NULL. + */ + //! returns pointer to the specified element (1D case) + template const _Tp* find(int i0, size_t* hashval=0) const; + //! returns pointer to the specified element (2D case) + template const _Tp* find(int i0, int i1, size_t* hashval=0) const; + //! returns pointer to the specified element (3D case) + template const _Tp* find(int i0, int i1, int i2, size_t* hashval=0) const; + //! returns pointer to the specified element (nD case) + template const _Tp* find(const int* idx, size_t* hashval=0) const; + //!@} + + //! erases the specified element (2D case) + void erase(int i0, int i1, size_t* hashval=0); + //! erases the specified element (3D case) + void erase(int i0, int i1, int i2, size_t* hashval=0); + //! erases the specified element (nD case) + void erase(const int* idx, size_t* hashval=0); + + //!@{ + /*! + return the sparse matrix iterator pointing to the first sparse matrix element + */ + //! returns the sparse matrix iterator at the matrix beginning + SparseMatIterator begin(); + //! returns the sparse matrix iterator at the matrix beginning + template SparseMatIterator_<_Tp> begin(); + //! returns the read-only sparse matrix iterator at the matrix beginning + SparseMatConstIterator begin() const; + //! returns the read-only sparse matrix iterator at the matrix beginning + template SparseMatConstIterator_<_Tp> begin() const; + //!@} + /*! + return the sparse matrix iterator pointing to the element following the last sparse matrix element + */ + //! returns the sparse matrix iterator at the matrix end + SparseMatIterator end(); + //! returns the read-only sparse matrix iterator at the matrix end + SparseMatConstIterator end() const; + //! returns the typed sparse matrix iterator at the matrix end + template SparseMatIterator_<_Tp> end(); + //! returns the typed read-only sparse matrix iterator at the matrix end + template SparseMatConstIterator_<_Tp> end() const; + + //! returns the value stored in the sparse martix node + template _Tp& value(Node* n); + //! returns the value stored in the sparse martix node + template const _Tp& value(const Node* n) const; + + ////////////// some internal-use methods /////////////// + Node* node(size_t nidx); + const Node* node(size_t nidx) const; + + uchar* newNode(const int* idx, size_t hashval); + void removeNode(size_t hidx, size_t nidx, size_t previdx); + void resizeHashTab(size_t newsize); + + int flags; + Hdr* hdr; +}; + + + +///////////////////////////////// SparseMat_<_Tp> //////////////////////////////////// + +/** @brief Template sparse n-dimensional array class derived from SparseMat + +SparseMat_ is a thin wrapper on top of SparseMat created in the same way as Mat_ . It simplifies +notation of some operations: +@code + int sz[] = {10, 20, 30}; + SparseMat_ M(3, sz); + ... + M.ref(1, 2, 3) = M(4, 5, 6) + M(7, 8, 9); +@endcode + */ +template class SparseMat_ : public SparseMat +{ +public: + typedef SparseMatIterator_<_Tp> iterator; + typedef SparseMatConstIterator_<_Tp> const_iterator; + + //! the default constructor + SparseMat_(); + //! the full constructor equivalent to SparseMat(dims, _sizes, DataType<_Tp>::type) + SparseMat_(int dims, const int* _sizes); + //! the copy constructor. If DataType<_Tp>.type != m.type(), the m elements are converted + SparseMat_(const SparseMat& m); + //! the copy constructor. This is O(1) operation - no data is copied + SparseMat_(const SparseMat_& m); + //! converts dense matrix to the sparse form + SparseMat_(const Mat& m); + //! converts the old-style sparse matrix to the C++ class. All the elements are copied + //SparseMat_(const CvSparseMat* m); + //! the assignment operator. If DataType<_Tp>.type != m.type(), the m elements are converted + SparseMat_& operator = (const SparseMat& m); + //! the assignment operator. This is O(1) operation - no data is copied + SparseMat_& operator = (const SparseMat_& m); + //! converts dense matrix to the sparse form + SparseMat_& operator = (const Mat& m); + + //! makes full copy of the matrix. All the elements are duplicated + CV_NODISCARD_STD SparseMat_ clone() const; + //! equivalent to cv::SparseMat::create(dims, _sizes, DataType<_Tp>::type) + void create(int dims, const int* _sizes); + //! converts sparse matrix to the old-style CvSparseMat. All the elements are copied + //operator CvSparseMat*() const; + + //! returns type of the matrix elements + int type() const; + //! returns depth of the matrix elements + int depth() const; + //! returns the number of channels in each matrix element + int channels() const; + + //! equivalent to SparseMat::ref<_Tp>(i0, hashval) + _Tp& ref(int i0, size_t* hashval=0); + //! equivalent to SparseMat::ref<_Tp>(i0, i1, hashval) + _Tp& ref(int i0, int i1, size_t* hashval=0); + //! equivalent to SparseMat::ref<_Tp>(i0, i1, i2, hashval) + _Tp& ref(int i0, int i1, int i2, size_t* hashval=0); + //! equivalent to SparseMat::ref<_Tp>(idx, hashval) + _Tp& ref(const int* idx, size_t* hashval=0); + + //! equivalent to SparseMat::value<_Tp>(i0, hashval) + _Tp operator()(int i0, size_t* hashval=0) const; + //! equivalent to SparseMat::value<_Tp>(i0, i1, hashval) + _Tp operator()(int i0, int i1, size_t* hashval=0) const; + //! equivalent to SparseMat::value<_Tp>(i0, i1, i2, hashval) + _Tp operator()(int i0, int i1, int i2, size_t* hashval=0) const; + //! equivalent to SparseMat::value<_Tp>(idx, hashval) + _Tp operator()(const int* idx, size_t* hashval=0) const; + + //! returns sparse matrix iterator pointing to the first sparse matrix element + SparseMatIterator_<_Tp> begin(); + //! returns read-only sparse matrix iterator pointing to the first sparse matrix element + SparseMatConstIterator_<_Tp> begin() const; + //! returns sparse matrix iterator pointing to the element following the last sparse matrix element + SparseMatIterator_<_Tp> end(); + //! returns read-only sparse matrix iterator pointing to the element following the last sparse matrix element + SparseMatConstIterator_<_Tp> end() const; +}; + + + +////////////////////////////////// MatConstIterator ////////////////////////////////// + +class CV_EXPORTS MatConstIterator +{ +public: + typedef uchar* value_type; + typedef ptrdiff_t difference_type; + typedef const uchar** pointer; + typedef uchar* reference; + + typedef std::random_access_iterator_tag iterator_category; + + //! default constructor + MatConstIterator(); + //! constructor that sets the iterator to the beginning of the matrix + MatConstIterator(const Mat* _m); + //! constructor that sets the iterator to the specified element of the matrix + MatConstIterator(const Mat* _m, int _row, int _col=0); + //! constructor that sets the iterator to the specified element of the matrix + MatConstIterator(const Mat* _m, Point _pt); + //! constructor that sets the iterator to the specified element of the matrix + MatConstIterator(const Mat* _m, const int* _idx); + //! copy constructor + MatConstIterator(const MatConstIterator& it); + + //! copy operator + MatConstIterator& operator = (const MatConstIterator& it); + //! returns the current matrix element + const uchar* operator *() const; + //! returns the i-th matrix element, relative to the current + const uchar* operator [](ptrdiff_t i) const; + + //! shifts the iterator forward by the specified number of elements + MatConstIterator& operator += (ptrdiff_t ofs); + //! shifts the iterator backward by the specified number of elements + MatConstIterator& operator -= (ptrdiff_t ofs); + //! decrements the iterator + MatConstIterator& operator --(); + //! decrements the iterator + MatConstIterator operator --(int); + //! increments the iterator + MatConstIterator& operator ++(); + //! increments the iterator + MatConstIterator operator ++(int); + //! returns the current iterator position + Point pos() const; + //! returns the current iterator position + void pos(int* _idx) const; + + ptrdiff_t lpos() const; + void seek(ptrdiff_t ofs, bool relative = false); + void seek(const int* _idx, bool relative = false); + + const Mat* m; + size_t elemSize; + const uchar* ptr; + const uchar* sliceStart; + const uchar* sliceEnd; +}; + + + +////////////////////////////////// MatConstIterator_ ///////////////////////////////// + +/** @brief Matrix read-only iterator + */ +template +class MatConstIterator_ : public MatConstIterator +{ +public: + typedef _Tp value_type; + typedef ptrdiff_t difference_type; + typedef const _Tp* pointer; + typedef const _Tp& reference; + + typedef std::random_access_iterator_tag iterator_category; + + //! default constructor + MatConstIterator_(); + //! constructor that sets the iterator to the beginning of the matrix + MatConstIterator_(const Mat_<_Tp>* _m); + //! constructor that sets the iterator to the specified element of the matrix + MatConstIterator_(const Mat_<_Tp>* _m, int _row, int _col=0); + //! constructor that sets the iterator to the specified element of the matrix + MatConstIterator_(const Mat_<_Tp>* _m, Point _pt); + //! constructor that sets the iterator to the specified element of the matrix + MatConstIterator_(const Mat_<_Tp>* _m, const int* _idx); + //! copy constructor + MatConstIterator_(const MatConstIterator_& it); + + //! copy operator + MatConstIterator_& operator = (const MatConstIterator_& it); + //! returns the current matrix element + const _Tp& operator *() const; + //! returns the i-th matrix element, relative to the current + const _Tp& operator [](ptrdiff_t i) const; + + //! shifts the iterator forward by the specified number of elements + MatConstIterator_& operator += (ptrdiff_t ofs); + //! shifts the iterator backward by the specified number of elements + MatConstIterator_& operator -= (ptrdiff_t ofs); + //! decrements the iterator + MatConstIterator_& operator --(); + //! decrements the iterator + MatConstIterator_ operator --(int); + //! increments the iterator + MatConstIterator_& operator ++(); + //! increments the iterator + MatConstIterator_ operator ++(int); + //! returns the current iterator position + Point pos() const; +}; + + + +//////////////////////////////////// MatIterator_ //////////////////////////////////// + +/** @brief Matrix read-write iterator +*/ +template +class MatIterator_ : public MatConstIterator_<_Tp> +{ +public: + typedef _Tp* pointer; + typedef _Tp& reference; + + typedef std::random_access_iterator_tag iterator_category; + + //! the default constructor + MatIterator_(); + //! constructor that sets the iterator to the beginning of the matrix + MatIterator_(Mat_<_Tp>* _m); + //! constructor that sets the iterator to the specified element of the matrix + MatIterator_(Mat_<_Tp>* _m, int _row, int _col=0); + //! constructor that sets the iterator to the specified element of the matrix + MatIterator_(Mat_<_Tp>* _m, Point _pt); + //! constructor that sets the iterator to the specified element of the matrix + MatIterator_(Mat_<_Tp>* _m, const int* _idx); + //! copy constructor + MatIterator_(const MatIterator_& it); + //! copy operator + MatIterator_& operator = (const MatIterator_<_Tp>& it ); + + //! returns the current matrix element + _Tp& operator *() const; + //! returns the i-th matrix element, relative to the current + _Tp& operator [](ptrdiff_t i) const; + + //! shifts the iterator forward by the specified number of elements + MatIterator_& operator += (ptrdiff_t ofs); + //! shifts the iterator backward by the specified number of elements + MatIterator_& operator -= (ptrdiff_t ofs); + //! decrements the iterator + MatIterator_& operator --(); + //! decrements the iterator + MatIterator_ operator --(int); + //! increments the iterator + MatIterator_& operator ++(); + //! increments the iterator + MatIterator_ operator ++(int); +}; + + + +/////////////////////////////// SparseMatConstIterator /////////////////////////////// + +/** @brief Read-Only Sparse Matrix Iterator. + + Here is how to use the iterator to compute the sum of floating-point sparse matrix elements: + + \code + SparseMatConstIterator it = m.begin(), it_end = m.end(); + double s = 0; + CV_Assert( m.type() == CV_32F ); + for( ; it != it_end; ++it ) + s += it.value(); + \endcode +*/ +class CV_EXPORTS SparseMatConstIterator +{ +public: + //! the default constructor + SparseMatConstIterator(); + //! the full constructor setting the iterator to the first sparse matrix element + SparseMatConstIterator(const SparseMat* _m); + //! the copy constructor + SparseMatConstIterator(const SparseMatConstIterator& it); + + //! the assignment operator + SparseMatConstIterator& operator = (const SparseMatConstIterator& it); + + //! template method returning the current matrix element + template const _Tp& value() const; + //! returns the current node of the sparse matrix. it.node->idx is the current element index + const SparseMat::Node* node() const; + + //! moves iterator to the previous element + SparseMatConstIterator& operator --(); + //! moves iterator to the previous element + SparseMatConstIterator operator --(int); + //! moves iterator to the next element + SparseMatConstIterator& operator ++(); + //! moves iterator to the next element + SparseMatConstIterator operator ++(int); + + //! moves iterator to the element after the last element + void seekEnd(); + + const SparseMat* m; + size_t hashidx; + uchar* ptr; +}; + + + +////////////////////////////////// SparseMatIterator ///////////////////////////////// + +/** @brief Read-write Sparse Matrix Iterator + + The class is similar to cv::SparseMatConstIterator, + but can be used for in-place modification of the matrix elements. +*/ +class CV_EXPORTS SparseMatIterator : public SparseMatConstIterator +{ +public: + //! the default constructor + SparseMatIterator(); + //! the full constructor setting the iterator to the first sparse matrix element + SparseMatIterator(SparseMat* _m); + //! the full constructor setting the iterator to the specified sparse matrix element + SparseMatIterator(SparseMat* _m, const int* idx); + //! the copy constructor + SparseMatIterator(const SparseMatIterator& it); + + //! the assignment operator + SparseMatIterator& operator = (const SparseMatIterator& it); + //! returns read-write reference to the current sparse matrix element + template _Tp& value() const; + //! returns pointer to the current sparse matrix node. it.node->idx is the index of the current element (do not modify it!) + SparseMat::Node* node() const; + + //! moves iterator to the next element + SparseMatIterator& operator ++(); + //! moves iterator to the next element + SparseMatIterator operator ++(int); +}; + + + +/////////////////////////////// SparseMatConstIterator_ ////////////////////////////// + +/** @brief Template Read-Only Sparse Matrix Iterator Class. + + This is the derived from SparseMatConstIterator class that + introduces more convenient operator *() for accessing the current element. +*/ +template class SparseMatConstIterator_ : public SparseMatConstIterator +{ +public: + + typedef std::forward_iterator_tag iterator_category; + + //! the default constructor + SparseMatConstIterator_(); + //! the full constructor setting the iterator to the first sparse matrix element + SparseMatConstIterator_(const SparseMat_<_Tp>* _m); + SparseMatConstIterator_(const SparseMat* _m); + //! the copy constructor + SparseMatConstIterator_(const SparseMatConstIterator_& it); + + //! the assignment operator + SparseMatConstIterator_& operator = (const SparseMatConstIterator_& it); + //! the element access operator + const _Tp& operator *() const; + + //! moves iterator to the next element + SparseMatConstIterator_& operator ++(); + //! moves iterator to the next element + SparseMatConstIterator_ operator ++(int); +}; + + + +///////////////////////////////// SparseMatIterator_ ///////////////////////////////// + +/** @brief Template Read-Write Sparse Matrix Iterator Class. + + This is the derived from cv::SparseMatConstIterator_ class that + introduces more convenient operator *() for accessing the current element. +*/ +template class SparseMatIterator_ : public SparseMatConstIterator_<_Tp> +{ +public: + + typedef std::forward_iterator_tag iterator_category; + + //! the default constructor + SparseMatIterator_(); + //! the full constructor setting the iterator to the first sparse matrix element + SparseMatIterator_(SparseMat_<_Tp>* _m); + SparseMatIterator_(SparseMat* _m); + //! the copy constructor + SparseMatIterator_(const SparseMatIterator_& it); + + //! the assignment operator + SparseMatIterator_& operator = (const SparseMatIterator_& it); + //! returns the reference to the current element + _Tp& operator *() const; + + //! moves the iterator to the next element + SparseMatIterator_& operator ++(); + //! moves the iterator to the next element + SparseMatIterator_ operator ++(int); +}; + + + +/////////////////////////////////// NAryMatIterator ////////////////////////////////// + +/** @brief n-ary multi-dimensional array iterator. + +Use the class to implement unary, binary, and, generally, n-ary element-wise operations on +multi-dimensional arrays. Some of the arguments of an n-ary function may be continuous arrays, some +may be not. It is possible to use conventional MatIterator 's for each array but incrementing all of +the iterators after each small operations may be a big overhead. In this case consider using +NAryMatIterator to iterate through several matrices simultaneously as long as they have the same +geometry (dimensionality and all the dimension sizes are the same). On each iteration `it.planes[0]`, +`it.planes[1]`,... will be the slices of the corresponding matrices. + +The example below illustrates how you can compute a normalized and threshold 3D color histogram: +@code + void computeNormalizedColorHist(const Mat& image, Mat& hist, int N, double minProb) + { + const int histSize[] = {N, N, N}; + + // make sure that the histogram has a proper size and type + hist.create(3, histSize, CV_32F); + + // and clear it + hist = Scalar(0); + + // the loop below assumes that the image + // is a 8-bit 3-channel. check it. + CV_Assert(image.type() == CV_8UC3); + MatConstIterator_ it = image.begin(), + it_end = image.end(); + for( ; it != it_end; ++it ) + { + const Vec3b& pix = *it; + hist.at(pix[0]*N/256, pix[1]*N/256, pix[2]*N/256) += 1.f; + } + + minProb *= image.rows*image.cols; + + // initialize iterator (the style is different from STL). + // after initialization the iterator will contain + // the number of slices or planes the iterator will go through. + // it simultaneously increments iterators for several matrices + // supplied as a null terminated list of pointers + const Mat* arrays[] = {&hist, 0}; + Mat planes[1]; + NAryMatIterator itNAry(arrays, planes, 1); + double s = 0; + // iterate through the matrix. on each iteration + // itNAry.planes[i] (of type Mat) will be set to the current plane + // of the i-th n-dim matrix passed to the iterator constructor. + for(int p = 0; p < itNAry.nplanes; p++, ++itNAry) + { + threshold(itNAry.planes[0], itNAry.planes[0], minProb, 0, THRESH_TOZERO); + s += sum(itNAry.planes[0])[0]; + } + + s = 1./s; + itNAry = NAryMatIterator(arrays, planes, 1); + for(int p = 0; p < itNAry.nplanes; p++, ++itNAry) + itNAry.planes[0] *= s; + } +@endcode + */ +class CV_EXPORTS NAryMatIterator +{ +public: + //! the default constructor + NAryMatIterator(); + //! the full constructor taking arbitrary number of n-dim matrices + NAryMatIterator(const Mat** arrays, uchar** ptrs, int narrays=-1); + //! the full constructor taking arbitrary number of n-dim matrices + NAryMatIterator(const Mat** arrays, Mat* planes, int narrays=-1); + //! the separate iterator initialization method + void init(const Mat** arrays, Mat* planes, uchar** ptrs, int narrays=-1); + + //! proceeds to the next plane of every iterated matrix + NAryMatIterator& operator ++(); + //! proceeds to the next plane of every iterated matrix (postfix increment operator) + NAryMatIterator operator ++(int); + + //! the iterated arrays + const Mat** arrays; + //! the current planes + Mat* planes; + //! data pointers + uchar** ptrs; + //! the number of arrays + int narrays; + //! the number of hyper-planes that the iterator steps through + size_t nplanes; + //! the size of each segment (in elements) + size_t size; +protected: + int iterdepth; + size_t idx; +}; + + + +///////////////////////////////// Matrix Expressions ///////////////////////////////// + +class CV_EXPORTS MatOp +{ +public: + MatOp(); + virtual ~MatOp(); + + virtual bool elementWise(const MatExpr& expr) const; + virtual void assign(const MatExpr& expr, Mat& m, int type=-1) const = 0; + virtual void roi(const MatExpr& expr, const Range& rowRange, + const Range& colRange, MatExpr& res) const; + virtual void diag(const MatExpr& expr, int d, MatExpr& res) const; + virtual void augAssignAdd(const MatExpr& expr, Mat& m) const; + virtual void augAssignSubtract(const MatExpr& expr, Mat& m) const; + virtual void augAssignMultiply(const MatExpr& expr, Mat& m) const; + virtual void augAssignDivide(const MatExpr& expr, Mat& m) const; + virtual void augAssignAnd(const MatExpr& expr, Mat& m) const; + virtual void augAssignOr(const MatExpr& expr, Mat& m) const; + virtual void augAssignXor(const MatExpr& expr, Mat& m) const; + + virtual void add(const MatExpr& expr1, const MatExpr& expr2, MatExpr& res) const; + virtual void add(const MatExpr& expr1, const Scalar& s, MatExpr& res) const; + + virtual void subtract(const MatExpr& expr1, const MatExpr& expr2, MatExpr& res) const; + virtual void subtract(const Scalar& s, const MatExpr& expr, MatExpr& res) const; + + virtual void multiply(const MatExpr& expr1, const MatExpr& expr2, MatExpr& res, double scale=1) const; + virtual void multiply(const MatExpr& expr1, double s, MatExpr& res) const; + + virtual void divide(const MatExpr& expr1, const MatExpr& expr2, MatExpr& res, double scale=1) const; + virtual void divide(double s, const MatExpr& expr, MatExpr& res) const; + + virtual void abs(const MatExpr& expr, MatExpr& res) const; + + virtual void transpose(const MatExpr& expr, MatExpr& res) const; + virtual void matmul(const MatExpr& expr1, const MatExpr& expr2, MatExpr& res) const; + virtual void invert(const MatExpr& expr, int method, MatExpr& res) const; + + virtual Size size(const MatExpr& expr) const; + virtual int type(const MatExpr& expr) const; +}; + +/** @brief Matrix expression representation +@anchor MatrixExpressions +This is a list of implemented matrix operations that can be combined in arbitrary complex +expressions (here A, B stand for matrices ( Mat ), s for a scalar ( Scalar ), alpha for a +real-valued scalar ( double )): +- Addition, subtraction, negation: `A+B`, `A-B`, `A+s`, `A-s`, `s+A`, `s-A`, `-A` +- Scaling: `A*alpha` +- Per-element multiplication and division: `A.mul(B)`, `A/B`, `alpha/A` +- Matrix multiplication: `A*B` +- Transposition: `A.t()` (means AT) +- Matrix inversion and pseudo-inversion, solving linear systems and least-squares problems: + `A.inv([method]) (~ A-1)`, `A.inv([method])*B (~ X: AX=B)` +- Comparison: `A cmpop B`, `A cmpop alpha`, `alpha cmpop A`, where *cmpop* is one of + `>`, `>=`, `==`, `!=`, `<=`, `<`. The result of comparison is an 8-bit single channel mask whose + elements are set to 255 (if the particular element or pair of elements satisfy the condition) or + 0. +- Bitwise logical operations: `A logicop B`, `A logicop s`, `s logicop A`, `~A`, where *logicop* is one of + `&`, `|`, `^`. +- Element-wise minimum and maximum: `min(A, B)`, `min(A, alpha)`, `max(A, B)`, `max(A, alpha)` +- Element-wise absolute value: `abs(A)` +- Cross-product, dot-product: `A.cross(B)`, `A.dot(B)` +- Any function of matrix or matrices and scalars that returns a matrix or a scalar, such as norm, + mean, sum, countNonZero, trace, determinant, repeat, and others. +- Matrix initializers ( Mat::eye(), Mat::zeros(), Mat::ones() ), matrix comma-separated + initializers, matrix constructors and operators that extract sub-matrices (see Mat description). +- Mat_() constructors to cast the result to the proper type. +@note Comma-separated initializers and probably some other operations may require additional +explicit Mat() or Mat_() constructor calls to resolve a possible ambiguity. + +Here are examples of matrix expressions: +@code + // compute pseudo-inverse of A, equivalent to A.inv(DECOMP_SVD) + SVD svd(A); + Mat pinvA = svd.vt.t()*Mat::diag(1./svd.w)*svd.u.t(); + + // compute the new vector of parameters in the Levenberg-Marquardt algorithm + x -= (A.t()*A + lambda*Mat::eye(A.cols,A.cols,A.type())).inv(DECOMP_CHOLESKY)*(A.t()*err); + + // sharpen image using "unsharp mask" algorithm + Mat blurred; double sigma = 1, threshold = 5, amount = 1; + GaussianBlur(img, blurred, Size(), sigma, sigma); + Mat lowContrastMask = abs(img - blurred) < threshold; + Mat sharpened = img*(1+amount) + blurred*(-amount); + img.copyTo(sharpened, lowContrastMask); +@endcode +*/ +class CV_EXPORTS MatExpr +{ +public: + MatExpr(); + explicit MatExpr(const Mat& m); + + MatExpr(const MatOp* _op, int _flags, const Mat& _a = Mat(), const Mat& _b = Mat(), + const Mat& _c = Mat(), double _alpha = 1, double _beta = 1, const Scalar& _s = Scalar()); + + operator Mat() const; + template operator Mat_<_Tp>() const; + + Size size() const; + int type() const; + + MatExpr row(int y) const; + MatExpr col(int x) const; + MatExpr diag(int d = 0) const; + MatExpr operator()( const Range& rowRange, const Range& colRange ) const; + MatExpr operator()( const Rect& roi ) const; + + MatExpr t() const; + MatExpr inv(int method = DECOMP_LU) const; + MatExpr mul(const MatExpr& e, double scale=1) const; + MatExpr mul(const Mat& m, double scale=1) const; + + Mat cross(const Mat& m) const; + double dot(const Mat& m) const; + + void swap(MatExpr& b); + + const MatOp* op; + int flags; + + Mat a, b, c; + double alpha, beta; + Scalar s; +}; + +//! @} core_basic + +//! @relates cv::MatExpr +//! @{ +CV_EXPORTS MatExpr operator + (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator + (const Mat& a, const Scalar& s); +CV_EXPORTS MatExpr operator + (const Scalar& s, const Mat& a); +CV_EXPORTS MatExpr operator + (const MatExpr& e, const Mat& m); +CV_EXPORTS MatExpr operator + (const Mat& m, const MatExpr& e); +CV_EXPORTS MatExpr operator + (const MatExpr& e, const Scalar& s); +CV_EXPORTS MatExpr operator + (const Scalar& s, const MatExpr& e); +CV_EXPORTS MatExpr operator + (const MatExpr& e1, const MatExpr& e2); +template static inline +MatExpr operator + (const Mat& a, const Matx<_Tp, m, n>& b) { return a + Mat(b); } +template static inline +MatExpr operator + (const Matx<_Tp, m, n>& a, const Mat& b) { return Mat(a) + b; } + +CV_EXPORTS MatExpr operator - (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator - (const Mat& a, const Scalar& s); +CV_EXPORTS MatExpr operator - (const Scalar& s, const Mat& a); +CV_EXPORTS MatExpr operator - (const MatExpr& e, const Mat& m); +CV_EXPORTS MatExpr operator - (const Mat& m, const MatExpr& e); +CV_EXPORTS MatExpr operator - (const MatExpr& e, const Scalar& s); +CV_EXPORTS MatExpr operator - (const Scalar& s, const MatExpr& e); +CV_EXPORTS MatExpr operator - (const MatExpr& e1, const MatExpr& e2); +template static inline +MatExpr operator - (const Mat& a, const Matx<_Tp, m, n>& b) { return a - Mat(b); } +template static inline +MatExpr operator - (const Matx<_Tp, m, n>& a, const Mat& b) { return Mat(a) - b; } + +CV_EXPORTS MatExpr operator - (const Mat& m); +CV_EXPORTS MatExpr operator - (const MatExpr& e); + +CV_EXPORTS MatExpr operator * (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator * (const Mat& a, double s); +CV_EXPORTS MatExpr operator * (double s, const Mat& a); +CV_EXPORTS MatExpr operator * (const MatExpr& e, const Mat& m); +CV_EXPORTS MatExpr operator * (const Mat& m, const MatExpr& e); +CV_EXPORTS MatExpr operator * (const MatExpr& e, double s); +CV_EXPORTS MatExpr operator * (double s, const MatExpr& e); +CV_EXPORTS MatExpr operator * (const MatExpr& e1, const MatExpr& e2); +template static inline +MatExpr operator * (const Mat& a, const Matx<_Tp, m, n>& b) { return a * Mat(b); } +template static inline +MatExpr operator * (const Matx<_Tp, m, n>& a, const Mat& b) { return Mat(a) * b; } + +CV_EXPORTS MatExpr operator / (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator / (const Mat& a, double s); +CV_EXPORTS MatExpr operator / (double s, const Mat& a); +CV_EXPORTS MatExpr operator / (const MatExpr& e, const Mat& m); +CV_EXPORTS MatExpr operator / (const Mat& m, const MatExpr& e); +CV_EXPORTS MatExpr operator / (const MatExpr& e, double s); +CV_EXPORTS MatExpr operator / (double s, const MatExpr& e); +CV_EXPORTS MatExpr operator / (const MatExpr& e1, const MatExpr& e2); +template static inline +MatExpr operator / (const Mat& a, const Matx<_Tp, m, n>& b) { return a / Mat(b); } +template static inline +MatExpr operator / (const Matx<_Tp, m, n>& a, const Mat& b) { return Mat(a) / b; } + +CV_EXPORTS MatExpr operator < (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator < (const Mat& a, double s); +CV_EXPORTS MatExpr operator < (double s, const Mat& a); +template static inline +MatExpr operator < (const Mat& a, const Matx<_Tp, m, n>& b) { return a < Mat(b); } +template static inline +MatExpr operator < (const Matx<_Tp, m, n>& a, const Mat& b) { return Mat(a) < b; } + +CV_EXPORTS MatExpr operator <= (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator <= (const Mat& a, double s); +CV_EXPORTS MatExpr operator <= (double s, const Mat& a); +template static inline +MatExpr operator <= (const Mat& a, const Matx<_Tp, m, n>& b) { return a <= Mat(b); } +template static inline +MatExpr operator <= (const Matx<_Tp, m, n>& a, const Mat& b) { return Mat(a) <= b; } + +CV_EXPORTS MatExpr operator == (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator == (const Mat& a, double s); +CV_EXPORTS MatExpr operator == (double s, const Mat& a); +template static inline +MatExpr operator == (const Mat& a, const Matx<_Tp, m, n>& b) { return a == Mat(b); } +template static inline +MatExpr operator == (const Matx<_Tp, m, n>& a, const Mat& b) { return Mat(a) == b; } + +CV_EXPORTS MatExpr operator != (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator != (const Mat& a, double s); +CV_EXPORTS MatExpr operator != (double s, const Mat& a); +template static inline +MatExpr operator != (const Mat& a, const Matx<_Tp, m, n>& b) { return a != Mat(b); } +template static inline +MatExpr operator != (const Matx<_Tp, m, n>& a, const Mat& b) { return Mat(a) != b; } + +CV_EXPORTS MatExpr operator >= (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator >= (const Mat& a, double s); +CV_EXPORTS MatExpr operator >= (double s, const Mat& a); +template static inline +MatExpr operator >= (const Mat& a, const Matx<_Tp, m, n>& b) { return a >= Mat(b); } +template static inline +MatExpr operator >= (const Matx<_Tp, m, n>& a, const Mat& b) { return Mat(a) >= b; } + +CV_EXPORTS MatExpr operator > (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator > (const Mat& a, double s); +CV_EXPORTS MatExpr operator > (double s, const Mat& a); +template static inline +MatExpr operator > (const Mat& a, const Matx<_Tp, m, n>& b) { return a > Mat(b); } +template static inline +MatExpr operator > (const Matx<_Tp, m, n>& a, const Mat& b) { return Mat(a) > b; } + +CV_EXPORTS MatExpr operator & (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator & (const Mat& a, const Scalar& s); +CV_EXPORTS MatExpr operator & (const Scalar& s, const Mat& a); +template static inline +MatExpr operator & (const Mat& a, const Matx<_Tp, m, n>& b) { return a & Mat(b); } +template static inline +MatExpr operator & (const Matx<_Tp, m, n>& a, const Mat& b) { return Mat(a) & b; } + +CV_EXPORTS MatExpr operator | (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator | (const Mat& a, const Scalar& s); +CV_EXPORTS MatExpr operator | (const Scalar& s, const Mat& a); +template static inline +MatExpr operator | (const Mat& a, const Matx<_Tp, m, n>& b) { return a | Mat(b); } +template static inline +MatExpr operator | (const Matx<_Tp, m, n>& a, const Mat& b) { return Mat(a) | b; } + +CV_EXPORTS MatExpr operator ^ (const Mat& a, const Mat& b); +CV_EXPORTS MatExpr operator ^ (const Mat& a, const Scalar& s); +CV_EXPORTS MatExpr operator ^ (const Scalar& s, const Mat& a); +template static inline +MatExpr operator ^ (const Mat& a, const Matx<_Tp, m, n>& b) { return a ^ Mat(b); } +template static inline +MatExpr operator ^ (const Matx<_Tp, m, n>& a, const Mat& b) { return Mat(a) ^ b; } + +CV_EXPORTS MatExpr operator ~(const Mat& m); + +CV_EXPORTS MatExpr min(const Mat& a, const Mat& b); +CV_EXPORTS MatExpr min(const Mat& a, double s); +CV_EXPORTS MatExpr min(double s, const Mat& a); +template static inline +MatExpr min (const Mat& a, const Matx<_Tp, m, n>& b) { return min(a, Mat(b)); } +template static inline +MatExpr min (const Matx<_Tp, m, n>& a, const Mat& b) { return min(Mat(a), b); } + +CV_EXPORTS MatExpr max(const Mat& a, const Mat& b); +CV_EXPORTS MatExpr max(const Mat& a, double s); +CV_EXPORTS MatExpr max(double s, const Mat& a); +template static inline +MatExpr max (const Mat& a, const Matx<_Tp, m, n>& b) { return max(a, Mat(b)); } +template static inline +MatExpr max (const Matx<_Tp, m, n>& a, const Mat& b) { return max(Mat(a), b); } + +/** @brief Calculates an absolute value of each matrix element. + +abs is a meta-function that is expanded to one of absdiff or convertScaleAbs forms: +- C = abs(A-B) is equivalent to `absdiff(A, B, C)` +- C = abs(A) is equivalent to `absdiff(A, Scalar::all(0), C)` +- C = `Mat_ >(abs(A*alpha + beta))` is equivalent to `convertScaleAbs(A, C, alpha, +beta)` + +The output matrix has the same size and the same type as the input one except for the last case, +where C is depth=CV_8U . +@param m matrix. +@sa @ref MatrixExpressions, absdiff, convertScaleAbs + */ +CV_EXPORTS MatExpr abs(const Mat& m); +/** @overload +@param e matrix expression. +*/ +CV_EXPORTS MatExpr abs(const MatExpr& e); +//! @} relates cv::MatExpr + +} // cv + +#include "opencv2/core/mat.inl.hpp" + +#endif // OPENCV_CORE_MAT_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/mat.inl.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/mat.inl.hpp new file mode 100644 index 0000000..886b82c --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/mat.inl.hpp @@ -0,0 +1,3422 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_MATRIX_OPERATIONS_HPP +#define OPENCV_CORE_MATRIX_OPERATIONS_HPP + +#ifndef __cplusplus +# error mat.inl.hpp header must be compiled as C++ +#endif + +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable: 4127 ) +#endif + +#if defined(CV_SKIP_DISABLE_CLANG_ENUM_WARNINGS) + // nothing +#elif defined(CV_FORCE_DISABLE_CLANG_ENUM_WARNINGS) + #define CV_DISABLE_CLANG_ENUM_WARNINGS +#elif defined(__clang__) && defined(__has_warning) + #if __has_warning("-Wdeprecated-enum-enum-conversion") && __has_warning("-Wdeprecated-anon-enum-enum-conversion") + #define CV_DISABLE_CLANG_ENUM_WARNINGS + #endif +#endif +#ifdef CV_DISABLE_CLANG_ENUM_WARNINGS +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion" +#pragma clang diagnostic ignored "-Wdeprecated-anon-enum-enum-conversion" +#endif + +namespace cv +{ +CV__DEBUG_NS_BEGIN + + +//! @cond IGNORED + +////////////////////////// Custom (raw) type wrapper ////////////////////////// + +template static inline +int rawType() +{ + CV_StaticAssert(sizeof(_Tp) <= CV_CN_MAX, "sizeof(_Tp) is too large"); + const int elemSize = sizeof(_Tp); + return (int)CV_MAKETYPE(CV_8U, elemSize); +} + +//////////////////////// Input/Output Arrays //////////////////////// + +inline void _InputArray::init(int _flags, const void* _obj) +{ flags = _flags; obj = (void*)_obj; } + +inline void _InputArray::init(int _flags, const void* _obj, Size _sz) +{ flags = _flags; obj = (void*)_obj; sz = _sz; } + +inline void* _InputArray::getObj() const { return obj; } +inline int _InputArray::getFlags() const { return flags; } +inline Size _InputArray::getSz() const { return sz; } + +inline _InputArray::_InputArray() { init(0 + NONE, 0); } +inline _InputArray::_InputArray(int _flags, void* _obj) { init(_flags, _obj); } +inline _InputArray::_InputArray(const Mat& m) { init(MAT+ACCESS_READ, &m); } +inline _InputArray::_InputArray(const std::vector& vec) { init(STD_VECTOR_MAT+ACCESS_READ, &vec); } +inline _InputArray::_InputArray(const UMat& m) { init(UMAT+ACCESS_READ, &m); } +inline _InputArray::_InputArray(const std::vector& vec) { init(STD_VECTOR_UMAT+ACCESS_READ, &vec); } + +template inline +_InputArray::_InputArray(const std::vector<_Tp>& vec) +{ init(FIXED_TYPE + STD_VECTOR + traits::Type<_Tp>::value + ACCESS_READ, &vec); } + +template inline +_InputArray::_InputArray(const std::array<_Tp, _Nm>& arr) +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_READ, arr.data(), Size(1, _Nm)); } + +template inline +_InputArray::_InputArray(const std::array& arr) +{ init(STD_ARRAY_MAT + ACCESS_READ, arr.data(), Size(1, _Nm)); } + +inline +_InputArray::_InputArray(const std::vector& vec) +{ init(FIXED_TYPE + STD_BOOL_VECTOR + traits::Type::value + ACCESS_READ, &vec); } + +template inline +_InputArray::_InputArray(const std::vector >& vec) +{ init(FIXED_TYPE + STD_VECTOR_VECTOR + traits::Type<_Tp>::value + ACCESS_READ, &vec); } + +template inline +_InputArray::_InputArray(const std::vector >& vec) +{ init(FIXED_TYPE + STD_VECTOR_MAT + traits::Type<_Tp>::value + ACCESS_READ, &vec); } + +template inline +_InputArray::_InputArray(const Matx<_Tp, m, n>& mtx) +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_READ, &mtx, Size(n, m)); } + +template inline +_InputArray::_InputArray(const _Tp* vec, int n) +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_READ, vec, Size(n, 1)); } + +template inline +_InputArray::_InputArray(const Mat_<_Tp>& m) +{ init(FIXED_TYPE + MAT + traits::Type<_Tp>::value + ACCESS_READ, &m); } + +inline _InputArray::_InputArray(const double& val) +{ init(FIXED_TYPE + FIXED_SIZE + MATX + CV_64F + ACCESS_READ, &val, Size(1,1)); } + +inline _InputArray::_InputArray(const cuda::GpuMat& d_mat) +{ init(CUDA_GPU_MAT + ACCESS_READ, &d_mat); } + +inline _InputArray::_InputArray(const std::vector& d_mat) +{ init(STD_VECTOR_CUDA_GPU_MAT + ACCESS_READ, &d_mat);} + +inline _InputArray::_InputArray(const ogl::Buffer& buf) +{ init(OPENGL_BUFFER + ACCESS_READ, &buf); } + +inline _InputArray::_InputArray(const cuda::HostMem& cuda_mem) +{ init(CUDA_HOST_MEM + ACCESS_READ, &cuda_mem); } + +template inline +_InputArray _InputArray::rawIn(const std::vector<_Tp>& vec) +{ + _InputArray v; + v.flags = _InputArray::FIXED_TYPE + _InputArray::STD_VECTOR + rawType<_Tp>() + ACCESS_READ; + v.obj = (void*)&vec; + return v; +} + +template inline +_InputArray _InputArray::rawIn(const std::array<_Tp, _Nm>& arr) +{ + _InputArray v; + v.flags = FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_READ; + v.obj = (void*)arr.data(); + v.sz = Size(1, _Nm); + return v; +} + +inline _InputArray::~_InputArray() {} + +inline Mat _InputArray::getMat(int i) const +{ + if( kind() == MAT && i < 0 ) + return *(const Mat*)obj; + return getMat_(i); +} + +inline bool _InputArray::isMat() const { return kind() == _InputArray::MAT; } +inline bool _InputArray::isUMat() const { return kind() == _InputArray::UMAT; } +inline bool _InputArray::isMatVector() const { return kind() == _InputArray::STD_VECTOR_MAT; } +inline bool _InputArray::isUMatVector() const { return kind() == _InputArray::STD_VECTOR_UMAT; } +inline bool _InputArray::isMatx() const { return kind() == _InputArray::MATX; } +inline bool _InputArray::isVector() const { return kind() == _InputArray::STD_VECTOR || + kind() == _InputArray::STD_BOOL_VECTOR || + (kind() == _InputArray::MATX && (sz.width <= 1 || sz.height <= 1)); } +inline bool _InputArray::isGpuMat() const { return kind() == _InputArray::CUDA_GPU_MAT; } +inline bool _InputArray::isGpuMatVector() const { return kind() == _InputArray::STD_VECTOR_CUDA_GPU_MAT; } + +//////////////////////////////////////////////////////////////////////////////////////// + +inline _OutputArray::_OutputArray() { init(NONE + ACCESS_WRITE, 0); } +inline _OutputArray::_OutputArray(int _flags, void* _obj) { init(_flags + ACCESS_WRITE, _obj); } +inline _OutputArray::_OutputArray(Mat& m) { init(MAT+ACCESS_WRITE, &m); } +inline _OutputArray::_OutputArray(std::vector& vec) { init(STD_VECTOR_MAT + ACCESS_WRITE, &vec); } +inline _OutputArray::_OutputArray(UMat& m) { init(UMAT + ACCESS_WRITE, &m); } +inline _OutputArray::_OutputArray(std::vector& vec) { init(STD_VECTOR_UMAT + ACCESS_WRITE, &vec); } + +template inline +_OutputArray::_OutputArray(std::vector<_Tp>& vec) +{ init(FIXED_TYPE + STD_VECTOR + traits::Type<_Tp>::value + ACCESS_WRITE, &vec); } + +template inline +_OutputArray::_OutputArray(std::array<_Tp, _Nm>& arr) +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_WRITE, arr.data(), Size(1, _Nm)); } + +template inline +_OutputArray::_OutputArray(std::array& arr) +{ init(STD_ARRAY_MAT + ACCESS_WRITE, arr.data(), Size(1, _Nm)); } + +template inline +_OutputArray::_OutputArray(std::vector >& vec) +{ init(FIXED_TYPE + STD_VECTOR_VECTOR + traits::Type<_Tp>::value + ACCESS_WRITE, &vec); } + +template inline +_OutputArray::_OutputArray(std::vector >& vec) +{ init(FIXED_TYPE + STD_VECTOR_MAT + traits::Type<_Tp>::value + ACCESS_WRITE, &vec); } + +template inline +_OutputArray::_OutputArray(Mat_<_Tp>& m) +{ init(FIXED_TYPE + MAT + traits::Type<_Tp>::value + ACCESS_WRITE, &m); } + +template inline +_OutputArray::_OutputArray(Matx<_Tp, m, n>& mtx) +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_WRITE, &mtx, Size(n, m)); } + +template inline +_OutputArray::_OutputArray(_Tp* vec, int n) +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_WRITE, vec, Size(n, 1)); } + +template inline +_OutputArray::_OutputArray(const std::vector<_Tp>& vec) +{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR + traits::Type<_Tp>::value + ACCESS_WRITE, &vec); } + +template inline +_OutputArray::_OutputArray(const std::array<_Tp, _Nm>& arr) +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_WRITE, arr.data(), Size(1, _Nm)); } + +template inline +_OutputArray::_OutputArray(const std::array& arr) +{ init(FIXED_SIZE + STD_ARRAY_MAT + ACCESS_WRITE, arr.data(), Size(1, _Nm)); } + +template inline +_OutputArray::_OutputArray(const std::vector >& vec) +{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_VECTOR + traits::Type<_Tp>::value + ACCESS_WRITE, &vec); } + +template inline +_OutputArray::_OutputArray(const std::vector >& vec) +{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_MAT + traits::Type<_Tp>::value + ACCESS_WRITE, &vec); } + +template inline +_OutputArray::_OutputArray(const Mat_<_Tp>& m) +{ init(FIXED_TYPE + FIXED_SIZE + MAT + traits::Type<_Tp>::value + ACCESS_WRITE, &m); } + +template inline +_OutputArray::_OutputArray(const Matx<_Tp, m, n>& mtx) +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_WRITE, &mtx, Size(n, m)); } + +template inline +_OutputArray::_OutputArray(const _Tp* vec, int n) +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_WRITE, vec, Size(n, 1)); } + +inline _OutputArray::_OutputArray(cuda::GpuMat& d_mat) +{ init(CUDA_GPU_MAT + ACCESS_WRITE, &d_mat); } + +inline _OutputArray::_OutputArray(std::vector& d_mat) +{ init(STD_VECTOR_CUDA_GPU_MAT + ACCESS_WRITE, &d_mat);} + +inline _OutputArray::_OutputArray(ogl::Buffer& buf) +{ init(OPENGL_BUFFER + ACCESS_WRITE, &buf); } + +inline _OutputArray::_OutputArray(cuda::HostMem& cuda_mem) +{ init(CUDA_HOST_MEM + ACCESS_WRITE, &cuda_mem); } + +inline _OutputArray::_OutputArray(const Mat& m) +{ init(FIXED_TYPE + FIXED_SIZE + MAT + ACCESS_WRITE, &m); } + +inline _OutputArray::_OutputArray(const std::vector& vec) +{ init(FIXED_SIZE + STD_VECTOR_MAT + ACCESS_WRITE, &vec); } + +inline _OutputArray::_OutputArray(const UMat& m) +{ init(FIXED_TYPE + FIXED_SIZE + UMAT + ACCESS_WRITE, &m); } + +inline _OutputArray::_OutputArray(const std::vector& vec) +{ init(FIXED_SIZE + STD_VECTOR_UMAT + ACCESS_WRITE, &vec); } + +inline _OutputArray::_OutputArray(const cuda::GpuMat& d_mat) +{ init(FIXED_TYPE + FIXED_SIZE + CUDA_GPU_MAT + ACCESS_WRITE, &d_mat); } + + +inline _OutputArray::_OutputArray(const ogl::Buffer& buf) +{ init(FIXED_TYPE + FIXED_SIZE + OPENGL_BUFFER + ACCESS_WRITE, &buf); } + +inline _OutputArray::_OutputArray(const cuda::HostMem& cuda_mem) +{ init(FIXED_TYPE + FIXED_SIZE + CUDA_HOST_MEM + ACCESS_WRITE, &cuda_mem); } + +template inline +_OutputArray _OutputArray::rawOut(std::vector<_Tp>& vec) +{ + _OutputArray v; + v.flags = _InputArray::FIXED_TYPE + _InputArray::STD_VECTOR + rawType<_Tp>() + ACCESS_WRITE; + v.obj = (void*)&vec; + return v; +} + +template inline +_OutputArray _OutputArray::rawOut(std::array<_Tp, _Nm>& arr) +{ + _OutputArray v; + v.flags = FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_WRITE; + v.obj = (void*)arr.data(); + v.sz = Size(1, _Nm); + return v; +} + +/////////////////////////////////////////////////////////////////////////////////////////// + +inline _InputOutputArray::_InputOutputArray() { init(0+ACCESS_RW, 0); } +inline _InputOutputArray::_InputOutputArray(int _flags, void* _obj) { init(_flags+ACCESS_RW, _obj); } +inline _InputOutputArray::_InputOutputArray(Mat& m) { init(MAT+ACCESS_RW, &m); } +inline _InputOutputArray::_InputOutputArray(std::vector& vec) { init(STD_VECTOR_MAT+ACCESS_RW, &vec); } +inline _InputOutputArray::_InputOutputArray(UMat& m) { init(UMAT+ACCESS_RW, &m); } +inline _InputOutputArray::_InputOutputArray(std::vector& vec) { init(STD_VECTOR_UMAT+ACCESS_RW, &vec); } + +template inline +_InputOutputArray::_InputOutputArray(std::vector<_Tp>& vec) +{ init(FIXED_TYPE + STD_VECTOR + traits::Type<_Tp>::value + ACCESS_RW, &vec); } + +template inline +_InputOutputArray::_InputOutputArray(std::array<_Tp, _Nm>& arr) +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_RW, arr.data(), Size(1, _Nm)); } + +template inline +_InputOutputArray::_InputOutputArray(std::array& arr) +{ init(STD_ARRAY_MAT + ACCESS_RW, arr.data(), Size(1, _Nm)); } + +template inline +_InputOutputArray::_InputOutputArray(std::vector >& vec) +{ init(FIXED_TYPE + STD_VECTOR_VECTOR + traits::Type<_Tp>::value + ACCESS_RW, &vec); } + +template inline +_InputOutputArray::_InputOutputArray(std::vector >& vec) +{ init(FIXED_TYPE + STD_VECTOR_MAT + traits::Type<_Tp>::value + ACCESS_RW, &vec); } + +template inline +_InputOutputArray::_InputOutputArray(Mat_<_Tp>& m) +{ init(FIXED_TYPE + MAT + traits::Type<_Tp>::value + ACCESS_RW, &m); } + +template inline +_InputOutputArray::_InputOutputArray(Matx<_Tp, m, n>& mtx) +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_RW, &mtx, Size(n, m)); } + +template inline +_InputOutputArray::_InputOutputArray(_Tp* vec, int n) +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_RW, vec, Size(n, 1)); } + +template inline +_InputOutputArray::_InputOutputArray(const std::vector<_Tp>& vec) +{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR + traits::Type<_Tp>::value + ACCESS_RW, &vec); } + +template inline +_InputOutputArray::_InputOutputArray(const std::array<_Tp, _Nm>& arr) +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_RW, arr.data(), Size(1, _Nm)); } + +template inline +_InputOutputArray::_InputOutputArray(const std::array& arr) +{ init(FIXED_SIZE + STD_ARRAY_MAT + ACCESS_RW, arr.data(), Size(1, _Nm)); } + +template inline +_InputOutputArray::_InputOutputArray(const std::vector >& vec) +{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_VECTOR + traits::Type<_Tp>::value + ACCESS_RW, &vec); } + +template inline +_InputOutputArray::_InputOutputArray(const std::vector >& vec) +{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_MAT + traits::Type<_Tp>::value + ACCESS_RW, &vec); } + +template inline +_InputOutputArray::_InputOutputArray(const Mat_<_Tp>& m) +{ init(FIXED_TYPE + FIXED_SIZE + MAT + traits::Type<_Tp>::value + ACCESS_RW, &m); } + +template inline +_InputOutputArray::_InputOutputArray(const Matx<_Tp, m, n>& mtx) +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_RW, &mtx, Size(n, m)); } + +template inline +_InputOutputArray::_InputOutputArray(const _Tp* vec, int n) +{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_RW, vec, Size(n, 1)); } + +inline _InputOutputArray::_InputOutputArray(cuda::GpuMat& d_mat) +{ init(CUDA_GPU_MAT + ACCESS_RW, &d_mat); } + +inline _InputOutputArray::_InputOutputArray(ogl::Buffer& buf) +{ init(OPENGL_BUFFER + ACCESS_RW, &buf); } + +inline _InputOutputArray::_InputOutputArray(cuda::HostMem& cuda_mem) +{ init(CUDA_HOST_MEM + ACCESS_RW, &cuda_mem); } + +inline _InputOutputArray::_InputOutputArray(const Mat& m) +{ init(FIXED_TYPE + FIXED_SIZE + MAT + ACCESS_RW, &m); } + +inline _InputOutputArray::_InputOutputArray(const std::vector& vec) +{ init(FIXED_SIZE + STD_VECTOR_MAT + ACCESS_RW, &vec); } + +inline _InputOutputArray::_InputOutputArray(const UMat& m) +{ init(FIXED_TYPE + FIXED_SIZE + UMAT + ACCESS_RW, &m); } + +inline _InputOutputArray::_InputOutputArray(const std::vector& vec) +{ init(FIXED_SIZE + STD_VECTOR_UMAT + ACCESS_RW, &vec); } + +inline _InputOutputArray::_InputOutputArray(const cuda::GpuMat& d_mat) +{ init(FIXED_TYPE + FIXED_SIZE + CUDA_GPU_MAT + ACCESS_RW, &d_mat); } + +inline _InputOutputArray::_InputOutputArray(const std::vector& d_mat) +{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_CUDA_GPU_MAT + ACCESS_RW, &d_mat);} + +template<> inline _InputOutputArray::_InputOutputArray(std::vector& d_mat) +{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_CUDA_GPU_MAT + ACCESS_RW, &d_mat);} + +inline _InputOutputArray::_InputOutputArray(const ogl::Buffer& buf) +{ init(FIXED_TYPE + FIXED_SIZE + OPENGL_BUFFER + ACCESS_RW, &buf); } + +inline _InputOutputArray::_InputOutputArray(const cuda::HostMem& cuda_mem) +{ init(FIXED_TYPE + FIXED_SIZE + CUDA_HOST_MEM + ACCESS_RW, &cuda_mem); } + +template inline +_InputOutputArray _InputOutputArray::rawInOut(std::vector<_Tp>& vec) +{ + _InputOutputArray v; + v.flags = _InputArray::FIXED_TYPE + _InputArray::STD_VECTOR + rawType<_Tp>() + ACCESS_RW; + v.obj = (void*)&vec; + return v; +} + +template inline +_InputOutputArray _InputOutputArray::rawInOut(std::array<_Tp, _Nm>& arr) +{ + _InputOutputArray v; + v.flags = FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_RW; + v.obj = (void*)arr.data(); + v.sz = Size(1, _Nm); + return v; +} + + +template static inline _InputArray rawIn(_Tp& v) { return _InputArray::rawIn(v); } +template static inline _OutputArray rawOut(_Tp& v) { return _OutputArray::rawOut(v); } +template static inline _InputOutputArray rawInOut(_Tp& v) { return _InputOutputArray::rawInOut(v); } + +CV__DEBUG_NS_END + +//////////////////////////////////////////// Mat ////////////////////////////////////////// + +template inline +Mat::Mat(const std::vector<_Tp>& vec, bool copyData) + : flags(MAGIC_VAL + traits::Type<_Tp>::value + CV_MAT_CONT_FLAG), dims(2), rows((int)vec.size()), + cols(1), data(0), datastart(0), dataend(0), datalimit(0), allocator(0), u(0), size(&rows), step(0) +{ + if(vec.empty()) + return; + if( !copyData ) + { + step[0] = step[1] = sizeof(_Tp); + datastart = data = (uchar*)&vec[0]; + datalimit = dataend = datastart + rows * step[0]; + } + else + Mat((int)vec.size(), 1, traits::Type<_Tp>::value, (uchar*)&vec[0]).copyTo(*this); +} + +template inline +Mat::Mat(const std::initializer_list<_Tp> list) + : Mat() +{ + CV_Assert(list.size() != 0); + Mat((int)list.size(), 1, traits::Type<_Tp>::value, (uchar*)list.begin()).copyTo(*this); +} + +template inline +Mat::Mat(const std::initializer_list sizes, const std::initializer_list<_Tp> list) + : Mat() +{ + size_t size_total = 1; + for(auto s : sizes) + size_total *= s; + CV_Assert(list.size() != 0); + CV_Assert(size_total == list.size()); + Mat((int)sizes.size(), (int*)sizes.begin(), traits::Type<_Tp>::value, (uchar*)list.begin()).copyTo(*this); +} + +template inline +Mat::Mat(const std::array<_Tp, _Nm>& arr, bool copyData) + : flags(MAGIC_VAL + traits::Type<_Tp>::value + CV_MAT_CONT_FLAG), dims(2), rows((int)arr.size()), + cols(1), data(0), datastart(0), dataend(0), datalimit(0), allocator(0), u(0), size(&rows), step(0) +{ + if(arr.empty()) + return; + if( !copyData ) + { + step[0] = step[1] = sizeof(_Tp); + datastart = data = (uchar*)arr.data(); + datalimit = dataend = datastart + rows * step[0]; + } + else + Mat((int)arr.size(), 1, traits::Type<_Tp>::value, (uchar*)arr.data()).copyTo(*this); +} + +template inline +Mat::Mat(const Vec<_Tp, n>& vec, bool copyData) + : flags(MAGIC_VAL + traits::Type<_Tp>::value + CV_MAT_CONT_FLAG), dims(2), rows(n), cols(1), data(0), + datastart(0), dataend(0), datalimit(0), allocator(0), u(0), size(&rows), step(0) +{ + if( !copyData ) + { + step[0] = step[1] = sizeof(_Tp); + datastart = data = (uchar*)vec.val; + datalimit = dataend = datastart + rows * step[0]; + } + else + Mat(n, 1, traits::Type<_Tp>::value, (void*)vec.val).copyTo(*this); +} + + +template inline +Mat::Mat(const Matx<_Tp,m,n>& M, bool copyData) + : flags(MAGIC_VAL + traits::Type<_Tp>::value + CV_MAT_CONT_FLAG), dims(2), rows(m), cols(n), data(0), + datastart(0), dataend(0), datalimit(0), allocator(0), u(0), size(&rows), step(0) +{ + if( !copyData ) + { + step[0] = cols * sizeof(_Tp); + step[1] = sizeof(_Tp); + datastart = data = (uchar*)M.val; + datalimit = dataend = datastart + rows * step[0]; + } + else + Mat(m, n, traits::Type<_Tp>::value, (uchar*)M.val).copyTo(*this); +} + +template inline +Mat::Mat(const Point_<_Tp>& pt, bool copyData) + : flags(MAGIC_VAL + traits::Type<_Tp>::value + CV_MAT_CONT_FLAG), dims(2), rows(2), cols(1), data(0), + datastart(0), dataend(0), datalimit(0), allocator(0), u(0), size(&rows), step(0) +{ + if( !copyData ) + { + step[0] = step[1] = sizeof(_Tp); + datastart = data = (uchar*)&pt.x; + datalimit = dataend = datastart + rows * step[0]; + } + else + { + create(2, 1, traits::Type<_Tp>::value); + ((_Tp*)data)[0] = pt.x; + ((_Tp*)data)[1] = pt.y; + } +} + +template inline +Mat::Mat(const Point3_<_Tp>& pt, bool copyData) + : flags(MAGIC_VAL + traits::Type<_Tp>::value + CV_MAT_CONT_FLAG), dims(2), rows(3), cols(1), data(0), + datastart(0), dataend(0), datalimit(0), allocator(0), u(0), size(&rows), step(0) +{ + if( !copyData ) + { + step[0] = step[1] = sizeof(_Tp); + datastart = data = (uchar*)&pt.x; + datalimit = dataend = datastart + rows * step[0]; + } + else + { + create(3, 1, traits::Type<_Tp>::value); + ((_Tp*)data)[0] = pt.x; + ((_Tp*)data)[1] = pt.y; + ((_Tp*)data)[2] = pt.z; + } +} + +template inline +Mat::Mat(const MatCommaInitializer_<_Tp>& commaInitializer) + : flags(MAGIC_VAL + traits::Type<_Tp>::value + CV_MAT_CONT_FLAG), dims(0), rows(0), cols(0), data(0), + datastart(0), dataend(0), allocator(0), u(0), size(&rows) +{ + *this = commaInitializer.operator Mat_<_Tp>(); +} + +inline +Mat Mat::row(int y) const +{ + return Mat(*this, Range(y, y + 1), Range::all()); +} + +inline +Mat Mat::col(int x) const +{ + return Mat(*this, Range::all(), Range(x, x + 1)); +} + +inline +Mat Mat::rowRange(int startrow, int endrow) const +{ + return Mat(*this, Range(startrow, endrow), Range::all()); +} + +inline +Mat Mat::rowRange(const Range& r) const +{ + return Mat(*this, r, Range::all()); +} + +inline +Mat Mat::colRange(int startcol, int endcol) const +{ + return Mat(*this, Range::all(), Range(startcol, endcol)); +} + +inline +Mat Mat::colRange(const Range& r) const +{ + return Mat(*this, Range::all(), r); +} + +inline +Mat Mat::operator()( Range _rowRange, Range _colRange ) const +{ + return Mat(*this, _rowRange, _colRange); +} + +inline +Mat Mat::operator()( const Rect& roi ) const +{ + return Mat(*this, roi); +} + +inline +Mat Mat::operator()(const Range* ranges) const +{ + return Mat(*this, ranges); +} + +inline +Mat Mat::operator()(const std::vector& ranges) const +{ + return Mat(*this, ranges); +} + +inline +bool Mat::isContinuous() const +{ + return (flags & CONTINUOUS_FLAG) != 0; +} + +inline +bool Mat::isSubmatrix() const +{ + return (flags & SUBMATRIX_FLAG) != 0; +} + +inline +size_t Mat::elemSize() const +{ + size_t res = dims > 0 ? step.p[dims - 1] : 0; + CV_DbgAssert(res != 0); + return res; +} + +inline +size_t Mat::elemSize1() const +{ + return CV_ELEM_SIZE1(flags); +} + +inline +int Mat::type() const +{ + return CV_MAT_TYPE(flags); +} + +inline +int Mat::depth() const +{ + return CV_MAT_DEPTH(flags); +} + +inline +int Mat::channels() const +{ + return CV_MAT_CN(flags); +} + +inline +uchar* Mat::ptr(int y) +{ + CV_DbgAssert( y == 0 || (data && dims >= 1 && (unsigned)y < (unsigned)size.p[0]) ); + return data + step.p[0] * y; +} + +inline +const uchar* Mat::ptr(int y) const +{ + CV_DbgAssert( y == 0 || (data && dims >= 1 && (unsigned)y < (unsigned)size.p[0]) ); + return data + step.p[0] * y; +} + +template inline +_Tp* Mat::ptr(int y) +{ + CV_DbgAssert( y == 0 || (data && dims >= 1 && (unsigned)y < (unsigned)size.p[0]) ); + return (_Tp*)(data + step.p[0] * y); +} + +template inline +const _Tp* Mat::ptr(int y) const +{ + CV_DbgAssert( y == 0 || (data && dims >= 1 && (unsigned)y < (unsigned)size.p[0]) ); + return (const _Tp*)(data + step.p[0] * y); +} + +inline +uchar* Mat::ptr(int i0, int i1) +{ + CV_DbgAssert(dims >= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)i1 < (unsigned)size.p[1]); + return data + i0 * step.p[0] + i1 * step.p[1]; +} + +inline +const uchar* Mat::ptr(int i0, int i1) const +{ + CV_DbgAssert(dims >= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)i1 < (unsigned)size.p[1]); + return data + i0 * step.p[0] + i1 * step.p[1]; +} + +template inline +_Tp* Mat::ptr(int i0, int i1) +{ + CV_DbgAssert(dims >= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)i1 < (unsigned)size.p[1]); + return (_Tp*)(data + i0 * step.p[0] + i1 * step.p[1]); +} + +template inline +const _Tp* Mat::ptr(int i0, int i1) const +{ + CV_DbgAssert(dims >= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)i1 < (unsigned)size.p[1]); + return (const _Tp*)(data + i0 * step.p[0] + i1 * step.p[1]); +} + +inline +uchar* Mat::ptr(int i0, int i1, int i2) +{ + CV_DbgAssert(dims >= 3); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)i1 < (unsigned)size.p[1]); + CV_DbgAssert((unsigned)i2 < (unsigned)size.p[2]); + return data + i0 * step.p[0] + i1 * step.p[1] + i2 * step.p[2]; +} + +inline +const uchar* Mat::ptr(int i0, int i1, int i2) const +{ + CV_DbgAssert(dims >= 3); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)i1 < (unsigned)size.p[1]); + CV_DbgAssert((unsigned)i2 < (unsigned)size.p[2]); + return data + i0 * step.p[0] + i1 * step.p[1] + i2 * step.p[2]; +} + +template inline +_Tp* Mat::ptr(int i0, int i1, int i2) +{ + CV_DbgAssert(dims >= 3); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)i1 < (unsigned)size.p[1]); + CV_DbgAssert((unsigned)i2 < (unsigned)size.p[2]); + return (_Tp*)(data + i0 * step.p[0] + i1 * step.p[1] + i2 * step.p[2]); +} + +template inline +const _Tp* Mat::ptr(int i0, int i1, int i2) const +{ + CV_DbgAssert(dims >= 3); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)i1 < (unsigned)size.p[1]); + CV_DbgAssert((unsigned)i2 < (unsigned)size.p[2]); + return (const _Tp*)(data + i0 * step.p[0] + i1 * step.p[1] + i2 * step.p[2]); +} + +inline +uchar* Mat::ptr(const int* idx) +{ + int i, d = dims; + uchar* p = data; + CV_DbgAssert( d >= 1 && p ); + for( i = 0; i < d; i++ ) + { + CV_DbgAssert( (unsigned)idx[i] < (unsigned)size.p[i] ); + p += idx[i] * step.p[i]; + } + return p; +} + +inline +const uchar* Mat::ptr(const int* idx) const +{ + int i, d = dims; + uchar* p = data; + CV_DbgAssert( d >= 1 && p ); + for( i = 0; i < d; i++ ) + { + CV_DbgAssert( (unsigned)idx[i] < (unsigned)size.p[i] ); + p += idx[i] * step.p[i]; + } + return p; +} + +template inline +_Tp* Mat::ptr(const int* idx) +{ + int i, d = dims; + uchar* p = data; + CV_DbgAssert( d >= 1 && p ); + for( i = 0; i < d; i++ ) + { + CV_DbgAssert( (unsigned)idx[i] < (unsigned)size.p[i] ); + p += idx[i] * step.p[i]; + } + return (_Tp*)p; +} + +template inline +const _Tp* Mat::ptr(const int* idx) const +{ + int i, d = dims; + uchar* p = data; + CV_DbgAssert( d >= 1 && p ); + for( i = 0; i < d; i++ ) + { + CV_DbgAssert( (unsigned)idx[i] < (unsigned)size.p[i] ); + p += idx[i] * step.p[i]; + } + return (const _Tp*)p; +} + +template inline +uchar* Mat::ptr(const Vec& idx) +{ + return Mat::ptr(idx.val); +} + +template inline +const uchar* Mat::ptr(const Vec& idx) const +{ + return Mat::ptr(idx.val); +} + +template inline +_Tp* Mat::ptr(const Vec& idx) +{ + CV_DbgAssert( elemSize() == sizeof(_Tp) ); + return Mat::ptr<_Tp>(idx.val); +} + +template inline +const _Tp* Mat::ptr(const Vec& idx) const +{ + CV_DbgAssert( elemSize() == sizeof(_Tp) ); + return Mat::ptr<_Tp>(idx.val); +} + + +template inline +_Tp& Mat::at(int i0, int i1) +{ + CV_DbgAssert(dims <= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)(i1 * DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels())); + CV_DbgAssert(CV_ELEM_SIZE1(traits::Depth<_Tp>::value) == elemSize1()); + return ((_Tp*)(data + step.p[0] * i0))[i1]; +} + +template inline +const _Tp& Mat::at(int i0, int i1) const +{ + CV_DbgAssert(dims <= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)(i1 * DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels())); + CV_DbgAssert(CV_ELEM_SIZE1(traits::Depth<_Tp>::value) == elemSize1()); + return ((const _Tp*)(data + step.p[0] * i0))[i1]; +} + +template inline +_Tp& Mat::at(Point pt) +{ + CV_DbgAssert(dims <= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)pt.y < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)(pt.x * DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels())); + CV_DbgAssert(CV_ELEM_SIZE1(traits::Depth<_Tp>::value) == elemSize1()); + return ((_Tp*)(data + step.p[0] * pt.y))[pt.x]; +} + +template inline +const _Tp& Mat::at(Point pt) const +{ + CV_DbgAssert(dims <= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)pt.y < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)(pt.x * DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels())); + CV_DbgAssert(CV_ELEM_SIZE1(traits::Depth<_Tp>::value) == elemSize1()); + return ((const _Tp*)(data + step.p[0] * pt.y))[pt.x]; +} + +template inline +_Tp& Mat::at(int i0) +{ + CV_DbgAssert(dims <= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)(size.p[0] * size.p[1])); + CV_DbgAssert(elemSize() == sizeof(_Tp)); + if( isContinuous() || size.p[0] == 1 ) + return ((_Tp*)data)[i0]; + if( size.p[1] == 1 ) + return *(_Tp*)(data + step.p[0] * i0); + int i = i0 / cols, j = i0 - i * cols; + return ((_Tp*)(data + step.p[0] * i))[j]; +} + +template inline +const _Tp& Mat::at(int i0) const +{ + CV_DbgAssert(dims <= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)(size.p[0] * size.p[1])); + CV_DbgAssert(elemSize() == sizeof(_Tp)); + if( isContinuous() || size.p[0] == 1 ) + return ((const _Tp*)data)[i0]; + if( size.p[1] == 1 ) + return *(const _Tp*)(data + step.p[0] * i0); + int i = i0 / cols, j = i0 - i * cols; + return ((const _Tp*)(data + step.p[0] * i))[j]; +} + +template inline +_Tp& Mat::at(int i0, int i1, int i2) +{ + CV_DbgAssert( elemSize() == sizeof(_Tp) ); + return *(_Tp*)ptr(i0, i1, i2); +} + +template inline +const _Tp& Mat::at(int i0, int i1, int i2) const +{ + CV_DbgAssert( elemSize() == sizeof(_Tp) ); + return *(const _Tp*)ptr(i0, i1, i2); +} + +template inline +_Tp& Mat::at(const int* idx) +{ + CV_DbgAssert( elemSize() == sizeof(_Tp) ); + return *(_Tp*)ptr(idx); +} + +template inline +const _Tp& Mat::at(const int* idx) const +{ + CV_DbgAssert( elemSize() == sizeof(_Tp) ); + return *(const _Tp*)ptr(idx); +} + +template inline +_Tp& Mat::at(const Vec& idx) +{ + CV_DbgAssert( elemSize() == sizeof(_Tp) ); + return *(_Tp*)ptr(idx.val); +} + +template inline +const _Tp& Mat::at(const Vec& idx) const +{ + CV_DbgAssert( elemSize() == sizeof(_Tp) ); + return *(const _Tp*)ptr(idx.val); +} + +template inline +MatConstIterator_<_Tp> Mat::begin() const +{ + if (empty()) + return MatConstIterator_<_Tp>(); + CV_DbgAssert( elemSize() == sizeof(_Tp) ); + return MatConstIterator_<_Tp>((const Mat_<_Tp>*)this); +} + +template inline +std::reverse_iterator> Mat::rbegin() const +{ + if (empty()) + return std::reverse_iterator>(); + CV_DbgAssert( elemSize() == sizeof(_Tp) ); + MatConstIterator_<_Tp> it((const Mat_<_Tp>*)this); + it += total(); + return std::reverse_iterator> (it); +} + +template inline +MatConstIterator_<_Tp> Mat::end() const +{ + if (empty()) + return MatConstIterator_<_Tp>(); + CV_DbgAssert( elemSize() == sizeof(_Tp) ); + MatConstIterator_<_Tp> it((const Mat_<_Tp>*)this); + it += total(); + return it; +} + +template inline +std::reverse_iterator> Mat::rend() const +{ + if (empty()) + return std::reverse_iterator>(); + CV_DbgAssert( elemSize() == sizeof(_Tp) ); + return std::reverse_iterator>((const Mat_<_Tp>*)this); +} + +template inline +MatIterator_<_Tp> Mat::begin() +{ + if (empty()) + return MatIterator_<_Tp>(); + CV_DbgAssert( elemSize() == sizeof(_Tp) ); + return MatIterator_<_Tp>((Mat_<_Tp>*)this); +} + +template inline +std::reverse_iterator> Mat::rbegin() +{ + if (empty()) + return std::reverse_iterator>(); + CV_DbgAssert( elemSize() == sizeof(_Tp) ); + MatIterator_<_Tp> it((Mat_<_Tp>*)this); + it += total(); + return std::reverse_iterator>(it); +} + +template inline +MatIterator_<_Tp> Mat::end() +{ + if (empty()) + return MatIterator_<_Tp>(); + CV_DbgAssert( elemSize() == sizeof(_Tp) ); + MatIterator_<_Tp> it((Mat_<_Tp>*)this); + it += total(); + return it; +} + +template inline +std::reverse_iterator> Mat::rend() +{ + if (empty()) + return std::reverse_iterator>(); + CV_DbgAssert( elemSize() == sizeof(_Tp) ); + return std::reverse_iterator>(MatIterator_<_Tp>((Mat_<_Tp>*)this)); +} + +template inline +void Mat::forEach(const Functor& operation) { + this->forEach_impl<_Tp>(operation); +} + +template inline +void Mat::forEach(const Functor& operation) const { + // call as not const + (const_cast(this))->forEach<_Tp>(operation); +} + +template inline +Mat::operator std::vector<_Tp>() const +{ + std::vector<_Tp> v; + copyTo(v); + return v; +} + +template inline +Mat::operator std::array<_Tp, _Nm>() const +{ + std::array<_Tp, _Nm> v; + copyTo(v); + return v; +} + +template inline +Mat::operator Vec<_Tp, n>() const +{ + CV_Assert( data && dims <= 2 && (rows == 1 || cols == 1) && + rows + cols - 1 == n && channels() == 1 ); + + if( isContinuous() && type() == traits::Type<_Tp>::value ) + return Vec<_Tp, n>((_Tp*)data); + Vec<_Tp, n> v; + Mat tmp(rows, cols, traits::Type<_Tp>::value, v.val); + convertTo(tmp, tmp.type()); + return v; +} + +template inline +Mat::operator Matx<_Tp, m, n>() const +{ + CV_Assert( data && dims <= 2 && rows == m && cols == n && channels() == 1 ); + + if( isContinuous() && type() == traits::Type<_Tp>::value ) + return Matx<_Tp, m, n>((_Tp*)data); + Matx<_Tp, m, n> mtx; + Mat tmp(rows, cols, traits::Type<_Tp>::value, mtx.val); + convertTo(tmp, tmp.type()); + return mtx; +} + +template inline +void Mat::push_back(const _Tp& elem) +{ + if( !data ) + { + *this = Mat(1, 1, traits::Type<_Tp>::value, (void*)&elem).clone(); + return; + } + CV_Assert(traits::Type<_Tp>::value == type() && cols == 1 + /* && dims == 2 (cols == 1 implies dims == 2) */); + const uchar* tmp = dataend + step[0]; + if( !isSubmatrix() && isContinuous() && tmp <= datalimit ) + { + *(_Tp*)(data + (size.p[0]++) * step.p[0]) = elem; + dataend = tmp; + } + else + push_back_(&elem); +} + +template inline +void Mat::push_back(const Mat_<_Tp>& m) +{ + push_back((const Mat&)m); +} + +template<> inline +void Mat::push_back(const MatExpr& expr) +{ + push_back(static_cast(expr)); +} + + +template inline +void Mat::push_back(const std::vector<_Tp>& v) +{ + push_back(Mat(v)); +} + + +///////////////////////////// MatSize //////////////////////////// + +inline +MatSize::MatSize(int* _p) CV_NOEXCEPT + : p(_p) {} + +inline +int MatSize::dims() const CV_NOEXCEPT +{ + return (p - 1)[0]; +} + +inline +Size MatSize::operator()() const +{ + CV_DbgAssert(dims() <= 2); + return Size(p[1], p[0]); +} + +inline +const int& MatSize::operator[](int i) const +{ + CV_DbgAssert(i < dims()); +#ifdef __OPENCV_BUILD + CV_DbgAssert(i >= 0); +#endif + return p[i]; +} + +inline +int& MatSize::operator[](int i) +{ + CV_DbgAssert(i < dims()); +#ifdef __OPENCV_BUILD + CV_DbgAssert(i >= 0); +#endif + return p[i]; +} + +inline +MatSize::operator const int*() const CV_NOEXCEPT +{ + return p; +} + +inline +bool MatSize::operator != (const MatSize& sz) const CV_NOEXCEPT +{ + return !(*this == sz); +} + + + +///////////////////////////// MatStep //////////////////////////// + +inline +MatStep::MatStep() CV_NOEXCEPT +{ + p = buf; p[0] = p[1] = 0; +} + +inline +MatStep::MatStep(size_t s) CV_NOEXCEPT +{ + p = buf; p[0] = s; p[1] = 0; +} + +inline +const size_t& MatStep::operator[](int i) const CV_NOEXCEPT +{ + return p[i]; +} + +inline +size_t& MatStep::operator[](int i) CV_NOEXCEPT +{ + return p[i]; +} + +inline MatStep::operator size_t() const +{ + CV_DbgAssert( p == buf ); + return buf[0]; +} + +inline MatStep& MatStep::operator = (size_t s) +{ + CV_DbgAssert( p == buf ); + buf[0] = s; + return *this; +} + + + +////////////////////////////// Mat_<_Tp> //////////////////////////// + +template inline +Mat_<_Tp>::Mat_() CV_NOEXCEPT + : Mat() +{ + flags = (flags & ~CV_MAT_TYPE_MASK) + traits::Type<_Tp>::value; +} + +template inline +Mat_<_Tp>::Mat_(int _rows, int _cols) + : Mat(_rows, _cols, traits::Type<_Tp>::value) +{ +} + +template inline +Mat_<_Tp>::Mat_(int _rows, int _cols, const _Tp& value) + : Mat(_rows, _cols, traits::Type<_Tp>::value) +{ + *this = value; +} + +template inline +Mat_<_Tp>::Mat_(Size _sz) + : Mat(_sz.height, _sz.width, traits::Type<_Tp>::value) +{} + +template inline +Mat_<_Tp>::Mat_(Size _sz, const _Tp& value) + : Mat(_sz.height, _sz.width, traits::Type<_Tp>::value) +{ + *this = value; +} + +template inline +Mat_<_Tp>::Mat_(int _dims, const int* _sz) + : Mat(_dims, _sz, traits::Type<_Tp>::value) +{} + +template inline +Mat_<_Tp>::Mat_(int _dims, const int* _sz, const _Tp& _s) + : Mat(_dims, _sz, traits::Type<_Tp>::value, Scalar(_s)) +{} + +template inline +Mat_<_Tp>::Mat_(int _dims, const int* _sz, _Tp* _data, const size_t* _steps) + : Mat(_dims, _sz, traits::Type<_Tp>::value, _data, _steps) +{} + +template inline +Mat_<_Tp>::Mat_(const Mat_<_Tp>& m, const Range* ranges) + : Mat(m, ranges) +{} + +template inline +Mat_<_Tp>::Mat_(const Mat_<_Tp>& m, const std::vector& ranges) + : Mat(m, ranges) +{} + +template inline +Mat_<_Tp>::Mat_(const Mat& m) + : Mat() +{ + flags = (flags & ~CV_MAT_TYPE_MASK) + traits::Type<_Tp>::value; + *this = m; +} + +template inline +Mat_<_Tp>::Mat_(const Mat_& m) + : Mat(m) +{} + +template inline +Mat_<_Tp>::Mat_(int _rows, int _cols, _Tp* _data, size_t steps) + : Mat(_rows, _cols, traits::Type<_Tp>::value, _data, steps) +{} + +template inline +Mat_<_Tp>::Mat_(const Mat_& m, const Range& _rowRange, const Range& _colRange) + : Mat(m, _rowRange, _colRange) +{} + +template inline +Mat_<_Tp>::Mat_(const Mat_& m, const Rect& roi) + : Mat(m, roi) +{} + +template template inline +Mat_<_Tp>::Mat_(const Vec::channel_type, n>& vec, bool copyData) + : Mat(n / DataType<_Tp>::channels, 1, traits::Type<_Tp>::value, (void*)&vec) +{ + CV_Assert(n%DataType<_Tp>::channels == 0); + if( copyData ) + *this = clone(); +} + +template template inline +Mat_<_Tp>::Mat_(const Matx::channel_type, m, n>& M, bool copyData) + : Mat(m, n / DataType<_Tp>::channels, traits::Type<_Tp>::value, (void*)&M) +{ + CV_Assert(n % DataType<_Tp>::channels == 0); + if( copyData ) + *this = clone(); +} + +template inline +Mat_<_Tp>::Mat_(const Point_::channel_type>& pt, bool copyData) + : Mat(2 / DataType<_Tp>::channels, 1, traits::Type<_Tp>::value, (void*)&pt) +{ + CV_Assert(2 % DataType<_Tp>::channels == 0); + if( copyData ) + *this = clone(); +} + +template inline +Mat_<_Tp>::Mat_(const Point3_::channel_type>& pt, bool copyData) + : Mat(3 / DataType<_Tp>::channels, 1, traits::Type<_Tp>::value, (void*)&pt) +{ + CV_Assert(3 % DataType<_Tp>::channels == 0); + if( copyData ) + *this = clone(); +} + +template inline +Mat_<_Tp>::Mat_(const MatCommaInitializer_<_Tp>& commaInitializer) + : Mat(commaInitializer) +{} + +template inline +Mat_<_Tp>::Mat_(const std::vector<_Tp>& vec, bool copyData) + : Mat(vec, copyData) +{} + +template inline +Mat_<_Tp>::Mat_(std::initializer_list<_Tp> list) + : Mat(list) +{} + +template inline +Mat_<_Tp>::Mat_(const std::initializer_list sizes, std::initializer_list<_Tp> list) + : Mat(sizes, list) +{} + +template template inline +Mat_<_Tp>::Mat_(const std::array<_Tp, _Nm>& arr, bool copyData) + : Mat(arr, copyData) +{} + +template inline +Mat_<_Tp>& Mat_<_Tp>::operator = (const Mat& m) +{ + if (m.empty()) + { + release(); + return *this; + } + if( traits::Type<_Tp>::value == m.type() ) + { + Mat::operator = (m); + return *this; + } + if( traits::Depth<_Tp>::value == m.depth() ) + { + return (*this = m.reshape(DataType<_Tp>::channels, m.dims, 0)); + } + CV_Assert(DataType<_Tp>::channels == m.channels() || m.empty()); + m.convertTo(*this, type()); + return *this; +} + +template inline +Mat_<_Tp>& Mat_<_Tp>::operator = (const Mat_& m) +{ + Mat::operator=(m); + return *this; +} + +template inline +Mat_<_Tp>& Mat_<_Tp>::operator = (const _Tp& s) +{ + typedef typename DataType<_Tp>::vec_type VT; + Mat::operator=(Scalar((const VT&)s)); + return *this; +} + +template inline +void Mat_<_Tp>::create(int _rows, int _cols) +{ + Mat::create(_rows, _cols, traits::Type<_Tp>::value); +} + +template inline +void Mat_<_Tp>::create(Size _sz) +{ + Mat::create(_sz, traits::Type<_Tp>::value); +} + +template inline +void Mat_<_Tp>::create(int _dims, const int* _sz) +{ + Mat::create(_dims, _sz, traits::Type<_Tp>::value); +} + +template inline +void Mat_<_Tp>::release() +{ + Mat::release(); + flags = (flags & ~CV_MAT_TYPE_MASK) + traits::Type<_Tp>::value; +} + +template inline +Mat_<_Tp> Mat_<_Tp>::cross(const Mat_& m) const +{ + return Mat_<_Tp>(Mat::cross(m)); +} + +template template inline +Mat_<_Tp>::operator Mat_() const +{ + return Mat_(static_cast(*this)); +} + +template inline +Mat_<_Tp> Mat_<_Tp>::row(int y) const +{ + return Mat_(*this, Range(y, y+1), Range::all()); +} + +template inline +Mat_<_Tp> Mat_<_Tp>::col(int x) const +{ + return Mat_(*this, Range::all(), Range(x, x+1)); +} + +template inline +Mat_<_Tp> Mat_<_Tp>::diag(int d) const +{ + return Mat_(Mat::diag(d)); +} + +template inline +Mat_<_Tp> Mat_<_Tp>::clone() const +{ + return Mat_(Mat::clone()); +} + +template inline +size_t Mat_<_Tp>::elemSize() const +{ + CV_DbgAssert( Mat::elemSize() == sizeof(_Tp) ); + return sizeof(_Tp); +} + +template inline +size_t Mat_<_Tp>::elemSize1() const +{ + CV_DbgAssert( Mat::elemSize1() == sizeof(_Tp) / DataType<_Tp>::channels ); + return sizeof(_Tp) / DataType<_Tp>::channels; +} + +template inline +int Mat_<_Tp>::type() const +{ + CV_DbgAssert( Mat::type() == traits::Type<_Tp>::value ); + return traits::Type<_Tp>::value; +} + +template inline +int Mat_<_Tp>::depth() const +{ + CV_DbgAssert( Mat::depth() == traits::Depth<_Tp>::value ); + return traits::Depth<_Tp>::value; +} + +template inline +int Mat_<_Tp>::channels() const +{ + CV_DbgAssert( Mat::channels() == DataType<_Tp>::channels ); + return DataType<_Tp>::channels; +} + +template inline +size_t Mat_<_Tp>::stepT(int i) const +{ + return step.p[i] / elemSize(); +} + +template inline +size_t Mat_<_Tp>::step1(int i) const +{ + return step.p[i] / elemSize1(); +} + +template inline +Mat_<_Tp>& Mat_<_Tp>::adjustROI( int dtop, int dbottom, int dleft, int dright ) +{ + return (Mat_<_Tp>&)(Mat::adjustROI(dtop, dbottom, dleft, dright)); +} + +template inline +Mat_<_Tp> Mat_<_Tp>::operator()( const Range& _rowRange, const Range& _colRange ) const +{ + return Mat_<_Tp>(*this, _rowRange, _colRange); +} + +template inline +Mat_<_Tp> Mat_<_Tp>::operator()( const Rect& roi ) const +{ + return Mat_<_Tp>(*this, roi); +} + +template inline +Mat_<_Tp> Mat_<_Tp>::operator()( const Range* ranges ) const +{ + return Mat_<_Tp>(*this, ranges); +} + +template inline +Mat_<_Tp> Mat_<_Tp>::operator()(const std::vector& ranges) const +{ + return Mat_<_Tp>(*this, ranges); +} + +template inline +_Tp* Mat_<_Tp>::operator [](int y) +{ + CV_DbgAssert( 0 <= y && y < size.p[0] ); + return (_Tp*)(data + y*step.p[0]); +} + +template inline +const _Tp* Mat_<_Tp>::operator [](int y) const +{ + CV_DbgAssert( 0 <= y && y < size.p[0] ); + return (const _Tp*)(data + y*step.p[0]); +} + +template inline +_Tp& Mat_<_Tp>::operator ()(int i0, int i1) +{ + CV_DbgAssert(dims <= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)i1 < (unsigned)size.p[1]); + CV_DbgAssert(type() == traits::Type<_Tp>::value); + return ((_Tp*)(data + step.p[0] * i0))[i1]; +} + +template inline +const _Tp& Mat_<_Tp>::operator ()(int i0, int i1) const +{ + CV_DbgAssert(dims <= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)i1 < (unsigned)size.p[1]); + CV_DbgAssert(type() == traits::Type<_Tp>::value); + return ((const _Tp*)(data + step.p[0] * i0))[i1]; +} + +template inline +_Tp& Mat_<_Tp>::operator ()(Point pt) +{ + CV_DbgAssert(dims <= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)pt.y < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)pt.x < (unsigned)size.p[1]); + CV_DbgAssert(type() == traits::Type<_Tp>::value); + return ((_Tp*)(data + step.p[0] * pt.y))[pt.x]; +} + +template inline +const _Tp& Mat_<_Tp>::operator ()(Point pt) const +{ + CV_DbgAssert(dims <= 2); + CV_DbgAssert(data); + CV_DbgAssert((unsigned)pt.y < (unsigned)size.p[0]); + CV_DbgAssert((unsigned)pt.x < (unsigned)size.p[1]); + CV_DbgAssert(type() == traits::Type<_Tp>::value); + return ((const _Tp*)(data + step.p[0] * pt.y))[pt.x]; +} + +template inline +_Tp& Mat_<_Tp>::operator ()(const int* idx) +{ + return Mat::at<_Tp>(idx); +} + +template inline +const _Tp& Mat_<_Tp>::operator ()(const int* idx) const +{ + return Mat::at<_Tp>(idx); +} + +template template inline +_Tp& Mat_<_Tp>::operator ()(const Vec& idx) +{ + return Mat::at<_Tp>(idx); +} + +template template inline +const _Tp& Mat_<_Tp>::operator ()(const Vec& idx) const +{ + return Mat::at<_Tp>(idx); +} + +template inline +_Tp& Mat_<_Tp>::operator ()(int i0) +{ + return this->at<_Tp>(i0); +} + +template inline +const _Tp& Mat_<_Tp>::operator ()(int i0) const +{ + return this->at<_Tp>(i0); +} + +template inline +_Tp& Mat_<_Tp>::operator ()(int i0, int i1, int i2) +{ + return this->at<_Tp>(i0, i1, i2); +} + +template inline +const _Tp& Mat_<_Tp>::operator ()(int i0, int i1, int i2) const +{ + return this->at<_Tp>(i0, i1, i2); +} + +template inline +Mat_<_Tp>::operator std::vector<_Tp>() const +{ + std::vector<_Tp> v; + copyTo(v); + return v; +} + +template template inline +Mat_<_Tp>::operator std::array<_Tp, _Nm>() const +{ + std::array<_Tp, _Nm> a; + copyTo(a); + return a; +} + +template template inline +Mat_<_Tp>::operator Vec::channel_type, n>() const +{ + CV_Assert(n % DataType<_Tp>::channels == 0); + +#if defined _MSC_VER + const Mat* pMat = (const Mat*)this; // workaround for MSVS <= 2012 compiler bugs (but GCC 4.6 dislikes this workaround) + return pMat->operator Vec::channel_type, n>(); +#else + return this->Mat::operator Vec::channel_type, n>(); +#endif +} + +template template inline +Mat_<_Tp>::operator Matx::channel_type, m, n>() const +{ + CV_Assert(n % DataType<_Tp>::channels == 0); + +#if defined _MSC_VER + const Mat* pMat = (const Mat*)this; // workaround for MSVS <= 2012 compiler bugs (but GCC 4.6 dislikes this workaround) + Matx::channel_type, m, n> res = pMat->operator Matx::channel_type, m, n>(); + return res; +#else + Matx::channel_type, m, n> res = this->Mat::operator Matx::channel_type, m, n>(); + return res; +#endif +} + +template inline +MatConstIterator_<_Tp> Mat_<_Tp>::begin() const +{ + return Mat::begin<_Tp>(); +} + +template inline +std::reverse_iterator> Mat_<_Tp>::rbegin() const +{ + return Mat::rbegin<_Tp>(); +} + +template inline +MatConstIterator_<_Tp> Mat_<_Tp>::end() const +{ + return Mat::end<_Tp>(); +} + +template inline +std::reverse_iterator> Mat_<_Tp>::rend() const +{ + return Mat::rend<_Tp>(); +} + +template inline +MatIterator_<_Tp> Mat_<_Tp>::begin() +{ + return Mat::begin<_Tp>(); +} + +template inline +std::reverse_iterator> Mat_<_Tp>::rbegin() +{ + return Mat::rbegin<_Tp>(); +} + +template inline +MatIterator_<_Tp> Mat_<_Tp>::end() +{ + return Mat::end<_Tp>(); +} + +template inline +std::reverse_iterator> Mat_<_Tp>::rend() +{ + return Mat::rend<_Tp>(); +} + +template template inline +void Mat_<_Tp>::forEach(const Functor& operation) { + Mat::forEach<_Tp, Functor>(operation); +} + +template template inline +void Mat_<_Tp>::forEach(const Functor& operation) const { + Mat::forEach<_Tp, Functor>(operation); +} + +template inline +Mat_<_Tp>::Mat_(Mat_&& m) + : Mat(std::move(m)) +{ +} + +template inline +Mat_<_Tp>& Mat_<_Tp>::operator = (Mat_&& m) +{ + Mat::operator = (std::move(m)); + return *this; +} + +template inline +Mat_<_Tp>::Mat_(Mat&& m) + : Mat() +{ + flags = (flags & ~CV_MAT_TYPE_MASK) + traits::Type<_Tp>::value; + *this = std::move(m); +} + +template inline +Mat_<_Tp>& Mat_<_Tp>::operator = (Mat&& m) +{ + if (m.empty()) + { + release(); + return *this; + } + if( traits::Type<_Tp>::value == m.type() ) + { + Mat::operator = ((Mat&&)m); + return *this; + } + if( traits::Depth<_Tp>::value == m.depth() ) + { + Mat::operator = ((Mat&&)m.reshape(DataType<_Tp>::channels, m.dims, 0)); + return *this; + } + CV_DbgAssert(DataType<_Tp>::channels == m.channels()); + m.convertTo(*this, type()); + return *this; +} + +template inline +Mat_<_Tp>::Mat_(MatExpr&& e) + : Mat() +{ + flags = (flags & ~CV_MAT_TYPE_MASK) + traits::Type<_Tp>::value; + *this = Mat(e); +} + + +///////////////////////////// SparseMat ///////////////////////////// + +inline +SparseMat SparseMat::clone() const +{ + SparseMat temp; + this->copyTo(temp); + return temp; +} + +inline +size_t SparseMat::elemSize() const +{ + return CV_ELEM_SIZE(flags); +} + +inline +size_t SparseMat::elemSize1() const +{ + return CV_ELEM_SIZE1(flags); +} + +inline +int SparseMat::type() const +{ + return CV_MAT_TYPE(flags); +} + +inline +int SparseMat::depth() const +{ + return CV_MAT_DEPTH(flags); +} + +inline +int SparseMat::channels() const +{ + return CV_MAT_CN(flags); +} + +inline +const int* SparseMat::size() const +{ + return hdr ? hdr->size : 0; +} + +inline +int SparseMat::size(int i) const +{ + if( hdr ) + { + CV_DbgAssert((unsigned)i < (unsigned)hdr->dims); + return hdr->size[i]; + } + return 0; +} + +inline +int SparseMat::dims() const +{ + return hdr ? hdr->dims : 0; +} + +inline +size_t SparseMat::nzcount() const +{ + return hdr ? hdr->nodeCount : 0; +} + +template inline +_Tp& SparseMat::ref(int i0, size_t* hashval) +{ + return *(_Tp*)((SparseMat*)this)->ptr(i0, true, hashval); +} + +template inline +_Tp& SparseMat::ref(int i0, int i1, size_t* hashval) +{ + return *(_Tp*)((SparseMat*)this)->ptr(i0, i1, true, hashval); +} + +template inline +_Tp& SparseMat::ref(int i0, int i1, int i2, size_t* hashval) +{ + return *(_Tp*)((SparseMat*)this)->ptr(i0, i1, i2, true, hashval); +} + +template inline +_Tp& SparseMat::ref(const int* idx, size_t* hashval) +{ + return *(_Tp*)((SparseMat*)this)->ptr(idx, true, hashval); +} + +template inline +_Tp SparseMat::value(int i0, size_t* hashval) const +{ + const _Tp* p = (const _Tp*)((SparseMat*)this)->ptr(i0, false, hashval); + return p ? *p : _Tp(); +} + +template inline +_Tp SparseMat::value(int i0, int i1, size_t* hashval) const +{ + const _Tp* p = (const _Tp*)((SparseMat*)this)->ptr(i0, i1, false, hashval); + return p ? *p : _Tp(); +} + +template inline +_Tp SparseMat::value(int i0, int i1, int i2, size_t* hashval) const +{ + const _Tp* p = (const _Tp*)((SparseMat*)this)->ptr(i0, i1, i2, false, hashval); + return p ? *p : _Tp(); +} + +template inline +_Tp SparseMat::value(const int* idx, size_t* hashval) const +{ + const _Tp* p = (const _Tp*)((SparseMat*)this)->ptr(idx, false, hashval); + return p ? *p : _Tp(); +} + +template inline +const _Tp* SparseMat::find(int i0, size_t* hashval) const +{ + return (const _Tp*)((SparseMat*)this)->ptr(i0, false, hashval); +} + +template inline +const _Tp* SparseMat::find(int i0, int i1, size_t* hashval) const +{ + return (const _Tp*)((SparseMat*)this)->ptr(i0, i1, false, hashval); +} + +template inline +const _Tp* SparseMat::find(int i0, int i1, int i2, size_t* hashval) const +{ + return (const _Tp*)((SparseMat*)this)->ptr(i0, i1, i2, false, hashval); +} + +template inline +const _Tp* SparseMat::find(const int* idx, size_t* hashval) const +{ + return (const _Tp*)((SparseMat*)this)->ptr(idx, false, hashval); +} + +template inline +_Tp& SparseMat::value(Node* n) +{ + return *(_Tp*)((uchar*)n + hdr->valueOffset); +} + +template inline +const _Tp& SparseMat::value(const Node* n) const +{ + return *(const _Tp*)((const uchar*)n + hdr->valueOffset); +} + +inline +SparseMat::Node* SparseMat::node(size_t nidx) +{ + return (Node*)(void*)&hdr->pool[nidx]; +} + +inline +const SparseMat::Node* SparseMat::node(size_t nidx) const +{ + return (const Node*)(const void*)&hdr->pool[nidx]; +} + +inline +SparseMatIterator SparseMat::begin() +{ + return SparseMatIterator(this); +} + +inline +SparseMatConstIterator SparseMat::begin() const +{ + return SparseMatConstIterator(this); +} + +inline +SparseMatIterator SparseMat::end() +{ + SparseMatIterator it(this); + it.seekEnd(); + return it; +} + +inline +SparseMatConstIterator SparseMat::end() const +{ + SparseMatConstIterator it(this); + it.seekEnd(); + return it; +} + +template inline +SparseMatIterator_<_Tp> SparseMat::begin() +{ + return SparseMatIterator_<_Tp>(this); +} + +template inline +SparseMatConstIterator_<_Tp> SparseMat::begin() const +{ + return SparseMatConstIterator_<_Tp>(this); +} + +template inline +SparseMatIterator_<_Tp> SparseMat::end() +{ + SparseMatIterator_<_Tp> it(this); + it.seekEnd(); + return it; +} + +template inline +SparseMatConstIterator_<_Tp> SparseMat::end() const +{ + SparseMatConstIterator_<_Tp> it(this); + it.seekEnd(); + return it; +} + + + +///////////////////////////// SparseMat_ //////////////////////////// + +template inline +SparseMat_<_Tp>::SparseMat_() +{ + flags = MAGIC_VAL + traits::Type<_Tp>::value; +} + +template inline +SparseMat_<_Tp>::SparseMat_(int _dims, const int* _sizes) + : SparseMat(_dims, _sizes, traits::Type<_Tp>::value) +{} + +template inline +SparseMat_<_Tp>::SparseMat_(const SparseMat& m) +{ + if( m.type() == traits::Type<_Tp>::value ) + *this = (const SparseMat_<_Tp>&)m; + else + m.convertTo(*this, traits::Type<_Tp>::value); +} + +template inline +SparseMat_<_Tp>::SparseMat_(const SparseMat_<_Tp>& m) +{ + this->flags = m.flags; + this->hdr = m.hdr; + if( this->hdr ) + CV_XADD(&this->hdr->refcount, 1); +} + +template inline +SparseMat_<_Tp>::SparseMat_(const Mat& m) +{ + SparseMat sm(m); + *this = sm; +} + +template inline +SparseMat_<_Tp>& SparseMat_<_Tp>::operator = (const SparseMat_<_Tp>& m) +{ + if( this != &m ) + { + if( m.hdr ) CV_XADD(&m.hdr->refcount, 1); + release(); + flags = m.flags; + hdr = m.hdr; + } + return *this; +} + +template inline +SparseMat_<_Tp>& SparseMat_<_Tp>::operator = (const SparseMat& m) +{ + if( m.type() == traits::Type<_Tp>::value ) + return (*this = (const SparseMat_<_Tp>&)m); + m.convertTo(*this, traits::Type<_Tp>::value); + return *this; +} + +template inline +SparseMat_<_Tp>& SparseMat_<_Tp>::operator = (const Mat& m) +{ + return (*this = SparseMat(m)); +} + +template inline +SparseMat_<_Tp> SparseMat_<_Tp>::clone() const +{ + SparseMat_<_Tp> m; + this->copyTo(m); + return m; +} + +template inline +void SparseMat_<_Tp>::create(int _dims, const int* _sizes) +{ + SparseMat::create(_dims, _sizes, traits::Type<_Tp>::value); +} + +template inline +int SparseMat_<_Tp>::type() const +{ + return traits::Type<_Tp>::value; +} + +template inline +int SparseMat_<_Tp>::depth() const +{ + return traits::Depth<_Tp>::value; +} + +template inline +int SparseMat_<_Tp>::channels() const +{ + return DataType<_Tp>::channels; +} + +template inline +_Tp& SparseMat_<_Tp>::ref(int i0, size_t* hashval) +{ + return SparseMat::ref<_Tp>(i0, hashval); +} + +template inline +_Tp SparseMat_<_Tp>::operator()(int i0, size_t* hashval) const +{ + return SparseMat::value<_Tp>(i0, hashval); +} + +template inline +_Tp& SparseMat_<_Tp>::ref(int i0, int i1, size_t* hashval) +{ + return SparseMat::ref<_Tp>(i0, i1, hashval); +} + +template inline +_Tp SparseMat_<_Tp>::operator()(int i0, int i1, size_t* hashval) const +{ + return SparseMat::value<_Tp>(i0, i1, hashval); +} + +template inline +_Tp& SparseMat_<_Tp>::ref(int i0, int i1, int i2, size_t* hashval) +{ + return SparseMat::ref<_Tp>(i0, i1, i2, hashval); +} + +template inline +_Tp SparseMat_<_Tp>::operator()(int i0, int i1, int i2, size_t* hashval) const +{ + return SparseMat::value<_Tp>(i0, i1, i2, hashval); +} + +template inline +_Tp& SparseMat_<_Tp>::ref(const int* idx, size_t* hashval) +{ + return SparseMat::ref<_Tp>(idx, hashval); +} + +template inline +_Tp SparseMat_<_Tp>::operator()(const int* idx, size_t* hashval) const +{ + return SparseMat::value<_Tp>(idx, hashval); +} + +template inline +SparseMatIterator_<_Tp> SparseMat_<_Tp>::begin() +{ + return SparseMatIterator_<_Tp>(this); +} + +template inline +SparseMatConstIterator_<_Tp> SparseMat_<_Tp>::begin() const +{ + return SparseMatConstIterator_<_Tp>(this); +} + +template inline +SparseMatIterator_<_Tp> SparseMat_<_Tp>::end() +{ + SparseMatIterator_<_Tp> it(this); + it.seekEnd(); + return it; +} + +template inline +SparseMatConstIterator_<_Tp> SparseMat_<_Tp>::end() const +{ + SparseMatConstIterator_<_Tp> it(this); + it.seekEnd(); + return it; +} + + + +////////////////////////// MatConstIterator ///////////////////////// + +inline +MatConstIterator::MatConstIterator() + : m(0), elemSize(0), ptr(0), sliceStart(0), sliceEnd(0) +{} + +inline +MatConstIterator::MatConstIterator(const Mat* _m) + : m(_m), elemSize(_m->elemSize()), ptr(0), sliceStart(0), sliceEnd(0) +{ + if( m && m->isContinuous() ) + { + CV_Assert(!m->empty()); + sliceStart = m->ptr(); + sliceEnd = sliceStart + m->total()*elemSize; + } + seek((const int*)0); +} + +inline +MatConstIterator::MatConstIterator(const Mat* _m, int _row, int _col) + : m(_m), elemSize(_m->elemSize()), ptr(0), sliceStart(0), sliceEnd(0) +{ + CV_Assert(m && m->dims <= 2); + if( m->isContinuous() ) + { + CV_Assert(!m->empty()); + sliceStart = m->ptr(); + sliceEnd = sliceStart + m->total()*elemSize; + } + int idx[] = {_row, _col}; + seek(idx); +} + +inline +MatConstIterator::MatConstIterator(const Mat* _m, Point _pt) + : m(_m), elemSize(_m->elemSize()), ptr(0), sliceStart(0), sliceEnd(0) +{ + CV_Assert(m && m->dims <= 2); + if( m->isContinuous() ) + { + CV_Assert(!m->empty()); + sliceStart = m->ptr(); + sliceEnd = sliceStart + m->total()*elemSize; + } + int idx[] = {_pt.y, _pt.x}; + seek(idx); +} + +inline +MatConstIterator::MatConstIterator(const MatConstIterator& it) + : m(it.m), elemSize(it.elemSize), ptr(it.ptr), sliceStart(it.sliceStart), sliceEnd(it.sliceEnd) +{} + +inline +MatConstIterator& MatConstIterator::operator = (const MatConstIterator& it ) +{ + m = it.m; elemSize = it.elemSize; ptr = it.ptr; + sliceStart = it.sliceStart; sliceEnd = it.sliceEnd; + return *this; +} + +inline +const uchar* MatConstIterator::operator *() const +{ + return ptr; +} + +inline MatConstIterator& MatConstIterator::operator += (ptrdiff_t ofs) +{ + if( !m || ofs == 0 ) + return *this; + ptrdiff_t ofsb = ofs*elemSize; + ptr += ofsb; + if( ptr < sliceStart || sliceEnd <= ptr ) + { + ptr -= ofsb; + seek(ofs, true); + } + return *this; +} + +inline +MatConstIterator& MatConstIterator::operator -= (ptrdiff_t ofs) +{ + return (*this += -ofs); +} + +inline +MatConstIterator& MatConstIterator::operator --() +{ + if( m && (ptr -= elemSize) < sliceStart ) + { + ptr += elemSize; + seek(-1, true); + } + return *this; +} + +inline +MatConstIterator MatConstIterator::operator --(int) +{ + MatConstIterator b = *this; + *this += -1; + return b; +} + +inline +MatConstIterator& MatConstIterator::operator ++() +{ + if( m && (ptr += elemSize) >= sliceEnd ) + { + ptr -= elemSize; + seek(1, true); + } + return *this; +} + +inline MatConstIterator MatConstIterator::operator ++(int) +{ + MatConstIterator b = *this; + *this += 1; + return b; +} + + +static inline +bool operator == (const MatConstIterator& a, const MatConstIterator& b) +{ + return a.m == b.m && a.ptr == b.ptr; +} + +static inline +bool operator != (const MatConstIterator& a, const MatConstIterator& b) +{ + return !(a == b); +} + +static inline +bool operator < (const MatConstIterator& a, const MatConstIterator& b) +{ + return a.ptr < b.ptr; +} + +static inline +bool operator > (const MatConstIterator& a, const MatConstIterator& b) +{ + return a.ptr > b.ptr; +} + +static inline +bool operator <= (const MatConstIterator& a, const MatConstIterator& b) +{ + return a.ptr <= b.ptr; +} + +static inline +bool operator >= (const MatConstIterator& a, const MatConstIterator& b) +{ + return a.ptr >= b.ptr; +} + +static inline +ptrdiff_t operator - (const MatConstIterator& b, const MatConstIterator& a) +{ + if( a.m != b.m ) + return ((size_t)(-1) >> 1); + if( a.sliceEnd == b.sliceEnd ) + return (b.ptr - a.ptr)/static_cast(b.elemSize); + + return b.lpos() - a.lpos(); +} + +static inline +MatConstIterator operator + (const MatConstIterator& a, ptrdiff_t ofs) +{ + MatConstIterator b = a; + return b += ofs; +} + +static inline +MatConstIterator operator + (ptrdiff_t ofs, const MatConstIterator& a) +{ + MatConstIterator b = a; + return b += ofs; +} + +static inline +MatConstIterator operator - (const MatConstIterator& a, ptrdiff_t ofs) +{ + MatConstIterator b = a; + return b += -ofs; +} + + +inline +const uchar* MatConstIterator::operator [](ptrdiff_t i) const +{ + return *(*this + i); +} + + + +///////////////////////// MatConstIterator_ ///////////////////////// + +template inline +MatConstIterator_<_Tp>::MatConstIterator_() +{} + +template inline +MatConstIterator_<_Tp>::MatConstIterator_(const Mat_<_Tp>* _m) + : MatConstIterator(_m) +{} + +template inline +MatConstIterator_<_Tp>::MatConstIterator_(const Mat_<_Tp>* _m, int _row, int _col) + : MatConstIterator(_m, _row, _col) +{} + +template inline +MatConstIterator_<_Tp>::MatConstIterator_(const Mat_<_Tp>* _m, Point _pt) + : MatConstIterator(_m, _pt) +{} + +template inline +MatConstIterator_<_Tp>::MatConstIterator_(const MatConstIterator_& it) + : MatConstIterator(it) +{} + +template inline +MatConstIterator_<_Tp>& MatConstIterator_<_Tp>::operator = (const MatConstIterator_& it ) +{ + MatConstIterator::operator = (it); + return *this; +} + +template inline +const _Tp& MatConstIterator_<_Tp>::operator *() const +{ + return *(_Tp*)(this->ptr); +} + +template inline +MatConstIterator_<_Tp>& MatConstIterator_<_Tp>::operator += (ptrdiff_t ofs) +{ + MatConstIterator::operator += (ofs); + return *this; +} + +template inline +MatConstIterator_<_Tp>& MatConstIterator_<_Tp>::operator -= (ptrdiff_t ofs) +{ + return (*this += -ofs); +} + +template inline +MatConstIterator_<_Tp>& MatConstIterator_<_Tp>::operator --() +{ + MatConstIterator::operator --(); + return *this; +} + +template inline +MatConstIterator_<_Tp> MatConstIterator_<_Tp>::operator --(int) +{ + MatConstIterator_ b = *this; + MatConstIterator::operator --(); + return b; +} + +template inline +MatConstIterator_<_Tp>& MatConstIterator_<_Tp>::operator ++() +{ + MatConstIterator::operator ++(); + return *this; +} + +template inline +MatConstIterator_<_Tp> MatConstIterator_<_Tp>::operator ++(int) +{ + MatConstIterator_ b = *this; + MatConstIterator::operator ++(); + return b; +} + + +template inline +Point MatConstIterator_<_Tp>::pos() const +{ + if( !m ) + return Point(); + CV_DbgAssert( m->dims <= 2 ); + if( m->isContinuous() ) + { + ptrdiff_t ofs = (const _Tp*)ptr - (const _Tp*)m->data; + int y = (int)(ofs / m->cols); + int x = (int)(ofs - (ptrdiff_t)y * m->cols); + return Point(x, y); + } + else + { + ptrdiff_t ofs = (uchar*)ptr - m->data; + int y = (int)(ofs / m->step); + int x = (int)((ofs - y * m->step)/sizeof(_Tp)); + return Point(x, y); + } +} + + +template static inline +bool operator == (const MatConstIterator_<_Tp>& a, const MatConstIterator_<_Tp>& b) +{ + return a.m == b.m && a.ptr == b.ptr; +} + +template static inline +bool operator != (const MatConstIterator_<_Tp>& a, const MatConstIterator_<_Tp>& b) +{ + return a.m != b.m || a.ptr != b.ptr; +} + +template static inline +MatConstIterator_<_Tp> operator + (const MatConstIterator_<_Tp>& a, ptrdiff_t ofs) +{ + MatConstIterator t = (const MatConstIterator&)a + ofs; + return (MatConstIterator_<_Tp>&)t; +} + +template static inline +MatConstIterator_<_Tp> operator + (ptrdiff_t ofs, const MatConstIterator_<_Tp>& a) +{ + MatConstIterator t = (const MatConstIterator&)a + ofs; + return (MatConstIterator_<_Tp>&)t; +} + +template static inline +MatConstIterator_<_Tp> operator - (const MatConstIterator_<_Tp>& a, ptrdiff_t ofs) +{ + MatConstIterator t = (const MatConstIterator&)a - ofs; + return (MatConstIterator_<_Tp>&)t; +} + +template inline +const _Tp& MatConstIterator_<_Tp>::operator [](ptrdiff_t i) const +{ + return *(_Tp*)MatConstIterator::operator [](i); +} + + + +//////////////////////////// MatIterator_ /////////////////////////// + +template inline +MatIterator_<_Tp>::MatIterator_() + : MatConstIterator_<_Tp>() +{} + +template inline +MatIterator_<_Tp>::MatIterator_(Mat_<_Tp>* _m) + : MatConstIterator_<_Tp>(_m) +{} + +template inline +MatIterator_<_Tp>::MatIterator_(Mat_<_Tp>* _m, int _row, int _col) + : MatConstIterator_<_Tp>(_m, _row, _col) +{} + +template inline +MatIterator_<_Tp>::MatIterator_(Mat_<_Tp>* _m, Point _pt) + : MatConstIterator_<_Tp>(_m, _pt) +{} + +template inline +MatIterator_<_Tp>::MatIterator_(Mat_<_Tp>* _m, const int* _idx) + : MatConstIterator_<_Tp>(_m, _idx) +{} + +template inline +MatIterator_<_Tp>::MatIterator_(const MatIterator_& it) + : MatConstIterator_<_Tp>(it) +{} + +template inline +MatIterator_<_Tp>& MatIterator_<_Tp>::operator = (const MatIterator_<_Tp>& it ) +{ + MatConstIterator::operator = (it); + return *this; +} + +template inline +_Tp& MatIterator_<_Tp>::operator *() const +{ + return *(_Tp*)(this->ptr); +} + +template inline +MatIterator_<_Tp>& MatIterator_<_Tp>::operator += (ptrdiff_t ofs) +{ + MatConstIterator::operator += (ofs); + return *this; +} + +template inline +MatIterator_<_Tp>& MatIterator_<_Tp>::operator -= (ptrdiff_t ofs) +{ + MatConstIterator::operator += (-ofs); + return *this; +} + +template inline +MatIterator_<_Tp>& MatIterator_<_Tp>::operator --() +{ + MatConstIterator::operator --(); + return *this; +} + +template inline +MatIterator_<_Tp> MatIterator_<_Tp>::operator --(int) +{ + MatIterator_ b = *this; + MatConstIterator::operator --(); + return b; +} + +template inline +MatIterator_<_Tp>& MatIterator_<_Tp>::operator ++() +{ + MatConstIterator::operator ++(); + return *this; +} + +template inline +MatIterator_<_Tp> MatIterator_<_Tp>::operator ++(int) +{ + MatIterator_ b = *this; + MatConstIterator::operator ++(); + return b; +} + +template inline +_Tp& MatIterator_<_Tp>::operator [](ptrdiff_t i) const +{ + return *(*this + i); +} + + +template static inline +bool operator == (const MatIterator_<_Tp>& a, const MatIterator_<_Tp>& b) +{ + return a.m == b.m && a.ptr == b.ptr; +} + +template static inline +bool operator != (const MatIterator_<_Tp>& a, const MatIterator_<_Tp>& b) +{ + return a.m != b.m || a.ptr != b.ptr; +} + +template static inline +MatIterator_<_Tp> operator + (const MatIterator_<_Tp>& a, ptrdiff_t ofs) +{ + MatConstIterator t = (const MatConstIterator&)a + ofs; + return (MatIterator_<_Tp>&)t; +} + +template static inline +MatIterator_<_Tp> operator + (ptrdiff_t ofs, const MatIterator_<_Tp>& a) +{ + MatConstIterator t = (const MatConstIterator&)a + ofs; + return (MatIterator_<_Tp>&)t; +} + +template static inline +MatIterator_<_Tp> operator - (const MatIterator_<_Tp>& a, ptrdiff_t ofs) +{ + MatConstIterator t = (const MatConstIterator&)a - ofs; + return (MatIterator_<_Tp>&)t; +} + + + +/////////////////////// SparseMatConstIterator ////////////////////// + +inline +SparseMatConstIterator::SparseMatConstIterator() + : m(0), hashidx(0), ptr(0) +{} + +inline +SparseMatConstIterator::SparseMatConstIterator(const SparseMatConstIterator& it) + : m(it.m), hashidx(it.hashidx), ptr(it.ptr) +{} + +inline SparseMatConstIterator& SparseMatConstIterator::operator = (const SparseMatConstIterator& it) +{ + if( this != &it ) + { + m = it.m; + hashidx = it.hashidx; + ptr = it.ptr; + } + return *this; +} + +template inline +const _Tp& SparseMatConstIterator::value() const +{ + return *(const _Tp*)ptr; +} + +inline +const SparseMat::Node* SparseMatConstIterator::node() const +{ + return (ptr && m && m->hdr) ? (const SparseMat::Node*)(const void*)(ptr - m->hdr->valueOffset) : 0; +} + +inline +SparseMatConstIterator SparseMatConstIterator::operator ++(int) +{ + SparseMatConstIterator it = *this; + ++*this; + return it; +} + +inline +void SparseMatConstIterator::seekEnd() +{ + if( m && m->hdr ) + { + hashidx = m->hdr->hashtab.size(); + ptr = 0; + } +} + + +static inline +bool operator == (const SparseMatConstIterator& it1, const SparseMatConstIterator& it2) +{ + return it1.m == it2.m && it1.ptr == it2.ptr; +} + +static inline +bool operator != (const SparseMatConstIterator& it1, const SparseMatConstIterator& it2) +{ + return !(it1 == it2); +} + + + +///////////////////////// SparseMatIterator ///////////////////////// + +inline +SparseMatIterator::SparseMatIterator() +{} + +inline +SparseMatIterator::SparseMatIterator(SparseMat* _m) + : SparseMatConstIterator(_m) +{} + +inline +SparseMatIterator::SparseMatIterator(const SparseMatIterator& it) + : SparseMatConstIterator(it) +{} + +inline +SparseMatIterator& SparseMatIterator::operator = (const SparseMatIterator& it) +{ + (SparseMatConstIterator&)*this = it; + return *this; +} + +template inline +_Tp& SparseMatIterator::value() const +{ + return *(_Tp*)ptr; +} + +inline +SparseMat::Node* SparseMatIterator::node() const +{ + return (SparseMat::Node*)SparseMatConstIterator::node(); +} + +inline +SparseMatIterator& SparseMatIterator::operator ++() +{ + SparseMatConstIterator::operator ++(); + return *this; +} + +inline +SparseMatIterator SparseMatIterator::operator ++(int) +{ + SparseMatIterator it = *this; + ++*this; + return it; +} + + + +////////////////////// SparseMatConstIterator_ ////////////////////// + +template inline +SparseMatConstIterator_<_Tp>::SparseMatConstIterator_() +{} + +template inline +SparseMatConstIterator_<_Tp>::SparseMatConstIterator_(const SparseMat_<_Tp>* _m) + : SparseMatConstIterator(_m) +{} + +template inline +SparseMatConstIterator_<_Tp>::SparseMatConstIterator_(const SparseMat* _m) + : SparseMatConstIterator(_m) +{ + CV_Assert( _m->type() == traits::Type<_Tp>::value ); +} + +template inline +SparseMatConstIterator_<_Tp>::SparseMatConstIterator_(const SparseMatConstIterator_<_Tp>& it) + : SparseMatConstIterator(it) +{} + +template inline +SparseMatConstIterator_<_Tp>& SparseMatConstIterator_<_Tp>::operator = (const SparseMatConstIterator_<_Tp>& it) +{ + return reinterpret_cast&> + (*reinterpret_cast(this) = + reinterpret_cast(it)); +} + +template inline +const _Tp& SparseMatConstIterator_<_Tp>::operator *() const +{ + return *(const _Tp*)this->ptr; +} + +template inline +SparseMatConstIterator_<_Tp>& SparseMatConstIterator_<_Tp>::operator ++() +{ + SparseMatConstIterator::operator ++(); + return *this; +} + +template inline +SparseMatConstIterator_<_Tp> SparseMatConstIterator_<_Tp>::operator ++(int) +{ + SparseMatConstIterator_<_Tp> it = *this; + SparseMatConstIterator::operator ++(); + return it; +} + + + +///////////////////////// SparseMatIterator_ //////////////////////// + +template inline +SparseMatIterator_<_Tp>::SparseMatIterator_() +{} + +template inline +SparseMatIterator_<_Tp>::SparseMatIterator_(SparseMat_<_Tp>* _m) + : SparseMatConstIterator_<_Tp>(_m) +{} + +template inline +SparseMatIterator_<_Tp>::SparseMatIterator_(SparseMat* _m) + : SparseMatConstIterator_<_Tp>(_m) +{} + +template inline +SparseMatIterator_<_Tp>::SparseMatIterator_(const SparseMatIterator_<_Tp>& it) + : SparseMatConstIterator_<_Tp>(it) +{} + +template inline +SparseMatIterator_<_Tp>& SparseMatIterator_<_Tp>::operator = (const SparseMatIterator_<_Tp>& it) +{ + return reinterpret_cast&> + (*reinterpret_cast(this) = + reinterpret_cast(it)); +} + +template inline +_Tp& SparseMatIterator_<_Tp>::operator *() const +{ + return *(_Tp*)this->ptr; +} + +template inline +SparseMatIterator_<_Tp>& SparseMatIterator_<_Tp>::operator ++() +{ + SparseMatConstIterator::operator ++(); + return *this; +} + +template inline +SparseMatIterator_<_Tp> SparseMatIterator_<_Tp>::operator ++(int) +{ + SparseMatIterator_<_Tp> it = *this; + SparseMatConstIterator::operator ++(); + return it; +} + + + +//////////////////////// MatCommaInitializer_ /////////////////////// + +template inline +MatCommaInitializer_<_Tp>::MatCommaInitializer_(Mat_<_Tp>* _m) + : it(_m) +{} + +template template inline +MatCommaInitializer_<_Tp>& MatCommaInitializer_<_Tp>::operator , (T2 v) +{ + CV_DbgAssert( this->it < ((const Mat_<_Tp>*)this->it.m)->end() ); + *this->it = _Tp(v); + ++this->it; + return *this; +} + +template inline +MatCommaInitializer_<_Tp>::operator Mat_<_Tp>() const +{ + CV_DbgAssert( this->it == ((const Mat_<_Tp>*)this->it.m)->end() ); + return Mat_<_Tp>(*this->it.m); +} + + +template static inline +MatCommaInitializer_<_Tp> operator << (const Mat_<_Tp>& m, T2 val) +{ + MatCommaInitializer_<_Tp> commaInitializer((Mat_<_Tp>*)&m); + return (commaInitializer, val); +} + + + +///////////////////////// Matrix Expressions //////////////////////// + +inline +Mat& Mat::operator = (const MatExpr& e) +{ + e.op->assign(e, *this); + return *this; +} + +template inline +Mat_<_Tp>::Mat_(const MatExpr& e) +{ + e.op->assign(e, *this, traits::Type<_Tp>::value); +} + +template inline +Mat_<_Tp>& Mat_<_Tp>::operator = (const MatExpr& e) +{ + e.op->assign(e, *this, traits::Type<_Tp>::value); + return *this; +} + +template inline +MatExpr Mat_<_Tp>::zeros(int rows, int cols) +{ + return Mat::zeros(rows, cols, traits::Type<_Tp>::value); +} + +template inline +MatExpr Mat_<_Tp>::zeros(Size sz) +{ + return Mat::zeros(sz, traits::Type<_Tp>::value); +} + +template inline +MatExpr Mat_<_Tp>::ones(int rows, int cols) +{ + return Mat::ones(rows, cols, traits::Type<_Tp>::value); +} + +template inline +MatExpr Mat_<_Tp>::ones(Size sz) +{ + return Mat::ones(sz, traits::Type<_Tp>::value); +} + +template inline +MatExpr Mat_<_Tp>::eye(int rows, int cols) +{ + return Mat::eye(rows, cols, traits::Type<_Tp>::value); +} + +template inline +MatExpr Mat_<_Tp>::eye(Size sz) +{ + return Mat::eye(sz, traits::Type<_Tp>::value); +} + +inline +MatExpr::MatExpr() + : op(0), flags(0), a(Mat()), b(Mat()), c(Mat()), alpha(0), beta(0), s() +{} + +inline +MatExpr::MatExpr(const MatOp* _op, int _flags, const Mat& _a, const Mat& _b, + const Mat& _c, double _alpha, double _beta, const Scalar& _s) + : op(_op), flags(_flags), a(_a), b(_b), c(_c), alpha(_alpha), beta(_beta), s(_s) +{} + +inline +MatExpr::operator Mat() const +{ + Mat m; + op->assign(*this, m); + return m; +} + +template inline +MatExpr::operator Mat_<_Tp>() const +{ + Mat_<_Tp> m; + op->assign(*this, m, traits::Type<_Tp>::value); + return m; +} + + +template static inline +MatExpr min(const Mat_<_Tp>& a, const Mat_<_Tp>& b) +{ + return cv::min((const Mat&)a, (const Mat&)b); +} + +template static inline +MatExpr min(const Mat_<_Tp>& a, double s) +{ + return cv::min((const Mat&)a, s); +} + +template static inline +MatExpr min(double s, const Mat_<_Tp>& a) +{ + return cv::min((const Mat&)a, s); +} + +template static inline +MatExpr max(const Mat_<_Tp>& a, const Mat_<_Tp>& b) +{ + return cv::max((const Mat&)a, (const Mat&)b); +} + +template static inline +MatExpr max(const Mat_<_Tp>& a, double s) +{ + return cv::max((const Mat&)a, s); +} + +template static inline +MatExpr max(double s, const Mat_<_Tp>& a) +{ + return cv::max((const Mat&)a, s); +} + +template static inline +MatExpr abs(const Mat_<_Tp>& m) +{ + return cv::abs((const Mat&)m); +} + + +static inline +Mat& operator += (Mat& a, const MatExpr& b) +{ + b.op->augAssignAdd(b, a); + return a; +} + +static inline +const Mat& operator += (const Mat& a, const MatExpr& b) +{ + b.op->augAssignAdd(b, (Mat&)a); + return a; +} + +template static inline +Mat_<_Tp>& operator += (Mat_<_Tp>& a, const MatExpr& b) +{ + b.op->augAssignAdd(b, a); + return a; +} + +template static inline +const Mat_<_Tp>& operator += (const Mat_<_Tp>& a, const MatExpr& b) +{ + b.op->augAssignAdd(b, (Mat&)a); + return a; +} + +static inline +Mat& operator -= (Mat& a, const MatExpr& b) +{ + b.op->augAssignSubtract(b, a); + return a; +} + +static inline +const Mat& operator -= (const Mat& a, const MatExpr& b) +{ + b.op->augAssignSubtract(b, (Mat&)a); + return a; +} + +template static inline +Mat_<_Tp>& operator -= (Mat_<_Tp>& a, const MatExpr& b) +{ + b.op->augAssignSubtract(b, a); + return a; +} + +template static inline +const Mat_<_Tp>& operator -= (const Mat_<_Tp>& a, const MatExpr& b) +{ + b.op->augAssignSubtract(b, (Mat&)a); + return a; +} + +static inline +Mat& operator *= (Mat& a, const MatExpr& b) +{ + b.op->augAssignMultiply(b, a); + return a; +} + +static inline +const Mat& operator *= (const Mat& a, const MatExpr& b) +{ + b.op->augAssignMultiply(b, (Mat&)a); + return a; +} + +template static inline +Mat_<_Tp>& operator *= (Mat_<_Tp>& a, const MatExpr& b) +{ + b.op->augAssignMultiply(b, a); + return a; +} + +template static inline +const Mat_<_Tp>& operator *= (const Mat_<_Tp>& a, const MatExpr& b) +{ + b.op->augAssignMultiply(b, (Mat&)a); + return a; +} + +static inline +Mat& operator /= (Mat& a, const MatExpr& b) +{ + b.op->augAssignDivide(b, a); + return a; +} + +static inline +const Mat& operator /= (const Mat& a, const MatExpr& b) +{ + b.op->augAssignDivide(b, (Mat&)a); + return a; +} + +template static inline +Mat_<_Tp>& operator /= (Mat_<_Tp>& a, const MatExpr& b) +{ + b.op->augAssignDivide(b, a); + return a; +} + +template static inline +const Mat_<_Tp>& operator /= (const Mat_<_Tp>& a, const MatExpr& b) +{ + b.op->augAssignDivide(b, (Mat&)a); + return a; +} + + +//////////////////////////////// UMat //////////////////////////////// + +template inline +UMat::UMat(const std::vector<_Tp>& vec, bool copyData) +: flags(MAGIC_VAL + traits::Type<_Tp>::value + CV_MAT_CONT_FLAG), dims(2), rows((int)vec.size()), +cols(1), allocator(0), usageFlags(USAGE_DEFAULT), u(0), offset(0), size(&rows) +{ + if(vec.empty()) + return; + if( !copyData ) + { + // !!!TODO!!! + CV_Error(Error::StsNotImplemented, ""); + } + else + Mat((int)vec.size(), 1, traits::Type<_Tp>::value, (uchar*)&vec[0]).copyTo(*this); +} + +inline +UMat UMat::row(int y) const +{ + return UMat(*this, Range(y, y + 1), Range::all()); +} + +inline +UMat UMat::col(int x) const +{ + return UMat(*this, Range::all(), Range(x, x + 1)); +} + +inline +UMat UMat::rowRange(int startrow, int endrow) const +{ + return UMat(*this, Range(startrow, endrow), Range::all()); +} + +inline +UMat UMat::rowRange(const Range& r) const +{ + return UMat(*this, r, Range::all()); +} + +inline +UMat UMat::colRange(int startcol, int endcol) const +{ + return UMat(*this, Range::all(), Range(startcol, endcol)); +} + +inline +UMat UMat::colRange(const Range& r) const +{ + return UMat(*this, Range::all(), r); +} + +inline +UMat UMat::operator()( Range _rowRange, Range _colRange ) const +{ + return UMat(*this, _rowRange, _colRange); +} + +inline +UMat UMat::operator()( const Rect& roi ) const +{ + return UMat(*this, roi); +} + +inline +UMat UMat::operator()(const Range* ranges) const +{ + return UMat(*this, ranges); +} + +inline +UMat UMat::operator()(const std::vector& ranges) const +{ + return UMat(*this, ranges); +} + +inline +bool UMat::isContinuous() const +{ + return (flags & CONTINUOUS_FLAG) != 0; +} + +inline +bool UMat::isSubmatrix() const +{ + return (flags & SUBMATRIX_FLAG) != 0; +} + +inline +size_t UMat::elemSize() const +{ + size_t res = dims > 0 ? step.p[dims - 1] : 0; + CV_DbgAssert(res != 0); + return res; +} + +inline +size_t UMat::elemSize1() const +{ + return CV_ELEM_SIZE1(flags); +} + +inline +int UMat::type() const +{ + return CV_MAT_TYPE(flags); +} + +inline +int UMat::depth() const +{ + return CV_MAT_DEPTH(flags); +} + +inline +int UMat::channels() const +{ + return CV_MAT_CN(flags); +} + +inline +size_t UMat::step1(int i) const +{ + return step.p[i] / elemSize1(); +} + + +inline bool UMatData::hostCopyObsolete() const { return (flags & HOST_COPY_OBSOLETE) != 0; } +inline bool UMatData::deviceCopyObsolete() const { return (flags & DEVICE_COPY_OBSOLETE) != 0; } +inline bool UMatData::deviceMemMapped() const { return (flags & DEVICE_MEM_MAPPED) != 0; } +inline bool UMatData::copyOnMap() const { return (flags & COPY_ON_MAP) != 0; } +inline bool UMatData::tempUMat() const { return (flags & TEMP_UMAT) != 0; } +inline bool UMatData::tempCopiedUMat() const { return (flags & TEMP_COPIED_UMAT) == TEMP_COPIED_UMAT; } + +inline void UMatData::markDeviceMemMapped(bool flag) +{ + if(flag) + flags |= DEVICE_MEM_MAPPED; + else + flags &= ~DEVICE_MEM_MAPPED; +} + +inline void UMatData::markHostCopyObsolete(bool flag) +{ + if(flag) + flags |= HOST_COPY_OBSOLETE; + else + flags &= ~HOST_COPY_OBSOLETE; +} +inline void UMatData::markDeviceCopyObsolete(bool flag) +{ + if(flag) + flags |= DEVICE_COPY_OBSOLETE; + else + flags &= ~DEVICE_COPY_OBSOLETE; +} + +//! @endcond + +static inline +void swap(MatExpr& a, MatExpr& b) { a.swap(b); } + +} //cv + +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + +#ifdef CV_DISABLE_CLANG_ENUM_WARNINGS +#undef CV_DISABLE_CLANG_ENUM_WARNINGS +#pragma clang diagnostic pop +#endif + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/matx.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/matx.hpp new file mode 100644 index 0000000..162ce6e --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/matx.hpp @@ -0,0 +1,1528 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_MATX_HPP +#define OPENCV_CORE_MATX_HPP + +#ifndef __cplusplus +# error matx.hpp header must be compiled as C++ +#endif + +#include "opencv2/core/cvdef.h" +#include "opencv2/core/base.hpp" +#include "opencv2/core/traits.hpp" +#include "opencv2/core/saturate.hpp" + +#include + +namespace cv +{ + +//! @addtogroup core_basic +//! @{ + +////////////////////////////// Small Matrix /////////////////////////// + +//! @cond IGNORED +// FIXIT Remove this (especially CV_EXPORTS modifier) +struct CV_EXPORTS Matx_AddOp { Matx_AddOp() {} Matx_AddOp(const Matx_AddOp&) {} }; +struct CV_EXPORTS Matx_SubOp { Matx_SubOp() {} Matx_SubOp(const Matx_SubOp&) {} }; +struct CV_EXPORTS Matx_ScaleOp { Matx_ScaleOp() {} Matx_ScaleOp(const Matx_ScaleOp&) {} }; +struct CV_EXPORTS Matx_MulOp { Matx_MulOp() {} Matx_MulOp(const Matx_MulOp&) {} }; +struct CV_EXPORTS Matx_DivOp { Matx_DivOp() {} Matx_DivOp(const Matx_DivOp&) {} }; +struct CV_EXPORTS Matx_MatMulOp { Matx_MatMulOp() {} Matx_MatMulOp(const Matx_MatMulOp&) {} }; +struct CV_EXPORTS Matx_TOp { Matx_TOp() {} Matx_TOp(const Matx_TOp&) {} }; +//! @endcond + +/** @brief Template class for small matrices whose type and size are known at compilation time + +If you need a more flexible type, use Mat . The elements of the matrix M are accessible using the +M(i,j) notation. Most of the common matrix operations (see also @ref MatrixExpressions ) are +available. To do an operation on Matx that is not implemented, you can easily convert the matrix to +Mat and backwards: +@code{.cpp} + Matx33f m(1, 2, 3, + 4, 5, 6, + 7, 8, 9); + cout << sum(Mat(m*m.t())) << endl; +@endcode +Except of the plain constructor which takes a list of elements, Matx can be initialized from a C-array: +@code{.cpp} + float values[] = { 1, 2, 3}; + Matx31f m(values); +@endcode +In case if C++11 features are available, std::initializer_list can be also used to initialize Matx: +@code{.cpp} + Matx31f m = { 1, 2, 3}; +@endcode + */ +template class Matx +{ +public: + enum { + rows = m, + cols = n, + channels = rows*cols, +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + depth = traits::Type<_Tp>::value, + type = CV_MAKETYPE(depth, channels), +#endif + shortdim = (m < n ? m : n) + }; + + typedef _Tp value_type; + typedef Matx<_Tp, m, n> mat_type; + typedef Matx<_Tp, shortdim, 1> diag_type; + + //! default constructor + Matx(); + + explicit Matx(_Tp v0); //!< 1x1 matrix + Matx(_Tp v0, _Tp v1); //!< 1x2 or 2x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2); //!< 1x3 or 3x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3); //!< 1x4, 2x2 or 4x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4); //!< 1x5 or 5x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5); //!< 1x6, 2x3, 3x2 or 6x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6); //!< 1x7 or 7x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7); //!< 1x8, 2x4, 4x2 or 8x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8); //!< 1x9, 3x3 or 9x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9); //!< 1x10, 2x5 or 5x2 or 10x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, + _Tp v4, _Tp v5, _Tp v6, _Tp v7, + _Tp v8, _Tp v9, _Tp v10, _Tp v11); //!< 1x12, 2x6, 3x4, 4x3, 6x2 or 12x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, + _Tp v4, _Tp v5, _Tp v6, _Tp v7, + _Tp v8, _Tp v9, _Tp v10, _Tp v11, + _Tp v12, _Tp v13); //!< 1x14, 2x7, 7x2 or 14x1 matrix + Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, + _Tp v4, _Tp v5, _Tp v6, _Tp v7, + _Tp v8, _Tp v9, _Tp v10, _Tp v11, + _Tp v12, _Tp v13, _Tp v14, _Tp v15); //!< 1x16, 4x4 or 16x1 matrix + explicit Matx(const _Tp* vals); //!< initialize from a plain array + + Matx(std::initializer_list<_Tp>); //!< initialize from an initializer list + + CV_NODISCARD_STD static Matx all(_Tp alpha); + CV_NODISCARD_STD static Matx zeros(); + CV_NODISCARD_STD static Matx ones(); + CV_NODISCARD_STD static Matx eye(); + CV_NODISCARD_STD static Matx diag(const diag_type& d); + /** @brief Generates uniformly distributed random numbers + @param a Range boundary. + @param b The other range boundary (boundaries don't have to be ordered, the lower boundary is inclusive, + the upper one is exclusive). + */ + CV_NODISCARD_STD static Matx randu(_Tp a, _Tp b); + /** @brief Generates normally distributed random numbers + @param a Mean value. + @param b Standard deviation. + */ + CV_NODISCARD_STD static Matx randn(_Tp a, _Tp b); + + //! dot product computed with the default precision + _Tp dot(const Matx<_Tp, m, n>& v) const; + + //! dot product computed in double-precision arithmetics + double ddot(const Matx<_Tp, m, n>& v) const; + + //! conversion to another data type + template operator Matx() const; + + //! change the matrix shape + template Matx<_Tp, m1, n1> reshape() const; + + //! extract part of the matrix + template Matx<_Tp, m1, n1> get_minor(int base_row, int base_col) const; + + //! extract the matrix row + Matx<_Tp, 1, n> row(int i) const; + + //! extract the matrix column + Matx<_Tp, m, 1> col(int i) const; + + //! extract the matrix diagonal + diag_type diag() const; + + //! transpose the matrix + Matx<_Tp, n, m> t() const; + + //! invert the matrix + Matx<_Tp, n, m> inv(int method=DECOMP_LU, bool *p_is_ok = NULL) const; + + //! solve linear system + template Matx<_Tp, n, l> solve(const Matx<_Tp, m, l>& rhs, int flags=DECOMP_LU) const; + Vec<_Tp, n> solve(const Vec<_Tp, m>& rhs, int method) const; + + //! multiply two matrices element-wise + Matx<_Tp, m, n> mul(const Matx<_Tp, m, n>& a) const; + + //! divide two matrices element-wise + Matx<_Tp, m, n> div(const Matx<_Tp, m, n>& a) const; + + //! element access + const _Tp& operator ()(int row, int col) const; + _Tp& operator ()(int row, int col); + + //! 1D element access + const _Tp& operator ()(int i) const; + _Tp& operator ()(int i); + + Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_AddOp); + Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_SubOp); + template Matx(const Matx<_Tp, m, n>& a, _T2 alpha, Matx_ScaleOp); + Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_MulOp); + Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_DivOp); + template Matx(const Matx<_Tp, m, l>& a, const Matx<_Tp, l, n>& b, Matx_MatMulOp); + Matx(const Matx<_Tp, n, m>& a, Matx_TOp); + + _Tp val[m*n]; //< matrix elements +}; + +typedef Matx Matx12f; +typedef Matx Matx12d; +typedef Matx Matx13f; +typedef Matx Matx13d; +typedef Matx Matx14f; +typedef Matx Matx14d; +typedef Matx Matx16f; +typedef Matx Matx16d; + +typedef Matx Matx21f; +typedef Matx Matx21d; +typedef Matx Matx31f; +typedef Matx Matx31d; +typedef Matx Matx41f; +typedef Matx Matx41d; +typedef Matx Matx61f; +typedef Matx Matx61d; + +typedef Matx Matx22f; +typedef Matx Matx22d; +typedef Matx Matx23f; +typedef Matx Matx23d; +typedef Matx Matx32f; +typedef Matx Matx32d; + +typedef Matx Matx33f; +typedef Matx Matx33d; + +typedef Matx Matx34f; +typedef Matx Matx34d; +typedef Matx Matx43f; +typedef Matx Matx43d; + +typedef Matx Matx44f; +typedef Matx Matx44d; +typedef Matx Matx66f; +typedef Matx Matx66d; + +/*! + traits +*/ +template class DataType< Matx<_Tp, m, n> > +{ +public: + typedef Matx<_Tp, m, n> value_type; + typedef Matx::work_type, m, n> work_type; + typedef _Tp channel_type; + typedef value_type vec_type; + + enum { generic_type = 0, + channels = m * n, + fmt = traits::SafeFmt::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif + }; +}; + +namespace traits { +template +struct Depth< Matx<_Tp, m, n> > { enum { value = Depth<_Tp>::value }; }; +template +struct Type< Matx<_Tp, m, n> > { enum { value = CV_MAKETYPE(Depth<_Tp>::value, n*m) }; }; +} // namespace + + +/** @brief Comma-separated Matrix Initializer +*/ +template class MatxCommaInitializer +{ +public: + MatxCommaInitializer(Matx<_Tp, m, n>* _mtx); + template MatxCommaInitializer<_Tp, m, n>& operator , (T2 val); + Matx<_Tp, m, n> operator *() const; + + Matx<_Tp, m, n>* dst; + int idx; +}; + +/* + Utility methods +*/ +template static double determinant(const Matx<_Tp, m, m>& a); +template static double trace(const Matx<_Tp, m, n>& a); +template static double norm(const Matx<_Tp, m, n>& M); +template static double norm(const Matx<_Tp, m, n>& M, int normType); + + + +/////////////////////// Vec (used as element of multi-channel images ///////////////////// + +/** @brief Template class for short numerical vectors, a partial case of Matx + +This template class represents short numerical vectors (of 1, 2, 3, 4 ... elements) on which you +can perform basic arithmetical operations, access individual elements using [] operator etc. The +vectors are allocated on stack, as opposite to std::valarray, std::vector, cv::Mat etc., which +elements are dynamically allocated in the heap. + +The template takes 2 parameters: +@tparam _Tp element type +@tparam cn the number of elements + +In addition to the universal notation like Vec, you can use shorter aliases +for the most popular specialized variants of Vec, e.g. Vec3f ~ Vec. + +It is possible to convert Vec\ to/from Point_, Vec\ to/from Point3_ , and Vec\ +to CvScalar or Scalar_. Use operator[] to access the elements of Vec. + +All the expected vector operations are also implemented: +- v1 = v2 + v3 +- v1 = v2 - v3 +- v1 = v2 \* scale +- v1 = scale \* v2 +- v1 = -v2 +- v1 += v2 and other augmenting operations +- v1 == v2, v1 != v2 +- norm(v1) (euclidean norm) +The Vec class is commonly used to describe pixel types of multi-channel arrays. See Mat for details. +*/ +template class Vec : public Matx<_Tp, cn, 1> +{ +public: + typedef _Tp value_type; + enum { + channels = cn, +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + depth = Matx<_Tp, cn, 1>::depth, + type = CV_MAKETYPE(depth, channels), +#endif + _dummy_enum_finalizer = 0 + }; + + //! default constructor + Vec(); + + Vec(_Tp v0); //!< 1-element vector constructor + Vec(_Tp v0, _Tp v1); //!< 2-element vector constructor + Vec(_Tp v0, _Tp v1, _Tp v2); //!< 3-element vector constructor + Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3); //!< 4-element vector constructor + Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4); //!< 5-element vector constructor + Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5); //!< 6-element vector constructor + Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6); //!< 7-element vector constructor + Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7); //!< 8-element vector constructor + Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8); //!< 9-element vector constructor + Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9); //!< 10-element vector constructor + Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9, _Tp v10, _Tp v11, _Tp v12, _Tp v13); //!< 14-element vector constructor + explicit Vec(const _Tp* values); + + Vec(std::initializer_list<_Tp>); + + Vec(const Vec<_Tp, cn>& v); + + static Vec all(_Tp alpha); + static Vec ones(); + static Vec randn(_Tp a, _Tp b); + static Vec randu(_Tp a, _Tp b); + static Vec zeros(); +#ifdef CV_CXX11 + static Vec diag(_Tp alpha) = delete; + static Vec eye() = delete; +#endif + + //! per-element multiplication + Vec mul(const Vec<_Tp, cn>& v) const; + + //! conjugation (makes sense for complex numbers and quaternions) + Vec conj() const; + + /*! + cross product of the two 3D vectors. + + For other dimensionalities the exception is raised + */ + Vec cross(const Vec& v) const; + //! conversion to another data type + template operator Vec() const; + + /*! element access */ + const _Tp& operator [](int i) const; + _Tp& operator[](int i); + const _Tp& operator ()(int i) const; + _Tp& operator ()(int i); + +#ifdef CV_CXX11 + Vec<_Tp, cn>& operator=(const Vec<_Tp, cn>& rhs) = default; +#endif + + Vec(const Matx<_Tp, cn, 1>& a, const Matx<_Tp, cn, 1>& b, Matx_AddOp); + Vec(const Matx<_Tp, cn, 1>& a, const Matx<_Tp, cn, 1>& b, Matx_SubOp); + template Vec(const Matx<_Tp, cn, 1>& a, _T2 alpha, Matx_ScaleOp); +}; + +/** @name Shorter aliases for the most popular specializations of Vec + @{ +*/ +typedef Vec Vec2b; +typedef Vec Vec3b; +typedef Vec Vec4b; + +typedef Vec Vec2s; +typedef Vec Vec3s; +typedef Vec Vec4s; + +typedef Vec Vec2w; +typedef Vec Vec3w; +typedef Vec Vec4w; + +typedef Vec Vec2i; +typedef Vec Vec3i; +typedef Vec Vec4i; +typedef Vec Vec6i; +typedef Vec Vec8i; + +typedef Vec Vec2f; +typedef Vec Vec3f; +typedef Vec Vec4f; +typedef Vec Vec6f; + +typedef Vec Vec2d; +typedef Vec Vec3d; +typedef Vec Vec4d; +typedef Vec Vec6d; +/** @} */ + +/*! + traits +*/ +template class DataType< Vec<_Tp, cn> > +{ +public: + typedef Vec<_Tp, cn> value_type; + typedef Vec::work_type, cn> work_type; + typedef _Tp channel_type; + typedef value_type vec_type; + + enum { generic_type = 0, + channels = cn, + fmt = DataType::fmt + ((channels - 1) << 8), +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + depth = DataType::depth, + type = CV_MAKETYPE(depth, channels), +#endif + _dummy_enum_finalizer = 0 + }; +}; + +namespace traits { +template +struct Depth< Vec<_Tp, cn> > { enum { value = Depth<_Tp>::value }; }; +template +struct Type< Vec<_Tp, cn> > { enum { value = CV_MAKETYPE(Depth<_Tp>::value, cn) }; }; +} // namespace + + +/** @brief Comma-separated Vec Initializer +*/ +template class VecCommaInitializer : public MatxCommaInitializer<_Tp, m, 1> +{ +public: + VecCommaInitializer(Vec<_Tp, m>* _vec); + template VecCommaInitializer<_Tp, m>& operator , (T2 val); + Vec<_Tp, m> operator *() const; +}; + +template static Vec<_Tp, cn> normalize(const Vec<_Tp, cn>& v); + +//! @} core_basic + +//! @cond IGNORED + +///////////////////////////////////// helper classes ///////////////////////////////////// +namespace internal +{ + +template struct Matx_DetOp +{ + double operator ()(const Matx<_Tp, m, m>& a) const + { + Matx<_Tp, m, m> temp = a; + double p = LU(temp.val, m*sizeof(_Tp), m, 0, 0, 0); + if( p == 0 ) + return p; + for( int i = 0; i < m; i++ ) + p *= temp(i, i); + return p; + } +}; + +template struct Matx_DetOp<_Tp, 1> +{ + double operator ()(const Matx<_Tp, 1, 1>& a) const + { + return a(0,0); + } +}; + +template struct Matx_DetOp<_Tp, 2> +{ + double operator ()(const Matx<_Tp, 2, 2>& a) const + { + return a(0,0)*a(1,1) - a(0,1)*a(1,0); + } +}; + +template struct Matx_DetOp<_Tp, 3> +{ + double operator ()(const Matx<_Tp, 3, 3>& a) const + { + return a(0,0)*(a(1,1)*a(2,2) - a(2,1)*a(1,2)) - + a(0,1)*(a(1,0)*a(2,2) - a(2,0)*a(1,2)) + + a(0,2)*(a(1,0)*a(2,1) - a(2,0)*a(1,1)); + } +}; + +template Vec<_Tp, 2> inline conjugate(const Vec<_Tp, 2>& v) +{ + return Vec<_Tp, 2>(v[0], -v[1]); +} + +template Vec<_Tp, 4> inline conjugate(const Vec<_Tp, 4>& v) +{ + return Vec<_Tp, 4>(v[0], -v[1], -v[2], -v[3]); +} + +} // internal + + + +////////////////////////////////// Matx Implementation /////////////////////////////////// + +template inline +Matx<_Tp, m, n>::Matx() +{ + for(int i = 0; i < channels; i++) val[i] = _Tp(0); +} + +template inline +Matx<_Tp, m, n>::Matx(_Tp v0) +{ + val[0] = v0; + for(int i = 1; i < channels; i++) val[i] = _Tp(0); +} + +template inline +Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1) +{ + CV_StaticAssert(channels >= 2, "Matx should have at least 2 elements."); + val[0] = v0; val[1] = v1; + for(int i = 2; i < channels; i++) val[i] = _Tp(0); +} + +template inline +Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2) +{ + CV_StaticAssert(channels >= 3, "Matx should have at least 3 elements."); + val[0] = v0; val[1] = v1; val[2] = v2; + for(int i = 3; i < channels; i++) val[i] = _Tp(0); +} + +template inline +Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3) +{ + CV_StaticAssert(channels >= 4, "Matx should have at least 4 elements."); + val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; + for(int i = 4; i < channels; i++) val[i] = _Tp(0); +} + +template inline +Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4) +{ + CV_StaticAssert(channels >= 5, "Matx should have at least 5 elements."); + val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4; + for(int i = 5; i < channels; i++) val[i] = _Tp(0); +} + +template inline +Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5) +{ + CV_StaticAssert(channels >= 6, "Matx should have at least 6 elements."); + val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; + val[4] = v4; val[5] = v5; + for(int i = 6; i < channels; i++) val[i] = _Tp(0); +} + +template inline +Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6) +{ + CV_StaticAssert(channels >= 7, "Matx should have at least 7 elements."); + val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; + val[4] = v4; val[5] = v5; val[6] = v6; + for(int i = 7; i < channels; i++) val[i] = _Tp(0); +} + +template inline +Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7) +{ + CV_StaticAssert(channels >= 8, "Matx should have at least 8 elements."); + val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; + val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; + for(int i = 8; i < channels; i++) val[i] = _Tp(0); +} + +template inline +Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8) +{ + CV_StaticAssert(channels >= 9, "Matx should have at least 9 elements."); + val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; + val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; + val[8] = v8; + for(int i = 9; i < channels; i++) val[i] = _Tp(0); +} + +template inline +Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9) +{ + CV_StaticAssert(channels >= 10, "Matx should have at least 10 elements."); + val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; + val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; + val[8] = v8; val[9] = v9; + for(int i = 10; i < channels; i++) val[i] = _Tp(0); +} + + +template inline +Matx<_Tp,m,n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9, _Tp v10, _Tp v11) +{ + CV_StaticAssert(channels >= 12, "Matx should have at least 12 elements."); + val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; + val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; + val[8] = v8; val[9] = v9; val[10] = v10; val[11] = v11; + for(int i = 12; i < channels; i++) val[i] = _Tp(0); +} + +template inline +Matx<_Tp,m,n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9, _Tp v10, _Tp v11, _Tp v12, _Tp v13) +{ + CV_StaticAssert(channels >= 14, "Matx should have at least 14 elements."); + val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; + val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; + val[8] = v8; val[9] = v9; val[10] = v10; val[11] = v11; + val[12] = v12; val[13] = v13; + for (int i = 14; i < channels; i++) val[i] = _Tp(0); +} + + +template inline +Matx<_Tp,m,n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9, _Tp v10, _Tp v11, _Tp v12, _Tp v13, _Tp v14, _Tp v15) +{ + CV_StaticAssert(channels >= 16, "Matx should have at least 16 elements."); + val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; + val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7; + val[8] = v8; val[9] = v9; val[10] = v10; val[11] = v11; + val[12] = v12; val[13] = v13; val[14] = v14; val[15] = v15; + for(int i = 16; i < channels; i++) val[i] = _Tp(0); +} + +template inline +Matx<_Tp, m, n>::Matx(const _Tp* values) +{ + for( int i = 0; i < channels; i++ ) val[i] = values[i]; +} + +template inline +Matx<_Tp, m, n>::Matx(std::initializer_list<_Tp> list) +{ + CV_DbgAssert(list.size() == channels); + int i = 0; + for(const auto& elem : list) + { + val[i++] = elem; + } +} + +template inline +Matx<_Tp, m, n> Matx<_Tp, m, n>::all(_Tp alpha) +{ + Matx<_Tp, m, n> M; + for( int i = 0; i < m*n; i++ ) M.val[i] = alpha; + return M; +} + +template inline +Matx<_Tp,m,n> Matx<_Tp,m,n>::zeros() +{ + return all(0); +} + +template inline +Matx<_Tp,m,n> Matx<_Tp,m,n>::ones() +{ + return all(1); +} + +template inline +Matx<_Tp,m,n> Matx<_Tp,m,n>::eye() +{ + Matx<_Tp,m,n> M; + for(int i = 0; i < shortdim; i++) + M(i,i) = 1; + return M; +} + +template inline +_Tp Matx<_Tp, m, n>::dot(const Matx<_Tp, m, n>& M) const +{ + _Tp s = 0; + for( int i = 0; i < channels; i++ ) s += val[i]*M.val[i]; + return s; +} + +template inline +double Matx<_Tp, m, n>::ddot(const Matx<_Tp, m, n>& M) const +{ + double s = 0; + for( int i = 0; i < channels; i++ ) s += (double)val[i]*M.val[i]; + return s; +} + +template inline +Matx<_Tp,m,n> Matx<_Tp,m,n>::diag(const typename Matx<_Tp,m,n>::diag_type& d) +{ + Matx<_Tp,m,n> M; + for(int i = 0; i < shortdim; i++) + M(i,i) = d(i, 0); + return M; +} + +template template +inline Matx<_Tp, m, n>::operator Matx() const +{ + Matx M; + for( int i = 0; i < m*n; i++ ) M.val[i] = saturate_cast(val[i]); + return M; +} + +template template inline +Matx<_Tp, m1, n1> Matx<_Tp, m, n>::reshape() const +{ + CV_StaticAssert(m1*n1 == m*n, "Input and destnarion matrices must have the same number of elements"); + return (const Matx<_Tp, m1, n1>&)*this; +} + +template +template inline +Matx<_Tp, m1, n1> Matx<_Tp, m, n>::get_minor(int base_row, int base_col) const +{ + CV_DbgAssert(0 <= base_row && base_row+m1 <= m && 0 <= base_col && base_col+n1 <= n); + Matx<_Tp, m1, n1> s; + for( int di = 0; di < m1; di++ ) + for( int dj = 0; dj < n1; dj++ ) + s(di, dj) = (*this)(base_row+di, base_col+dj); + return s; +} + +template inline +Matx<_Tp, 1, n> Matx<_Tp, m, n>::row(int i) const +{ + CV_DbgAssert((unsigned)i < (unsigned)m); + return Matx<_Tp, 1, n>(&val[i*n]); +} + +template inline +Matx<_Tp, m, 1> Matx<_Tp, m, n>::col(int j) const +{ + CV_DbgAssert((unsigned)j < (unsigned)n); + Matx<_Tp, m, 1> v; + for( int i = 0; i < m; i++ ) + v.val[i] = val[i*n + j]; + return v; +} + +template inline +typename Matx<_Tp, m, n>::diag_type Matx<_Tp, m, n>::diag() const +{ + diag_type d; + for( int i = 0; i < shortdim; i++ ) + d.val[i] = val[i*n + i]; + return d; +} + +template inline +const _Tp& Matx<_Tp, m, n>::operator()(int row_idx, int col_idx) const +{ + CV_DbgAssert( (unsigned)row_idx < (unsigned)m && (unsigned)col_idx < (unsigned)n ); + return this->val[row_idx*n + col_idx]; +} + +template inline +_Tp& Matx<_Tp, m, n>::operator ()(int row_idx, int col_idx) +{ + CV_DbgAssert( (unsigned)row_idx < (unsigned)m && (unsigned)col_idx < (unsigned)n ); + return val[row_idx*n + col_idx]; +} + +template inline +const _Tp& Matx<_Tp, m, n>::operator ()(int i) const +{ + CV_StaticAssert(m == 1 || n == 1, "Single index indexation requires matrix to be a column or a row"); + CV_DbgAssert( (unsigned)i < (unsigned)(m+n-1) ); + return val[i]; +} + +template inline +_Tp& Matx<_Tp, m, n>::operator ()(int i) +{ + CV_StaticAssert(m == 1 || n == 1, "Single index indexation requires matrix to be a column or a row"); + CV_DbgAssert( (unsigned)i < (unsigned)(m+n-1) ); + return val[i]; +} + +template inline +Matx<_Tp,m,n>::Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_AddOp) +{ + for( int i = 0; i < channels; i++ ) + val[i] = saturate_cast<_Tp>(a.val[i] + b.val[i]); +} + +template inline +Matx<_Tp,m,n>::Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_SubOp) +{ + for( int i = 0; i < channels; i++ ) + val[i] = saturate_cast<_Tp>(a.val[i] - b.val[i]); +} + +template template inline +Matx<_Tp,m,n>::Matx(const Matx<_Tp, m, n>& a, _T2 alpha, Matx_ScaleOp) +{ + for( int i = 0; i < channels; i++ ) + val[i] = saturate_cast<_Tp>(a.val[i] * alpha); +} + +template inline +Matx<_Tp,m,n>::Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_MulOp) +{ + for( int i = 0; i < channels; i++ ) + val[i] = saturate_cast<_Tp>(a.val[i] * b.val[i]); +} + +template inline +Matx<_Tp,m,n>::Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_DivOp) +{ + for( int i = 0; i < channels; i++ ) + val[i] = saturate_cast<_Tp>(a.val[i] / b.val[i]); +} + +template template inline +Matx<_Tp,m,n>::Matx(const Matx<_Tp, m, l>& a, const Matx<_Tp, l, n>& b, Matx_MatMulOp) +{ + for( int i = 0; i < m; i++ ) + for( int j = 0; j < n; j++ ) + { + _Tp s = 0; + for( int k = 0; k < l; k++ ) + s += a(i, k) * b(k, j); + val[i*n + j] = s; + } +} + +template inline +Matx<_Tp,m,n>::Matx(const Matx<_Tp, n, m>& a, Matx_TOp) +{ + for( int i = 0; i < m; i++ ) + for( int j = 0; j < n; j++ ) + val[i*n + j] = a(j, i); +} + +template inline +Matx<_Tp, m, n> Matx<_Tp, m, n>::mul(const Matx<_Tp, m, n>& a) const +{ + return Matx<_Tp, m, n>(*this, a, Matx_MulOp()); +} + +template inline +Matx<_Tp, m, n> Matx<_Tp, m, n>::div(const Matx<_Tp, m, n>& a) const +{ + return Matx<_Tp, m, n>(*this, a, Matx_DivOp()); +} + +template inline +Matx<_Tp, n, m> Matx<_Tp, m, n>::t() const +{ + return Matx<_Tp, n, m>(*this, Matx_TOp()); +} + +template inline +Vec<_Tp, n> Matx<_Tp, m, n>::solve(const Vec<_Tp, m>& rhs, int method) const +{ + Matx<_Tp, n, 1> x = solve((const Matx<_Tp, m, 1>&)(rhs), method); + return (Vec<_Tp, n>&)(x); +} + +template static inline +double determinant(const Matx<_Tp, m, m>& a) +{ + return cv::internal::Matx_DetOp<_Tp, m>()(a); +} + +template static inline +double trace(const Matx<_Tp, m, n>& a) +{ + _Tp s = 0; + for( int i = 0; i < std::min(m, n); i++ ) + s += a(i,i); + return s; +} + +template static inline +double norm(const Matx<_Tp, m, n>& M) +{ + return std::sqrt(normL2Sqr<_Tp, double>(M.val, m*n)); +} + +template static inline +double norm(const Matx<_Tp, m, n>& M, int normType) +{ + switch(normType) { + case NORM_INF: + return (double)normInf<_Tp, typename DataType<_Tp>::work_type>(M.val, m*n); + case NORM_L1: + return (double)normL1<_Tp, typename DataType<_Tp>::work_type>(M.val, m*n); + case NORM_L2SQR: + return (double)normL2Sqr<_Tp, typename DataType<_Tp>::work_type>(M.val, m*n); + default: + case NORM_L2: + return std::sqrt((double)normL2Sqr<_Tp, typename DataType<_Tp>::work_type>(M.val, m*n)); + } +} + + + +//////////////////////////////// matx comma initializer ////////////////////////////////// + +template static inline +MatxCommaInitializer<_Tp, m, n> operator << (const Matx<_Tp, m, n>& mtx, _T2 val) +{ + MatxCommaInitializer<_Tp, m, n> commaInitializer((Matx<_Tp, m, n>*)&mtx); + return (commaInitializer, val); +} + +template inline +MatxCommaInitializer<_Tp, m, n>::MatxCommaInitializer(Matx<_Tp, m, n>* _mtx) + : dst(_mtx), idx(0) +{} + +template template inline +MatxCommaInitializer<_Tp, m, n>& MatxCommaInitializer<_Tp, m, n>::operator , (_T2 value) +{ + CV_DbgAssert( idx < m*n ); + dst->val[idx++] = saturate_cast<_Tp>(value); + return *this; +} + +template inline +Matx<_Tp, m, n> MatxCommaInitializer<_Tp, m, n>::operator *() const +{ + CV_DbgAssert( idx == n*m ); + return *dst; +} + + + +/////////////////////////////////// Vec Implementation /////////////////////////////////// + +template inline +Vec<_Tp, cn>::Vec() {} + +template inline +Vec<_Tp, cn>::Vec(_Tp v0) + : Matx<_Tp, cn, 1>(v0) {} + +template inline +Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1) + : Matx<_Tp, cn, 1>(v0, v1) {} + +template inline +Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2) + : Matx<_Tp, cn, 1>(v0, v1, v2) {} + +template inline +Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3) + : Matx<_Tp, cn, 1>(v0, v1, v2, v3) {} + +template inline +Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4) + : Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4) {} + +template inline +Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5) + : Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5) {} + +template inline +Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6) + : Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5, v6) {} + +template inline +Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7) + : Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5, v6, v7) {} + +template inline +Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8) + : Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5, v6, v7, v8) {} + +template inline +Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9) + : Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9) {} + +template inline +Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9, _Tp v10, _Tp v11, _Tp v12, _Tp v13) + : Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) {} + +template inline +Vec<_Tp, cn>::Vec(const _Tp* values) + : Matx<_Tp, cn, 1>(values) {} + +template inline +Vec<_Tp, cn>::Vec(std::initializer_list<_Tp> list) + : Matx<_Tp, cn, 1>(list) {} + +template inline +Vec<_Tp, cn>::Vec(const Vec<_Tp, cn>& m) + : Matx<_Tp, cn, 1>(m.val) {} + +template inline +Vec<_Tp, cn>::Vec(const Matx<_Tp, cn, 1>& a, const Matx<_Tp, cn, 1>& b, Matx_AddOp op) + : Matx<_Tp, cn, 1>(a, b, op) {} + +template inline +Vec<_Tp, cn>::Vec(const Matx<_Tp, cn, 1>& a, const Matx<_Tp, cn, 1>& b, Matx_SubOp op) + : Matx<_Tp, cn, 1>(a, b, op) {} + +template template inline +Vec<_Tp, cn>::Vec(const Matx<_Tp, cn, 1>& a, _T2 alpha, Matx_ScaleOp op) + : Matx<_Tp, cn, 1>(a, alpha, op) {} + +template inline +Vec<_Tp, cn> Vec<_Tp, cn>::all(_Tp alpha) +{ + Vec v; + for( int i = 0; i < cn; i++ ) v.val[i] = alpha; + return v; +} + +template inline +Vec<_Tp, cn> Vec<_Tp, cn>::ones() +{ + return Vec::all(1); +} + +template inline +Vec<_Tp, cn> Vec<_Tp, cn>::zeros() +{ + return Vec::all(0); +} + +template inline +Vec<_Tp, cn> Vec<_Tp, cn>::mul(const Vec<_Tp, cn>& v) const +{ + Vec<_Tp, cn> w; + for( int i = 0; i < cn; i++ ) w.val[i] = saturate_cast<_Tp>(this->val[i]*v.val[i]); + return w; +} + +template<> inline +Vec Vec::conj() const +{ + return cv::internal::conjugate(*this); +} + +template<> inline +Vec Vec::conj() const +{ + return cv::internal::conjugate(*this); +} + +template<> inline +Vec Vec::conj() const +{ + return cv::internal::conjugate(*this); +} + +template<> inline +Vec Vec::conj() const +{ + return cv::internal::conjugate(*this); +} + +template inline +Vec<_Tp, cn> Vec<_Tp, cn>::cross(const Vec<_Tp, cn>&) const +{ + CV_StaticAssert(cn == 3, "for arbitrary-size vector there is no cross-product defined"); + return Vec<_Tp, cn>(); +} + +template<> inline +Vec Vec::cross(const Vec& v) const +{ + return Vec(this->val[1]*v.val[2] - this->val[2]*v.val[1], + this->val[2]*v.val[0] - this->val[0]*v.val[2], + this->val[0]*v.val[1] - this->val[1]*v.val[0]); +} + +template<> inline +Vec Vec::cross(const Vec& v) const +{ + return Vec(this->val[1]*v.val[2] - this->val[2]*v.val[1], + this->val[2]*v.val[0] - this->val[0]*v.val[2], + this->val[0]*v.val[1] - this->val[1]*v.val[0]); +} + +template template inline +Vec<_Tp, cn>::operator Vec() const +{ + Vec v; + for( int i = 0; i < cn; i++ ) v.val[i] = saturate_cast(this->val[i]); + return v; +} + +template inline +const _Tp& Vec<_Tp, cn>::operator [](int i) const +{ + CV_DbgAssert( (unsigned)i < (unsigned)cn ); + return this->val[i]; +} + +template inline +_Tp& Vec<_Tp, cn>::operator [](int i) +{ + CV_DbgAssert( (unsigned)i < (unsigned)cn ); + return this->val[i]; +} + +template inline +const _Tp& Vec<_Tp, cn>::operator ()(int i) const +{ + CV_DbgAssert( (unsigned)i < (unsigned)cn ); + return this->val[i]; +} + +template inline +_Tp& Vec<_Tp, cn>::operator ()(int i) +{ + CV_DbgAssert( (unsigned)i < (unsigned)cn ); + return this->val[i]; +} + +template inline +Vec<_Tp, cn> normalize(const Vec<_Tp, cn>& v) +{ + double nv = norm(v); + return v * (nv ? 1./nv : 0.); +} + + + +//////////////////////////////// vec comma initializer ////////////////////////////////// + + +template static inline +VecCommaInitializer<_Tp, cn> operator << (const Vec<_Tp, cn>& vec, _T2 val) +{ + VecCommaInitializer<_Tp, cn> commaInitializer((Vec<_Tp, cn>*)&vec); + return (commaInitializer, val); +} + +template inline +VecCommaInitializer<_Tp, cn>::VecCommaInitializer(Vec<_Tp, cn>* _vec) + : MatxCommaInitializer<_Tp, cn, 1>(_vec) +{} + +template template inline +VecCommaInitializer<_Tp, cn>& VecCommaInitializer<_Tp, cn>::operator , (_T2 value) +{ + CV_DbgAssert( this->idx < cn ); + this->dst->val[this->idx++] = saturate_cast<_Tp>(value); + return *this; +} + +template inline +Vec<_Tp, cn> VecCommaInitializer<_Tp, cn>::operator *() const +{ + CV_DbgAssert( this->idx == cn ); + return *this->dst; +} + +//! @endcond + +///////////////////////////// Matx out-of-class operators //////////////////////////////// + +//! @relates cv::Matx +//! @{ + +template static inline +Matx<_Tp1, m, n>& operator += (Matx<_Tp1, m, n>& a, const Matx<_Tp2, m, n>& b) +{ + for( int i = 0; i < m*n; i++ ) + a.val[i] = saturate_cast<_Tp1>(a.val[i] + b.val[i]); + return a; +} + +template static inline +Matx<_Tp1, m, n>& operator -= (Matx<_Tp1, m, n>& a, const Matx<_Tp2, m, n>& b) +{ + for( int i = 0; i < m*n; i++ ) + a.val[i] = saturate_cast<_Tp1>(a.val[i] - b.val[i]); + return a; +} + +template static inline +Matx<_Tp, m, n> operator + (const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b) +{ + return Matx<_Tp, m, n>(a, b, Matx_AddOp()); +} + +template static inline +Matx<_Tp, m, n> operator - (const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b) +{ + return Matx<_Tp, m, n>(a, b, Matx_SubOp()); +} + +template static inline +Matx<_Tp, m, n>& operator *= (Matx<_Tp, m, n>& a, int alpha) +{ + for( int i = 0; i < m*n; i++ ) + a.val[i] = saturate_cast<_Tp>(a.val[i] * alpha); + return a; +} + +template static inline +Matx<_Tp, m, n>& operator *= (Matx<_Tp, m, n>& a, float alpha) +{ + for( int i = 0; i < m*n; i++ ) + a.val[i] = saturate_cast<_Tp>(a.val[i] * alpha); + return a; +} + +template static inline +Matx<_Tp, m, n>& operator *= (Matx<_Tp, m, n>& a, double alpha) +{ + for( int i = 0; i < m*n; i++ ) + a.val[i] = saturate_cast<_Tp>(a.val[i] * alpha); + return a; +} + +template static inline +Matx<_Tp, m, n> operator * (const Matx<_Tp, m, n>& a, int alpha) +{ + return Matx<_Tp, m, n>(a, alpha, Matx_ScaleOp()); +} + +template static inline +Matx<_Tp, m, n> operator * (const Matx<_Tp, m, n>& a, float alpha) +{ + return Matx<_Tp, m, n>(a, alpha, Matx_ScaleOp()); +} + +template static inline +Matx<_Tp, m, n> operator * (const Matx<_Tp, m, n>& a, double alpha) +{ + return Matx<_Tp, m, n>(a, alpha, Matx_ScaleOp()); +} + +template static inline +Matx<_Tp, m, n> operator * (int alpha, const Matx<_Tp, m, n>& a) +{ + return Matx<_Tp, m, n>(a, alpha, Matx_ScaleOp()); +} + +template static inline +Matx<_Tp, m, n> operator * (float alpha, const Matx<_Tp, m, n>& a) +{ + return Matx<_Tp, m, n>(a, alpha, Matx_ScaleOp()); +} + +template static inline +Matx<_Tp, m, n> operator * (double alpha, const Matx<_Tp, m, n>& a) +{ + return Matx<_Tp, m, n>(a, alpha, Matx_ScaleOp()); +} + +template static inline +Matx<_Tp, m, n>& operator /= (Matx<_Tp, m, n>& a, float alpha) +{ + for( int i = 0; i < m*n; i++ ) + a.val[i] = a.val[i] / alpha; + return a; +} + +template static inline +Matx<_Tp, m, n>& operator /= (Matx<_Tp, m, n>& a, double alpha) +{ + for( int i = 0; i < m*n; i++ ) + a.val[i] = a.val[i] / alpha; + return a; +} + +template static inline +Matx<_Tp, m, n> operator / (const Matx<_Tp, m, n>& a, float alpha) +{ + return Matx<_Tp, m, n>(a, 1.f/alpha, Matx_ScaleOp()); +} + +template static inline +Matx<_Tp, m, n> operator / (const Matx<_Tp, m, n>& a, double alpha) +{ + return Matx<_Tp, m, n>(a, 1./alpha, Matx_ScaleOp()); +} + +template static inline +Matx<_Tp, m, n> operator - (const Matx<_Tp, m, n>& a) +{ + return Matx<_Tp, m, n>(a, -1, Matx_ScaleOp()); +} + +template static inline +Matx<_Tp, m, n> operator * (const Matx<_Tp, m, l>& a, const Matx<_Tp, l, n>& b) +{ + return Matx<_Tp, m, n>(a, b, Matx_MatMulOp()); +} + +template static inline +Vec<_Tp, m> operator * (const Matx<_Tp, m, n>& a, const Vec<_Tp, n>& b) +{ + Matx<_Tp, m, 1> c(a, b, Matx_MatMulOp()); + return (const Vec<_Tp, m>&)(c); +} + +template static inline +bool operator == (const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b) +{ + for( int i = 0; i < m*n; i++ ) + if( a.val[i] != b.val[i] ) return false; + return true; +} + +template static inline +bool operator != (const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b) +{ + return !(a == b); +} + +//! @} + +////////////////////////////// Vec out-of-class operators //////////////////////////////// + +//! @relates cv::Vec +//! @{ + +template static inline +Vec<_Tp1, cn>& operator += (Vec<_Tp1, cn>& a, const Vec<_Tp2, cn>& b) +{ + for( int i = 0; i < cn; i++ ) + a.val[i] = saturate_cast<_Tp1>(a.val[i] + b.val[i]); + return a; +} + +template static inline +Vec<_Tp1, cn>& operator -= (Vec<_Tp1, cn>& a, const Vec<_Tp2, cn>& b) +{ + for( int i = 0; i < cn; i++ ) + a.val[i] = saturate_cast<_Tp1>(a.val[i] - b.val[i]); + return a; +} + +template static inline +Vec<_Tp, cn> operator + (const Vec<_Tp, cn>& a, const Vec<_Tp, cn>& b) +{ + return Vec<_Tp, cn>(a, b, Matx_AddOp()); +} + +template static inline +Vec<_Tp, cn> operator - (const Vec<_Tp, cn>& a, const Vec<_Tp, cn>& b) +{ + return Vec<_Tp, cn>(a, b, Matx_SubOp()); +} + +template static inline +Vec<_Tp, cn>& operator *= (Vec<_Tp, cn>& a, int alpha) +{ + for( int i = 0; i < cn; i++ ) + a[i] = saturate_cast<_Tp>(a[i]*alpha); + return a; +} + +template static inline +Vec<_Tp, cn>& operator *= (Vec<_Tp, cn>& a, float alpha) +{ + for( int i = 0; i < cn; i++ ) + a[i] = saturate_cast<_Tp>(a[i]*alpha); + return a; +} + +template static inline +Vec<_Tp, cn>& operator *= (Vec<_Tp, cn>& a, double alpha) +{ + for( int i = 0; i < cn; i++ ) + a[i] = saturate_cast<_Tp>(a[i]*alpha); + return a; +} + +template static inline +Vec<_Tp, cn>& operator /= (Vec<_Tp, cn>& a, int alpha) +{ + double ialpha = 1./alpha; + for( int i = 0; i < cn; i++ ) + a[i] = saturate_cast<_Tp>(a[i]*ialpha); + return a; +} + +template static inline +Vec<_Tp, cn>& operator /= (Vec<_Tp, cn>& a, float alpha) +{ + float ialpha = 1.f/alpha; + for( int i = 0; i < cn; i++ ) + a[i] = saturate_cast<_Tp>(a[i]*ialpha); + return a; +} + +template static inline +Vec<_Tp, cn>& operator /= (Vec<_Tp, cn>& a, double alpha) +{ + double ialpha = 1./alpha; + for( int i = 0; i < cn; i++ ) + a[i] = saturate_cast<_Tp>(a[i]*ialpha); + return a; +} + +template static inline +Vec<_Tp, cn> operator * (const Vec<_Tp, cn>& a, int alpha) +{ + return Vec<_Tp, cn>(a, alpha, Matx_ScaleOp()); +} + +template static inline +Vec<_Tp, cn> operator * (int alpha, const Vec<_Tp, cn>& a) +{ + return Vec<_Tp, cn>(a, alpha, Matx_ScaleOp()); +} + +template static inline +Vec<_Tp, cn> operator * (const Vec<_Tp, cn>& a, float alpha) +{ + return Vec<_Tp, cn>(a, alpha, Matx_ScaleOp()); +} + +template static inline +Vec<_Tp, cn> operator * (float alpha, const Vec<_Tp, cn>& a) +{ + return Vec<_Tp, cn>(a, alpha, Matx_ScaleOp()); +} + +template static inline +Vec<_Tp, cn> operator * (const Vec<_Tp, cn>& a, double alpha) +{ + return Vec<_Tp, cn>(a, alpha, Matx_ScaleOp()); +} + +template static inline +Vec<_Tp, cn> operator * (double alpha, const Vec<_Tp, cn>& a) +{ + return Vec<_Tp, cn>(a, alpha, Matx_ScaleOp()); +} + +template static inline +Vec<_Tp, cn> operator / (const Vec<_Tp, cn>& a, int alpha) +{ + return Vec<_Tp, cn>(a, 1./alpha, Matx_ScaleOp()); +} + +template static inline +Vec<_Tp, cn> operator / (const Vec<_Tp, cn>& a, float alpha) +{ + return Vec<_Tp, cn>(a, 1.f/alpha, Matx_ScaleOp()); +} + +template static inline +Vec<_Tp, cn> operator / (const Vec<_Tp, cn>& a, double alpha) +{ + return Vec<_Tp, cn>(a, 1./alpha, Matx_ScaleOp()); +} + +template static inline +Vec<_Tp, cn> operator - (const Vec<_Tp, cn>& a) +{ + Vec<_Tp,cn> t; + for( int i = 0; i < cn; i++ ) t.val[i] = saturate_cast<_Tp>(-a.val[i]); + return t; +} + +template inline Vec<_Tp, 4> operator * (const Vec<_Tp, 4>& v1, const Vec<_Tp, 4>& v2) +{ + return Vec<_Tp, 4>(saturate_cast<_Tp>(v1[0]*v2[0] - v1[1]*v2[1] - v1[2]*v2[2] - v1[3]*v2[3]), + saturate_cast<_Tp>(v1[0]*v2[1] + v1[1]*v2[0] + v1[2]*v2[3] - v1[3]*v2[2]), + saturate_cast<_Tp>(v1[0]*v2[2] - v1[1]*v2[3] + v1[2]*v2[0] + v1[3]*v2[1]), + saturate_cast<_Tp>(v1[0]*v2[3] + v1[1]*v2[2] - v1[2]*v2[1] + v1[3]*v2[0])); +} + +template inline Vec<_Tp, 4>& operator *= (Vec<_Tp, 4>& v1, const Vec<_Tp, 4>& v2) +{ + v1 = v1 * v2; + return v1; +} + +//! @} + +} // cv + +#endif // OPENCV_CORE_MATX_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/neon_utils.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/neon_utils.hpp new file mode 100644 index 0000000..573ba99 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/neon_utils.hpp @@ -0,0 +1,128 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_HAL_NEON_UTILS_HPP +#define OPENCV_HAL_NEON_UTILS_HPP + +#include "opencv2/core/cvdef.h" + +//! @addtogroup core_utils_neon +//! @{ + +#if CV_NEON + +inline int32x2_t cv_vrnd_s32_f32(float32x2_t v) +{ + static int32x2_t v_sign = vdup_n_s32(1 << 31), + v_05 = vreinterpret_s32_f32(vdup_n_f32(0.5f)); + + int32x2_t v_addition = vorr_s32(v_05, vand_s32(v_sign, vreinterpret_s32_f32(v))); + return vcvt_s32_f32(vadd_f32(v, vreinterpret_f32_s32(v_addition))); +} + +inline int32x4_t cv_vrndq_s32_f32(float32x4_t v) +{ + static int32x4_t v_sign = vdupq_n_s32(1 << 31), + v_05 = vreinterpretq_s32_f32(vdupq_n_f32(0.5f)); + + int32x4_t v_addition = vorrq_s32(v_05, vandq_s32(v_sign, vreinterpretq_s32_f32(v))); + return vcvtq_s32_f32(vaddq_f32(v, vreinterpretq_f32_s32(v_addition))); +} + +inline uint32x2_t cv_vrnd_u32_f32(float32x2_t v) +{ + static float32x2_t v_05 = vdup_n_f32(0.5f); + return vcvt_u32_f32(vadd_f32(v, v_05)); +} + +inline uint32x4_t cv_vrndq_u32_f32(float32x4_t v) +{ + static float32x4_t v_05 = vdupq_n_f32(0.5f); + return vcvtq_u32_f32(vaddq_f32(v, v_05)); +} + +inline float32x4_t cv_vrecpq_f32(float32x4_t val) +{ + float32x4_t reciprocal = vrecpeq_f32(val); + reciprocal = vmulq_f32(vrecpsq_f32(val, reciprocal), reciprocal); + reciprocal = vmulq_f32(vrecpsq_f32(val, reciprocal), reciprocal); + return reciprocal; +} + +inline float32x2_t cv_vrecp_f32(float32x2_t val) +{ + float32x2_t reciprocal = vrecpe_f32(val); + reciprocal = vmul_f32(vrecps_f32(val, reciprocal), reciprocal); + reciprocal = vmul_f32(vrecps_f32(val, reciprocal), reciprocal); + return reciprocal; +} + +inline float32x4_t cv_vrsqrtq_f32(float32x4_t val) +{ + float32x4_t e = vrsqrteq_f32(val); + e = vmulq_f32(vrsqrtsq_f32(vmulq_f32(e, e), val), e); + e = vmulq_f32(vrsqrtsq_f32(vmulq_f32(e, e), val), e); + return e; +} + +inline float32x2_t cv_vrsqrt_f32(float32x2_t val) +{ + float32x2_t e = vrsqrte_f32(val); + e = vmul_f32(vrsqrts_f32(vmul_f32(e, e), val), e); + e = vmul_f32(vrsqrts_f32(vmul_f32(e, e), val), e); + return e; +} + +inline float32x4_t cv_vsqrtq_f32(float32x4_t val) +{ + return cv_vrecpq_f32(cv_vrsqrtq_f32(val)); +} + +inline float32x2_t cv_vsqrt_f32(float32x2_t val) +{ + return cv_vrecp_f32(cv_vrsqrt_f32(val)); +} + +#endif + +//! @} + +#endif // OPENCV_HAL_NEON_UTILS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/ocl.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/ocl.hpp new file mode 100644 index 0000000..642b050 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/ocl.hpp @@ -0,0 +1,902 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 OpenCV Foundation 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. +// +//M*/ + +#ifndef OPENCV_OPENCL_HPP +#define OPENCV_OPENCL_HPP + +#include "opencv2/core.hpp" +#include +#include + +namespace cv { namespace ocl { + +//! @addtogroup core_opencl +//! @{ + +CV_EXPORTS_W bool haveOpenCL(); +CV_EXPORTS_W bool useOpenCL(); +CV_EXPORTS_W bool haveAmdBlas(); +CV_EXPORTS_W bool haveAmdFft(); +CV_EXPORTS_W void setUseOpenCL(bool flag); +CV_EXPORTS_W void finish(); + +CV_EXPORTS bool haveSVM(); + +class CV_EXPORTS Context; +class CV_EXPORTS_W_SIMPLE Device; +class CV_EXPORTS Kernel; +class CV_EXPORTS Program; +class CV_EXPORTS ProgramSource; +class CV_EXPORTS Queue; +class CV_EXPORTS PlatformInfo; +class CV_EXPORTS Image2D; + +class CV_EXPORTS_W_SIMPLE Device +{ +public: + CV_WRAP Device() CV_NOEXCEPT; + explicit Device(void* d); + Device(const Device& d); + Device& operator = (const Device& d); + Device(Device&& d) CV_NOEXCEPT; + Device& operator = (Device&& d) CV_NOEXCEPT; + CV_WRAP ~Device(); + + void set(void* d); + + enum + { + TYPE_DEFAULT = (1 << 0), + TYPE_CPU = (1 << 1), + TYPE_GPU = (1 << 2), + TYPE_ACCELERATOR = (1 << 3), + TYPE_DGPU = TYPE_GPU + (1 << 16), + TYPE_IGPU = TYPE_GPU + (1 << 17), + TYPE_ALL = 0xFFFFFFFF + }; + + CV_WRAP String name() const; + CV_WRAP String extensions() const; + CV_WRAP bool isExtensionSupported(const String& extensionName) const; + CV_WRAP String version() const; + CV_WRAP String vendorName() const; + CV_WRAP String OpenCL_C_Version() const; + CV_WRAP String OpenCLVersion() const; + CV_WRAP int deviceVersionMajor() const; + CV_WRAP int deviceVersionMinor() const; + CV_WRAP String driverVersion() const; + void* ptr() const; + + CV_WRAP int type() const; + + CV_WRAP int addressBits() const; + CV_WRAP bool available() const; + CV_WRAP bool compilerAvailable() const; + CV_WRAP bool linkerAvailable() const; + + enum + { + FP_DENORM=(1 << 0), + FP_INF_NAN=(1 << 1), + FP_ROUND_TO_NEAREST=(1 << 2), + FP_ROUND_TO_ZERO=(1 << 3), + FP_ROUND_TO_INF=(1 << 4), + FP_FMA=(1 << 5), + FP_SOFT_FLOAT=(1 << 6), + FP_CORRECTLY_ROUNDED_DIVIDE_SQRT=(1 << 7) + }; + CV_WRAP int doubleFPConfig() const; + CV_WRAP int singleFPConfig() const; + CV_WRAP int halfFPConfig() const; + + CV_WRAP bool endianLittle() const; + CV_WRAP bool errorCorrectionSupport() const; + + enum + { + EXEC_KERNEL=(1 << 0), + EXEC_NATIVE_KERNEL=(1 << 1) + }; + CV_WRAP int executionCapabilities() const; + + CV_WRAP size_t globalMemCacheSize() const; + + enum + { + NO_CACHE=0, + READ_ONLY_CACHE=1, + READ_WRITE_CACHE=2 + }; + CV_WRAP int globalMemCacheType() const; + CV_WRAP int globalMemCacheLineSize() const; + CV_WRAP size_t globalMemSize() const; + + CV_WRAP size_t localMemSize() const; + enum + { + NO_LOCAL_MEM=0, + LOCAL_IS_LOCAL=1, + LOCAL_IS_GLOBAL=2 + }; + CV_WRAP int localMemType() const; + CV_WRAP bool hostUnifiedMemory() const; + + CV_WRAP bool imageSupport() const; + + CV_WRAP bool imageFromBufferSupport() const; + uint imagePitchAlignment() const; + uint imageBaseAddressAlignment() const; + + /// deprecated, use isExtensionSupported() method (probably with "cl_khr_subgroups" value) + CV_WRAP bool intelSubgroupsSupport() const; + + CV_WRAP size_t image2DMaxWidth() const; + CV_WRAP size_t image2DMaxHeight() const; + + CV_WRAP size_t image3DMaxWidth() const; + CV_WRAP size_t image3DMaxHeight() const; + CV_WRAP size_t image3DMaxDepth() const; + + CV_WRAP size_t imageMaxBufferSize() const; + CV_WRAP size_t imageMaxArraySize() const; + + enum + { + UNKNOWN_VENDOR=0, + VENDOR_AMD=1, + VENDOR_INTEL=2, + VENDOR_NVIDIA=3 + }; + CV_WRAP int vendorID() const; + // FIXIT + // dev.isAMD() doesn't work for OpenCL CPU devices from AMD OpenCL platform. + // This method should use platform name instead of vendor name. + // After fix restore code in arithm.cpp: ocl_compare() + CV_WRAP inline bool isAMD() const { return vendorID() == VENDOR_AMD; } + CV_WRAP inline bool isIntel() const { return vendorID() == VENDOR_INTEL; } + CV_WRAP inline bool isNVidia() const { return vendorID() == VENDOR_NVIDIA; } + + CV_WRAP int maxClockFrequency() const; + CV_WRAP int maxComputeUnits() const; + CV_WRAP int maxConstantArgs() const; + CV_WRAP size_t maxConstantBufferSize() const; + + CV_WRAP size_t maxMemAllocSize() const; + CV_WRAP size_t maxParameterSize() const; + + CV_WRAP int maxReadImageArgs() const; + CV_WRAP int maxWriteImageArgs() const; + CV_WRAP int maxSamplers() const; + + CV_WRAP size_t maxWorkGroupSize() const; + CV_WRAP int maxWorkItemDims() const; + void maxWorkItemSizes(size_t*) const; + + CV_WRAP int memBaseAddrAlign() const; + + CV_WRAP int nativeVectorWidthChar() const; + CV_WRAP int nativeVectorWidthShort() const; + CV_WRAP int nativeVectorWidthInt() const; + CV_WRAP int nativeVectorWidthLong() const; + CV_WRAP int nativeVectorWidthFloat() const; + CV_WRAP int nativeVectorWidthDouble() const; + CV_WRAP int nativeVectorWidthHalf() const; + + CV_WRAP int preferredVectorWidthChar() const; + CV_WRAP int preferredVectorWidthShort() const; + CV_WRAP int preferredVectorWidthInt() const; + CV_WRAP int preferredVectorWidthLong() const; + CV_WRAP int preferredVectorWidthFloat() const; + CV_WRAP int preferredVectorWidthDouble() const; + CV_WRAP int preferredVectorWidthHalf() const; + + CV_WRAP size_t printfBufferSize() const; + CV_WRAP size_t profilingTimerResolution() const; + + CV_WRAP static const Device& getDefault(); + + /** + * @param d OpenCL handle (cl_device_id). clRetainDevice() is called on success. + * + * @note Ownership of the passed device is passed to OpenCV on success. + * The caller should additionally call `clRetainDevice` on it if it intends + * to continue using the device. + */ + static Device fromHandle(void* d); + + struct Impl; + inline Impl* getImpl() const { return (Impl*)p; } + inline bool empty() const { return !p; } +protected: + Impl* p; +}; + + +class CV_EXPORTS Context +{ +public: + Context() CV_NOEXCEPT; + explicit Context(int dtype); //!< @deprecated + ~Context(); + Context(const Context& c); + Context& operator= (const Context& c); + Context(Context&& c) CV_NOEXCEPT; + Context& operator = (Context&& c) CV_NOEXCEPT; + + /** @deprecated */ + bool create(); + /** @deprecated */ + bool create(int dtype); + + size_t ndevices() const; + Device& device(size_t idx) const; + Program getProg(const ProgramSource& prog, + const String& buildopt, String& errmsg); + void unloadProg(Program& prog); + + + /** Get thread-local OpenCL context (initialize if necessary) */ +#if 0 // OpenCV 5.0 + static Context& getDefault(); +#else + static Context& getDefault(bool initialize = true); +#endif + + /** @returns cl_context value */ + void* ptr() const; + + /** + * @brief Get OpenCL context property specified on context creation + * @param propertyId Property id (CL_CONTEXT_* as defined in cl_context_properties type) + * @returns Property value if property was specified on clCreateContext, or NULL if context created without the property + */ + void* getOpenCLContextProperty(int propertyId) const; + + bool useSVM() const; + void setUseSVM(bool enabled); + + /** + * @param context OpenCL handle (cl_context). clRetainContext() is called on success + */ + static Context fromHandle(void* context); + static Context fromDevice(const ocl::Device& device); + static Context create(const std::string& configuration); + + void release(); + + struct Impl; + inline Impl* getImpl() const { return (Impl*)p; } + inline bool empty() const { return !p; } +// TODO OpenCV 5.0 +//protected: + Impl* p; +}; + +/** @deprecated */ +class CV_EXPORTS Platform +{ +public: + Platform() CV_NOEXCEPT; + ~Platform(); + Platform(const Platform& p); + Platform& operator = (const Platform& p); + Platform(Platform&& p) CV_NOEXCEPT; + Platform& operator = (Platform&& p) CV_NOEXCEPT; + + void* ptr() const; + + /** @deprecated */ + static Platform& getDefault(); + + struct Impl; + inline Impl* getImpl() const { return (Impl*)p; } + inline bool empty() const { return !p; } +protected: + Impl* p; +}; + +/** @brief Attaches OpenCL context to OpenCV +@note + OpenCV will check if available OpenCL platform has platformName name, then assign context to + OpenCV and call `clRetainContext` function. The deviceID device will be used as target device and + new command queue will be created. +@param platformName name of OpenCL platform to attach, this string is used to check if platform is available to OpenCV at runtime +@param platformID ID of platform attached context was created for +@param context OpenCL context to be attached to OpenCV +@param deviceID ID of device, must be created from attached context +*/ +CV_EXPORTS void attachContext(const String& platformName, void* platformID, void* context, void* deviceID); + +/** @brief Convert OpenCL buffer to UMat +@note + OpenCL buffer (cl_mem_buffer) should contain 2D image data, compatible with OpenCV. Memory + content is not copied from `clBuffer` to UMat. Instead, buffer handle assigned to UMat and + `clRetainMemObject` is called. +@param cl_mem_buffer source clBuffer handle +@param step num of bytes in single row +@param rows number of rows +@param cols number of cols +@param type OpenCV type of image +@param dst destination UMat +*/ +CV_EXPORTS void convertFromBuffer(void* cl_mem_buffer, size_t step, int rows, int cols, int type, UMat& dst); + +/** @brief Convert OpenCL image2d_t to UMat +@note + OpenCL `image2d_t` (cl_mem_image), should be compatible with OpenCV UMat formats. Memory content + is copied from image to UMat with `clEnqueueCopyImageToBuffer` function. +@param cl_mem_image source image2d_t handle +@param dst destination UMat +*/ +CV_EXPORTS void convertFromImage(void* cl_mem_image, UMat& dst); + +// TODO Move to internal header +/// @deprecated +void initializeContextFromHandle(Context& ctx, void* platform, void* context, void* device); + +class CV_EXPORTS Queue +{ +public: + Queue() CV_NOEXCEPT; + explicit Queue(const Context& c, const Device& d=Device()); + ~Queue(); + Queue(const Queue& q); + Queue& operator = (const Queue& q); + Queue(Queue&& q) CV_NOEXCEPT; + Queue& operator = (Queue&& q) CV_NOEXCEPT; + + bool create(const Context& c=Context(), const Device& d=Device()); + void finish(); + void* ptr() const; + static Queue& getDefault(); + + /// @brief Returns OpenCL command queue with enable profiling mode support + const Queue& getProfilingQueue() const; + + struct Impl; friend struct Impl; + inline Impl* getImpl() const { return p; } + inline bool empty() const { return !p; } +protected: + Impl* p; +}; + + +class CV_EXPORTS KernelArg +{ +public: + enum { LOCAL=1, READ_ONLY=2, WRITE_ONLY=4, READ_WRITE=6, CONSTANT=8, PTR_ONLY = 16, NO_SIZE=256 }; + KernelArg(int _flags, UMat* _m, int wscale=1, int iwscale=1, const void* _obj=0, size_t _sz=0); + KernelArg() CV_NOEXCEPT; + + static KernelArg Local(size_t localMemSize) + { return KernelArg(LOCAL, 0, 1, 1, 0, localMemSize); } + static KernelArg PtrWriteOnly(const UMat& m) + { return KernelArg(PTR_ONLY+WRITE_ONLY, (UMat*)&m); } + static KernelArg PtrReadOnly(const UMat& m) + { return KernelArg(PTR_ONLY+READ_ONLY, (UMat*)&m); } + static KernelArg PtrReadWrite(const UMat& m) + { return KernelArg(PTR_ONLY+READ_WRITE, (UMat*)&m); } + static KernelArg ReadWrite(const UMat& m, int wscale=1, int iwscale=1) + { return KernelArg(READ_WRITE, (UMat*)&m, wscale, iwscale); } + static KernelArg ReadWriteNoSize(const UMat& m, int wscale=1, int iwscale=1) + { return KernelArg(READ_WRITE+NO_SIZE, (UMat*)&m, wscale, iwscale); } + static KernelArg ReadOnly(const UMat& m, int wscale=1, int iwscale=1) + { return KernelArg(READ_ONLY, (UMat*)&m, wscale, iwscale); } + static KernelArg WriteOnly(const UMat& m, int wscale=1, int iwscale=1) + { return KernelArg(WRITE_ONLY, (UMat*)&m, wscale, iwscale); } + static KernelArg ReadOnlyNoSize(const UMat& m, int wscale=1, int iwscale=1) + { return KernelArg(READ_ONLY+NO_SIZE, (UMat*)&m, wscale, iwscale); } + static KernelArg WriteOnlyNoSize(const UMat& m, int wscale=1, int iwscale=1) + { return KernelArg(WRITE_ONLY+NO_SIZE, (UMat*)&m, wscale, iwscale); } + static KernelArg Constant(const Mat& m); + template static KernelArg Constant(const _Tp* arr, size_t n) + { return KernelArg(CONSTANT, 0, 1, 1, (void*)arr, n); } + + int flags; + UMat* m; + const void* obj; + size_t sz; + int wscale, iwscale; +}; + + +class CV_EXPORTS Kernel +{ +public: + Kernel() CV_NOEXCEPT; + Kernel(const char* kname, const Program& prog); + Kernel(const char* kname, const ProgramSource& prog, + const String& buildopts = String(), String* errmsg=0); + ~Kernel(); + Kernel(const Kernel& k); + Kernel& operator = (const Kernel& k); + Kernel(Kernel&& k) CV_NOEXCEPT; + Kernel& operator = (Kernel&& k) CV_NOEXCEPT; + + bool empty() const; + bool create(const char* kname, const Program& prog); + bool create(const char* kname, const ProgramSource& prog, + const String& buildopts, String* errmsg=0); + + int set(int i, const void* value, size_t sz); + int set(int i, const Image2D& image2D); + int set(int i, const UMat& m); + int set(int i, const KernelArg& arg); + template int set(int i, const _Tp& value) + { return set(i, &value, sizeof(value)); } + + +protected: + template inline + int set_args_(int i, const _Tp0& a0) { return set(i, a0); } + template inline + int set_args_(int i, const _Tp0& a0, const _Tps&... rest_args) { i = set(i, a0); return set_args_(i, rest_args...); } +public: + /** @brief Setup OpenCL Kernel arguments. + Avoid direct using of set(i, ...) methods. + @code + bool ok = kernel + .args( + srcUMat, dstUMat, + (float)some_float_param + ).run(ndims, globalSize, localSize); + if (!ok) return false; + @endcode + */ + template inline + Kernel& args(const _Tps&... kernel_args) { set_args_(0, kernel_args...); return *this; } + + /** @brief Run the OpenCL kernel (globalsize value may be adjusted) + + @param dims the work problem dimensions. It is the length of globalsize and localsize. It can be either 1, 2 or 3. + @param globalsize work items for each dimension. It is not the final globalsize passed to + OpenCL. Each dimension will be adjusted to the nearest integer divisible by the corresponding + value in localsize. If localsize is NULL, it will still be adjusted depending on dims. The + adjusted values are greater than or equal to the original values. + @param localsize work-group size for each dimension. + @param sync specify whether to wait for OpenCL computation to finish before return. + @param q command queue + + @note Use run_() if your kernel code doesn't support adjusted globalsize. + */ + bool run(int dims, size_t globalsize[], + size_t localsize[], bool sync, const Queue& q=Queue()); + + /** @brief Run the OpenCL kernel + * + * @param dims the work problem dimensions. It is the length of globalsize and localsize. It can be either 1, 2 or 3. + * @param globalsize work items for each dimension. This value is passed to OpenCL without changes. + * @param localsize work-group size for each dimension. + * @param sync specify whether to wait for OpenCL computation to finish before return. + * @param q command queue + */ + bool run_(int dims, size_t globalsize[], size_t localsize[], bool sync, const Queue& q=Queue()); + + bool runTask(bool sync, const Queue& q=Queue()); + + /** @brief Similar to synchronized run_() call with returning of kernel execution time + * + * Separate OpenCL command queue may be used (with CL_QUEUE_PROFILING_ENABLE) + * @return Execution time in nanoseconds or negative number on error + */ + int64 runProfiling(int dims, size_t globalsize[], size_t localsize[], const Queue& q=Queue()); + + size_t workGroupSize() const; + size_t preferedWorkGroupSizeMultiple() const; + bool compileWorkGroupSize(size_t wsz[]) const; + size_t localMemSize() const; + + void* ptr() const; + struct Impl; + +protected: + Impl* p; +}; + +class CV_EXPORTS Program +{ +public: + Program() CV_NOEXCEPT; + Program(const ProgramSource& src, + const String& buildflags, String& errmsg); + Program(const Program& prog); + Program& operator = (const Program& prog); + Program(Program&& prog) CV_NOEXCEPT; + Program& operator = (Program&& prog) CV_NOEXCEPT; + ~Program(); + + bool create(const ProgramSource& src, + const String& buildflags, String& errmsg); + + void* ptr() const; + + /** + * @brief Query device-specific program binary. + * + * Returns RAW OpenCL executable binary without additional attachments. + * + * @sa ProgramSource::fromBinary + * + * @param[out] binary output buffer + */ + void getBinary(std::vector& binary) const; + + struct Impl; friend struct Impl; + inline Impl* getImpl() const { return (Impl*)p; } + inline bool empty() const { return !p; } +protected: + Impl* p; +public: +#ifndef OPENCV_REMOVE_DEPRECATED_API + // TODO Remove this + CV_DEPRECATED bool read(const String& buf, const String& buildflags); // removed, use ProgramSource instead + CV_DEPRECATED bool write(String& buf) const; // removed, use getBinary() method instead (RAW OpenCL binary) + CV_DEPRECATED const ProgramSource& source() const; // implementation removed + CV_DEPRECATED String getPrefix() const; // deprecated, implementation replaced + CV_DEPRECATED static String getPrefix(const String& buildflags); // deprecated, implementation replaced +#endif +}; + + +class CV_EXPORTS ProgramSource +{ +public: + typedef uint64 hash_t; // deprecated + + ProgramSource() CV_NOEXCEPT; + explicit ProgramSource(const String& module, const String& name, const String& codeStr, const String& codeHash); + explicit ProgramSource(const String& prog); // deprecated + explicit ProgramSource(const char* prog); // deprecated + ~ProgramSource(); + ProgramSource(const ProgramSource& prog); + ProgramSource& operator = (const ProgramSource& prog); + ProgramSource(ProgramSource&& prog) CV_NOEXCEPT; + ProgramSource& operator = (ProgramSource&& prog) CV_NOEXCEPT; + + const String& source() const; // deprecated + hash_t hash() const; // deprecated + + + /** @brief Describe OpenCL program binary. + * Do not call clCreateProgramWithBinary() and/or clBuildProgram(). + * + * Caller should guarantee binary buffer lifetime greater than ProgramSource object (and any of its copies). + * + * This kind of binary is not portable between platforms in general - it is specific to OpenCL vendor / device / driver version. + * + * @param module name of program owner module + * @param name unique name of program (module+name is used as key for OpenCL program caching) + * @param binary buffer address. See buffer lifetime requirement in description. + * @param size buffer size + * @param buildOptions additional program-related build options passed to clBuildProgram() + * @return created ProgramSource object + */ + static ProgramSource fromBinary(const String& module, const String& name, + const unsigned char* binary, const size_t size, + const cv::String& buildOptions = cv::String()); + + /** @brief Describe OpenCL program in SPIR format. + * Do not call clCreateProgramWithBinary() and/or clBuildProgram(). + * + * Supports SPIR 1.2 by default (pass '-spir-std=X.Y' in buildOptions to override this behavior) + * + * Caller should guarantee binary buffer lifetime greater than ProgramSource object (and any of its copies). + * + * Programs in this format are portable between OpenCL implementations with 'khr_spir' extension: + * https://www.khronos.org/registry/OpenCL/sdk/2.0/docs/man/xhtml/cl_khr_spir.html + * (but they are not portable between different platforms: 32-bit / 64-bit) + * + * Note: these programs can't support vendor specific extensions, like 'cl_intel_subgroups'. + * + * @param module name of program owner module + * @param name unique name of program (module+name is used as key for OpenCL program caching) + * @param binary buffer address. See buffer lifetime requirement in description. + * @param size buffer size + * @param buildOptions additional program-related build options passed to clBuildProgram() + * (these options are added automatically: '-x spir' and '-spir-std=1.2') + * @return created ProgramSource object. + */ + static ProgramSource fromSPIR(const String& module, const String& name, + const unsigned char* binary, const size_t size, + const cv::String& buildOptions = cv::String()); + + //OpenCL 2.1+ only + //static Program fromSPIRV(const String& module, const String& name, + // const unsigned char* binary, const size_t size, + // const cv::String& buildOptions = cv::String()); + + struct Impl; friend struct Impl; + inline Impl* getImpl() const { return (Impl*)p; } + inline bool empty() const { return !p; } +protected: + Impl* p; +}; + +class CV_EXPORTS PlatformInfo +{ +public: + PlatformInfo() CV_NOEXCEPT; + /** + * @param id pointer cl_platform_id (cl_platform_id*) + */ + explicit PlatformInfo(void* id); + ~PlatformInfo(); + + PlatformInfo(const PlatformInfo& i); + PlatformInfo& operator =(const PlatformInfo& i); + PlatformInfo(PlatformInfo&& i) CV_NOEXCEPT; + PlatformInfo& operator = (PlatformInfo&& i) CV_NOEXCEPT; + + String name() const; + String vendor() const; + + /// See CL_PLATFORM_VERSION + String version() const; + int versionMajor() const; + int versionMinor() const; + + int deviceNumber() const; + void getDevice(Device& device, int d) const; + + struct Impl; + bool empty() const { return !p; } +protected: + Impl* p; +}; + +CV_EXPORTS const char* convertTypeStr(int sdepth, int ddepth, int cn, char* buf); +CV_EXPORTS const char* typeToStr(int t); +CV_EXPORTS const char* memopTypeToStr(int t); +CV_EXPORTS const char* vecopTypeToStr(int t); +CV_EXPORTS const char* getOpenCLErrorString(int errorCode); +CV_EXPORTS String kernelToStr(InputArray _kernel, int ddepth = -1, const char * name = NULL); +CV_EXPORTS void getPlatfomsInfo(std::vector& platform_info); + + +enum OclVectorStrategy +{ + // all matrices have its own vector width + OCL_VECTOR_OWN = 0, + // all matrices have maximal vector width among all matrices + // (useful for cases when matrices have different data types) + OCL_VECTOR_MAX = 1, + + // default strategy + OCL_VECTOR_DEFAULT = OCL_VECTOR_OWN +}; + +CV_EXPORTS int predictOptimalVectorWidth(InputArray src1, InputArray src2 = noArray(), InputArray src3 = noArray(), + InputArray src4 = noArray(), InputArray src5 = noArray(), InputArray src6 = noArray(), + InputArray src7 = noArray(), InputArray src8 = noArray(), InputArray src9 = noArray(), + OclVectorStrategy strat = OCL_VECTOR_DEFAULT); + +CV_EXPORTS int checkOptimalVectorWidth(const int *vectorWidths, + InputArray src1, InputArray src2 = noArray(), InputArray src3 = noArray(), + InputArray src4 = noArray(), InputArray src5 = noArray(), InputArray src6 = noArray(), + InputArray src7 = noArray(), InputArray src8 = noArray(), InputArray src9 = noArray(), + OclVectorStrategy strat = OCL_VECTOR_DEFAULT); + +// with OCL_VECTOR_MAX strategy +CV_EXPORTS int predictOptimalVectorWidthMax(InputArray src1, InputArray src2 = noArray(), InputArray src3 = noArray(), + InputArray src4 = noArray(), InputArray src5 = noArray(), InputArray src6 = noArray(), + InputArray src7 = noArray(), InputArray src8 = noArray(), InputArray src9 = noArray()); + +CV_EXPORTS void buildOptionsAddMatrixDescription(String& buildOptions, const String& name, InputArray _m); + +class CV_EXPORTS Image2D +{ +public: + Image2D() CV_NOEXCEPT; + + /** + @param src UMat object from which to get image properties and data + @param norm flag to enable the use of normalized channel data types + @param alias flag indicating that the image should alias the src UMat. If true, changes to the + image or src will be reflected in both objects. + */ + explicit Image2D(const UMat &src, bool norm = false, bool alias = false); + Image2D(const Image2D & i); + ~Image2D(); + + Image2D & operator = (const Image2D & i); + Image2D(Image2D &&) CV_NOEXCEPT; + Image2D &operator=(Image2D &&) CV_NOEXCEPT; + + /** Indicates if creating an aliased image should succeed. + Depends on the underlying platform and the dimensions of the UMat. + */ + static bool canCreateAlias(const UMat &u); + + /** Indicates if the image format is supported. + */ + static bool isFormatSupported(int depth, int cn, bool norm); + + void* ptr() const; +protected: + struct Impl; + Impl* p; +}; + +class CV_EXPORTS Timer +{ +public: + Timer(const Queue& q); + ~Timer(); + void start(); + void stop(); + + uint64 durationNS() const; //< duration in nanoseconds + +protected: + struct Impl; + Impl* const p; + +private: + Timer(const Timer&); // disabled + Timer& operator=(const Timer&); // disabled +}; + +CV_EXPORTS MatAllocator* getOpenCLAllocator(); + + +class CV_EXPORTS_W OpenCLExecutionContext +{ +public: + OpenCLExecutionContext() = default; + ~OpenCLExecutionContext() = default; + + OpenCLExecutionContext(const OpenCLExecutionContext&) = default; + OpenCLExecutionContext(OpenCLExecutionContext&&) = default; + + OpenCLExecutionContext& operator=(const OpenCLExecutionContext&) = default; + OpenCLExecutionContext& operator=(OpenCLExecutionContext&&) = default; + + /** Get associated ocl::Context */ + Context& getContext() const; + /** Get the single default associated ocl::Device */ + Device& getDevice() const; + /** Get the single ocl::Queue that is associated with the ocl::Context and + * the single default ocl::Device + */ + Queue& getQueue() const; + + bool useOpenCL() const; + void setUseOpenCL(bool flag); + + /** Get OpenCL execution context of current thread. + * + * Initialize OpenCL execution context if it is empty + * - create new + * - reuse context of the main thread (threadID = 0) + */ + static OpenCLExecutionContext& getCurrent(); + + /** Get OpenCL execution context of current thread (can be empty) */ + static OpenCLExecutionContext& getCurrentRef(); + + /** Bind this OpenCL execution context to current thread. + * + * Context can't be empty. + * + * @note clFinish is not called for queue of previous execution context + */ + void bind() const; + + /** Creates new execution context with same OpenCV context and device + * + * @param q OpenCL queue + */ + OpenCLExecutionContext cloneWithNewQueue(const ocl::Queue& q) const; + /** @overload */ + OpenCLExecutionContext cloneWithNewQueue() const; + + /** @brief Creates OpenCL execution context + * OpenCV will check if available OpenCL platform has platformName name, + * then assign context to OpenCV. + * The deviceID device will be used as target device and a new command queue will be created. + * + * @note On success, ownership of one reference of the context and device is taken. + * The caller should additionally call `clRetainContext` and/or `clRetainDevice` + * to increase the reference count if it wishes to continue using them. + * + * @param platformName name of OpenCL platform to attach, this string is used to check if platform is available to OpenCV at runtime + * @param platformID ID of platform attached context was created for (cl_platform_id) + * @param context OpenCL context to be attached to OpenCV (cl_context) + * @param deviceID OpenCL device (cl_device_id) + */ + static OpenCLExecutionContext create(const std::string& platformName, void* platformID, void* context, void* deviceID); + + /** @brief Creates OpenCL execution context + * + * @param context non-empty OpenCL context + * @param device non-empty OpenCL device (must be a part of context) + * @param queue non-empty OpenCL queue for provided context and device + */ + static OpenCLExecutionContext create(const Context& context, const Device& device, const ocl::Queue& queue); + /** @overload */ + static OpenCLExecutionContext create(const Context& context, const Device& device); + + struct Impl; + inline bool empty() const { return !p; } + void release(); +protected: + std::shared_ptr p; +}; + +class OpenCLExecutionContextScope +{ + OpenCLExecutionContext ctx_; +public: + inline OpenCLExecutionContextScope(const OpenCLExecutionContext& ctx) + { + CV_Assert(!ctx.empty()); + ctx_ = OpenCLExecutionContext::getCurrentRef(); + ctx.bind(); + } + + inline ~OpenCLExecutionContextScope() + { + if (!ctx_.empty()) + { + ctx_.bind(); + } + } +}; + +#ifdef __OPENCV_BUILD +namespace internal { + +CV_EXPORTS bool isOpenCLForced(); +#define OCL_FORCE_CHECK(condition) (cv::ocl::internal::isOpenCLForced() || (condition)) + +CV_EXPORTS bool isPerformanceCheckBypassed(); +#define OCL_PERFORMANCE_CHECK(condition) (cv::ocl::internal::isPerformanceCheckBypassed() || (condition)) + +CV_EXPORTS bool isCLBuffer(UMat& u); + +} // namespace internal +#endif + +//! @} + +}} + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/ocl_genbase.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/ocl_genbase.hpp new file mode 100644 index 0000000..5334cf1 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/ocl_genbase.hpp @@ -0,0 +1,69 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 OpenCV Foundation 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. +// +//M*/ + +#ifndef OPENCV_OPENCL_GENBASE_HPP +#define OPENCV_OPENCL_GENBASE_HPP + +//! @cond IGNORED + +namespace cv { +namespace ocl { + +class ProgramSource; + +namespace internal { + +struct CV_EXPORTS ProgramEntry +{ + const char* module; + const char* name; + const char* programCode; + const char* programHash; + ProgramSource* pProgramSource; + + operator ProgramSource& () const; +}; + +} } } // namespace + +//! @endcond + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/ocl_defs.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/ocl_defs.hpp new file mode 100644 index 0000000..14df750 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/ocl_defs.hpp @@ -0,0 +1,82 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +// Copyright (C) 2014, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. + +#ifndef OPENCV_CORE_OPENCL_DEFS_HPP +#define OPENCV_CORE_OPENCL_DEFS_HPP + +#include "opencv2/core/utility.hpp" +#include "cvconfig.h" + +namespace cv { namespace ocl { +#ifdef HAVE_OPENCL +/// Call is similar to useOpenCL() but doesn't try to load OpenCL runtime or create OpenCL context +CV_EXPORTS bool isOpenCLActivated(); +#else +static inline bool isOpenCLActivated() { return false; } +#endif +}} // namespace + + +//#define CV_OPENCL_RUN_ASSERT + +#ifdef HAVE_OPENCL + +#ifdef CV_OPENCL_RUN_VERBOSE +#define CV_OCL_RUN_(condition, func, ...) \ + { \ + if (cv::ocl::isOpenCLActivated() && (condition) && func) \ + { \ + printf("%s: OpenCL implementation is running\n", CV_Func); \ + fflush(stdout); \ + CV_IMPL_ADD(CV_IMPL_OCL); \ + return __VA_ARGS__; \ + } \ + else \ + { \ + printf("%s: Plain implementation is running\n", CV_Func); \ + fflush(stdout); \ + } \ + } +#elif defined CV_OPENCL_RUN_ASSERT +#define CV_OCL_RUN_(condition, func, ...) \ + { \ + if (cv::ocl::isOpenCLActivated() && (condition)) \ + { \ + if(func) \ + { \ + CV_IMPL_ADD(CV_IMPL_OCL); \ + } \ + else \ + { \ + CV_Error(cv::Error::StsAssert, #func); \ + } \ + return __VA_ARGS__; \ + } \ + } +#else +#define CV_OCL_RUN_(condition, func, ...) \ +try \ +{ \ + if (cv::ocl::isOpenCLActivated() && (condition) && func) \ + { \ + CV_IMPL_ADD(CV_IMPL_OCL); \ + return __VA_ARGS__; \ + } \ +} \ +catch (const cv::Exception& e) \ +{ \ + CV_UNUSED(e); /* TODO: Add some logging here */ \ +} +#endif + +#else +#define CV_OCL_RUN_(condition, func, ...) +#endif + +#define CV_OCL_RUN(condition, func) CV_OCL_RUN_(condition, func) + +#endif // OPENCV_CORE_OPENCL_DEFS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/opencl_info.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/opencl_info.hpp new file mode 100644 index 0000000..3ead76e --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/opencl_info.hpp @@ -0,0 +1,212 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#include + +#include +#include + +#ifndef DUMP_CONFIG_PROPERTY +#define DUMP_CONFIG_PROPERTY(...) +#endif + +#ifndef DUMP_MESSAGE_STDOUT +#define DUMP_MESSAGE_STDOUT(...) do { std::cout << __VA_ARGS__ << std::endl; } while (false) +#endif + +namespace cv { + +namespace { +static std::string bytesToStringRepr(size_t value) +{ + size_t b = value % 1024; + value /= 1024; + + size_t kb = value % 1024; + value /= 1024; + + size_t mb = value % 1024; + value /= 1024; + + size_t gb = value; + + std::ostringstream stream; + + if (gb > 0) + stream << gb << " GB "; + if (mb > 0) + stream << mb << " MB "; + if (kb > 0) + stream << kb << " KB "; + if (b > 0) + stream << b << " B"; + + std::string s = stream.str(); + if (s[s.size() - 1] == ' ') + s = s.substr(0, s.size() - 1); + return s; +} + +static String getDeviceTypeString(const cv::ocl::Device& device) +{ + if (device.type() == cv::ocl::Device::TYPE_CPU) { + return "CPU"; + } + + if (device.type() == cv::ocl::Device::TYPE_GPU) { + if (device.hostUnifiedMemory()) { + return "iGPU"; + } else { + return "dGPU"; + } + } + + return "unknown"; +} +} // namespace + +static void dumpOpenCLInformation() +{ + using namespace cv::ocl; + + try + { + if (!haveOpenCL() || !useOpenCL()) + { + DUMP_MESSAGE_STDOUT("OpenCL is disabled"); + DUMP_CONFIG_PROPERTY("cv_ocl", "disabled"); + return; + } + + std::vector platforms; + cv::ocl::getPlatfomsInfo(platforms); + if (platforms.empty()) + { + DUMP_MESSAGE_STDOUT("OpenCL is not available"); + DUMP_CONFIG_PROPERTY("cv_ocl", "not available"); + return; + } + + DUMP_MESSAGE_STDOUT("OpenCL Platforms: "); + for (size_t i = 0; i < platforms.size(); i++) + { + const PlatformInfo* platform = &platforms[i]; + DUMP_MESSAGE_STDOUT(" " << platform->name()); + Device current_device; + for (int j = 0; j < platform->deviceNumber(); j++) + { + platform->getDevice(current_device, j); + String deviceTypeStr = getDeviceTypeString(current_device); + DUMP_MESSAGE_STDOUT( " " << deviceTypeStr << ": " << current_device.name() << " (" << current_device.version() << ")"); + DUMP_CONFIG_PROPERTY( cv::format("cv_ocl_platform_%d_device_%d", (int)i, j ), + cv::format("(Platform=%s)(Type=%s)(Name=%s)(Version=%s)", + platform->name().c_str(), deviceTypeStr.c_str(), current_device.name().c_str(), current_device.version().c_str()) ); + } + } + const Device& device = Device::getDefault(); + if (!device.available()) + CV_Error(Error::OpenCLInitError, "OpenCL device is not available"); + + DUMP_MESSAGE_STDOUT("Current OpenCL device: "); + + String deviceTypeStr = getDeviceTypeString(device); + DUMP_MESSAGE_STDOUT(" Type = " << deviceTypeStr); + DUMP_CONFIG_PROPERTY("cv_ocl_current_deviceType", deviceTypeStr); + + DUMP_MESSAGE_STDOUT(" Name = " << device.name()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_deviceName", device.name()); + + DUMP_MESSAGE_STDOUT(" Version = " << device.version()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_deviceVersion", device.version()); + + DUMP_MESSAGE_STDOUT(" Driver version = " << device.driverVersion()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_driverVersion", device.driverVersion()); + + DUMP_MESSAGE_STDOUT(" Address bits = " << device.addressBits()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_addressBits", device.addressBits()); + + DUMP_MESSAGE_STDOUT(" Compute units = " << device.maxComputeUnits()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_maxComputeUnits", device.maxComputeUnits()); + + DUMP_MESSAGE_STDOUT(" Max work group size = " << device.maxWorkGroupSize()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_maxWorkGroupSize", device.maxWorkGroupSize()); + + std::string localMemorySizeStr = bytesToStringRepr(device.localMemSize()); + DUMP_MESSAGE_STDOUT(" Local memory size = " << localMemorySizeStr); + DUMP_CONFIG_PROPERTY("cv_ocl_current_localMemSize", device.localMemSize()); + + std::string maxMemAllocSizeStr = bytesToStringRepr(device.maxMemAllocSize()); + DUMP_MESSAGE_STDOUT(" Max memory allocation size = " << maxMemAllocSizeStr); + DUMP_CONFIG_PROPERTY("cv_ocl_current_maxMemAllocSize", device.maxMemAllocSize()); + + const char* doubleSupportStr = device.doubleFPConfig() > 0 ? "Yes" : "No"; + DUMP_MESSAGE_STDOUT(" Double support = " << doubleSupportStr); + DUMP_CONFIG_PROPERTY("cv_ocl_current_haveDoubleSupport", device.doubleFPConfig() > 0); + + const char* halfSupportStr = device.halfFPConfig() > 0 ? "Yes" : "No"; + DUMP_MESSAGE_STDOUT(" Half support = " << halfSupportStr); + DUMP_CONFIG_PROPERTY("cv_ocl_current_haveHalfSupport", device.halfFPConfig() > 0); + + const char* isUnifiedMemoryStr = device.hostUnifiedMemory() ? "Yes" : "No"; + DUMP_MESSAGE_STDOUT(" Host unified memory = " << isUnifiedMemoryStr); + DUMP_CONFIG_PROPERTY("cv_ocl_current_hostUnifiedMemory", device.hostUnifiedMemory()); + + DUMP_MESSAGE_STDOUT(" Device extensions:"); + String extensionsStr = device.extensions(); + size_t pos = 0; + while (pos < extensionsStr.size()) + { + size_t pos2 = extensionsStr.find(' ', pos); + if (pos2 == String::npos) + pos2 = extensionsStr.size(); + if (pos2 > pos) + { + String extensionName = extensionsStr.substr(pos, pos2 - pos); + DUMP_MESSAGE_STDOUT(" " << extensionName); + } + pos = pos2 + 1; + } + DUMP_CONFIG_PROPERTY("cv_ocl_current_extensions", extensionsStr); + + const char* haveAmdBlasStr = haveAmdBlas() ? "Yes" : "No"; + DUMP_MESSAGE_STDOUT(" Has AMD Blas = " << haveAmdBlasStr); + DUMP_CONFIG_PROPERTY("cv_ocl_current_AmdBlas", haveAmdBlas()); + + const char* haveAmdFftStr = haveAmdFft() ? "Yes" : "No"; + DUMP_MESSAGE_STDOUT(" Has AMD Fft = " << haveAmdFftStr); + DUMP_CONFIG_PROPERTY("cv_ocl_current_AmdFft", haveAmdFft()); + + + DUMP_MESSAGE_STDOUT(" Preferred vector width char = " << device.preferredVectorWidthChar()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_preferredVectorWidthChar", device.preferredVectorWidthChar()); + + DUMP_MESSAGE_STDOUT(" Preferred vector width short = " << device.preferredVectorWidthShort()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_preferredVectorWidthShort", device.preferredVectorWidthShort()); + + DUMP_MESSAGE_STDOUT(" Preferred vector width int = " << device.preferredVectorWidthInt()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_preferredVectorWidthInt", device.preferredVectorWidthInt()); + + DUMP_MESSAGE_STDOUT(" Preferred vector width long = " << device.preferredVectorWidthLong()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_preferredVectorWidthLong", device.preferredVectorWidthLong()); + + DUMP_MESSAGE_STDOUT(" Preferred vector width float = " << device.preferredVectorWidthFloat()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_preferredVectorWidthFloat", device.preferredVectorWidthFloat()); + + DUMP_MESSAGE_STDOUT(" Preferred vector width double = " << device.preferredVectorWidthDouble()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_preferredVectorWidthDouble", device.preferredVectorWidthDouble()); + + DUMP_MESSAGE_STDOUT(" Preferred vector width half = " << device.preferredVectorWidthHalf()); + DUMP_CONFIG_PROPERTY("cv_ocl_current_preferredVectorWidthHalf", device.preferredVectorWidthHalf()); + } + catch (...) + { + DUMP_MESSAGE_STDOUT("Exception. Can't dump OpenCL info"); + DUMP_MESSAGE_STDOUT("OpenCL device not available"); + DUMP_CONFIG_PROPERTY("cv_ocl", "not available"); + } +} +#undef DUMP_MESSAGE_STDOUT +#undef DUMP_CONFIG_PROPERTY + +} // namespace diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/opencl_svm.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/opencl_svm.hpp new file mode 100644 index 0000000..7453082 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/opencl_svm.hpp @@ -0,0 +1,81 @@ +/* See LICENSE file in the root OpenCV directory */ + +#ifndef OPENCV_CORE_OPENCL_SVM_HPP +#define OPENCV_CORE_OPENCL_SVM_HPP + +// +// Internal usage only (binary compatibility is not guaranteed) +// +#ifndef __OPENCV_BUILD +#error Internal header file +#endif + +#if defined(HAVE_OPENCL) && defined(HAVE_OPENCL_SVM) +#include "runtime/opencl_core.hpp" +#include "runtime/opencl_svm_20.hpp" +#include "runtime/opencl_svm_hsa_extension.hpp" + +namespace cv { namespace ocl { namespace svm { + +struct SVMCapabilities +{ + enum Value + { + SVM_COARSE_GRAIN_BUFFER = (1 << 0), + SVM_FINE_GRAIN_BUFFER = (1 << 1), + SVM_FINE_GRAIN_SYSTEM = (1 << 2), + SVM_ATOMICS = (1 << 3), + }; + int value_; + + SVMCapabilities(int capabilities = 0) : value_(capabilities) { } + operator int() const { return value_; } + + inline bool isNoSVMSupport() const { return value_ == 0; } + inline bool isSupportCoarseGrainBuffer() const { return (value_ & SVM_COARSE_GRAIN_BUFFER) != 0; } + inline bool isSupportFineGrainBuffer() const { return (value_ & SVM_FINE_GRAIN_BUFFER) != 0; } + inline bool isSupportFineGrainSystem() const { return (value_ & SVM_FINE_GRAIN_SYSTEM) != 0; } + inline bool isSupportAtomics() const { return (value_ & SVM_ATOMICS) != 0; } +}; + +CV_EXPORTS const SVMCapabilities getSVMCapabilitites(const ocl::Context& context); + +struct SVMFunctions +{ + clSVMAllocAMD_fn fn_clSVMAlloc; + clSVMFreeAMD_fn fn_clSVMFree; + clSetKernelArgSVMPointerAMD_fn fn_clSetKernelArgSVMPointer; + //clSetKernelExecInfoAMD_fn fn_clSetKernelExecInfo; + //clEnqueueSVMFreeAMD_fn fn_clEnqueueSVMFree; + clEnqueueSVMMemcpyAMD_fn fn_clEnqueueSVMMemcpy; + clEnqueueSVMMemFillAMD_fn fn_clEnqueueSVMMemFill; + clEnqueueSVMMapAMD_fn fn_clEnqueueSVMMap; + clEnqueueSVMUnmapAMD_fn fn_clEnqueueSVMUnmap; + + inline SVMFunctions() + : fn_clSVMAlloc(NULL), fn_clSVMFree(NULL), + fn_clSetKernelArgSVMPointer(NULL), /*fn_clSetKernelExecInfo(NULL),*/ + /*fn_clEnqueueSVMFree(NULL),*/ fn_clEnqueueSVMMemcpy(NULL), fn_clEnqueueSVMMemFill(NULL), + fn_clEnqueueSVMMap(NULL), fn_clEnqueueSVMUnmap(NULL) + { + // nothing + } + + inline bool isValid() const + { + return fn_clSVMAlloc != NULL && fn_clSVMFree && fn_clSetKernelArgSVMPointer && + /*fn_clSetKernelExecInfo && fn_clEnqueueSVMFree &&*/ fn_clEnqueueSVMMemcpy && + fn_clEnqueueSVMMemFill && fn_clEnqueueSVMMap && fn_clEnqueueSVMUnmap; + } +}; + +// We should guarantee that SVMFunctions lifetime is not less than context's lifetime +CV_EXPORTS const SVMFunctions* getSVMFunctions(const ocl::Context& context); + +CV_EXPORTS bool useSVM(UMatUsageFlags usageFlags); + +}}} //namespace cv::ocl::svm +#endif + +#endif // OPENCV_CORE_OPENCL_SVM_HPP +/* End of file. */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_clblas.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_clblas.hpp new file mode 100644 index 0000000..2749927 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_clblas.hpp @@ -0,0 +1,602 @@ +// +// AUTOGENERATED, DO NOT EDIT +// +#ifndef OPENCV_CORE_OCL_RUNTIME_CLAMDBLAS_HPP +#error "Invalid usage" +#endif + +// generated by parser_clblas.py +#define clblasCaxpy clblasCaxpy_ +#define clblasCcopy clblasCcopy_ +#define clblasCdotc clblasCdotc_ +#define clblasCdotu clblasCdotu_ +#define clblasCgbmv clblasCgbmv_ +#define clblasCgemm clblasCgemm_ +#define clblasCgemv clblasCgemv_ +#define clblasCgerc clblasCgerc_ +#define clblasCgeru clblasCgeru_ +#define clblasChbmv clblasChbmv_ +#define clblasChemm clblasChemm_ +#define clblasChemv clblasChemv_ +#define clblasCher clblasCher_ +#define clblasCher2 clblasCher2_ +#define clblasCher2k clblasCher2k_ +#define clblasCherk clblasCherk_ +#define clblasChpmv clblasChpmv_ +#define clblasChpr clblasChpr_ +#define clblasChpr2 clblasChpr2_ +#define clblasCrotg clblasCrotg_ +#define clblasCscal clblasCscal_ +#define clblasCsrot clblasCsrot_ +#define clblasCsscal clblasCsscal_ +#define clblasCswap clblasCswap_ +#define clblasCsymm clblasCsymm_ +#define clblasCsyr2k clblasCsyr2k_ +#define clblasCsyrk clblasCsyrk_ +#define clblasCtbmv clblasCtbmv_ +#define clblasCtbsv clblasCtbsv_ +#define clblasCtpmv clblasCtpmv_ +#define clblasCtpsv clblasCtpsv_ +#define clblasCtrmm clblasCtrmm_ +#define clblasCtrmv clblasCtrmv_ +#define clblasCtrsm clblasCtrsm_ +#define clblasCtrsv clblasCtrsv_ +#define clblasDasum clblasDasum_ +#define clblasDaxpy clblasDaxpy_ +#define clblasDcopy clblasDcopy_ +#define clblasDdot clblasDdot_ +#define clblasDgbmv clblasDgbmv_ +#define clblasDgemm clblasDgemm_ +#define clblasDgemv clblasDgemv_ +#define clblasDger clblasDger_ +#define clblasDnrm2 clblasDnrm2_ +#define clblasDrot clblasDrot_ +#define clblasDrotg clblasDrotg_ +#define clblasDrotm clblasDrotm_ +#define clblasDrotmg clblasDrotmg_ +#define clblasDsbmv clblasDsbmv_ +#define clblasDscal clblasDscal_ +#define clblasDspmv clblasDspmv_ +#define clblasDspr clblasDspr_ +#define clblasDspr2 clblasDspr2_ +#define clblasDswap clblasDswap_ +#define clblasDsymm clblasDsymm_ +#define clblasDsymv clblasDsymv_ +#define clblasDsyr clblasDsyr_ +#define clblasDsyr2 clblasDsyr2_ +#define clblasDsyr2k clblasDsyr2k_ +#define clblasDsyrk clblasDsyrk_ +#define clblasDtbmv clblasDtbmv_ +#define clblasDtbsv clblasDtbsv_ +#define clblasDtpmv clblasDtpmv_ +#define clblasDtpsv clblasDtpsv_ +#define clblasDtrmm clblasDtrmm_ +#define clblasDtrmv clblasDtrmv_ +#define clblasDtrsm clblasDtrsm_ +#define clblasDtrsv clblasDtrsv_ +#define clblasDzasum clblasDzasum_ +#define clblasDznrm2 clblasDznrm2_ +#define clblasGetVersion clblasGetVersion_ +#define clblasSasum clblasSasum_ +#define clblasSaxpy clblasSaxpy_ +#define clblasScasum clblasScasum_ +#define clblasScnrm2 clblasScnrm2_ +#define clblasScopy clblasScopy_ +#define clblasSdot clblasSdot_ +#define clblasSetup clblasSetup_ +#define clblasSgbmv clblasSgbmv_ +#define clblasSgemm clblasSgemm_ +#define clblasSgemv clblasSgemv_ +#define clblasSger clblasSger_ +#define clblasSnrm2 clblasSnrm2_ +#define clblasSrot clblasSrot_ +#define clblasSrotg clblasSrotg_ +#define clblasSrotm clblasSrotm_ +#define clblasSrotmg clblasSrotmg_ +#define clblasSsbmv clblasSsbmv_ +#define clblasSscal clblasSscal_ +#define clblasSspmv clblasSspmv_ +#define clblasSspr clblasSspr_ +#define clblasSspr2 clblasSspr2_ +#define clblasSswap clblasSswap_ +#define clblasSsymm clblasSsymm_ +#define clblasSsymv clblasSsymv_ +#define clblasSsyr clblasSsyr_ +#define clblasSsyr2 clblasSsyr2_ +#define clblasSsyr2k clblasSsyr2k_ +#define clblasSsyrk clblasSsyrk_ +#define clblasStbmv clblasStbmv_ +#define clblasStbsv clblasStbsv_ +#define clblasStpmv clblasStpmv_ +#define clblasStpsv clblasStpsv_ +#define clblasStrmm clblasStrmm_ +#define clblasStrmv clblasStrmv_ +#define clblasStrsm clblasStrsm_ +#define clblasStrsv clblasStrsv_ +#define clblasTeardown clblasTeardown_ +#define clblasZaxpy clblasZaxpy_ +#define clblasZcopy clblasZcopy_ +#define clblasZdotc clblasZdotc_ +#define clblasZdotu clblasZdotu_ +#define clblasZdrot clblasZdrot_ +#define clblasZdscal clblasZdscal_ +#define clblasZgbmv clblasZgbmv_ +#define clblasZgemm clblasZgemm_ +#define clblasZgemv clblasZgemv_ +#define clblasZgerc clblasZgerc_ +#define clblasZgeru clblasZgeru_ +#define clblasZhbmv clblasZhbmv_ +#define clblasZhemm clblasZhemm_ +#define clblasZhemv clblasZhemv_ +#define clblasZher clblasZher_ +#define clblasZher2 clblasZher2_ +#define clblasZher2k clblasZher2k_ +#define clblasZherk clblasZherk_ +#define clblasZhpmv clblasZhpmv_ +#define clblasZhpr clblasZhpr_ +#define clblasZhpr2 clblasZhpr2_ +#define clblasZrotg clblasZrotg_ +#define clblasZscal clblasZscal_ +#define clblasZswap clblasZswap_ +#define clblasZsymm clblasZsymm_ +#define clblasZsyr2k clblasZsyr2k_ +#define clblasZsyrk clblasZsyrk_ +#define clblasZtbmv clblasZtbmv_ +#define clblasZtbsv clblasZtbsv_ +#define clblasZtpmv clblasZtpmv_ +#define clblasZtpsv clblasZtpsv_ +#define clblasZtrmm clblasZtrmm_ +#define clblasZtrmv clblasZtrmv_ +#define clblasZtrsm clblasZtrsm_ +#define clblasZtrsv clblasZtrsv_ +#define clblasiCamax clblasiCamax_ +#define clblasiDamax clblasiDamax_ +#define clblasiSamax clblasiSamax_ +#define clblasiZamax clblasiZamax_ + +#include + +// generated by parser_clblas.py +#undef clblasCaxpy +//#define clblasCaxpy clblasCaxpy_pfn +#undef clblasCcopy +//#define clblasCcopy clblasCcopy_pfn +#undef clblasCdotc +//#define clblasCdotc clblasCdotc_pfn +#undef clblasCdotu +//#define clblasCdotu clblasCdotu_pfn +#undef clblasCgbmv +//#define clblasCgbmv clblasCgbmv_pfn +#undef clblasCgemm +#define clblasCgemm clblasCgemm_pfn +#undef clblasCgemv +//#define clblasCgemv clblasCgemv_pfn +#undef clblasCgerc +//#define clblasCgerc clblasCgerc_pfn +#undef clblasCgeru +//#define clblasCgeru clblasCgeru_pfn +#undef clblasChbmv +//#define clblasChbmv clblasChbmv_pfn +#undef clblasChemm +//#define clblasChemm clblasChemm_pfn +#undef clblasChemv +//#define clblasChemv clblasChemv_pfn +#undef clblasCher +//#define clblasCher clblasCher_pfn +#undef clblasCher2 +//#define clblasCher2 clblasCher2_pfn +#undef clblasCher2k +//#define clblasCher2k clblasCher2k_pfn +#undef clblasCherk +//#define clblasCherk clblasCherk_pfn +#undef clblasChpmv +//#define clblasChpmv clblasChpmv_pfn +#undef clblasChpr +//#define clblasChpr clblasChpr_pfn +#undef clblasChpr2 +//#define clblasChpr2 clblasChpr2_pfn +#undef clblasCrotg +//#define clblasCrotg clblasCrotg_pfn +#undef clblasCscal +//#define clblasCscal clblasCscal_pfn +#undef clblasCsrot +//#define clblasCsrot clblasCsrot_pfn +#undef clblasCsscal +//#define clblasCsscal clblasCsscal_pfn +#undef clblasCswap +//#define clblasCswap clblasCswap_pfn +#undef clblasCsymm +//#define clblasCsymm clblasCsymm_pfn +#undef clblasCsyr2k +//#define clblasCsyr2k clblasCsyr2k_pfn +#undef clblasCsyrk +//#define clblasCsyrk clblasCsyrk_pfn +#undef clblasCtbmv +//#define clblasCtbmv clblasCtbmv_pfn +#undef clblasCtbsv +//#define clblasCtbsv clblasCtbsv_pfn +#undef clblasCtpmv +//#define clblasCtpmv clblasCtpmv_pfn +#undef clblasCtpsv +//#define clblasCtpsv clblasCtpsv_pfn +#undef clblasCtrmm +//#define clblasCtrmm clblasCtrmm_pfn +#undef clblasCtrmv +//#define clblasCtrmv clblasCtrmv_pfn +#undef clblasCtrsm +//#define clblasCtrsm clblasCtrsm_pfn +#undef clblasCtrsv +//#define clblasCtrsv clblasCtrsv_pfn +#undef clblasDasum +//#define clblasDasum clblasDasum_pfn +#undef clblasDaxpy +//#define clblasDaxpy clblasDaxpy_pfn +#undef clblasDcopy +//#define clblasDcopy clblasDcopy_pfn +#undef clblasDdot +//#define clblasDdot clblasDdot_pfn +#undef clblasDgbmv +//#define clblasDgbmv clblasDgbmv_pfn +#undef clblasDgemm +#define clblasDgemm clblasDgemm_pfn +#undef clblasDgemv +//#define clblasDgemv clblasDgemv_pfn +#undef clblasDger +//#define clblasDger clblasDger_pfn +#undef clblasDnrm2 +//#define clblasDnrm2 clblasDnrm2_pfn +#undef clblasDrot +//#define clblasDrot clblasDrot_pfn +#undef clblasDrotg +//#define clblasDrotg clblasDrotg_pfn +#undef clblasDrotm +//#define clblasDrotm clblasDrotm_pfn +#undef clblasDrotmg +//#define clblasDrotmg clblasDrotmg_pfn +#undef clblasDsbmv +//#define clblasDsbmv clblasDsbmv_pfn +#undef clblasDscal +//#define clblasDscal clblasDscal_pfn +#undef clblasDspmv +//#define clblasDspmv clblasDspmv_pfn +#undef clblasDspr +//#define clblasDspr clblasDspr_pfn +#undef clblasDspr2 +//#define clblasDspr2 clblasDspr2_pfn +#undef clblasDswap +//#define clblasDswap clblasDswap_pfn +#undef clblasDsymm +//#define clblasDsymm clblasDsymm_pfn +#undef clblasDsymv +//#define clblasDsymv clblasDsymv_pfn +#undef clblasDsyr +//#define clblasDsyr clblasDsyr_pfn +#undef clblasDsyr2 +//#define clblasDsyr2 clblasDsyr2_pfn +#undef clblasDsyr2k +//#define clblasDsyr2k clblasDsyr2k_pfn +#undef clblasDsyrk +//#define clblasDsyrk clblasDsyrk_pfn +#undef clblasDtbmv +//#define clblasDtbmv clblasDtbmv_pfn +#undef clblasDtbsv +//#define clblasDtbsv clblasDtbsv_pfn +#undef clblasDtpmv +//#define clblasDtpmv clblasDtpmv_pfn +#undef clblasDtpsv +//#define clblasDtpsv clblasDtpsv_pfn +#undef clblasDtrmm +//#define clblasDtrmm clblasDtrmm_pfn +#undef clblasDtrmv +//#define clblasDtrmv clblasDtrmv_pfn +#undef clblasDtrsm +//#define clblasDtrsm clblasDtrsm_pfn +#undef clblasDtrsv +//#define clblasDtrsv clblasDtrsv_pfn +#undef clblasDzasum +//#define clblasDzasum clblasDzasum_pfn +#undef clblasDznrm2 +//#define clblasDznrm2 clblasDznrm2_pfn +#undef clblasGetVersion +//#define clblasGetVersion clblasGetVersion_pfn +#undef clblasSasum +//#define clblasSasum clblasSasum_pfn +#undef clblasSaxpy +//#define clblasSaxpy clblasSaxpy_pfn +#undef clblasScasum +//#define clblasScasum clblasScasum_pfn +#undef clblasScnrm2 +//#define clblasScnrm2 clblasScnrm2_pfn +#undef clblasScopy +//#define clblasScopy clblasScopy_pfn +#undef clblasSdot +//#define clblasSdot clblasSdot_pfn +#undef clblasSetup +#define clblasSetup clblasSetup_pfn +#undef clblasSgbmv +//#define clblasSgbmv clblasSgbmv_pfn +#undef clblasSgemm +#define clblasSgemm clblasSgemm_pfn +#undef clblasSgemv +//#define clblasSgemv clblasSgemv_pfn +#undef clblasSger +//#define clblasSger clblasSger_pfn +#undef clblasSnrm2 +//#define clblasSnrm2 clblasSnrm2_pfn +#undef clblasSrot +//#define clblasSrot clblasSrot_pfn +#undef clblasSrotg +//#define clblasSrotg clblasSrotg_pfn +#undef clblasSrotm +//#define clblasSrotm clblasSrotm_pfn +#undef clblasSrotmg +//#define clblasSrotmg clblasSrotmg_pfn +#undef clblasSsbmv +//#define clblasSsbmv clblasSsbmv_pfn +#undef clblasSscal +//#define clblasSscal clblasSscal_pfn +#undef clblasSspmv +//#define clblasSspmv clblasSspmv_pfn +#undef clblasSspr +//#define clblasSspr clblasSspr_pfn +#undef clblasSspr2 +//#define clblasSspr2 clblasSspr2_pfn +#undef clblasSswap +//#define clblasSswap clblasSswap_pfn +#undef clblasSsymm +//#define clblasSsymm clblasSsymm_pfn +#undef clblasSsymv +//#define clblasSsymv clblasSsymv_pfn +#undef clblasSsyr +//#define clblasSsyr clblasSsyr_pfn +#undef clblasSsyr2 +//#define clblasSsyr2 clblasSsyr2_pfn +#undef clblasSsyr2k +//#define clblasSsyr2k clblasSsyr2k_pfn +#undef clblasSsyrk +//#define clblasSsyrk clblasSsyrk_pfn +#undef clblasStbmv +//#define clblasStbmv clblasStbmv_pfn +#undef clblasStbsv +//#define clblasStbsv clblasStbsv_pfn +#undef clblasStpmv +//#define clblasStpmv clblasStpmv_pfn +#undef clblasStpsv +//#define clblasStpsv clblasStpsv_pfn +#undef clblasStrmm +//#define clblasStrmm clblasStrmm_pfn +#undef clblasStrmv +//#define clblasStrmv clblasStrmv_pfn +#undef clblasStrsm +//#define clblasStrsm clblasStrsm_pfn +#undef clblasStrsv +//#define clblasStrsv clblasStrsv_pfn +#undef clblasTeardown +#define clblasTeardown clblasTeardown_pfn +#undef clblasZaxpy +//#define clblasZaxpy clblasZaxpy_pfn +#undef clblasZcopy +//#define clblasZcopy clblasZcopy_pfn +#undef clblasZdotc +//#define clblasZdotc clblasZdotc_pfn +#undef clblasZdotu +//#define clblasZdotu clblasZdotu_pfn +#undef clblasZdrot +//#define clblasZdrot clblasZdrot_pfn +#undef clblasZdscal +//#define clblasZdscal clblasZdscal_pfn +#undef clblasZgbmv +//#define clblasZgbmv clblasZgbmv_pfn +#undef clblasZgemm +#define clblasZgemm clblasZgemm_pfn +#undef clblasZgemv +//#define clblasZgemv clblasZgemv_pfn +#undef clblasZgerc +//#define clblasZgerc clblasZgerc_pfn +#undef clblasZgeru +//#define clblasZgeru clblasZgeru_pfn +#undef clblasZhbmv +//#define clblasZhbmv clblasZhbmv_pfn +#undef clblasZhemm +//#define clblasZhemm clblasZhemm_pfn +#undef clblasZhemv +//#define clblasZhemv clblasZhemv_pfn +#undef clblasZher +//#define clblasZher clblasZher_pfn +#undef clblasZher2 +//#define clblasZher2 clblasZher2_pfn +#undef clblasZher2k +//#define clblasZher2k clblasZher2k_pfn +#undef clblasZherk +//#define clblasZherk clblasZherk_pfn +#undef clblasZhpmv +//#define clblasZhpmv clblasZhpmv_pfn +#undef clblasZhpr +//#define clblasZhpr clblasZhpr_pfn +#undef clblasZhpr2 +//#define clblasZhpr2 clblasZhpr2_pfn +#undef clblasZrotg +//#define clblasZrotg clblasZrotg_pfn +#undef clblasZscal +//#define clblasZscal clblasZscal_pfn +#undef clblasZswap +//#define clblasZswap clblasZswap_pfn +#undef clblasZsymm +//#define clblasZsymm clblasZsymm_pfn +#undef clblasZsyr2k +//#define clblasZsyr2k clblasZsyr2k_pfn +#undef clblasZsyrk +//#define clblasZsyrk clblasZsyrk_pfn +#undef clblasZtbmv +//#define clblasZtbmv clblasZtbmv_pfn +#undef clblasZtbsv +//#define clblasZtbsv clblasZtbsv_pfn +#undef clblasZtpmv +//#define clblasZtpmv clblasZtpmv_pfn +#undef clblasZtpsv +//#define clblasZtpsv clblasZtpsv_pfn +#undef clblasZtrmm +//#define clblasZtrmm clblasZtrmm_pfn +#undef clblasZtrmv +//#define clblasZtrmv clblasZtrmv_pfn +#undef clblasZtrsm +//#define clblasZtrsm clblasZtrsm_pfn +#undef clblasZtrsv +//#define clblasZtrsv clblasZtrsv_pfn +#undef clblasiCamax +//#define clblasiCamax clblasiCamax_pfn +#undef clblasiDamax +//#define clblasiDamax clblasiDamax_pfn +#undef clblasiSamax +//#define clblasiSamax clblasiSamax_pfn +#undef clblasiZamax +//#define clblasiZamax clblasiZamax_pfn + +// generated by parser_clblas.py +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCaxpy)(size_t N, cl_float2 alpha, const cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCcopy)(size_t N, const cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCdotc)(size_t N, cl_mem dotProduct, size_t offDP, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCdotu)(size_t N, cl_mem dotProduct, size_t offDP, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCgbmv)(clblasOrder order, clblasTranspose trans, size_t M, size_t N, size_t KL, size_t KU, cl_float2 alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem X, size_t offx, int incx, cl_float2 beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +extern CL_RUNTIME_EXPORT clblasStatus (*clblasCgemm)(clblasOrder order, clblasTranspose transA, clblasTranspose transB, size_t M, size_t N, size_t K, FloatComplex alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem B, size_t offB, size_t ldb, FloatComplex beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCgemv)(clblasOrder order, clblasTranspose transA, size_t M, size_t N, FloatComplex alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem x, size_t offx, int incx, FloatComplex beta, cl_mem y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCgerc)(clblasOrder order, size_t M, size_t N, cl_float2 alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCgeru)(clblasOrder order, size_t M, size_t N, cl_float2 alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasChbmv)(clblasOrder order, clblasUplo uplo, size_t N, size_t K, cl_float2 alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem X, size_t offx, int incx, cl_float2 beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasChemm)(clblasOrder order, clblasSide side, clblasUplo uplo, size_t M, size_t N, cl_float2 alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem B, size_t offb, size_t ldb, cl_float2 beta, cl_mem C, size_t offc, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasChemv)(clblasOrder order, clblasUplo uplo, size_t N, FloatComplex alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem X, size_t offx, int incx, FloatComplex beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCher)(clblasOrder order, clblasUplo uplo, size_t N, cl_float alpha, const cl_mem X, size_t offx, int incx, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCher2)(clblasOrder order, clblasUplo uplo, size_t N, cl_float2 alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCher2k)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, size_t N, size_t K, FloatComplex alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem B, size_t offb, size_t ldb, cl_float beta, cl_mem C, size_t offc, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCherk)(clblasOrder order, clblasUplo uplo, clblasTranspose transA, size_t N, size_t K, float alpha, const cl_mem A, size_t offa, size_t lda, float beta, cl_mem C, size_t offc, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasChpmv)(clblasOrder order, clblasUplo uplo, size_t N, cl_float2 alpha, const cl_mem AP, size_t offa, const cl_mem X, size_t offx, int incx, cl_float2 beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasChpr)(clblasOrder order, clblasUplo uplo, size_t N, cl_float alpha, const cl_mem X, size_t offx, int incx, cl_mem AP, size_t offa, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasChpr2)(clblasOrder order, clblasUplo uplo, size_t N, cl_float2 alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem AP, size_t offa, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCrotg)(cl_mem CA, size_t offCA, cl_mem CB, size_t offCB, cl_mem C, size_t offC, cl_mem S, size_t offS, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCscal)(size_t N, cl_float2 alpha, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCsrot)(size_t N, cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_float C, cl_float S, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCsscal)(size_t N, cl_float alpha, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCswap)(size_t N, cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCsymm)(clblasOrder order, clblasSide side, clblasUplo uplo, size_t M, size_t N, cl_float2 alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem B, size_t offb, size_t ldb, cl_float2 beta, cl_mem C, size_t offc, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCsyr2k)(clblasOrder order, clblasUplo uplo, clblasTranspose transAB, size_t N, size_t K, FloatComplex alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem B, size_t offB, size_t ldb, FloatComplex beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCsyrk)(clblasOrder order, clblasUplo uplo, clblasTranspose transA, size_t N, size_t K, FloatComplex alpha, const cl_mem A, size_t offA, size_t lda, FloatComplex beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCtbmv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, size_t K, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCtbsv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, size_t K, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCtpmv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, const cl_mem AP, size_t offa, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCtpsv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, const cl_mem A, size_t offa, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCtrmm)(clblasOrder order, clblasSide side, clblasUplo uplo, clblasTranspose transA, clblasDiag diag, size_t M, size_t N, FloatComplex alpha, const cl_mem A, size_t offA, size_t lda, cl_mem B, size_t offB, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCtrmv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCtrsm)(clblasOrder order, clblasSide side, clblasUplo uplo, clblasTranspose transA, clblasDiag diag, size_t M, size_t N, FloatComplex alpha, const cl_mem A, size_t offA, size_t lda, cl_mem B, size_t offB, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasCtrsv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDasum)(size_t N, cl_mem asum, size_t offAsum, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDaxpy)(size_t N, cl_double alpha, const cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDcopy)(size_t N, const cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDdot)(size_t N, cl_mem dotProduct, size_t offDP, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDgbmv)(clblasOrder order, clblasTranspose trans, size_t M, size_t N, size_t KL, size_t KU, cl_double alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem X, size_t offx, int incx, cl_double beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +extern CL_RUNTIME_EXPORT clblasStatus (*clblasDgemm)(clblasOrder order, clblasTranspose transA, clblasTranspose transB, size_t M, size_t N, size_t K, cl_double alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem B, size_t offB, size_t ldb, cl_double beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDgemv)(clblasOrder order, clblasTranspose transA, size_t M, size_t N, cl_double alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem x, size_t offx, int incx, cl_double beta, cl_mem y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDger)(clblasOrder order, size_t M, size_t N, cl_double alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDnrm2)(size_t N, cl_mem NRM2, size_t offNRM2, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDrot)(size_t N, cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_double C, cl_double S, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDrotg)(cl_mem DA, size_t offDA, cl_mem DB, size_t offDB, cl_mem C, size_t offC, cl_mem S, size_t offS, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDrotm)(size_t N, cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, const cl_mem DPARAM, size_t offDparam, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDrotmg)(cl_mem DD1, size_t offDD1, cl_mem DD2, size_t offDD2, cl_mem DX1, size_t offDX1, const cl_mem DY1, size_t offDY1, cl_mem DPARAM, size_t offDparam, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDsbmv)(clblasOrder order, clblasUplo uplo, size_t N, size_t K, cl_double alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem X, size_t offx, int incx, cl_double beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDscal)(size_t N, cl_double alpha, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDspmv)(clblasOrder order, clblasUplo uplo, size_t N, cl_double alpha, const cl_mem AP, size_t offa, const cl_mem X, size_t offx, int incx, cl_double beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDspr)(clblasOrder order, clblasUplo uplo, size_t N, cl_double alpha, const cl_mem X, size_t offx, int incx, cl_mem AP, size_t offa, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDspr2)(clblasOrder order, clblasUplo uplo, size_t N, cl_double alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem AP, size_t offa, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDswap)(size_t N, cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDsymm)(clblasOrder order, clblasSide side, clblasUplo uplo, size_t M, size_t N, cl_double alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem B, size_t offb, size_t ldb, cl_double beta, cl_mem C, size_t offc, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDsymv)(clblasOrder order, clblasUplo uplo, size_t N, cl_double alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem x, size_t offx, int incx, cl_double beta, cl_mem y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDsyr)(clblasOrder order, clblasUplo uplo, size_t N, cl_double alpha, const cl_mem X, size_t offx, int incx, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDsyr2)(clblasOrder order, clblasUplo uplo, size_t N, cl_double alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDsyr2k)(clblasOrder order, clblasUplo uplo, clblasTranspose transAB, size_t N, size_t K, cl_double alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem B, size_t offB, size_t ldb, cl_double beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDsyrk)(clblasOrder order, clblasUplo uplo, clblasTranspose transA, size_t N, size_t K, cl_double alpha, const cl_mem A, size_t offA, size_t lda, cl_double beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDtbmv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, size_t K, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDtbsv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, size_t K, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDtpmv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, const cl_mem AP, size_t offa, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDtpsv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, const cl_mem A, size_t offa, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDtrmm)(clblasOrder order, clblasSide side, clblasUplo uplo, clblasTranspose transA, clblasDiag diag, size_t M, size_t N, cl_double alpha, const cl_mem A, size_t offA, size_t lda, cl_mem B, size_t offB, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDtrmv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDtrsm)(clblasOrder order, clblasSide side, clblasUplo uplo, clblasTranspose transA, clblasDiag diag, size_t M, size_t N, cl_double alpha, const cl_mem A, size_t offA, size_t lda, cl_mem B, size_t offB, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDtrsv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDzasum)(size_t N, cl_mem asum, size_t offAsum, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasDznrm2)(size_t N, cl_mem NRM2, size_t offNRM2, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasGetVersion)(cl_uint* major, cl_uint* minor, cl_uint* patch); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSasum)(size_t N, cl_mem asum, size_t offAsum, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSaxpy)(size_t N, cl_float alpha, const cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasScasum)(size_t N, cl_mem asum, size_t offAsum, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasScnrm2)(size_t N, cl_mem NRM2, size_t offNRM2, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasScopy)(size_t N, const cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSdot)(size_t N, cl_mem dotProduct, size_t offDP, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +extern CL_RUNTIME_EXPORT clblasStatus (*clblasSetup)(); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSgbmv)(clblasOrder order, clblasTranspose trans, size_t M, size_t N, size_t KL, size_t KU, cl_float alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem X, size_t offx, int incx, cl_float beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +extern CL_RUNTIME_EXPORT clblasStatus (*clblasSgemm)(clblasOrder order, clblasTranspose transA, clblasTranspose transB, size_t M, size_t N, size_t K, cl_float alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem B, size_t offB, size_t ldb, cl_float beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSgemv)(clblasOrder order, clblasTranspose transA, size_t M, size_t N, cl_float alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem x, size_t offx, int incx, cl_float beta, cl_mem y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSger)(clblasOrder order, size_t M, size_t N, cl_float alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSnrm2)(size_t N, cl_mem NRM2, size_t offNRM2, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSrot)(size_t N, cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_float C, cl_float S, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSrotg)(cl_mem SA, size_t offSA, cl_mem SB, size_t offSB, cl_mem C, size_t offC, cl_mem S, size_t offS, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSrotm)(size_t N, cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, const cl_mem SPARAM, size_t offSparam, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSrotmg)(cl_mem SD1, size_t offSD1, cl_mem SD2, size_t offSD2, cl_mem SX1, size_t offSX1, const cl_mem SY1, size_t offSY1, cl_mem SPARAM, size_t offSparam, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSsbmv)(clblasOrder order, clblasUplo uplo, size_t N, size_t K, cl_float alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem X, size_t offx, int incx, cl_float beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSscal)(size_t N, cl_float alpha, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSspmv)(clblasOrder order, clblasUplo uplo, size_t N, cl_float alpha, const cl_mem AP, size_t offa, const cl_mem X, size_t offx, int incx, cl_float beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSspr)(clblasOrder order, clblasUplo uplo, size_t N, cl_float alpha, const cl_mem X, size_t offx, int incx, cl_mem AP, size_t offa, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSspr2)(clblasOrder order, clblasUplo uplo, size_t N, cl_float alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem AP, size_t offa, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSswap)(size_t N, cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSsymm)(clblasOrder order, clblasSide side, clblasUplo uplo, size_t M, size_t N, cl_float alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem B, size_t offb, size_t ldb, cl_float beta, cl_mem C, size_t offc, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSsymv)(clblasOrder order, clblasUplo uplo, size_t N, cl_float alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem x, size_t offx, int incx, cl_float beta, cl_mem y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSsyr)(clblasOrder order, clblasUplo uplo, size_t N, cl_float alpha, const cl_mem X, size_t offx, int incx, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSsyr2)(clblasOrder order, clblasUplo uplo, size_t N, cl_float alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSsyr2k)(clblasOrder order, clblasUplo uplo, clblasTranspose transAB, size_t N, size_t K, cl_float alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem B, size_t offB, size_t ldb, cl_float beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasSsyrk)(clblasOrder order, clblasUplo uplo, clblasTranspose transA, size_t N, size_t K, cl_float alpha, const cl_mem A, size_t offA, size_t lda, cl_float beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasStbmv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, size_t K, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasStbsv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, size_t K, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasStpmv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, const cl_mem AP, size_t offa, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasStpsv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, const cl_mem A, size_t offa, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasStrmm)(clblasOrder order, clblasSide side, clblasUplo uplo, clblasTranspose transA, clblasDiag diag, size_t M, size_t N, cl_float alpha, const cl_mem A, size_t offA, size_t lda, cl_mem B, size_t offB, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasStrmv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasStrsm)(clblasOrder order, clblasSide side, clblasUplo uplo, clblasTranspose transA, clblasDiag diag, size_t M, size_t N, cl_float alpha, const cl_mem A, size_t offA, size_t lda, cl_mem B, size_t offB, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasStrsv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +extern CL_RUNTIME_EXPORT void (*clblasTeardown)(); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZaxpy)(size_t N, cl_double2 alpha, const cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZcopy)(size_t N, const cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZdotc)(size_t N, cl_mem dotProduct, size_t offDP, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZdotu)(size_t N, cl_mem dotProduct, size_t offDP, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZdrot)(size_t N, cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_double C, cl_double S, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZdscal)(size_t N, cl_double alpha, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZgbmv)(clblasOrder order, clblasTranspose trans, size_t M, size_t N, size_t KL, size_t KU, cl_double2 alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem X, size_t offx, int incx, cl_double2 beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +extern CL_RUNTIME_EXPORT clblasStatus (*clblasZgemm)(clblasOrder order, clblasTranspose transA, clblasTranspose transB, size_t M, size_t N, size_t K, DoubleComplex alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem B, size_t offB, size_t ldb, DoubleComplex beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZgemv)(clblasOrder order, clblasTranspose transA, size_t M, size_t N, DoubleComplex alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem x, size_t offx, int incx, DoubleComplex beta, cl_mem y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZgerc)(clblasOrder order, size_t M, size_t N, cl_double2 alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZgeru)(clblasOrder order, size_t M, size_t N, cl_double2 alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZhbmv)(clblasOrder order, clblasUplo uplo, size_t N, size_t K, cl_double2 alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem X, size_t offx, int incx, cl_double2 beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZhemm)(clblasOrder order, clblasSide side, clblasUplo uplo, size_t M, size_t N, cl_double2 alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem B, size_t offb, size_t ldb, cl_double2 beta, cl_mem C, size_t offc, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZhemv)(clblasOrder order, clblasUplo uplo, size_t N, DoubleComplex alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem X, size_t offx, int incx, DoubleComplex beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZher)(clblasOrder order, clblasUplo uplo, size_t N, cl_double alpha, const cl_mem X, size_t offx, int incx, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZher2)(clblasOrder order, clblasUplo uplo, size_t N, cl_double2 alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem A, size_t offa, size_t lda, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZher2k)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, size_t N, size_t K, DoubleComplex alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem B, size_t offb, size_t ldb, cl_double beta, cl_mem C, size_t offc, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZherk)(clblasOrder order, clblasUplo uplo, clblasTranspose transA, size_t N, size_t K, double alpha, const cl_mem A, size_t offa, size_t lda, double beta, cl_mem C, size_t offc, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZhpmv)(clblasOrder order, clblasUplo uplo, size_t N, cl_double2 alpha, const cl_mem AP, size_t offa, const cl_mem X, size_t offx, int incx, cl_double2 beta, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZhpr)(clblasOrder order, clblasUplo uplo, size_t N, cl_double alpha, const cl_mem X, size_t offx, int incx, cl_mem AP, size_t offa, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZhpr2)(clblasOrder order, clblasUplo uplo, size_t N, cl_double2 alpha, const cl_mem X, size_t offx, int incx, const cl_mem Y, size_t offy, int incy, cl_mem AP, size_t offa, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZrotg)(cl_mem CA, size_t offCA, cl_mem CB, size_t offCB, cl_mem C, size_t offC, cl_mem S, size_t offS, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZscal)(size_t N, cl_double2 alpha, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZswap)(size_t N, cl_mem X, size_t offx, int incx, cl_mem Y, size_t offy, int incy, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZsymm)(clblasOrder order, clblasSide side, clblasUplo uplo, size_t M, size_t N, cl_double2 alpha, const cl_mem A, size_t offa, size_t lda, const cl_mem B, size_t offb, size_t ldb, cl_double2 beta, cl_mem C, size_t offc, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZsyr2k)(clblasOrder order, clblasUplo uplo, clblasTranspose transAB, size_t N, size_t K, DoubleComplex alpha, const cl_mem A, size_t offA, size_t lda, const cl_mem B, size_t offB, size_t ldb, DoubleComplex beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZsyrk)(clblasOrder order, clblasUplo uplo, clblasTranspose transA, size_t N, size_t K, DoubleComplex alpha, const cl_mem A, size_t offA, size_t lda, DoubleComplex beta, cl_mem C, size_t offC, size_t ldc, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZtbmv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, size_t K, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZtbsv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, size_t K, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZtpmv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, const cl_mem AP, size_t offa, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZtpsv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, const cl_mem A, size_t offa, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZtrmm)(clblasOrder order, clblasSide side, clblasUplo uplo, clblasTranspose transA, clblasDiag diag, size_t M, size_t N, DoubleComplex alpha, const cl_mem A, size_t offA, size_t lda, cl_mem B, size_t offB, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZtrmv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZtrsm)(clblasOrder order, clblasSide side, clblasUplo uplo, clblasTranspose transA, clblasDiag diag, size_t M, size_t N, DoubleComplex alpha, const cl_mem A, size_t offA, size_t lda, cl_mem B, size_t offB, size_t ldb, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasZtrsv)(clblasOrder order, clblasUplo uplo, clblasTranspose trans, clblasDiag diag, size_t N, const cl_mem A, size_t offa, size_t lda, cl_mem X, size_t offx, int incx, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasiCamax)(size_t N, cl_mem iMax, size_t offiMax, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasiDamax)(size_t N, cl_mem iMax, size_t offiMax, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasiSamax)(size_t N, cl_mem iMax, size_t offiMax, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); +//extern CL_RUNTIME_EXPORT clblasStatus (*clblasiZamax)(size_t N, cl_mem iMax, size_t offiMax, const cl_mem X, size_t offx, int incx, cl_mem scratchBuff, cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList, const cl_event* eventWaitList, cl_event* events); diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_clfft.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_clfft.hpp new file mode 100644 index 0000000..dff3b40 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_clfft.hpp @@ -0,0 +1,146 @@ +// +// AUTOGENERATED, DO NOT EDIT +// +#ifndef OPENCV_CORE_OCL_RUNTIME_CLAMDFFT_HPP +#error "Invalid usage" +#endif + +// generated by parser_clfft.py +#define clfftBakePlan clfftBakePlan_ +#define clfftCopyPlan clfftCopyPlan_ +#define clfftCreateDefaultPlan clfftCreateDefaultPlan_ +#define clfftDestroyPlan clfftDestroyPlan_ +#define clfftEnqueueTransform clfftEnqueueTransform_ +#define clfftGetLayout clfftGetLayout_ +#define clfftGetPlanBatchSize clfftGetPlanBatchSize_ +#define clfftGetPlanContext clfftGetPlanContext_ +#define clfftGetPlanDim clfftGetPlanDim_ +#define clfftGetPlanDistance clfftGetPlanDistance_ +#define clfftGetPlanInStride clfftGetPlanInStride_ +#define clfftGetPlanLength clfftGetPlanLength_ +#define clfftGetPlanOutStride clfftGetPlanOutStride_ +#define clfftGetPlanPrecision clfftGetPlanPrecision_ +#define clfftGetPlanScale clfftGetPlanScale_ +#define clfftGetPlanTransposeResult clfftGetPlanTransposeResult_ +#define clfftGetResultLocation clfftGetResultLocation_ +#define clfftGetTmpBufSize clfftGetTmpBufSize_ +#define clfftGetVersion clfftGetVersion_ +#define clfftSetLayout clfftSetLayout_ +#define clfftSetPlanBatchSize clfftSetPlanBatchSize_ +#define clfftSetPlanCallback clfftSetPlanCallback_ +#define clfftSetPlanDim clfftSetPlanDim_ +#define clfftSetPlanDistance clfftSetPlanDistance_ +#define clfftSetPlanInStride clfftSetPlanInStride_ +#define clfftSetPlanLength clfftSetPlanLength_ +#define clfftSetPlanOutStride clfftSetPlanOutStride_ +#define clfftSetPlanPrecision clfftSetPlanPrecision_ +#define clfftSetPlanScale clfftSetPlanScale_ +#define clfftSetPlanTransposeResult clfftSetPlanTransposeResult_ +#define clfftSetResultLocation clfftSetResultLocation_ +#define clfftSetup clfftSetup_ +#define clfftTeardown clfftTeardown_ + +#include + +// generated by parser_clfft.py +#undef clfftBakePlan +#define clfftBakePlan clfftBakePlan_pfn +#undef clfftCopyPlan +//#define clfftCopyPlan clfftCopyPlan_pfn +#undef clfftCreateDefaultPlan +#define clfftCreateDefaultPlan clfftCreateDefaultPlan_pfn +#undef clfftDestroyPlan +#define clfftDestroyPlan clfftDestroyPlan_pfn +#undef clfftEnqueueTransform +#define clfftEnqueueTransform clfftEnqueueTransform_pfn +#undef clfftGetLayout +//#define clfftGetLayout clfftGetLayout_pfn +#undef clfftGetPlanBatchSize +//#define clfftGetPlanBatchSize clfftGetPlanBatchSize_pfn +#undef clfftGetPlanContext +//#define clfftGetPlanContext clfftGetPlanContext_pfn +#undef clfftGetPlanDim +//#define clfftGetPlanDim clfftGetPlanDim_pfn +#undef clfftGetPlanDistance +//#define clfftGetPlanDistance clfftGetPlanDistance_pfn +#undef clfftGetPlanInStride +//#define clfftGetPlanInStride clfftGetPlanInStride_pfn +#undef clfftGetPlanLength +//#define clfftGetPlanLength clfftGetPlanLength_pfn +#undef clfftGetPlanOutStride +//#define clfftGetPlanOutStride clfftGetPlanOutStride_pfn +#undef clfftGetPlanPrecision +//#define clfftGetPlanPrecision clfftGetPlanPrecision_pfn +#undef clfftGetPlanScale +//#define clfftGetPlanScale clfftGetPlanScale_pfn +#undef clfftGetPlanTransposeResult +//#define clfftGetPlanTransposeResult clfftGetPlanTransposeResult_pfn +#undef clfftGetResultLocation +//#define clfftGetResultLocation clfftGetResultLocation_pfn +#undef clfftGetTmpBufSize +#define clfftGetTmpBufSize clfftGetTmpBufSize_pfn +#undef clfftGetVersion +#define clfftGetVersion clfftGetVersion_pfn +#undef clfftSetLayout +#define clfftSetLayout clfftSetLayout_pfn +#undef clfftSetPlanBatchSize +#define clfftSetPlanBatchSize clfftSetPlanBatchSize_pfn +#undef clfftSetPlanCallback +//#define clfftSetPlanCallback clfftSetPlanCallback_pfn +#undef clfftSetPlanDim +//#define clfftSetPlanDim clfftSetPlanDim_pfn +#undef clfftSetPlanDistance +#define clfftSetPlanDistance clfftSetPlanDistance_pfn +#undef clfftSetPlanInStride +#define clfftSetPlanInStride clfftSetPlanInStride_pfn +#undef clfftSetPlanLength +//#define clfftSetPlanLength clfftSetPlanLength_pfn +#undef clfftSetPlanOutStride +#define clfftSetPlanOutStride clfftSetPlanOutStride_pfn +#undef clfftSetPlanPrecision +#define clfftSetPlanPrecision clfftSetPlanPrecision_pfn +#undef clfftSetPlanScale +#define clfftSetPlanScale clfftSetPlanScale_pfn +#undef clfftSetPlanTransposeResult +//#define clfftSetPlanTransposeResult clfftSetPlanTransposeResult_pfn +#undef clfftSetResultLocation +#define clfftSetResultLocation clfftSetResultLocation_pfn +#undef clfftSetup +#define clfftSetup clfftSetup_pfn +#undef clfftTeardown +#define clfftTeardown clfftTeardown_pfn + +// generated by parser_clfft.py +extern CL_RUNTIME_EXPORT clfftStatus (*clfftBakePlan)(clfftPlanHandle plHandle, cl_uint numQueues, cl_command_queue* commQueueFFT, void (CL_CALLBACK* pfn_notify) (clfftPlanHandle plHandle, void* user_data), void* user_data); +//extern CL_RUNTIME_EXPORT clfftStatus (*clfftCopyPlan)(clfftPlanHandle* out_plHandle, cl_context new_context, clfftPlanHandle in_plHandle); +extern CL_RUNTIME_EXPORT clfftStatus (*clfftCreateDefaultPlan)(clfftPlanHandle* plHandle, cl_context context, const clfftDim dim, const size_t* clLengths); +extern CL_RUNTIME_EXPORT clfftStatus (*clfftDestroyPlan)(clfftPlanHandle* plHandle); +extern CL_RUNTIME_EXPORT clfftStatus (*clfftEnqueueTransform)(clfftPlanHandle plHandle, clfftDirection dir, cl_uint numQueuesAndEvents, cl_command_queue* commQueues, cl_uint numWaitEvents, const cl_event* waitEvents, cl_event* outEvents, cl_mem* inputBuffers, cl_mem* outputBuffers, cl_mem tmpBuffer); +//extern CL_RUNTIME_EXPORT clfftStatus (*clfftGetLayout)(const clfftPlanHandle plHandle, clfftLayout* iLayout, clfftLayout* oLayout); +//extern CL_RUNTIME_EXPORT clfftStatus (*clfftGetPlanBatchSize)(const clfftPlanHandle plHandle, size_t* batchSize); +//extern CL_RUNTIME_EXPORT clfftStatus (*clfftGetPlanContext)(const clfftPlanHandle plHandle, cl_context* context); +//extern CL_RUNTIME_EXPORT clfftStatus (*clfftGetPlanDim)(const clfftPlanHandle plHandle, clfftDim* dim, cl_uint* size); +//extern CL_RUNTIME_EXPORT clfftStatus (*clfftGetPlanDistance)(const clfftPlanHandle plHandle, size_t* iDist, size_t* oDist); +//extern CL_RUNTIME_EXPORT clfftStatus (*clfftGetPlanInStride)(const clfftPlanHandle plHandle, const clfftDim dim, size_t* clStrides); +//extern CL_RUNTIME_EXPORT clfftStatus (*clfftGetPlanLength)(const clfftPlanHandle plHandle, const clfftDim dim, size_t* clLengths); +//extern CL_RUNTIME_EXPORT clfftStatus (*clfftGetPlanOutStride)(const clfftPlanHandle plHandle, const clfftDim dim, size_t* clStrides); +//extern CL_RUNTIME_EXPORT clfftStatus (*clfftGetPlanPrecision)(const clfftPlanHandle plHandle, clfftPrecision* precision); +//extern CL_RUNTIME_EXPORT clfftStatus (*clfftGetPlanScale)(const clfftPlanHandle plHandle, clfftDirection dir, cl_float* scale); +//extern CL_RUNTIME_EXPORT clfftStatus (*clfftGetPlanTransposeResult)(const clfftPlanHandle plHandle, clfftResultTransposed* transposed); +//extern CL_RUNTIME_EXPORT clfftStatus (*clfftGetResultLocation)(const clfftPlanHandle plHandle, clfftResultLocation* placeness); +extern CL_RUNTIME_EXPORT clfftStatus (*clfftGetTmpBufSize)(const clfftPlanHandle plHandle, size_t* buffersize); +extern CL_RUNTIME_EXPORT clfftStatus (*clfftGetVersion)(cl_uint* major, cl_uint* minor, cl_uint* patch); +extern CL_RUNTIME_EXPORT clfftStatus (*clfftSetLayout)(clfftPlanHandle plHandle, clfftLayout iLayout, clfftLayout oLayout); +extern CL_RUNTIME_EXPORT clfftStatus (*clfftSetPlanBatchSize)(clfftPlanHandle plHandle, size_t batchSize); +//extern CL_RUNTIME_EXPORT clfftStatus (*clfftSetPlanCallback)(clfftPlanHandle plHandle, const char* funcName, const char* funcString, int localMemSize, clfftCallbackType callbackType, cl_mem* userdata, int numUserdataBuffers); +//extern CL_RUNTIME_EXPORT clfftStatus (*clfftSetPlanDim)(clfftPlanHandle plHandle, const clfftDim dim); +extern CL_RUNTIME_EXPORT clfftStatus (*clfftSetPlanDistance)(clfftPlanHandle plHandle, size_t iDist, size_t oDist); +extern CL_RUNTIME_EXPORT clfftStatus (*clfftSetPlanInStride)(clfftPlanHandle plHandle, const clfftDim dim, size_t* clStrides); +//extern CL_RUNTIME_EXPORT clfftStatus (*clfftSetPlanLength)(clfftPlanHandle plHandle, const clfftDim dim, const size_t* clLengths); +extern CL_RUNTIME_EXPORT clfftStatus (*clfftSetPlanOutStride)(clfftPlanHandle plHandle, const clfftDim dim, size_t* clStrides); +extern CL_RUNTIME_EXPORT clfftStatus (*clfftSetPlanPrecision)(clfftPlanHandle plHandle, clfftPrecision precision); +extern CL_RUNTIME_EXPORT clfftStatus (*clfftSetPlanScale)(clfftPlanHandle plHandle, clfftDirection dir, cl_float scale); +//extern CL_RUNTIME_EXPORT clfftStatus (*clfftSetPlanTransposeResult)(clfftPlanHandle plHandle, clfftResultTransposed transposed); +extern CL_RUNTIME_EXPORT clfftStatus (*clfftSetResultLocation)(clfftPlanHandle plHandle, clfftResultLocation placeness); +extern CL_RUNTIME_EXPORT clfftStatus (*clfftSetup)(const clfftSetupData* setupData); +extern CL_RUNTIME_EXPORT clfftStatus (*clfftTeardown)(); diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_core.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_core.hpp new file mode 100644 index 0000000..28618a1 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_core.hpp @@ -0,0 +1,371 @@ +// +// AUTOGENERATED, DO NOT EDIT +// +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_CORE_HPP +#error "Invalid usage" +#endif + +// generated by parser_cl.py +#define clBuildProgram clBuildProgram_ +#define clCompileProgram clCompileProgram_ +#define clCreateBuffer clCreateBuffer_ +#define clCreateCommandQueue clCreateCommandQueue_ +#define clCreateContext clCreateContext_ +#define clCreateContextFromType clCreateContextFromType_ +#define clCreateImage clCreateImage_ +#define clCreateImage2D clCreateImage2D_ +#define clCreateImage3D clCreateImage3D_ +#define clCreateKernel clCreateKernel_ +#define clCreateKernelsInProgram clCreateKernelsInProgram_ +#define clCreateProgramWithBinary clCreateProgramWithBinary_ +#define clCreateProgramWithBuiltInKernels clCreateProgramWithBuiltInKernels_ +#define clCreateProgramWithSource clCreateProgramWithSource_ +#define clCreateSampler clCreateSampler_ +#define clCreateSubBuffer clCreateSubBuffer_ +#define clCreateSubDevices clCreateSubDevices_ +#define clCreateUserEvent clCreateUserEvent_ +#define clEnqueueBarrier clEnqueueBarrier_ +#define clEnqueueBarrierWithWaitList clEnqueueBarrierWithWaitList_ +#define clEnqueueCopyBuffer clEnqueueCopyBuffer_ +#define clEnqueueCopyBufferRect clEnqueueCopyBufferRect_ +#define clEnqueueCopyBufferToImage clEnqueueCopyBufferToImage_ +#define clEnqueueCopyImage clEnqueueCopyImage_ +#define clEnqueueCopyImageToBuffer clEnqueueCopyImageToBuffer_ +#define clEnqueueFillBuffer clEnqueueFillBuffer_ +#define clEnqueueFillImage clEnqueueFillImage_ +#define clEnqueueMapBuffer clEnqueueMapBuffer_ +#define clEnqueueMapImage clEnqueueMapImage_ +#define clEnqueueMarker clEnqueueMarker_ +#define clEnqueueMarkerWithWaitList clEnqueueMarkerWithWaitList_ +#define clEnqueueMigrateMemObjects clEnqueueMigrateMemObjects_ +#define clEnqueueNDRangeKernel clEnqueueNDRangeKernel_ +#define clEnqueueNativeKernel clEnqueueNativeKernel_ +#define clEnqueueReadBuffer clEnqueueReadBuffer_ +#define clEnqueueReadBufferRect clEnqueueReadBufferRect_ +#define clEnqueueReadImage clEnqueueReadImage_ +#define clEnqueueTask clEnqueueTask_ +#define clEnqueueUnmapMemObject clEnqueueUnmapMemObject_ +#define clEnqueueWaitForEvents clEnqueueWaitForEvents_ +#define clEnqueueWriteBuffer clEnqueueWriteBuffer_ +#define clEnqueueWriteBufferRect clEnqueueWriteBufferRect_ +#define clEnqueueWriteImage clEnqueueWriteImage_ +#define clFinish clFinish_ +#define clFlush clFlush_ +#define clGetCommandQueueInfo clGetCommandQueueInfo_ +#define clGetContextInfo clGetContextInfo_ +#define clGetDeviceIDs clGetDeviceIDs_ +#define clGetDeviceInfo clGetDeviceInfo_ +#define clGetEventInfo clGetEventInfo_ +#define clGetEventProfilingInfo clGetEventProfilingInfo_ +#define clGetExtensionFunctionAddress clGetExtensionFunctionAddress_ +#define clGetExtensionFunctionAddressForPlatform clGetExtensionFunctionAddressForPlatform_ +#define clGetImageInfo clGetImageInfo_ +#define clGetKernelArgInfo clGetKernelArgInfo_ +#define clGetKernelInfo clGetKernelInfo_ +#define clGetKernelWorkGroupInfo clGetKernelWorkGroupInfo_ +#define clGetMemObjectInfo clGetMemObjectInfo_ +#define clGetPlatformIDs clGetPlatformIDs_ +#define clGetPlatformInfo clGetPlatformInfo_ +#define clGetProgramBuildInfo clGetProgramBuildInfo_ +#define clGetProgramInfo clGetProgramInfo_ +#define clGetSamplerInfo clGetSamplerInfo_ +#define clGetSupportedImageFormats clGetSupportedImageFormats_ +#define clLinkProgram clLinkProgram_ +#define clReleaseCommandQueue clReleaseCommandQueue_ +#define clReleaseContext clReleaseContext_ +#define clReleaseDevice clReleaseDevice_ +#define clReleaseEvent clReleaseEvent_ +#define clReleaseKernel clReleaseKernel_ +#define clReleaseMemObject clReleaseMemObject_ +#define clReleaseProgram clReleaseProgram_ +#define clReleaseSampler clReleaseSampler_ +#define clRetainCommandQueue clRetainCommandQueue_ +#define clRetainContext clRetainContext_ +#define clRetainDevice clRetainDevice_ +#define clRetainEvent clRetainEvent_ +#define clRetainKernel clRetainKernel_ +#define clRetainMemObject clRetainMemObject_ +#define clRetainProgram clRetainProgram_ +#define clRetainSampler clRetainSampler_ +#define clSetEventCallback clSetEventCallback_ +#define clSetKernelArg clSetKernelArg_ +#define clSetMemObjectDestructorCallback clSetMemObjectDestructorCallback_ +#define clSetUserEventStatus clSetUserEventStatus_ +#define clUnloadCompiler clUnloadCompiler_ +#define clUnloadPlatformCompiler clUnloadPlatformCompiler_ +#define clWaitForEvents clWaitForEvents_ + +#if defined __APPLE__ +#define CL_SILENCE_DEPRECATION +#include +#else +#include +#endif + +// generated by parser_cl.py +#undef clBuildProgram +#define clBuildProgram clBuildProgram_pfn +#undef clCompileProgram +#define clCompileProgram clCompileProgram_pfn +#undef clCreateBuffer +#define clCreateBuffer clCreateBuffer_pfn +#undef clCreateCommandQueue +#define clCreateCommandQueue clCreateCommandQueue_pfn +#undef clCreateContext +#define clCreateContext clCreateContext_pfn +#undef clCreateContextFromType +#define clCreateContextFromType clCreateContextFromType_pfn +#undef clCreateImage +#define clCreateImage clCreateImage_pfn +#undef clCreateImage2D +#define clCreateImage2D clCreateImage2D_pfn +#undef clCreateImage3D +#define clCreateImage3D clCreateImage3D_pfn +#undef clCreateKernel +#define clCreateKernel clCreateKernel_pfn +#undef clCreateKernelsInProgram +#define clCreateKernelsInProgram clCreateKernelsInProgram_pfn +#undef clCreateProgramWithBinary +#define clCreateProgramWithBinary clCreateProgramWithBinary_pfn +#undef clCreateProgramWithBuiltInKernels +#define clCreateProgramWithBuiltInKernels clCreateProgramWithBuiltInKernels_pfn +#undef clCreateProgramWithSource +#define clCreateProgramWithSource clCreateProgramWithSource_pfn +#undef clCreateSampler +#define clCreateSampler clCreateSampler_pfn +#undef clCreateSubBuffer +#define clCreateSubBuffer clCreateSubBuffer_pfn +#undef clCreateSubDevices +#define clCreateSubDevices clCreateSubDevices_pfn +#undef clCreateUserEvent +#define clCreateUserEvent clCreateUserEvent_pfn +#undef clEnqueueBarrier +#define clEnqueueBarrier clEnqueueBarrier_pfn +#undef clEnqueueBarrierWithWaitList +#define clEnqueueBarrierWithWaitList clEnqueueBarrierWithWaitList_pfn +#undef clEnqueueCopyBuffer +#define clEnqueueCopyBuffer clEnqueueCopyBuffer_pfn +#undef clEnqueueCopyBufferRect +#define clEnqueueCopyBufferRect clEnqueueCopyBufferRect_pfn +#undef clEnqueueCopyBufferToImage +#define clEnqueueCopyBufferToImage clEnqueueCopyBufferToImage_pfn +#undef clEnqueueCopyImage +#define clEnqueueCopyImage clEnqueueCopyImage_pfn +#undef clEnqueueCopyImageToBuffer +#define clEnqueueCopyImageToBuffer clEnqueueCopyImageToBuffer_pfn +#undef clEnqueueFillBuffer +#define clEnqueueFillBuffer clEnqueueFillBuffer_pfn +#undef clEnqueueFillImage +#define clEnqueueFillImage clEnqueueFillImage_pfn +#undef clEnqueueMapBuffer +#define clEnqueueMapBuffer clEnqueueMapBuffer_pfn +#undef clEnqueueMapImage +#define clEnqueueMapImage clEnqueueMapImage_pfn +#undef clEnqueueMarker +#define clEnqueueMarker clEnqueueMarker_pfn +#undef clEnqueueMarkerWithWaitList +#define clEnqueueMarkerWithWaitList clEnqueueMarkerWithWaitList_pfn +#undef clEnqueueMigrateMemObjects +#define clEnqueueMigrateMemObjects clEnqueueMigrateMemObjects_pfn +#undef clEnqueueNDRangeKernel +#define clEnqueueNDRangeKernel clEnqueueNDRangeKernel_pfn +#undef clEnqueueNativeKernel +#define clEnqueueNativeKernel clEnqueueNativeKernel_pfn +#undef clEnqueueReadBuffer +#define clEnqueueReadBuffer clEnqueueReadBuffer_pfn +#undef clEnqueueReadBufferRect +#define clEnqueueReadBufferRect clEnqueueReadBufferRect_pfn +#undef clEnqueueReadImage +#define clEnqueueReadImage clEnqueueReadImage_pfn +#undef clEnqueueTask +#define clEnqueueTask clEnqueueTask_pfn +#undef clEnqueueUnmapMemObject +#define clEnqueueUnmapMemObject clEnqueueUnmapMemObject_pfn +#undef clEnqueueWaitForEvents +#define clEnqueueWaitForEvents clEnqueueWaitForEvents_pfn +#undef clEnqueueWriteBuffer +#define clEnqueueWriteBuffer clEnqueueWriteBuffer_pfn +#undef clEnqueueWriteBufferRect +#define clEnqueueWriteBufferRect clEnqueueWriteBufferRect_pfn +#undef clEnqueueWriteImage +#define clEnqueueWriteImage clEnqueueWriteImage_pfn +#undef clFinish +#define clFinish clFinish_pfn +#undef clFlush +#define clFlush clFlush_pfn +#undef clGetCommandQueueInfo +#define clGetCommandQueueInfo clGetCommandQueueInfo_pfn +#undef clGetContextInfo +#define clGetContextInfo clGetContextInfo_pfn +#undef clGetDeviceIDs +#define clGetDeviceIDs clGetDeviceIDs_pfn +#undef clGetDeviceInfo +#define clGetDeviceInfo clGetDeviceInfo_pfn +#undef clGetEventInfo +#define clGetEventInfo clGetEventInfo_pfn +#undef clGetEventProfilingInfo +#define clGetEventProfilingInfo clGetEventProfilingInfo_pfn +#undef clGetExtensionFunctionAddress +#define clGetExtensionFunctionAddress clGetExtensionFunctionAddress_pfn +#undef clGetExtensionFunctionAddressForPlatform +#define clGetExtensionFunctionAddressForPlatform clGetExtensionFunctionAddressForPlatform_pfn +#undef clGetImageInfo +#define clGetImageInfo clGetImageInfo_pfn +#undef clGetKernelArgInfo +#define clGetKernelArgInfo clGetKernelArgInfo_pfn +#undef clGetKernelInfo +#define clGetKernelInfo clGetKernelInfo_pfn +#undef clGetKernelWorkGroupInfo +#define clGetKernelWorkGroupInfo clGetKernelWorkGroupInfo_pfn +#undef clGetMemObjectInfo +#define clGetMemObjectInfo clGetMemObjectInfo_pfn +#undef clGetPlatformIDs +#define clGetPlatformIDs clGetPlatformIDs_pfn +#undef clGetPlatformInfo +#define clGetPlatformInfo clGetPlatformInfo_pfn +#undef clGetProgramBuildInfo +#define clGetProgramBuildInfo clGetProgramBuildInfo_pfn +#undef clGetProgramInfo +#define clGetProgramInfo clGetProgramInfo_pfn +#undef clGetSamplerInfo +#define clGetSamplerInfo clGetSamplerInfo_pfn +#undef clGetSupportedImageFormats +#define clGetSupportedImageFormats clGetSupportedImageFormats_pfn +#undef clLinkProgram +#define clLinkProgram clLinkProgram_pfn +#undef clReleaseCommandQueue +#define clReleaseCommandQueue clReleaseCommandQueue_pfn +#undef clReleaseContext +#define clReleaseContext clReleaseContext_pfn +#undef clReleaseDevice +#define clReleaseDevice clReleaseDevice_pfn +#undef clReleaseEvent +#define clReleaseEvent clReleaseEvent_pfn +#undef clReleaseKernel +#define clReleaseKernel clReleaseKernel_pfn +#undef clReleaseMemObject +#define clReleaseMemObject clReleaseMemObject_pfn +#undef clReleaseProgram +#define clReleaseProgram clReleaseProgram_pfn +#undef clReleaseSampler +#define clReleaseSampler clReleaseSampler_pfn +#undef clRetainCommandQueue +#define clRetainCommandQueue clRetainCommandQueue_pfn +#undef clRetainContext +#define clRetainContext clRetainContext_pfn +#undef clRetainDevice +#define clRetainDevice clRetainDevice_pfn +#undef clRetainEvent +#define clRetainEvent clRetainEvent_pfn +#undef clRetainKernel +#define clRetainKernel clRetainKernel_pfn +#undef clRetainMemObject +#define clRetainMemObject clRetainMemObject_pfn +#undef clRetainProgram +#define clRetainProgram clRetainProgram_pfn +#undef clRetainSampler +#define clRetainSampler clRetainSampler_pfn +#undef clSetEventCallback +#define clSetEventCallback clSetEventCallback_pfn +#undef clSetKernelArg +#define clSetKernelArg clSetKernelArg_pfn +#undef clSetMemObjectDestructorCallback +#define clSetMemObjectDestructorCallback clSetMemObjectDestructorCallback_pfn +#undef clSetUserEventStatus +#define clSetUserEventStatus clSetUserEventStatus_pfn +#undef clUnloadCompiler +#define clUnloadCompiler clUnloadCompiler_pfn +#undef clUnloadPlatformCompiler +#define clUnloadPlatformCompiler clUnloadPlatformCompiler_pfn +#undef clWaitForEvents +#define clWaitForEvents clWaitForEvents_pfn + +// generated by parser_cl.py +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clBuildProgram)(cl_program, cl_uint, const cl_device_id*, const char*, void (CL_CALLBACK*) (cl_program, void*), void*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clCompileProgram)(cl_program, cl_uint, const cl_device_id*, const char*, cl_uint, const cl_program*, const char**, void (CL_CALLBACK*) (cl_program, void*), void*); +extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateBuffer)(cl_context, cl_mem_flags, size_t, void*, cl_int*); +extern CL_RUNTIME_EXPORT cl_command_queue (CL_API_CALL*clCreateCommandQueue)(cl_context, cl_device_id, cl_command_queue_properties, cl_int*); +extern CL_RUNTIME_EXPORT cl_context (CL_API_CALL*clCreateContext)(const cl_context_properties*, cl_uint, const cl_device_id*, void (CL_CALLBACK*) (const char*, const void*, size_t, void*), void*, cl_int*); +extern CL_RUNTIME_EXPORT cl_context (CL_API_CALL*clCreateContextFromType)(const cl_context_properties*, cl_device_type, void (CL_CALLBACK*) (const char*, const void*, size_t, void*), void*, cl_int*); +extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateImage)(cl_context, cl_mem_flags, const cl_image_format*, const cl_image_desc*, void*, cl_int*); +extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateImage2D)(cl_context, cl_mem_flags, const cl_image_format*, size_t, size_t, size_t, void*, cl_int*); +extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateImage3D)(cl_context, cl_mem_flags, const cl_image_format*, size_t, size_t, size_t, size_t, size_t, void*, cl_int*); +extern CL_RUNTIME_EXPORT cl_kernel (CL_API_CALL*clCreateKernel)(cl_program, const char*, cl_int*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clCreateKernelsInProgram)(cl_program, cl_uint, cl_kernel*, cl_uint*); +extern CL_RUNTIME_EXPORT cl_program (CL_API_CALL*clCreateProgramWithBinary)(cl_context, cl_uint, const cl_device_id*, const size_t*, const unsigned char**, cl_int*, cl_int*); +extern CL_RUNTIME_EXPORT cl_program (CL_API_CALL*clCreateProgramWithBuiltInKernels)(cl_context, cl_uint, const cl_device_id*, const char*, cl_int*); +extern CL_RUNTIME_EXPORT cl_program (CL_API_CALL*clCreateProgramWithSource)(cl_context, cl_uint, const char**, const size_t*, cl_int*); +extern CL_RUNTIME_EXPORT cl_sampler (CL_API_CALL*clCreateSampler)(cl_context, cl_bool, cl_addressing_mode, cl_filter_mode, cl_int*); +extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateSubBuffer)(cl_mem, cl_mem_flags, cl_buffer_create_type, const void*, cl_int*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clCreateSubDevices)(cl_device_id, const cl_device_partition_property*, cl_uint, cl_device_id*, cl_uint*); +extern CL_RUNTIME_EXPORT cl_event (CL_API_CALL*clCreateUserEvent)(cl_context, cl_int*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueBarrier)(cl_command_queue); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueBarrierWithWaitList)(cl_command_queue, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueCopyBuffer)(cl_command_queue, cl_mem, cl_mem, size_t, size_t, size_t, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueCopyBufferRect)(cl_command_queue, cl_mem, cl_mem, const size_t*, const size_t*, const size_t*, size_t, size_t, size_t, size_t, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueCopyBufferToImage)(cl_command_queue, cl_mem, cl_mem, size_t, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueCopyImage)(cl_command_queue, cl_mem, cl_mem, const size_t*, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueCopyImageToBuffer)(cl_command_queue, cl_mem, cl_mem, const size_t*, const size_t*, size_t, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueFillBuffer)(cl_command_queue, cl_mem, const void*, size_t, size_t, size_t, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueFillImage)(cl_command_queue, cl_mem, const void*, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT void* (CL_API_CALL*clEnqueueMapBuffer)(cl_command_queue, cl_mem, cl_bool, cl_map_flags, size_t, size_t, cl_uint, const cl_event*, cl_event*, cl_int*); +extern CL_RUNTIME_EXPORT void* (CL_API_CALL*clEnqueueMapImage)(cl_command_queue, cl_mem, cl_bool, cl_map_flags, const size_t*, const size_t*, size_t*, size_t*, cl_uint, const cl_event*, cl_event*, cl_int*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueMarker)(cl_command_queue, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueMarkerWithWaitList)(cl_command_queue, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueMigrateMemObjects)(cl_command_queue, cl_uint, const cl_mem*, cl_mem_migration_flags, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueNDRangeKernel)(cl_command_queue, cl_kernel, cl_uint, const size_t*, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueNativeKernel)(cl_command_queue, void (CL_CALLBACK*) (void*), void*, size_t, cl_uint, const cl_mem*, const void**, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueReadBuffer)(cl_command_queue, cl_mem, cl_bool, size_t, size_t, void*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueReadBufferRect)(cl_command_queue, cl_mem, cl_bool, const size_t*, const size_t*, const size_t*, size_t, size_t, size_t, size_t, void*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueReadImage)(cl_command_queue, cl_mem, cl_bool, const size_t*, const size_t*, size_t, size_t, void*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueTask)(cl_command_queue, cl_kernel, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueUnmapMemObject)(cl_command_queue, cl_mem, void*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueWaitForEvents)(cl_command_queue, cl_uint, const cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueWriteBuffer)(cl_command_queue, cl_mem, cl_bool, size_t, size_t, const void*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueWriteBufferRect)(cl_command_queue, cl_mem, cl_bool, const size_t*, const size_t*, const size_t*, size_t, size_t, size_t, size_t, const void*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueWriteImage)(cl_command_queue, cl_mem, cl_bool, const size_t*, const size_t*, size_t, size_t, const void*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clFinish)(cl_command_queue); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clFlush)(cl_command_queue); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetCommandQueueInfo)(cl_command_queue, cl_command_queue_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetContextInfo)(cl_context, cl_context_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetDeviceIDs)(cl_platform_id, cl_device_type, cl_uint, cl_device_id*, cl_uint*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetDeviceInfo)(cl_device_id, cl_device_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetEventInfo)(cl_event, cl_event_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetEventProfilingInfo)(cl_event, cl_profiling_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT void* (CL_API_CALL*clGetExtensionFunctionAddress)(const char*); +extern CL_RUNTIME_EXPORT void* (CL_API_CALL*clGetExtensionFunctionAddressForPlatform)(cl_platform_id, const char*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetImageInfo)(cl_mem, cl_image_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetKernelArgInfo)(cl_kernel, cl_uint, cl_kernel_arg_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetKernelInfo)(cl_kernel, cl_kernel_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetKernelWorkGroupInfo)(cl_kernel, cl_device_id, cl_kernel_work_group_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetMemObjectInfo)(cl_mem, cl_mem_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetPlatformIDs)(cl_uint, cl_platform_id*, cl_uint*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetPlatformInfo)(cl_platform_id, cl_platform_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetProgramBuildInfo)(cl_program, cl_device_id, cl_program_build_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetProgramInfo)(cl_program, cl_program_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetSamplerInfo)(cl_sampler, cl_sampler_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetSupportedImageFormats)(cl_context, cl_mem_flags, cl_mem_object_type, cl_uint, cl_image_format*, cl_uint*); +extern CL_RUNTIME_EXPORT cl_program (CL_API_CALL*clLinkProgram)(cl_context, cl_uint, const cl_device_id*, const char*, cl_uint, const cl_program*, void (CL_CALLBACK*) (cl_program, void*), void*, cl_int*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clReleaseCommandQueue)(cl_command_queue); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clReleaseContext)(cl_context); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clReleaseDevice)(cl_device_id); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clReleaseEvent)(cl_event); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clReleaseKernel)(cl_kernel); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clReleaseMemObject)(cl_mem); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clReleaseProgram)(cl_program); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clReleaseSampler)(cl_sampler); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clRetainCommandQueue)(cl_command_queue); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clRetainContext)(cl_context); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clRetainDevice)(cl_device_id); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clRetainEvent)(cl_event); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clRetainKernel)(cl_kernel); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clRetainMemObject)(cl_mem); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clRetainProgram)(cl_program); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clRetainSampler)(cl_sampler); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clSetEventCallback)(cl_event, cl_int, void (CL_CALLBACK*) (cl_event, cl_int, void*), void*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clSetKernelArg)(cl_kernel, cl_uint, size_t, const void*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clSetMemObjectDestructorCallback)(cl_mem, void (CL_CALLBACK*) (cl_mem, void*), void*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clSetUserEventStatus)(cl_event, cl_int); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clUnloadCompiler)(); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clUnloadPlatformCompiler)(cl_platform_id); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clWaitForEvents)(cl_uint, const cl_event*); diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_core_wrappers.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_core_wrappers.hpp new file mode 100644 index 0000000..216b22b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_core_wrappers.hpp @@ -0,0 +1,272 @@ +// +// AUTOGENERATED, DO NOT EDIT +// +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_WRAPPERS_HPP +#error "Invalid usage" +#endif + +// generated by parser_cl.py +#undef clBuildProgram +#define clBuildProgram clBuildProgram_fn +inline cl_int clBuildProgram(cl_program p0, cl_uint p1, const cl_device_id* p2, const char* p3, void (CL_CALLBACK*p4) (cl_program, void*), void* p5) { return clBuildProgram_pfn(p0, p1, p2, p3, p4, p5); } +#undef clCompileProgram +#define clCompileProgram clCompileProgram_fn +inline cl_int clCompileProgram(cl_program p0, cl_uint p1, const cl_device_id* p2, const char* p3, cl_uint p4, const cl_program* p5, const char** p6, void (CL_CALLBACK*p7) (cl_program, void*), void* p8) { return clCompileProgram_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8); } +#undef clCreateBuffer +#define clCreateBuffer clCreateBuffer_fn +inline cl_mem clCreateBuffer(cl_context p0, cl_mem_flags p1, size_t p2, void* p3, cl_int* p4) { return clCreateBuffer_pfn(p0, p1, p2, p3, p4); } +#undef clCreateCommandQueue +#define clCreateCommandQueue clCreateCommandQueue_fn +inline cl_command_queue clCreateCommandQueue(cl_context p0, cl_device_id p1, cl_command_queue_properties p2, cl_int* p3) { return clCreateCommandQueue_pfn(p0, p1, p2, p3); } +#undef clCreateContext +#define clCreateContext clCreateContext_fn +inline cl_context clCreateContext(const cl_context_properties* p0, cl_uint p1, const cl_device_id* p2, void (CL_CALLBACK*p3) (const char*, const void*, size_t, void*), void* p4, cl_int* p5) { return clCreateContext_pfn(p0, p1, p2, p3, p4, p5); } +#undef clCreateContextFromType +#define clCreateContextFromType clCreateContextFromType_fn +inline cl_context clCreateContextFromType(const cl_context_properties* p0, cl_device_type p1, void (CL_CALLBACK*p2) (const char*, const void*, size_t, void*), void* p3, cl_int* p4) { return clCreateContextFromType_pfn(p0, p1, p2, p3, p4); } +#undef clCreateImage +#define clCreateImage clCreateImage_fn +inline cl_mem clCreateImage(cl_context p0, cl_mem_flags p1, const cl_image_format* p2, const cl_image_desc* p3, void* p4, cl_int* p5) { return clCreateImage_pfn(p0, p1, p2, p3, p4, p5); } +#undef clCreateImage2D +#define clCreateImage2D clCreateImage2D_fn +inline cl_mem clCreateImage2D(cl_context p0, cl_mem_flags p1, const cl_image_format* p2, size_t p3, size_t p4, size_t p5, void* p6, cl_int* p7) { return clCreateImage2D_pfn(p0, p1, p2, p3, p4, p5, p6, p7); } +#undef clCreateImage3D +#define clCreateImage3D clCreateImage3D_fn +inline cl_mem clCreateImage3D(cl_context p0, cl_mem_flags p1, const cl_image_format* p2, size_t p3, size_t p4, size_t p5, size_t p6, size_t p7, void* p8, cl_int* p9) { return clCreateImage3D_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); } +#undef clCreateKernel +#define clCreateKernel clCreateKernel_fn +inline cl_kernel clCreateKernel(cl_program p0, const char* p1, cl_int* p2) { return clCreateKernel_pfn(p0, p1, p2); } +#undef clCreateKernelsInProgram +#define clCreateKernelsInProgram clCreateKernelsInProgram_fn +inline cl_int clCreateKernelsInProgram(cl_program p0, cl_uint p1, cl_kernel* p2, cl_uint* p3) { return clCreateKernelsInProgram_pfn(p0, p1, p2, p3); } +#undef clCreateProgramWithBinary +#define clCreateProgramWithBinary clCreateProgramWithBinary_fn +inline cl_program clCreateProgramWithBinary(cl_context p0, cl_uint p1, const cl_device_id* p2, const size_t* p3, const unsigned char** p4, cl_int* p5, cl_int* p6) { return clCreateProgramWithBinary_pfn(p0, p1, p2, p3, p4, p5, p6); } +#undef clCreateProgramWithBuiltInKernels +#define clCreateProgramWithBuiltInKernels clCreateProgramWithBuiltInKernels_fn +inline cl_program clCreateProgramWithBuiltInKernels(cl_context p0, cl_uint p1, const cl_device_id* p2, const char* p3, cl_int* p4) { return clCreateProgramWithBuiltInKernels_pfn(p0, p1, p2, p3, p4); } +#undef clCreateProgramWithSource +#define clCreateProgramWithSource clCreateProgramWithSource_fn +inline cl_program clCreateProgramWithSource(cl_context p0, cl_uint p1, const char** p2, const size_t* p3, cl_int* p4) { return clCreateProgramWithSource_pfn(p0, p1, p2, p3, p4); } +#undef clCreateSampler +#define clCreateSampler clCreateSampler_fn +inline cl_sampler clCreateSampler(cl_context p0, cl_bool p1, cl_addressing_mode p2, cl_filter_mode p3, cl_int* p4) { return clCreateSampler_pfn(p0, p1, p2, p3, p4); } +#undef clCreateSubBuffer +#define clCreateSubBuffer clCreateSubBuffer_fn +inline cl_mem clCreateSubBuffer(cl_mem p0, cl_mem_flags p1, cl_buffer_create_type p2, const void* p3, cl_int* p4) { return clCreateSubBuffer_pfn(p0, p1, p2, p3, p4); } +#undef clCreateSubDevices +#define clCreateSubDevices clCreateSubDevices_fn +inline cl_int clCreateSubDevices(cl_device_id p0, const cl_device_partition_property* p1, cl_uint p2, cl_device_id* p3, cl_uint* p4) { return clCreateSubDevices_pfn(p0, p1, p2, p3, p4); } +#undef clCreateUserEvent +#define clCreateUserEvent clCreateUserEvent_fn +inline cl_event clCreateUserEvent(cl_context p0, cl_int* p1) { return clCreateUserEvent_pfn(p0, p1); } +#undef clEnqueueBarrier +#define clEnqueueBarrier clEnqueueBarrier_fn +inline cl_int clEnqueueBarrier(cl_command_queue p0) { return clEnqueueBarrier_pfn(p0); } +#undef clEnqueueBarrierWithWaitList +#define clEnqueueBarrierWithWaitList clEnqueueBarrierWithWaitList_fn +inline cl_int clEnqueueBarrierWithWaitList(cl_command_queue p0, cl_uint p1, const cl_event* p2, cl_event* p3) { return clEnqueueBarrierWithWaitList_pfn(p0, p1, p2, p3); } +#undef clEnqueueCopyBuffer +#define clEnqueueCopyBuffer clEnqueueCopyBuffer_fn +inline cl_int clEnqueueCopyBuffer(cl_command_queue p0, cl_mem p1, cl_mem p2, size_t p3, size_t p4, size_t p5, cl_uint p6, const cl_event* p7, cl_event* p8) { return clEnqueueCopyBuffer_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8); } +#undef clEnqueueCopyBufferRect +#define clEnqueueCopyBufferRect clEnqueueCopyBufferRect_fn +inline cl_int clEnqueueCopyBufferRect(cl_command_queue p0, cl_mem p1, cl_mem p2, const size_t* p3, const size_t* p4, const size_t* p5, size_t p6, size_t p7, size_t p8, size_t p9, cl_uint p10, const cl_event* p11, cl_event* p12) { return clEnqueueCopyBufferRect_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); } +#undef clEnqueueCopyBufferToImage +#define clEnqueueCopyBufferToImage clEnqueueCopyBufferToImage_fn +inline cl_int clEnqueueCopyBufferToImage(cl_command_queue p0, cl_mem p1, cl_mem p2, size_t p3, const size_t* p4, const size_t* p5, cl_uint p6, const cl_event* p7, cl_event* p8) { return clEnqueueCopyBufferToImage_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8); } +#undef clEnqueueCopyImage +#define clEnqueueCopyImage clEnqueueCopyImage_fn +inline cl_int clEnqueueCopyImage(cl_command_queue p0, cl_mem p1, cl_mem p2, const size_t* p3, const size_t* p4, const size_t* p5, cl_uint p6, const cl_event* p7, cl_event* p8) { return clEnqueueCopyImage_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8); } +#undef clEnqueueCopyImageToBuffer +#define clEnqueueCopyImageToBuffer clEnqueueCopyImageToBuffer_fn +inline cl_int clEnqueueCopyImageToBuffer(cl_command_queue p0, cl_mem p1, cl_mem p2, const size_t* p3, const size_t* p4, size_t p5, cl_uint p6, const cl_event* p7, cl_event* p8) { return clEnqueueCopyImageToBuffer_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8); } +#undef clEnqueueFillBuffer +#define clEnqueueFillBuffer clEnqueueFillBuffer_fn +inline cl_int clEnqueueFillBuffer(cl_command_queue p0, cl_mem p1, const void* p2, size_t p3, size_t p4, size_t p5, cl_uint p6, const cl_event* p7, cl_event* p8) { return clEnqueueFillBuffer_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8); } +#undef clEnqueueFillImage +#define clEnqueueFillImage clEnqueueFillImage_fn +inline cl_int clEnqueueFillImage(cl_command_queue p0, cl_mem p1, const void* p2, const size_t* p3, const size_t* p4, cl_uint p5, const cl_event* p6, cl_event* p7) { return clEnqueueFillImage_pfn(p0, p1, p2, p3, p4, p5, p6, p7); } +#undef clEnqueueMapBuffer +#define clEnqueueMapBuffer clEnqueueMapBuffer_fn +inline void* clEnqueueMapBuffer(cl_command_queue p0, cl_mem p1, cl_bool p2, cl_map_flags p3, size_t p4, size_t p5, cl_uint p6, const cl_event* p7, cl_event* p8, cl_int* p9) { return clEnqueueMapBuffer_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); } +#undef clEnqueueMapImage +#define clEnqueueMapImage clEnqueueMapImage_fn +inline void* clEnqueueMapImage(cl_command_queue p0, cl_mem p1, cl_bool p2, cl_map_flags p3, const size_t* p4, const size_t* p5, size_t* p6, size_t* p7, cl_uint p8, const cl_event* p9, cl_event* p10, cl_int* p11) { return clEnqueueMapImage_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); } +#undef clEnqueueMarker +#define clEnqueueMarker clEnqueueMarker_fn +inline cl_int clEnqueueMarker(cl_command_queue p0, cl_event* p1) { return clEnqueueMarker_pfn(p0, p1); } +#undef clEnqueueMarkerWithWaitList +#define clEnqueueMarkerWithWaitList clEnqueueMarkerWithWaitList_fn +inline cl_int clEnqueueMarkerWithWaitList(cl_command_queue p0, cl_uint p1, const cl_event* p2, cl_event* p3) { return clEnqueueMarkerWithWaitList_pfn(p0, p1, p2, p3); } +#undef clEnqueueMigrateMemObjects +#define clEnqueueMigrateMemObjects clEnqueueMigrateMemObjects_fn +inline cl_int clEnqueueMigrateMemObjects(cl_command_queue p0, cl_uint p1, const cl_mem* p2, cl_mem_migration_flags p3, cl_uint p4, const cl_event* p5, cl_event* p6) { return clEnqueueMigrateMemObjects_pfn(p0, p1, p2, p3, p4, p5, p6); } +#undef clEnqueueNDRangeKernel +#define clEnqueueNDRangeKernel clEnqueueNDRangeKernel_fn +inline cl_int clEnqueueNDRangeKernel(cl_command_queue p0, cl_kernel p1, cl_uint p2, const size_t* p3, const size_t* p4, const size_t* p5, cl_uint p6, const cl_event* p7, cl_event* p8) { return clEnqueueNDRangeKernel_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8); } +#undef clEnqueueNativeKernel +#define clEnqueueNativeKernel clEnqueueNativeKernel_fn +inline cl_int clEnqueueNativeKernel(cl_command_queue p0, void (CL_CALLBACK*p1) (void*), void* p2, size_t p3, cl_uint p4, const cl_mem* p5, const void** p6, cl_uint p7, const cl_event* p8, cl_event* p9) { return clEnqueueNativeKernel_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); } +#undef clEnqueueReadBuffer +#define clEnqueueReadBuffer clEnqueueReadBuffer_fn +inline cl_int clEnqueueReadBuffer(cl_command_queue p0, cl_mem p1, cl_bool p2, size_t p3, size_t p4, void* p5, cl_uint p6, const cl_event* p7, cl_event* p8) { return clEnqueueReadBuffer_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8); } +#undef clEnqueueReadBufferRect +#define clEnqueueReadBufferRect clEnqueueReadBufferRect_fn +inline cl_int clEnqueueReadBufferRect(cl_command_queue p0, cl_mem p1, cl_bool p2, const size_t* p3, const size_t* p4, const size_t* p5, size_t p6, size_t p7, size_t p8, size_t p9, void* p10, cl_uint p11, const cl_event* p12, cl_event* p13) { return clEnqueueReadBufferRect_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); } +#undef clEnqueueReadImage +#define clEnqueueReadImage clEnqueueReadImage_fn +inline cl_int clEnqueueReadImage(cl_command_queue p0, cl_mem p1, cl_bool p2, const size_t* p3, const size_t* p4, size_t p5, size_t p6, void* p7, cl_uint p8, const cl_event* p9, cl_event* p10) { return clEnqueueReadImage_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); } +#undef clEnqueueTask +#define clEnqueueTask clEnqueueTask_fn +inline cl_int clEnqueueTask(cl_command_queue p0, cl_kernel p1, cl_uint p2, const cl_event* p3, cl_event* p4) { return clEnqueueTask_pfn(p0, p1, p2, p3, p4); } +#undef clEnqueueUnmapMemObject +#define clEnqueueUnmapMemObject clEnqueueUnmapMemObject_fn +inline cl_int clEnqueueUnmapMemObject(cl_command_queue p0, cl_mem p1, void* p2, cl_uint p3, const cl_event* p4, cl_event* p5) { return clEnqueueUnmapMemObject_pfn(p0, p1, p2, p3, p4, p5); } +#undef clEnqueueWaitForEvents +#define clEnqueueWaitForEvents clEnqueueWaitForEvents_fn +inline cl_int clEnqueueWaitForEvents(cl_command_queue p0, cl_uint p1, const cl_event* p2) { return clEnqueueWaitForEvents_pfn(p0, p1, p2); } +#undef clEnqueueWriteBuffer +#define clEnqueueWriteBuffer clEnqueueWriteBuffer_fn +inline cl_int clEnqueueWriteBuffer(cl_command_queue p0, cl_mem p1, cl_bool p2, size_t p3, size_t p4, const void* p5, cl_uint p6, const cl_event* p7, cl_event* p8) { return clEnqueueWriteBuffer_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8); } +#undef clEnqueueWriteBufferRect +#define clEnqueueWriteBufferRect clEnqueueWriteBufferRect_fn +inline cl_int clEnqueueWriteBufferRect(cl_command_queue p0, cl_mem p1, cl_bool p2, const size_t* p3, const size_t* p4, const size_t* p5, size_t p6, size_t p7, size_t p8, size_t p9, const void* p10, cl_uint p11, const cl_event* p12, cl_event* p13) { return clEnqueueWriteBufferRect_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); } +#undef clEnqueueWriteImage +#define clEnqueueWriteImage clEnqueueWriteImage_fn +inline cl_int clEnqueueWriteImage(cl_command_queue p0, cl_mem p1, cl_bool p2, const size_t* p3, const size_t* p4, size_t p5, size_t p6, const void* p7, cl_uint p8, const cl_event* p9, cl_event* p10) { return clEnqueueWriteImage_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); } +#undef clFinish +#define clFinish clFinish_fn +inline cl_int clFinish(cl_command_queue p0) { return clFinish_pfn(p0); } +#undef clFlush +#define clFlush clFlush_fn +inline cl_int clFlush(cl_command_queue p0) { return clFlush_pfn(p0); } +#undef clGetCommandQueueInfo +#define clGetCommandQueueInfo clGetCommandQueueInfo_fn +inline cl_int clGetCommandQueueInfo(cl_command_queue p0, cl_command_queue_info p1, size_t p2, void* p3, size_t* p4) { return clGetCommandQueueInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetContextInfo +#define clGetContextInfo clGetContextInfo_fn +inline cl_int clGetContextInfo(cl_context p0, cl_context_info p1, size_t p2, void* p3, size_t* p4) { return clGetContextInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetDeviceIDs +#define clGetDeviceIDs clGetDeviceIDs_fn +inline cl_int clGetDeviceIDs(cl_platform_id p0, cl_device_type p1, cl_uint p2, cl_device_id* p3, cl_uint* p4) { return clGetDeviceIDs_pfn(p0, p1, p2, p3, p4); } +#undef clGetDeviceInfo +#define clGetDeviceInfo clGetDeviceInfo_fn +inline cl_int clGetDeviceInfo(cl_device_id p0, cl_device_info p1, size_t p2, void* p3, size_t* p4) { return clGetDeviceInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetEventInfo +#define clGetEventInfo clGetEventInfo_fn +inline cl_int clGetEventInfo(cl_event p0, cl_event_info p1, size_t p2, void* p3, size_t* p4) { return clGetEventInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetEventProfilingInfo +#define clGetEventProfilingInfo clGetEventProfilingInfo_fn +inline cl_int clGetEventProfilingInfo(cl_event p0, cl_profiling_info p1, size_t p2, void* p3, size_t* p4) { return clGetEventProfilingInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetExtensionFunctionAddress +#define clGetExtensionFunctionAddress clGetExtensionFunctionAddress_fn +inline void* clGetExtensionFunctionAddress(const char* p0) { return clGetExtensionFunctionAddress_pfn(p0); } +#undef clGetExtensionFunctionAddressForPlatform +#define clGetExtensionFunctionAddressForPlatform clGetExtensionFunctionAddressForPlatform_fn +inline void* clGetExtensionFunctionAddressForPlatform(cl_platform_id p0, const char* p1) { return clGetExtensionFunctionAddressForPlatform_pfn(p0, p1); } +#undef clGetImageInfo +#define clGetImageInfo clGetImageInfo_fn +inline cl_int clGetImageInfo(cl_mem p0, cl_image_info p1, size_t p2, void* p3, size_t* p4) { return clGetImageInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetKernelArgInfo +#define clGetKernelArgInfo clGetKernelArgInfo_fn +inline cl_int clGetKernelArgInfo(cl_kernel p0, cl_uint p1, cl_kernel_arg_info p2, size_t p3, void* p4, size_t* p5) { return clGetKernelArgInfo_pfn(p0, p1, p2, p3, p4, p5); } +#undef clGetKernelInfo +#define clGetKernelInfo clGetKernelInfo_fn +inline cl_int clGetKernelInfo(cl_kernel p0, cl_kernel_info p1, size_t p2, void* p3, size_t* p4) { return clGetKernelInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetKernelWorkGroupInfo +#define clGetKernelWorkGroupInfo clGetKernelWorkGroupInfo_fn +inline cl_int clGetKernelWorkGroupInfo(cl_kernel p0, cl_device_id p1, cl_kernel_work_group_info p2, size_t p3, void* p4, size_t* p5) { return clGetKernelWorkGroupInfo_pfn(p0, p1, p2, p3, p4, p5); } +#undef clGetMemObjectInfo +#define clGetMemObjectInfo clGetMemObjectInfo_fn +inline cl_int clGetMemObjectInfo(cl_mem p0, cl_mem_info p1, size_t p2, void* p3, size_t* p4) { return clGetMemObjectInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetPlatformIDs +#define clGetPlatformIDs clGetPlatformIDs_fn +inline cl_int clGetPlatformIDs(cl_uint p0, cl_platform_id* p1, cl_uint* p2) { return clGetPlatformIDs_pfn(p0, p1, p2); } +#undef clGetPlatformInfo +#define clGetPlatformInfo clGetPlatformInfo_fn +inline cl_int clGetPlatformInfo(cl_platform_id p0, cl_platform_info p1, size_t p2, void* p3, size_t* p4) { return clGetPlatformInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetProgramBuildInfo +#define clGetProgramBuildInfo clGetProgramBuildInfo_fn +inline cl_int clGetProgramBuildInfo(cl_program p0, cl_device_id p1, cl_program_build_info p2, size_t p3, void* p4, size_t* p5) { return clGetProgramBuildInfo_pfn(p0, p1, p2, p3, p4, p5); } +#undef clGetProgramInfo +#define clGetProgramInfo clGetProgramInfo_fn +inline cl_int clGetProgramInfo(cl_program p0, cl_program_info p1, size_t p2, void* p3, size_t* p4) { return clGetProgramInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetSamplerInfo +#define clGetSamplerInfo clGetSamplerInfo_fn +inline cl_int clGetSamplerInfo(cl_sampler p0, cl_sampler_info p1, size_t p2, void* p3, size_t* p4) { return clGetSamplerInfo_pfn(p0, p1, p2, p3, p4); } +#undef clGetSupportedImageFormats +#define clGetSupportedImageFormats clGetSupportedImageFormats_fn +inline cl_int clGetSupportedImageFormats(cl_context p0, cl_mem_flags p1, cl_mem_object_type p2, cl_uint p3, cl_image_format* p4, cl_uint* p5) { return clGetSupportedImageFormats_pfn(p0, p1, p2, p3, p4, p5); } +#undef clLinkProgram +#define clLinkProgram clLinkProgram_fn +inline cl_program clLinkProgram(cl_context p0, cl_uint p1, const cl_device_id* p2, const char* p3, cl_uint p4, const cl_program* p5, void (CL_CALLBACK*p6) (cl_program, void*), void* p7, cl_int* p8) { return clLinkProgram_pfn(p0, p1, p2, p3, p4, p5, p6, p7, p8); } +#undef clReleaseCommandQueue +#define clReleaseCommandQueue clReleaseCommandQueue_fn +inline cl_int clReleaseCommandQueue(cl_command_queue p0) { return clReleaseCommandQueue_pfn(p0); } +#undef clReleaseContext +#define clReleaseContext clReleaseContext_fn +inline cl_int clReleaseContext(cl_context p0) { return clReleaseContext_pfn(p0); } +#undef clReleaseDevice +#define clReleaseDevice clReleaseDevice_fn +inline cl_int clReleaseDevice(cl_device_id p0) { return clReleaseDevice_pfn(p0); } +#undef clReleaseEvent +#define clReleaseEvent clReleaseEvent_fn +inline cl_int clReleaseEvent(cl_event p0) { return clReleaseEvent_pfn(p0); } +#undef clReleaseKernel +#define clReleaseKernel clReleaseKernel_fn +inline cl_int clReleaseKernel(cl_kernel p0) { return clReleaseKernel_pfn(p0); } +#undef clReleaseMemObject +#define clReleaseMemObject clReleaseMemObject_fn +inline cl_int clReleaseMemObject(cl_mem p0) { return clReleaseMemObject_pfn(p0); } +#undef clReleaseProgram +#define clReleaseProgram clReleaseProgram_fn +inline cl_int clReleaseProgram(cl_program p0) { return clReleaseProgram_pfn(p0); } +#undef clReleaseSampler +#define clReleaseSampler clReleaseSampler_fn +inline cl_int clReleaseSampler(cl_sampler p0) { return clReleaseSampler_pfn(p0); } +#undef clRetainCommandQueue +#define clRetainCommandQueue clRetainCommandQueue_fn +inline cl_int clRetainCommandQueue(cl_command_queue p0) { return clRetainCommandQueue_pfn(p0); } +#undef clRetainContext +#define clRetainContext clRetainContext_fn +inline cl_int clRetainContext(cl_context p0) { return clRetainContext_pfn(p0); } +#undef clRetainDevice +#define clRetainDevice clRetainDevice_fn +inline cl_int clRetainDevice(cl_device_id p0) { return clRetainDevice_pfn(p0); } +#undef clRetainEvent +#define clRetainEvent clRetainEvent_fn +inline cl_int clRetainEvent(cl_event p0) { return clRetainEvent_pfn(p0); } +#undef clRetainKernel +#define clRetainKernel clRetainKernel_fn +inline cl_int clRetainKernel(cl_kernel p0) { return clRetainKernel_pfn(p0); } +#undef clRetainMemObject +#define clRetainMemObject clRetainMemObject_fn +inline cl_int clRetainMemObject(cl_mem p0) { return clRetainMemObject_pfn(p0); } +#undef clRetainProgram +#define clRetainProgram clRetainProgram_fn +inline cl_int clRetainProgram(cl_program p0) { return clRetainProgram_pfn(p0); } +#undef clRetainSampler +#define clRetainSampler clRetainSampler_fn +inline cl_int clRetainSampler(cl_sampler p0) { return clRetainSampler_pfn(p0); } +#undef clSetEventCallback +#define clSetEventCallback clSetEventCallback_fn +inline cl_int clSetEventCallback(cl_event p0, cl_int p1, void (CL_CALLBACK*p2) (cl_event, cl_int, void*), void* p3) { return clSetEventCallback_pfn(p0, p1, p2, p3); } +#undef clSetKernelArg +#define clSetKernelArg clSetKernelArg_fn +inline cl_int clSetKernelArg(cl_kernel p0, cl_uint p1, size_t p2, const void* p3) { return clSetKernelArg_pfn(p0, p1, p2, p3); } +#undef clSetMemObjectDestructorCallback +#define clSetMemObjectDestructorCallback clSetMemObjectDestructorCallback_fn +inline cl_int clSetMemObjectDestructorCallback(cl_mem p0, void (CL_CALLBACK*p1) (cl_mem, void*), void* p2) { return clSetMemObjectDestructorCallback_pfn(p0, p1, p2); } +#undef clSetUserEventStatus +#define clSetUserEventStatus clSetUserEventStatus_fn +inline cl_int clSetUserEventStatus(cl_event p0, cl_int p1) { return clSetUserEventStatus_pfn(p0, p1); } +#undef clUnloadCompiler +#define clUnloadCompiler clUnloadCompiler_fn +inline cl_int clUnloadCompiler() { return clUnloadCompiler_pfn(); } +#undef clUnloadPlatformCompiler +#define clUnloadPlatformCompiler clUnloadPlatformCompiler_fn +inline cl_int clUnloadPlatformCompiler(cl_platform_id p0) { return clUnloadPlatformCompiler_pfn(p0); } +#undef clWaitForEvents +#define clWaitForEvents clWaitForEvents_fn +inline cl_int clWaitForEvents(cl_uint p0, const cl_event* p1) { return clWaitForEvents_pfn(p0, p1); } diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp new file mode 100644 index 0000000..0b12aed --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp @@ -0,0 +1,62 @@ +// +// AUTOGENERATED, DO NOT EDIT +// +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_HPP +#error "Invalid usage" +#endif + +// generated by parser_cl.py +#define clCreateFromGLBuffer clCreateFromGLBuffer_ +#define clCreateFromGLRenderbuffer clCreateFromGLRenderbuffer_ +#define clCreateFromGLTexture clCreateFromGLTexture_ +#define clCreateFromGLTexture2D clCreateFromGLTexture2D_ +#define clCreateFromGLTexture3D clCreateFromGLTexture3D_ +#define clEnqueueAcquireGLObjects clEnqueueAcquireGLObjects_ +#define clEnqueueReleaseGLObjects clEnqueueReleaseGLObjects_ +#define clGetGLContextInfoKHR clGetGLContextInfoKHR_ +#define clGetGLObjectInfo clGetGLObjectInfo_ +#define clGetGLTextureInfo clGetGLTextureInfo_ + +#if defined __APPLE__ +#include +#else +#include +#endif + +// generated by parser_cl.py +#undef clCreateFromGLBuffer +#define clCreateFromGLBuffer clCreateFromGLBuffer_pfn +#undef clCreateFromGLRenderbuffer +#define clCreateFromGLRenderbuffer clCreateFromGLRenderbuffer_pfn +#undef clCreateFromGLTexture +#define clCreateFromGLTexture clCreateFromGLTexture_pfn +#undef clCreateFromGLTexture2D +#define clCreateFromGLTexture2D clCreateFromGLTexture2D_pfn +#undef clCreateFromGLTexture3D +#define clCreateFromGLTexture3D clCreateFromGLTexture3D_pfn +#undef clEnqueueAcquireGLObjects +#define clEnqueueAcquireGLObjects clEnqueueAcquireGLObjects_pfn +#undef clEnqueueReleaseGLObjects +#define clEnqueueReleaseGLObjects clEnqueueReleaseGLObjects_pfn +#undef clGetGLContextInfoKHR +#define clGetGLContextInfoKHR clGetGLContextInfoKHR_pfn +#undef clGetGLObjectInfo +#define clGetGLObjectInfo clGetGLObjectInfo_pfn +#undef clGetGLTextureInfo +#define clGetGLTextureInfo clGetGLTextureInfo_pfn + +#ifdef cl_khr_gl_sharing + +// generated by parser_cl.py +extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateFromGLBuffer)(cl_context, cl_mem_flags, cl_GLuint, int*); +extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateFromGLRenderbuffer)(cl_context, cl_mem_flags, cl_GLuint, cl_int*); +extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateFromGLTexture)(cl_context, cl_mem_flags, cl_GLenum, cl_GLint, cl_GLuint, cl_int*); +extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateFromGLTexture2D)(cl_context, cl_mem_flags, cl_GLenum, cl_GLint, cl_GLuint, cl_int*); +extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateFromGLTexture3D)(cl_context, cl_mem_flags, cl_GLenum, cl_GLint, cl_GLuint, cl_int*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueAcquireGLObjects)(cl_command_queue, cl_uint, const cl_mem*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueReleaseGLObjects)(cl_command_queue, cl_uint, const cl_mem*, cl_uint, const cl_event*, cl_event*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetGLContextInfoKHR)(const cl_context_properties*, cl_gl_context_info, size_t, void*, size_t*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetGLObjectInfo)(cl_mem, cl_gl_object_type*, cl_GLuint*); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetGLTextureInfo)(cl_mem, cl_gl_texture_info, size_t, void*, size_t*); + +#endif // cl_khr_gl_sharing diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl_wrappers.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl_wrappers.hpp new file mode 100644 index 0000000..12f342b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl_wrappers.hpp @@ -0,0 +1,42 @@ +// +// AUTOGENERATED, DO NOT EDIT +// +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_WRAPPERS_HPP +#error "Invalid usage" +#endif + +#ifdef cl_khr_gl_sharing + +// generated by parser_cl.py +#undef clCreateFromGLBuffer +#define clCreateFromGLBuffer clCreateFromGLBuffer_fn +inline cl_mem clCreateFromGLBuffer(cl_context p0, cl_mem_flags p1, cl_GLuint p2, int* p3) { return clCreateFromGLBuffer_pfn(p0, p1, p2, p3); } +#undef clCreateFromGLRenderbuffer +#define clCreateFromGLRenderbuffer clCreateFromGLRenderbuffer_fn +inline cl_mem clCreateFromGLRenderbuffer(cl_context p0, cl_mem_flags p1, cl_GLuint p2, cl_int* p3) { return clCreateFromGLRenderbuffer_pfn(p0, p1, p2, p3); } +#undef clCreateFromGLTexture +#define clCreateFromGLTexture clCreateFromGLTexture_fn +inline cl_mem clCreateFromGLTexture(cl_context p0, cl_mem_flags p1, cl_GLenum p2, cl_GLint p3, cl_GLuint p4, cl_int* p5) { return clCreateFromGLTexture_pfn(p0, p1, p2, p3, p4, p5); } +#undef clCreateFromGLTexture2D +#define clCreateFromGLTexture2D clCreateFromGLTexture2D_fn +inline cl_mem clCreateFromGLTexture2D(cl_context p0, cl_mem_flags p1, cl_GLenum p2, cl_GLint p3, cl_GLuint p4, cl_int* p5) { return clCreateFromGLTexture2D_pfn(p0, p1, p2, p3, p4, p5); } +#undef clCreateFromGLTexture3D +#define clCreateFromGLTexture3D clCreateFromGLTexture3D_fn +inline cl_mem clCreateFromGLTexture3D(cl_context p0, cl_mem_flags p1, cl_GLenum p2, cl_GLint p3, cl_GLuint p4, cl_int* p5) { return clCreateFromGLTexture3D_pfn(p0, p1, p2, p3, p4, p5); } +#undef clEnqueueAcquireGLObjects +#define clEnqueueAcquireGLObjects clEnqueueAcquireGLObjects_fn +inline cl_int clEnqueueAcquireGLObjects(cl_command_queue p0, cl_uint p1, const cl_mem* p2, cl_uint p3, const cl_event* p4, cl_event* p5) { return clEnqueueAcquireGLObjects_pfn(p0, p1, p2, p3, p4, p5); } +#undef clEnqueueReleaseGLObjects +#define clEnqueueReleaseGLObjects clEnqueueReleaseGLObjects_fn +inline cl_int clEnqueueReleaseGLObjects(cl_command_queue p0, cl_uint p1, const cl_mem* p2, cl_uint p3, const cl_event* p4, cl_event* p5) { return clEnqueueReleaseGLObjects_pfn(p0, p1, p2, p3, p4, p5); } +#undef clGetGLContextInfoKHR +#define clGetGLContextInfoKHR clGetGLContextInfoKHR_fn +inline cl_int clGetGLContextInfoKHR(const cl_context_properties* p0, cl_gl_context_info p1, size_t p2, void* p3, size_t* p4) { return clGetGLContextInfoKHR_pfn(p0, p1, p2, p3, p4); } +#undef clGetGLObjectInfo +#define clGetGLObjectInfo clGetGLObjectInfo_fn +inline cl_int clGetGLObjectInfo(cl_mem p0, cl_gl_object_type* p1, cl_GLuint* p2) { return clGetGLObjectInfo_pfn(p0, p1, p2); } +#undef clGetGLTextureInfo +#define clGetGLTextureInfo clGetGLTextureInfo_fn +inline cl_int clGetGLTextureInfo(cl_mem p0, cl_gl_texture_info p1, size_t p2, void* p3, size_t* p4) { return clGetGLTextureInfo_pfn(p0, p1, p2, p3, p4); } + +#endif // cl_khr_gl_sharing diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_clblas.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_clblas.hpp new file mode 100644 index 0000000..ccddf8f --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_clblas.hpp @@ -0,0 +1,53 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 OpenCV Foundation 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. +// +//M*/ + +#ifndef OPENCV_CORE_OCL_RUNTIME_CLAMDBLAS_HPP +#define OPENCV_CORE_OCL_RUNTIME_CLAMDBLAS_HPP + +#ifdef HAVE_CLAMDBLAS + +#include "opencl_core.hpp" + +#include "autogenerated/opencl_clblas.hpp" + +#endif // HAVE_CLAMDBLAS + +#endif // OPENCV_CORE_OCL_RUNTIME_CLAMDBLAS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_clfft.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_clfft.hpp new file mode 100644 index 0000000..7f4af5e --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_clfft.hpp @@ -0,0 +1,53 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 OpenCV Foundation 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. +// +//M*/ + +#ifndef OPENCV_CORE_OCL_RUNTIME_CLAMDFFT_HPP +#define OPENCV_CORE_OCL_RUNTIME_CLAMDFFT_HPP + +#ifdef HAVE_CLAMDFFT + +#include "opencl_core.hpp" + +#include "autogenerated/opencl_clfft.hpp" + +#endif // HAVE_CLAMDFFT + +#endif // OPENCV_CORE_OCL_RUNTIME_CLAMDFFT_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_core.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_core.hpp new file mode 100644 index 0000000..0404b31 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_core.hpp @@ -0,0 +1,84 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 OpenCV Foundation 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. +// +//M*/ + +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_CORE_HPP +#define OPENCV_CORE_OCL_RUNTIME_OPENCL_CORE_HPP + +#ifdef HAVE_OPENCL + +#ifndef CL_RUNTIME_EXPORT +#if (defined(BUILD_SHARED_LIBS) || defined(OPENCV_CORE_SHARED)) && (defined _WIN32 || defined WINCE) && \ + !(defined(__OPENCV_BUILD) && defined(OPENCV_MODULE_IS_PART_OF_WORLD)) +#define CL_RUNTIME_EXPORT __declspec(dllimport) +#else +#define CL_RUNTIME_EXPORT +#endif +#endif + +#ifdef HAVE_OPENCL_SVM +#define clSVMAlloc clSVMAlloc_ +#define clSVMFree clSVMFree_ +#define clSetKernelArgSVMPointer clSetKernelArgSVMPointer_ +#define clSetKernelExecInfo clSetKernelExecInfo_ +#define clEnqueueSVMFree clEnqueueSVMFree_ +#define clEnqueueSVMMemcpy clEnqueueSVMMemcpy_ +#define clEnqueueSVMMemFill clEnqueueSVMMemFill_ +#define clEnqueueSVMMap clEnqueueSVMMap_ +#define clEnqueueSVMUnmap clEnqueueSVMUnmap_ +#endif + +#include "autogenerated/opencl_core.hpp" + +#ifndef CL_DEVICE_DOUBLE_FP_CONFIG +#define CL_DEVICE_DOUBLE_FP_CONFIG 0x1032 +#endif + +#ifndef CL_DEVICE_HALF_FP_CONFIG +#define CL_DEVICE_HALF_FP_CONFIG 0x1033 +#endif + +#ifndef CL_VERSION_1_2 +#define CV_REQUIRE_OPENCL_1_2_ERROR CV_Error(cv::Error::OpenCLApiCallError, "OpenCV compiled without OpenCL v1.2 support, so we can't use functionality from OpenCL v1.2") +#endif + +#endif // HAVE_OPENCL + +#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_CORE_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_core_wrappers.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_core_wrappers.hpp new file mode 100644 index 0000000..38fcae9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_core_wrappers.hpp @@ -0,0 +1,47 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 OpenCV Foundation 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. +// +//M*/ + +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_WRAPPERS_HPP +#define OPENCV_CORE_OCL_RUNTIME_OPENCL_WRAPPERS_HPP + +#include "autogenerated/opencl_core_wrappers.hpp" + +#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_WRAPPERS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_gl.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_gl.hpp new file mode 100644 index 0000000..659c7d8 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_gl.hpp @@ -0,0 +1,53 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 OpenCV Foundation 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. +// +//M*/ + +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_HPP +#define OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_HPP + +#if defined HAVE_OPENCL && defined HAVE_OPENGL + +#include "opencl_core.hpp" + +#include "autogenerated/opencl_gl.hpp" + +#endif // defined HAVE_OPENCL && defined HAVE_OPENGL + +#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_gl_wrappers.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_gl_wrappers.hpp new file mode 100644 index 0000000..9700004 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_gl_wrappers.hpp @@ -0,0 +1,47 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 OpenCV Foundation 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. +// +//M*/ + +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_WRAPPERS_HPP +#define OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_WRAPPERS_HPP + +#include "autogenerated/opencl_gl_wrappers.hpp" + +#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_WRAPPERS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_svm_20.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_svm_20.hpp new file mode 100644 index 0000000..9636b19 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_svm_20.hpp @@ -0,0 +1,48 @@ +/* See LICENSE file in the root OpenCV directory */ + +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_2_0_HPP +#define OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_2_0_HPP + +#if defined(HAVE_OPENCL_SVM) +#include "opencl_core.hpp" + +#include "opencl_svm_definitions.hpp" + +#undef clSVMAlloc +#define clSVMAlloc clSVMAlloc_pfn +#undef clSVMFree +#define clSVMFree clSVMFree_pfn +#undef clSetKernelArgSVMPointer +#define clSetKernelArgSVMPointer clSetKernelArgSVMPointer_pfn +#undef clSetKernelExecInfo +//#define clSetKernelExecInfo clSetKernelExecInfo_pfn +#undef clEnqueueSVMFree +//#define clEnqueueSVMFree clEnqueueSVMFree_pfn +#undef clEnqueueSVMMemcpy +#define clEnqueueSVMMemcpy clEnqueueSVMMemcpy_pfn +#undef clEnqueueSVMMemFill +#define clEnqueueSVMMemFill clEnqueueSVMMemFill_pfn +#undef clEnqueueSVMMap +#define clEnqueueSVMMap clEnqueueSVMMap_pfn +#undef clEnqueueSVMUnmap +#define clEnqueueSVMUnmap clEnqueueSVMUnmap_pfn + +extern CL_RUNTIME_EXPORT void* (CL_API_CALL *clSVMAlloc)(cl_context context, cl_svm_mem_flags flags, size_t size, unsigned int alignment); +extern CL_RUNTIME_EXPORT void (CL_API_CALL *clSVMFree)(cl_context context, void* svm_pointer); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL *clSetKernelArgSVMPointer)(cl_kernel kernel, cl_uint arg_index, const void* arg_value); +//extern CL_RUNTIME_EXPORT void* (CL_API_CALL *clSetKernelExecInfo)(cl_kernel kernel, cl_kernel_exec_info param_name, size_t param_value_size, const void* param_value); +//extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL *clEnqueueSVMFree)(cl_command_queue command_queue, cl_uint num_svm_pointers, void* svm_pointers[], +// void (CL_CALLBACK *pfn_free_func)(cl_command_queue queue, cl_uint num_svm_pointers, void* svm_pointers[], void* user_data), void* user_data, +// cl_uint num_events_in_wait_list, const cl_event* event_wait_list, cl_event* event); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL *clEnqueueSVMMemcpy)(cl_command_queue command_queue, cl_bool blocking_copy, void* dst_ptr, const void* src_ptr, size_t size, + cl_uint num_events_in_wait_list, const cl_event* event_wait_list, cl_event* event); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL *clEnqueueSVMMemFill)(cl_command_queue command_queue, void* svm_ptr, const void* pattern, size_t pattern_size, size_t size, + cl_uint num_events_in_wait_list, const cl_event* event_wait_list, cl_event* event); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL *clEnqueueSVMMap)(cl_command_queue command_queue, cl_bool blocking_map, cl_map_flags map_flags, void* svm_ptr, size_t size, + cl_uint num_events_in_wait_list, const cl_event* event_wait_list, cl_event* event); +extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL *clEnqueueSVMUnmap)(cl_command_queue command_queue, void* svm_ptr, + cl_uint num_events_in_wait_list, const cl_event* event_wait_list, cl_event* event); + +#endif // HAVE_OPENCL_SVM + +#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_2_0_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_svm_definitions.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_svm_definitions.hpp new file mode 100644 index 0000000..97c927b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_svm_definitions.hpp @@ -0,0 +1,42 @@ +/* See LICENSE file in the root OpenCV directory */ + +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_DEFINITIONS_HPP +#define OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_DEFINITIONS_HPP + +#if defined(HAVE_OPENCL_SVM) +#if defined(CL_VERSION_2_0) + +// OpenCL 2.0 contains SVM definitions + +#else + +typedef cl_bitfield cl_device_svm_capabilities; +typedef cl_bitfield cl_svm_mem_flags; +typedef cl_uint cl_kernel_exec_info; + +// +// TODO Add real values after OpenCL 2.0 release +// + +#ifndef CL_DEVICE_SVM_CAPABILITIES +#define CL_DEVICE_SVM_CAPABILITIES 0x1053 + +#define CL_DEVICE_SVM_COARSE_GRAIN_BUFFER (1 << 0) +#define CL_DEVICE_SVM_FINE_GRAIN_BUFFER (1 << 1) +#define CL_DEVICE_SVM_FINE_GRAIN_SYSTEM (1 << 2) +#define CL_DEVICE_SVM_ATOMICS (1 << 3) +#endif + +#ifndef CL_MEM_SVM_FINE_GRAIN_BUFFER +#define CL_MEM_SVM_FINE_GRAIN_BUFFER (1 << 10) +#endif + +#ifndef CL_MEM_SVM_ATOMICS +#define CL_MEM_SVM_ATOMICS (1 << 11) +#endif + + +#endif // CL_VERSION_2_0 +#endif // HAVE_OPENCL_SVM + +#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_DEFINITIONS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_svm_hsa_extension.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_svm_hsa_extension.hpp new file mode 100644 index 0000000..497bc3d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opencl/runtime/opencl_svm_hsa_extension.hpp @@ -0,0 +1,166 @@ +/* See LICENSE file in the root OpenCV directory */ + +#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_HSA_EXTENSION_HPP +#define OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_HSA_EXTENSION_HPP + +#if defined(HAVE_OPENCL_SVM) +#include "opencl_core.hpp" + +#ifndef CL_DEVICE_SVM_CAPABILITIES_AMD +// +// Part of the file is an extract from the cl_ext.h file from AMD APP SDK package. +// Below is the original copyright. +// +/******************************************************************************* + * Copyright (c) 2008-2013 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Materials. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + ******************************************************************************/ + +/******************************************* + * Shared Virtual Memory (SVM) extension + *******************************************/ +typedef cl_bitfield cl_device_svm_capabilities_amd; +typedef cl_bitfield cl_svm_mem_flags_amd; +typedef cl_uint cl_kernel_exec_info_amd; + +/* cl_device_info */ +#define CL_DEVICE_SVM_CAPABILITIES_AMD 0x1053 +#define CL_DEVICE_PREFERRED_PLATFORM_ATOMIC_ALIGNMENT_AMD 0x1054 + +/* cl_device_svm_capabilities_amd */ +#define CL_DEVICE_SVM_COARSE_GRAIN_BUFFER_AMD (1 << 0) +#define CL_DEVICE_SVM_FINE_GRAIN_BUFFER_AMD (1 << 1) +#define CL_DEVICE_SVM_FINE_GRAIN_SYSTEM_AMD (1 << 2) +#define CL_DEVICE_SVM_ATOMICS_AMD (1 << 3) + +/* cl_svm_mem_flags_amd */ +#define CL_MEM_SVM_FINE_GRAIN_BUFFER_AMD (1 << 10) +#define CL_MEM_SVM_ATOMICS_AMD (1 << 11) + +/* cl_mem_info */ +#define CL_MEM_USES_SVM_POINTER_AMD 0x1109 + +/* cl_kernel_exec_info_amd */ +#define CL_KERNEL_EXEC_INFO_SVM_PTRS_AMD 0x11B6 +#define CL_KERNEL_EXEC_INFO_SVM_FINE_GRAIN_SYSTEM_AMD 0x11B7 + +/* cl_command_type */ +#define CL_COMMAND_SVM_FREE_AMD 0x1209 +#define CL_COMMAND_SVM_MEMCPY_AMD 0x120A +#define CL_COMMAND_SVM_MEMFILL_AMD 0x120B +#define CL_COMMAND_SVM_MAP_AMD 0x120C +#define CL_COMMAND_SVM_UNMAP_AMD 0x120D + +typedef CL_API_ENTRY void* +(CL_API_CALL * clSVMAllocAMD_fn)( + cl_context /* context */, + cl_svm_mem_flags_amd /* flags */, + size_t /* size */, + unsigned int /* alignment */ +) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY void +(CL_API_CALL * clSVMFreeAMD_fn)( + cl_context /* context */, + void* /* svm_pointer */ +) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int +(CL_API_CALL * clEnqueueSVMFreeAMD_fn)( + cl_command_queue /* command_queue */, + cl_uint /* num_svm_pointers */, + void** /* svm_pointers */, + void (CL_CALLBACK *)( /*pfn_free_func*/ + cl_command_queue /* queue */, + cl_uint /* num_svm_pointers */, + void** /* svm_pointers */, + void* /* user_data */), + void* /* user_data */, + cl_uint /* num_events_in_wait_list */, + const cl_event* /* event_wait_list */, + cl_event* /* event */ +) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int +(CL_API_CALL * clEnqueueSVMMemcpyAMD_fn)( + cl_command_queue /* command_queue */, + cl_bool /* blocking_copy */, + void* /* dst_ptr */, + const void* /* src_ptr */, + size_t /* size */, + cl_uint /* num_events_in_wait_list */, + const cl_event* /* event_wait_list */, + cl_event* /* event */ +) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int +(CL_API_CALL * clEnqueueSVMMemFillAMD_fn)( + cl_command_queue /* command_queue */, + void* /* svm_ptr */, + const void* /* pattern */, + size_t /* pattern_size */, + size_t /* size */, + cl_uint /* num_events_in_wait_list */, + const cl_event* /* event_wait_list */, + cl_event* /* event */ +) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int +(CL_API_CALL * clEnqueueSVMMapAMD_fn)( + cl_command_queue /* command_queue */, + cl_bool /* blocking_map */, + cl_map_flags /* map_flags */, + void* /* svm_ptr */, + size_t /* size */, + cl_uint /* num_events_in_wait_list */, + const cl_event* /* event_wait_list */, + cl_event* /* event */ +) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int +(CL_API_CALL * clEnqueueSVMUnmapAMD_fn)( + cl_command_queue /* command_queue */, + void* /* svm_ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event* /* event_wait_list */, + cl_event* /* event */ +) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int +(CL_API_CALL * clSetKernelArgSVMPointerAMD_fn)( + cl_kernel /* kernel */, + cl_uint /* arg_index */, + const void * /* arg_value */ +) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int +(CL_API_CALL * clSetKernelExecInfoAMD_fn)( + cl_kernel /* kernel */, + cl_kernel_exec_info_amd /* param_name */, + size_t /* param_value_size */, + const void * /* param_value */ +) CL_EXT_SUFFIX__VERSION_1_2; + +#endif + +#endif // HAVE_OPENCL_SVM + +#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_HSA_EXTENSION_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opengl.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opengl.hpp new file mode 100644 index 0000000..a311ce2 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/opengl.hpp @@ -0,0 +1,725 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_OPENGL_HPP +#define OPENCV_CORE_OPENGL_HPP + +#ifndef __cplusplus +# error opengl.hpp header must be compiled as C++ +#endif + +#include "opencv2/core.hpp" +#include "ocl.hpp" + +namespace cv { namespace ogl { + +/** @addtogroup core_opengl +This section describes OpenGL interoperability. + +To enable OpenGL support, configure OpenCV using CMake with WITH_OPENGL=ON . Currently OpenGL is +supported only with WIN32, GTK and Qt backends on Windows and Linux (MacOS and Android are not +supported). For GTK backend gtkglext-1.0 library is required. + +To use OpenGL functionality you should first create OpenGL context (window or frame buffer). You can +do this with namedWindow function or with other OpenGL toolkit (GLUT, for example). +*/ +//! @{ + +/////////////////// OpenGL Objects /////////////////// + +/** @brief Smart pointer for OpenGL buffer object with reference counting. + +Buffer Objects are OpenGL objects that store an array of unformatted memory allocated by the OpenGL +context. These can be used to store vertex data, pixel data retrieved from images or the +framebuffer, and a variety of other things. + +ogl::Buffer has interface similar with Mat interface and represents 2D array memory. + +ogl::Buffer supports memory transfers between host and device and also can be mapped to CUDA memory. + */ +class CV_EXPORTS Buffer +{ +public: + /** @brief The target defines how you intend to use the buffer object. + */ + enum Target + { + ARRAY_BUFFER = 0x8892, //!< The buffer will be used as a source for vertex data + ELEMENT_ARRAY_BUFFER = 0x8893, //!< The buffer will be used for indices (in glDrawElements, for example) + PIXEL_PACK_BUFFER = 0x88EB, //!< The buffer will be used for reading from OpenGL textures + PIXEL_UNPACK_BUFFER = 0x88EC //!< The buffer will be used for writing to OpenGL textures + }; + + enum Access + { + READ_ONLY = 0x88B8, + WRITE_ONLY = 0x88B9, + READ_WRITE = 0x88BA + }; + + /** @brief The constructors. + + Creates empty ogl::Buffer object, creates ogl::Buffer object from existed buffer ( abufId + parameter), allocates memory for ogl::Buffer object or copies from host/device memory. + */ + Buffer(); + + /** @overload + @param arows Number of rows in a 2D array. + @param acols Number of columns in a 2D array. + @param atype Array type ( CV_8UC1, ..., CV_64FC4 ). See Mat for details. + @param abufId Buffer object name. + @param autoRelease Auto release mode (if true, release will be called in object's destructor). + */ + Buffer(int arows, int acols, int atype, unsigned int abufId, bool autoRelease = false); + + /** @overload + @param asize 2D array size. + @param atype Array type ( CV_8UC1, ..., CV_64FC4 ). See Mat for details. + @param abufId Buffer object name. + @param autoRelease Auto release mode (if true, release will be called in object's destructor). + */ + Buffer(Size asize, int atype, unsigned int abufId, bool autoRelease = false); + + /** @overload + @param arows Number of rows in a 2D array. + @param acols Number of columns in a 2D array. + @param atype Array type ( CV_8UC1, ..., CV_64FC4 ). See Mat for details. + @param target Buffer usage. See cv::ogl::Buffer::Target . + @param autoRelease Auto release mode (if true, release will be called in object's destructor). + */ + Buffer(int arows, int acols, int atype, Target target = ARRAY_BUFFER, bool autoRelease = false); + + /** @overload + @param asize 2D array size. + @param atype Array type ( CV_8UC1, ..., CV_64FC4 ). See Mat for details. + @param target Buffer usage. See cv::ogl::Buffer::Target . + @param autoRelease Auto release mode (if true, release will be called in object's destructor). + */ + Buffer(Size asize, int atype, Target target = ARRAY_BUFFER, bool autoRelease = false); + + /** @overload + @param arr Input array (host or device memory, it can be Mat , cuda::GpuMat or std::vector ). + @param target Buffer usage. See cv::ogl::Buffer::Target . + @param autoRelease Auto release mode (if true, release will be called in object's destructor). + */ + explicit Buffer(InputArray arr, Target target = ARRAY_BUFFER, bool autoRelease = false); + + /** @brief Allocates memory for ogl::Buffer object. + + @param arows Number of rows in a 2D array. + @param acols Number of columns in a 2D array. + @param atype Array type ( CV_8UC1, ..., CV_64FC4 ). See Mat for details. + @param target Buffer usage. See cv::ogl::Buffer::Target . + @param autoRelease Auto release mode (if true, release will be called in object's destructor). + */ + void create(int arows, int acols, int atype, Target target = ARRAY_BUFFER, bool autoRelease = false); + + /** @overload + @param asize 2D array size. + @param atype Array type ( CV_8UC1, ..., CV_64FC4 ). See Mat for details. + @param target Buffer usage. See cv::ogl::Buffer::Target . + @param autoRelease Auto release mode (if true, release will be called in object's destructor). + */ + void create(Size asize, int atype, Target target = ARRAY_BUFFER, bool autoRelease = false); + + /** @brief Decrements the reference counter and destroys the buffer object if needed. + + The function will call setAutoRelease(true) . + */ + void release(); + + /** @brief Sets auto release mode. + + The lifetime of the OpenGL object is tied to the lifetime of the context. If OpenGL context was + bound to a window it could be released at any time (user can close a window). If object's destructor + is called after destruction of the context it will cause an error. Thus ogl::Buffer doesn't destroy + OpenGL object in destructor by default (all OpenGL resources will be released with OpenGL context). + This function can force ogl::Buffer destructor to destroy OpenGL object. + @param flag Auto release mode (if true, release will be called in object's destructor). + */ + void setAutoRelease(bool flag); + + /** @brief Copies from host/device memory to OpenGL buffer. + @param arr Input array (host or device memory, it can be Mat , cuda::GpuMat or std::vector ). + @param target Buffer usage. See cv::ogl::Buffer::Target . + @param autoRelease Auto release mode (if true, release will be called in object's destructor). + */ + void copyFrom(InputArray arr, Target target = ARRAY_BUFFER, bool autoRelease = false); + + /** @overload */ + void copyFrom(InputArray arr, cuda::Stream& stream, Target target = ARRAY_BUFFER, bool autoRelease = false); + + /** @brief Copies from OpenGL buffer to host/device memory or another OpenGL buffer object. + + @param arr Destination array (host or device memory, can be Mat , cuda::GpuMat , std::vector or + ogl::Buffer ). + */ + void copyTo(OutputArray arr) const; + + /** @overload */ + void copyTo(OutputArray arr, cuda::Stream& stream) const; + + /** @brief Creates a full copy of the buffer object and the underlying data. + + @param target Buffer usage for destination buffer. + @param autoRelease Auto release mode for destination buffer. + */ + Buffer clone(Target target = ARRAY_BUFFER, bool autoRelease = false) const; + + /** @brief Binds OpenGL buffer to the specified buffer binding point. + + @param target Binding point. See cv::ogl::Buffer::Target . + */ + void bind(Target target) const; + + /** @brief Unbind any buffers from the specified binding point. + + @param target Binding point. See cv::ogl::Buffer::Target . + */ + static void unbind(Target target); + + /** @brief Maps OpenGL buffer to host memory. + + mapHost maps to the client's address space the entire data store of the buffer object. The data can + then be directly read and/or written relative to the returned pointer, depending on the specified + access policy. + + A mapped data store must be unmapped with ogl::Buffer::unmapHost before its buffer object is used. + + This operation can lead to memory transfers between host and device. + + Only one buffer object can be mapped at a time. + @param access Access policy, indicating whether it will be possible to read from, write to, or both + read from and write to the buffer object's mapped data store. The symbolic constant must be + ogl::Buffer::READ_ONLY , ogl::Buffer::WRITE_ONLY or ogl::Buffer::READ_WRITE . + */ + Mat mapHost(Access access); + + /** @brief Unmaps OpenGL buffer. + */ + void unmapHost(); + + //! map to device memory (blocking) + cuda::GpuMat mapDevice(); + void unmapDevice(); + + /** @brief Maps OpenGL buffer to CUDA device memory. + + This operation doesn't copy data. Several buffer objects can be mapped to CUDA memory at a time. + + A mapped data store must be unmapped with ogl::Buffer::unmapDevice before its buffer object is used. + */ + cuda::GpuMat mapDevice(cuda::Stream& stream); + + /** @brief Unmaps OpenGL buffer. + */ + void unmapDevice(cuda::Stream& stream); + + int rows() const; + int cols() const; + Size size() const; + bool empty() const; + + int type() const; + int depth() const; + int channels() const; + int elemSize() const; + int elemSize1() const; + + //! get OpenGL opject id + unsigned int bufId() const; + + class Impl; + +private: + Ptr impl_; + int rows_; + int cols_; + int type_; +}; + +/** @brief Smart pointer for OpenGL 2D texture memory with reference counting. + */ +class CV_EXPORTS Texture2D +{ +public: + /** @brief An Image Format describes the way that the images in Textures store their data. + */ + enum Format + { + NONE = 0, + DEPTH_COMPONENT = 0x1902, //!< Depth + RGB = 0x1907, //!< Red, Green, Blue + RGBA = 0x1908 //!< Red, Green, Blue, Alpha + }; + + /** @brief The constructors. + + Creates empty ogl::Texture2D object, allocates memory for ogl::Texture2D object or copies from + host/device memory. + */ + Texture2D(); + + /** @overload */ + Texture2D(int arows, int acols, Format aformat, unsigned int atexId, bool autoRelease = false); + + /** @overload */ + Texture2D(Size asize, Format aformat, unsigned int atexId, bool autoRelease = false); + + /** @overload + @param arows Number of rows. + @param acols Number of columns. + @param aformat Image format. See cv::ogl::Texture2D::Format . + @param autoRelease Auto release mode (if true, release will be called in object's destructor). + */ + Texture2D(int arows, int acols, Format aformat, bool autoRelease = false); + + /** @overload + @param asize 2D array size. + @param aformat Image format. See cv::ogl::Texture2D::Format . + @param autoRelease Auto release mode (if true, release will be called in object's destructor). + */ + Texture2D(Size asize, Format aformat, bool autoRelease = false); + + /** @overload + @param arr Input array (host or device memory, it can be Mat , cuda::GpuMat or ogl::Buffer ). + @param autoRelease Auto release mode (if true, release will be called in object's destructor). + */ + explicit Texture2D(InputArray arr, bool autoRelease = false); + + /** @brief Allocates memory for ogl::Texture2D object. + + @param arows Number of rows. + @param acols Number of columns. + @param aformat Image format. See cv::ogl::Texture2D::Format . + @param autoRelease Auto release mode (if true, release will be called in object's destructor). + */ + void create(int arows, int acols, Format aformat, bool autoRelease = false); + /** @overload + @param asize 2D array size. + @param aformat Image format. See cv::ogl::Texture2D::Format . + @param autoRelease Auto release mode (if true, release will be called in object's destructor). + */ + void create(Size asize, Format aformat, bool autoRelease = false); + + /** @brief Decrements the reference counter and destroys the texture object if needed. + + The function will call setAutoRelease(true) . + */ + void release(); + + /** @brief Sets auto release mode. + + @param flag Auto release mode (if true, release will be called in object's destructor). + + The lifetime of the OpenGL object is tied to the lifetime of the context. If OpenGL context was + bound to a window it could be released at any time (user can close a window). If object's destructor + is called after destruction of the context it will cause an error. Thus ogl::Texture2D doesn't + destroy OpenGL object in destructor by default (all OpenGL resources will be released with OpenGL + context). This function can force ogl::Texture2D destructor to destroy OpenGL object. + */ + void setAutoRelease(bool flag); + + /** @brief Copies from host/device memory to OpenGL texture. + + @param arr Input array (host or device memory, it can be Mat , cuda::GpuMat or ogl::Buffer ). + @param autoRelease Auto release mode (if true, release will be called in object's destructor). + */ + void copyFrom(InputArray arr, bool autoRelease = false); + + /** @brief Copies from OpenGL texture to host/device memory or another OpenGL texture object. + + @param arr Destination array (host or device memory, can be Mat , cuda::GpuMat , ogl::Buffer or + ogl::Texture2D ). + @param ddepth Destination depth. + @param autoRelease Auto release mode for destination buffer (if arr is OpenGL buffer or texture). + */ + void copyTo(OutputArray arr, int ddepth = CV_32F, bool autoRelease = false) const; + + /** @brief Binds texture to current active texture unit for GL_TEXTURE_2D target. + */ + void bind() const; + + int rows() const; + int cols() const; + Size size() const; + bool empty() const; + + Format format() const; + + //! get OpenGL opject id + unsigned int texId() const; + + class Impl; + +private: + Ptr impl_; + int rows_; + int cols_; + Format format_; +}; + +/** @brief Wrapper for OpenGL Client-Side Vertex arrays. + +ogl::Arrays stores vertex data in ogl::Buffer objects. + */ +class CV_EXPORTS Arrays +{ +public: + /** @brief Default constructor + */ + Arrays(); + + /** @brief Sets an array of vertex coordinates. + @param vertex array with vertex coordinates, can be both host and device memory. + */ + void setVertexArray(InputArray vertex); + + /** @brief Resets vertex coordinates. + */ + void resetVertexArray(); + + /** @brief Sets an array of vertex colors. + @param color array with vertex colors, can be both host and device memory. + */ + void setColorArray(InputArray color); + + /** @brief Resets vertex colors. + */ + void resetColorArray(); + + /** @brief Sets an array of vertex normals. + @param normal array with vertex normals, can be both host and device memory. + */ + void setNormalArray(InputArray normal); + + /** @brief Resets vertex normals. + */ + void resetNormalArray(); + + /** @brief Sets an array of vertex texture coordinates. + @param texCoord array with vertex texture coordinates, can be both host and device memory. + */ + void setTexCoordArray(InputArray texCoord); + + /** @brief Resets vertex texture coordinates. + */ + void resetTexCoordArray(); + + /** @brief Releases all inner buffers. + */ + void release(); + + /** @brief Sets auto release mode all inner buffers. + @param flag Auto release mode. + */ + void setAutoRelease(bool flag); + + /** @brief Binds all vertex arrays. + */ + void bind() const; + + /** @brief Returns the vertex count. + */ + int size() const; + bool empty() const; + +private: + int size_; + Buffer vertex_; + Buffer color_; + Buffer normal_; + Buffer texCoord_; +}; + +/////////////////// Render Functions /////////////////// + +//! render mode +enum RenderModes { + POINTS = 0x0000, + LINES = 0x0001, + LINE_LOOP = 0x0002, + LINE_STRIP = 0x0003, + TRIANGLES = 0x0004, + TRIANGLE_STRIP = 0x0005, + TRIANGLE_FAN = 0x0006, + QUADS = 0x0007, + QUAD_STRIP = 0x0008, + POLYGON = 0x0009 +}; + +/** @brief Render OpenGL texture or primitives. +@param tex Texture to draw. +@param wndRect Region of window, where to draw a texture (normalized coordinates). +@param texRect Region of texture to draw (normalized coordinates). + */ +CV_EXPORTS void render(const Texture2D& tex, + Rect_ wndRect = Rect_(0.0, 0.0, 1.0, 1.0), + Rect_ texRect = Rect_(0.0, 0.0, 1.0, 1.0)); + +/** @overload +@param arr Array of privitives vertices. +@param mode Render mode. One of cv::ogl::RenderModes +@param color Color for all vertices. Will be used if arr doesn't contain color array. +*/ +CV_EXPORTS void render(const Arrays& arr, int mode = POINTS, Scalar color = Scalar::all(255)); + +/** @overload +@param arr Array of privitives vertices. +@param indices Array of vertices indices (host or device memory). +@param mode Render mode. One of cv::ogl::RenderModes +@param color Color for all vertices. Will be used if arr doesn't contain color array. +*/ +CV_EXPORTS void render(const Arrays& arr, InputArray indices, int mode = POINTS, Scalar color = Scalar::all(255)); + +/////////////////// CL-GL Interoperability Functions /////////////////// + +namespace ocl { +using namespace cv::ocl; + +// TODO static functions in the Context class +/** @brief Creates OpenCL context from GL. +@return Returns reference to OpenCL Context + */ +CV_EXPORTS Context& initializeContextFromGL(); + +} // namespace cv::ogl::ocl + +/** @brief Converts InputArray to Texture2D object. +@param src - source InputArray. +@param texture - destination Texture2D object. + */ +CV_EXPORTS void convertToGLTexture2D(InputArray src, Texture2D& texture); + +/** @brief Converts Texture2D object to OutputArray. +@param texture - source Texture2D object. +@param dst - destination OutputArray. + */ +CV_EXPORTS void convertFromGLTexture2D(const Texture2D& texture, OutputArray dst); + +/** @brief Maps Buffer object to process on CL side (convert to UMat). + +Function creates CL buffer from GL one, and then constructs UMat that can be used +to process buffer data with OpenCV functions. Note that in current implementation +UMat constructed this way doesn't own corresponding GL buffer object, so it is +the user responsibility to close down CL/GL buffers relationships by explicitly +calling unmapGLBuffer() function. +@param buffer - source Buffer object. +@param accessFlags - data access flags (ACCESS_READ|ACCESS_WRITE). +@return Returns UMat object + */ +CV_EXPORTS UMat mapGLBuffer(const Buffer& buffer, AccessFlag accessFlags = ACCESS_READ | ACCESS_WRITE); + +/** @brief Unmaps Buffer object (releases UMat, previously mapped from Buffer). + +Function must be called explicitly by the user for each UMat previously constructed +by the call to mapGLBuffer() function. +@param u - source UMat, created by mapGLBuffer(). + */ +CV_EXPORTS void unmapGLBuffer(UMat& u); + +//! @} +}} // namespace cv::ogl + +namespace cv { namespace cuda { + +/** @brief Sets a CUDA device and initializes it for the current thread with OpenGL interoperability. + +This function should be explicitly called after OpenGL context creation and before any CUDA calls. +@param device System index of a CUDA device starting with 0. +@ingroup core_opengl + */ +CV_EXPORTS void setGlDevice(int device = 0); + +}} + +//! @cond IGNORED + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +inline +cv::ogl::Buffer::Buffer(int arows, int acols, int atype, Target target, bool autoRelease) : rows_(0), cols_(0), type_(0) +{ + create(arows, acols, atype, target, autoRelease); +} + +inline +cv::ogl::Buffer::Buffer(Size asize, int atype, Target target, bool autoRelease) : rows_(0), cols_(0), type_(0) +{ + create(asize, atype, target, autoRelease); +} + +inline +void cv::ogl::Buffer::create(Size asize, int atype, Target target, bool autoRelease) +{ + create(asize.height, asize.width, atype, target, autoRelease); +} + +inline +int cv::ogl::Buffer::rows() const +{ + return rows_; +} + +inline +int cv::ogl::Buffer::cols() const +{ + return cols_; +} + +inline +cv::Size cv::ogl::Buffer::size() const +{ + return Size(cols_, rows_); +} + +inline +bool cv::ogl::Buffer::empty() const +{ + return rows_ == 0 || cols_ == 0; +} + +inline +int cv::ogl::Buffer::type() const +{ + return type_; +} + +inline +int cv::ogl::Buffer::depth() const +{ + return CV_MAT_DEPTH(type_); +} + +inline +int cv::ogl::Buffer::channels() const +{ + return CV_MAT_CN(type_); +} + +inline +int cv::ogl::Buffer::elemSize() const +{ + return CV_ELEM_SIZE(type_); +} + +inline +int cv::ogl::Buffer::elemSize1() const +{ + return CV_ELEM_SIZE1(type_); +} + +/////// + +inline +cv::ogl::Texture2D::Texture2D(int arows, int acols, Format aformat, bool autoRelease) : rows_(0), cols_(0), format_(NONE) +{ + create(arows, acols, aformat, autoRelease); +} + +inline +cv::ogl::Texture2D::Texture2D(Size asize, Format aformat, bool autoRelease) : rows_(0), cols_(0), format_(NONE) +{ + create(asize, aformat, autoRelease); +} + +inline +void cv::ogl::Texture2D::create(Size asize, Format aformat, bool autoRelease) +{ + create(asize.height, asize.width, aformat, autoRelease); +} + +inline +int cv::ogl::Texture2D::rows() const +{ + return rows_; +} + +inline +int cv::ogl::Texture2D::cols() const +{ + return cols_; +} + +inline +cv::Size cv::ogl::Texture2D::size() const +{ + return Size(cols_, rows_); +} + +inline +bool cv::ogl::Texture2D::empty() const +{ + return rows_ == 0 || cols_ == 0; +} + +inline +cv::ogl::Texture2D::Format cv::ogl::Texture2D::format() const +{ + return format_; +} + +/////// + +inline +cv::ogl::Arrays::Arrays() : size_(0) +{ +} + +inline +int cv::ogl::Arrays::size() const +{ + return size_; +} + +inline +bool cv::ogl::Arrays::empty() const +{ + return size_ == 0; +} + +//! @endcond + +#endif /* OPENCV_CORE_OPENGL_HPP */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/operations.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/operations.hpp new file mode 100644 index 0000000..43a9eb8 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/operations.hpp @@ -0,0 +1,610 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_OPERATIONS_HPP +#define OPENCV_CORE_OPERATIONS_HPP + +#ifndef __cplusplus +# error operations.hpp header must be compiled as C++ +#endif + +#include + +#if defined(__GNUC__) || defined(__clang__) // at least GCC 3.1+, clang 3.5+ +# if defined(__MINGW_PRINTF_FORMAT) // https://sourceforge.net/p/mingw-w64/wiki2/gnu%20printf/. +# define CV_FORMAT_PRINTF(string_idx, first_to_check) __attribute__ ((format (__MINGW_PRINTF_FORMAT, string_idx, first_to_check))) +# else +# define CV_FORMAT_PRINTF(string_idx, first_to_check) __attribute__ ((format (printf, string_idx, first_to_check))) +# endif +#else +# define CV_FORMAT_PRINTF(A, B) +#endif + +//! @cond IGNORED + +namespace cv +{ + +////////////////////////////// Matx methods depending on core API ///////////////////////////// + +namespace internal +{ + +template struct Matx_FastInvOp +{ + bool operator()(const Matx<_Tp, m, n>& a, Matx<_Tp, n, m>& b, int method) const + { + return invert(a, b, method) != 0; + } +}; + +template struct Matx_FastInvOp<_Tp, m, m> +{ + bool operator()(const Matx<_Tp, m, m>& a, Matx<_Tp, m, m>& b, int method) const + { + if (method == DECOMP_LU || method == DECOMP_CHOLESKY) + { + Matx<_Tp, m, m> temp = a; + + // assume that b is all 0's on input => make it a unity matrix + for (int i = 0; i < m; i++) + b(i, i) = (_Tp)1; + + if (method == DECOMP_CHOLESKY) + return Cholesky(temp.val, m*sizeof(_Tp), m, b.val, m*sizeof(_Tp), m); + + return LU(temp.val, m*sizeof(_Tp), m, b.val, m*sizeof(_Tp), m) != 0; + } + else + { + return invert(a, b, method) != 0; + } + } +}; + +template struct Matx_FastInvOp<_Tp, 2, 2> +{ + bool operator()(const Matx<_Tp, 2, 2>& a, Matx<_Tp, 2, 2>& b, int /*method*/) const + { + _Tp d = (_Tp)determinant(a); + if (d == 0) + return false; + d = 1/d; + b(1,1) = a(0,0)*d; + b(0,0) = a(1,1)*d; + b(0,1) = -a(0,1)*d; + b(1,0) = -a(1,0)*d; + return true; + } +}; + +template struct Matx_FastInvOp<_Tp, 3, 3> +{ + bool operator()(const Matx<_Tp, 3, 3>& a, Matx<_Tp, 3, 3>& b, int /*method*/) const + { + _Tp d = (_Tp)determinant(a); + if (d == 0) + return false; + d = 1/d; + b(0,0) = (a(1,1) * a(2,2) - a(1,2) * a(2,1)) * d; + b(0,1) = (a(0,2) * a(2,1) - a(0,1) * a(2,2)) * d; + b(0,2) = (a(0,1) * a(1,2) - a(0,2) * a(1,1)) * d; + + b(1,0) = (a(1,2) * a(2,0) - a(1,0) * a(2,2)) * d; + b(1,1) = (a(0,0) * a(2,2) - a(0,2) * a(2,0)) * d; + b(1,2) = (a(0,2) * a(1,0) - a(0,0) * a(1,2)) * d; + + b(2,0) = (a(1,0) * a(2,1) - a(1,1) * a(2,0)) * d; + b(2,1) = (a(0,1) * a(2,0) - a(0,0) * a(2,1)) * d; + b(2,2) = (a(0,0) * a(1,1) - a(0,1) * a(1,0)) * d; + return true; + } +}; + + +template struct Matx_FastSolveOp +{ + bool operator()(const Matx<_Tp, m, l>& a, const Matx<_Tp, m, n>& b, + Matx<_Tp, l, n>& x, int method) const + { + return cv::solve(a, b, x, method); + } +}; + +template struct Matx_FastSolveOp<_Tp, m, m, n> +{ + bool operator()(const Matx<_Tp, m, m>& a, const Matx<_Tp, m, n>& b, + Matx<_Tp, m, n>& x, int method) const + { + if (method == DECOMP_LU || method == DECOMP_CHOLESKY) + { + Matx<_Tp, m, m> temp = a; + x = b; + if( method == DECOMP_CHOLESKY ) + return Cholesky(temp.val, m*sizeof(_Tp), m, x.val, n*sizeof(_Tp), n); + + return LU(temp.val, m*sizeof(_Tp), m, x.val, n*sizeof(_Tp), n) != 0; + } + else + { + return cv::solve(a, b, x, method); + } + } +}; + +template struct Matx_FastSolveOp<_Tp, 2, 2, 1> +{ + bool operator()(const Matx<_Tp, 2, 2>& a, const Matx<_Tp, 2, 1>& b, + Matx<_Tp, 2, 1>& x, int) const + { + _Tp d = (_Tp)determinant(a); + if (d == 0) + return false; + d = 1/d; + x(0) = (b(0)*a(1,1) - b(1)*a(0,1))*d; + x(1) = (b(1)*a(0,0) - b(0)*a(1,0))*d; + return true; + } +}; + +template struct Matx_FastSolveOp<_Tp, 3, 3, 1> +{ + bool operator()(const Matx<_Tp, 3, 3>& a, const Matx<_Tp, 3, 1>& b, + Matx<_Tp, 3, 1>& x, int) const + { + _Tp d = (_Tp)determinant(a); + if (d == 0) + return false; + d = 1/d; + x(0) = d*(b(0)*(a(1,1)*a(2,2) - a(1,2)*a(2,1)) - + a(0,1)*(b(1)*a(2,2) - a(1,2)*b(2)) + + a(0,2)*(b(1)*a(2,1) - a(1,1)*b(2))); + + x(1) = d*(a(0,0)*(b(1)*a(2,2) - a(1,2)*b(2)) - + b(0)*(a(1,0)*a(2,2) - a(1,2)*a(2,0)) + + a(0,2)*(a(1,0)*b(2) - b(1)*a(2,0))); + + x(2) = d*(a(0,0)*(a(1,1)*b(2) - b(1)*a(2,1)) - + a(0,1)*(a(1,0)*b(2) - b(1)*a(2,0)) + + b(0)*(a(1,0)*a(2,1) - a(1,1)*a(2,0))); + return true; + } +}; + +} // internal + +template inline +Matx<_Tp,m,n> Matx<_Tp,m,n>::randu(_Tp a, _Tp b) +{ + Matx<_Tp,m,n> M; + cv::randu(M, Scalar(a), Scalar(b)); + return M; +} + +template inline +Matx<_Tp,m,n> Matx<_Tp,m,n>::randn(_Tp a, _Tp b) +{ + Matx<_Tp,m,n> M; + cv::randn(M, Scalar(a), Scalar(b)); + return M; +} + +template inline +Vec<_Tp, cn> Vec<_Tp, cn>::randu(_Tp a, _Tp b) +{ + Vec<_Tp,cn> V; + cv::randu(V, Scalar(a), Scalar(b)); + return V; +} + +template inline +Vec<_Tp, cn> Vec<_Tp, cn>::randn(_Tp a, _Tp b) +{ + Vec<_Tp,cn> V; + cv::randn(V, Scalar(a), Scalar(b)); + return V; +} + +template inline +Matx<_Tp, n, m> Matx<_Tp, m, n>::inv(int method, bool *p_is_ok /*= NULL*/) const +{ + Matx<_Tp, n, m> b; + bool ok = cv::internal::Matx_FastInvOp<_Tp, m, n>()(*this, b, method); + if (p_is_ok) *p_is_ok = ok; + return ok ? b : Matx<_Tp, n, m>::zeros(); +} + +template template inline +Matx<_Tp, n, l> Matx<_Tp, m, n>::solve(const Matx<_Tp, m, l>& rhs, int method) const +{ + Matx<_Tp, n, l> x; + bool ok = cv::internal::Matx_FastSolveOp<_Tp, m, n, l>()(*this, rhs, x, method); + return ok ? x : Matx<_Tp, n, l>::zeros(); +} + + + +////////////////////////// Augmenting algebraic & logical operations ////////////////////////// + +#define CV_MAT_AUG_OPERATOR1(op, cvop, A, B) \ + static inline A& operator op (A& a, const B& b) { cvop; return a; } + +#define CV_MAT_AUG_OPERATOR(op, cvop, A, B) \ + CV_MAT_AUG_OPERATOR1(op, cvop, A, B) \ + CV_MAT_AUG_OPERATOR1(op, cvop, const A, B) + +#define CV_MAT_AUG_OPERATOR_T(op, cvop, A, B) \ + template CV_MAT_AUG_OPERATOR1(op, cvop, A, B) \ + template CV_MAT_AUG_OPERATOR1(op, cvop, const A, B) + +#define CV_MAT_AUG_OPERATOR_TN(op, cvop, A) \ + template static inline A& operator op (A& a, const Matx<_Tp,m,n>& b) { cvop; return a; } \ + template static inline const A& operator op (const A& a, const Matx<_Tp,m,n>& b) { cvop; return a; } + +CV_MAT_AUG_OPERATOR (+=, cv::add(a, b, (const Mat&)a), Mat, Mat) +CV_MAT_AUG_OPERATOR (+=, cv::add(a, b, (const Mat&)a), Mat, Scalar) +CV_MAT_AUG_OPERATOR_T(+=, cv::add(a, b, (const Mat&)a), Mat_<_Tp>, Mat) +CV_MAT_AUG_OPERATOR_T(+=, cv::add(a, b, (const Mat&)a), Mat_<_Tp>, Scalar) +CV_MAT_AUG_OPERATOR_T(+=, cv::add(a, b, (const Mat&)a), Mat_<_Tp>, Mat_<_Tp>) +CV_MAT_AUG_OPERATOR_TN(+=, cv::add(a, Mat(b), (const Mat&)a), Mat) +CV_MAT_AUG_OPERATOR_TN(+=, cv::add(a, Mat(b), (const Mat&)a), Mat_<_Tp>) + +CV_MAT_AUG_OPERATOR (-=, cv::subtract(a, b, (const Mat&)a), Mat, Mat) +CV_MAT_AUG_OPERATOR (-=, cv::subtract(a, b, (const Mat&)a), Mat, Scalar) +CV_MAT_AUG_OPERATOR_T(-=, cv::subtract(a, b, (const Mat&)a), Mat_<_Tp>, Mat) +CV_MAT_AUG_OPERATOR_T(-=, cv::subtract(a, b, (const Mat&)a), Mat_<_Tp>, Scalar) +CV_MAT_AUG_OPERATOR_T(-=, cv::subtract(a, b, (const Mat&)a), Mat_<_Tp>, Mat_<_Tp>) +CV_MAT_AUG_OPERATOR_TN(-=, cv::subtract(a, Mat(b), (const Mat&)a), Mat) +CV_MAT_AUG_OPERATOR_TN(-=, cv::subtract(a, Mat(b), (const Mat&)a), Mat_<_Tp>) + +CV_MAT_AUG_OPERATOR (*=, cv::gemm(a, b, 1, Mat(), 0, a, 0), Mat, Mat) +CV_MAT_AUG_OPERATOR_T(*=, cv::gemm(a, b, 1, Mat(), 0, a, 0), Mat_<_Tp>, Mat) +CV_MAT_AUG_OPERATOR_T(*=, cv::gemm(a, b, 1, Mat(), 0, a, 0), Mat_<_Tp>, Mat_<_Tp>) +CV_MAT_AUG_OPERATOR (*=, a.convertTo(a, -1, b), Mat, double) +CV_MAT_AUG_OPERATOR_T(*=, a.convertTo(a, -1, b), Mat_<_Tp>, double) +CV_MAT_AUG_OPERATOR_TN(*=, cv::gemm(a, Mat(b), 1, Mat(), 0, a, 0), Mat) +CV_MAT_AUG_OPERATOR_TN(*=, cv::gemm(a, Mat(b), 1, Mat(), 0, a, 0), Mat_<_Tp>) + +CV_MAT_AUG_OPERATOR (/=, cv::divide(a, b, (const Mat&)a), Mat, Mat) +CV_MAT_AUG_OPERATOR_T(/=, cv::divide(a, b, (const Mat&)a), Mat_<_Tp>, Mat) +CV_MAT_AUG_OPERATOR_T(/=, cv::divide(a, b, (const Mat&)a), Mat_<_Tp>, Mat_<_Tp>) +CV_MAT_AUG_OPERATOR (/=, a.convertTo((Mat&)a, -1, 1./b), Mat, double) +CV_MAT_AUG_OPERATOR_T(/=, a.convertTo((Mat&)a, -1, 1./b), Mat_<_Tp>, double) +CV_MAT_AUG_OPERATOR_TN(/=, cv::divide(a, Mat(b), (const Mat&)a), Mat) +CV_MAT_AUG_OPERATOR_TN(/=, cv::divide(a, Mat(b), (const Mat&)a), Mat_<_Tp>) + +CV_MAT_AUG_OPERATOR (&=, cv::bitwise_and(a, b, (const Mat&)a), Mat, Mat) +CV_MAT_AUG_OPERATOR (&=, cv::bitwise_and(a, b, (const Mat&)a), Mat, Scalar) +CV_MAT_AUG_OPERATOR_T(&=, cv::bitwise_and(a, b, (const Mat&)a), Mat_<_Tp>, Mat) +CV_MAT_AUG_OPERATOR_T(&=, cv::bitwise_and(a, b, (const Mat&)a), Mat_<_Tp>, Scalar) +CV_MAT_AUG_OPERATOR_T(&=, cv::bitwise_and(a, b, (const Mat&)a), Mat_<_Tp>, Mat_<_Tp>) +CV_MAT_AUG_OPERATOR_TN(&=, cv::bitwise_and(a, Mat(b), (const Mat&)a), Mat) +CV_MAT_AUG_OPERATOR_TN(&=, cv::bitwise_and(a, Mat(b), (const Mat&)a), Mat_<_Tp>) + +CV_MAT_AUG_OPERATOR (|=, cv::bitwise_or(a, b, (const Mat&)a), Mat, Mat) +CV_MAT_AUG_OPERATOR (|=, cv::bitwise_or(a, b, (const Mat&)a), Mat, Scalar) +CV_MAT_AUG_OPERATOR_T(|=, cv::bitwise_or(a, b, (const Mat&)a), Mat_<_Tp>, Mat) +CV_MAT_AUG_OPERATOR_T(|=, cv::bitwise_or(a, b, (const Mat&)a), Mat_<_Tp>, Scalar) +CV_MAT_AUG_OPERATOR_T(|=, cv::bitwise_or(a, b, (const Mat&)a), Mat_<_Tp>, Mat_<_Tp>) +CV_MAT_AUG_OPERATOR_TN(|=, cv::bitwise_or(a, Mat(b), (const Mat&)a), Mat) +CV_MAT_AUG_OPERATOR_TN(|=, cv::bitwise_or(a, Mat(b), (const Mat&)a), Mat_<_Tp>) + +CV_MAT_AUG_OPERATOR (^=, cv::bitwise_xor(a, b, (const Mat&)a), Mat, Mat) +CV_MAT_AUG_OPERATOR (^=, cv::bitwise_xor(a, b, (const Mat&)a), Mat, Scalar) +CV_MAT_AUG_OPERATOR_T(^=, cv::bitwise_xor(a, b, (const Mat&)a), Mat_<_Tp>, Mat) +CV_MAT_AUG_OPERATOR_T(^=, cv::bitwise_xor(a, b, (const Mat&)a), Mat_<_Tp>, Scalar) +CV_MAT_AUG_OPERATOR_T(^=, cv::bitwise_xor(a, b, (const Mat&)a), Mat_<_Tp>, Mat_<_Tp>) +CV_MAT_AUG_OPERATOR_TN(^=, cv::bitwise_xor(a, Mat(b), (const Mat&)a), Mat) +CV_MAT_AUG_OPERATOR_TN(^=, cv::bitwise_xor(a, Mat(b), (const Mat&)a), Mat_<_Tp>) + +#undef CV_MAT_AUG_OPERATOR_TN +#undef CV_MAT_AUG_OPERATOR_T +#undef CV_MAT_AUG_OPERATOR +#undef CV_MAT_AUG_OPERATOR1 + + + +///////////////////////////////////////////// SVD ///////////////////////////////////////////// + +inline SVD::SVD() {} +inline SVD::SVD( InputArray m, int flags ) { operator ()(m, flags); } +inline void SVD::solveZ( InputArray m, OutputArray _dst ) +{ + Mat mtx = m.getMat(); + SVD svd(mtx, (mtx.rows >= mtx.cols ? 0 : SVD::FULL_UV)); + _dst.create(svd.vt.cols, 1, svd.vt.type()); + Mat dst = _dst.getMat(); + svd.vt.row(svd.vt.rows-1).reshape(1,svd.vt.cols).copyTo(dst); +} + +template inline void + SVD::compute( const Matx<_Tp, m, n>& a, Matx<_Tp, nm, 1>& w, Matx<_Tp, m, nm>& u, Matx<_Tp, n, nm>& vt ) +{ + CV_StaticAssert( nm == MIN(m, n), "Invalid size of output vector."); + Mat _a(a, false), _u(u, false), _w(w, false), _vt(vt, false); + SVD::compute(_a, _w, _u, _vt); + CV_Assert(_w.data == (uchar*)&w.val[0] && _u.data == (uchar*)&u.val[0] && _vt.data == (uchar*)&vt.val[0]); +} + +template inline void +SVD::compute( const Matx<_Tp, m, n>& a, Matx<_Tp, nm, 1>& w ) +{ + CV_StaticAssert( nm == MIN(m, n), "Invalid size of output vector."); + Mat _a(a, false), _w(w, false); + SVD::compute(_a, _w); + CV_Assert(_w.data == (uchar*)&w.val[0]); +} + +template inline void +SVD::backSubst( const Matx<_Tp, nm, 1>& w, const Matx<_Tp, m, nm>& u, + const Matx<_Tp, n, nm>& vt, const Matx<_Tp, m, nb>& rhs, + Matx<_Tp, n, nb>& dst ) +{ + CV_StaticAssert( nm == MIN(m, n), "Invalid size of output vector."); + Mat _u(u, false), _w(w, false), _vt(vt, false), _rhs(rhs, false), _dst(dst, false); + SVD::backSubst(_w, _u, _vt, _rhs, _dst); + CV_Assert(_dst.data == (uchar*)&dst.val[0]); +} + + + +/////////////////////////////////// Multiply-with-Carry RNG /////////////////////////////////// + +inline RNG::RNG() { state = 0xffffffff; } +inline RNG::RNG(uint64 _state) { state = _state ? _state : 0xffffffff; } + +inline RNG::operator uchar() { return (uchar)next(); } +inline RNG::operator schar() { return (schar)next(); } +inline RNG::operator ushort() { return (ushort)next(); } +inline RNG::operator short() { return (short)next(); } +inline RNG::operator int() { return (int)next(); } +inline RNG::operator unsigned() { return next(); } +inline RNG::operator float() { return next()*2.3283064365386962890625e-10f; } +inline RNG::operator double() { unsigned t = next(); return (((uint64)t << 32) | next()) * 5.4210108624275221700372640043497e-20; } + +inline unsigned RNG::operator ()(unsigned N) { return (unsigned)uniform(0,N); } +inline unsigned RNG::operator ()() { return next(); } + +inline int RNG::uniform(int a, int b) { return a == b ? a : (int)(next() % (b - a) + a); } +inline float RNG::uniform(float a, float b) { return ((float)*this)*(b - a) + a; } +inline double RNG::uniform(double a, double b) { return ((double)*this)*(b - a) + a; } + +inline bool RNG::operator ==(const RNG& other) const { return state == other.state; } + +inline unsigned RNG::next() +{ + state = (uint64)(unsigned)state* /*CV_RNG_COEFF*/ 4164903690U + (unsigned)(state >> 32); + return (unsigned)state; +} + +//! returns the next uniformly-distributed random number of the specified type +template static inline _Tp randu() +{ + return (_Tp)theRNG(); +} + +///////////////////////////////// Formatted string generation ///////////////////////////////// + +/** @brief Returns a text string formatted using the printf-like expression. + +The function acts like sprintf but forms and returns an STL string. It can be used to form an error +message in the Exception constructor. +@param fmt printf-compatible formatting specifiers. + +**Note**: +|Type|Specifier| +|-|-| +|`const char*`|`%s`| +|`char`|`%c`| +|`float` / `double`|`%f`,`%g`| +|`int`, `long`, `long long`|`%d`, `%ld`, ``%lld`| +|`unsigned`, `unsigned long`, `unsigned long long`|`%u`, `%lu`, `%llu`| +|`uint64` -> `uintmax_t`, `int64` -> `intmax_t`|`%ju`, `%jd`| +|`size_t`|`%zu`| + */ +CV_EXPORTS String format( const char* fmt, ... ) CV_FORMAT_PRINTF(1, 2); + +///////////////////////////////// Formatted output of cv::Mat ///////////////////////////////// + +static inline +Ptr format(InputArray mtx, Formatter::FormatType fmt) +{ + return Formatter::get(fmt)->format(mtx.getMat()); +} + +static inline +int print(Ptr fmtd, FILE* stream = stdout) +{ + int written = 0; + fmtd->reset(); + for(const char* str = fmtd->next(); str; str = fmtd->next()) + written += fputs(str, stream); + + return written; +} + +static inline +int print(const Mat& mtx, FILE* stream = stdout) +{ + return print(Formatter::get()->format(mtx), stream); +} + +static inline +int print(const UMat& mtx, FILE* stream = stdout) +{ + return print(Formatter::get()->format(mtx.getMat(ACCESS_READ)), stream); +} + +template static inline +int print(const std::vector >& vec, FILE* stream = stdout) +{ + return print(Formatter::get()->format(Mat(vec)), stream); +} + +template static inline +int print(const std::vector >& vec, FILE* stream = stdout) +{ + return print(Formatter::get()->format(Mat(vec)), stream); +} + +template static inline +int print(const Matx<_Tp, m, n>& matx, FILE* stream = stdout) +{ + return print(Formatter::get()->format(cv::Mat(matx)), stream); +} + +//! @endcond + +/****************************************************************************************\ +* Auxiliary algorithms * +\****************************************************************************************/ + +/** @brief Splits an element set into equivalency classes. + +The generic function partition implements an \f$O(N^2)\f$ algorithm for splitting a set of \f$N\f$ elements +into one or more equivalency classes, as described in + . The function returns the number of +equivalency classes. +@param _vec Set of elements stored as a vector. +@param labels Output vector of labels. It contains as many elements as vec. Each label labels[i] is +a 0-based cluster index of `vec[i]`. +@param predicate Equivalence predicate (pointer to a boolean function of two arguments or an +instance of the class that has the method bool operator()(const _Tp& a, const _Tp& b) ). The +predicate returns true when the elements are certainly in the same class, and returns false if they +may or may not be in the same class. +@ingroup core_cluster +*/ +template int +partition( const std::vector<_Tp>& _vec, std::vector& labels, + _EqPredicate predicate=_EqPredicate()) +{ + int i, j, N = (int)_vec.size(); + const _Tp* vec = &_vec[0]; + + const int PARENT=0; + const int RANK=1; + + std::vector _nodes(N*2); + int (*nodes)[2] = (int(*)[2])&_nodes[0]; + + // The first O(N) pass: create N single-vertex trees + for(i = 0; i < N; i++) + { + nodes[i][PARENT]=-1; + nodes[i][RANK] = 0; + } + + // The main O(N^2) pass: merge connected components + for( i = 0; i < N; i++ ) + { + int root = i; + + // find root + while( nodes[root][PARENT] >= 0 ) + root = nodes[root][PARENT]; + + for( j = 0; j < N; j++ ) + { + if( i == j || !predicate(vec[i], vec[j])) + continue; + int root2 = j; + + while( nodes[root2][PARENT] >= 0 ) + root2 = nodes[root2][PARENT]; + + if( root2 != root ) + { + // unite both trees + int rank = nodes[root][RANK], rank2 = nodes[root2][RANK]; + if( rank > rank2 ) + nodes[root2][PARENT] = root; + else + { + nodes[root][PARENT] = root2; + nodes[root2][RANK] += rank == rank2; + root = root2; + } + CV_Assert( nodes[root][PARENT] < 0 ); + + int k = j, parent; + + // compress the path from node2 to root + while( (parent = nodes[k][PARENT]) >= 0 ) + { + nodes[k][PARENT] = root; + k = parent; + } + + // compress the path from node to root + k = i; + while( (parent = nodes[k][PARENT]) >= 0 ) + { + nodes[k][PARENT] = root; + k = parent; + } + } + } + } + + // Final O(N) pass: enumerate classes + labels.resize(N); + int nclasses = 0; + + for( i = 0; i < N; i++ ) + { + int root = i; + while( nodes[root][PARENT] >= 0 ) + root = nodes[root][PARENT]; + // re-use the rank as the class label + if( nodes[root][RANK] >= 0 ) + nodes[root][RANK] = ~nclasses++; + labels[i] = ~nodes[root][RANK]; + } + + return nclasses; +} + +} // cv + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/optim.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/optim.hpp new file mode 100644 index 0000000..f61a2b9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/optim.hpp @@ -0,0 +1,302 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 OpenCV Foundation 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. +// +//M*/ + +#ifndef OPENCV_OPTIM_HPP +#define OPENCV_OPTIM_HPP + +#include "opencv2/core.hpp" + +namespace cv +{ + +/** @addtogroup core_optim +The algorithms in this section minimize or maximize function value within specified constraints or +without any constraints. +@{ +*/ + +/** @brief Basic interface for all solvers + */ +class CV_EXPORTS MinProblemSolver : public Algorithm +{ +public: + /** @brief Represents function being optimized + */ + class CV_EXPORTS Function + { + public: + virtual ~Function() {} + virtual int getDims() const = 0; + virtual double getGradientEps() const; + virtual double calc(const double* x) const = 0; + virtual void getGradient(const double* x,double* grad); + }; + + /** @brief Getter for the optimized function. + + The optimized function is represented by Function interface, which requires derivatives to + implement the calc(double*) and getDim() methods to evaluate the function. + + @return Smart-pointer to an object that implements Function interface - it represents the + function that is being optimized. It can be empty, if no function was given so far. + */ + virtual Ptr getFunction() const = 0; + + /** @brief Setter for the optimized function. + + *It should be called at least once before the call to* minimize(), as default value is not usable. + + @param f The new function to optimize. + */ + virtual void setFunction(const Ptr& f) = 0; + + /** @brief Getter for the previously set terminal criteria for this algorithm. + + @return Deep copy of the terminal criteria used at the moment. + */ + virtual TermCriteria getTermCriteria() const = 0; + + /** @brief Set terminal criteria for solver. + + This method *is not necessary* to be called before the first call to minimize(), as the default + value is sensible. + + Algorithm stops when the number of function evaluations done exceeds termcrit.maxCount, when + the function values at the vertices of simplex are within termcrit.epsilon range or simplex + becomes so small that it can enclosed in a box with termcrit.epsilon sides, whatever comes + first. + @param termcrit Terminal criteria to be used, represented as cv::TermCriteria structure. + */ + virtual void setTermCriteria(const TermCriteria& termcrit) = 0; + + /** @brief actually runs the algorithm and performs the minimization. + + The sole input parameter determines the centroid of the starting simplex (roughly, it tells + where to start), all the others (terminal criteria, initial step, function to be minimized) are + supposed to be set via the setters before the call to this method or the default values (not + always sensible) will be used. + + @param x The initial point, that will become a centroid of an initial simplex. After the algorithm + will terminate, it will be set to the point where the algorithm stops, the point of possible + minimum. + @return The value of a function at the point found. + */ + virtual double minimize(InputOutputArray x) = 0; +}; + +/** @brief This class is used to perform the non-linear non-constrained minimization of a function, + +defined on an `n`-dimensional Euclidean space, using the **Nelder-Mead method**, also known as +**downhill simplex method**. The basic idea about the method can be obtained from +. + +It should be noted, that this method, although deterministic, is rather a heuristic and therefore +may converge to a local minima, not necessary a global one. It is iterative optimization technique, +which at each step uses an information about the values of a function evaluated only at `n+1` +points, arranged as a *simplex* in `n`-dimensional space (hence the second name of the method). At +each step new point is chosen to evaluate function at, obtained value is compared with previous +ones and based on this information simplex changes it's shape , slowly moving to the local minimum. +Thus this method is using *only* function values to make decision, on contrary to, say, Nonlinear +Conjugate Gradient method (which is also implemented in optim). + +Algorithm stops when the number of function evaluations done exceeds termcrit.maxCount, when the +function values at the vertices of simplex are within termcrit.epsilon range or simplex becomes so +small that it can enclosed in a box with termcrit.epsilon sides, whatever comes first, for some +defined by user positive integer termcrit.maxCount and positive non-integer termcrit.epsilon. + +@note DownhillSolver is a derivative of the abstract interface +cv::MinProblemSolver, which in turn is derived from the Algorithm interface and is used to +encapsulate the functionality, common to all non-linear optimization algorithms in the optim +module. + +@note term criteria should meet following condition: +@code + termcrit.type == (TermCriteria::MAX_ITER + TermCriteria::EPS) && termcrit.epsilon > 0 && termcrit.maxCount > 0 +@endcode + */ +class CV_EXPORTS DownhillSolver : public MinProblemSolver +{ +public: + /** @brief Returns the initial step that will be used in downhill simplex algorithm. + + @param step Initial step that will be used in algorithm. Note, that although corresponding setter + accepts column-vectors as well as row-vectors, this method will return a row-vector. + @see DownhillSolver::setInitStep + */ + virtual void getInitStep(OutputArray step) const=0; + + /** @brief Sets the initial step that will be used in downhill simplex algorithm. + + Step, together with initial point (given in DownhillSolver::minimize) are two `n`-dimensional + vectors that are used to determine the shape of initial simplex. Roughly said, initial point + determines the position of a simplex (it will become simplex's centroid), while step determines the + spread (size in each dimension) of a simplex. To be more precise, if \f$s,x_0\in\mathbb{R}^n\f$ are + the initial step and initial point respectively, the vertices of a simplex will be: + \f$v_0:=x_0-\frac{1}{2} s\f$ and \f$v_i:=x_0+s_i\f$ for \f$i=1,2,\dots,n\f$ where \f$s_i\f$ denotes + projections of the initial step of *n*-th coordinate (the result of projection is treated to be + vector given by \f$s_i:=e_i\cdot\left\f$, where \f$e_i\f$ form canonical basis) + + @param step Initial step that will be used in algorithm. Roughly said, it determines the spread + (size in each dimension) of an initial simplex. + */ + virtual void setInitStep(InputArray step)=0; + + /** @brief This function returns the reference to the ready-to-use DownhillSolver object. + + All the parameters are optional, so this procedure can be called even without parameters at + all. In this case, the default values will be used. As default value for terminal criteria are + the only sensible ones, MinProblemSolver::setFunction() and DownhillSolver::setInitStep() + should be called upon the obtained object, if the respective parameters were not given to + create(). Otherwise, the two ways (give parameters to createDownhillSolver() or miss them out + and call the MinProblemSolver::setFunction() and DownhillSolver::setInitStep()) are absolutely + equivalent (and will drop the same errors in the same way, should invalid input be detected). + @param f Pointer to the function that will be minimized, similarly to the one you submit via + MinProblemSolver::setFunction. + @param initStep Initial step, that will be used to construct the initial simplex, similarly to the one + you submit via MinProblemSolver::setInitStep. + @param termcrit Terminal criteria to the algorithm, similarly to the one you submit via + MinProblemSolver::setTermCriteria. + */ + static Ptr create(const Ptr& f=Ptr(), + InputArray initStep=Mat_(1,1,0.0), + TermCriteria termcrit=TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS,5000,0.000001)); +}; + +/** @brief This class is used to perform the non-linear non-constrained minimization of a function +with known gradient, + +defined on an *n*-dimensional Euclidean space, using the **Nonlinear Conjugate Gradient method**. +The implementation was done based on the beautifully clear explanatory article [An Introduction to +the Conjugate Gradient Method Without the Agonizing +Pain](http://www.cs.cmu.edu/~quake-papers/painless-conjugate-gradient.pdf) by Jonathan Richard +Shewchuk. The method can be seen as an adaptation of a standard Conjugate Gradient method (see, for +example ) for numerically solving the +systems of linear equations. + +It should be noted, that this method, although deterministic, is rather a heuristic method and +therefore may converge to a local minima, not necessary a global one. What is even more disastrous, +most of its behaviour is ruled by gradient, therefore it essentially cannot distinguish between +local minima and maxima. Therefore, if it starts sufficiently near to the local maximum, it may +converge to it. Another obvious restriction is that it should be possible to compute the gradient of +a function at any point, thus it is preferable to have analytic expression for gradient and +computational burden should be born by the user. + +The latter responsibility is accomplished via the getGradient method of a +MinProblemSolver::Function interface (which represents function being optimized). This method takes +point a point in *n*-dimensional space (first argument represents the array of coordinates of that +point) and compute its gradient (it should be stored in the second argument as an array). + +@note class ConjGradSolver thus does not add any new methods to the basic MinProblemSolver interface. + +@note term criteria should meet following condition: +@code + termcrit.type == (TermCriteria::MAX_ITER + TermCriteria::EPS) && termcrit.epsilon > 0 && termcrit.maxCount > 0 + // or + termcrit.type == TermCriteria::MAX_ITER) && termcrit.maxCount > 0 +@endcode + */ +class CV_EXPORTS ConjGradSolver : public MinProblemSolver +{ +public: + /** @brief This function returns the reference to the ready-to-use ConjGradSolver object. + + All the parameters are optional, so this procedure can be called even without parameters at + all. In this case, the default values will be used. As default value for terminal criteria are + the only sensible ones, MinProblemSolver::setFunction() should be called upon the obtained + object, if the function was not given to create(). Otherwise, the two ways (submit it to + create() or miss it out and call the MinProblemSolver::setFunction()) are absolutely equivalent + (and will drop the same errors in the same way, should invalid input be detected). + @param f Pointer to the function that will be minimized, similarly to the one you submit via + MinProblemSolver::setFunction. + @param termcrit Terminal criteria to the algorithm, similarly to the one you submit via + MinProblemSolver::setTermCriteria. + */ + static Ptr create(const Ptr& f=Ptr(), + TermCriteria termcrit=TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS,5000,0.000001)); +}; + +//! return codes for cv::solveLP() function +enum SolveLPResult +{ + SOLVELP_UNBOUNDED = -2, //!< problem is unbounded (target function can achieve arbitrary high values) + SOLVELP_UNFEASIBLE = -1, //!< problem is unfeasible (there are no points that satisfy all the constraints imposed) + SOLVELP_SINGLE = 0, //!< there is only one maximum for target function + SOLVELP_MULTI = 1 //!< there are multiple maxima for target function - the arbitrary one is returned +}; + +/** @brief Solve given (non-integer) linear programming problem using the Simplex Algorithm (Simplex Method). + +What we mean here by "linear programming problem" (or LP problem, for short) can be formulated as: + +\f[\mbox{Maximize } c\cdot x\\ + \mbox{Subject to:}\\ + Ax\leq b\\ + x\geq 0\f] + +Where \f$c\f$ is fixed `1`-by-`n` row-vector, \f$A\f$ is fixed `m`-by-`n` matrix, \f$b\f$ is fixed `m`-by-`1` +column vector and \f$x\f$ is an arbitrary `n`-by-`1` column vector, which satisfies the constraints. + +Simplex algorithm is one of many algorithms that are designed to handle this sort of problems +efficiently. Although it is not optimal in theoretical sense (there exist algorithms that can solve +any problem written as above in polynomial time, while simplex method degenerates to exponential +time for some special cases), it is well-studied, easy to implement and is shown to work well for +real-life purposes. + +The particular implementation is taken almost verbatim from **Introduction to Algorithms, third +edition** by T. H. Cormen, C. E. Leiserson, R. L. Rivest and Clifford Stein. In particular, the +Bland's rule is used to prevent cycling. + +@param Func This row-vector corresponds to \f$c\f$ in the LP problem formulation (see above). It should +contain 32- or 64-bit floating point numbers. As a convenience, column-vector may be also submitted, +in the latter case it is understood to correspond to \f$c^T\f$. +@param Constr `m`-by-`n+1` matrix, whose rightmost column corresponds to \f$b\f$ in formulation above +and the remaining to \f$A\f$. It should contain 32- or 64-bit floating point numbers. +@param z The solution will be returned here as a column-vector - it corresponds to \f$c\f$ in the +formulation above. It will contain 64-bit floating point numbers. +@return One of cv::SolveLPResult + */ +CV_EXPORTS_W int solveLP(InputArray Func, InputArray Constr, OutputArray z); + +//! @} + +}// cv + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/ovx.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/ovx.hpp new file mode 100644 index 0000000..8bb7d54 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/ovx.hpp @@ -0,0 +1,28 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +// Copyright (C) 2016, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. + +// OpenVX related definitions and declarations + +#pragma once +#ifndef OPENCV_OVX_HPP +#define OPENCV_OVX_HPP + +#include "cvdef.h" + +namespace cv +{ +/// Check if use of OpenVX is possible +CV_EXPORTS_W bool haveOpenVX(); + +/// Check if use of OpenVX is enabled +CV_EXPORTS_W bool useOpenVX(); + +/// Enable/disable use of OpenVX +CV_EXPORTS_W void setUseOpenVX(bool flag); +} // namespace cv + +#endif // OPENCV_OVX_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/parallel/backend/parallel_for.openmp.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/parallel/backend/parallel_for.openmp.hpp new file mode 100644 index 0000000..b172cac --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/parallel/backend/parallel_for.openmp.hpp @@ -0,0 +1,72 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_PARALLEL_FOR_OPENMP_HPP +#define OPENCV_CORE_PARALLEL_FOR_OPENMP_HPP + +#include "opencv2/core/parallel/parallel_backend.hpp" + +#if !defined(_OPENMP) && !defined(OPENCV_SKIP_OPENMP_PRESENSE_CHECK) +#error "This file must be compiled with enabled OpenMP" +#endif + +#include + +namespace cv { namespace parallel { namespace openmp { + +/** OpenMP parallel_for API implementation + * + * @sa setParallelForBackend + * @ingroup core_parallel_backend + */ +class ParallelForBackend : public ParallelForAPI +{ +protected: + int numThreads; + int numThreadsMax; +public: + ParallelForBackend() + { + numThreads = 0; + numThreadsMax = omp_get_max_threads(); + } + + virtual ~ParallelForBackend() {} + + virtual void parallel_for(int tasks, FN_parallel_for_body_cb_t body_callback, void* callback_data) CV_OVERRIDE + { +#pragma omp parallel for schedule(dynamic) num_threads(numThreads > 0 ? numThreads : numThreadsMax) + for (int i = 0; i < tasks; ++i) + body_callback(i, i + 1, callback_data); + } + + virtual int getThreadNum() const CV_OVERRIDE + { + return omp_get_thread_num(); + } + + virtual int getNumThreads() const CV_OVERRIDE + { + return numThreads > 0 + ? numThreads + : numThreadsMax; + } + + virtual int setNumThreads(int nThreads) CV_OVERRIDE + { + int oldNumThreads = numThreads; + numThreads = nThreads; + // nothing needed as numThreads is used in #pragma omp parallel for directly + return oldNumThreads; + } + + const char* getName() const CV_OVERRIDE + { + return "openmp"; + } +}; + +}}} // namespace + +#endif // OPENCV_CORE_PARALLEL_FOR_OPENMP_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/parallel/backend/parallel_for.tbb.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/parallel/backend/parallel_for.tbb.hpp new file mode 100644 index 0000000..04b0c4c --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/parallel/backend/parallel_for.tbb.hpp @@ -0,0 +1,153 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_PARALLEL_FOR_TBB_HPP +#define OPENCV_CORE_PARALLEL_FOR_TBB_HPP + +#include "opencv2/core/parallel/parallel_backend.hpp" +#include + +#ifndef TBB_SUPPRESS_DEPRECATED_MESSAGES // supress warning +#define TBB_SUPPRESS_DEPRECATED_MESSAGES 1 +#endif +#include "tbb/tbb.h" +#if !defined(TBB_INTERFACE_VERSION) +#error "Unknows/unsupported TBB version" +#endif + +#if TBB_INTERFACE_VERSION >= 8000 +#include "tbb/task_arena.h" +#endif + +namespace cv { namespace parallel { namespace tbb { + +using namespace ::tbb; + +#if TBB_INTERFACE_VERSION >= 8000 +static tbb::task_arena& getArena() +{ + static tbb::task_arena tbbArena(tbb::task_arena::automatic); + return tbbArena; +} +#else +static tbb::task_scheduler_init& getScheduler() +{ + static tbb::task_scheduler_init tbbScheduler(tbb::task_scheduler_init::deferred); + return tbbScheduler; +} +#endif + +/** TBB parallel_for API implementation + * + * @sa setParallelForBackend + * @ingroup core_parallel_backend + */ +class ParallelForBackend : public ParallelForAPI +{ +protected: + int numThreads; + int numThreadsMax; +public: + ParallelForBackend() + { + CV_LOG_INFO(NULL, "Initializing TBB parallel backend: TBB_INTERFACE_VERSION=" << TBB_INTERFACE_VERSION); + numThreads = 0; +#if TBB_INTERFACE_VERSION >= 8000 + (void)getArena(); +#else + (void)getScheduler(); +#endif + } + + virtual ~ParallelForBackend() {} + + class CallbackProxy + { + const FN_parallel_for_body_cb_t& callback; + void* const callback_data; + const int tasks; + public: + inline CallbackProxy(int tasks_, FN_parallel_for_body_cb_t& callback_, void* callback_data_) + : callback(callback_), callback_data(callback_data_), tasks(tasks_) + { + // nothing + } + + void operator()(const tbb::blocked_range& range) const + { + this->callback(range.begin(), range.end(), callback_data); + } + + void operator()() const + { + tbb::parallel_for(tbb::blocked_range(0, tasks), *this); + } + }; + + virtual void parallel_for(int tasks, FN_parallel_for_body_cb_t body_callback, void* callback_data) CV_OVERRIDE + { + CallbackProxy task(tasks, body_callback, callback_data); +#if TBB_INTERFACE_VERSION >= 8000 + getArena().execute(task); +#else + task(); +#endif + } + + virtual int getThreadNum() const CV_OVERRIDE + { +#if TBB_INTERFACE_VERSION >= 9100 + return tbb::this_task_arena::current_thread_index(); +#elif TBB_INTERFACE_VERSION >= 8000 + return tbb::task_arena::current_thread_index(); +#else + return 0; +#endif + } + + virtual int getNumThreads() const CV_OVERRIDE + { +#if TBB_INTERFACE_VERSION >= 9100 + return getArena().max_concurrency(); +#elif TBB_INTERFACE_VERSION >= 8000 + return numThreads > 0 + ? numThreads + : tbb::task_scheduler_init::default_num_threads(); +#else + return getScheduler().is_active() + ? numThreads + : tbb::task_scheduler_init::default_num_threads(); +#endif + } + + virtual int setNumThreads(int nThreads) CV_OVERRIDE + { + int oldNumThreads = numThreads; + numThreads = nThreads; + +#if TBB_INTERFACE_VERSION >= 8000 + auto& tbbArena = getArena(); + if (tbbArena.is_active()) + tbbArena.terminate(); + if (numThreads > 0) + tbbArena.initialize(numThreads); +#else + auto& tbbScheduler = getScheduler(); + if (tbbScheduler.is_active()) + tbbScheduler.terminate(); + if (numThreads > 0) + tbbScheduler.initialize(numThreads); +#endif + return oldNumThreads; + } + + const char* getName() const CV_OVERRIDE + { + return "tbb"; + } +}; + +}}} // namespace + +#endif // OPENCV_CORE_PARALLEL_FOR_TBB_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/parallel/parallel_backend.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/parallel/parallel_backend.hpp new file mode 100644 index 0000000..c3e8333 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/parallel/parallel_backend.hpp @@ -0,0 +1,90 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_PARALLEL_BACKEND_HPP +#define OPENCV_CORE_PARALLEL_BACKEND_HPP + +#include "opencv2/core/cvdef.h" +#include + +namespace cv { namespace parallel { +#ifndef CV_API_CALL +#define CV_API_CALL +#endif + +/** @addtogroup core_parallel_backend + * @{ + * API below is provided to resolve problem of CPU resource over-subscription by multiple thread pools from different multi-threading frameworks. + * This is common problem for cases when OpenCV compiled threading framework is different from the Users Applications framework. + * + * Applications can replace OpenCV `parallel_for()` backend with own implementation (to reuse Application's thread pool). + * + * + * ### Backend API usage examples + * + * #### Intel TBB + * + * - include header with simple implementation of TBB backend: + * @snippet parallel_backend/example-tbb.cpp tbb_include + * - execute backend replacement code: + * @snippet parallel_backend/example-tbb.cpp tbb_backend + * - configuration of compiler/linker options is responsibility of Application's scripts + * + * #### OpenMP + * + * - include header with simple implementation of OpenMP backend: + * @snippet parallel_backend/example-openmp.cpp openmp_include + * - execute backend replacement code: + * @snippet parallel_backend/example-openmp.cpp openmp_backend + * - Configuration of compiler/linker options is responsibility of Application's scripts + * + * + * ### Plugins support + * + * Runtime configuration options: + * - change backend priority: `OPENCV_PARALLEL_PRIORITY_=9999` + * - disable backend: `OPENCV_PARALLEL_PRIORITY_=0` + * - specify list of backends with high priority (>100000): `OPENCV_PARALLEL_PRIORITY_LIST=TBB,OPENMP`. Unknown backends are registered as new plugins. + * + */ + +/** Interface for parallel_for backends implementations + * + * @sa setParallelForBackend + */ +class CV_EXPORTS ParallelForAPI +{ +public: + virtual ~ParallelForAPI(); + + typedef void (CV_API_CALL *FN_parallel_for_body_cb_t)(int start, int end, void* data); + + virtual void parallel_for(int tasks, FN_parallel_for_body_cb_t body_callback, void* callback_data) = 0; + + virtual int getThreadNum() const = 0; + + virtual int getNumThreads() const = 0; + + virtual int setNumThreads(int nThreads) = 0; + + virtual const char* getName() const = 0; +}; + +/** @brief Replace OpenCV parallel_for backend + * + * Application can replace OpenCV `parallel_for()` backend with own implementation. + * + * @note This call is not thread-safe. Consider calling this function from the `main()` before any other OpenCV processing functions (and without any other created threads). + */ +CV_EXPORTS void setParallelForBackend(const std::shared_ptr& api, bool propagateNumThreads = true); + +/** @brief Change OpenCV parallel_for backend + * + * @note This call is not thread-safe. Consider calling this function from the `main()` before any other OpenCV processing functions (and without any other created threads). + */ +CV_EXPORTS_W bool setParallelForBackend(const std::string& backendName, bool propagateNumThreads = true); + +//! @} +}} // namespace +#endif // OPENCV_CORE_PARALLEL_BACKEND_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/persistence.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/persistence.hpp new file mode 100644 index 0000000..8e135d1 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/persistence.hpp @@ -0,0 +1,1350 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_PERSISTENCE_HPP +#define OPENCV_CORE_PERSISTENCE_HPP + +#ifndef CV_DOXYGEN +/// Define to support persistence legacy formats +#define CV__LEGACY_PERSISTENCE +#endif + +#ifndef __cplusplus +# error persistence.hpp header must be compiled as C++ +#endif + +//! @addtogroup core_c +//! @{ + +/** @brief "black box" representation of the file storage associated with a file on disk. + +Several functions that are described below take CvFileStorage\* as inputs and allow the user to +save or to load hierarchical collections that consist of scalar values, standard CXCore objects +(such as matrices, sequences, graphs), and user-defined objects. + +OpenCV can read and write data in XML (), YAML () or +JSON () formats. Below is an example of 3x3 floating-point identity matrix A, +stored in XML and YAML files +using CXCore functions: +XML: +@code{.xml} + + + + 3 + 3 +
f
+ 1. 0. 0. 0. 1. 0. 0. 0. 1. +
+
+@endcode +YAML: +@code{.yaml} + %YAML:1.0 + A: !!opencv-matrix + rows: 3 + cols: 3 + dt: f + data: [ 1., 0., 0., 0., 1., 0., 0., 0., 1.] +@endcode +As it can be seen from the examples, XML uses nested tags to represent hierarchy, while YAML uses +indentation for that purpose (similar to the Python programming language). + +The same functions can read and write data in both formats; the particular format is determined by +the extension of the opened file, ".xml" for XML files, ".yml" or ".yaml" for YAML and ".json" for +JSON. + */ + +//! @} core_c + +#include "opencv2/core/types.hpp" +#include "opencv2/core/mat.hpp" + +namespace cv { + +/** @addtogroup core_xml + +XML/YAML/JSON file storages. {#xml_storage} +======================= +Writing to a file storage. +-------------------------- +You can store and then restore various OpenCV data structures to/from XML (), +YAML () or JSON () formats. Also, it is possible to store +and load arbitrarily complex data structures, which include OpenCV data structures, as well as +primitive data types (integer and floating-point numbers and text strings) as their elements. + +Use the following procedure to write something to XML, YAML or JSON: +-# Create new FileStorage and open it for writing. It can be done with a single call to +FileStorage::FileStorage constructor that takes a filename, or you can use the default constructor +and then call FileStorage::open. Format of the file (XML, YAML or JSON) is determined from the filename +extension (".xml", ".yml"/".yaml" and ".json", respectively) +-# Write all the data you want using the streaming operator `<<`, just like in the case of STL +streams. +-# Close the file using FileStorage::release. FileStorage destructor also closes the file. + +Here is an example: +@code + #include "opencv2/core.hpp" + #include + + using namespace cv; + + int main(int, char** argv) + { + FileStorage fs("test.yml", FileStorage::WRITE); + + fs << "frameCount" << 5; + time_t rawtime; time(&rawtime); + fs << "calibrationDate" << asctime(localtime(&rawtime)); + Mat cameraMatrix = (Mat_(3,3) << 1000, 0, 320, 0, 1000, 240, 0, 0, 1); + Mat distCoeffs = (Mat_(5,1) << 0.1, 0.01, -0.001, 0, 0); + fs << "cameraMatrix" << cameraMatrix << "distCoeffs" << distCoeffs; + fs << "features" << "["; + for( int i = 0; i < 3; i++ ) + { + int x = rand() % 640; + int y = rand() % 480; + uchar lbp = rand() % 256; + + fs << "{:" << "x" << x << "y" << y << "lbp" << "[:"; + for( int j = 0; j < 8; j++ ) + fs << ((lbp >> j) & 1); + fs << "]" << "}"; + } + fs << "]"; + fs.release(); + return 0; + } +@endcode +The sample above stores to YML an integer, a text string (calibration date), 2 matrices, and a custom +structure "feature", which includes feature coordinates and LBP (local binary pattern) value. Here +is output of the sample: +@code{.yaml} +%YAML:1.0 +frameCount: 5 +calibrationDate: "Fri Jun 17 14:09:29 2011\n" +cameraMatrix: !!opencv-matrix + rows: 3 + cols: 3 + dt: d + data: [ 1000., 0., 320., 0., 1000., 240., 0., 0., 1. ] +distCoeffs: !!opencv-matrix + rows: 5 + cols: 1 + dt: d + data: [ 1.0000000000000001e-01, 1.0000000000000000e-02, + -1.0000000000000000e-03, 0., 0. ] +features: + - { x:167, y:49, lbp:[ 1, 0, 0, 1, 1, 0, 1, 1 ] } + - { x:298, y:130, lbp:[ 0, 0, 0, 1, 0, 0, 1, 1 ] } + - { x:344, y:158, lbp:[ 1, 1, 0, 0, 0, 0, 1, 0 ] } +@endcode + +As an exercise, you can replace ".yml" with ".xml" or ".json" in the sample above and see, how the +corresponding XML file will look like. + +Several things can be noted by looking at the sample code and the output: + +- The produced YAML (and XML/JSON) consists of heterogeneous collections that can be nested. There are + 2 types of collections: named collections (mappings) and unnamed collections (sequences). In mappings + each element has a name and is accessed by name. This is similar to structures and std::map in + C/C++ and dictionaries in Python. In sequences elements do not have names, they are accessed by + indices. This is similar to arrays and std::vector in C/C++ and lists, tuples in Python. + "Heterogeneous" means that elements of each single collection can have different types. + + Top-level collection in YAML/XML/JSON is a mapping. Each matrix is stored as a mapping, and the matrix + elements are stored as a sequence. Then, there is a sequence of features, where each feature is + represented a mapping, and lbp value in a nested sequence. + +- When you write to a mapping (a structure), you write element name followed by its value. When you + write to a sequence, you simply write the elements one by one. OpenCV data structures (such as + cv::Mat) are written in absolutely the same way as simple C data structures - using `<<` + operator. + +- To write a mapping, you first write the special string `{` to the storage, then write the + elements as pairs (`fs << << `) and then write the closing + `}`. + +- To write a sequence, you first write the special string `[`, then write the elements, then + write the closing `]`. + +- In YAML/JSON (but not XML), mappings and sequences can be written in a compact Python-like inline + form. In the sample above matrix elements, as well as each feature, including its lbp value, is + stored in such inline form. To store a mapping/sequence in a compact form, put `:` after the + opening character, e.g. use `{:` instead of `{` and `[:` instead of `[`. When the + data is written to XML, those extra `:` are ignored. + +Reading data from a file storage. +--------------------------------- +To read the previously written XML, YAML or JSON file, do the following: +-# Open the file storage using FileStorage::FileStorage constructor or FileStorage::open method. + In the current implementation the whole file is parsed and the whole representation of file + storage is built in memory as a hierarchy of file nodes (see FileNode) + +-# Read the data you are interested in. Use FileStorage::operator [], FileNode::operator [] + and/or FileNodeIterator. + +-# Close the storage using FileStorage::release. + +Here is how to read the file created by the code sample above: +@code + FileStorage fs2("test.yml", FileStorage::READ); + + // first method: use (type) operator on FileNode. + int frameCount = (int)fs2["frameCount"]; + + String date; + // second method: use FileNode::operator >> + fs2["calibrationDate"] >> date; + + Mat cameraMatrix2, distCoeffs2; + fs2["cameraMatrix"] >> cameraMatrix2; + fs2["distCoeffs"] >> distCoeffs2; + + cout << "frameCount: " << frameCount << endl + << "calibration date: " << date << endl + << "camera matrix: " << cameraMatrix2 << endl + << "distortion coeffs: " << distCoeffs2 << endl; + + FileNode features = fs2["features"]; + FileNodeIterator it = features.begin(), it_end = features.end(); + int idx = 0; + std::vector lbpval; + + // iterate through a sequence using FileNodeIterator + for( ; it != it_end; ++it, idx++ ) + { + cout << "feature #" << idx << ": "; + cout << "x=" << (int)(*it)["x"] << ", y=" << (int)(*it)["y"] << ", lbp: ("; + // you can also easily read numerical arrays using FileNode >> std::vector operator. + (*it)["lbp"] >> lbpval; + for( int i = 0; i < (int)lbpval.size(); i++ ) + cout << " " << (int)lbpval[i]; + cout << ")" << endl; + } + fs2.release(); +@endcode + +Format specification {#format_spec} +-------------------- +`([count]{u|c|w|s|i|f|d})`... where the characters correspond to fundamental C++ types: +- `u` 8-bit unsigned number +- `c` 8-bit signed number +- `w` 16-bit unsigned number +- `s` 16-bit signed number +- `i` 32-bit signed number +- `f` single precision floating-point number +- `d` double precision floating-point number +- `r` pointer, 32 lower bits of which are written as a signed integer. The type can be used to + store structures with links between the elements. + +`count` is the optional counter of values of a given type. For example, `2if` means that each array +element is a structure of 2 integers, followed by a single-precision floating-point number. The +equivalent notations of the above specification are `iif`, `2i1f` and so forth. Other examples: `u` +means that the array consists of bytes, and `2d` means the array consists of pairs of doubles. + +@see @ref samples/cpp/filestorage.cpp +*/ + +//! @{ + +/** @example samples/cpp/filestorage.cpp +A complete example using the FileStorage interface +*/ + +////////////////////////// XML & YAML I/O ////////////////////////// + +class CV_EXPORTS FileNode; +class CV_EXPORTS FileNodeIterator; + +/** @brief XML/YAML/JSON file storage class that encapsulates all the information necessary for writing or +reading data to/from a file. + */ +class CV_EXPORTS_W FileStorage +{ +public: + //! file storage mode + enum Mode + { + READ = 0, //!< value, open the file for reading + WRITE = 1, //!< value, open the file for writing + APPEND = 2, //!< value, open the file for appending + MEMORY = 4, /**< flag, read data from source or write data to the internal buffer (which is + returned by FileStorage::release) */ + FORMAT_MASK = (7<<3), //!< mask for format flags + FORMAT_AUTO = 0, //!< flag, auto format + FORMAT_XML = (1<<3), //!< flag, XML format + FORMAT_YAML = (2<<3), //!< flag, YAML format + FORMAT_JSON = (3<<3), //!< flag, JSON format + + BASE64 = 64, //!< flag, write rawdata in Base64 by default. (consider using WRITE_BASE64) + WRITE_BASE64 = BASE64 | WRITE, //!< flag, enable both WRITE and BASE64 + }; + enum State + { + UNDEFINED = 0, + VALUE_EXPECTED = 1, + NAME_EXPECTED = 2, + INSIDE_MAP = 4 + }; + + /** @brief The constructors. + + The full constructor opens the file. Alternatively you can use the default constructor and then + call FileStorage::open. + */ + CV_WRAP FileStorage(); + + /** @overload + @copydoc open() + */ + CV_WRAP FileStorage(const String& filename, int flags, const String& encoding=String()); + + //! the destructor. calls release() + virtual ~FileStorage(); + + /** @brief Opens a file. + + See description of parameters in FileStorage::FileStorage. The method calls FileStorage::release + before opening the file. + @param filename Name of the file to open or the text string to read the data from. + Extension of the file (.xml, .yml/.yaml or .json) determines its format (XML, YAML or JSON + respectively). Also you can append .gz to work with compressed files, for example myHugeMatrix.xml.gz. If both + FileStorage::WRITE and FileStorage::MEMORY flags are specified, source is used just to specify + the output file format (e.g. mydata.xml, .yml etc.). A file name can also contain parameters. + You can use this format, "*?base64" (e.g. "file.json?base64" (case sensitive)), as an alternative to + FileStorage::BASE64 flag. + @param flags Mode of operation. One of FileStorage::Mode + @param encoding Encoding of the file. Note that UTF-16 XML encoding is not supported currently and + you should use 8-bit encoding instead of it. + */ + CV_WRAP virtual bool open(const String& filename, int flags, const String& encoding=String()); + + /** @brief Checks whether the file is opened. + + @returns true if the object is associated with the current file and false otherwise. It is a + good practice to call this method after you tried to open a file. + */ + CV_WRAP virtual bool isOpened() const; + + /** @brief Closes the file and releases all the memory buffers. + + Call this method after all I/O operations with the storage are finished. + */ + CV_WRAP virtual void release(); + + /** @brief Closes the file and releases all the memory buffers. + + Call this method after all I/O operations with the storage are finished. If the storage was + opened for writing data and FileStorage::WRITE was specified + */ + CV_WRAP virtual String releaseAndGetString(); + + /** @brief Returns the first element of the top-level mapping. + @returns The first element of the top-level mapping. + */ + CV_WRAP FileNode getFirstTopLevelNode() const; + + /** @brief Returns the top-level mapping + @param streamidx Zero-based index of the stream. In most cases there is only one stream in the file. + However, YAML supports multiple streams and so there can be several. + @returns The top-level mapping. + */ + CV_WRAP FileNode root(int streamidx=0) const; + + /** @brief Returns the specified element of the top-level mapping. + @param nodename Name of the file node. + @returns Node with the given name. + */ + FileNode operator[](const String& nodename) const; + + /** @overload */ + CV_WRAP_AS(getNode) FileNode operator[](const char* nodename) const; + + /** + * @brief Simplified writing API to use with bindings. + * @param name Name of the written object. When writing to sequences (a.k.a. "arrays"), pass an empty string. + * @param val Value of the written object. + */ + CV_WRAP void write(const String& name, int val); + /// @overload + CV_WRAP void write(const String& name, double val); + /// @overload + CV_WRAP void write(const String& name, const String& val); + /// @overload + CV_WRAP void write(const String& name, const Mat& val); + /// @overload + CV_WRAP void write(const String& name, const std::vector& val); + + /** @brief Writes multiple numbers. + + Writes one or more numbers of the specified format to the currently written structure. Usually it is + more convenient to use operator `<<` instead of this method. + @param fmt Specification of each array element, see @ref format_spec "format specification" + @param vec Pointer to the written array. + @param len Number of the uchar elements to write. + */ + void writeRaw( const String& fmt, const void* vec, size_t len ); + + /** @brief Writes a comment. + + The function writes a comment into file storage. The comments are skipped when the storage is read. + @param comment The written comment, single-line or multi-line + @param append If true, the function tries to put the comment at the end of current line. + Else if the comment is multi-line, or if it does not fit at the end of the current + line, the comment starts a new line. + */ + CV_WRAP void writeComment(const String& comment, bool append = false); + + /** @brief Starts to write a nested structure (sequence or a mapping). + @param name name of the structure. When writing to sequences (a.k.a. "arrays"), pass an empty string. + @param flags type of the structure (FileNode::MAP or FileNode::SEQ (both with optional FileNode::FLOW)). + @param typeName optional name of the type you store. The effect of setting this depends on the storage format. + I.e. if the format has a specification for storing type information, this parameter is used. + */ + CV_WRAP void startWriteStruct(const String& name, int flags, const String& typeName=String()); + + /** @brief Finishes writing nested structure (should pair startWriteStruct()) + */ + CV_WRAP void endWriteStruct(); + + /** @brief Returns the normalized object name for the specified name of a file. + @param filename Name of a file + @returns The normalized object name. + */ + static String getDefaultObjectName(const String& filename); + + /** @brief Returns the current format. + * @returns The current format, see FileStorage::Mode + */ + CV_WRAP int getFormat() const; + + int state; + std::string elname; + + class Impl; + Ptr p; +}; + +/** @brief File Storage Node class. + +The node is used to store each and every element of the file storage opened for reading. When +XML/YAML file is read, it is first parsed and stored in the memory as a hierarchical collection of +nodes. Each node can be a "leaf" that is contain a single number or a string, or be a collection of +other nodes. There can be named collections (mappings) where each element has a name and it is +accessed by a name, and ordered collections (sequences) where elements do not have names but rather +accessed by index. Type of the file node can be determined using FileNode::type method. + +Note that file nodes are only used for navigating file storages opened for reading. When a file +storage is opened for writing, no data is stored in memory after it is written. + */ +class CV_EXPORTS_W_SIMPLE FileNode +{ +public: + //! type of the file storage node + enum + { + NONE = 0, //!< empty node + INT = 1, //!< an integer + REAL = 2, //!< floating-point number + FLOAT = REAL, //!< synonym or REAL + STR = 3, //!< text string in UTF-8 encoding + STRING = STR, //!< synonym for STR + SEQ = 4, //!< sequence + MAP = 5, //!< mapping + TYPE_MASK = 7, + + FLOW = 8, //!< compact representation of a sequence or mapping. Used only by YAML writer + UNIFORM = 8, //!< if set, means that all the collection elements are numbers of the same type (real's or int's). + //!< UNIFORM is used only when reading FileStorage; FLOW is used only when writing. So they share the same bit + EMPTY = 16, //!< empty structure (sequence or mapping) + NAMED = 32 //!< the node has a name (i.e. it is element of a mapping). + }; + /** @brief The constructors. + + These constructors are used to create a default file node, construct it from obsolete structures or + from the another file node. + */ + CV_WRAP FileNode(); + + /** @overload + @param fs Pointer to the file storage structure. + @param blockIdx Index of the memory block where the file node is stored + @param ofs Offset in bytes from the beginning of the serialized storage + + @deprecated + */ + FileNode(const FileStorage* fs, size_t blockIdx, size_t ofs); + + /** @overload + @param node File node to be used as initialization for the created file node. + */ + FileNode(const FileNode& node); + + FileNode& operator=(const FileNode& node); + + /** @brief Returns element of a mapping node or a sequence node. + @param nodename Name of an element in the mapping node. + @returns Returns the element with the given identifier. + */ + FileNode operator[](const String& nodename) const; + + /** @overload + @param nodename Name of an element in the mapping node. + */ + CV_WRAP_AS(getNode) FileNode operator[](const char* nodename) const; + + /** @overload + @param i Index of an element in the sequence node. + */ + CV_WRAP_AS(at) FileNode operator[](int i) const; + + /** @brief Returns keys of a mapping node. + @returns Keys of a mapping node. + */ + CV_WRAP std::vector keys() const; + + /** @brief Returns type of the node. + @returns Type of the node. See FileNode::Type + */ + CV_WRAP int type() const; + + //! returns true if the node is empty + CV_WRAP bool empty() const; + //! returns true if the node is a "none" object + CV_WRAP bool isNone() const; + //! returns true if the node is a sequence + CV_WRAP bool isSeq() const; + //! returns true if the node is a mapping + CV_WRAP bool isMap() const; + //! returns true if the node is an integer + CV_WRAP bool isInt() const; + //! returns true if the node is a floating-point number + CV_WRAP bool isReal() const; + //! returns true if the node is a text string + CV_WRAP bool isString() const; + //! returns true if the node has a name + CV_WRAP bool isNamed() const; + //! returns the node name or an empty string if the node is nameless + CV_WRAP std::string name() const; + //! returns the number of elements in the node, if it is a sequence or mapping, or 1 otherwise. + CV_WRAP size_t size() const; + //! returns raw size of the FileNode in bytes + CV_WRAP size_t rawSize() const; + //! returns the node content as an integer. If the node stores floating-point number, it is rounded. + operator int() const; + //! returns the node content as float + operator float() const; + //! returns the node content as double + operator double() const; + //! returns the node content as text string + inline operator std::string() const { return this->string(); } + + static bool isMap(int flags); + static bool isSeq(int flags); + static bool isCollection(int flags); + static bool isEmptyCollection(int flags); + static bool isFlow(int flags); + + uchar* ptr(); + const uchar* ptr() const; + + //! returns iterator pointing to the first node element + FileNodeIterator begin() const; + //! returns iterator pointing to the element following the last node element + FileNodeIterator end() const; + + /** @brief Reads node elements to the buffer with the specified format. + + Usually it is more convenient to use operator `>>` instead of this method. + @param fmt Specification of each array element. See @ref format_spec "format specification" + @param vec Pointer to the destination array. + @param len Number of bytes to read (buffer size limit). If it is greater than number of + remaining elements then all of them will be read. + */ + void readRaw( const String& fmt, void* vec, size_t len ) const; + + /** Internal method used when reading FileStorage. + Sets the type (int, real or string) and value of the previously created node. + */ + void setValue( int type, const void* value, int len=-1 ); + + //! Simplified reading API to use with bindings. + CV_WRAP double real() const; + //! Simplified reading API to use with bindings. + CV_WRAP std::string string() const; + //! Simplified reading API to use with bindings. + CV_WRAP Mat mat() const; + + //protected: + FileNode(FileStorage::Impl* fs, size_t blockIdx, size_t ofs); + + FileStorage::Impl* fs; + size_t blockIdx; + size_t ofs; +}; + + +/** @brief used to iterate through sequences and mappings. + + A standard STL notation, with node.begin(), node.end() denoting the beginning and the end of a + sequence, stored in node. See the data reading sample in the beginning of the section. + */ +class CV_EXPORTS FileNodeIterator +{ +public: + /** @brief The constructors. + + These constructors are used to create a default iterator, set it to specific element in a file node + or construct it from another iterator. + */ + FileNodeIterator(); + + /** @overload + @param node File node - the collection to iterate over; + it can be a scalar (equivalent to 1-element collection) or "none" (equivalent to empty collection). + @param seekEnd - true if iterator needs to be set after the last element of the node; + that is: + * node.begin() => FileNodeIterator(node, false) + * node.end() => FileNodeIterator(node, true) + */ + FileNodeIterator(const FileNode& node, bool seekEnd); + + /** @overload + @param it Iterator to be used as initialization for the created iterator. + */ + FileNodeIterator(const FileNodeIterator& it); + + FileNodeIterator& operator=(const FileNodeIterator& it); + + //! returns the currently observed element + FileNode operator *() const; + + //! moves iterator to the next node + FileNodeIterator& operator ++ (); + //! moves iterator to the next node + FileNodeIterator operator ++ (int); + //! moves iterator forward by the specified offset (possibly negative) + FileNodeIterator& operator += (int ofs); + + /** @brief Reads node elements to the buffer with the specified format. + + Usually it is more convenient to use operator `>>` instead of this method. + @param fmt Specification of each array element. See @ref format_spec "format specification" + @param vec Pointer to the destination array. + @param len Number of bytes to read (buffer size limit). If it is greater than number of + remaining elements then all of them will be read. + */ + FileNodeIterator& readRaw( const String& fmt, void* vec, + size_t len=(size_t)INT_MAX ); + + //! returns the number of remaining (not read yet) elements + size_t remaining() const; + + bool equalTo(const FileNodeIterator& it) const; + +protected: + FileStorage::Impl* fs; + size_t blockIdx; + size_t ofs; + size_t blockSize; + size_t nodeNElems; + size_t idx; +}; + +//! @} core_xml + +/////////////////// XML & YAML I/O implementation ////////////////// + +//! @relates cv::FileStorage +//! @{ + +CV_EXPORTS void write( FileStorage& fs, const String& name, int value ); +CV_EXPORTS void write( FileStorage& fs, const String& name, float value ); +CV_EXPORTS void write( FileStorage& fs, const String& name, double value ); +CV_EXPORTS void write( FileStorage& fs, const String& name, const String& value ); +CV_EXPORTS void write( FileStorage& fs, const String& name, const Mat& value ); +CV_EXPORTS void write( FileStorage& fs, const String& name, const SparseMat& value ); +#ifdef CV__LEGACY_PERSISTENCE +CV_EXPORTS void write( FileStorage& fs, const String& name, const std::vector& value); +CV_EXPORTS void write( FileStorage& fs, const String& name, const std::vector& value); +#endif + +CV_EXPORTS void writeScalar( FileStorage& fs, int value ); +CV_EXPORTS void writeScalar( FileStorage& fs, float value ); +CV_EXPORTS void writeScalar( FileStorage& fs, double value ); +CV_EXPORTS void writeScalar( FileStorage& fs, const String& value ); + +//! @} + +//! @relates cv::FileNode +//! @{ + +CV_EXPORTS void read(const FileNode& node, int& value, int default_value); +CV_EXPORTS void read(const FileNode& node, float& value, float default_value); +CV_EXPORTS void read(const FileNode& node, double& value, double default_value); +CV_EXPORTS void read(const FileNode& node, std::string& value, const std::string& default_value); +CV_EXPORTS void read(const FileNode& node, Mat& mat, const Mat& default_mat = Mat() ); +CV_EXPORTS void read(const FileNode& node, SparseMat& mat, const SparseMat& default_mat = SparseMat() ); +#ifdef CV__LEGACY_PERSISTENCE +CV_EXPORTS void read(const FileNode& node, std::vector& keypoints); +CV_EXPORTS void read(const FileNode& node, std::vector& matches); +#endif +CV_EXPORTS void read(const FileNode& node, KeyPoint& value, const KeyPoint& default_value); +CV_EXPORTS void read(const FileNode& node, DMatch& value, const DMatch& default_value); + +template static inline void read(const FileNode& node, Point_<_Tp>& value, const Point_<_Tp>& default_value) +{ + std::vector<_Tp> temp; FileNodeIterator it = node.begin(); it >> temp; + value = temp.size() != 2 ? default_value : Point_<_Tp>(saturate_cast<_Tp>(temp[0]), saturate_cast<_Tp>(temp[1])); +} + +template static inline void read(const FileNode& node, Point3_<_Tp>& value, const Point3_<_Tp>& default_value) +{ + std::vector<_Tp> temp; FileNodeIterator it = node.begin(); it >> temp; + value = temp.size() != 3 ? default_value : Point3_<_Tp>(saturate_cast<_Tp>(temp[0]), saturate_cast<_Tp>(temp[1]), + saturate_cast<_Tp>(temp[2])); +} + +template static inline void read(const FileNode& node, Size_<_Tp>& value, const Size_<_Tp>& default_value) +{ + std::vector<_Tp> temp; FileNodeIterator it = node.begin(); it >> temp; + value = temp.size() != 2 ? default_value : Size_<_Tp>(saturate_cast<_Tp>(temp[0]), saturate_cast<_Tp>(temp[1])); +} + +template static inline void read(const FileNode& node, Complex<_Tp>& value, const Complex<_Tp>& default_value) +{ + std::vector<_Tp> temp; FileNodeIterator it = node.begin(); it >> temp; + value = temp.size() != 2 ? default_value : Complex<_Tp>(saturate_cast<_Tp>(temp[0]), saturate_cast<_Tp>(temp[1])); +} + +template static inline void read(const FileNode& node, Rect_<_Tp>& value, const Rect_<_Tp>& default_value) +{ + std::vector<_Tp> temp; FileNodeIterator it = node.begin(); it >> temp; + value = temp.size() != 4 ? default_value : Rect_<_Tp>(saturate_cast<_Tp>(temp[0]), saturate_cast<_Tp>(temp[1]), + saturate_cast<_Tp>(temp[2]), saturate_cast<_Tp>(temp[3])); +} + +template static inline void read(const FileNode& node, Vec<_Tp, cn>& value, const Vec<_Tp, cn>& default_value) +{ + std::vector<_Tp> temp; FileNodeIterator it = node.begin(); it >> temp; + value = temp.size() != cn ? default_value : Vec<_Tp, cn>(&temp[0]); +} + +template static inline void read(const FileNode& node, Matx<_Tp, m, n>& value, const Matx<_Tp, m, n>& default_matx = Matx<_Tp, m, n>()) +{ + Mat temp; + read(node, temp); // read as a Mat class + + if (temp.empty()) + value = default_matx; + else + value = Matx<_Tp, m, n>(temp); +} + +template static inline void read(const FileNode& node, Scalar_<_Tp>& value, const Scalar_<_Tp>& default_value) +{ + std::vector<_Tp> temp; FileNodeIterator it = node.begin(); it >> temp; + value = temp.size() != 4 ? default_value : Scalar_<_Tp>(saturate_cast<_Tp>(temp[0]), saturate_cast<_Tp>(temp[1]), + saturate_cast<_Tp>(temp[2]), saturate_cast<_Tp>(temp[3])); +} + +static inline void read(const FileNode& node, Range& value, const Range& default_value) +{ + Point2i temp(value.start, value.end); const Point2i default_temp = Point2i(default_value.start, default_value.end); + read(node, temp, default_temp); + value.start = temp.x; value.end = temp.y; +} + +//! @} + +/** @brief Writes string to a file storage. +@relates cv::FileStorage + */ +CV_EXPORTS FileStorage& operator << (FileStorage& fs, const String& str); + +//! @cond IGNORED + +namespace internal +{ + class CV_EXPORTS WriteStructContext + { + public: + WriteStructContext(FileStorage& _fs, const String& name, int flags, const String& typeName = String()); + ~WriteStructContext(); + private: + FileStorage* fs; + }; + + template class VecWriterProxy + { + public: + VecWriterProxy( FileStorage* _fs ) : fs(_fs) {} + void operator()(const std::vector<_Tp>& vec) const + { + size_t count = vec.size(); + for (size_t i = 0; i < count; i++) + write(*fs, vec[i]); + } + private: + FileStorage* fs; + }; + + template class VecWriterProxy<_Tp, 1> + { + public: + VecWriterProxy( FileStorage* _fs ) : fs(_fs) {} + void operator()(const std::vector<_Tp>& vec) const + { + int _fmt = traits::SafeFmt<_Tp>::fmt; + char fmt[] = { (char)((_fmt >> 8) + '1'), (char)_fmt, '\0' }; + fs->writeRaw(fmt, !vec.empty() ? (uchar*)&vec[0] : 0, vec.size() * sizeof(_Tp)); + } + private: + FileStorage* fs; + }; + + template class VecReaderProxy + { + public: + VecReaderProxy( FileNodeIterator* _it ) : it(_it) {} + void operator()(std::vector<_Tp>& vec, size_t count) const + { + count = std::min(count, it->remaining()); + vec.resize(count); + for (size_t i = 0; i < count; i++, ++(*it)) + read(**it, vec[i], _Tp()); + } + private: + FileNodeIterator* it; + }; + + template class VecReaderProxy<_Tp, 1> + { + public: + VecReaderProxy( FileNodeIterator* _it ) : it(_it) {} + void operator()(std::vector<_Tp>& vec, size_t count) const + { + size_t remaining = it->remaining(); + size_t cn = DataType<_Tp>::channels; + int _fmt = traits::SafeFmt<_Tp>::fmt; + CV_Assert((_fmt >> 8) < 9); + char fmt[] = { (char)((_fmt >> 8)+'1'), (char)_fmt, '\0' }; + CV_Assert((remaining % cn) == 0); + size_t remaining1 = remaining / cn; + count = count > remaining1 ? remaining1 : count; + vec.resize(count); + it->readRaw(fmt, !vec.empty() ? (uchar*)&vec[0] : 0, count*sizeof(_Tp)); + } + private: + FileNodeIterator* it; + }; + +} // internal + +//! @endcond + +//! @relates cv::FileStorage +//! @{ + +template static inline +void write(FileStorage& fs, const _Tp& value) +{ + write(fs, String(), value); +} + +template<> inline +void write( FileStorage& fs, const int& value ) +{ + writeScalar(fs, value); +} + +template<> inline +void write( FileStorage& fs, const float& value ) +{ + writeScalar(fs, value); +} + +template<> inline +void write( FileStorage& fs, const double& value ) +{ + writeScalar(fs, value); +} + +template<> inline +void write( FileStorage& fs, const String& value ) +{ + writeScalar(fs, value); +} + +template static inline +void write(FileStorage& fs, const Point_<_Tp>& pt ) +{ + write(fs, pt.x); + write(fs, pt.y); +} + +template static inline +void write(FileStorage& fs, const Point3_<_Tp>& pt ) +{ + write(fs, pt.x); + write(fs, pt.y); + write(fs, pt.z); +} + +template static inline +void write(FileStorage& fs, const Size_<_Tp>& sz ) +{ + write(fs, sz.width); + write(fs, sz.height); +} + +template static inline +void write(FileStorage& fs, const Complex<_Tp>& c ) +{ + write(fs, c.re); + write(fs, c.im); +} + +template static inline +void write(FileStorage& fs, const Rect_<_Tp>& r ) +{ + write(fs, r.x); + write(fs, r.y); + write(fs, r.width); + write(fs, r.height); +} + +template static inline +void write(FileStorage& fs, const Vec<_Tp, cn>& v ) +{ + for(int i = 0; i < cn; i++) + write(fs, v.val[i]); +} + +template static inline +void write(FileStorage& fs, const Matx<_Tp, m, n>& x ) +{ + write(fs, Mat(x)); // write as a Mat class +} + +template static inline +void write(FileStorage& fs, const Scalar_<_Tp>& s ) +{ + write(fs, s.val[0]); + write(fs, s.val[1]); + write(fs, s.val[2]); + write(fs, s.val[3]); +} + +static inline +void write(FileStorage& fs, const Range& r ) +{ + write(fs, r.start); + write(fs, r.end); +} + +template static inline +void write( FileStorage& fs, const std::vector<_Tp>& vec ) +{ + cv::internal::VecWriterProxy<_Tp, traits::SafeFmt<_Tp>::fmt != 0> w(&fs); + w(vec); +} + +template static inline +void write(FileStorage& fs, const String& name, const Point_<_Tp>& pt ) +{ + cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ+FileNode::FLOW); + write(fs, pt); +} + +template static inline +void write(FileStorage& fs, const String& name, const Point3_<_Tp>& pt ) +{ + cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ+FileNode::FLOW); + write(fs, pt); +} + +template static inline +void write(FileStorage& fs, const String& name, const Size_<_Tp>& sz ) +{ + cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ+FileNode::FLOW); + write(fs, sz); +} + +template static inline +void write(FileStorage& fs, const String& name, const Complex<_Tp>& c ) +{ + cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ+FileNode::FLOW); + write(fs, c); +} + +template static inline +void write(FileStorage& fs, const String& name, const Rect_<_Tp>& r ) +{ + cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ+FileNode::FLOW); + write(fs, r); +} + +template static inline +void write(FileStorage& fs, const String& name, const Vec<_Tp, cn>& v ) +{ + cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ+FileNode::FLOW); + write(fs, v); +} + +template static inline +void write(FileStorage& fs, const String& name, const Matx<_Tp, m, n>& x ) +{ + write(fs, name, Mat(x)); // write as a Mat class +} + +template static inline +void write(FileStorage& fs, const String& name, const Scalar_<_Tp>& s ) +{ + cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ+FileNode::FLOW); + write(fs, s); +} + +static inline +void write(FileStorage& fs, const String& name, const Range& r ) +{ + cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ+FileNode::FLOW); + write(fs, r); +} + +static inline +void write(FileStorage& fs, const String& name, const KeyPoint& kpt) +{ + cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ+FileNode::FLOW); + write(fs, kpt.pt.x); + write(fs, kpt.pt.y); + write(fs, kpt.size); + write(fs, kpt.angle); + write(fs, kpt.response); + write(fs, kpt.octave); + write(fs, kpt.class_id); +} + +static inline +void write(FileStorage& fs, const String& name, const DMatch& m) +{ + cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ+FileNode::FLOW); + write(fs, m.queryIdx); + write(fs, m.trainIdx); + write(fs, m.imgIdx); + write(fs, m.distance); +} + +template::value >::type* = nullptr> +static inline void write( FileStorage& fs, const String& name, const _Tp& val ) +{ + write(fs, name, static_cast(val)); +} + +template static inline +void write( FileStorage& fs, const String& name, const std::vector<_Tp>& vec ) +{ + cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ+(traits::SafeFmt<_Tp>::fmt != 0 ? FileNode::FLOW : 0)); + write(fs, vec); +} + +template static inline +void write( FileStorage& fs, const String& name, const std::vector< std::vector<_Tp> >& vec ) +{ + cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ); + for(size_t i = 0; i < vec.size(); i++) + { + cv::internal::WriteStructContext ws_(fs, name, FileNode::SEQ+(traits::SafeFmt<_Tp>::fmt != 0 ? FileNode::FLOW : 0)); + write(fs, vec[i]); + } +} + +#ifdef CV__LEGACY_PERSISTENCE +// This code is not needed anymore, but it is preserved here to keep source compatibility +// Implementation is similar to templates instantiations +static inline void write(FileStorage& fs, const KeyPoint& kpt) { write(fs, String(), kpt); } +static inline void write(FileStorage& fs, const DMatch& m) { write(fs, String(), m); } +static inline void write(FileStorage& fs, const std::vector& vec) +{ + cv::internal::VecWriterProxy w(&fs); + w(vec); +} +static inline void write(FileStorage& fs, const std::vector& vec) +{ + cv::internal::VecWriterProxy w(&fs); + w(vec); + +} +#endif + +//! @} FileStorage + +//! @relates cv::FileNode +//! @{ + +static inline +void read(const FileNode& node, bool& value, bool default_value) +{ + int temp; + read(node, temp, (int)default_value); + value = temp != 0; +} + +static inline +void read(const FileNode& node, uchar& value, uchar default_value) +{ + int temp; + read(node, temp, (int)default_value); + value = saturate_cast(temp); +} + +static inline +void read(const FileNode& node, schar& value, schar default_value) +{ + int temp; + read(node, temp, (int)default_value); + value = saturate_cast(temp); +} + +static inline +void read(const FileNode& node, ushort& value, ushort default_value) +{ + int temp; + read(node, temp, (int)default_value); + value = saturate_cast(temp); +} + +static inline +void read(const FileNode& node, short& value, short default_value) +{ + int temp; + read(node, temp, (int)default_value); + value = saturate_cast(temp); +} + +template static inline +void read( FileNodeIterator& it, std::vector<_Tp>& vec, size_t maxCount = (size_t)INT_MAX ) +{ + cv::internal::VecReaderProxy<_Tp, traits::SafeFmt<_Tp>::fmt != 0> r(&it); + r(vec, maxCount); +} + +template::value >::type* = nullptr> +static inline void read(const FileNode& node, _Tp& value, const _Tp& default_value = static_cast<_Tp>(0)) +{ + int temp; + read(node, temp, static_cast(default_value)); + value = static_cast<_Tp>(temp); +} + +template static inline +void read( const FileNode& node, std::vector<_Tp>& vec, const std::vector<_Tp>& default_value = std::vector<_Tp>() ) +{ + if(node.empty()) + vec = default_value; + else + { + FileNodeIterator it = node.begin(); + read( it, vec ); + } +} + +static inline +void read( const FileNode& node, std::vector& vec, const std::vector& default_value ) +{ + if(node.empty()) + vec = default_value; + else + read(node, vec); +} + +static inline +void read( const FileNode& node, std::vector& vec, const std::vector& default_value ) +{ + if(node.empty()) + vec = default_value; + else + read(node, vec); +} + +//! @} FileNode + +//! @relates cv::FileStorage +//! @{ + +/** @brief Writes data to a file storage. + */ +template static inline +FileStorage& operator << (FileStorage& fs, const _Tp& value) +{ + if( !fs.isOpened() ) + return fs; + if( fs.state == FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP ) + CV_Error( Error::StsError, "No element name has been given" ); + write( fs, fs.elname, value ); + if( fs.state & FileStorage::INSIDE_MAP ) + fs.state = FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP; + return fs; +} + +/** @brief Writes data to a file storage. + */ +static inline +FileStorage& operator << (FileStorage& fs, const char* str) +{ + return (fs << String(str)); +} + +/** @brief Writes data to a file storage. + */ +static inline +FileStorage& operator << (FileStorage& fs, char* value) +{ + return (fs << String(value)); +} + +//! @} FileStorage + +//! @relates cv::FileNodeIterator +//! @{ + +/** @brief Reads data from a file storage. + */ +template static inline +FileNodeIterator& operator >> (FileNodeIterator& it, _Tp& value) +{ + read( *it, value, _Tp()); + return ++it; +} + +/** @brief Reads data from a file storage. + */ +template static inline +FileNodeIterator& operator >> (FileNodeIterator& it, std::vector<_Tp>& vec) +{ + cv::internal::VecReaderProxy<_Tp, traits::SafeFmt<_Tp>::fmt != 0> r(&it); + r(vec, (size_t)INT_MAX); + return it; +} + +//! @} FileNodeIterator + +//! @relates cv::FileNode +//! @{ + +/** @brief Reads data from a file storage. + */ +template static inline +void operator >> (const FileNode& n, _Tp& value) +{ + read( n, value, _Tp()); +} + +/** @brief Reads data from a file storage. + */ +template static inline +void operator >> (const FileNode& n, std::vector<_Tp>& vec) +{ + FileNodeIterator it = n.begin(); + it >> vec; +} + +/** @brief Reads KeyPoint from a file storage. +*/ +//It needs special handling because it contains two types of fields, int & float. +static inline +void operator >> (const FileNode& n, KeyPoint& kpt) +{ + FileNodeIterator it = n.begin(); + it >> kpt.pt.x >> kpt.pt.y >> kpt.size >> kpt.angle >> kpt.response >> kpt.octave >> kpt.class_id; +} + +#ifdef CV__LEGACY_PERSISTENCE +static inline +void operator >> (const FileNode& n, std::vector& vec) +{ + read(n, vec); +} +static inline +void operator >> (const FileNode& n, std::vector& vec) +{ + read(n, vec); +} +#endif + +/** @brief Reads DMatch from a file storage. +*/ +//It needs special handling because it contains two types of fields, int & float. +static inline +void operator >> (const FileNode& n, DMatch& m) +{ + FileNodeIterator it = n.begin(); + it >> m.queryIdx >> m.trainIdx >> m.imgIdx >> m.distance; +} + +//! @} FileNode + +//! @relates cv::FileNodeIterator +//! @{ + +CV_EXPORTS bool operator == (const FileNodeIterator& it1, const FileNodeIterator& it2); +CV_EXPORTS bool operator != (const FileNodeIterator& it1, const FileNodeIterator& it2); + +static inline +ptrdiff_t operator - (const FileNodeIterator& it1, const FileNodeIterator& it2) +{ + return it2.remaining() - it1.remaining(); +} + +static inline +bool operator < (const FileNodeIterator& it1, const FileNodeIterator& it2) +{ + return it1.remaining() > it2.remaining(); +} + +//! @} FileNodeIterator + +} // cv + +#endif // OPENCV_CORE_PERSISTENCE_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/quaternion.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/quaternion.hpp new file mode 100644 index 0000000..8c21501 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/quaternion.hpp @@ -0,0 +1,1696 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2020, Huawei Technologies Co., Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Liangqian Kong +// Longbu Wang +#ifndef OPENCV_CORE_QUATERNION_HPP +#define OPENCV_CORE_QUATERNION_HPP + +#include +#include +#include +namespace cv +{ +//! @addtogroup core +//! @{ + +//! Unit quaternion flag +enum QuatAssumeType +{ + /** + * This flag is specified by default. + * If this flag is specified, the input quaternions are assumed to be not unit quaternions. + * It can guarantee the correctness of the calculations, + * although the calculation speed will be slower than the flag QUAT_ASSUME_UNIT. + */ + QUAT_ASSUME_NOT_UNIT, + /** + * If this flag is specified, the input quaternions are assumed to be unit quaternions which + * will save some computations. However, if this flag is specified without unit quaternion, + * the program correctness of the result will not be guaranteed. + */ + QUAT_ASSUME_UNIT +}; + +class QuatEnum +{ +public: + /** @brief Enum of Euler angles type. + * + * Without considering the possibility of using two different convertions for the definition of the rotation axes , + * there exists twelve possible sequences of rotation axes, divided into two groups: + * - Proper Euler angles (Z-X-Z, X-Y-X, Y-Z-Y, Z-Y-Z, X-Z-X, Y-X-Y) + * - Tait–Bryan angles (X-Y-Z, Y-Z-X, Z-X-Y, X-Z-Y, Z-Y-X, Y-X-Z). + * + * The three elemental rotations may be [extrinsic](https://en.wikipedia.org/wiki/Euler_angles#Definition_by_extrinsic_rotations) + * (rotations about the axes *xyz* of the original coordinate system, which is assumed to remain motionless), + * or [intrinsic](https://en.wikipedia.org/wiki/Euler_angles#Definition_by_intrinsic_rotations)(rotations about the axes of the rotating coordinate system *XYZ*, solidary with the moving body, which changes its orientation after each elemental rotation). + * + * + * Extrinsic and intrinsic rotations are relevant. + * + * The definition of the Euler angles is as following, + * - \f$\theta_1 \f$ represents the first rotation angle, + * - \f$\theta_2 \f$ represents the second rotation angle, + * - \f$\theta_3 \f$ represents the third rotation angle. + * + * For intrinsic rotations in the order of X-Y-Z, the rotation matrix R can be calculated by:\f[R =X(\theta_1) Y(\theta_2) Z(\theta_3) \f] + * For extrinsic rotations in the order of X-Y-Z, the rotation matrix R can be calculated by:\f[R =Z({\theta_3}) Y({\theta_2}) X({\theta_1})\f] + * where + * \f[X({\theta})={\begin{bmatrix}1&0&0\\0&\cos {\theta_1} &-\sin {\theta_1} \\0&\sin {\theta_1} &\cos {\theta_1} \\\end{bmatrix}}, + * Y({\theta})={\begin{bmatrix}\cos \theta_{2}&0&\sin \theta_{2}\\0&1 &0 \\\ -sin \theta_2& 0&\cos \theta_{2} \\\end{bmatrix}}, + * Z({\theta})={\begin{bmatrix}\cos\theta_{3} &-\sin \theta_3&0\\\sin \theta_3 &\cos \theta_3 &0\\0&0&1\\\end{bmatrix}}. + * \f] + * + * The function is designed according to this set of conventions: + * - [Right handed](https://en.wikipedia.org/wiki/Right_hand_rule) reference frames are adopted, and the [right hand rule](https://en.wikipedia.org/wiki/Right_hand_rule) is used to determine the sign of angles. + * - Each matrix is meant to represent an [active rotation](https://en.wikipedia.org/wiki/Active_and_passive_transformation) (the composing and composed matrices + * are supposed to act on the coordinates of vectors defined in the initial fixed reference frame and give as a result the coordinates of a rotated vector defined in the same reference frame). + * - For \f$\theta_1\f$ and \f$\theta_3\f$, the valid range is (−π, π]. + * + * For \f$\theta_2\f$, the valid range is [−π/2, π/2] or [0, π]. + * + * For Tait–Bryan angles, the valid range of \f$\theta_2\f$ is [−π/2, π/2]. When transforming a quaternion to Euler angles, the solution of Euler angles is unique in condition of \f$ \theta_2 \in (−π/2, π/2)\f$ . + * If \f$\theta_2 = −π/2 \f$ or \f$ \theta_2 = π/2\f$, there are infinite solutions. The common name for this situation is gimbal lock. + * For Proper Euler angles,the valid range of \f$\theta_2\f$ is in [0, π]. The solutions of Euler angles are unique in condition of \f$ \theta_2 \in (0, π)\f$ . If \f$\theta_2 =0 \f$ or \f$\theta_2 =π \f$, + * there are infinite solutions and gimbal lock will occur. + */ + enum EulerAnglesType + { + INT_XYZ, ///< Intrinsic rotations with the Euler angles type X-Y-Z + INT_XZY, ///< Intrinsic rotations with the Euler angles type X-Z-Y + INT_YXZ, ///< Intrinsic rotations with the Euler angles type Y-X-Z + INT_YZX, ///< Intrinsic rotations with the Euler angles type Y-Z-X + INT_ZXY, ///< Intrinsic rotations with the Euler angles type Z-X-Y + INT_ZYX, ///< Intrinsic rotations with the Euler angles type Z-Y-X + INT_XYX, ///< Intrinsic rotations with the Euler angles type X-Y-X + INT_XZX, ///< Intrinsic rotations with the Euler angles type X-Z-X + INT_YXY, ///< Intrinsic rotations with the Euler angles type Y-X-Y + INT_YZY, ///< Intrinsic rotations with the Euler angles type Y-Z-Y + INT_ZXZ, ///< Intrinsic rotations with the Euler angles type Z-X-Z + INT_ZYZ, ///< Intrinsic rotations with the Euler angles type Z-Y-Z + + EXT_XYZ, ///< Extrinsic rotations with the Euler angles type X-Y-Z + EXT_XZY, ///< Extrinsic rotations with the Euler angles type X-Z-Y + EXT_YXZ, ///< Extrinsic rotations with the Euler angles type Y-X-Z + EXT_YZX, ///< Extrinsic rotations with the Euler angles type Y-Z-X + EXT_ZXY, ///< Extrinsic rotations with the Euler angles type Z-X-Y + EXT_ZYX, ///< Extrinsic rotations with the Euler angles type Z-Y-X + EXT_XYX, ///< Extrinsic rotations with the Euler angles type X-Y-X + EXT_XZX, ///< Extrinsic rotations with the Euler angles type X-Z-X + EXT_YXY, ///< Extrinsic rotations with the Euler angles type Y-X-Y + EXT_YZY, ///< Extrinsic rotations with the Euler angles type Y-Z-Y + EXT_ZXZ, ///< Extrinsic rotations with the Euler angles type Z-X-Z + EXT_ZYZ, ///< Extrinsic rotations with the Euler angles type Z-Y-Z + #ifndef CV_DOXYGEN + EULER_ANGLES_MAX_VALUE + #endif + }; + +}; + +template class Quat; +template std::ostream& operator<<(std::ostream&, const Quat<_Tp>&); + +/** + * Quaternion is a number system that extends the complex numbers. It can be expressed as a + * rotation in three-dimensional space. + * A quaternion is generally represented in the form: + * \f[q = w + x\boldsymbol{i} + y\boldsymbol{j} + z\boldsymbol{k}\f] + * \f[q = [w, x, y, z]\f] + * \f[q = [w, \boldsymbol{v}] \f] + * \f[q = ||q||[\cos\psi, u_x\sin\psi,u_y\sin\psi, u_z\sin\psi].\f] + * \f[q = ||q||[\cos\psi, \boldsymbol{u}\sin\psi]\f] + * where \f$\psi = \frac{\theta}{2}\f$, \f$\theta\f$ represents rotation angle, + * \f$\boldsymbol{u} = [u_x, u_y, u_z]\f$ represents normalized rotation axis, + * and \f$||q||\f$ represents the norm of \f$q\f$. + * + * A unit quaternion is usually represents rotation, which has the form: + * \f[q = [\cos\psi, u_x\sin\psi,u_y\sin\psi, u_z\sin\psi].\f] + * + * To create a quaternion representing the rotation around the axis \f$\boldsymbol{u}\f$ + * with angle \f$\theta\f$, you can use + * ``` + * using namespace cv; + * double angle = CV_PI; + * Vec3d axis = {0, 0, 1}; + * Quatd q = Quatd::createFromAngleAxis(angle, axis); + * ``` + * + * You can simply use four same type number to create a quaternion + * ``` + * Quatd q(1, 2, 3, 4); + * ``` + * Or use a Vec4d or Vec4f vector. + * ``` + * Vec4d vec{1, 2, 3, 4}; + * Quatd q(vec); + * ``` + * + * ``` + * Vec4f vec{1, 2, 3, 4}; + * Quatf q(vec); + * ``` + * + * If you already have a 3x3 rotation matrix R, then you can use + * ``` + * Quatd q = Quatd::createFromRotMat(R); + * ``` + * + * If you already have a rotation vector rvec which has the form of `angle * axis`, then you can use + * ``` + * Quatd q = Quatd::createFromRvec(rvec); + * ``` + * + * To extract the rotation matrix from quaternion, see toRotMat3x3() + * + * To extract the Vec4d or Vec4f, see toVec() + * + * To extract the rotation vector, see toRotVec() + * + * If there are two quaternions \f$q_0, q_1\f$ are needed to interpolate, you can use nlerp(), slerp() or spline() + * ``` + * Quatd::nlerp(q0, q1, t) + * + * Quatd::slerp(q0, q1, t) + * + * Quatd::spline(q0, q0, q1, q1, t) + * ``` + * spline can smoothly connect rotations of multiple quaternions + * + * Three ways to get an element in Quaternion + * ``` + * Quatf q(1,2,3,4); + * std::cout << q.w << std::endl; // w=1, x=2, y=3, z=4 + * std::cout << q[0] << std::endl; // q[0]=1, q[1]=2, q[2]=3, q[3]=4 + * std::cout << q.at(0) << std::endl; + * ``` + */ +template +class Quat +{ + static_assert(std::is_floating_point<_Tp>::value, "Quaternion only make sense with type of float or double"); + using value_type = _Tp; +public: + static constexpr _Tp CV_QUAT_EPS = (_Tp)1.e-6; + static constexpr _Tp CV_QUAT_CONVERT_THRESHOLD = (_Tp)1.e-6; + + Quat(); + + /** + * @brief From Vec4d or Vec4f. + */ + explicit Quat(const Vec<_Tp, 4> &coeff); + + /** + * @brief from four numbers. + */ + Quat(_Tp w, _Tp x, _Tp y, _Tp z); + + /** + * @brief from an angle, axis. Axis will be normalized in this function. And + * it generates + * \f[q = [\cos\psi, u_x\sin\psi,u_y\sin\psi, u_z\sin\psi].\f] + * where \f$\psi = \frac{\theta}{2}\f$, \f$\theta\f$ is the rotation angle. + */ + static Quat<_Tp> createFromAngleAxis(const _Tp angle, const Vec<_Tp, 3> &axis); + + /** + * @brief from a 3x3 rotation matrix. + */ + static Quat<_Tp> createFromRotMat(InputArray R); + + /** + * @brief from a rotation vector + * \f$r\f$ has the form \f$\theta \cdot \boldsymbol{u}\f$, where \f$\theta\f$ + * represents rotation angle and \f$\boldsymbol{u}\f$ represents normalized rotation axis. + * + * Angle and axis could be easily derived as: + * \f[ + * \begin{equation} + * \begin{split} + * \psi &= ||r||\\ + * \boldsymbol{u} &= \frac{r}{\theta} + * \end{split} + * \end{equation} + * \f] + * Then a quaternion can be calculated by + * \f[q = [\cos\psi, \boldsymbol{u}\sin\psi]\f] + * where \f$\psi = \theta / 2 \f$ + */ + static Quat<_Tp> createFromRvec(InputArray rvec); + + /** + * @brief + * from Euler angles + * + * A quaternion can be generated from Euler angles by combining the quaternion representations of the Euler rotations. + * + * For example, if we use intrinsic rotations in the order of X-Y-Z,\f$\theta_1 \f$ is rotation around the X-axis, \f$\theta_2 \f$ is rotation around the Y-axis, + * \f$\theta_3 \f$ is rotation around the Z-axis. The final quaternion q can be calculated by + * + * \f[ {q} = q_{X, \theta_1} q_{Y, \theta_2} q_{Z, \theta_3}\f] + * where \f$ q_{X, \theta_1} \f$ is created from @ref createFromXRot, \f$ q_{Y, \theta_2} \f$ is created from @ref createFromYRot, + * \f$ q_{Z, \theta_3} \f$ is created from @ref createFromZRot. + * @param angles the Euler angles in a vector of length 3 + * @param eulerAnglesType the convertion Euler angles type + */ + static Quat<_Tp> createFromEulerAngles(const Vec<_Tp, 3> &angles, QuatEnum::EulerAnglesType eulerAnglesType); + + /** + * @brief get a quaternion from a rotation about the Y-axis by \f$\theta\f$ . + * \f[q = \cos(\theta/2)+0 i+ sin(\theta/2) j +0k \f] + */ + static Quat<_Tp> createFromYRot(const _Tp theta); + + /** + * @brief get a quaternion from a rotation about the X-axis by \f$\theta\f$ . + * \f[q = \cos(\theta/2)+sin(\theta/2) i +0 j +0 k \f] + */ + static Quat<_Tp> createFromXRot(const _Tp theta); + + /** + * @brief get a quaternion from a rotation about the Z-axis by \f$\theta\f$. + * \f[q = \cos(\theta/2)+0 i +0 j +sin(\theta/2) k \f] + */ + static Quat<_Tp> createFromZRot(const _Tp theta); + + /** + * @brief a way to get element. + * @param index over a range [0, 3]. + * + * A quaternion q + * + * q.at(0) is equivalent to q.w, + * + * q.at(1) is equivalent to q.x, + * + * q.at(2) is equivalent to q.y, + * + * q.at(3) is equivalent to q.z. + */ + _Tp at(size_t index) const; + + /** + * @brief return the conjugate of this quaternion. + * \f[q.conjugate() = (w, -x, -y, -z).\f] + */ + Quat<_Tp> conjugate() const; + + /** + * + * @brief return the value of exponential value. + * \f[\exp(q) = e^w (\cos||\boldsymbol{v}||+ \frac{v}{||\boldsymbol{v}||})\sin||\boldsymbol{v}||\f] + * where \f$\boldsymbol{v} = [x, y, z].\f$ + * @param q a quaternion. + * + * For example: + * ``` + * Quatd q{1,2,3,4}; + * cout << exp(q) << endl; + * ``` + */ + template + friend Quat exp(const Quat &q); + + /** + * @brief return the value of exponential value. + * \f[\exp(q) = e^w (\cos||\boldsymbol{v}||+ \frac{v}{||\boldsymbol{v}||}\sin||\boldsymbol{v}||)\f] + * where \f$\boldsymbol{v} = [x, y, z].\f$ + * + * For example + * ``` + * Quatd q{1,2,3,4}; + * cout << q.exp() << endl; + * ``` + */ + Quat<_Tp> exp() const; + + /** + * @brief return the value of logarithm function. + * \f[\ln(q) = \ln||q|| + \frac{\boldsymbol{v}}{||\boldsymbol{v}||}\arccos\frac{w}{||q||}.\f] + * where \f$\boldsymbol{v} = [x, y, z].\f$ + * @param q a quaternion. + * @param assumeUnit if QUAT_ASSUME_UNIT, q assume to be a unit quaternion and this function will save some computations. + * + * For example + * ``` + * Quatd q1{1,2,3,4}; + * cout << log(q1) << endl; + * ``` + */ + template + friend Quat log(const Quat &q, QuatAssumeType assumeUnit); + + /** + * @brief return the value of logarithm function. + * \f[\ln(q) = \ln||q|| + \frac{\boldsymbol{v}}{||\boldsymbol{v}||}\arccos\frac{w}{||q||}\f]. + * where \f$\boldsymbol{v} = [x, y, z].\f$ + * @param assumeUnit if QUAT_ASSUME_UNIT, this quaternion assume to be a unit quaternion and this function will save some computations. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * q.log(); + * + * QuatAssumeType assumeUnit = QUAT_ASSUME_UNIT; + * Quatd q1(1,2,3,4); + * q1.normalize().log(assumeUnit); + * ``` + */ + Quat<_Tp> log(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const; + + /** + * @brief return the value of power function with index \f$x\f$. + * \f[q^x = ||q||(cos(x\theta) + \boldsymbol{u}sin(x\theta))).\f] + * @param q a quaternion. + * @param x index of exponentiation. + * @param assumeUnit if QUAT_ASSUME_UNIT, quaternion q assume to be a unit quaternion and this function will save some computations. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * power(q, 2.0); + * + * QuatAssumeType assumeUnit = QUAT_ASSUME_UNIT; + * double angle = CV_PI; + * Vec3d axis{0, 0, 1}; + * Quatd q1 = Quatd::createFromAngleAxis(angle, axis); //generate a unit quat by axis and angle + * power(q1, 2.0, assumeUnit);//This assumeUnit means q1 is a unit quaternion. + * ``` + * @note the type of the index should be the same as the quaternion. + */ + template + friend Quat power(const Quat &q, const T x, QuatAssumeType assumeUnit); + + /** + * @brief return the value of power function with index \f$x\f$. + * \f[q^x = ||q||(\cos(x\theta) + \boldsymbol{u}\sin(x\theta))).\f] + * @param x index of exponentiation. + * @param assumeUnit if QUAT_ASSUME_UNIT, this quaternion assume to be a unit quaternion and this function will save some computations. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * q.power(2.0); + * + * QuatAssumeType assumeUnit = QUAT_ASSUME_UNIT; + * double angle = CV_PI; + * Vec3d axis{0, 0, 1}; + * Quatd q1 = Quatd::createFromAngleAxis(angle, axis); //generate a unit quat by axis and angle + * q1.power(2.0, assumeUnit); //This assumeUnt means q1 is a unit quaternion + * ``` + */ + Quat<_Tp> power(const _Tp x, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const; + + /** + * @brief return \f$\sqrt{q}\f$. + * @param q a quaternion. + * @param assumeUnit if QUAT_ASSUME_UNIT, quaternion q assume to be a unit quaternion and this function will save some computations. + * + * For example + * ``` + * Quatf q(1,2,3,4); + * sqrt(q); + * + * QuatAssumeType assumeUnit = QUAT_ASSUME_UNIT; + * q = {1,0,0,0}; + * sqrt(q, assumeUnit); //This assumeUnit means q is a unit quaternion. + * ``` + */ + template + friend Quat sqrt(const Quat &q, QuatAssumeType assumeUnit); + + /** + * @brief return \f$\sqrt{q}\f$. + * @param assumeUnit if QUAT_ASSUME_UNIT, this quaternion assume to be a unit quaternion and this function will save some computations. + * + * For example + * ``` + * Quatf q(1,2,3,4); + * q.sqrt(); + * + * QuatAssumeType assumeUnit = QUAT_ASSUME_UNIT; + * q = {1,0,0,0}; + * q.sqrt(assumeUnit); //This assumeUnit means q is a unit quaternion + * ``` + */ + Quat<_Tp> sqrt(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const; + + /** + * @brief return the value of power function with quaternion \f$q\f$. + * \f[p^q = e^{q\ln(p)}.\f] + * @param p base quaternion of power function. + * @param q index quaternion of power function. + * @param assumeUnit if QUAT_ASSUME_UNIT, quaternion \f$p\f$ assume to be a unit quaternion and this function will save some computations. + * + * For example + * ``` + * Quatd p(1,2,3,4); + * Quatd q(5,6,7,8); + * power(p, q); + * + * QuatAssumeType assumeUnit = QUAT_ASSUME_UNIT; + * p = p.normalize(); + * power(p, q, assumeUnit); //This assumeUnit means p is a unit quaternion + * ``` + */ + template + friend Quat power(const Quat &p, const Quat &q, QuatAssumeType assumeUnit); + + /** + * @brief return the value of power function with quaternion \f$q\f$. + * \f[p^q = e^{q\ln(p)}.\f] + * @param q index quaternion of power function. + * @param assumeUnit if QUAT_ASSUME_UNIT, this quaternion assume to be a unit quaternion and this function will save some computations. + * + * For example + * ``` + * Quatd p(1,2,3,4); + * Quatd q(5,6,7,8); + * p.power(q); + * + * QuatAssumeType assumeUnit = QUAT_ASSUME_UNIT; + * p = p.normalize(); + * p.power(q, assumeUnit); //This assumeUnit means p is a unit quaternion + * ``` + */ + Quat<_Tp> power(const Quat<_Tp> &q, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const; + + /** + * @brief return the crossProduct between \f$p = (a, b, c, d) = (a, \boldsymbol{u})\f$ and \f$q = (w, x, y, z) = (w, \boldsymbol{v})\f$. + * \f[p \times q = \frac{pq- qp}{2}\f] + * \f[p \times q = \boldsymbol{u} \times \boldsymbol{v}\f] + * \f[p \times q = (cz-dy)i + (dx-bz)j + (by-xc)k \f] + * + * For example + * ``` + * Quatd q{1,2,3,4}; + * Quatd p{5,6,7,8}; + * crossProduct(p, q); + * ``` + */ + template + friend Quat crossProduct(const Quat &p, const Quat &q); + + /** + * @brief return the crossProduct between \f$p = (a, b, c, d) = (a, \boldsymbol{u})\f$ and \f$q = (w, x, y, z) = (w, \boldsymbol{v})\f$. + * \f[p \times q = \frac{pq- qp}{2}.\f] + * \f[p \times q = \boldsymbol{u} \times \boldsymbol{v}.\f] + * \f[p \times q = (cz-dy)i + (dx-bz)j + (by-xc)k. \f] + * + * For example + * ``` + * Quatd q{1,2,3,4}; + * Quatd p{5,6,7,8}; + * p.crossProduct(q) + * ``` + */ + Quat<_Tp> crossProduct(const Quat<_Tp> &q) const; + + /** + * @brief return the norm of quaternion. + * \f[||q|| = \sqrt{w^2 + x^2 + y^2 + z^2}.\f] + */ + _Tp norm() const; + + /** + * @brief return a normalized \f$p\f$. + * \f[p = \frac{q}{||q||}\f] + * where \f$p\f$ satisfies \f$(p.x)^2 + (p.y)^2 + (p.z)^2 + (p.w)^2 = 1.\f$ + */ + Quat<_Tp> normalize() const; + + /** + * @brief return \f$q^{-1}\f$ which is an inverse of \f$q\f$ + * which satisfies \f$q * q^{-1} = 1\f$. + * @param q a quaternion. + * @param assumeUnit if QUAT_ASSUME_UNIT, quaternion q assume to be a unit quaternion and this function will save some computations. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * inv(q); + * + * QuatAssumeType assumeUnit = QUAT_ASSUME_UNIT; + * q = q.normalize(); + * inv(q, assumeUnit);//This assumeUnit means p is a unit quaternion + * ``` + */ + template + friend Quat inv(const Quat &q, QuatAssumeType assumeUnit); + + /** + * @brief return \f$q^{-1}\f$ which is an inverse of \f$q\f$ + * satisfying \f$q * q^{-1} = 1\f$. + * @param assumeUnit if QUAT_ASSUME_UNIT, quaternion q assume to be a unit quaternion and this function will save some computations. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * q.inv(); + * + * QuatAssumeType assumeUnit = QUAT_ASSUME_UNIT; + * q = q.normalize(); + * q.inv(assumeUnit); //assumeUnit means p is a unit quaternion + * ``` + */ + Quat<_Tp> inv(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const; + + /** + * @brief return sinh value of quaternion q, sinh could be calculated as: + * \f[\sinh(p) = \sin(w)\cos(||\boldsymbol{v}||) + \cosh(w)\frac{v}{||\boldsymbol{v}||}\sin||\boldsymbol{v}||\f] + * where \f$\boldsymbol{v} = [x, y, z].\f$ + * @param q a quaternion. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * sinh(q); + * ``` + */ + template + friend Quat sinh(const Quat &q); + + /** + * @brief return sinh value of this quaternion, sinh could be calculated as: + * \f$\sinh(p) = \sin(w)\cos(||\boldsymbol{v}||) + \cosh(w)\frac{v}{||\boldsymbol{v}||}\sin||\boldsymbol{v}||\f$ + * where \f$\boldsymbol{v} = [x, y, z].\f$ + * + * For example + * ``` + * Quatd q(1,2,3,4); + * q.sinh(); + * ``` + */ + Quat<_Tp> sinh() const; + + /** + * @brief return cosh value of quaternion q, cosh could be calculated as: + * \f[\cosh(p) = \cosh(w) * \cos(||\boldsymbol{v}||) + \sinh(w)\frac{\boldsymbol{v}}{||\boldsymbol{v}||}\sin(||\boldsymbol{v}||)\f] + * where \f$\boldsymbol{v} = [x, y, z].\f$ + * @param q a quaternion. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * cosh(q); + * ``` + */ + template + friend Quat cosh(const Quat &q); + + /** + * @brief return cosh value of this quaternion, cosh could be calculated as: + * \f[\cosh(p) = \cosh(w) * \cos(||\boldsymbol{v}||) + \sinh(w)\frac{\boldsymbol{v}}{||\boldsymbol{v}||}sin(||\boldsymbol{v}||)\f] + * where \f$\boldsymbol{v} = [x, y, z].\f$ + * + * For example + * ``` + * Quatd q(1,2,3,4); + * q.cosh(); + * ``` + */ + Quat<_Tp> cosh() const; + + /** + * @brief return tanh value of quaternion q, tanh could be calculated as: + * \f[ \tanh(q) = \frac{\sinh(q)}{\cosh(q)}.\f] + * @param q a quaternion. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * tanh(q); + * ``` + * @sa sinh, cosh + */ + template + friend Quat tanh(const Quat &q); + + /** + * @brief return tanh value of this quaternion, tanh could be calculated as: + * \f[ \tanh(q) = \frac{\sinh(q)}{\cosh(q)}.\f] + * + * For example + * ``` + * Quatd q(1,2,3,4); + * q.tanh(); + * ``` + * @sa sinh, cosh + */ + Quat<_Tp> tanh() const; + + /** + * @brief return tanh value of quaternion q, sin could be calculated as: + * \f[\sin(p) = \sin(w) * \cosh(||\boldsymbol{v}||) + \cos(w)\frac{\boldsymbol{v}}{||\boldsymbol{v}||}\sinh(||\boldsymbol{v}||)\f] + * where \f$\boldsymbol{v} = [x, y, z].\f$ + * @param q a quaternion. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * sin(q); + * ``` + */ + template + friend Quat sin(const Quat &q); + + /** + * @brief return sin value of this quaternion, sin could be calculated as: + * \f[\sin(p) = \sin(w) * \cosh(||\boldsymbol{v}||) + \cos(w)\frac{\boldsymbol{v}}{||\boldsymbol{v}||}\sinh(||\boldsymbol{v}||)\f] + * where \f$\boldsymbol{v} = [x, y, z].\f$ + * + * For example + * ``` + * Quatd q(1,2,3,4); + * q.sin(); + * ``` + */ + Quat<_Tp> sin() const; + + /** + * @brief return sin value of quaternion q, cos could be calculated as: + * \f[\cos(p) = \cos(w) * \cosh(||\boldsymbol{v}||) - \sin(w)\frac{\boldsymbol{v}}{||\boldsymbol{v}||}\sinh(||\boldsymbol{v}||)\f] + * where \f$\boldsymbol{v} = [x, y, z].\f$ + * @param q a quaternion. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * cos(q); + * ``` + */ + template + friend Quat cos(const Quat &q); + + /** + * @brief return cos value of this quaternion, cos could be calculated as: + * \f[\cos(p) = \cos(w) * \cosh(||\boldsymbol{v}||) - \sin(w)\frac{\boldsymbol{v}}{||\boldsymbol{v}||}\sinh(||\boldsymbol{v}||)\f] + * where \f$\boldsymbol{v} = [x, y, z].\f$ + * + * For example + * ``` + * Quatd q(1,2,3,4); + * q.cos(); + * ``` + */ + Quat<_Tp> cos() const; + + /** + * @brief return tan value of quaternion q, tan could be calculated as: + * \f[\tan(q) = \frac{\sin(q)}{\cos(q)}.\f] + * @param q a quaternion. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * tan(q); + * ``` + */ + template + friend Quat tan(const Quat &q); + + /** + * @brief return tan value of this quaternion, tan could be calculated as: + * \f[\tan(q) = \frac{\sin(q)}{\cos(q)}.\f] + * + * For example + * ``` + * Quatd q(1,2,3,4); + * q.tan(); + * ``` + */ + Quat<_Tp> tan() const; + + /** + * @brief return arcsin value of quaternion q, arcsin could be calculated as: + * \f[\arcsin(q) = -\frac{\boldsymbol{v}}{||\boldsymbol{v}||}arcsinh(q\frac{\boldsymbol{v}}{||\boldsymbol{v}||})\f] + * where \f$\boldsymbol{v} = [x, y, z].\f$ + * @param q a quaternion. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * asin(q); + * ``` + */ + template + friend Quat asin(const Quat &q); + + /** + * @brief return arcsin value of this quaternion, arcsin could be calculated as: + * \f[\arcsin(q) = -\frac{\boldsymbol{v}}{||\boldsymbol{v}||}arcsinh(q\frac{\boldsymbol{v}}{||\boldsymbol{v}||})\f] + * where \f$\boldsymbol{v} = [x, y, z].\f$ + * + * For example + * ``` + * Quatd q(1,2,3,4); + * q.asin(); + * ``` + */ + Quat<_Tp> asin() const; + + /** + * @brief return arccos value of quaternion q, arccos could be calculated as: + * \f[\arccos(q) = -\frac{\boldsymbol{v}}{||\boldsymbol{v}||}arccosh(q)\f] + * where \f$\boldsymbol{v} = [x, y, z].\f$ + * @param q a quaternion. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * acos(q); + * ``` + */ + template + friend Quat acos(const Quat &q); + + /** + * @brief return arccos value of this quaternion, arccos could be calculated as: + * \f[\arccos(q) = -\frac{\boldsymbol{v}}{||\boldsymbol{v}||}arccosh(q)\f] + * where \f$\boldsymbol{v} = [x, y, z].\f$ + * + * For example + * ``` + * Quatd q(1,2,3,4); + * q.acos(); + * ``` + */ + Quat<_Tp> acos() const; + + /** + * @brief return arctan value of quaternion q, arctan could be calculated as: + * \f[\arctan(q) = -\frac{\boldsymbol{v}}{||\boldsymbol{v}||}arctanh(q\frac{\boldsymbol{v}}{||\boldsymbol{v}||})\f] + * where \f$\boldsymbol{v} = [x, y, z].\f$ + * @param q a quaternion. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * atan(q); + * ``` + */ + template + friend Quat atan(const Quat &q); + + /** + * @brief return arctan value of this quaternion, arctan could be calculated as: + * \f[\arctan(q) = -\frac{\boldsymbol{v}}{||\boldsymbol{v}||}arctanh(q\frac{\boldsymbol{v}}{||\boldsymbol{v}||})\f] + * where \f$\boldsymbol{v} = [x, y, z].\f$ + * + * For example + * ``` + * Quatd q(1,2,3,4); + * q.atan(); + * ``` + */ + Quat<_Tp> atan() const; + + /** + * @brief return arcsinh value of quaternion q, arcsinh could be calculated as: + * \f[arcsinh(q) = \ln(q + \sqrt{q^2 + 1})\f]. + * @param q a quaternion. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * asinh(q); + * ``` + */ + template + friend Quat asinh(const Quat &q); + + /** + * @brief return arcsinh value of this quaternion, arcsinh could be calculated as: + * \f[arcsinh(q) = \ln(q + \sqrt{q^2 + 1})\f]. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * q.asinh(); + * ``` + */ + Quat<_Tp> asinh() const; + + /** + * @brief return arccosh value of quaternion q, arccosh could be calculated as: + * \f[arccosh(q) = \ln(q + \sqrt{q^2 - 1})\f]. + * @param q a quaternion. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * acosh(q); + * ``` + */ + template + friend Quat acosh(const Quat &q); + + /** + * @brief return arccosh value of this quaternion, arccosh could be calculated as: + * \f[arcosh(q) = \ln(q + \sqrt{q^2 - 1})\f]. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * q.acosh(); + * ``` + */ + Quat<_Tp> acosh() const; + + /** + * @brief return arctanh value of quaternion q, arctanh could be calculated as: + * \f[arctanh(q) = \frac{\ln(q + 1) - \ln(1 - q)}{2}\f]. + * @param q a quaternion. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * atanh(q); + * ``` + */ + template + friend Quat atanh(const Quat &q); + + /** + * @brief return arctanh value of this quaternion, arctanh could be calculated as: + * \f[arcsinh(q) = \frac{\ln(q + 1) - \ln(1 - q)}{2}\f]. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * q.atanh(); + * ``` + */ + Quat<_Tp> atanh() const; + + /** + * @brief return true if this quaternion is a unit quaternion. + * @param eps tolerance scope of normalization. The eps could be defined as + * + * \f[eps = |1 - dotValue|\f] where \f[dotValue = (this.w^2 + this.x^2 + this,y^2 + this.z^2).\f] + * And this function will consider it is normalized when the dotValue over a range \f$[1-eps, 1+eps]\f$. + */ + bool isNormal(_Tp eps=CV_QUAT_EPS) const; + + /** + * @brief to throw an error if this quaternion is not a unit quaternion. + * @param eps tolerance scope of normalization. + * @sa isNormal + */ + void assertNormal(_Tp eps=CV_QUAT_EPS) const; + + /** + * @brief transform a quaternion to a 3x3 rotation matrix. + * @param assumeUnit if QUAT_ASSUME_UNIT, this quaternion assume to be a unit quaternion and + * this function will save some computations. Otherwise, this function will normalize this + * quaternion at first then do the transformation. + * + * @note Matrix A which is to be rotated should have the form + * \f[\begin{bmatrix} + * x_0& x_1& x_2&...&x_n\\ + * y_0& y_1& y_2&...&y_n\\ + * z_0& z_1& z_2&...&z_n + * \end{bmatrix}\f] + * where the same subscript represents a point. The shape of A assume to be [3, n] + * The points matrix A can be rotated by toRotMat3x3() * A. + * The result has 3 rows and n columns too. + + * For example + * ``` + * double angle = CV_PI; + * Vec3d axis{0,0,1}; + * Quatd q_unit = Quatd::createFromAngleAxis(angle, axis); //quaternion could also be get by interpolation by two or more quaternions. + * + * //assume there is two points (1,0,0) and (1,0,1) to be rotated + * Mat pointsA = (Mat_(2, 3) << 1,0,0,1,0,1); + * //change the shape + * pointsA = pointsA.t(); + * // rotate 180 degrees around the z axis + * Mat new_point = q_unit.toRotMat3x3() * pointsA; + * // print two points + * cout << new_point << endl; + * ``` + */ + Matx<_Tp, 3, 3> toRotMat3x3(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const; + + /** + * @brief transform a quaternion to a 4x4 rotation matrix. + * @param assumeUnit if QUAT_ASSUME_UNIT, this quaternion assume to be a unit quaternion and + * this function will save some computations. Otherwise, this function will normalize this + * quaternion at first then do the transformation. + * + * The operations is similar as toRotMat3x3 + * except that the points matrix should have the form + * \f[\begin{bmatrix} + * x_0& x_1& x_2&...&x_n\\ + * y_0& y_1& y_2&...&y_n\\ + * z_0& z_1& z_2&...&z_n\\ + * 0&0&0&...&0 + * \end{bmatrix}\f] + * + * @sa toRotMat3x3 + */ + + Matx<_Tp, 4, 4> toRotMat4x4(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const; + + /** + * @brief transform the this quaternion to a Vec. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * q.toVec(); + * ``` + */ + Vec<_Tp, 4> toVec() const; + + /** + * @brief transform this quaternion to a Rotation vector. + * @param assumeUnit if QUAT_ASSUME_UNIT, this quaternion assume to be a unit quaternion and + * this function will save some computations. + * Rotation vector rVec is defined as: + * \f[ rVec = [\theta v_x, \theta v_y, \theta v_z]\f] + * where \f$\theta\f$ represents rotation angle, and \f$\boldsymbol{v}\f$ represents the normalized rotation axis. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * q.toRotVec(); + * + * QuatAssumeType assumeUnit = QUAT_ASSUME_UNIT; + * q.normalize().toRotVec(assumeUnit); //answer is same as q.toRotVec(). + * ``` + */ + Vec<_Tp, 3> toRotVec(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const; + + /** + * @brief get the angle of quaternion, it returns the rotation angle. + * @param assumeUnit if QUAT_ASSUME_UNIT, this quaternion assume to be a unit quaternion and + * this function will save some computations. + * \f[\psi = 2 *arccos(\frac{w}{||q||})\f] + * + * For example + * ``` + * Quatd q(1,2,3,4); + * q.getAngle(); + * + * QuatAssumeType assumeUnit = QUAT_ASSUME_UNIT; + * q.normalize().getAngle(assumeUnit);//same as q.getAngle(). + * ``` + * @note It always return the value between \f$[0, 2\pi]\f$. + */ + _Tp getAngle(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const; + + /** + * @brief get the axis of quaternion, it returns a vector of length 3. + * @param assumeUnit if QUAT_ASSUME_UNIT, this quaternion assume to be a unit quaternion and + * this function will save some computations. + * + * the unit axis \f$\boldsymbol{u}\f$ is defined by + * \f[\begin{equation} + * \begin{split} + * \boldsymbol{v} + * &= \boldsymbol{u} ||\boldsymbol{v}||\\ + * &= \boldsymbol{u}||q||sin(\frac{\theta}{2}) + * \end{split} + * \end{equation}\f] + * where \f$v=[x, y ,z]\f$ and \f$\theta\f$ represents rotation angle. + * + * + * For example + * ``` + * Quatd q(1,2,3,4); + * q.getAxis(); + * + * QuatAssumeType assumeUnit = QUAT_ASSUME_UNIT; + * q.normalize().getAxis(assumeUnit);//same as q.getAxis() + * ``` + */ + Vec<_Tp, 3> getAxis(QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT) const; + + /** + * @brief return the dot between quaternion \f$q\f$ and this quaternion. + * + * dot(p, q) is a good metric of how close the quaternions are. + * Indeed, consider the unit quaternion difference \f$p^{-1} * q\f$, its real part is dot(p, q). + * At the same time its real part is equal to \f$\cos(\beta/2)\f$ where \f$\beta\f$ is + * an angle of rotation between p and q, i.e., + * Therefore, the closer dot(p, q) to 1, + * the smaller rotation between them. + * \f[p \cdot q = p.w \cdot q.w + p.x \cdot q.x + p.y \cdot q.y + p.z \cdot q.z\f] + * @param q the other quaternion. + * + * For example + * ``` + * Quatd q(1,2,3,4); + * Quatd p(5,6,7,8); + * p.dot(q); + * ``` + */ + _Tp dot(Quat<_Tp> q) const; + + /** + * @brief To calculate the interpolation from \f$q_0\f$ to \f$q_1\f$ by Linear Interpolation(Nlerp) + * For two quaternions, this interpolation curve can be displayed as: + * \f[Lerp(q_0, q_1, t) = (1 - t)q_0 + tq_1.\f] + * Obviously, the lerp will interpolate along a straight line if we think of \f$q_0\f$ and \f$q_1\f$ as a vector + * in a two-dimensional space. When \f$t = 0\f$, it returns \f$q_0\f$ and when \f$t= 1\f$, it returns \f$q_1\f$. + * \f$t\f$ should to be ranged in \f$[0, 1]\f$ normally. + * @param q0 a quaternion used in linear interpolation. + * @param q1 a quaternion used in linear interpolation. + * @param t percent of vector \f$\overrightarrow{q_0q_1}\f$ over a range [0, 1]. + * @note it returns a non-unit quaternion. + */ + static Quat<_Tp> lerp(const Quat<_Tp> &q0, const Quat &q1, const _Tp t); + + /** + * @brief To calculate the interpolation from \f$q_0\f$ to \f$q_1\f$ by Normalized Linear Interpolation(Nlerp). + * it returns a normalized quaternion of Linear Interpolation(Lerp). + * \f[ Nlerp(q_0, q_1, t) = \frac{(1 - t)q_0 + tq_1}{||(1 - t)q_0 + tq_1||}.\f] + * The interpolation will always choose the shortest path but the constant speed is not guaranteed. + * @param q0 a quaternion used in normalized linear interpolation. + * @param q1 a quaternion used in normalized linear interpolation. + * @param t percent of vector \f$\overrightarrow{q_0q_1}\f$ over a range [0, 1]. + * @param assumeUnit if QUAT_ASSUME_UNIT, all input quaternions assume to be unit quaternion. Otherwise, all inputs + quaternion will be normalized inside the function. + * @sa lerp + */ + static Quat<_Tp> nlerp(const Quat<_Tp> &q0, const Quat &q1, const _Tp t, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT); + + /** + @brief To calculate the interpolation between \f$q_0\f$ and \f$q_1\f$ by Spherical Linear + Interpolation(Slerp), which can be defined as: + \f[ Slerp(q_0, q_1, t) = \frac{\sin((1-t)\theta)}{\sin(\theta)}q_0 + \frac{\sin(t\theta)}{\sin(\theta)}q_1\f] + where \f$\theta\f$ can be calculated as: + \f[\theta=cos^{-1}(q_0\cdot q_1)\f] + resulting from the both of their norm is unit. + @param q0 a quaternion used in Slerp. + @param q1 a quaternion used in Slerp. + @param t percent of angle between \f$q_0\f$ and \f$q_1\f$ over a range [0, 1]. + @param assumeUnit if QUAT_ASSUME_UNIT, all input quaternions assume to be unit quaternions. Otherwise, all input + quaternions will be normalized inside the function. + @param directChange if QUAT_ASSUME_UNIT, the interpolation will choose the nearest path. + @note If the interpolation angle is small, the error between Nlerp and Slerp is not so large. To improve efficiency and + avoid zero division error, we use Nlerp instead of Slerp. + */ + static Quat<_Tp> slerp(const Quat<_Tp> &q0, const Quat &q1, const _Tp t, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT, bool directChange=true); + + /** + * @brief To calculate the interpolation between \f$q_0\f$,\f$q_1\f$,\f$q_2\f$,\f$q_3\f$ by Spherical and quadrangle(Squad). This could be defined as: + * \f[Squad(q_i, s_i, s_{i+1}, q_{i+1}, t) = Slerp(Slerp(q_i, q_{i+1}, t), Slerp(s_i, s_{i+1}, t), 2t(1-t))\f] + * where + * \f[s_i = q_i\exp(-\frac{\log(q^*_iq_{i+1}) + \log(q^*_iq_{i-1})}{4})\f] + * + * The Squad expression is analogous to the \f$B\acute{e}zier\f$ curve, but involves spherical linear + * interpolation instead of simple linear interpolation. Each \f$s_i\f$ needs to be calculated by three + * quaternions. + * + * @param q0 the first quaternion. + * @param s0 the second quaternion. + * @param s1 the third quaternion. + * @param q1 thr fourth quaternion. + * @param t interpolation parameter of quadratic and linear interpolation over a range \f$[0, 1]\f$. + * @param assumeUnit if QUAT_ASSUME_UNIT, all input quaternions assume to be unit quaternion. Otherwise, all input + * quaternions will be normalized inside the function. + * @param directChange if QUAT_ASSUME_UNIT, squad will find the nearest path to interpolate. + * @sa interPoint, spline + */ + static Quat<_Tp> squad(const Quat<_Tp> &q0, const Quat<_Tp> &s0, + const Quat<_Tp> &s1, const Quat<_Tp> &q1, + const _Tp t, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT, + bool directChange=true); + + /** + * @brief This is the part calculation of squad. + * To calculate the intermedia quaternion \f$s_i\f$ between each three quaternion + * \f[s_i = q_i\exp(-\frac{\log(q^*_iq_{i+1}) + \log(q^*_iq_{i-1})}{4}).\f] + * @param q0 the first quaternion. + * @param q1 the second quaternion. + * @param q2 the third quaternion. + * @param assumeUnit if QUAT_ASSUME_UNIT, all input quaternions assume to be unit quaternion. Otherwise, all input + * quaternions will be normalized inside the function. + * @sa squad + */ + static Quat<_Tp> interPoint(const Quat<_Tp> &q0, const Quat<_Tp> &q1, + const Quat<_Tp> &q2, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT); + + /** + * @brief to calculate a quaternion which is the result of a \f$C^1\f$ continuous + * spline curve constructed by squad at the ratio t. Here, the interpolation values are + * between \f$q_1\f$ and \f$q_2\f$. \f$q_0\f$ and \f$q_2\f$ are used to ensure the \f$C^1\f$ + * continuity. if t = 0, it returns \f$q_1\f$, if t = 1, it returns \f$q_2\f$. + * @param q0 the first input quaternion to ensure \f$C^1\f$ continuity. + * @param q1 the second input quaternion. + * @param q2 the third input quaternion. + * @param q3 the fourth input quaternion the same use of \f$q1\f$. + * @param t ratio over a range [0, 1]. + * @param assumeUnit if QUAT_ASSUME_UNIT, \f$q_0, q_1, q_2, q_3\f$ assume to be unit quaternion. Otherwise, all input + * quaternions will be normalized inside the function. + * + * For example: + * + * If there are three double quaternions \f$v_0, v_1, v_2\f$ waiting to be interpolated. + * + * Interpolation between \f$v_0\f$ and \f$v_1\f$ with a ratio \f$t_0\f$ could be calculated as + * ``` + * Quatd::spline(v0, v0, v1, v2, t0); + * ``` + * Interpolation between \f$v_1\f$ and \f$v_2\f$ with a ratio \f$t_0\f$ could be calculated as + * ``` + * Quatd::spline(v0, v1, v2, v2, t0); + * ``` + * @sa squad, slerp + */ + static Quat<_Tp> spline(const Quat<_Tp> &q0, const Quat<_Tp> &q1, + const Quat<_Tp> &q2, const Quat<_Tp> &q3, + const _Tp t, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT); + + /** + * @brief Return opposite quaternion \f$-p\f$ + * which satisfies \f$p + (-p) = 0.\f$ + * + * For example + * ``` + * Quatd q{1, 2, 3, 4}; + * std::cout << -q << std::endl; // [-1, -2, -3, -4] + * ``` + */ + Quat<_Tp> operator-() const; + + /** + * @brief return true if two quaternions p and q are nearly equal, i.e. when the absolute + * value of each \f$p_i\f$ and \f$q_i\f$ is less than CV_QUAT_EPS. + */ + bool operator==(const Quat<_Tp>&) const; + + /** + * @brief Addition operator of two quaternions p and q. + * It returns a new quaternion that each value is the sum of \f$p_i\f$ and \f$q_i\f$. + * + * For example + * ``` + * Quatd p{1, 2, 3, 4}; + * Quatd q{5, 6, 7, 8}; + * std::cout << p + q << std::endl; //[6, 8, 10, 12] + * ``` + */ + Quat<_Tp> operator+(const Quat<_Tp>&) const; + + /** + * @brief Addition assignment operator of two quaternions p and q. + * It adds right operand to the left operand and assign the result to left operand. + * + * For example + * ``` + * Quatd p{1, 2, 3, 4}; + * Quatd q{5, 6, 7, 8}; + * p += q; // equivalent to p = p + q + * std::cout << p << std::endl; //[6, 8, 10, 12] + * + * ``` + */ + Quat<_Tp>& operator+=(const Quat<_Tp>&); + + /** + * @brief Subtraction operator of two quaternions p and q. + * It returns a new quaternion that each value is the sum of \f$p_i\f$ and \f$-q_i\f$. + * + * For example + * ``` + * Quatd p{1, 2, 3, 4}; + * Quatd q{5, 6, 7, 8}; + * std::cout << p - q << std::endl; //[-4, -4, -4, -4] + * ``` + */ + Quat<_Tp> operator-(const Quat<_Tp>&) const; + + /** + * @brief Subtraction assignment operator of two quaternions p and q. + * It subtracts right operand from the left operand and assign the result to left operand. + * + * For example + * ``` + * Quatd p{1, 2, 3, 4}; + * Quatd q{5, 6, 7, 8}; + * p -= q; // equivalent to p = p - q + * std::cout << p << std::endl; //[-4, -4, -4, -4] + * + * ``` + */ + Quat<_Tp>& operator-=(const Quat<_Tp>&); + + /** + * @brief Multiplication assignment operator of two quaternions q and p. + * It multiplies right operand with the left operand and assign the result to left operand. + * + * Rule of quaternion multiplication: + * \f[ + * \begin{equation} + * \begin{split} + * p * q &= [p_0, \boldsymbol{u}]*[q_0, \boldsymbol{v}]\\ + * &=[p_0q_0 - \boldsymbol{u}\cdot \boldsymbol{v}, p_0\boldsymbol{v} + q_0\boldsymbol{u}+ \boldsymbol{u}\times \boldsymbol{v}]. + * \end{split} + * \end{equation} + * \f] + * where \f$\cdot\f$ means dot product and \f$\times \f$ means cross product. + * + * For example + * ``` + * Quatd p{1, 2, 3, 4}; + * Quatd q{5, 6, 7, 8}; + * p *= q; // equivalent to p = p * q + * std::cout << p << std::endl; //[-60, 12, 30, 24] + * ``` + */ + Quat<_Tp>& operator*=(const Quat<_Tp>&); + + /** + * @brief Multiplication assignment operator of a quaternions and a scalar. + * It multiplies right operand with the left operand and assign the result to left operand. + * + * Rule of quaternion multiplication with a scalar: + * \f[ + * \begin{equation} + * \begin{split} + * p * s &= [w, x, y, z] * s\\ + * &=[w * s, x * s, y * s, z * s]. + * \end{split} + * \end{equation} + * \f] + * + * For example + * ``` + * Quatd p{1, 2, 3, 4}; + * double s = 2.0; + * p *= s; // equivalent to p = p * s + * std::cout << p << std::endl; //[2.0, 4.0, 6.0, 8.0] + * ``` + * @note the type of scalar should be equal to the quaternion. + */ + Quat<_Tp>& operator*=(const _Tp s); + + /** + * @brief Multiplication operator of two quaternions q and p. + * Multiplies values on either side of the operator. + * + * Rule of quaternion multiplication: + * \f[ + * \begin{equation} + * \begin{split} + * p * q &= [p_0, \boldsymbol{u}]*[q_0, \boldsymbol{v}]\\ + * &=[p_0q_0 - \boldsymbol{u}\cdot \boldsymbol{v}, p_0\boldsymbol{v} + q_0\boldsymbol{u}+ \boldsymbol{u}\times \boldsymbol{v}]. + * \end{split} + * \end{equation} + * \f] + * where \f$\cdot\f$ means dot product and \f$\times \f$ means cross product. + * + * For example + * ``` + * Quatd p{1, 2, 3, 4}; + * Quatd q{5, 6, 7, 8}; + * std::cout << p * q << std::endl; //[-60, 12, 30, 24] + * ``` + */ + Quat<_Tp> operator*(const Quat<_Tp>&) const; + + /** + * @brief Division operator of a quaternions and a scalar. + * It divides left operand with the right operand and assign the result to left operand. + * + * Rule of quaternion division with a scalar: + * \f[ + * \begin{equation} + * \begin{split} + * p / s &= [w, x, y, z] / s\\ + * &=[w/s, x/s, y/s, z/s]. + * \end{split} + * \end{equation} + * \f] + * + * For example + * ``` + * Quatd p{1, 2, 3, 4}; + * double s = 2.0; + * p /= s; // equivalent to p = p / s + * std::cout << p << std::endl; //[0.5, 1, 1.5, 2] + * ``` + * @note the type of scalar should be equal to this quaternion. + */ + Quat<_Tp> operator/(const _Tp s) const; + + /** + * @brief Division operator of two quaternions p and q. + * Divides left hand operand by right hand operand. + * + * Rule of quaternion division with a scalar: + * \f[ + * \begin{equation} + * \begin{split} + * p / q &= p * q.inv()\\ + * \end{split} + * \end{equation} + * \f] + * + * For example + * ``` + * Quatd p{1, 2, 3, 4}; + * Quatd q{5, 6, 7, 8}; + * std::cout << p / q << std::endl; // equivalent to p * q.inv() + * ``` + */ + Quat<_Tp> operator/(const Quat<_Tp>&) const; + + /** + * @brief Division assignment operator of a quaternions and a scalar. + * It divides left operand with the right operand and assign the result to left operand. + * + * Rule of quaternion division with a scalar: + * \f[ + * \begin{equation} + * \begin{split} + * p / s &= [w, x, y, z] / s\\ + * &=[w / s, x / s, y / s, z / s]. + * \end{split} + * \end{equation} + * \f] + * + * For example + * ``` + * Quatd p{1, 2, 3, 4}; + * double s = 2.0;; + * p /= s; // equivalent to p = p / s + * std::cout << p << std::endl; //[0.5, 1.0, 1.5, 2.0] + * ``` + * @note the type of scalar should be equal to the quaternion. + */ + Quat<_Tp>& operator/=(const _Tp s); + + /** + * @brief Division assignment operator of two quaternions p and q; + * It divides left operand with the right operand and assign the result to left operand. + * + * Rule of quaternion division with a quaternion: + * \f[ + * \begin{equation} + * \begin{split} + * p / q&= p * q.inv()\\ + * \end{split} + * \end{equation} + * \f] + * + * For example + * ``` + * Quatd p{1, 2, 3, 4}; + * Quatd q{5, 6, 7, 8}; + * p /= q; // equivalent to p = p * q.inv() + * std::cout << p << std::endl; + * ``` + */ + Quat<_Tp>& operator/=(const Quat<_Tp>&); + + _Tp& operator[](std::size_t n); + + const _Tp& operator[](std::size_t n) const; + + /** + * @brief Subtraction operator of a scalar and a quaternions. + * Subtracts right hand operand from left hand operand. + * + * For example + * ``` + * Quatd p{1, 2, 3, 4}; + * double scalar = 2.0; + * std::cout << scalar - p << std::endl; //[1.0, -2, -3, -4] + * ``` + * @note the type of scalar should be equal to the quaternion. + */ + template + friend Quat cv::operator-(const T s, const Quat&); + + /** + * @brief Subtraction operator of a quaternions and a scalar. + * Subtracts right hand operand from left hand operand. + * + * For example + * ``` + * Quatd p{1, 2, 3, 4}; + * double scalar = 2.0; + * std::cout << p - scalar << std::endl; //[-1.0, 2, 3, 4] + * ``` + * @note the type of scalar should be equal to the quaternion. + */ + template + friend Quat cv::operator-(const Quat&, const T s); + + /** + * @brief Addition operator of a quaternions and a scalar. + * Adds right hand operand from left hand operand. + * + * For example + * ``` + * Quatd p{1, 2, 3, 4}; + * double scalar = 2.0; + * std::cout << scalar + p << std::endl; //[3.0, 2, 3, 4] + * ``` + * @note the type of scalar should be equal to the quaternion. + */ + template + friend Quat cv::operator+(const T s, const Quat&); + + /** + * @brief Addition operator of a quaternions and a scalar. + * Adds right hand operand from left hand operand. + * + * For example + * ``` + * Quatd p{1, 2, 3, 4}; + * double scalar = 2.0; + * std::cout << p + scalar << std::endl; //[3.0, 2, 3, 4] + * ``` + * @note the type of scalar should be equal to the quaternion. + */ + template + friend Quat cv::operator+(const Quat&, const T s); + + /** + * @brief Multiplication operator of a scalar and a quaternions. + * It multiplies right operand with the left operand and assign the result to left operand. + * + * Rule of quaternion multiplication with a scalar: + * \f[ + * \begin{equation} + * \begin{split} + * p * s &= [w, x, y, z] * s\\ + * &=[w * s, x * s, y * s, z * s]. + * \end{split} + * \end{equation} + * \f] + * + * For example + * ``` + * Quatd p{1, 2, 3, 4}; + * double s = 2.0; + * std::cout << s * p << std::endl; //[2.0, 4.0, 6.0, 8.0] + * ``` + * @note the type of scalar should be equal to the quaternion. + */ + template + friend Quat cv::operator*(const T s, const Quat&); + + /** + * @brief Multiplication operator of a quaternion and a scalar. + * It multiplies right operand with the left operand and assign the result to left operand. + * + * Rule of quaternion multiplication with a scalar: + * \f[ + * \begin{equation} + * \begin{split} + * p * s &= [w, x, y, z] * s\\ + * &=[w * s, x * s, y * s, z * s]. + * \end{split} + * \end{equation} + * \f] + * + * For example + * ``` + * Quatd p{1, 2, 3, 4}; + * double s = 2.0; + * std::cout << p * s << std::endl; //[2.0, 4.0, 6.0, 8.0] + * ``` + * @note the type of scalar should be equal to the quaternion. + */ + template + friend Quat cv::operator*(const Quat&, const T s); + + template + friend std::ostream& cv::operator<<(std::ostream&, const Quat&); + + /** + * @brief Transform a quaternion q to Euler angles. + * + * + * When transforming a quaternion \f$q = w + x\boldsymbol{i} + y\boldsymbol{j} + z\boldsymbol{k}\f$ to Euler angles, rotation matrix M can be calculated by: + * \f[ \begin{aligned} {M} &={\begin{bmatrix}1-2(y^{2}+z^{2})&2(xy-zx)&2(xz+yw)\\2(xy+zw)&1-2(x^{2}+z^{2})&2(yz-xw)\\2(xz-yw)&2(yz+xw)&1-2(x^{2}+y^{2})\end{bmatrix}}\end{aligned}.\f] + * On the other hand, the rotation matrix can be obtained from Euler angles. + * Using intrinsic rotations with Euler angles type XYZ as an example, + * \f$\theta_1 \f$, \f$\theta_2 \f$, \f$\theta_3 \f$ are three angles for Euler angles, the rotation matrix R can be calculated by:\f[R =X(\theta_1)Y(\theta_2)Z(\theta_3) + * ={\begin{bmatrix}\cos\theta_{2}\cos\theta_{3}&-\cos\theta_{2}\sin\theta_{3}&\sin\theta_{2}\\\cos\theta_{1}\sin\theta_{3}+\cos\theta_{3}\sin\theta_{1}\sin\theta_{2}&\cos\theta_{1}\cos\theta_{3}-\sin\theta_{1}\sin\theta_{2}\sin\theta_{3}&-\cos\theta_{2}\sin\theta_{1}\\\sin\theta_{1}\sin\theta_{3}-\cos\theta_{1}\cos\theta_{3}\sin\theta_{2}&\cos\theta_{3}\sin\theta_{1}+\cos\theta_{1}\sin\theta_{2}\sin\theta_{3}&\cos\theta_{1}\cos_{2}\end{bmatrix}}\f] + * Rotation matrix M and R are equal. As long as \f$ s_{2} \neq 1 \f$, by comparing each element of two matrices ,the solution is\f$\begin{cases} \theta_1 = \arctan2(-m_{23},m_{33})\\\theta_2 = arcsin(m_{13}) \\\theta_3 = \arctan2(-m_{12},m_{11}) \end{cases}\f$. + * + * When \f$ s_{2}=1\f$ or \f$ s_{2}=-1\f$, the gimbal lock occurs. The function will prompt "WARNING: Gimbal Lock will occur. Euler angles is non-unique. For intrinsic rotations, we set the third angle to 0, and for external rotation, we set the first angle to 0.". + * + * When \f$ s_{2}=1\f$ , + * The rotation matrix R is \f$R = {\begin{bmatrix}0&0&1\\\sin(\theta_1+\theta_3)&\cos(\theta_1+\theta_3)&0\\-\cos(\theta_1+\theta_3)&\sin(\theta_1+\theta_3)&0\end{bmatrix}}\f$. + * + * The number of solutions is infinite with the condition \f$\begin{cases} \theta_1+\theta_3 = \arctan2(m_{21},m_{22})\\ \theta_2=\pi/2 \end{cases}\ \f$. + * + * We set \f$ \theta_3 = 0\f$, the solution is \f$\begin{cases} \theta_1=\arctan2(m_{21},m_{22})\\ \theta_2=\pi/2\\ \theta_3=0 \end{cases}\f$. + * + * When \f$ s_{2}=-1\f$, + * The rotation matrix R is \f$X_{1}Y_{2}Z_{3}={\begin{bmatrix}0&0&-1\\-\sin(\theta_1-\theta_3)&\cos(\theta_1-\theta_3)&0\\\cos(\theta_1-\theta_3)&\sin(\theta_1-\theta_3)&0\end{bmatrix}}\f$. + * + * The number of solutions is infinite with the condition \f$\begin{cases} \theta_1+\theta_3 = \arctan2(m_{32},m_{22})\\ \theta_2=\pi/2 \end{cases}\ \f$. + * + * We set \f$ \theta_3 = 0\f$, the solution is \f$ \begin{cases}\theta_1=\arctan2(m_{32},m_{22}) \\ \theta_2=-\pi/2\\ \theta_3=0\end{cases}\f$. + * + * Since \f$ sin \theta\in [-1,1] \f$ and \f$ cos \theta \in [-1,1] \f$, the unnormalized quaternion will cause computational troubles. For this reason, this function will normalize the quaternion at first and @ref QuatAssumeType is not needed. + * + * When the gimbal lock occurs, we set \f$\theta_3 = 0\f$ for intrinsic rotations or \f$\theta_1 = 0\f$ for extrinsic rotations. + * + * As a result, for every Euler angles type, we can get solution as shown in the following table. + * EulerAnglesType | Ordinary | \f$\theta_2 = π/2\f$ | \f$\theta_2 = -π/2\f$ + * ------------- | -------------| -------------| ------------- + * INT_XYZ|\f$ \theta_1 = \arctan2(-m_{23},m_{33})\\\theta_2 = \arcsin(m_{13}) \\\theta_3= \arctan2(-m_{12},m_{11}) \f$|\f$ \theta_1=\arctan2(m_{21},m_{22})\\ \theta_2=\pi/2\\ \theta_3=0 \f$|\f$ \theta_1=\arctan2(m_{32},m_{22})\\ \theta_2=-\pi/2\\ \theta_3=0 \f$ + * INT_XZY|\f$ \theta_1 = \arctan2(m_{32},m_{22})\\\theta_2 = -\arcsin(m_{12}) \\\theta_3= \arctan2(m_{13},m_{11}) \f$|\f$ \theta_1=\arctan2(m_{31},m_{33})\\ \theta_2=\pi/2\\ \theta_3=0 \f$|\f$ \theta_1=\arctan2(-m_{23},m_{33})\\ \theta_2=-\pi/2\\ \theta_3=0 \f$ + * INT_YXZ|\f$ \theta_1 = \arctan2(m_{13},m_{33})\\\theta_2 = -\arcsin(m_{23}) \\\theta_3= \arctan2(m_{21},m_{22}) \f$|\f$ \theta_1=\arctan2(m_{12},m_{11})\\ \theta_2=\pi/2\\ \theta_3=0 \f$|\f$ \theta_1=\arctan2(-m_{12},m_{11})\\ \theta_2=-\pi/2\\ \theta_3=0 \f$ + * INT_YZX|\f$ \theta_1 = \arctan2(-m_{31},m_{11})\\\theta_2 = \arcsin(m_{21}) \\\theta_3= \arctan2(-m_{23},m_{22}) \f$|\f$ \theta_1=\arctan2(m_{13},m_{33})\\ \theta_2=\pi/2\\ \theta_3=0 \f$|\f$ \theta_1=\arctan2(m_{13},m_{12})\\ \theta_2=-\pi/2\\ \theta_3=0 \f$ + * INT_ZXY|\f$ \theta_1 = \arctan2(-m_{12},m_{22})\\\theta_2 = \arcsin(m_{32}) \\\theta_3= \arctan2(-m_{31},m_{33}) \f$|\f$ \theta_1=\arctan2(m_{21},m_{11})\\ \theta_2=\pi/2\\ \theta_3=0 \f$|\f$ \theta_1=\arctan2(m_{21},m_{11})\\ \theta_2=-\pi/2\\ \theta_3=0 \f$ + * INT_ZYX|\f$ \theta_1 = \arctan2(m_{21},m_{11})\\\theta_2 = \arcsin(-m_{31}) \\\theta_3= \arctan2(m_{32},m_{33}) \f$|\f$ \theta_1=\arctan2(m_{23},m_{22})\\ \theta_2=\pi/2\\ \theta_3=0 \f$|\f$ \theta_1=\arctan2(-m_{12},m_{22})\\ \theta_2=-\pi/2\\ \theta_3=0 \f$ + * EXT_XYZ|\f$ \theta_1 = \arctan2(m_{32},m_{33})\\\theta_2 = \arcsin(-m_{31}) \\\ \theta_3 = \arctan2(m_{21},m_{11})\f$|\f$ \theta_1= 0\\ \theta_2=\pi/2\\ \theta_3=\arctan2(m_{23},m_{22}) \f$|\f$ \theta_1=0\\ \theta_2=-\pi/2\\ \theta_3=\arctan2(-m_{12},m_{22}) \f$ + * EXT_XZY|\f$ \theta_1 = \arctan2(-m_{23},m_{22})\\\theta_2 = \arcsin(m_{21}) \\\theta_3= \arctan2(-m_{31},m_{11})\f$|\f$ \theta_1= 0\\ \theta_2=\pi/2\\ \theta_3=\arctan2(m_{13},m_{33}) \f$|\f$ \theta_1=0\\ \theta_2=-\pi/2\\ \theta_3=\arctan2(m_{13},m_{12}) \f$ + * EXT_YXZ|\f$ \theta_1 = \arctan2(-m_{31},m_{33}) \\\theta_2 = \arcsin(m_{32}) \\\theta_3= \arctan2(-m_{12},m_{22})\f$|\f$ \theta_1= 0\\ \theta_2=\pi/2\\ \theta_3=\arctan2(m_{21},m_{11}) \f$|\f$ \theta_1=0\\ \theta_2=-\pi/2\\ \theta_3=\arctan2(m_{21},m_{11}) \f$ + * EXT_YZX|\f$ \theta_1 = \arctan2(m_{13},m_{11})\\\theta_2 = -\arcsin(m_{12}) \\\theta_3= \arctan2(m_{32},m_{22})\f$|\f$ \theta_1= 0\\ \theta_2=\pi/2\\ \theta_3=\arctan2(m_{31},m_{33}) \f$|\f$ \theta_1=0\\ \theta_2=-\pi/2\\ \theta_3=\arctan2(-m_{23},m_{33}) \f$ + * EXT_ZXY|\f$ \theta_1 = \arctan2(m_{21},m_{22})\\\theta_2 = -\arcsin(m_{23}) \\\theta_3= \arctan2(m_{13},m_{33})\f$|\f$ \theta_1= 0\\ \theta_2=\pi/2\\ \theta_3=\arctan2(m_{12},m_{11}) \f$|\f$ \theta_1= 0\\ \theta_2=-\pi/2\\ \theta_3=\arctan2(-m_{12},m_{11}) \f$ + * EXT_ZYX|\f$ \theta_1 = \arctan2(-m_{12},m_{11})\\\theta_2 = \arcsin(m_{13}) \\\theta_3= \arctan2(-m_{23},m_{33})\f$|\f$ \theta_1=0\\ \theta_2=\pi/2\\ \theta_3=\arctan2(m_{21},m_{22}) \f$|\f$ \theta_1=0\\ \theta_2=-\pi/2\\ \theta_3=\arctan2(m_{32},m_{22}) \f$ + * + * EulerAnglesType | Ordinary | \f$\theta_2 = 0\f$ | \f$\theta_2 = π\f$ + * ------------- | -------------| -------------| ------------- + * INT_XYX| \f$ \theta_1 = \arctan2(m_{21},-m_{31})\\\theta_2 =\arccos(m_{11}) \\\theta_3 = \arctan2(m_{12},m_{13}) \f$| \f$ \theta_1=\arctan2(m_{32},m_{33})\\ \theta_2=0\\ \theta_3=0 \f$| \f$ \theta_1=\arctan2(m_{23},m_{22})\\ \theta_2=\pi\\ \theta_3=0 \f$ + * INT_XZX| \f$ \theta_1 = \arctan2(m_{31},m_{21})\\\theta_2 = \arccos(m_{11}) \\\theta_3 = \arctan2(m_{13},-m_{12}) \f$| \f$ \theta_1=\arctan2(m_{32},m_{33})\\ \theta_2=0\\ \theta_3=0 \f$| \f$ \theta_1=\arctan2(-m_{32},m_{33})\\ \theta_2=\pi\\ \theta_3=0 \f$ + * INT_YXY| \f$ \theta_1 = \arctan2(m_{12},m_{32})\\\theta_2 = \arccos(m_{22}) \\\theta_3 = \arctan2(m_{21},-m_{23}) \f$| \f$ \theta_1=\arctan2(m_{13},m_{11})\\ \theta_2=0\\ \theta_3=0 \f$| \f$ \theta_1=\arctan2(-m_{31},m_{11})\\ \theta_2=\pi\\ \theta_3=0 \f$ + * INT_YZY| \f$ \theta_1 = \arctan2(m_{32},-m_{12})\\\theta_2 = \arccos(m_{22}) \\\theta_3 =\arctan2(m_{23},m_{21}) \f$| \f$ \theta_1=\arctan2(m_{13},m_{11})\\ \theta_2=0\\ \theta_3=0 \f$| \f$ \theta_1=\arctan2(m_{13},-m_{11})\\ \theta_2=\pi\\ \theta_3=0 \f$ + * INT_ZXZ| \f$ \theta_1 = \arctan2(-m_{13},m_{23})\\\theta_2 = \arccos(m_{33}) \\\theta_3 =\arctan2(m_{31},m_{32}) \f$| \f$ \theta_1=\arctan2(m_{21},m_{22})\\ \theta_2=0\\ \theta_3=0 \f$| \f$ \theta_1=\arctan2(m_{21},m_{11})\\ \theta_2=\pi\\ \theta_3=0 \f$ + * INT_ZYZ| \f$ \theta_1 = \arctan2(m_{23},m_{13})\\\theta_2 = \arccos(m_{33}) \\\theta_3 = \arctan2(m_{32},-m_{31}) \f$| \f$ \theta_1=\arctan2(m_{21},m_{11})\\ \theta_2=0\\ \theta_3=0 \f$| \f$ \theta_1=\arctan2(m_{21},m_{11})\\ \theta_2=\pi\\ \theta_3=0 \f$ + * EXT_XYX| \f$ \theta_1 = \arctan2(m_{12},m_{13}) \\\theta_2 = \arccos(m_{11}) \\\theta_3 = \arctan2(m_{21},-m_{31})\f$| \f$ \theta_1=0\\ \theta_2=0\\ \theta_3=\arctan2(m_{32},m_{33}) \f$| \f$ \theta_1= 0\\ \theta_2=\pi\\ \theta_3= \arctan2(m_{23},m_{22}) \f$ + * EXT_XZX| \f$ \theta_1 = \arctan2(m_{13},-m_{12})\\\theta_2 = \arccos(m_{11}) \\\theta_3 = \arctan2(m_{31},m_{21})\f$| \f$ \theta_1= 0\\ \theta_2=0\\ \theta_3=\arctan2(m_{32},m_{33}) \f$| \f$ \theta_1= 0\\ \theta_2=\pi\\ \theta_3=\arctan2(-m_{32},m_{33}) \f$ + * EXT_YXY| \f$ \theta_1 = \arctan2(m_{21},-m_{23})\\\theta_2 = \arccos(m_{22}) \\\theta_3 = \arctan2(m_{12},m_{32}) \f$| \f$ \theta_1= 0\\ \theta_2=0\\ \theta_3=\arctan2(m_{13},m_{11}) \f$| \f$ \theta_1= 0\\ \theta_2=\pi\\ \theta_3=\arctan2(-m_{31},m_{11}) \f$ + * EXT_YZY| \f$ \theta_1 = \arctan2(m_{23},m_{21}) \\\theta_2 = \arccos(m_{22}) \\\theta_3 = \arctan2(m_{32},-m_{12}) \f$| \f$ \theta_1= 0\\ \theta_2=0\\ \theta_3=\arctan2(m_{13},m_{11}) \f$| \f$ \theta_1=0\\ \theta_2=\pi\\ \theta_3=\arctan2(m_{13},-m_{11}) \f$ + * EXT_ZXZ| \f$ \theta_1 = \arctan2(m_{31},m_{32}) \\\theta_2 = \arccos(m_{33}) \\\theta_3 = \arctan2(-m_{13},m_{23})\f$| \f$ \theta_1=0\\ \theta_2=0\\ \theta_3=\arctan2(m_{21},m_{22}) \f$| \f$ \theta_1= 0\\ \theta_2=\pi\\ \theta_3=\arctan2(m_{21},m_{11}) \f$ + * EXT_ZYZ| \f$ \theta_1 = \arctan2(m_{32},-m_{31})\\\theta_2 = \arccos(m_{33}) \\\theta_3 = \arctan2(m_{23},m_{13}) \f$| \f$ \theta_1=0\\ \theta_2=0\\ \theta_3=\arctan2(m_{21},m_{11}) \f$| \f$ \theta_1= 0\\ \theta_2=\pi\\ \theta_3=\arctan2(m_{21},m_{11}) \f$ + * + * @param eulerAnglesType the convertion Euler angles type + */ + + Vec<_Tp, 3> toEulerAngles(QuatEnum::EulerAnglesType eulerAnglesType); + + _Tp w, x, y, z; + +}; + +template +Quat inv(const Quat &q, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT); + +template +Quat sinh(const Quat &q); + +template +Quat cosh(const Quat &q); + +template +Quat tanh(const Quat &q); + +template +Quat sin(const Quat &q); + +template +Quat cos(const Quat &q); + +template +Quat tan(const Quat &q); + +template +Quat asinh(const Quat &q); + +template +Quat acosh(const Quat &q); + +template +Quat atanh(const Quat &q); + +template +Quat asin(const Quat &q); + +template +Quat acos(const Quat &q); + +template +Quat atan(const Quat &q); + +template +Quat power(const Quat &q, const Quat &p, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT); + +template +Quat exp(const Quat &q); + +template +Quat log(const Quat &q, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT); + +template +Quat power(const Quat& q, const T x, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT); + +template +Quat crossProduct(const Quat &p, const Quat &q); + +template +Quat sqrt(const Quat &q, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT); + +template +Quat operator*(const T, const Quat&); + +template +Quat operator*(const Quat&, const T); + +template +std::ostream& operator<<(std::ostream&, const Quat&); + +using Quatd = Quat; +using Quatf = Quat; + +//! @} core +} + +#include "opencv2/core/quaternion.inl.hpp" + +#endif /* OPENCV_CORE_QUATERNION_HPP */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/quaternion.inl.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/quaternion.inl.hpp new file mode 100644 index 0000000..29a16d9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/quaternion.inl.hpp @@ -0,0 +1,1063 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2020, Huawei Technologies Co., Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Liangqian Kong +// Longbu Wang + +#ifndef OPENCV_CORE_QUATERNION_INL_HPP +#define OPENCV_CORE_QUATERNION_INL_HPP + +#ifndef OPENCV_CORE_QUATERNION_HPP +#erorr This is not a standalone header. Include quaternion.hpp instead. +#endif + +//@cond IGNORE +/////////////////////////////////////////////////////////////////////////////////////// +//Implementation +namespace cv { + +template +Quat::Quat() : w(0), x(0), y(0), z(0) {} + +template +Quat::Quat(const Vec &coeff):w(coeff[0]), x(coeff[1]), y(coeff[2]), z(coeff[3]){} + +template +Quat::Quat(const T qw, const T qx, const T qy, const T qz):w(qw), x(qx), y(qy), z(qz){} + +template +Quat Quat::createFromAngleAxis(const T angle, const Vec &axis) +{ + T w, x, y, z; + T vNorm = std::sqrt(axis.dot(axis)); + if (vNorm < CV_QUAT_EPS) + { + CV_Error(Error::StsBadArg, "this quaternion does not represent a rotation"); + } + const T angle_half = angle * T(0.5); + w = std::cos(angle_half); + const T sin_v = std::sin(angle_half); + const T sin_norm = sin_v / vNorm; + x = sin_norm * axis[0]; + y = sin_norm * axis[1]; + z = sin_norm * axis[2]; + return Quat(w, x, y, z); +} + +template +Quat Quat::createFromRotMat(InputArray _R) +{ + CV_CheckTypeEQ(_R.type(), cv::traits::Type::value, ""); + if (_R.rows() != 3 || _R.cols() != 3) + { + CV_Error(Error::StsBadArg, "Cannot convert matrix to quaternion: rotation matrix should be a 3x3 matrix"); + } + Matx R; + _R.copyTo(R); + + T S, w, x, y, z; + T trace = R(0, 0) + R(1, 1) + R(2, 2); + if (trace > 0) + { + S = std::sqrt(trace + 1) * T(2); + x = (R(1, 2) - R(2, 1)) / S; + y = (R(2, 0) - R(0, 2)) / S; + z = (R(0, 1) - R(1, 0)) / S; + w = -T(0.25) * S; + } + else if (R(0, 0) > R(1, 1) && R(0, 0) > R(2, 2)) + { + + S = std::sqrt(T(1.0) + R(0, 0) - R(1, 1) - R(2, 2)) * T(2); + x = -T(0.25) * S; + y = -(R(1, 0) + R(0, 1)) / S; + z = -(R(0, 2) + R(2, 0)) / S; + w = (R(1, 2) - R(2, 1)) / S; + } + else if (R(1, 1) > R(2, 2)) + { + S = std::sqrt(T(1.0) - R(0, 0) + R(1, 1) - R(2, 2)) * T(2); + x = (R(0, 1) + R(1, 0)) / S; + y = T(0.25) * S; + z = (R(1, 2) + R(2, 1)) / S; + w = (R(0, 2) - R(2, 0)) / S; + } + else + { + S = std::sqrt(T(1.0) - R(0, 0) - R(1, 1) + R(2, 2)) * T(2); + x = (R(0, 2) + R(2, 0)) / S; + y = (R(1, 2) + R(2, 1)) / S; + z = T(0.25) * S; + w = -(R(0, 1) - R(1, 0)) / S; + } + return Quat (w, x, y, z); +} + +template +Quat Quat::createFromRvec(InputArray _rvec) +{ + if (!((_rvec.cols() == 1 && _rvec.rows() == 3) || (_rvec.cols() == 3 && _rvec.rows() == 1))) { + CV_Error(Error::StsBadArg, "Cannot convert rotation vector to quaternion: The length of rotation vector should be 3"); + } + Vec rvec; + _rvec.copyTo(rvec); + T psi = std::sqrt(rvec.dot(rvec)); + if (abs(psi) < CV_QUAT_EPS) { + return Quat (1, 0, 0, 0); + } + Vec axis = rvec / psi; + return createFromAngleAxis(psi, axis); +} + +template +inline Quat Quat::operator-() const +{ + return Quat(-w, -x, -y, -z); +} + + +template +inline bool Quat::operator==(const Quat &q) const +{ + return (abs(w - q.w) < CV_QUAT_EPS && abs(x - q.x) < CV_QUAT_EPS && abs(y - q.y) < CV_QUAT_EPS && abs(z - q.z) < CV_QUAT_EPS); +} + +template +inline Quat Quat::operator+(const Quat &q1) const +{ + return Quat(w + q1.w, x + q1.x, y + q1.y, z + q1.z); +} + +template +inline Quat operator+(const T a, const Quat& q) +{ + return Quat(q.w + a, q.x, q.y, q.z); +} + +template +inline Quat operator+(const Quat& q, const T a) +{ + return Quat(q.w + a, q.x, q.y, q.z); +} + +template +inline Quat operator-(const T a, const Quat& q) +{ + return Quat(a - q.w, -q.x, -q.y, -q.z); +} + +template +inline Quat operator-(const Quat& q, const T a) +{ + return Quat(q.w - a, q.x, q.y, q.z); +} + +template +inline Quat Quat::operator-(const Quat &q1) const +{ + return Quat(w - q1.w, x - q1.x, y - q1.y, z - q1.z); +} + +template +inline Quat& Quat::operator+=(const Quat &q1) +{ + w += q1.w; + x += q1.x; + y += q1.y; + z += q1.z; + return *this; +} + +template +inline Quat& Quat::operator-=(const Quat &q1) +{ + w -= q1.w; + x -= q1.x; + y -= q1.y; + z -= q1.z; + return *this; +} + +template +inline Quat Quat::operator*(const Quat &q1) const +{ + Vec q{w, x, y, z}; + Vec q2{q1.w, q1.x, q1.y, q1.z}; + return Quat(q * q2); +} + + +template +Quat operator*(const Quat &q1, const T a) +{ + return Quat(a * q1.w, a * q1.x, a * q1.y, a * q1.z); +} + +template +Quat operator*(const T a, const Quat &q1) +{ + return Quat(a * q1.w, a * q1.x, a * q1.y, a * q1.z); +} + +template +inline Quat& Quat::operator*=(const Quat &q1) +{ + T qw, qx, qy, qz; + qw = w * q1.w - x * q1.x - y * q1.y - z * q1.z; + qx = x * q1.w + w * q1.x + y * q1.z - z * q1.y; + qy = y * q1.w + w * q1.y + z * q1.x - x * q1.z; + qz = z * q1.w + w * q1.z + x * q1.y - y * q1.x; + w = qw; + x = qx; + y = qy; + z = qz; + return *this; +} + +template +inline Quat& Quat::operator/=(const Quat &q1) +{ + Quat q(*this * q1.inv()); + w = q.w; + x = q.x; + y = q.y; + z = q.z; + return *this; +} +template +Quat& Quat::operator*=(const T q1) +{ + w *= q1; + x *= q1; + y *= q1; + z *= q1; + return *this; +} + +template +inline Quat& Quat::operator/=(const T a) +{ + const T a_inv = 1.0 / a; + w *= a_inv; + x *= a_inv; + y *= a_inv; + z *= a_inv; + return *this; +} + +template +inline Quat Quat::operator/(const T a) const +{ + const T a_inv = T(1.0) / a; + return Quat(w * a_inv, x * a_inv, y * a_inv, z * a_inv); +} + +template +inline Quat Quat::operator/(const Quat &q) const +{ + return *this * q.inv(); +} + +template +inline const T& Quat::operator[](std::size_t n) const +{ + switch (n) { + case 0: + return w; + case 1: + return x; + case 2: + return y; + case 3: + return z; + default: + CV_Error(Error::StsOutOfRange, "subscript exceeds the index range"); + } +} + +template +inline T& Quat::operator[](std::size_t n) +{ + switch (n) { + case 0: + return w; + case 1: + return x; + case 2: + return y; + case 3: + return z; + default: + CV_Error(Error::StsOutOfRange, "subscript exceeds the index range"); + } +} + +template +std::ostream & operator<<(std::ostream &os, const Quat &q) +{ + os << "Quat " << Vec{q.w, q.x, q.y, q.z}; + return os; +} + +template +inline T Quat::at(size_t index) const +{ + return (*this)[index]; +} + +template +inline Quat Quat::conjugate() const +{ + return Quat(w, -x, -y, -z); +} + +template +inline T Quat::norm() const +{ + return std::sqrt(dot(*this)); +} + +template +Quat exp(const Quat &q) +{ + return q.exp(); +} + +template +Quat Quat::exp() const +{ + Vec v{x, y, z}; + T normV = std::sqrt(v.dot(v)); + T k = normV < CV_QUAT_EPS ? 1 : std::sin(normV) / normV; + return std::exp(w) * Quat(std::cos(normV), v[0] * k, v[1] * k, v[2] * k); +} + +template +Quat log(const Quat &q, QuatAssumeType assumeUnit) +{ + return q.log(assumeUnit); +} + +template +Quat Quat::log(QuatAssumeType assumeUnit) const +{ + Vec v{x, y, z}; + T vNorm = std::sqrt(v.dot(v)); + if (assumeUnit) + { + T k = vNorm < CV_QUAT_EPS ? 1 : std::acos(w) / vNorm; + return Quat(0, v[0] * k, v[1] * k, v[2] * k); + } + T qNorm = norm(); + if (qNorm < CV_QUAT_EPS) + { + CV_Error(Error::StsBadArg, "Cannot apply this quaternion to log function: undefined"); + } + T k = vNorm < CV_QUAT_EPS ? 1 : std::acos(w / qNorm) / vNorm; + return Quat(std::log(qNorm), v[0] * k, v[1] * k, v[2] *k); +} + +template +inline Quat power(const Quat &q1, const T alpha, QuatAssumeType assumeUnit) +{ + return q1.power(alpha, assumeUnit); +} + +template +inline Quat Quat::power(const T alpha, QuatAssumeType assumeUnit) const +{ + if (x * x + y * y + z * z > CV_QUAT_EPS) + { + T angle = getAngle(assumeUnit); + Vec axis = getAxis(assumeUnit); + if (assumeUnit) + { + return createFromAngleAxis(alpha * angle, axis); + } + return std::pow(norm(), alpha) * createFromAngleAxis(alpha * angle, axis); + } + else + { + return std::pow(norm(), alpha) * Quat(w, x, y, z); + } +} + + +template +inline Quat sqrt(const Quat &q, QuatAssumeType assumeUnit) +{ + return q.sqrt(assumeUnit); +} + +template +inline Quat Quat::sqrt(QuatAssumeType assumeUnit) const +{ + return power(0.5, assumeUnit); +} + + +template +inline Quat power(const Quat &p, const Quat &q, QuatAssumeType assumeUnit) +{ + return p.power(q, assumeUnit); +} + + +template +inline Quat Quat::power(const Quat &q, QuatAssumeType assumeUnit) const +{ + return cv::exp(q * log(assumeUnit)); +} + +template +inline T Quat::dot(Quat q1) const +{ + return w * q1.w + x * q1.x + y * q1.y + z * q1.z; +} + + +template +inline Quat crossProduct(const Quat &p, const Quat &q) +{ + return p.crossProduct(q); +} + + +template +inline Quat Quat::crossProduct(const Quat &q) const +{ + return Quat (0, y * q.z - z * q.y, z * q.x - x * q.z, x * q.y - q.x * y); +} + +template +inline Quat Quat::normalize() const +{ + T normVal = norm(); + if (normVal < CV_QUAT_EPS) + { + CV_Error(Error::StsBadArg, "Cannot normalize this quaternion: the norm is too small."); + } + return Quat(w / normVal, x / normVal, y / normVal, z / normVal) ; +} + +template +inline Quat inv(const Quat &q, QuatAssumeType assumeUnit) +{ + return q.inv(assumeUnit); +} + + +template +inline Quat Quat::inv(QuatAssumeType assumeUnit) const +{ + if (assumeUnit) + { + return conjugate(); + } + T norm2 = dot(*this); + if (norm2 < CV_QUAT_EPS) + { + CV_Error(Error::StsBadArg, "This quaternion do not have inverse quaternion"); + } + return conjugate() / norm2; +} + +template +inline Quat sinh(const Quat &q) +{ + return q.sinh(); +} + + +template +inline Quat Quat::sinh() const +{ + Vec v{x, y ,z}; + T vNorm = std::sqrt(v.dot(v)); + T k = vNorm < CV_QUAT_EPS ? 1 : std::cosh(w) * std::sin(vNorm) / vNorm; + return Quat(std::sinh(w) * std::cos(vNorm), v[0] * k, v[1] * k, v[2] * k); +} + + +template +inline Quat cosh(const Quat &q) +{ + return q.cosh(); +} + + +template +inline Quat Quat::cosh() const +{ + Vec v{x, y ,z}; + T vNorm = std::sqrt(v.dot(v)); + T k = vNorm < CV_QUAT_EPS ? 1 : std::sinh(w) * std::sin(vNorm) / vNorm; + return Quat(std::cosh(w) * std::cos(vNorm), v[0] * k, v[1] * k, v[2] * k); +} + +template +inline Quat tanh(const Quat &q) +{ + return q.tanh(); +} + +template +inline Quat Quat::tanh() const +{ + return sinh() * cosh().inv(); +} + + +template +inline Quat sin(const Quat &q) +{ + return q.sin(); +} + + +template +inline Quat Quat::sin() const +{ + Vec v{x, y ,z}; + T vNorm = std::sqrt(v.dot(v)); + T k = vNorm < CV_QUAT_EPS ? 1 : std::cos(w) * std::sinh(vNorm) / vNorm; + return Quat(std::sin(w) * std::cosh(vNorm), v[0] * k, v[1] * k, v[2] * k); +} + +template +inline Quat cos(const Quat &q) +{ + return q.cos(); +} + +template +inline Quat Quat::cos() const +{ + Vec v{x, y ,z}; + T vNorm = std::sqrt(v.dot(v)); + T k = vNorm < CV_QUAT_EPS ? 1 : std::sin(w) * std::sinh(vNorm) / vNorm; + return Quat(std::cos(w) * std::cosh(vNorm), -v[0] * k, -v[1] * k, -v[2] * k); +} + +template +inline Quat tan(const Quat &q) +{ + return q.tan(); +} + +template +inline Quat Quat::tan() const +{ + return sin() * cos().inv(); +} + +template +inline Quat asinh(const Quat &q) +{ + return q.asinh(); +} + +template +inline Quat Quat::asinh() const +{ + return cv::log(*this + cv::power(*this * *this + Quat(1, 0, 0, 0), 0.5)); +} + +template +inline Quat acosh(const Quat &q) +{ + return q.acosh(); +} + +template +inline Quat Quat::acosh() const +{ + return cv::log(*this + cv::power(*this * *this - Quat(1,0,0,0), 0.5)); +} + +template +inline Quat atanh(const Quat &q) +{ + return q.atanh(); +} + +template +inline Quat Quat::atanh() const +{ + Quat ident(1, 0, 0, 0); + Quat c1 = (ident + *this).log(); + Quat c2 = (ident - *this).log(); + return 0.5 * (c1 - c2); +} + +template +inline Quat asin(const Quat &q) +{ + return q.asin(); +} + +template +inline Quat Quat::asin() const +{ + Quat v(0, x, y, z); + T vNorm = v.norm(); + T k = vNorm < CV_QUAT_EPS ? 1 : vNorm; + return -v / k * (*this * v / k).asinh(); +} + +template +inline Quat acos(const Quat &q) +{ + return q.acos(); +} + +template +inline Quat Quat::acos() const +{ + Quat v(0, x, y, z); + T vNorm = v.norm(); + T k = vNorm < CV_QUAT_EPS ? 1 : vNorm; + return -v / k * acosh(); +} + +template +inline Quat atan(const Quat &q) +{ + return q.atan(); +} + +template +inline Quat Quat::atan() const +{ + Quat v(0, x, y, z); + T vNorm = v.norm(); + T k = vNorm < CV_QUAT_EPS ? 1 : vNorm; + return -v / k * (*this * v / k).atanh(); +} + +template +inline T Quat::getAngle(QuatAssumeType assumeUnit) const +{ + if (assumeUnit) + { + return 2 * std::acos(w); + } + if (norm() < CV_QUAT_EPS) + { + CV_Error(Error::StsBadArg, "This quaternion does not represent a rotation"); + } + return 2 * std::acos(w / norm()); +} + +template +inline Vec Quat::getAxis(QuatAssumeType assumeUnit) const +{ + T angle = getAngle(assumeUnit); + const T sin_v = std::sin(angle * 0.5); + if (assumeUnit) + { + return Vec{x, y, z} / sin_v; + } + return Vec {x, y, z} / (norm() * sin_v); +} + +template +Matx Quat::toRotMat4x4(QuatAssumeType assumeUnit) const +{ + T a = w, b = x, c = y, d = z; + if (!assumeUnit) + { + Quat qTemp = normalize(); + a = qTemp.w; + b = qTemp.x; + c = qTemp.y; + d = qTemp.z; + } + Matx R{ + 1 - 2 * (c * c + d * d), 2 * (b * c - a * d) , 2 * (b * d + a * c) , 0, + 2 * (b * c + a * d) , 1 - 2 * (b * b + d * d), 2 * (c * d - a * b) , 0, + 2 * (b * d - a * c) , 2 * (c * d + a * b) , 1 - 2 * (b * b + c * c), 0, + 0 , 0 , 0 , 1, + }; + return R; +} + +template +Matx Quat::toRotMat3x3(QuatAssumeType assumeUnit) const +{ + T a = w, b = x, c = y, d = z; + if (!assumeUnit) + { + Quat qTemp = normalize(); + a = qTemp.w; + b = qTemp.x; + c = qTemp.y; + d = qTemp.z; + } + Matx R{ + 1 - 2 * (c * c + d * d), 2 * (b * c - a * d) , 2 * (b * d + a * c), + 2 * (b * c + a * d) , 1 - 2 * (b * b + d * d), 2 * (c * d - a * b), + 2 * (b * d - a * c) , 2 * (c * d + a * b) , 1 - 2 * (b * b + c * c) + }; + return R; +} + +template +Vec Quat::toRotVec(QuatAssumeType assumeUnit) const +{ + T angle = getAngle(assumeUnit); + Vec axis = getAxis(assumeUnit); + return angle * axis; +} + +template +Vec Quat::toVec() const +{ + return Vec{w, x, y, z}; +} + +template +Quat Quat::lerp(const Quat &q0, const Quat &q1, const T t) +{ + return (1 - t) * q0 + t * q1; +} + +template +Quat Quat::slerp(const Quat &q0, const Quat &q1, const T t, QuatAssumeType assumeUnit, bool directChange) +{ + Quatd v0(q0); + Quatd v1(q1); + if (!assumeUnit) + { + v0 = v0.normalize(); + v1 = v1.normalize(); + } + T cosTheta = v0.dot(v1); + constexpr T DOT_THRESHOLD = 0.995; + if (cosTheta > DOT_THRESHOLD) + { + return nlerp(v0, v1, t, QUAT_ASSUME_UNIT); + } + + if (directChange && cosTheta < 0) + { + v0 = -v0; + cosTheta = -cosTheta; + } + T sinTheta = std::sqrt(1 - cosTheta * cosTheta); + T angle = atan2(sinTheta, cosTheta); + return (std::sin((1 - t) * angle) / (sinTheta) * v0 + std::sin(t * angle) / (sinTheta) * v1).normalize(); +} + + +template +inline Quat Quat::nlerp(const Quat &q0, const Quat &q1, const T t, QuatAssumeType assumeUnit) +{ + Quat v0(q0), v1(q1); + if (v1.dot(v0) < 0) + { + v0 = -v0; + } + if (assumeUnit) + { + return ((1 - t) * v0 + t * v1).normalize(); + } + v0 = v0.normalize(); + v1 = v1.normalize(); + return ((1 - t) * v0 + t * v1).normalize(); +} + + +template +inline bool Quat::isNormal(T eps) const +{ + + double normVar = norm(); + if ((normVar > 1 - eps) && (normVar < 1 + eps)) + return true; + return false; +} + +template +inline void Quat::assertNormal(T eps) const +{ + if (!isNormal(eps)) + CV_Error(Error::StsBadArg, "Quaternion should be normalized"); +} + + +template +inline Quat Quat::squad(const Quat &q0, const Quat &q1, + const Quat &q2, const Quat &q3, + const T t, QuatAssumeType assumeUnit, + bool directChange) +{ + Quat v0(q0), v1(q1), v2(q2), v3(q3); + if (!assumeUnit) + { + v0 = v0.normalize(); + v1 = v1.normalize(); + v2 = v2.normalize(); + v3 = v3.normalize(); + } + + Quat c0 = slerp(v0, v3, t, assumeUnit, directChange); + Quat c1 = slerp(v1, v2, t, assumeUnit, directChange); + return slerp(c0, c1, 2 * t * (1 - t), assumeUnit, directChange); +} + +template +Quat Quat::interPoint(const Quat &q0, const Quat &q1, + const Quat &q2, QuatAssumeType assumeUnit) +{ + Quat v0(q0), v1(q1), v2(q2); + if (!assumeUnit) + { + v0 = v0.normalize(); + v1 = v1.normalize(); + v2 = v2.normalize(); + } + return v1 * cv::exp(-(cv::log(v1.conjugate() * v0, assumeUnit) + (cv::log(v1.conjugate() * v2, assumeUnit))) / 4); +} + +template +Quat Quat::spline(const Quat &q0, const Quat &q1, const Quat &q2, const Quat &q3, const T t, QuatAssumeType assumeUnit) +{ + Quatd v0(q0), v1(q1), v2(q2), v3(q3); + if (!assumeUnit) + { + v0 = v0.normalize(); + v1 = v1.normalize(); + v2 = v2.normalize(); + v3 = v3.normalize(); + } + T cosTheta; + std::vector> vec{v0, v1, v2, v3}; + for (size_t i = 0; i < 3; ++i) + { + cosTheta = vec[i].dot(vec[i + 1]); + if (cosTheta < 0) + { + vec[i + 1] = -vec[i + 1]; + } + } + Quat s1 = interPoint(vec[0], vec[1], vec[2], QUAT_ASSUME_UNIT); + Quat s2 = interPoint(vec[1], vec[2], vec[3], QUAT_ASSUME_UNIT); + return squad(vec[1], s1, s2, vec[2], t, assumeUnit, QUAT_ASSUME_NOT_UNIT); +} + +namespace detail { + +template static +Quat createFromAxisRot(int axis, const T theta) +{ + if (axis == 0) + return Quat::createFromXRot(theta); + if (axis == 1) + return Quat::createFromYRot(theta); + if (axis == 2) + return Quat::createFromZRot(theta); + CV_Assert(0); +} + +inline bool isIntAngleType(QuatEnum::EulerAnglesType eulerAnglesType) +{ + return eulerAnglesType < QuatEnum::EXT_XYZ; +} + +inline bool isTaitBryan(QuatEnum::EulerAnglesType eulerAnglesType) +{ + return eulerAnglesType/6 == 1 || eulerAnglesType/6 == 3; +} +} // namespace detail + +template +Quat Quat::createFromYRot(const T theta) +{ + return Quat{std::cos(theta * 0.5f), 0, std::sin(theta * 0.5f), 0}; +} + +template +Quat Quat::createFromXRot(const T theta){ + return Quat{std::cos(theta * 0.5f), std::sin(theta * 0.5f), 0, 0}; +} + +template +Quat Quat::createFromZRot(const T theta){ + return Quat{std::cos(theta * 0.5f), 0, 0, std::sin(theta * 0.5f)}; +} + + +template +Quat Quat::createFromEulerAngles(const Vec &angles, QuatEnum::EulerAnglesType eulerAnglesType) { + CV_Assert(eulerAnglesType < QuatEnum::EulerAnglesType::EULER_ANGLES_MAX_VALUE); + static const int rotationAxis[24][3] = { + {0, 1, 2}, ///< Intrinsic rotations with the Euler angles type X-Y-Z + {0, 2, 1}, ///< Intrinsic rotations with the Euler angles type X-Z-Y + {1, 0, 2}, ///< Intrinsic rotations with the Euler angles type Y-X-Z + {1, 2, 0}, ///< Intrinsic rotations with the Euler angles type Y-Z-X + {2, 0, 1}, ///< Intrinsic rotations with the Euler angles type Z-X-Y + {2, 1, 0}, ///< Intrinsic rotations with the Euler angles type Z-Y-X + {0, 1, 0}, ///< Intrinsic rotations with the Euler angles type X-Y-X + {0, 2, 0}, ///< Intrinsic rotations with the Euler angles type X-Z-X + {1, 0, 1}, ///< Intrinsic rotations with the Euler angles type Y-X-Y + {1, 2, 1}, ///< Intrinsic rotations with the Euler angles type Y-Z-Y + {2, 0, 2}, ///< Intrinsic rotations with the Euler angles type Z-X-Z + {2, 1, 2}, ///< Intrinsic rotations with the Euler angles type Z-Y-Z + {0, 1, 2}, ///< Extrinsic rotations with the Euler angles type X-Y-Z + {0, 2, 1}, ///< Extrinsic rotations with the Euler angles type X-Z-Y + {1, 0, 2}, ///< Extrinsic rotations with the Euler angles type Y-X-Z + {1, 2, 0}, ///< Extrinsic rotations with the Euler angles type Y-Z-X + {2, 0, 1}, ///< Extrinsic rotations with the Euler angles type Z-X-Y + {2, 1, 0}, ///< Extrinsic rotations with the Euler angles type Z-Y-X + {0, 1, 0}, ///< Extrinsic rotations with the Euler angles type X-Y-X + {0, 2, 0}, ///< Extrinsic rotations with the Euler angles type X-Z-X + {1, 0, 1}, ///< Extrinsic rotations with the Euler angles type Y-X-Y + {1, 2, 1}, ///< Extrinsic rotations with the Euler angles type Y-Z-Y + {2, 0, 2}, ///< Extrinsic rotations with the Euler angles type Z-X-Z + {2, 1, 2} ///< Extrinsic rotations with the Euler angles type Z-Y-Z + }; + Quat q1 = detail::createFromAxisRot(rotationAxis[eulerAnglesType][0], angles(0)); + Quat q2 = detail::createFromAxisRot(rotationAxis[eulerAnglesType][1], angles(1)); + Quat q3 = detail::createFromAxisRot(rotationAxis[eulerAnglesType][2], angles(2)); + if (detail::isIntAngleType(eulerAnglesType)) + { + return q1 * q2 * q3; + } + else // (!detail::isIntAngleType(eulerAnglesType)) + { + return q3 * q2 * q1; + } +} + +template +Vec Quat::toEulerAngles(QuatEnum::EulerAnglesType eulerAnglesType){ + CV_Assert(eulerAnglesType < QuatEnum::EulerAnglesType::EULER_ANGLES_MAX_VALUE); + Matx33d R = toRotMat3x3(); + enum { + C_ZERO, + C_PI, + C_PI_2, + N_CONSTANTS, + R_0_0 = N_CONSTANTS, R_0_1, R_0_2, + R_1_0, R_1_1, R_1_2, + R_2_0, R_2_1, R_2_2 + }; + static const T constants_[N_CONSTANTS] = { + 0, // C_ZERO + (T)CV_PI, // C_PI + (T)(CV_PI * 0.5) // C_PI_2, -C_PI_2 + }; + static const int rotationR_[24][12] = { + {+R_0_2, +R_1_0, +R_1_1, C_PI_2, +R_2_1, +R_1_1, -C_PI_2, -R_1_2, +R_2_2, +R_0_2, -R_0_1, +R_0_0}, // INT_XYZ + {+R_0_1, -R_1_2, +R_2_2, -C_PI_2, +R_2_0, +R_2_2, C_PI_2, +R_2_1, +R_1_1, -R_0_1, +R_0_2, +R_0_0}, // INT_XZY + {+R_1_2, -R_0_1, +R_0_0, -C_PI_2, +R_0_1, +R_0_0, C_PI_2, +R_0_2, +R_2_2, -R_1_2, +R_1_0, +R_1_1}, // INT_YXZ + {+R_1_0, +R_0_2, +R_2_2, C_PI_2, +R_0_2, +R_0_1, -C_PI_2, -R_2_0, +R_0_0, +R_1_0, -R_1_2, +R_1_1}, // INT_YZX + {+R_2_1, +R_1_0, +R_0_0, C_PI_2, +R_1_0, +R_0_0, -C_PI_2, -R_0_1, +R_1_1, +R_2_1, -R_2_0, +R_2_2}, // INT_ZXY + {+R_2_0, -R_0_1, +R_1_1, -C_PI_2, +R_1_2, +R_1_1, C_PI_2, +R_1_0, +R_0_0, -R_2_0, +R_2_1, +R_2_2}, // INT_ZYX + {+R_0_0, +R_2_1, +R_2_2, C_ZERO, +R_1_2, +R_1_1, C_PI, +R_1_0, -R_2_0, +R_0_0, +R_0_1, +R_0_2}, // INT_XYX + {+R_0_0, +R_2_1, +R_2_2, C_ZERO, -R_2_1, +R_2_2, C_PI, +R_2_0, +R_1_0, +R_0_0, +R_0_2, -R_0_1}, // INT_XZX + {+R_1_1, +R_0_2, +R_0_0, C_ZERO, -R_2_0, +R_0_0, C_PI, +R_0_1, +R_2_1, +R_1_1, +R_1_0, -R_1_2}, // INT_YXY + {+R_1_1, +R_0_2, +R_0_0, C_ZERO, +R_0_2, -R_0_0, C_PI, +R_2_1, -R_0_1, +R_1_1, +R_1_2, +R_1_0}, // INT_YZY + {+R_2_2, +R_1_0, +R_1_1, C_ZERO, +R_1_0, +R_0_0, C_PI, +R_0_2, -R_1_2, +R_2_2, +R_2_0, +R_2_1}, // INT_ZXZ + {+R_2_2, +R_1_0, +R_0_0, C_ZERO, +R_1_0, +R_0_0, C_PI, +R_1_2, +R_0_2, +R_2_2, +R_2_1, -R_2_0}, // INT_ZYZ + + {+R_2_0, -C_PI_2, -R_0_1, +R_1_1, C_PI_2, +R_1_2, +R_1_1, +R_2_1, +R_2_2, -R_2_0, +R_1_0, +R_0_0}, // EXT_XYZ + {+R_1_0, C_PI_2, +R_0_2, +R_2_2, -C_PI_2, +R_0_2, +R_0_1, -R_1_2, +R_1_1, +R_1_0, -R_2_0, +R_0_0}, // EXT_XZY + {+R_2_1, C_PI_2, +R_1_0, +R_0_0, -C_PI_2, +R_1_0, +R_0_0, -R_2_0, +R_2_2, +R_2_1, -R_0_1, +R_1_1}, // EXT_YXZ + {+R_0_2, -C_PI_2, -R_1_2, +R_2_2, C_PI_2, +R_2_0, +R_2_2, +R_0_2, +R_0_0, -R_0_1, +R_2_1, +R_1_1}, // EXT_YZX + {+R_1_2, -C_PI_2, -R_0_1, +R_0_0, C_PI_2, +R_0_1, +R_0_0, +R_1_0, +R_1_1, -R_1_2, +R_0_2, +R_2_2}, // EXT_ZXY + {+R_0_2, C_PI_2, +R_1_0, +R_1_1, -C_PI_2, +R_2_1, +R_1_1, -R_0_1, +R_0_0, +R_0_2, -R_1_2, +R_2_2}, // EXT_ZYX + {+R_0_0, C_ZERO, +R_2_1, +R_2_2, C_PI, +R_1_2, +R_1_1, +R_0_1, +R_0_2, +R_0_0, +R_1_0, -R_2_0}, // EXT_XYX + {+R_0_0, C_ZERO, +R_2_1, +R_2_2, C_PI, +R_2_1, +R_2_2, +R_0_2, -R_0_1, +R_0_0, +R_2_0, +R_1_0}, // EXT_XZX + {+R_1_1, C_ZERO, +R_0_2, +R_0_0, C_PI, -R_2_0, +R_0_0, +R_1_0, -R_1_2, +R_1_1, +R_0_1, +R_2_1}, // EXT_YXY + {+R_1_1, C_ZERO, +R_0_2, +R_0_0, C_PI, +R_0_2, -R_0_0, +R_1_2, +R_1_0, +R_1_1, +R_2_1, -R_0_1}, // EXT_YZY + {+R_2_2, C_ZERO, +R_1_0, +R_1_1, C_PI, +R_1_0, +R_0_0, +R_2_0, +R_2_1, +R_2_2, +R_0_2, -R_1_2}, // EXT_ZXZ + {+R_2_2, C_ZERO, +R_1_0, +R_0_0, C_PI, +R_1_0, +R_0_0, +R_2_1, -R_2_0, +R_2_2, +R_1_2, +R_0_2}, // EXT_ZYZ + }; + T rotationR[12]; + for (int i = 0; i < 12; i++) + { + int id = rotationR_[eulerAnglesType][i]; + unsigned idx = std::abs(id); + T value = 0.0f; + if (idx < N_CONSTANTS) + { + value = constants_[idx]; + } + else + { + unsigned r_idx = idx - N_CONSTANTS; + CV_DbgAssert(r_idx < 9); + value = R.val[r_idx]; + } + bool isNegative = id < 0; + if (isNegative) + value = -value; + rotationR[i] = value; + } + Vec angles; + if (detail::isIntAngleType(eulerAnglesType)) + { + if (abs(rotationR[0] - 1) < CV_QUAT_CONVERT_THRESHOLD) + { + CV_LOG_WARNING(NULL,"Gimbal Lock occurs. Euler angles are non-unique, we set the third angle to 0"); + angles = {std::atan2(rotationR[1], rotationR[2]), rotationR[3], 0}; + return angles; + } + else if(abs(rotationR[0] + 1) < CV_QUAT_CONVERT_THRESHOLD) + { + CV_LOG_WARNING(NULL,"Gimbal Lock occurs. Euler angles are non-unique, we set the third angle to 0"); + angles = {std::atan2(rotationR[4], rotationR[5]), rotationR[6], 0}; + return angles; + } + } + else // (!detail::isIntAngleType(eulerAnglesType)) + { + if (abs(rotationR[0] - 1) < CV_QUAT_CONVERT_THRESHOLD) + { + CV_LOG_WARNING(NULL,"Gimbal Lock occurs. Euler angles are non-unique, we set the first angle to 0"); + angles = {0, rotationR[1], std::atan2(rotationR[2], rotationR[3])}; + return angles; + } + else if (abs(rotationR[0] + 1) < CV_QUAT_CONVERT_THRESHOLD) + { + CV_LOG_WARNING(NULL,"Gimbal Lock occurs. Euler angles are non-unique, we set the first angle to 0"); + angles = {0, rotationR[4], std::atan2(rotationR[5], rotationR[6])}; + return angles; + } + } + + angles(0) = std::atan2(rotationR[7], rotationR[8]); + if (detail::isTaitBryan(eulerAnglesType)) + angles(1) = std::acos(rotationR[9]); + else + angles(1) = std::asin(rotationR[9]); + angles(2) = std::atan2(rotationR[10], rotationR[11]); + return angles; +} + +} // namepsace +//! @endcond + +#endif /*OPENCV_CORE_QUATERNION_INL_HPP*/ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/saturate.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/saturate.hpp new file mode 100644 index 0000000..8127e3d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/saturate.hpp @@ -0,0 +1,179 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2014, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_SATURATE_HPP +#define OPENCV_CORE_SATURATE_HPP + +#include "opencv2/core/cvdef.h" +#include "opencv2/core/fast_math.hpp" + +namespace cv +{ + +//! @addtogroup core_utils +//! @{ + +/////////////// saturate_cast (used in image & signal processing) /////////////////// + +/** @brief Template function for accurate conversion from one primitive type to another. + + The function saturate_cast resembles the standard C++ cast operations, such as static_cast\() + and others. It perform an efficient and accurate conversion from one primitive type to another + (see the introduction chapter). saturate in the name means that when the input value v is out of the + range of the target type, the result is not formed just by taking low bits of the input, but instead + the value is clipped. For example: + @code + uchar a = saturate_cast(-100); // a = 0 (UCHAR_MIN) + short b = saturate_cast(33333.33333); // b = 32767 (SHRT_MAX) + @endcode + Such clipping is done when the target type is unsigned char , signed char , unsigned short or + signed short . For 32-bit integers, no clipping is done. + + When the parameter is a floating-point value and the target type is an integer (8-, 16- or 32-bit), + the floating-point value is first rounded to the nearest integer and then clipped if needed (when + the target type is 8- or 16-bit). + + @param v Function parameter. + @sa add, subtract, multiply, divide, Mat::convertTo + */ +template static inline _Tp saturate_cast(uchar v) { return _Tp(v); } +/** @overload */ +template static inline _Tp saturate_cast(schar v) { return _Tp(v); } +/** @overload */ +template static inline _Tp saturate_cast(ushort v) { return _Tp(v); } +/** @overload */ +template static inline _Tp saturate_cast(short v) { return _Tp(v); } +/** @overload */ +template static inline _Tp saturate_cast(unsigned v) { return _Tp(v); } +/** @overload */ +template static inline _Tp saturate_cast(int v) { return _Tp(v); } +/** @overload */ +template static inline _Tp saturate_cast(float v) { return _Tp(v); } +/** @overload */ +template static inline _Tp saturate_cast(double v) { return _Tp(v); } +/** @overload */ +template static inline _Tp saturate_cast(int64 v) { return _Tp(v); } +/** @overload */ +template static inline _Tp saturate_cast(uint64 v) { return _Tp(v); } + +template<> inline uchar saturate_cast(schar v) { return (uchar)std::max((int)v, 0); } +template<> inline uchar saturate_cast(ushort v) { return (uchar)std::min((unsigned)v, (unsigned)UCHAR_MAX); } +template<> inline uchar saturate_cast(int v) { return (uchar)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); } +template<> inline uchar saturate_cast(short v) { return saturate_cast((int)v); } +template<> inline uchar saturate_cast(unsigned v) { return (uchar)std::min(v, (unsigned)UCHAR_MAX); } +template<> inline uchar saturate_cast(float v) { int iv = cvRound(v); return saturate_cast(iv); } +template<> inline uchar saturate_cast(double v) { int iv = cvRound(v); return saturate_cast(iv); } +template<> inline uchar saturate_cast(int64 v) { return (uchar)((uint64)v <= (uint64)UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); } +template<> inline uchar saturate_cast(uint64 v) { return (uchar)std::min(v, (uint64)UCHAR_MAX); } + +template<> inline schar saturate_cast(uchar v) { return (schar)std::min((int)v, SCHAR_MAX); } +template<> inline schar saturate_cast(ushort v) { return (schar)std::min((unsigned)v, (unsigned)SCHAR_MAX); } +template<> inline schar saturate_cast(int v) { return (schar)((unsigned)(v-SCHAR_MIN) <= (unsigned)UCHAR_MAX ? v : v > 0 ? SCHAR_MAX : SCHAR_MIN); } +template<> inline schar saturate_cast(short v) { return saturate_cast((int)v); } +template<> inline schar saturate_cast(unsigned v) { return (schar)std::min(v, (unsigned)SCHAR_MAX); } +template<> inline schar saturate_cast(float v) { int iv = cvRound(v); return saturate_cast(iv); } +template<> inline schar saturate_cast(double v) { int iv = cvRound(v); return saturate_cast(iv); } +template<> inline schar saturate_cast(int64 v) { return (schar)((uint64)((int64)v-SCHAR_MIN) <= (uint64)UCHAR_MAX ? v : v > 0 ? SCHAR_MAX : SCHAR_MIN); } +template<> inline schar saturate_cast(uint64 v) { return (schar)std::min(v, (uint64)SCHAR_MAX); } + +template<> inline ushort saturate_cast(schar v) { return (ushort)std::max((int)v, 0); } +template<> inline ushort saturate_cast(short v) { return (ushort)std::max((int)v, 0); } +template<> inline ushort saturate_cast(int v) { return (ushort)((unsigned)v <= (unsigned)USHRT_MAX ? v : v > 0 ? USHRT_MAX : 0); } +template<> inline ushort saturate_cast(unsigned v) { return (ushort)std::min(v, (unsigned)USHRT_MAX); } +template<> inline ushort saturate_cast(float v) { int iv = cvRound(v); return saturate_cast(iv); } +template<> inline ushort saturate_cast(double v) { int iv = cvRound(v); return saturate_cast(iv); } +template<> inline ushort saturate_cast(int64 v) { return (ushort)((uint64)v <= (uint64)USHRT_MAX ? v : v > 0 ? USHRT_MAX : 0); } +template<> inline ushort saturate_cast(uint64 v) { return (ushort)std::min(v, (uint64)USHRT_MAX); } + +template<> inline short saturate_cast(ushort v) { return (short)std::min((int)v, SHRT_MAX); } +template<> inline short saturate_cast(int v) { return (short)((unsigned)(v - SHRT_MIN) <= (unsigned)USHRT_MAX ? v : v > 0 ? SHRT_MAX : SHRT_MIN); } +template<> inline short saturate_cast(unsigned v) { return (short)std::min(v, (unsigned)SHRT_MAX); } +template<> inline short saturate_cast(float v) { int iv = cvRound(v); return saturate_cast(iv); } +template<> inline short saturate_cast(double v) { int iv = cvRound(v); return saturate_cast(iv); } +template<> inline short saturate_cast(int64 v) { return (short)((uint64)((int64)v - SHRT_MIN) <= (uint64)USHRT_MAX ? v : v > 0 ? SHRT_MAX : SHRT_MIN); } +template<> inline short saturate_cast(uint64 v) { return (short)std::min(v, (uint64)SHRT_MAX); } + +template<> inline int saturate_cast(unsigned v) { return (int)std::min(v, (unsigned)INT_MAX); } +template<> inline int saturate_cast(int64 v) { return (int)((uint64)(v - INT_MIN) <= (uint64)UINT_MAX ? v : v > 0 ? INT_MAX : INT_MIN); } +template<> inline int saturate_cast(uint64 v) { return (int)std::min(v, (uint64)INT_MAX); } +template<> inline int saturate_cast(float v) { return cvRound(v); } +template<> inline int saturate_cast(double v) { return cvRound(v); } + +template<> inline unsigned saturate_cast(schar v) { return (unsigned)std::max(v, (schar)0); } +template<> inline unsigned saturate_cast(short v) { return (unsigned)std::max(v, (short)0); } +template<> inline unsigned saturate_cast(int v) { return (unsigned)std::max(v, (int)0); } +template<> inline unsigned saturate_cast(int64 v) { return (unsigned)((uint64)v <= (uint64)UINT_MAX ? v : v > 0 ? UINT_MAX : 0); } +template<> inline unsigned saturate_cast(uint64 v) { return (unsigned)std::min(v, (uint64)UINT_MAX); } +// we intentionally do not clip negative numbers, to make -1 become 0xffffffff etc. +template<> inline unsigned saturate_cast(float v) { return static_cast(cvRound(v)); } +template<> inline unsigned saturate_cast(double v) { return static_cast(cvRound(v)); } + +template<> inline uint64 saturate_cast(schar v) { return (uint64)std::max(v, (schar)0); } +template<> inline uint64 saturate_cast(short v) { return (uint64)std::max(v, (short)0); } +template<> inline uint64 saturate_cast(int v) { return (uint64)std::max(v, (int)0); } +template<> inline uint64 saturate_cast(int64 v) { return (uint64)std::max(v, (int64)0); } + +template<> inline int64 saturate_cast(uint64 v) { return (int64)std::min(v, (uint64)LLONG_MAX); } + +/** @overload */ +template static inline _Tp saturate_cast(float16_t v) { return saturate_cast<_Tp>((float)v); } + +// in theory, we could use a LUT for 8u/8s->16f conversion, +// but with hardware support for FP32->FP16 conversion the current approach is preferable +template<> inline float16_t saturate_cast(uchar v) { return float16_t((float)v); } +template<> inline float16_t saturate_cast(schar v) { return float16_t((float)v); } +template<> inline float16_t saturate_cast(ushort v) { return float16_t((float)v); } +template<> inline float16_t saturate_cast(short v) { return float16_t((float)v); } +template<> inline float16_t saturate_cast(unsigned v){ return float16_t((float)v); } +template<> inline float16_t saturate_cast(int v) { return float16_t((float)v); } +template<> inline float16_t saturate_cast(uint64 v) { return float16_t((float)v); } +template<> inline float16_t saturate_cast(int64 v) { return float16_t((float)v); } +template<> inline float16_t saturate_cast(float v) { return float16_t(v); } +template<> inline float16_t saturate_cast(double v) { return float16_t((float)v); } + +//! @} + +} // cv + +#endif // OPENCV_CORE_SATURATE_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/simd_intrinsics.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/simd_intrinsics.hpp new file mode 100644 index 0000000..2658d92 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/simd_intrinsics.hpp @@ -0,0 +1,87 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_SIMD_INTRINSICS_HPP +#define OPENCV_CORE_SIMD_INTRINSICS_HPP + +/** +Helper header to support SIMD intrinsics (universal intrinsics) in user code. +Intrinsics documentation: https://docs.opencv.org/4.x/df/d91/group__core__hal__intrin.html + + +Checks of target CPU instruction set based on compiler definitions don't work well enough. +More reliable solutions require utilization of configuration systems (like CMake). + +So, probably you need to specify your own configuration. + +You can do that via CMake in this way: + add_definitions(/DOPENCV_SIMD_CONFIG_HEADER=opencv_simd_config_custom.hpp) +or + add_definitions(/DOPENCV_SIMD_CONFIG_INCLUDE_DIR=1) + +Additionally you may need to add include directory to your files: + include_directories("${CMAKE_CURRENT_LIST_DIR}/opencv_config_${MYTARGET}") + +These files can be pre-generated for target configurations of your application +or generated by CMake on the fly (use CMAKE_BINARY_DIR for that). + +Notes: +- H/W capability checks are still responsibility of your application +- runtime dispatching is not covered by this helper header +*/ + +#ifdef __OPENCV_BUILD +#error "Use core/hal/intrin.hpp during OpenCV build" +#endif + +#ifdef OPENCV_HAL_INTRIN_HPP +#error "core/simd_intrinsics.hpp must be included before core/hal/intrin.hpp" +#endif + +#include "opencv2/core/cvdef.h" + +#ifdef OPENCV_SIMD_CONFIG_HEADER +#include CVAUX_STR(OPENCV_SIMD_CONFIG_HEADER) +#elif defined(OPENCV_SIMD_CONFIG_INCLUDE_DIR) +#include "opencv_simd_config.hpp" // corresponding directory should be added via -I compiler parameter +#else // custom config headers + +#if (!defined(CV_AVX_512F) || !CV_AVX_512F) && (defined(__AVX512__) || defined(__AVX512F__)) +# include +# undef CV_AVX_512F +# define CV_AVX_512F 1 +# ifndef OPENCV_SIMD_DONT_ASSUME_SKX // Skylake-X with AVX-512F/CD/BW/DQ/VL +# undef CV_AVX512_SKX +# define CV_AVX512_SKX 1 +# undef CV_AVX_512CD +# define CV_AVX_512CD 1 +# undef CV_AVX_512BW +# define CV_AVX_512BW 1 +# undef CV_AVX_512DQ +# define CV_AVX_512DQ 1 +# undef CV_AVX_512VL +# define CV_AVX_512VL 1 +# endif +#endif // AVX512 + +// GCC/Clang: -mavx2 +// MSVC: /arch:AVX2 +#if defined __AVX2__ +# include +# undef CV_AVX2 +# define CV_AVX2 1 +# if defined __F16C__ +# undef CV_FP16 +# define CV_FP16 1 +# endif +#endif + +#endif + +// SSE / NEON / VSX is handled by cv_cpu_dispatch.h compatibility block +#include "cv_cpu_dispatch.h" + +#include "hal/intrin.hpp" + +#endif // OPENCV_CORE_SIMD_INTRINSICS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/softfloat.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/softfloat.hpp new file mode 100644 index 0000000..485e15c --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/softfloat.hpp @@ -0,0 +1,514 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + +// This file is based on files from package issued with the following license: + +/*============================================================================ + +This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic +Package, Release 3c, by John R. Hauser. + +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the +University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. 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. + + 3. Neither the name of the University nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + +=============================================================================*/ + +#pragma once +#ifndef softfloat_h +#define softfloat_h 1 + +#include "cvdef.h" + +namespace cv +{ + +/** @addtogroup core_utils_softfloat + + [SoftFloat](http://www.jhauser.us/arithmetic/SoftFloat.html) is a software implementation + of floating-point calculations according to IEEE 754 standard. + All calculations are done in integers, that's why they are machine-independent and bit-exact. + This library can be useful in accuracy-critical parts like look-up tables generation, tests, etc. + OpenCV contains a subset of SoftFloat partially rewritten to C++. + + ### Types + + There are two basic types: @ref softfloat and @ref softdouble. + These types are binary compatible with float and double types respectively + and support conversions to/from them. + Other types from original SoftFloat library like fp16 or fp128 were thrown away + as well as quiet/signaling NaN support, on-the-fly rounding mode switch + and exception flags (though exceptions can be implemented in the future). + + ### Operations + + Both types support the following: + - Construction from signed and unsigned 32-bit and 64 integers, + float/double or raw binary representation + - Conversions between each other, to float or double and to int + using @ref cvRound, @ref cvTrunc, @ref cvFloor, @ref cvCeil or a bunch of + saturate_cast functions + - Add, subtract, multiply, divide, remainder, square root, FMA with absolute precision + - Comparison operations + - Explicit sign, exponent and significand manipulation through get/set methods, + number state indicators (isInf, isNan, isSubnormal) + - Type-specific constants like eps, minimum/maximum value, best pi approximation, etc. + - min(), max(), abs(), exp(), log() and pow() functions + +*/ +//! @{ + +struct softfloat; +struct softdouble; + +struct CV_EXPORTS softfloat +{ +public: + /** @brief Default constructor */ + softfloat() { v = 0; } + /** @brief Copy constructor */ + softfloat( const softfloat& c) { v = c.v; } + /** @brief Assign constructor */ + softfloat& operator=( const softfloat& c ) + { + if(&c != this) v = c.v; + return *this; + } + /** @brief Construct from raw + + Builds new value from raw binary representation + */ + static const softfloat fromRaw( const uint32_t a ) { softfloat x; x.v = a; return x; } + + /** @brief Construct from integer */ + explicit softfloat( const uint32_t ); + explicit softfloat( const uint64_t ); + explicit softfloat( const int32_t ); + explicit softfloat( const int64_t ); + +#ifdef CV_INT32_T_IS_LONG_INT + // for platforms with int32_t = long int + explicit softfloat( const int a ) { *this = softfloat(static_cast(a)); } +#endif + + /** @brief Construct from float */ + explicit softfloat( const float a ) { Cv32suf s; s.f = a; v = s.u; } + + /** @brief Type casts */ + operator softdouble() const; + operator float() const { Cv32suf s; s.u = v; return s.f; } + + /** @brief Basic arithmetics */ + softfloat operator + (const softfloat&) const; + softfloat operator - (const softfloat&) const; + softfloat operator * (const softfloat&) const; + softfloat operator / (const softfloat&) const; + softfloat operator - () const { softfloat x; x.v = v ^ (1U << 31); return x; } + + /** @brief Remainder operator + + A quote from original SoftFloat manual: + + > The IEEE Standard remainder operation computes the value + > a - n * b, where n is the integer closest to a / b. + > If a / b is exactly halfway between two integers, n is the even integer + > closest to a / b. The IEEE Standard’s remainder operation is always exact and so requires no rounding. + > Depending on the relative magnitudes of the operands, the remainder functions + > can take considerably longer to execute than the other SoftFloat functions. + > This is an inherent characteristic of the remainder operation itself and is not a flaw + > in the SoftFloat implementation. + */ + softfloat operator % (const softfloat&) const; + + softfloat& operator += (const softfloat& a) { *this = *this + a; return *this; } + softfloat& operator -= (const softfloat& a) { *this = *this - a; return *this; } + softfloat& operator *= (const softfloat& a) { *this = *this * a; return *this; } + softfloat& operator /= (const softfloat& a) { *this = *this / a; return *this; } + softfloat& operator %= (const softfloat& a) { *this = *this % a; return *this; } + + /** @brief Comparison operations + + - Any operation with NaN produces false + + The only exception is when x is NaN: x != y for any y. + - Positive and negative zeros are equal + */ + bool operator == ( const softfloat& ) const; + bool operator != ( const softfloat& ) const; + bool operator > ( const softfloat& ) const; + bool operator >= ( const softfloat& ) const; + bool operator < ( const softfloat& ) const; + bool operator <= ( const softfloat& ) const; + + /** @brief NaN state indicator */ + inline bool isNaN() const { return (v & 0x7fffffff) > 0x7f800000; } + /** @brief Inf state indicator */ + inline bool isInf() const { return (v & 0x7fffffff) == 0x7f800000; } + /** @brief Subnormal number indicator */ + inline bool isSubnormal() const { return ((v >> 23) & 0xFF) == 0; } + + /** @brief Get sign bit */ + inline bool getSign() const { return (v >> 31) != 0; } + /** @brief Construct a copy with new sign bit */ + inline softfloat setSign(bool sign) const { softfloat x; x.v = (v & ((1U << 31) - 1)) | ((uint32_t)sign << 31); return x; } + /** @brief Get 0-based exponent */ + inline int getExp() const { return ((v >> 23) & 0xFF) - 127; } + /** @brief Construct a copy with new 0-based exponent */ + inline softfloat setExp(int e) const { softfloat x; x.v = (v & 0x807fffff) | (((e + 127) & 0xFF) << 23 ); return x; } + + /** @brief Get a fraction part + + Returns a number 1 <= x < 2 with the same significand + */ + inline softfloat getFrac() const + { + uint_fast32_t vv = (v & 0x007fffff) | (127 << 23); + return softfloat::fromRaw(vv); + } + /** @brief Construct a copy with provided significand + + Constructs a copy of a number with significand taken from parameter + */ + inline softfloat setFrac(const softfloat& s) const + { + softfloat x; + x.v = (v & 0xff800000) | (s.v & 0x007fffff); + return x; + } + + /** @brief Zero constant */ + static softfloat zero() { return softfloat::fromRaw( 0 ); } + /** @brief Positive infinity constant */ + static softfloat inf() { return softfloat::fromRaw( 0xFF << 23 ); } + /** @brief Default NaN constant */ + static softfloat nan() { return softfloat::fromRaw( 0x7fffffff ); } + /** @brief One constant */ + static softfloat one() { return softfloat::fromRaw( 127 << 23 ); } + /** @brief Smallest normalized value */ + static softfloat min() { return softfloat::fromRaw( 0x01 << 23 ); } + /** @brief Difference between 1 and next representable value */ + static softfloat eps() { return softfloat::fromRaw( (127 - 23) << 23 ); } + /** @brief Biggest finite value */ + static softfloat max() { return softfloat::fromRaw( (0xFF << 23) - 1 ); } + /** @brief Correct pi approximation */ + static softfloat pi() { return softfloat::fromRaw( 0x40490fdb ); } + + uint32_t v; +}; + +/*---------------------------------------------------------------------------- +*----------------------------------------------------------------------------*/ + +struct CV_EXPORTS softdouble +{ +public: + /** @brief Default constructor */ + softdouble() : v(0) { } + /** @brief Copy constructor */ + softdouble( const softdouble& c) { v = c.v; } + /** @brief Assign constructor */ + softdouble& operator=( const softdouble& c ) + { + if(&c != this) v = c.v; + return *this; + } + /** @brief Construct from raw + + Builds new value from raw binary representation + */ + static softdouble fromRaw( const uint64_t a ) { softdouble x; x.v = a; return x; } + + /** @brief Construct from integer */ + explicit softdouble( const uint32_t ); + explicit softdouble( const uint64_t ); + explicit softdouble( const int32_t ); + explicit softdouble( const int64_t ); + +#ifdef CV_INT32_T_IS_LONG_INT + // for platforms with int32_t = long int + explicit softdouble( const int a ) { *this = softdouble(static_cast(a)); } +#endif + + /** @brief Construct from double */ + explicit softdouble( const double a ) { Cv64suf s; s.f = a; v = s.u; } + + /** @brief Type casts */ + operator softfloat() const; + operator double() const { Cv64suf s; s.u = v; return s.f; } + + /** @brief Basic arithmetics */ + softdouble operator + (const softdouble&) const; + softdouble operator - (const softdouble&) const; + softdouble operator * (const softdouble&) const; + softdouble operator / (const softdouble&) const; + softdouble operator - () const { softdouble x; x.v = v ^ (1ULL << 63); return x; } + + /** @brief Remainder operator + + A quote from original SoftFloat manual: + + > The IEEE Standard remainder operation computes the value + > a - n * b, where n is the integer closest to a / b. + > If a / b is exactly halfway between two integers, n is the even integer + > closest to a / b. The IEEE Standard’s remainder operation is always exact and so requires no rounding. + > Depending on the relative magnitudes of the operands, the remainder functions + > can take considerably longer to execute than the other SoftFloat functions. + > This is an inherent characteristic of the remainder operation itself and is not a flaw + > in the SoftFloat implementation. + */ + softdouble operator % (const softdouble&) const; + + softdouble& operator += (const softdouble& a) { *this = *this + a; return *this; } + softdouble& operator -= (const softdouble& a) { *this = *this - a; return *this; } + softdouble& operator *= (const softdouble& a) { *this = *this * a; return *this; } + softdouble& operator /= (const softdouble& a) { *this = *this / a; return *this; } + softdouble& operator %= (const softdouble& a) { *this = *this % a; return *this; } + + /** @brief Comparison operations + + - Any operation with NaN produces false + + The only exception is when x is NaN: x != y for any y. + - Positive and negative zeros are equal + */ + bool operator == ( const softdouble& ) const; + bool operator != ( const softdouble& ) const; + bool operator > ( const softdouble& ) const; + bool operator >= ( const softdouble& ) const; + bool operator < ( const softdouble& ) const; + bool operator <= ( const softdouble& ) const; + + /** @brief NaN state indicator */ + inline bool isNaN() const { return (v & 0x7fffffffffffffff) > 0x7ff0000000000000; } + /** @brief Inf state indicator */ + inline bool isInf() const { return (v & 0x7fffffffffffffff) == 0x7ff0000000000000; } + /** @brief Subnormal number indicator */ + inline bool isSubnormal() const { return ((v >> 52) & 0x7FF) == 0; } + + /** @brief Get sign bit */ + inline bool getSign() const { return (v >> 63) != 0; } + /** @brief Construct a copy with new sign bit */ + softdouble setSign(bool sign) const { softdouble x; x.v = (v & ((1ULL << 63) - 1)) | ((uint_fast64_t)(sign) << 63); return x; } + /** @brief Get 0-based exponent */ + inline int getExp() const { return ((v >> 52) & 0x7FF) - 1023; } + /** @brief Construct a copy with new 0-based exponent */ + inline softdouble setExp(int e) const + { + softdouble x; + x.v = (v & 0x800FFFFFFFFFFFFF) | ((uint_fast64_t)((e + 1023) & 0x7FF) << 52); + return x; + } + + /** @brief Get a fraction part + + Returns a number 1 <= x < 2 with the same significand + */ + inline softdouble getFrac() const + { + uint_fast64_t vv = (v & 0x000FFFFFFFFFFFFF) | ((uint_fast64_t)(1023) << 52); + return softdouble::fromRaw(vv); + } + /** @brief Construct a copy with provided significand + + Constructs a copy of a number with significand taken from parameter + */ + inline softdouble setFrac(const softdouble& s) const + { + softdouble x; + x.v = (v & 0xFFF0000000000000) | (s.v & 0x000FFFFFFFFFFFFF); + return x; + } + + /** @brief Zero constant */ + static softdouble zero() { return softdouble::fromRaw( 0 ); } + /** @brief Positive infinity constant */ + static softdouble inf() { return softdouble::fromRaw( (uint_fast64_t)(0x7FF) << 52 ); } + /** @brief Default NaN constant */ + static softdouble nan() { return softdouble::fromRaw( CV_BIG_INT(0x7FFFFFFFFFFFFFFF) ); } + /** @brief One constant */ + static softdouble one() { return softdouble::fromRaw( (uint_fast64_t)( 1023) << 52 ); } + /** @brief Smallest normalized value */ + static softdouble min() { return softdouble::fromRaw( (uint_fast64_t)( 0x01) << 52 ); } + /** @brief Difference between 1 and next representable value */ + static softdouble eps() { return softdouble::fromRaw( (uint_fast64_t)( 1023 - 52 ) << 52 ); } + /** @brief Biggest finite value */ + static softdouble max() { return softdouble::fromRaw( ((uint_fast64_t)(0x7FF) << 52) - 1 ); } + /** @brief Correct pi approximation */ + static softdouble pi() { return softdouble::fromRaw( CV_BIG_INT(0x400921FB54442D18) ); } + + uint64_t v; +}; + +/*---------------------------------------------------------------------------- +*----------------------------------------------------------------------------*/ + +/** @brief Fused Multiplication and Addition + +Computes (a*b)+c with single rounding +*/ +CV_EXPORTS softfloat mulAdd( const softfloat& a, const softfloat& b, const softfloat & c); +CV_EXPORTS softdouble mulAdd( const softdouble& a, const softdouble& b, const softdouble& c); + +/** @brief Square root */ +CV_EXPORTS softfloat sqrt( const softfloat& a ); +CV_EXPORTS softdouble sqrt( const softdouble& a ); +} + +/*---------------------------------------------------------------------------- +| Ported from OpenCV and added for usability +*----------------------------------------------------------------------------*/ + +/** @brief Truncates number to integer with minimum magnitude */ +CV_EXPORTS int cvTrunc(const cv::softfloat& a); +CV_EXPORTS int cvTrunc(const cv::softdouble& a); + +/** @brief Rounds a number to nearest even integer */ +CV_EXPORTS int cvRound(const cv::softfloat& a); +CV_EXPORTS int cvRound(const cv::softdouble& a); + +/** @brief Rounds a number to nearest even long long integer */ +CV_EXPORTS int64_t cvRound64(const cv::softdouble& a); + +/** @brief Rounds a number down to integer */ +CV_EXPORTS int cvFloor(const cv::softfloat& a); +CV_EXPORTS int cvFloor(const cv::softdouble& a); + +/** @brief Rounds number up to integer */ +CV_EXPORTS int cvCeil(const cv::softfloat& a); +CV_EXPORTS int cvCeil(const cv::softdouble& a); + +namespace cv +{ +/** @brief Saturate casts */ +template static inline _Tp saturate_cast(softfloat a) { return _Tp(a); } +template static inline _Tp saturate_cast(softdouble a) { return _Tp(a); } + +template<> inline uchar saturate_cast(softfloat a) { return (uchar)std::max(std::min(cvRound(a), (int)UCHAR_MAX), 0); } +template<> inline uchar saturate_cast(softdouble a) { return (uchar)std::max(std::min(cvRound(a), (int)UCHAR_MAX), 0); } + +template<> inline schar saturate_cast(softfloat a) { return (schar)std::min(std::max(cvRound(a), (int)SCHAR_MIN), (int)SCHAR_MAX); } +template<> inline schar saturate_cast(softdouble a) { return (schar)std::min(std::max(cvRound(a), (int)SCHAR_MIN), (int)SCHAR_MAX); } + +template<> inline ushort saturate_cast(softfloat a) { return (ushort)std::max(std::min(cvRound(a), (int)USHRT_MAX), 0); } +template<> inline ushort saturate_cast(softdouble a) { return (ushort)std::max(std::min(cvRound(a), (int)USHRT_MAX), 0); } + +template<> inline short saturate_cast(softfloat a) { return (short)std::min(std::max(cvRound(a), (int)SHRT_MIN), (int)SHRT_MAX); } +template<> inline short saturate_cast(softdouble a) { return (short)std::min(std::max(cvRound(a), (int)SHRT_MIN), (int)SHRT_MAX); } + +template<> inline int saturate_cast(softfloat a) { return cvRound(a); } +template<> inline int saturate_cast(softdouble a) { return cvRound(a); } + +template<> inline int64_t saturate_cast(softfloat a) { return cvRound(a); } +template<> inline int64_t saturate_cast(softdouble a) { return cvRound64(a); } + +/** @brief Saturate cast to unsigned integer and unsigned long long integer +We intentionally do not clip negative numbers, to make -1 become 0xffffffff etc. +*/ +template<> inline unsigned saturate_cast(softfloat a) { return cvRound(a); } +template<> inline unsigned saturate_cast(softdouble a) { return cvRound(a); } + +template<> inline uint64_t saturate_cast(softfloat a) { return cvRound(a); } +template<> inline uint64_t saturate_cast(softdouble a) { return cvRound64(a); } + +/** @brief Min and Max functions */ +inline softfloat min(const softfloat& a, const softfloat& b) { return (a > b) ? b : a; } +inline softdouble min(const softdouble& a, const softdouble& b) { return (a > b) ? b : a; } + +inline softfloat max(const softfloat& a, const softfloat& b) { return (a > b) ? a : b; } +inline softdouble max(const softdouble& a, const softdouble& b) { return (a > b) ? a : b; } + +/** @brief Absolute value */ +inline softfloat abs( softfloat a) { softfloat x; x.v = a.v & ((1U << 31) - 1); return x; } +inline softdouble abs( softdouble a) { softdouble x; x.v = a.v & ((1ULL << 63) - 1); return x; } + +/** @brief Exponent + +Special cases: +- exp(NaN) is NaN +- exp(-Inf) == 0 +- exp(+Inf) == +Inf +*/ +CV_EXPORTS softfloat exp( const softfloat& a); +CV_EXPORTS softdouble exp( const softdouble& a); + +/** @brief Natural logarithm + +Special cases: +- log(NaN), log(x < 0) are NaN +- log(0) == -Inf +*/ +CV_EXPORTS softfloat log( const softfloat& a ); +CV_EXPORTS softdouble log( const softdouble& a ); + +/** @brief Raising to the power + +Special cases: +- x**NaN is NaN for any x +- ( |x| == 1 )**Inf is NaN +- ( |x| > 1 )**+Inf or ( |x| < 1 )**-Inf is +Inf +- ( |x| > 1 )**-Inf or ( |x| < 1 )**+Inf is 0 +- x ** 0 == 1 for any x +- x ** 1 == 1 for any x +- NaN ** y is NaN for any other y +- Inf**(y < 0) == 0 +- Inf ** y is +Inf for any other y +- (x < 0)**y is NaN for any other y if x can't be correctly rounded to integer +- 0 ** 0 == 1 +- 0 ** (y < 0) is +Inf +- 0 ** (y > 0) is 0 +*/ +CV_EXPORTS softfloat pow( const softfloat& a, const softfloat& b); +CV_EXPORTS softdouble pow( const softdouble& a, const softdouble& b); + +/** @brief Cube root + +Special cases: +- cbrt(NaN) is NaN +- cbrt(+/-Inf) is +/-Inf +*/ +CV_EXPORTS softfloat cbrt( const softfloat& a ); + +/** @brief Sine + +Special cases: +- sin(Inf) or sin(NaN) is NaN +- sin(x) == x when sin(x) is close to zero +*/ +CV_EXPORTS softdouble sin( const softdouble& a ); + +/** @brief Cosine + * +Special cases: +- cos(Inf) or cos(NaN) is NaN +- cos(x) == +/- 1 when cos(x) is close to +/- 1 +*/ +CV_EXPORTS softdouble cos( const softdouble& a ); + +//! @} core_utils_softfloat + +} // cv:: + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/sse_utils.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/sse_utils.hpp new file mode 100644 index 0000000..0906583 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/sse_utils.hpp @@ -0,0 +1,652 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_SSE_UTILS_HPP +#define OPENCV_CORE_SSE_UTILS_HPP + +#ifndef __cplusplus +# error sse_utils.hpp header must be compiled as C++ +#endif + +#include "opencv2/core/cvdef.h" + +//! @addtogroup core_utils_sse +//! @{ + +#if CV_SSE2 + +inline void _mm_deinterleave_epi8(__m128i & v_r0, __m128i & v_r1, __m128i & v_g0, __m128i & v_g1) +{ + __m128i layer1_chunk0 = _mm_unpacklo_epi8(v_r0, v_g0); + __m128i layer1_chunk1 = _mm_unpackhi_epi8(v_r0, v_g0); + __m128i layer1_chunk2 = _mm_unpacklo_epi8(v_r1, v_g1); + __m128i layer1_chunk3 = _mm_unpackhi_epi8(v_r1, v_g1); + + __m128i layer2_chunk0 = _mm_unpacklo_epi8(layer1_chunk0, layer1_chunk2); + __m128i layer2_chunk1 = _mm_unpackhi_epi8(layer1_chunk0, layer1_chunk2); + __m128i layer2_chunk2 = _mm_unpacklo_epi8(layer1_chunk1, layer1_chunk3); + __m128i layer2_chunk3 = _mm_unpackhi_epi8(layer1_chunk1, layer1_chunk3); + + __m128i layer3_chunk0 = _mm_unpacklo_epi8(layer2_chunk0, layer2_chunk2); + __m128i layer3_chunk1 = _mm_unpackhi_epi8(layer2_chunk0, layer2_chunk2); + __m128i layer3_chunk2 = _mm_unpacklo_epi8(layer2_chunk1, layer2_chunk3); + __m128i layer3_chunk3 = _mm_unpackhi_epi8(layer2_chunk1, layer2_chunk3); + + __m128i layer4_chunk0 = _mm_unpacklo_epi8(layer3_chunk0, layer3_chunk2); + __m128i layer4_chunk1 = _mm_unpackhi_epi8(layer3_chunk0, layer3_chunk2); + __m128i layer4_chunk2 = _mm_unpacklo_epi8(layer3_chunk1, layer3_chunk3); + __m128i layer4_chunk3 = _mm_unpackhi_epi8(layer3_chunk1, layer3_chunk3); + + v_r0 = _mm_unpacklo_epi8(layer4_chunk0, layer4_chunk2); + v_r1 = _mm_unpackhi_epi8(layer4_chunk0, layer4_chunk2); + v_g0 = _mm_unpacklo_epi8(layer4_chunk1, layer4_chunk3); + v_g1 = _mm_unpackhi_epi8(layer4_chunk1, layer4_chunk3); +} + +inline void _mm_deinterleave_epi8(__m128i & v_r0, __m128i & v_r1, __m128i & v_g0, + __m128i & v_g1, __m128i & v_b0, __m128i & v_b1) +{ + __m128i layer1_chunk0 = _mm_unpacklo_epi8(v_r0, v_g1); + __m128i layer1_chunk1 = _mm_unpackhi_epi8(v_r0, v_g1); + __m128i layer1_chunk2 = _mm_unpacklo_epi8(v_r1, v_b0); + __m128i layer1_chunk3 = _mm_unpackhi_epi8(v_r1, v_b0); + __m128i layer1_chunk4 = _mm_unpacklo_epi8(v_g0, v_b1); + __m128i layer1_chunk5 = _mm_unpackhi_epi8(v_g0, v_b1); + + __m128i layer2_chunk0 = _mm_unpacklo_epi8(layer1_chunk0, layer1_chunk3); + __m128i layer2_chunk1 = _mm_unpackhi_epi8(layer1_chunk0, layer1_chunk3); + __m128i layer2_chunk2 = _mm_unpacklo_epi8(layer1_chunk1, layer1_chunk4); + __m128i layer2_chunk3 = _mm_unpackhi_epi8(layer1_chunk1, layer1_chunk4); + __m128i layer2_chunk4 = _mm_unpacklo_epi8(layer1_chunk2, layer1_chunk5); + __m128i layer2_chunk5 = _mm_unpackhi_epi8(layer1_chunk2, layer1_chunk5); + + __m128i layer3_chunk0 = _mm_unpacklo_epi8(layer2_chunk0, layer2_chunk3); + __m128i layer3_chunk1 = _mm_unpackhi_epi8(layer2_chunk0, layer2_chunk3); + __m128i layer3_chunk2 = _mm_unpacklo_epi8(layer2_chunk1, layer2_chunk4); + __m128i layer3_chunk3 = _mm_unpackhi_epi8(layer2_chunk1, layer2_chunk4); + __m128i layer3_chunk4 = _mm_unpacklo_epi8(layer2_chunk2, layer2_chunk5); + __m128i layer3_chunk5 = _mm_unpackhi_epi8(layer2_chunk2, layer2_chunk5); + + __m128i layer4_chunk0 = _mm_unpacklo_epi8(layer3_chunk0, layer3_chunk3); + __m128i layer4_chunk1 = _mm_unpackhi_epi8(layer3_chunk0, layer3_chunk3); + __m128i layer4_chunk2 = _mm_unpacklo_epi8(layer3_chunk1, layer3_chunk4); + __m128i layer4_chunk3 = _mm_unpackhi_epi8(layer3_chunk1, layer3_chunk4); + __m128i layer4_chunk4 = _mm_unpacklo_epi8(layer3_chunk2, layer3_chunk5); + __m128i layer4_chunk5 = _mm_unpackhi_epi8(layer3_chunk2, layer3_chunk5); + + v_r0 = _mm_unpacklo_epi8(layer4_chunk0, layer4_chunk3); + v_r1 = _mm_unpackhi_epi8(layer4_chunk0, layer4_chunk3); + v_g0 = _mm_unpacklo_epi8(layer4_chunk1, layer4_chunk4); + v_g1 = _mm_unpackhi_epi8(layer4_chunk1, layer4_chunk4); + v_b0 = _mm_unpacklo_epi8(layer4_chunk2, layer4_chunk5); + v_b1 = _mm_unpackhi_epi8(layer4_chunk2, layer4_chunk5); +} + +inline void _mm_deinterleave_epi8(__m128i & v_r0, __m128i & v_r1, __m128i & v_g0, __m128i & v_g1, + __m128i & v_b0, __m128i & v_b1, __m128i & v_a0, __m128i & v_a1) +{ + __m128i layer1_chunk0 = _mm_unpacklo_epi8(v_r0, v_b0); + __m128i layer1_chunk1 = _mm_unpackhi_epi8(v_r0, v_b0); + __m128i layer1_chunk2 = _mm_unpacklo_epi8(v_r1, v_b1); + __m128i layer1_chunk3 = _mm_unpackhi_epi8(v_r1, v_b1); + __m128i layer1_chunk4 = _mm_unpacklo_epi8(v_g0, v_a0); + __m128i layer1_chunk5 = _mm_unpackhi_epi8(v_g0, v_a0); + __m128i layer1_chunk6 = _mm_unpacklo_epi8(v_g1, v_a1); + __m128i layer1_chunk7 = _mm_unpackhi_epi8(v_g1, v_a1); + + __m128i layer2_chunk0 = _mm_unpacklo_epi8(layer1_chunk0, layer1_chunk4); + __m128i layer2_chunk1 = _mm_unpackhi_epi8(layer1_chunk0, layer1_chunk4); + __m128i layer2_chunk2 = _mm_unpacklo_epi8(layer1_chunk1, layer1_chunk5); + __m128i layer2_chunk3 = _mm_unpackhi_epi8(layer1_chunk1, layer1_chunk5); + __m128i layer2_chunk4 = _mm_unpacklo_epi8(layer1_chunk2, layer1_chunk6); + __m128i layer2_chunk5 = _mm_unpackhi_epi8(layer1_chunk2, layer1_chunk6); + __m128i layer2_chunk6 = _mm_unpacklo_epi8(layer1_chunk3, layer1_chunk7); + __m128i layer2_chunk7 = _mm_unpackhi_epi8(layer1_chunk3, layer1_chunk7); + + __m128i layer3_chunk0 = _mm_unpacklo_epi8(layer2_chunk0, layer2_chunk4); + __m128i layer3_chunk1 = _mm_unpackhi_epi8(layer2_chunk0, layer2_chunk4); + __m128i layer3_chunk2 = _mm_unpacklo_epi8(layer2_chunk1, layer2_chunk5); + __m128i layer3_chunk3 = _mm_unpackhi_epi8(layer2_chunk1, layer2_chunk5); + __m128i layer3_chunk4 = _mm_unpacklo_epi8(layer2_chunk2, layer2_chunk6); + __m128i layer3_chunk5 = _mm_unpackhi_epi8(layer2_chunk2, layer2_chunk6); + __m128i layer3_chunk6 = _mm_unpacklo_epi8(layer2_chunk3, layer2_chunk7); + __m128i layer3_chunk7 = _mm_unpackhi_epi8(layer2_chunk3, layer2_chunk7); + + __m128i layer4_chunk0 = _mm_unpacklo_epi8(layer3_chunk0, layer3_chunk4); + __m128i layer4_chunk1 = _mm_unpackhi_epi8(layer3_chunk0, layer3_chunk4); + __m128i layer4_chunk2 = _mm_unpacklo_epi8(layer3_chunk1, layer3_chunk5); + __m128i layer4_chunk3 = _mm_unpackhi_epi8(layer3_chunk1, layer3_chunk5); + __m128i layer4_chunk4 = _mm_unpacklo_epi8(layer3_chunk2, layer3_chunk6); + __m128i layer4_chunk5 = _mm_unpackhi_epi8(layer3_chunk2, layer3_chunk6); + __m128i layer4_chunk6 = _mm_unpacklo_epi8(layer3_chunk3, layer3_chunk7); + __m128i layer4_chunk7 = _mm_unpackhi_epi8(layer3_chunk3, layer3_chunk7); + + v_r0 = _mm_unpacklo_epi8(layer4_chunk0, layer4_chunk4); + v_r1 = _mm_unpackhi_epi8(layer4_chunk0, layer4_chunk4); + v_g0 = _mm_unpacklo_epi8(layer4_chunk1, layer4_chunk5); + v_g1 = _mm_unpackhi_epi8(layer4_chunk1, layer4_chunk5); + v_b0 = _mm_unpacklo_epi8(layer4_chunk2, layer4_chunk6); + v_b1 = _mm_unpackhi_epi8(layer4_chunk2, layer4_chunk6); + v_a0 = _mm_unpacklo_epi8(layer4_chunk3, layer4_chunk7); + v_a1 = _mm_unpackhi_epi8(layer4_chunk3, layer4_chunk7); +} + +inline void _mm_interleave_epi8(__m128i & v_r0, __m128i & v_r1, __m128i & v_g0, __m128i & v_g1) +{ + __m128i v_mask = _mm_set1_epi16(0x00ff); + + __m128i layer4_chunk0 = _mm_packus_epi16(_mm_and_si128(v_r0, v_mask), _mm_and_si128(v_r1, v_mask)); + __m128i layer4_chunk2 = _mm_packus_epi16(_mm_srli_epi16(v_r0, 8), _mm_srli_epi16(v_r1, 8)); + __m128i layer4_chunk1 = _mm_packus_epi16(_mm_and_si128(v_g0, v_mask), _mm_and_si128(v_g1, v_mask)); + __m128i layer4_chunk3 = _mm_packus_epi16(_mm_srli_epi16(v_g0, 8), _mm_srli_epi16(v_g1, 8)); + + __m128i layer3_chunk0 = _mm_packus_epi16(_mm_and_si128(layer4_chunk0, v_mask), _mm_and_si128(layer4_chunk1, v_mask)); + __m128i layer3_chunk2 = _mm_packus_epi16(_mm_srli_epi16(layer4_chunk0, 8), _mm_srli_epi16(layer4_chunk1, 8)); + __m128i layer3_chunk1 = _mm_packus_epi16(_mm_and_si128(layer4_chunk2, v_mask), _mm_and_si128(layer4_chunk3, v_mask)); + __m128i layer3_chunk3 = _mm_packus_epi16(_mm_srli_epi16(layer4_chunk2, 8), _mm_srli_epi16(layer4_chunk3, 8)); + + __m128i layer2_chunk0 = _mm_packus_epi16(_mm_and_si128(layer3_chunk0, v_mask), _mm_and_si128(layer3_chunk1, v_mask)); + __m128i layer2_chunk2 = _mm_packus_epi16(_mm_srli_epi16(layer3_chunk0, 8), _mm_srli_epi16(layer3_chunk1, 8)); + __m128i layer2_chunk1 = _mm_packus_epi16(_mm_and_si128(layer3_chunk2, v_mask), _mm_and_si128(layer3_chunk3, v_mask)); + __m128i layer2_chunk3 = _mm_packus_epi16(_mm_srli_epi16(layer3_chunk2, 8), _mm_srli_epi16(layer3_chunk3, 8)); + + __m128i layer1_chunk0 = _mm_packus_epi16(_mm_and_si128(layer2_chunk0, v_mask), _mm_and_si128(layer2_chunk1, v_mask)); + __m128i layer1_chunk2 = _mm_packus_epi16(_mm_srli_epi16(layer2_chunk0, 8), _mm_srli_epi16(layer2_chunk1, 8)); + __m128i layer1_chunk1 = _mm_packus_epi16(_mm_and_si128(layer2_chunk2, v_mask), _mm_and_si128(layer2_chunk3, v_mask)); + __m128i layer1_chunk3 = _mm_packus_epi16(_mm_srli_epi16(layer2_chunk2, 8), _mm_srli_epi16(layer2_chunk3, 8)); + + v_r0 = _mm_packus_epi16(_mm_and_si128(layer1_chunk0, v_mask), _mm_and_si128(layer1_chunk1, v_mask)); + v_g0 = _mm_packus_epi16(_mm_srli_epi16(layer1_chunk0, 8), _mm_srli_epi16(layer1_chunk1, 8)); + v_r1 = _mm_packus_epi16(_mm_and_si128(layer1_chunk2, v_mask), _mm_and_si128(layer1_chunk3, v_mask)); + v_g1 = _mm_packus_epi16(_mm_srli_epi16(layer1_chunk2, 8), _mm_srli_epi16(layer1_chunk3, 8)); +} + +inline void _mm_interleave_epi8(__m128i & v_r0, __m128i & v_r1, __m128i & v_g0, + __m128i & v_g1, __m128i & v_b0, __m128i & v_b1) +{ + __m128i v_mask = _mm_set1_epi16(0x00ff); + + __m128i layer4_chunk0 = _mm_packus_epi16(_mm_and_si128(v_r0, v_mask), _mm_and_si128(v_r1, v_mask)); + __m128i layer4_chunk3 = _mm_packus_epi16(_mm_srli_epi16(v_r0, 8), _mm_srli_epi16(v_r1, 8)); + __m128i layer4_chunk1 = _mm_packus_epi16(_mm_and_si128(v_g0, v_mask), _mm_and_si128(v_g1, v_mask)); + __m128i layer4_chunk4 = _mm_packus_epi16(_mm_srli_epi16(v_g0, 8), _mm_srli_epi16(v_g1, 8)); + __m128i layer4_chunk2 = _mm_packus_epi16(_mm_and_si128(v_b0, v_mask), _mm_and_si128(v_b1, v_mask)); + __m128i layer4_chunk5 = _mm_packus_epi16(_mm_srli_epi16(v_b0, 8), _mm_srli_epi16(v_b1, 8)); + + __m128i layer3_chunk0 = _mm_packus_epi16(_mm_and_si128(layer4_chunk0, v_mask), _mm_and_si128(layer4_chunk1, v_mask)); + __m128i layer3_chunk3 = _mm_packus_epi16(_mm_srli_epi16(layer4_chunk0, 8), _mm_srli_epi16(layer4_chunk1, 8)); + __m128i layer3_chunk1 = _mm_packus_epi16(_mm_and_si128(layer4_chunk2, v_mask), _mm_and_si128(layer4_chunk3, v_mask)); + __m128i layer3_chunk4 = _mm_packus_epi16(_mm_srli_epi16(layer4_chunk2, 8), _mm_srli_epi16(layer4_chunk3, 8)); + __m128i layer3_chunk2 = _mm_packus_epi16(_mm_and_si128(layer4_chunk4, v_mask), _mm_and_si128(layer4_chunk5, v_mask)); + __m128i layer3_chunk5 = _mm_packus_epi16(_mm_srli_epi16(layer4_chunk4, 8), _mm_srli_epi16(layer4_chunk5, 8)); + + __m128i layer2_chunk0 = _mm_packus_epi16(_mm_and_si128(layer3_chunk0, v_mask), _mm_and_si128(layer3_chunk1, v_mask)); + __m128i layer2_chunk3 = _mm_packus_epi16(_mm_srli_epi16(layer3_chunk0, 8), _mm_srli_epi16(layer3_chunk1, 8)); + __m128i layer2_chunk1 = _mm_packus_epi16(_mm_and_si128(layer3_chunk2, v_mask), _mm_and_si128(layer3_chunk3, v_mask)); + __m128i layer2_chunk4 = _mm_packus_epi16(_mm_srli_epi16(layer3_chunk2, 8), _mm_srli_epi16(layer3_chunk3, 8)); + __m128i layer2_chunk2 = _mm_packus_epi16(_mm_and_si128(layer3_chunk4, v_mask), _mm_and_si128(layer3_chunk5, v_mask)); + __m128i layer2_chunk5 = _mm_packus_epi16(_mm_srli_epi16(layer3_chunk4, 8), _mm_srli_epi16(layer3_chunk5, 8)); + + __m128i layer1_chunk0 = _mm_packus_epi16(_mm_and_si128(layer2_chunk0, v_mask), _mm_and_si128(layer2_chunk1, v_mask)); + __m128i layer1_chunk3 = _mm_packus_epi16(_mm_srli_epi16(layer2_chunk0, 8), _mm_srli_epi16(layer2_chunk1, 8)); + __m128i layer1_chunk1 = _mm_packus_epi16(_mm_and_si128(layer2_chunk2, v_mask), _mm_and_si128(layer2_chunk3, v_mask)); + __m128i layer1_chunk4 = _mm_packus_epi16(_mm_srli_epi16(layer2_chunk2, 8), _mm_srli_epi16(layer2_chunk3, 8)); + __m128i layer1_chunk2 = _mm_packus_epi16(_mm_and_si128(layer2_chunk4, v_mask), _mm_and_si128(layer2_chunk5, v_mask)); + __m128i layer1_chunk5 = _mm_packus_epi16(_mm_srli_epi16(layer2_chunk4, 8), _mm_srli_epi16(layer2_chunk5, 8)); + + v_r0 = _mm_packus_epi16(_mm_and_si128(layer1_chunk0, v_mask), _mm_and_si128(layer1_chunk1, v_mask)); + v_g1 = _mm_packus_epi16(_mm_srli_epi16(layer1_chunk0, 8), _mm_srli_epi16(layer1_chunk1, 8)); + v_r1 = _mm_packus_epi16(_mm_and_si128(layer1_chunk2, v_mask), _mm_and_si128(layer1_chunk3, v_mask)); + v_b0 = _mm_packus_epi16(_mm_srli_epi16(layer1_chunk2, 8), _mm_srli_epi16(layer1_chunk3, 8)); + v_g0 = _mm_packus_epi16(_mm_and_si128(layer1_chunk4, v_mask), _mm_and_si128(layer1_chunk5, v_mask)); + v_b1 = _mm_packus_epi16(_mm_srli_epi16(layer1_chunk4, 8), _mm_srli_epi16(layer1_chunk5, 8)); +} + +inline void _mm_interleave_epi8(__m128i & v_r0, __m128i & v_r1, __m128i & v_g0, __m128i & v_g1, + __m128i & v_b0, __m128i & v_b1, __m128i & v_a0, __m128i & v_a1) +{ + __m128i v_mask = _mm_set1_epi16(0x00ff); + + __m128i layer4_chunk0 = _mm_packus_epi16(_mm_and_si128(v_r0, v_mask), _mm_and_si128(v_r1, v_mask)); + __m128i layer4_chunk4 = _mm_packus_epi16(_mm_srli_epi16(v_r0, 8), _mm_srli_epi16(v_r1, 8)); + __m128i layer4_chunk1 = _mm_packus_epi16(_mm_and_si128(v_g0, v_mask), _mm_and_si128(v_g1, v_mask)); + __m128i layer4_chunk5 = _mm_packus_epi16(_mm_srli_epi16(v_g0, 8), _mm_srli_epi16(v_g1, 8)); + __m128i layer4_chunk2 = _mm_packus_epi16(_mm_and_si128(v_b0, v_mask), _mm_and_si128(v_b1, v_mask)); + __m128i layer4_chunk6 = _mm_packus_epi16(_mm_srli_epi16(v_b0, 8), _mm_srli_epi16(v_b1, 8)); + __m128i layer4_chunk3 = _mm_packus_epi16(_mm_and_si128(v_a0, v_mask), _mm_and_si128(v_a1, v_mask)); + __m128i layer4_chunk7 = _mm_packus_epi16(_mm_srli_epi16(v_a0, 8), _mm_srli_epi16(v_a1, 8)); + + __m128i layer3_chunk0 = _mm_packus_epi16(_mm_and_si128(layer4_chunk0, v_mask), _mm_and_si128(layer4_chunk1, v_mask)); + __m128i layer3_chunk4 = _mm_packus_epi16(_mm_srli_epi16(layer4_chunk0, 8), _mm_srli_epi16(layer4_chunk1, 8)); + __m128i layer3_chunk1 = _mm_packus_epi16(_mm_and_si128(layer4_chunk2, v_mask), _mm_and_si128(layer4_chunk3, v_mask)); + __m128i layer3_chunk5 = _mm_packus_epi16(_mm_srli_epi16(layer4_chunk2, 8), _mm_srli_epi16(layer4_chunk3, 8)); + __m128i layer3_chunk2 = _mm_packus_epi16(_mm_and_si128(layer4_chunk4, v_mask), _mm_and_si128(layer4_chunk5, v_mask)); + __m128i layer3_chunk6 = _mm_packus_epi16(_mm_srli_epi16(layer4_chunk4, 8), _mm_srli_epi16(layer4_chunk5, 8)); + __m128i layer3_chunk3 = _mm_packus_epi16(_mm_and_si128(layer4_chunk6, v_mask), _mm_and_si128(layer4_chunk7, v_mask)); + __m128i layer3_chunk7 = _mm_packus_epi16(_mm_srli_epi16(layer4_chunk6, 8), _mm_srli_epi16(layer4_chunk7, 8)); + + __m128i layer2_chunk0 = _mm_packus_epi16(_mm_and_si128(layer3_chunk0, v_mask), _mm_and_si128(layer3_chunk1, v_mask)); + __m128i layer2_chunk4 = _mm_packus_epi16(_mm_srli_epi16(layer3_chunk0, 8), _mm_srli_epi16(layer3_chunk1, 8)); + __m128i layer2_chunk1 = _mm_packus_epi16(_mm_and_si128(layer3_chunk2, v_mask), _mm_and_si128(layer3_chunk3, v_mask)); + __m128i layer2_chunk5 = _mm_packus_epi16(_mm_srli_epi16(layer3_chunk2, 8), _mm_srli_epi16(layer3_chunk3, 8)); + __m128i layer2_chunk2 = _mm_packus_epi16(_mm_and_si128(layer3_chunk4, v_mask), _mm_and_si128(layer3_chunk5, v_mask)); + __m128i layer2_chunk6 = _mm_packus_epi16(_mm_srli_epi16(layer3_chunk4, 8), _mm_srli_epi16(layer3_chunk5, 8)); + __m128i layer2_chunk3 = _mm_packus_epi16(_mm_and_si128(layer3_chunk6, v_mask), _mm_and_si128(layer3_chunk7, v_mask)); + __m128i layer2_chunk7 = _mm_packus_epi16(_mm_srli_epi16(layer3_chunk6, 8), _mm_srli_epi16(layer3_chunk7, 8)); + + __m128i layer1_chunk0 = _mm_packus_epi16(_mm_and_si128(layer2_chunk0, v_mask), _mm_and_si128(layer2_chunk1, v_mask)); + __m128i layer1_chunk4 = _mm_packus_epi16(_mm_srli_epi16(layer2_chunk0, 8), _mm_srli_epi16(layer2_chunk1, 8)); + __m128i layer1_chunk1 = _mm_packus_epi16(_mm_and_si128(layer2_chunk2, v_mask), _mm_and_si128(layer2_chunk3, v_mask)); + __m128i layer1_chunk5 = _mm_packus_epi16(_mm_srli_epi16(layer2_chunk2, 8), _mm_srli_epi16(layer2_chunk3, 8)); + __m128i layer1_chunk2 = _mm_packus_epi16(_mm_and_si128(layer2_chunk4, v_mask), _mm_and_si128(layer2_chunk5, v_mask)); + __m128i layer1_chunk6 = _mm_packus_epi16(_mm_srli_epi16(layer2_chunk4, 8), _mm_srli_epi16(layer2_chunk5, 8)); + __m128i layer1_chunk3 = _mm_packus_epi16(_mm_and_si128(layer2_chunk6, v_mask), _mm_and_si128(layer2_chunk7, v_mask)); + __m128i layer1_chunk7 = _mm_packus_epi16(_mm_srli_epi16(layer2_chunk6, 8), _mm_srli_epi16(layer2_chunk7, 8)); + + v_r0 = _mm_packus_epi16(_mm_and_si128(layer1_chunk0, v_mask), _mm_and_si128(layer1_chunk1, v_mask)); + v_b0 = _mm_packus_epi16(_mm_srli_epi16(layer1_chunk0, 8), _mm_srli_epi16(layer1_chunk1, 8)); + v_r1 = _mm_packus_epi16(_mm_and_si128(layer1_chunk2, v_mask), _mm_and_si128(layer1_chunk3, v_mask)); + v_b1 = _mm_packus_epi16(_mm_srli_epi16(layer1_chunk2, 8), _mm_srli_epi16(layer1_chunk3, 8)); + v_g0 = _mm_packus_epi16(_mm_and_si128(layer1_chunk4, v_mask), _mm_and_si128(layer1_chunk5, v_mask)); + v_a0 = _mm_packus_epi16(_mm_srli_epi16(layer1_chunk4, 8), _mm_srli_epi16(layer1_chunk5, 8)); + v_g1 = _mm_packus_epi16(_mm_and_si128(layer1_chunk6, v_mask), _mm_and_si128(layer1_chunk7, v_mask)); + v_a1 = _mm_packus_epi16(_mm_srli_epi16(layer1_chunk6, 8), _mm_srli_epi16(layer1_chunk7, 8)); +} + +inline void _mm_deinterleave_epi16(__m128i & v_r0, __m128i & v_r1, __m128i & v_g0, __m128i & v_g1) +{ + __m128i layer1_chunk0 = _mm_unpacklo_epi16(v_r0, v_g0); + __m128i layer1_chunk1 = _mm_unpackhi_epi16(v_r0, v_g0); + __m128i layer1_chunk2 = _mm_unpacklo_epi16(v_r1, v_g1); + __m128i layer1_chunk3 = _mm_unpackhi_epi16(v_r1, v_g1); + + __m128i layer2_chunk0 = _mm_unpacklo_epi16(layer1_chunk0, layer1_chunk2); + __m128i layer2_chunk1 = _mm_unpackhi_epi16(layer1_chunk0, layer1_chunk2); + __m128i layer2_chunk2 = _mm_unpacklo_epi16(layer1_chunk1, layer1_chunk3); + __m128i layer2_chunk3 = _mm_unpackhi_epi16(layer1_chunk1, layer1_chunk3); + + __m128i layer3_chunk0 = _mm_unpacklo_epi16(layer2_chunk0, layer2_chunk2); + __m128i layer3_chunk1 = _mm_unpackhi_epi16(layer2_chunk0, layer2_chunk2); + __m128i layer3_chunk2 = _mm_unpacklo_epi16(layer2_chunk1, layer2_chunk3); + __m128i layer3_chunk3 = _mm_unpackhi_epi16(layer2_chunk1, layer2_chunk3); + + v_r0 = _mm_unpacklo_epi16(layer3_chunk0, layer3_chunk2); + v_r1 = _mm_unpackhi_epi16(layer3_chunk0, layer3_chunk2); + v_g0 = _mm_unpacklo_epi16(layer3_chunk1, layer3_chunk3); + v_g1 = _mm_unpackhi_epi16(layer3_chunk1, layer3_chunk3); +} + +inline void _mm_deinterleave_epi16(__m128i & v_r0, __m128i & v_r1, __m128i & v_g0, + __m128i & v_g1, __m128i & v_b0, __m128i & v_b1) +{ + __m128i layer1_chunk0 = _mm_unpacklo_epi16(v_r0, v_g1); + __m128i layer1_chunk1 = _mm_unpackhi_epi16(v_r0, v_g1); + __m128i layer1_chunk2 = _mm_unpacklo_epi16(v_r1, v_b0); + __m128i layer1_chunk3 = _mm_unpackhi_epi16(v_r1, v_b0); + __m128i layer1_chunk4 = _mm_unpacklo_epi16(v_g0, v_b1); + __m128i layer1_chunk5 = _mm_unpackhi_epi16(v_g0, v_b1); + + __m128i layer2_chunk0 = _mm_unpacklo_epi16(layer1_chunk0, layer1_chunk3); + __m128i layer2_chunk1 = _mm_unpackhi_epi16(layer1_chunk0, layer1_chunk3); + __m128i layer2_chunk2 = _mm_unpacklo_epi16(layer1_chunk1, layer1_chunk4); + __m128i layer2_chunk3 = _mm_unpackhi_epi16(layer1_chunk1, layer1_chunk4); + __m128i layer2_chunk4 = _mm_unpacklo_epi16(layer1_chunk2, layer1_chunk5); + __m128i layer2_chunk5 = _mm_unpackhi_epi16(layer1_chunk2, layer1_chunk5); + + __m128i layer3_chunk0 = _mm_unpacklo_epi16(layer2_chunk0, layer2_chunk3); + __m128i layer3_chunk1 = _mm_unpackhi_epi16(layer2_chunk0, layer2_chunk3); + __m128i layer3_chunk2 = _mm_unpacklo_epi16(layer2_chunk1, layer2_chunk4); + __m128i layer3_chunk3 = _mm_unpackhi_epi16(layer2_chunk1, layer2_chunk4); + __m128i layer3_chunk4 = _mm_unpacklo_epi16(layer2_chunk2, layer2_chunk5); + __m128i layer3_chunk5 = _mm_unpackhi_epi16(layer2_chunk2, layer2_chunk5); + + v_r0 = _mm_unpacklo_epi16(layer3_chunk0, layer3_chunk3); + v_r1 = _mm_unpackhi_epi16(layer3_chunk0, layer3_chunk3); + v_g0 = _mm_unpacklo_epi16(layer3_chunk1, layer3_chunk4); + v_g1 = _mm_unpackhi_epi16(layer3_chunk1, layer3_chunk4); + v_b0 = _mm_unpacklo_epi16(layer3_chunk2, layer3_chunk5); + v_b1 = _mm_unpackhi_epi16(layer3_chunk2, layer3_chunk5); +} + +inline void _mm_deinterleave_epi16(__m128i & v_r0, __m128i & v_r1, __m128i & v_g0, __m128i & v_g1, + __m128i & v_b0, __m128i & v_b1, __m128i & v_a0, __m128i & v_a1) +{ + __m128i layer1_chunk0 = _mm_unpacklo_epi16(v_r0, v_b0); + __m128i layer1_chunk1 = _mm_unpackhi_epi16(v_r0, v_b0); + __m128i layer1_chunk2 = _mm_unpacklo_epi16(v_r1, v_b1); + __m128i layer1_chunk3 = _mm_unpackhi_epi16(v_r1, v_b1); + __m128i layer1_chunk4 = _mm_unpacklo_epi16(v_g0, v_a0); + __m128i layer1_chunk5 = _mm_unpackhi_epi16(v_g0, v_a0); + __m128i layer1_chunk6 = _mm_unpacklo_epi16(v_g1, v_a1); + __m128i layer1_chunk7 = _mm_unpackhi_epi16(v_g1, v_a1); + + __m128i layer2_chunk0 = _mm_unpacklo_epi16(layer1_chunk0, layer1_chunk4); + __m128i layer2_chunk1 = _mm_unpackhi_epi16(layer1_chunk0, layer1_chunk4); + __m128i layer2_chunk2 = _mm_unpacklo_epi16(layer1_chunk1, layer1_chunk5); + __m128i layer2_chunk3 = _mm_unpackhi_epi16(layer1_chunk1, layer1_chunk5); + __m128i layer2_chunk4 = _mm_unpacklo_epi16(layer1_chunk2, layer1_chunk6); + __m128i layer2_chunk5 = _mm_unpackhi_epi16(layer1_chunk2, layer1_chunk6); + __m128i layer2_chunk6 = _mm_unpacklo_epi16(layer1_chunk3, layer1_chunk7); + __m128i layer2_chunk7 = _mm_unpackhi_epi16(layer1_chunk3, layer1_chunk7); + + __m128i layer3_chunk0 = _mm_unpacklo_epi16(layer2_chunk0, layer2_chunk4); + __m128i layer3_chunk1 = _mm_unpackhi_epi16(layer2_chunk0, layer2_chunk4); + __m128i layer3_chunk2 = _mm_unpacklo_epi16(layer2_chunk1, layer2_chunk5); + __m128i layer3_chunk3 = _mm_unpackhi_epi16(layer2_chunk1, layer2_chunk5); + __m128i layer3_chunk4 = _mm_unpacklo_epi16(layer2_chunk2, layer2_chunk6); + __m128i layer3_chunk5 = _mm_unpackhi_epi16(layer2_chunk2, layer2_chunk6); + __m128i layer3_chunk6 = _mm_unpacklo_epi16(layer2_chunk3, layer2_chunk7); + __m128i layer3_chunk7 = _mm_unpackhi_epi16(layer2_chunk3, layer2_chunk7); + + v_r0 = _mm_unpacklo_epi16(layer3_chunk0, layer3_chunk4); + v_r1 = _mm_unpackhi_epi16(layer3_chunk0, layer3_chunk4); + v_g0 = _mm_unpacklo_epi16(layer3_chunk1, layer3_chunk5); + v_g1 = _mm_unpackhi_epi16(layer3_chunk1, layer3_chunk5); + v_b0 = _mm_unpacklo_epi16(layer3_chunk2, layer3_chunk6); + v_b1 = _mm_unpackhi_epi16(layer3_chunk2, layer3_chunk6); + v_a0 = _mm_unpacklo_epi16(layer3_chunk3, layer3_chunk7); + v_a1 = _mm_unpackhi_epi16(layer3_chunk3, layer3_chunk7); +} + +#if CV_SSE4_1 + +inline void _mm_interleave_epi16(__m128i & v_r0, __m128i & v_r1, __m128i & v_g0, __m128i & v_g1) +{ + __m128i v_mask = _mm_set1_epi32(0x0000ffff); + + __m128i layer3_chunk0 = _mm_packus_epi32(_mm_and_si128(v_r0, v_mask), _mm_and_si128(v_r1, v_mask)); + __m128i layer3_chunk2 = _mm_packus_epi32(_mm_srli_epi32(v_r0, 16), _mm_srli_epi32(v_r1, 16)); + __m128i layer3_chunk1 = _mm_packus_epi32(_mm_and_si128(v_g0, v_mask), _mm_and_si128(v_g1, v_mask)); + __m128i layer3_chunk3 = _mm_packus_epi32(_mm_srli_epi32(v_g0, 16), _mm_srli_epi32(v_g1, 16)); + + __m128i layer2_chunk0 = _mm_packus_epi32(_mm_and_si128(layer3_chunk0, v_mask), _mm_and_si128(layer3_chunk1, v_mask)); + __m128i layer2_chunk2 = _mm_packus_epi32(_mm_srli_epi32(layer3_chunk0, 16), _mm_srli_epi32(layer3_chunk1, 16)); + __m128i layer2_chunk1 = _mm_packus_epi32(_mm_and_si128(layer3_chunk2, v_mask), _mm_and_si128(layer3_chunk3, v_mask)); + __m128i layer2_chunk3 = _mm_packus_epi32(_mm_srli_epi32(layer3_chunk2, 16), _mm_srli_epi32(layer3_chunk3, 16)); + + __m128i layer1_chunk0 = _mm_packus_epi32(_mm_and_si128(layer2_chunk0, v_mask), _mm_and_si128(layer2_chunk1, v_mask)); + __m128i layer1_chunk2 = _mm_packus_epi32(_mm_srli_epi32(layer2_chunk0, 16), _mm_srli_epi32(layer2_chunk1, 16)); + __m128i layer1_chunk1 = _mm_packus_epi32(_mm_and_si128(layer2_chunk2, v_mask), _mm_and_si128(layer2_chunk3, v_mask)); + __m128i layer1_chunk3 = _mm_packus_epi32(_mm_srli_epi32(layer2_chunk2, 16), _mm_srli_epi32(layer2_chunk3, 16)); + + v_r0 = _mm_packus_epi32(_mm_and_si128(layer1_chunk0, v_mask), _mm_and_si128(layer1_chunk1, v_mask)); + v_g0 = _mm_packus_epi32(_mm_srli_epi32(layer1_chunk0, 16), _mm_srli_epi32(layer1_chunk1, 16)); + v_r1 = _mm_packus_epi32(_mm_and_si128(layer1_chunk2, v_mask), _mm_and_si128(layer1_chunk3, v_mask)); + v_g1 = _mm_packus_epi32(_mm_srli_epi32(layer1_chunk2, 16), _mm_srli_epi32(layer1_chunk3, 16)); +} + +inline void _mm_interleave_epi16(__m128i & v_r0, __m128i & v_r1, __m128i & v_g0, + __m128i & v_g1, __m128i & v_b0, __m128i & v_b1) +{ + __m128i v_mask = _mm_set1_epi32(0x0000ffff); + + __m128i layer3_chunk0 = _mm_packus_epi32(_mm_and_si128(v_r0, v_mask), _mm_and_si128(v_r1, v_mask)); + __m128i layer3_chunk3 = _mm_packus_epi32(_mm_srli_epi32(v_r0, 16), _mm_srli_epi32(v_r1, 16)); + __m128i layer3_chunk1 = _mm_packus_epi32(_mm_and_si128(v_g0, v_mask), _mm_and_si128(v_g1, v_mask)); + __m128i layer3_chunk4 = _mm_packus_epi32(_mm_srli_epi32(v_g0, 16), _mm_srli_epi32(v_g1, 16)); + __m128i layer3_chunk2 = _mm_packus_epi32(_mm_and_si128(v_b0, v_mask), _mm_and_si128(v_b1, v_mask)); + __m128i layer3_chunk5 = _mm_packus_epi32(_mm_srli_epi32(v_b0, 16), _mm_srli_epi32(v_b1, 16)); + + __m128i layer2_chunk0 = _mm_packus_epi32(_mm_and_si128(layer3_chunk0, v_mask), _mm_and_si128(layer3_chunk1, v_mask)); + __m128i layer2_chunk3 = _mm_packus_epi32(_mm_srli_epi32(layer3_chunk0, 16), _mm_srli_epi32(layer3_chunk1, 16)); + __m128i layer2_chunk1 = _mm_packus_epi32(_mm_and_si128(layer3_chunk2, v_mask), _mm_and_si128(layer3_chunk3, v_mask)); + __m128i layer2_chunk4 = _mm_packus_epi32(_mm_srli_epi32(layer3_chunk2, 16), _mm_srli_epi32(layer3_chunk3, 16)); + __m128i layer2_chunk2 = _mm_packus_epi32(_mm_and_si128(layer3_chunk4, v_mask), _mm_and_si128(layer3_chunk5, v_mask)); + __m128i layer2_chunk5 = _mm_packus_epi32(_mm_srli_epi32(layer3_chunk4, 16), _mm_srli_epi32(layer3_chunk5, 16)); + + __m128i layer1_chunk0 = _mm_packus_epi32(_mm_and_si128(layer2_chunk0, v_mask), _mm_and_si128(layer2_chunk1, v_mask)); + __m128i layer1_chunk3 = _mm_packus_epi32(_mm_srli_epi32(layer2_chunk0, 16), _mm_srli_epi32(layer2_chunk1, 16)); + __m128i layer1_chunk1 = _mm_packus_epi32(_mm_and_si128(layer2_chunk2, v_mask), _mm_and_si128(layer2_chunk3, v_mask)); + __m128i layer1_chunk4 = _mm_packus_epi32(_mm_srli_epi32(layer2_chunk2, 16), _mm_srli_epi32(layer2_chunk3, 16)); + __m128i layer1_chunk2 = _mm_packus_epi32(_mm_and_si128(layer2_chunk4, v_mask), _mm_and_si128(layer2_chunk5, v_mask)); + __m128i layer1_chunk5 = _mm_packus_epi32(_mm_srli_epi32(layer2_chunk4, 16), _mm_srli_epi32(layer2_chunk5, 16)); + + v_r0 = _mm_packus_epi32(_mm_and_si128(layer1_chunk0, v_mask), _mm_and_si128(layer1_chunk1, v_mask)); + v_g1 = _mm_packus_epi32(_mm_srli_epi32(layer1_chunk0, 16), _mm_srli_epi32(layer1_chunk1, 16)); + v_r1 = _mm_packus_epi32(_mm_and_si128(layer1_chunk2, v_mask), _mm_and_si128(layer1_chunk3, v_mask)); + v_b0 = _mm_packus_epi32(_mm_srli_epi32(layer1_chunk2, 16), _mm_srli_epi32(layer1_chunk3, 16)); + v_g0 = _mm_packus_epi32(_mm_and_si128(layer1_chunk4, v_mask), _mm_and_si128(layer1_chunk5, v_mask)); + v_b1 = _mm_packus_epi32(_mm_srli_epi32(layer1_chunk4, 16), _mm_srli_epi32(layer1_chunk5, 16)); +} + +inline void _mm_interleave_epi16(__m128i & v_r0, __m128i & v_r1, __m128i & v_g0, __m128i & v_g1, + __m128i & v_b0, __m128i & v_b1, __m128i & v_a0, __m128i & v_a1) +{ + __m128i v_mask = _mm_set1_epi32(0x0000ffff); + + __m128i layer3_chunk0 = _mm_packus_epi32(_mm_and_si128(v_r0, v_mask), _mm_and_si128(v_r1, v_mask)); + __m128i layer3_chunk4 = _mm_packus_epi32(_mm_srli_epi32(v_r0, 16), _mm_srli_epi32(v_r1, 16)); + __m128i layer3_chunk1 = _mm_packus_epi32(_mm_and_si128(v_g0, v_mask), _mm_and_si128(v_g1, v_mask)); + __m128i layer3_chunk5 = _mm_packus_epi32(_mm_srli_epi32(v_g0, 16), _mm_srli_epi32(v_g1, 16)); + __m128i layer3_chunk2 = _mm_packus_epi32(_mm_and_si128(v_b0, v_mask), _mm_and_si128(v_b1, v_mask)); + __m128i layer3_chunk6 = _mm_packus_epi32(_mm_srli_epi32(v_b0, 16), _mm_srli_epi32(v_b1, 16)); + __m128i layer3_chunk3 = _mm_packus_epi32(_mm_and_si128(v_a0, v_mask), _mm_and_si128(v_a1, v_mask)); + __m128i layer3_chunk7 = _mm_packus_epi32(_mm_srli_epi32(v_a0, 16), _mm_srli_epi32(v_a1, 16)); + + __m128i layer2_chunk0 = _mm_packus_epi32(_mm_and_si128(layer3_chunk0, v_mask), _mm_and_si128(layer3_chunk1, v_mask)); + __m128i layer2_chunk4 = _mm_packus_epi32(_mm_srli_epi32(layer3_chunk0, 16), _mm_srli_epi32(layer3_chunk1, 16)); + __m128i layer2_chunk1 = _mm_packus_epi32(_mm_and_si128(layer3_chunk2, v_mask), _mm_and_si128(layer3_chunk3, v_mask)); + __m128i layer2_chunk5 = _mm_packus_epi32(_mm_srli_epi32(layer3_chunk2, 16), _mm_srli_epi32(layer3_chunk3, 16)); + __m128i layer2_chunk2 = _mm_packus_epi32(_mm_and_si128(layer3_chunk4, v_mask), _mm_and_si128(layer3_chunk5, v_mask)); + __m128i layer2_chunk6 = _mm_packus_epi32(_mm_srli_epi32(layer3_chunk4, 16), _mm_srli_epi32(layer3_chunk5, 16)); + __m128i layer2_chunk3 = _mm_packus_epi32(_mm_and_si128(layer3_chunk6, v_mask), _mm_and_si128(layer3_chunk7, v_mask)); + __m128i layer2_chunk7 = _mm_packus_epi32(_mm_srli_epi32(layer3_chunk6, 16), _mm_srli_epi32(layer3_chunk7, 16)); + + __m128i layer1_chunk0 = _mm_packus_epi32(_mm_and_si128(layer2_chunk0, v_mask), _mm_and_si128(layer2_chunk1, v_mask)); + __m128i layer1_chunk4 = _mm_packus_epi32(_mm_srli_epi32(layer2_chunk0, 16), _mm_srli_epi32(layer2_chunk1, 16)); + __m128i layer1_chunk1 = _mm_packus_epi32(_mm_and_si128(layer2_chunk2, v_mask), _mm_and_si128(layer2_chunk3, v_mask)); + __m128i layer1_chunk5 = _mm_packus_epi32(_mm_srli_epi32(layer2_chunk2, 16), _mm_srli_epi32(layer2_chunk3, 16)); + __m128i layer1_chunk2 = _mm_packus_epi32(_mm_and_si128(layer2_chunk4, v_mask), _mm_and_si128(layer2_chunk5, v_mask)); + __m128i layer1_chunk6 = _mm_packus_epi32(_mm_srli_epi32(layer2_chunk4, 16), _mm_srli_epi32(layer2_chunk5, 16)); + __m128i layer1_chunk3 = _mm_packus_epi32(_mm_and_si128(layer2_chunk6, v_mask), _mm_and_si128(layer2_chunk7, v_mask)); + __m128i layer1_chunk7 = _mm_packus_epi32(_mm_srli_epi32(layer2_chunk6, 16), _mm_srli_epi32(layer2_chunk7, 16)); + + v_r0 = _mm_packus_epi32(_mm_and_si128(layer1_chunk0, v_mask), _mm_and_si128(layer1_chunk1, v_mask)); + v_b0 = _mm_packus_epi32(_mm_srli_epi32(layer1_chunk0, 16), _mm_srli_epi32(layer1_chunk1, 16)); + v_r1 = _mm_packus_epi32(_mm_and_si128(layer1_chunk2, v_mask), _mm_and_si128(layer1_chunk3, v_mask)); + v_b1 = _mm_packus_epi32(_mm_srli_epi32(layer1_chunk2, 16), _mm_srli_epi32(layer1_chunk3, 16)); + v_g0 = _mm_packus_epi32(_mm_and_si128(layer1_chunk4, v_mask), _mm_and_si128(layer1_chunk5, v_mask)); + v_a0 = _mm_packus_epi32(_mm_srli_epi32(layer1_chunk4, 16), _mm_srli_epi32(layer1_chunk5, 16)); + v_g1 = _mm_packus_epi32(_mm_and_si128(layer1_chunk6, v_mask), _mm_and_si128(layer1_chunk7, v_mask)); + v_a1 = _mm_packus_epi32(_mm_srli_epi32(layer1_chunk6, 16), _mm_srli_epi32(layer1_chunk7, 16)); +} + +#endif // CV_SSE4_1 + +inline void _mm_deinterleave_ps(__m128 & v_r0, __m128 & v_r1, __m128 & v_g0, __m128 & v_g1) +{ + __m128 layer1_chunk0 = _mm_unpacklo_ps(v_r0, v_g0); + __m128 layer1_chunk1 = _mm_unpackhi_ps(v_r0, v_g0); + __m128 layer1_chunk2 = _mm_unpacklo_ps(v_r1, v_g1); + __m128 layer1_chunk3 = _mm_unpackhi_ps(v_r1, v_g1); + + __m128 layer2_chunk0 = _mm_unpacklo_ps(layer1_chunk0, layer1_chunk2); + __m128 layer2_chunk1 = _mm_unpackhi_ps(layer1_chunk0, layer1_chunk2); + __m128 layer2_chunk2 = _mm_unpacklo_ps(layer1_chunk1, layer1_chunk3); + __m128 layer2_chunk3 = _mm_unpackhi_ps(layer1_chunk1, layer1_chunk3); + + v_r0 = _mm_unpacklo_ps(layer2_chunk0, layer2_chunk2); + v_r1 = _mm_unpackhi_ps(layer2_chunk0, layer2_chunk2); + v_g0 = _mm_unpacklo_ps(layer2_chunk1, layer2_chunk3); + v_g1 = _mm_unpackhi_ps(layer2_chunk1, layer2_chunk3); +} + +inline void _mm_deinterleave_ps(__m128 & v_r0, __m128 & v_r1, __m128 & v_g0, + __m128 & v_g1, __m128 & v_b0, __m128 & v_b1) +{ + __m128 layer1_chunk0 = _mm_unpacklo_ps(v_r0, v_g1); + __m128 layer1_chunk1 = _mm_unpackhi_ps(v_r0, v_g1); + __m128 layer1_chunk2 = _mm_unpacklo_ps(v_r1, v_b0); + __m128 layer1_chunk3 = _mm_unpackhi_ps(v_r1, v_b0); + __m128 layer1_chunk4 = _mm_unpacklo_ps(v_g0, v_b1); + __m128 layer1_chunk5 = _mm_unpackhi_ps(v_g0, v_b1); + + __m128 layer2_chunk0 = _mm_unpacklo_ps(layer1_chunk0, layer1_chunk3); + __m128 layer2_chunk1 = _mm_unpackhi_ps(layer1_chunk0, layer1_chunk3); + __m128 layer2_chunk2 = _mm_unpacklo_ps(layer1_chunk1, layer1_chunk4); + __m128 layer2_chunk3 = _mm_unpackhi_ps(layer1_chunk1, layer1_chunk4); + __m128 layer2_chunk4 = _mm_unpacklo_ps(layer1_chunk2, layer1_chunk5); + __m128 layer2_chunk5 = _mm_unpackhi_ps(layer1_chunk2, layer1_chunk5); + + v_r0 = _mm_unpacklo_ps(layer2_chunk0, layer2_chunk3); + v_r1 = _mm_unpackhi_ps(layer2_chunk0, layer2_chunk3); + v_g0 = _mm_unpacklo_ps(layer2_chunk1, layer2_chunk4); + v_g1 = _mm_unpackhi_ps(layer2_chunk1, layer2_chunk4); + v_b0 = _mm_unpacklo_ps(layer2_chunk2, layer2_chunk5); + v_b1 = _mm_unpackhi_ps(layer2_chunk2, layer2_chunk5); +} + +inline void _mm_deinterleave_ps(__m128 & v_r0, __m128 & v_r1, __m128 & v_g0, __m128 & v_g1, + __m128 & v_b0, __m128 & v_b1, __m128 & v_a0, __m128 & v_a1) +{ + __m128 layer1_chunk0 = _mm_unpacklo_ps(v_r0, v_b0); + __m128 layer1_chunk1 = _mm_unpackhi_ps(v_r0, v_b0); + __m128 layer1_chunk2 = _mm_unpacklo_ps(v_r1, v_b1); + __m128 layer1_chunk3 = _mm_unpackhi_ps(v_r1, v_b1); + __m128 layer1_chunk4 = _mm_unpacklo_ps(v_g0, v_a0); + __m128 layer1_chunk5 = _mm_unpackhi_ps(v_g0, v_a0); + __m128 layer1_chunk6 = _mm_unpacklo_ps(v_g1, v_a1); + __m128 layer1_chunk7 = _mm_unpackhi_ps(v_g1, v_a1); + + __m128 layer2_chunk0 = _mm_unpacklo_ps(layer1_chunk0, layer1_chunk4); + __m128 layer2_chunk1 = _mm_unpackhi_ps(layer1_chunk0, layer1_chunk4); + __m128 layer2_chunk2 = _mm_unpacklo_ps(layer1_chunk1, layer1_chunk5); + __m128 layer2_chunk3 = _mm_unpackhi_ps(layer1_chunk1, layer1_chunk5); + __m128 layer2_chunk4 = _mm_unpacklo_ps(layer1_chunk2, layer1_chunk6); + __m128 layer2_chunk5 = _mm_unpackhi_ps(layer1_chunk2, layer1_chunk6); + __m128 layer2_chunk6 = _mm_unpacklo_ps(layer1_chunk3, layer1_chunk7); + __m128 layer2_chunk7 = _mm_unpackhi_ps(layer1_chunk3, layer1_chunk7); + + v_r0 = _mm_unpacklo_ps(layer2_chunk0, layer2_chunk4); + v_r1 = _mm_unpackhi_ps(layer2_chunk0, layer2_chunk4); + v_g0 = _mm_unpacklo_ps(layer2_chunk1, layer2_chunk5); + v_g1 = _mm_unpackhi_ps(layer2_chunk1, layer2_chunk5); + v_b0 = _mm_unpacklo_ps(layer2_chunk2, layer2_chunk6); + v_b1 = _mm_unpackhi_ps(layer2_chunk2, layer2_chunk6); + v_a0 = _mm_unpacklo_ps(layer2_chunk3, layer2_chunk7); + v_a1 = _mm_unpackhi_ps(layer2_chunk3, layer2_chunk7); +} + +inline void _mm_interleave_ps(__m128 & v_r0, __m128 & v_r1, __m128 & v_g0, __m128 & v_g1) +{ + enum { mask_lo = _MM_SHUFFLE(2, 0, 2, 0), mask_hi = _MM_SHUFFLE(3, 1, 3, 1) }; + + __m128 layer2_chunk0 = _mm_shuffle_ps(v_r0, v_r1, mask_lo); + __m128 layer2_chunk2 = _mm_shuffle_ps(v_r0, v_r1, mask_hi); + __m128 layer2_chunk1 = _mm_shuffle_ps(v_g0, v_g1, mask_lo); + __m128 layer2_chunk3 = _mm_shuffle_ps(v_g0, v_g1, mask_hi); + + __m128 layer1_chunk0 = _mm_shuffle_ps(layer2_chunk0, layer2_chunk1, mask_lo); + __m128 layer1_chunk2 = _mm_shuffle_ps(layer2_chunk0, layer2_chunk1, mask_hi); + __m128 layer1_chunk1 = _mm_shuffle_ps(layer2_chunk2, layer2_chunk3, mask_lo); + __m128 layer1_chunk3 = _mm_shuffle_ps(layer2_chunk2, layer2_chunk3, mask_hi); + + v_r0 = _mm_shuffle_ps(layer1_chunk0, layer1_chunk1, mask_lo); + v_g0 = _mm_shuffle_ps(layer1_chunk0, layer1_chunk1, mask_hi); + v_r1 = _mm_shuffle_ps(layer1_chunk2, layer1_chunk3, mask_lo); + v_g1 = _mm_shuffle_ps(layer1_chunk2, layer1_chunk3, mask_hi); +} + +inline void _mm_interleave_ps(__m128 & v_r0, __m128 & v_r1, __m128 & v_g0, + __m128 & v_g1, __m128 & v_b0, __m128 & v_b1) +{ + enum { mask_lo = _MM_SHUFFLE(2, 0, 2, 0), mask_hi = _MM_SHUFFLE(3, 1, 3, 1) }; + + __m128 layer2_chunk0 = _mm_shuffle_ps(v_r0, v_r1, mask_lo); + __m128 layer2_chunk3 = _mm_shuffle_ps(v_r0, v_r1, mask_hi); + __m128 layer2_chunk1 = _mm_shuffle_ps(v_g0, v_g1, mask_lo); + __m128 layer2_chunk4 = _mm_shuffle_ps(v_g0, v_g1, mask_hi); + __m128 layer2_chunk2 = _mm_shuffle_ps(v_b0, v_b1, mask_lo); + __m128 layer2_chunk5 = _mm_shuffle_ps(v_b0, v_b1, mask_hi); + + __m128 layer1_chunk0 = _mm_shuffle_ps(layer2_chunk0, layer2_chunk1, mask_lo); + __m128 layer1_chunk3 = _mm_shuffle_ps(layer2_chunk0, layer2_chunk1, mask_hi); + __m128 layer1_chunk1 = _mm_shuffle_ps(layer2_chunk2, layer2_chunk3, mask_lo); + __m128 layer1_chunk4 = _mm_shuffle_ps(layer2_chunk2, layer2_chunk3, mask_hi); + __m128 layer1_chunk2 = _mm_shuffle_ps(layer2_chunk4, layer2_chunk5, mask_lo); + __m128 layer1_chunk5 = _mm_shuffle_ps(layer2_chunk4, layer2_chunk5, mask_hi); + + v_r0 = _mm_shuffle_ps(layer1_chunk0, layer1_chunk1, mask_lo); + v_g1 = _mm_shuffle_ps(layer1_chunk0, layer1_chunk1, mask_hi); + v_r1 = _mm_shuffle_ps(layer1_chunk2, layer1_chunk3, mask_lo); + v_b0 = _mm_shuffle_ps(layer1_chunk2, layer1_chunk3, mask_hi); + v_g0 = _mm_shuffle_ps(layer1_chunk4, layer1_chunk5, mask_lo); + v_b1 = _mm_shuffle_ps(layer1_chunk4, layer1_chunk5, mask_hi); +} + +inline void _mm_interleave_ps(__m128 & v_r0, __m128 & v_r1, __m128 & v_g0, __m128 & v_g1, + __m128 & v_b0, __m128 & v_b1, __m128 & v_a0, __m128 & v_a1) +{ + enum { mask_lo = _MM_SHUFFLE(2, 0, 2, 0), mask_hi = _MM_SHUFFLE(3, 1, 3, 1) }; + + __m128 layer2_chunk0 = _mm_shuffle_ps(v_r0, v_r1, mask_lo); + __m128 layer2_chunk4 = _mm_shuffle_ps(v_r0, v_r1, mask_hi); + __m128 layer2_chunk1 = _mm_shuffle_ps(v_g0, v_g1, mask_lo); + __m128 layer2_chunk5 = _mm_shuffle_ps(v_g0, v_g1, mask_hi); + __m128 layer2_chunk2 = _mm_shuffle_ps(v_b0, v_b1, mask_lo); + __m128 layer2_chunk6 = _mm_shuffle_ps(v_b0, v_b1, mask_hi); + __m128 layer2_chunk3 = _mm_shuffle_ps(v_a0, v_a1, mask_lo); + __m128 layer2_chunk7 = _mm_shuffle_ps(v_a0, v_a1, mask_hi); + + __m128 layer1_chunk0 = _mm_shuffle_ps(layer2_chunk0, layer2_chunk1, mask_lo); + __m128 layer1_chunk4 = _mm_shuffle_ps(layer2_chunk0, layer2_chunk1, mask_hi); + __m128 layer1_chunk1 = _mm_shuffle_ps(layer2_chunk2, layer2_chunk3, mask_lo); + __m128 layer1_chunk5 = _mm_shuffle_ps(layer2_chunk2, layer2_chunk3, mask_hi); + __m128 layer1_chunk2 = _mm_shuffle_ps(layer2_chunk4, layer2_chunk5, mask_lo); + __m128 layer1_chunk6 = _mm_shuffle_ps(layer2_chunk4, layer2_chunk5, mask_hi); + __m128 layer1_chunk3 = _mm_shuffle_ps(layer2_chunk6, layer2_chunk7, mask_lo); + __m128 layer1_chunk7 = _mm_shuffle_ps(layer2_chunk6, layer2_chunk7, mask_hi); + + v_r0 = _mm_shuffle_ps(layer1_chunk0, layer1_chunk1, mask_lo); + v_b0 = _mm_shuffle_ps(layer1_chunk0, layer1_chunk1, mask_hi); + v_r1 = _mm_shuffle_ps(layer1_chunk2, layer1_chunk3, mask_lo); + v_b1 = _mm_shuffle_ps(layer1_chunk2, layer1_chunk3, mask_hi); + v_g0 = _mm_shuffle_ps(layer1_chunk4, layer1_chunk5, mask_lo); + v_a0 = _mm_shuffle_ps(layer1_chunk4, layer1_chunk5, mask_hi); + v_g1 = _mm_shuffle_ps(layer1_chunk6, layer1_chunk7, mask_lo); + v_a1 = _mm_shuffle_ps(layer1_chunk6, layer1_chunk7, mask_hi); +} + +#endif // CV_SSE2 + +//! @} + +#endif //OPENCV_CORE_SSE_UTILS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/traits.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/traits.hpp new file mode 100644 index 0000000..52ab083 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/traits.hpp @@ -0,0 +1,417 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_TRAITS_HPP +#define OPENCV_CORE_TRAITS_HPP + +#include "opencv2/core/cvdef.h" + +namespace cv +{ + +//#define OPENCV_TRAITS_ENABLE_DEPRECATED + +//! @addtogroup core_basic +//! @{ + +/** @brief Template "trait" class for OpenCV primitive data types. + +@note Deprecated. This is replaced by "single purpose" traits: traits::Type and traits::Depth + +A primitive OpenCV data type is one of unsigned char, bool, signed char, unsigned short, signed +short, int, float, double, or a tuple of values of one of these types, where all the values in the +tuple have the same type. Any primitive type from the list can be defined by an identifier in the +form CV_\{U|S|F}C(\), for example: uchar \~ CV_8UC1, 3-element +floating-point tuple \~ CV_32FC3, and so on. A universal OpenCV structure that is able to store a +single instance of such a primitive data type is Vec. Multiple instances of such a type can be +stored in a std::vector, Mat, Mat_, SparseMat, SparseMat_, or any other container that is able to +store Vec instances. + +The DataType class is basically used to provide a description of such primitive data types without +adding any fields or methods to the corresponding classes (and it is actually impossible to add +anything to primitive C/C++ data types). This technique is known in C++ as class traits. It is not +DataType itself that is used but its specialized versions, such as: +@code + template<> class DataType + { + typedef uchar value_type; + typedef int work_type; + typedef uchar channel_type; + enum { channel_type = CV_8U, channels = 1, fmt='u', type = CV_8U }; + }; + ... + template DataType > + { + typedef std::complex<_Tp> value_type; + typedef std::complex<_Tp> work_type; + typedef _Tp channel_type; + // DataDepth is another helper trait class + enum { depth = DataDepth<_Tp>::value, channels=2, + fmt=(channels-1)*256+DataDepth<_Tp>::fmt, + type=CV_MAKETYPE(depth, channels) }; + }; + ... +@endcode +The main purpose of this class is to convert compilation-time type information to an +OpenCV-compatible data type identifier, for example: +@code + // allocates a 30x40 floating-point matrix + Mat A(30, 40, DataType::type); + + Mat B = Mat_ >(3, 3); + // the statement below will print 6, 2 , that is depth == CV_64F, channels == 2 + cout << B.depth() << ", " << B.channels() << endl; +@endcode +So, such traits are used to tell OpenCV which data type you are working with, even if such a type is +not native to OpenCV. For example, the matrix B initialization above is compiled because OpenCV +defines the proper specialized template class DataType\ \> . This mechanism is also +useful (and used in OpenCV this way) for generic algorithms implementations. + +@note Default values were dropped to stop confusing developers about using of unsupported types (see #7599) +*/ +template class DataType +{ +public: +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + typedef _Tp value_type; + typedef value_type work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 1, + depth = -1, + channels = 1, + fmt = 0, + type = CV_MAKETYPE(depth, channels) + }; +#endif +}; + +template<> class DataType +{ +public: + typedef bool value_type; + typedef int work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 0, + depth = CV_8U, + channels = 1, + fmt = (int)'u', + type = CV_MAKETYPE(depth, channels) + }; +}; + +template<> class DataType +{ +public: + typedef uchar value_type; + typedef int work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 0, + depth = CV_8U, + channels = 1, + fmt = (int)'u', + type = CV_MAKETYPE(depth, channels) + }; +}; + +template<> class DataType +{ +public: + typedef schar value_type; + typedef int work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 0, + depth = CV_8S, + channels = 1, + fmt = (int)'c', + type = CV_MAKETYPE(depth, channels) + }; +}; + +template<> class DataType +{ +public: + typedef schar value_type; + typedef int work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 0, + depth = CV_8S, + channels = 1, + fmt = (int)'c', + type = CV_MAKETYPE(depth, channels) + }; +}; + +template<> class DataType +{ +public: + typedef ushort value_type; + typedef int work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 0, + depth = CV_16U, + channels = 1, + fmt = (int)'w', + type = CV_MAKETYPE(depth, channels) + }; +}; + +template<> class DataType +{ +public: + typedef short value_type; + typedef int work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 0, + depth = CV_16S, + channels = 1, + fmt = (int)'s', + type = CV_MAKETYPE(depth, channels) + }; +}; + +template<> class DataType +{ +public: + typedef int value_type; + typedef value_type work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 0, + depth = CV_32S, + channels = 1, + fmt = (int)'i', + type = CV_MAKETYPE(depth, channels) + }; +}; + +template<> class DataType +{ +public: + typedef float value_type; + typedef value_type work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 0, + depth = CV_32F, + channels = 1, + fmt = (int)'f', + type = CV_MAKETYPE(depth, channels) + }; +}; + +template<> class DataType +{ +public: + typedef double value_type; + typedef value_type work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 0, + depth = CV_64F, + channels = 1, + fmt = (int)'d', + type = CV_MAKETYPE(depth, channels) + }; +}; + +template<> class DataType +{ +public: + typedef float16_t value_type; + typedef float work_type; + typedef value_type channel_type; + typedef value_type vec_type; + enum { generic_type = 0, + depth = CV_16F, + channels = 1, + fmt = (int)'h', + type = CV_MAKETYPE(depth, channels) + }; +}; + +/** @brief A helper class for cv::DataType + +The class is specialized for each fundamental numerical data type supported by OpenCV. It provides +DataDepth::value constant. +*/ +template class DataDepth +{ +public: + enum + { + value = DataType<_Tp>::depth, + fmt = DataType<_Tp>::fmt + }; +}; + + +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + +template class TypeDepth +{ +#ifdef OPENCV_TRAITS_ENABLE_LEGACY_DEFAULTS + enum { depth = CV_USRTYPE1 }; + typedef void value_type; +#endif +}; + +template<> class TypeDepth +{ + enum { depth = CV_8U }; + typedef uchar value_type; +}; + +template<> class TypeDepth +{ + enum { depth = CV_8S }; + typedef schar value_type; +}; + +template<> class TypeDepth +{ + enum { depth = CV_16U }; + typedef ushort value_type; +}; + +template<> class TypeDepth +{ + enum { depth = CV_16S }; + typedef short value_type; +}; + +template<> class TypeDepth +{ + enum { depth = CV_32S }; + typedef int value_type; +}; + +template<> class TypeDepth +{ + enum { depth = CV_32F }; + typedef float value_type; +}; + +template<> class TypeDepth +{ + enum { depth = CV_64F }; + typedef double value_type; +}; + +template<> class TypeDepth +{ + enum { depth = CV_16F }; + typedef float16_t value_type; +}; + +#endif + +//! @} + +namespace traits { + +namespace internal { +#define CV_CREATE_MEMBER_CHECK(X) \ +template class CheckMember_##X { \ + struct Fallback { int X; }; \ + struct Derived : T, Fallback { }; \ + template struct Check; \ + typedef char CV_NO[1]; \ + typedef char CV_YES[2]; \ + template static CV_NO & func(Check *); \ + template static CV_YES & func(...); \ +public: \ + typedef CheckMember_##X type; \ + enum { value = sizeof(func(0)) == sizeof(CV_YES) }; \ +}; + +CV_CREATE_MEMBER_CHECK(fmt) +CV_CREATE_MEMBER_CHECK(type) + +} // namespace internal + + +template +struct Depth +{ enum { value = DataType::depth }; }; + +template +struct Type +{ enum { value = DataType::type }; }; + +/** Similar to traits::Type but has value = -1 in case of unknown type (instead of compiler error) */ +template >::value > +struct SafeType {}; + +template +struct SafeType +{ enum { value = -1 }; }; + +template +struct SafeType +{ enum { value = Type::value }; }; + + +template >::value > +struct SafeFmt {}; + +template +struct SafeFmt +{ enum { fmt = 0 }; }; + +template +struct SafeFmt +{ enum { fmt = DataType::fmt }; }; + + +} // namespace + +} // cv + +#endif // OPENCV_CORE_TRAITS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/types.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/types.hpp new file mode 100644 index 0000000..2867520 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/types.hpp @@ -0,0 +1,2439 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_TYPES_HPP +#define OPENCV_CORE_TYPES_HPP + +#ifndef __cplusplus +# error types.hpp header must be compiled as C++ +#endif + +#include +#include +#include +#include + +#include "opencv2/core/cvdef.h" +#include "opencv2/core/cvstd.hpp" +#include "opencv2/core/matx.hpp" + +namespace cv +{ + +//! @addtogroup core_basic +//! @{ + +//////////////////////////////// Complex ////////////////////////////// + +/** @brief A complex number class. + + The template class is similar and compatible with std::complex, however it provides slightly + more convenient access to the real and imaginary parts using through the simple field access, as opposite + to std::complex::real() and std::complex::imag(). +*/ +template class Complex +{ +public: + + //! default constructor + Complex(); + Complex( _Tp _re, _Tp _im = 0 ); + + //! conversion to another data type + template operator Complex() const; + //! conjugation + Complex conj() const; + + _Tp re, im; //< the real and the imaginary parts +}; + +typedef Complex Complexf; +typedef Complex Complexd; + +template class DataType< Complex<_Tp> > +{ +public: + typedef Complex<_Tp> value_type; + typedef value_type work_type; + typedef _Tp channel_type; + + enum { generic_type = 0, + channels = 2, + fmt = DataType::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif + }; + + typedef Vec vec_type; +}; + +namespace traits { +template +struct Depth< Complex<_Tp> > { enum { value = Depth<_Tp>::value }; }; +template +struct Type< Complex<_Tp> > { enum { value = CV_MAKETYPE(Depth<_Tp>::value, 2) }; }; +} // namespace + + +//////////////////////////////// Point_ //////////////////////////////// + +/** @brief Template class for 2D points specified by its coordinates `x` and `y`. + +An instance of the class is interchangeable with C structures, CvPoint and CvPoint2D32f . There is +also a cast operator to convert point coordinates to the specified type. The conversion from +floating-point coordinates to integer coordinates is done by rounding. Commonly, the conversion +uses this operation for each of the coordinates. Besides the class members listed in the +declaration above, the following operations on points are implemented: +@code + pt1 = pt2 + pt3; + pt1 = pt2 - pt3; + pt1 = pt2 * a; + pt1 = a * pt2; + pt1 = pt2 / a; + pt1 += pt2; + pt1 -= pt2; + pt1 *= a; + pt1 /= a; + double value = norm(pt); // L2 norm + pt1 == pt2; + pt1 != pt2; +@endcode +For your convenience, the following type aliases are defined: +@code + typedef Point_ Point2i; + typedef Point2i Point; + typedef Point_ Point2f; + typedef Point_ Point2d; +@endcode +Example: +@code + Point2f a(0.3f, 0.f), b(0.f, 0.4f); + Point pt = (a + b)*10.f; + cout << pt.x << ", " << pt.y << endl; +@endcode +*/ +template class Point_ +{ +public: + typedef _Tp value_type; + + //! default constructor + Point_(); + Point_(_Tp _x, _Tp _y); +#if (defined(__GNUC__) && __GNUC__ < 5) && !defined(__clang__) // GCC 4.x bug. Details: https://github.com/opencv/opencv/pull/20837 + Point_(const Point_& pt); + Point_(Point_&& pt) CV_NOEXCEPT = default; +#elif OPENCV_ABI_COMPATIBILITY < 500 + Point_(const Point_& pt) = default; + Point_(Point_&& pt) CV_NOEXCEPT = default; +#endif + Point_(const Size_<_Tp>& sz); + Point_(const Vec<_Tp, 2>& v); + +#if (defined(__GNUC__) && __GNUC__ < 5) && !defined(__clang__) // GCC 4.x bug. Details: https://github.com/opencv/opencv/pull/20837 + Point_& operator = (const Point_& pt); + Point_& operator = (Point_&& pt) CV_NOEXCEPT = default; +#elif OPENCV_ABI_COMPATIBILITY < 500 + Point_& operator = (const Point_& pt) = default; + Point_& operator = (Point_&& pt) CV_NOEXCEPT = default; +#endif + //! conversion to another data type + template operator Point_<_Tp2>() const; + + //! conversion to the old-style C structures + operator Vec<_Tp, 2>() const; + + //! dot product + _Tp dot(const Point_& pt) const; + //! dot product computed in double-precision arithmetics + double ddot(const Point_& pt) const; + //! cross-product + double cross(const Point_& pt) const; + //! checks whether the point is inside the specified rectangle + bool inside(const Rect_<_Tp>& r) const; + _Tp x; //!< x coordinate of the point + _Tp y; //!< y coordinate of the point +}; + +typedef Point_ Point2i; +typedef Point_ Point2l; +typedef Point_ Point2f; +typedef Point_ Point2d; +typedef Point2i Point; + +template class DataType< Point_<_Tp> > +{ +public: + typedef Point_<_Tp> value_type; + typedef Point_::work_type> work_type; + typedef _Tp channel_type; + + enum { generic_type = 0, + channels = 2, + fmt = traits::SafeFmt::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif + }; + + typedef Vec vec_type; +}; + +namespace traits { +template +struct Depth< Point_<_Tp> > { enum { value = Depth<_Tp>::value }; }; +template +struct Type< Point_<_Tp> > { enum { value = CV_MAKETYPE(Depth<_Tp>::value, 2) }; }; +} // namespace + + +//////////////////////////////// Point3_ //////////////////////////////// + +/** @brief Template class for 3D points specified by its coordinates `x`, `y` and `z`. + +An instance of the class is interchangeable with the C structure CvPoint2D32f . Similarly to +Point_ , the coordinates of 3D points can be converted to another type. The vector arithmetic and +comparison operations are also supported. + +The following Point3_\<\> aliases are available: +@code + typedef Point3_ Point3i; + typedef Point3_ Point3f; + typedef Point3_ Point3d; +@endcode +@see cv::Point3i, cv::Point3f and cv::Point3d +*/ +template class Point3_ +{ +public: + typedef _Tp value_type; + + //! default constructor + Point3_(); + Point3_(_Tp _x, _Tp _y, _Tp _z); +#if OPENCV_ABI_COMPATIBILITY < 500 + Point3_(const Point3_& pt) = default; + Point3_(Point3_&& pt) CV_NOEXCEPT = default; +#endif + explicit Point3_(const Point_<_Tp>& pt); + Point3_(const Vec<_Tp, 3>& v); + +#if OPENCV_ABI_COMPATIBILITY < 500 + Point3_& operator = (const Point3_& pt) = default; + Point3_& operator = (Point3_&& pt) CV_NOEXCEPT = default; +#endif + //! conversion to another data type + template operator Point3_<_Tp2>() const; + //! conversion to cv::Vec<> + operator Vec<_Tp, 3>() const; + + //! dot product + _Tp dot(const Point3_& pt) const; + //! dot product computed in double-precision arithmetics + double ddot(const Point3_& pt) const; + //! cross product of the 2 3D points + Point3_ cross(const Point3_& pt) const; + _Tp x; //!< x coordinate of the 3D point + _Tp y; //!< y coordinate of the 3D point + _Tp z; //!< z coordinate of the 3D point +}; + +typedef Point3_ Point3i; +typedef Point3_ Point3f; +typedef Point3_ Point3d; + +template class DataType< Point3_<_Tp> > +{ +public: + typedef Point3_<_Tp> value_type; + typedef Point3_::work_type> work_type; + typedef _Tp channel_type; + + enum { generic_type = 0, + channels = 3, + fmt = traits::SafeFmt::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif + }; + + typedef Vec vec_type; +}; + +namespace traits { +template +struct Depth< Point3_<_Tp> > { enum { value = Depth<_Tp>::value }; }; +template +struct Type< Point3_<_Tp> > { enum { value = CV_MAKETYPE(Depth<_Tp>::value, 3) }; }; +} // namespace + +//////////////////////////////// Size_ //////////////////////////////// + +/** @brief Template class for specifying the size of an image or rectangle. + +The class includes two members called width and height. The structure can be converted to and from +the old OpenCV structures CvSize and CvSize2D32f . The same set of arithmetic and comparison +operations as for Point_ is available. + +OpenCV defines the following Size_\<\> aliases: +@code + typedef Size_ Size2i; + typedef Size2i Size; + typedef Size_ Size2f; +@endcode +*/ +template class Size_ +{ +public: + typedef _Tp value_type; + + //! default constructor + Size_(); + Size_(_Tp _width, _Tp _height); +#if OPENCV_ABI_COMPATIBILITY < 500 + Size_(const Size_& sz) = default; + Size_(Size_&& sz) CV_NOEXCEPT = default; +#endif + Size_(const Point_<_Tp>& pt); + +#if OPENCV_ABI_COMPATIBILITY < 500 + Size_& operator = (const Size_& sz) = default; + Size_& operator = (Size_&& sz) CV_NOEXCEPT = default; +#endif + //! the area (width*height) + _Tp area() const; + //! aspect ratio (width/height) + double aspectRatio() const; + //! true if empty + bool empty() const; + + //! conversion of another data type. + template operator Size_<_Tp2>() const; + + _Tp width; //!< the width + _Tp height; //!< the height +}; + +typedef Size_ Size2i; +typedef Size_ Size2l; +typedef Size_ Size2f; +typedef Size_ Size2d; +typedef Size2i Size; + +template class DataType< Size_<_Tp> > +{ +public: + typedef Size_<_Tp> value_type; + typedef Size_::work_type> work_type; + typedef _Tp channel_type; + + enum { generic_type = 0, + channels = 2, + fmt = DataType::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif + }; + + typedef Vec vec_type; +}; + +namespace traits { +template +struct Depth< Size_<_Tp> > { enum { value = Depth<_Tp>::value }; }; +template +struct Type< Size_<_Tp> > { enum { value = CV_MAKETYPE(Depth<_Tp>::value, 2) }; }; +} // namespace + +//////////////////////////////// Rect_ //////////////////////////////// + +/** @brief Template class for 2D rectangles + +described by the following parameters: +- Coordinates of the top-left corner. This is a default interpretation of Rect_::x and Rect_::y + in OpenCV. Though, in your algorithms you may count x and y from the bottom-left corner. +- Rectangle width and height. + +OpenCV typically assumes that the top and left boundary of the rectangle are inclusive, while the +right and bottom boundaries are not. For example, the method Rect_::contains returns true if + +\f[x \leq pt.x < x+width, + y \leq pt.y < y+height\f] + +Virtually every loop over an image ROI in OpenCV (where ROI is specified by Rect_\ ) is +implemented as: +@code + for(int y = roi.y; y < roi.y + roi.height; y++) + for(int x = roi.x; x < roi.x + roi.width; x++) + { + // ... + } +@endcode +In addition to the class members, the following operations on rectangles are implemented: +- \f$\texttt{rect} = \texttt{rect} \pm \texttt{point}\f$ (shifting a rectangle by a certain offset) +- \f$\texttt{rect} = \texttt{rect} \pm \texttt{size}\f$ (expanding or shrinking a rectangle by a + certain amount) +- rect += point, rect -= point, rect += size, rect -= size (augmenting operations) +- rect = rect1 & rect2 (rectangle intersection) +- rect = rect1 | rect2 (minimum area rectangle containing rect1 and rect2 ) +- rect &= rect1, rect |= rect1 (and the corresponding augmenting operations) +- rect == rect1, rect != rect1 (rectangle comparison) + +This is an example how the partial ordering on rectangles can be established (rect1 \f$\subseteq\f$ +rect2): +@code + template inline bool + operator <= (const Rect_<_Tp>& r1, const Rect_<_Tp>& r2) + { + return (r1 & r2) == r1; + } +@endcode +For your convenience, the Rect_\<\> alias is available: cv::Rect +*/ +template class Rect_ +{ +public: + typedef _Tp value_type; + + //! default constructor + Rect_(); + Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height); +#if OPENCV_ABI_COMPATIBILITY < 500 + Rect_(const Rect_& r) = default; + Rect_(Rect_&& r) CV_NOEXCEPT = default; +#endif + Rect_(const Point_<_Tp>& org, const Size_<_Tp>& sz); + Rect_(const Point_<_Tp>& pt1, const Point_<_Tp>& pt2); + +#if OPENCV_ABI_COMPATIBILITY < 500 + Rect_& operator = (const Rect_& r) = default; + Rect_& operator = (Rect_&& r) CV_NOEXCEPT = default; +#endif + //! the top-left corner + Point_<_Tp> tl() const; + //! the bottom-right corner + Point_<_Tp> br() const; + + //! size (width, height) of the rectangle + Size_<_Tp> size() const; + //! area (width*height) of the rectangle + _Tp area() const; + //! true if empty + bool empty() const; + + //! conversion to another data type + template operator Rect_<_Tp2>() const; + + //! checks whether the rectangle contains the point + bool contains(const Point_<_Tp>& pt) const; + + _Tp x; //!< x coordinate of the top-left corner + _Tp y; //!< y coordinate of the top-left corner + _Tp width; //!< width of the rectangle + _Tp height; //!< height of the rectangle +}; + +typedef Rect_ Rect2i; +typedef Rect_ Rect2f; +typedef Rect_ Rect2d; +typedef Rect2i Rect; + +template class DataType< Rect_<_Tp> > +{ +public: + typedef Rect_<_Tp> value_type; + typedef Rect_::work_type> work_type; + typedef _Tp channel_type; + + enum { generic_type = 0, + channels = 4, + fmt = traits::SafeFmt::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif + }; + + typedef Vec vec_type; +}; + +namespace traits { +template +struct Depth< Rect_<_Tp> > { enum { value = Depth<_Tp>::value }; }; +template +struct Type< Rect_<_Tp> > { enum { value = CV_MAKETYPE(Depth<_Tp>::value, 4) }; }; +} // namespace + +///////////////////////////// RotatedRect ///////////////////////////// + +/** @brief The class represents rotated (i.e. not up-right) rectangles on a plane. + +Each rectangle is specified by the center point (mass center), length of each side (represented by +#Size2f structure) and the rotation angle in degrees. + +The sample below demonstrates how to use RotatedRect: +@snippet snippets/core_various.cpp RotatedRect_demo +![image](pics/rotatedrect.png) + +@sa CamShift, fitEllipse, minAreaRect, CvBox2D +*/ +class CV_EXPORTS RotatedRect +{ +public: + //! default constructor + RotatedRect(); + /** full constructor + @param center The rectangle mass center. + @param size Width and height of the rectangle. + @param angle The rotation angle in a clockwise direction. When the angle is 0, 90, 180, 270 etc., + the rectangle becomes an up-right rectangle. + */ + RotatedRect(const Point2f& center, const Size2f& size, float angle); + /** + Any 3 end points of the RotatedRect. They must be given in order (either clockwise or + anticlockwise). + */ + RotatedRect(const Point2f& point1, const Point2f& point2, const Point2f& point3); + + /** returns 4 vertices of the rectangle + @param pts The points array for storing rectangle vertices. The order is bottomLeft, topLeft, topRight, bottomRight. + */ + void points(Point2f pts[]) const; + //! returns the minimal up-right integer rectangle containing the rotated rectangle + Rect boundingRect() const; + //! returns the minimal (exact) floating point rectangle containing the rotated rectangle, not intended for use with images + Rect_ boundingRect2f() const; + //! returns the rectangle mass center + Point2f center; + //! returns width and height of the rectangle + Size2f size; + //! returns the rotation angle. When the angle is 0, 90, 180, 270 etc., the rectangle becomes an up-right rectangle. + float angle; +}; + +template<> class DataType< RotatedRect > +{ +public: + typedef RotatedRect value_type; + typedef value_type work_type; + typedef float channel_type; + + enum { generic_type = 0, + channels = (int)sizeof(value_type)/sizeof(channel_type), // 5 + fmt = traits::SafeFmt::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif + }; + + typedef Vec vec_type; +}; + +namespace traits { +template<> +struct Depth< RotatedRect > { enum { value = Depth::value }; }; +template<> +struct Type< RotatedRect > { enum { value = CV_MAKETYPE(Depth::value, (int)sizeof(RotatedRect)/sizeof(float)) }; }; +} // namespace + + +//////////////////////////////// Range ///////////////////////////////// + +/** @brief Template class specifying a continuous subsequence (slice) of a sequence. + +The class is used to specify a row or a column span in a matrix ( Mat ) and for many other purposes. +Range(a,b) is basically the same as a:b in Matlab or a..b in Python. As in Python, start is an +inclusive left boundary of the range and end is an exclusive right boundary of the range. Such a +half-opened interval is usually denoted as \f$[start,end)\f$ . + +The static method Range::all() returns a special variable that means "the whole sequence" or "the +whole range", just like " : " in Matlab or " ... " in Python. All the methods and functions in +OpenCV that take Range support this special Range::all() value. But, of course, in case of your own +custom processing, you will probably have to check and handle it explicitly: +@code + void my_function(..., const Range& r, ....) + { + if(r == Range::all()) { + // process all the data + } + else { + // process [r.start, r.end) + } + } +@endcode +*/ +class CV_EXPORTS Range +{ +public: + Range(); + Range(int _start, int _end); + int size() const; + bool empty() const; + static Range all(); + + int start, end; +}; + +template<> class DataType +{ +public: + typedef Range value_type; + typedef value_type work_type; + typedef int channel_type; + + enum { generic_type = 0, + channels = 2, + fmt = traits::SafeFmt::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif + }; + + typedef Vec vec_type; +}; + +namespace traits { +template<> +struct Depth< Range > { enum { value = Depth::value }; }; +template<> +struct Type< Range > { enum { value = CV_MAKETYPE(Depth::value, 2) }; }; +} // namespace + + +//////////////////////////////// Scalar_ /////////////////////////////// + +/** @brief Template class for a 4-element vector derived from Vec. + +Being derived from Vec\<_Tp, 4\> , Scalar\_ and Scalar can be used just as typical 4-element +vectors. In addition, they can be converted to/from CvScalar . The type Scalar is widely used in +OpenCV to pass pixel values. +*/ +template class Scalar_ : public Vec<_Tp, 4> +{ +public: + //! default constructor + Scalar_(); + Scalar_(_Tp v0, _Tp v1, _Tp v2=0, _Tp v3=0); + Scalar_(_Tp v0); + + Scalar_(const Scalar_& s); + Scalar_(Scalar_&& s) CV_NOEXCEPT; + + Scalar_& operator=(const Scalar_& s); + Scalar_& operator=(Scalar_&& s) CV_NOEXCEPT; + + template + Scalar_(const Vec<_Tp2, cn>& v); + + //! returns a scalar with all elements set to v0 + static Scalar_<_Tp> all(_Tp v0); + + //! conversion to another data type + template operator Scalar_() const; + + //! per-element product + Scalar_<_Tp> mul(const Scalar_<_Tp>& a, double scale=1 ) const; + + //! returns (v0, -v1, -v2, -v3) + Scalar_<_Tp> conj() const; + + //! returns true iff v1 == v2 == v3 == 0 + bool isReal() const; +}; + +typedef Scalar_ Scalar; + +template class DataType< Scalar_<_Tp> > +{ +public: + typedef Scalar_<_Tp> value_type; + typedef Scalar_::work_type> work_type; + typedef _Tp channel_type; + + enum { generic_type = 0, + channels = 4, + fmt = traits::SafeFmt::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif + }; + + typedef Vec vec_type; +}; + +namespace traits { +template +struct Depth< Scalar_<_Tp> > { enum { value = Depth<_Tp>::value }; }; +template +struct Type< Scalar_<_Tp> > { enum { value = CV_MAKETYPE(Depth<_Tp>::value, 4) }; }; +} // namespace + + +/////////////////////////////// KeyPoint //////////////////////////////// + +/** @brief Data structure for salient point detectors. + +The class instance stores a keypoint, i.e. a point feature found by one of many available keypoint +detectors, such as Harris corner detector, #FAST, %StarDetector, %SURF, %SIFT etc. + +The keypoint is characterized by the 2D position, scale (proportional to the diameter of the +neighborhood that needs to be taken into account), orientation and some other parameters. The +keypoint neighborhood is then analyzed by another algorithm that builds a descriptor (usually +represented as a feature vector). The keypoints representing the same object in different images +can then be matched using %KDTree or another method. +*/ +class CV_EXPORTS_W_SIMPLE KeyPoint +{ +public: + //! the default constructor + CV_WRAP KeyPoint(); + /** + @param pt x & y coordinates of the keypoint + @param size keypoint diameter + @param angle keypoint orientation + @param response keypoint detector response on the keypoint (that is, strength of the keypoint) + @param octave pyramid octave in which the keypoint has been detected + @param class_id object id + */ + KeyPoint(Point2f pt, float size, float angle=-1, float response=0, int octave=0, int class_id=-1); + /** + @param x x-coordinate of the keypoint + @param y y-coordinate of the keypoint + @param size keypoint diameter + @param angle keypoint orientation + @param response keypoint detector response on the keypoint (that is, strength of the keypoint) + @param octave pyramid octave in which the keypoint has been detected + @param class_id object id + */ + CV_WRAP KeyPoint(float x, float y, float size, float angle=-1, float response=0, int octave=0, int class_id=-1); + + size_t hash() const; + + /** + This method converts vector of keypoints to vector of points or the reverse, where each keypoint is + assigned the same size and the same orientation. + + @param keypoints Keypoints obtained from any feature detection algorithm like SIFT/SURF/ORB + @param points2f Array of (x,y) coordinates of each keypoint + @param keypointIndexes Array of indexes of keypoints to be converted to points. (Acts like a mask to + convert only specified keypoints) + */ + CV_WRAP static void convert(const std::vector& keypoints, + CV_OUT std::vector& points2f, + const std::vector& keypointIndexes=std::vector()); + /** @overload + @param points2f Array of (x,y) coordinates of each keypoint + @param keypoints Keypoints obtained from any feature detection algorithm like SIFT/SURF/ORB + @param size keypoint diameter + @param response keypoint detector response on the keypoint (that is, strength of the keypoint) + @param octave pyramid octave in which the keypoint has been detected + @param class_id object id + */ + CV_WRAP static void convert(const std::vector& points2f, + CV_OUT std::vector& keypoints, + float size=1, float response=1, int octave=0, int class_id=-1); + + /** + This method computes overlap for pair of keypoints. Overlap is the ratio between area of keypoint + regions' intersection and area of keypoint regions' union (considering keypoint region as circle). + If they don't overlap, we get zero. If they coincide at same location with same size, we get 1. + @param kp1 First keypoint + @param kp2 Second keypoint + */ + CV_WRAP static float overlap(const KeyPoint& kp1, const KeyPoint& kp2); + + CV_PROP_RW Point2f pt; //!< coordinates of the keypoints + CV_PROP_RW float size; //!< diameter of the meaningful keypoint neighborhood + CV_PROP_RW float angle; //!< computed orientation of the keypoint (-1 if not applicable); + //!< it's in [0,360) degrees and measured relative to + //!< image coordinate system, ie in clockwise. + CV_PROP_RW float response; //!< the response by which the most strong keypoints have been selected. Can be used for the further sorting or subsampling + CV_PROP_RW int octave; //!< octave (pyramid layer) from which the keypoint has been extracted + CV_PROP_RW int class_id; //!< object class (if the keypoints need to be clustered by an object they belong to) +}; + +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED +template<> class DataType +{ +public: + typedef KeyPoint value_type; + typedef float work_type; + typedef float channel_type; + + enum { generic_type = 0, + depth = DataType::depth, + channels = (int)(sizeof(value_type)/sizeof(channel_type)), // 7 + fmt = DataType::fmt + ((channels - 1) << 8), + type = CV_MAKETYPE(depth, channels) + }; + + typedef Vec vec_type; +}; +#endif + + +//////////////////////////////// DMatch ///////////////////////////////// + +/** @brief Class for matching keypoint descriptors + +query descriptor index, train descriptor index, train image index, and distance between +descriptors. +*/ +class CV_EXPORTS_W_SIMPLE DMatch +{ +public: + CV_WRAP DMatch(); + CV_WRAP DMatch(int _queryIdx, int _trainIdx, float _distance); + CV_WRAP DMatch(int _queryIdx, int _trainIdx, int _imgIdx, float _distance); + + CV_PROP_RW int queryIdx; //!< query descriptor index + CV_PROP_RW int trainIdx; //!< train descriptor index + CV_PROP_RW int imgIdx; //!< train image index + + CV_PROP_RW float distance; + + // less is better + bool operator<(const DMatch &m) const; +}; + +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED +template<> class DataType +{ +public: + typedef DMatch value_type; + typedef int work_type; + typedef int channel_type; + + enum { generic_type = 0, + depth = DataType::depth, + channels = (int)(sizeof(value_type)/sizeof(channel_type)), // 4 + fmt = DataType::fmt + ((channels - 1) << 8), + type = CV_MAKETYPE(depth, channels) + }; + + typedef Vec vec_type; +}; +#endif + + +///////////////////////////// TermCriteria ////////////////////////////// + +/** @brief The class defining termination criteria for iterative algorithms. + +You can initialize it by default constructor and then override any parameters, or the structure may +be fully initialized using the advanced variant of the constructor. +*/ +class CV_EXPORTS TermCriteria +{ +public: + /** + Criteria type, can be one of: COUNT, EPS or COUNT + EPS + */ + enum Type + { + COUNT=1, //!< the maximum number of iterations or elements to compute + MAX_ITER=COUNT, //!< ditto + EPS=2 //!< the desired accuracy or change in parameters at which the iterative algorithm stops + }; + + //! default constructor + TermCriteria(); + /** + @param type The type of termination criteria, one of TermCriteria::Type + @param maxCount The maximum number of iterations or elements to compute. + @param epsilon The desired accuracy or change in parameters at which the iterative algorithm stops. + */ + TermCriteria(int type, int maxCount, double epsilon); + + inline bool isValid() const + { + const bool isCount = (type & COUNT) && maxCount > 0; + const bool isEps = (type & EPS) && !cvIsNaN(epsilon); + return isCount || isEps; + } + + int type; //!< the type of termination criteria: COUNT, EPS or COUNT + EPS + int maxCount; //!< the maximum number of iterations/elements + double epsilon; //!< the desired accuracy +}; + + +//! @} core_basic + +///////////////////////// raster image moments ////////////////////////// + +//! @addtogroup imgproc_shape +//! @{ + +/** @brief struct returned by cv::moments + +The spatial moments \f$\texttt{Moments::m}_{ji}\f$ are computed as: + +\f[\texttt{m} _{ji}= \sum _{x,y} \left ( \texttt{array} (x,y) \cdot x^j \cdot y^i \right )\f] + +The central moments \f$\texttt{Moments::mu}_{ji}\f$ are computed as: + +\f[\texttt{mu} _{ji}= \sum _{x,y} \left ( \texttt{array} (x,y) \cdot (x - \bar{x} )^j \cdot (y - \bar{y} )^i \right )\f] + +where \f$(\bar{x}, \bar{y})\f$ is the mass center: + +\f[\bar{x} = \frac{\texttt{m}_{10}}{\texttt{m}_{00}} , \; \bar{y} = \frac{\texttt{m}_{01}}{\texttt{m}_{00}}\f] + +The normalized central moments \f$\texttt{Moments::nu}_{ij}\f$ are computed as: + +\f[\texttt{nu} _{ji}= \frac{\texttt{mu}_{ji}}{\texttt{m}_{00}^{(i+j)/2+1}} .\f] + +@note +\f$\texttt{mu}_{00}=\texttt{m}_{00}\f$, \f$\texttt{nu}_{00}=1\f$ +\f$\texttt{nu}_{10}=\texttt{mu}_{10}=\texttt{mu}_{01}=\texttt{mu}_{10}=0\f$ , hence the values are not +stored. + +The moments of a contour are defined in the same way but computed using the Green's formula (see +). So, due to a limited raster resolution, the moments +computed for a contour are slightly different from the moments computed for the same rasterized +contour. + +@note +Since the contour moments are computed using Green formula, you may get seemingly odd results for +contours with self-intersections, e.g. a zero area (m00) for butterfly-shaped contours. + */ +class CV_EXPORTS_W_MAP Moments +{ +public: + //! the default constructor + Moments(); + //! the full constructor + Moments(double m00, double m10, double m01, double m20, double m11, + double m02, double m30, double m21, double m12, double m03 ); + ////! the conversion from CvMoments + //Moments( const CvMoments& moments ); + ////! the conversion to CvMoments + //operator CvMoments() const; + + //! @name spatial moments + //! @{ + CV_PROP_RW double m00, m10, m01, m20, m11, m02, m30, m21, m12, m03; + //! @} + + //! @name central moments + //! @{ + CV_PROP_RW double mu20, mu11, mu02, mu30, mu21, mu12, mu03; + //! @} + + //! @name central normalized moments + //! @{ + CV_PROP_RW double nu20, nu11, nu02, nu30, nu21, nu12, nu03; + //! @} +}; + +template<> class DataType +{ +public: + typedef Moments value_type; + typedef double work_type; + typedef double channel_type; + + enum { generic_type = 0, + channels = (int)(sizeof(value_type)/sizeof(channel_type)), // 24 + fmt = DataType::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + ,depth = DataType::depth + ,type = CV_MAKETYPE(depth, channels) +#endif + }; + + typedef Vec vec_type; +}; + +namespace traits { +template<> +struct Depth< Moments > { enum { value = Depth::value }; }; +template<> +struct Type< Moments > { enum { value = CV_MAKETYPE(Depth::value, (int)(sizeof(Moments)/sizeof(double))) }; }; +} // namespace + +//! @} imgproc_shape + +//! @cond IGNORED + +///////////////////////////////////////////////////////////////////////// +///////////////////////////// Implementation //////////////////////////// +///////////////////////////////////////////////////////////////////////// + +//////////////////////////////// Complex //////////////////////////////// + +template inline +Complex<_Tp>::Complex() + : re(0), im(0) {} + +template inline +Complex<_Tp>::Complex( _Tp _re, _Tp _im ) + : re(_re), im(_im) {} + +template template inline +Complex<_Tp>::operator Complex() const +{ + return Complex(saturate_cast(re), saturate_cast(im)); +} + +template inline +Complex<_Tp> Complex<_Tp>::conj() const +{ + return Complex<_Tp>(re, -im); +} + + +template static inline +bool operator == (const Complex<_Tp>& a, const Complex<_Tp>& b) +{ + return a.re == b.re && a.im == b.im; +} + +template static inline +bool operator != (const Complex<_Tp>& a, const Complex<_Tp>& b) +{ + return a.re != b.re || a.im != b.im; +} + +template static inline +Complex<_Tp> operator + (const Complex<_Tp>& a, const Complex<_Tp>& b) +{ + return Complex<_Tp>( a.re + b.re, a.im + b.im ); +} + +template static inline +Complex<_Tp>& operator += (Complex<_Tp>& a, const Complex<_Tp>& b) +{ + a.re += b.re; a.im += b.im; + return a; +} + +template static inline +Complex<_Tp> operator - (const Complex<_Tp>& a, const Complex<_Tp>& b) +{ + return Complex<_Tp>( a.re - b.re, a.im - b.im ); +} + +template static inline +Complex<_Tp>& operator -= (Complex<_Tp>& a, const Complex<_Tp>& b) +{ + a.re -= b.re; a.im -= b.im; + return a; +} + +template static inline +Complex<_Tp> operator - (const Complex<_Tp>& a) +{ + return Complex<_Tp>(-a.re, -a.im); +} + +template static inline +Complex<_Tp> operator * (const Complex<_Tp>& a, const Complex<_Tp>& b) +{ + return Complex<_Tp>( a.re*b.re - a.im*b.im, a.re*b.im + a.im*b.re ); +} + +template static inline +Complex<_Tp> operator * (const Complex<_Tp>& a, _Tp b) +{ + return Complex<_Tp>( a.re*b, a.im*b ); +} + +template static inline +Complex<_Tp> operator * (_Tp b, const Complex<_Tp>& a) +{ + return Complex<_Tp>( a.re*b, a.im*b ); +} + +template static inline +Complex<_Tp> operator + (const Complex<_Tp>& a, _Tp b) +{ + return Complex<_Tp>( a.re + b, a.im ); +} + +template static inline +Complex<_Tp> operator - (const Complex<_Tp>& a, _Tp b) +{ return Complex<_Tp>( a.re - b, a.im ); } + +template static inline +Complex<_Tp> operator + (_Tp b, const Complex<_Tp>& a) +{ + return Complex<_Tp>( a.re + b, a.im ); +} + +template static inline +Complex<_Tp> operator - (_Tp b, const Complex<_Tp>& a) +{ + return Complex<_Tp>( b - a.re, -a.im ); +} + +template static inline +Complex<_Tp>& operator += (Complex<_Tp>& a, _Tp b) +{ + a.re += b; return a; +} + +template static inline +Complex<_Tp>& operator -= (Complex<_Tp>& a, _Tp b) +{ + a.re -= b; return a; +} + +template static inline +Complex<_Tp>& operator *= (Complex<_Tp>& a, _Tp b) +{ + a.re *= b; a.im *= b; return a; +} + +template static inline +double abs(const Complex<_Tp>& a) +{ + return std::sqrt( (double)a.re*a.re + (double)a.im*a.im); +} + +template static inline +Complex<_Tp> operator / (const Complex<_Tp>& a, const Complex<_Tp>& b) +{ + double t = 1./((double)b.re*b.re + (double)b.im*b.im); + return Complex<_Tp>( (_Tp)((a.re*b.re + a.im*b.im)*t), + (_Tp)((-a.re*b.im + a.im*b.re)*t) ); +} + +template static inline +Complex<_Tp>& operator /= (Complex<_Tp>& a, const Complex<_Tp>& b) +{ + a = a / b; + return a; +} + +template static inline +Complex<_Tp> operator / (const Complex<_Tp>& a, _Tp b) +{ + _Tp t = (_Tp)1/b; + return Complex<_Tp>( a.re*t, a.im*t ); +} + +template static inline +Complex<_Tp> operator / (_Tp b, const Complex<_Tp>& a) +{ + return Complex<_Tp>(b)/a; +} + +template static inline +Complex<_Tp> operator /= (const Complex<_Tp>& a, _Tp b) +{ + _Tp t = (_Tp)1/b; + a.re *= t; a.im *= t; return a; +} + + + +//////////////////////////////// 2D Point /////////////////////////////// + +template inline +Point_<_Tp>::Point_() + : x(0), y(0) {} + +template inline +Point_<_Tp>::Point_(_Tp _x, _Tp _y) + : x(_x), y(_y) {} + +#if (defined(__GNUC__) && __GNUC__ < 5) && !defined(__clang__) // GCC 4.x bug. Details: https://github.com/opencv/opencv/pull/20837 +template inline +Point_<_Tp>::Point_(const Point_& pt) + : x(pt.x), y(pt.y) {} +#endif + +template inline +Point_<_Tp>::Point_(const Size_<_Tp>& sz) + : x(sz.width), y(sz.height) {} + +template inline +Point_<_Tp>::Point_(const Vec<_Tp,2>& v) + : x(v[0]), y(v[1]) {} + +#if (defined(__GNUC__) && __GNUC__ < 5) && !defined(__clang__) // GCC 4.x bug. Details: https://github.com/opencv/opencv/pull/20837 +template inline +Point_<_Tp>& Point_<_Tp>::operator = (const Point_& pt) +{ + x = pt.x; y = pt.y; + return *this; +} +#endif + +template template inline +Point_<_Tp>::operator Point_<_Tp2>() const +{ + return Point_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y)); +} + +template inline +Point_<_Tp>::operator Vec<_Tp, 2>() const +{ + return Vec<_Tp, 2>(x, y); +} + +template inline +_Tp Point_<_Tp>::dot(const Point_& pt) const +{ + return saturate_cast<_Tp>(x*pt.x + y*pt.y); +} + +template inline +double Point_<_Tp>::ddot(const Point_& pt) const +{ + return (double)x*(double)(pt.x) + (double)y*(double)(pt.y); +} + +template inline +double Point_<_Tp>::cross(const Point_& pt) const +{ + return (double)x*pt.y - (double)y*pt.x; +} + +template inline bool +Point_<_Tp>::inside( const Rect_<_Tp>& r ) const +{ + return r.contains(*this); +} + + +template static inline +Point_<_Tp>& operator += (Point_<_Tp>& a, const Point_<_Tp>& b) +{ + a.x += b.x; + a.y += b.y; + return a; +} + +template static inline +Point_<_Tp>& operator -= (Point_<_Tp>& a, const Point_<_Tp>& b) +{ + a.x -= b.x; + a.y -= b.y; + return a; +} + +template static inline +Point_<_Tp>& operator *= (Point_<_Tp>& a, int b) +{ + a.x = saturate_cast<_Tp>(a.x * b); + a.y = saturate_cast<_Tp>(a.y * b); + return a; +} + +template static inline +Point_<_Tp>& operator *= (Point_<_Tp>& a, float b) +{ + a.x = saturate_cast<_Tp>(a.x * b); + a.y = saturate_cast<_Tp>(a.y * b); + return a; +} + +template static inline +Point_<_Tp>& operator *= (Point_<_Tp>& a, double b) +{ + a.x = saturate_cast<_Tp>(a.x * b); + a.y = saturate_cast<_Tp>(a.y * b); + return a; +} + +template static inline +Point_<_Tp>& operator /= (Point_<_Tp>& a, int b) +{ + a.x = saturate_cast<_Tp>(a.x / b); + a.y = saturate_cast<_Tp>(a.y / b); + return a; +} + +template static inline +Point_<_Tp>& operator /= (Point_<_Tp>& a, float b) +{ + a.x = saturate_cast<_Tp>(a.x / b); + a.y = saturate_cast<_Tp>(a.y / b); + return a; +} + +template static inline +Point_<_Tp>& operator /= (Point_<_Tp>& a, double b) +{ + a.x = saturate_cast<_Tp>(a.x / b); + a.y = saturate_cast<_Tp>(a.y / b); + return a; +} + +template static inline +double norm(const Point_<_Tp>& pt) +{ + return std::sqrt((double)pt.x*pt.x + (double)pt.y*pt.y); +} + +template static inline +bool operator == (const Point_<_Tp>& a, const Point_<_Tp>& b) +{ + return a.x == b.x && a.y == b.y; +} + +template static inline +bool operator != (const Point_<_Tp>& a, const Point_<_Tp>& b) +{ + return a.x != b.x || a.y != b.y; +} + +template static inline +Point_<_Tp> operator + (const Point_<_Tp>& a, const Point_<_Tp>& b) +{ + return Point_<_Tp>( saturate_cast<_Tp>(a.x + b.x), saturate_cast<_Tp>(a.y + b.y) ); +} + +template static inline +Point_<_Tp> operator - (const Point_<_Tp>& a, const Point_<_Tp>& b) +{ + return Point_<_Tp>( saturate_cast<_Tp>(a.x - b.x), saturate_cast<_Tp>(a.y - b.y) ); +} + +template static inline +Point_<_Tp> operator - (const Point_<_Tp>& a) +{ + return Point_<_Tp>( saturate_cast<_Tp>(-a.x), saturate_cast<_Tp>(-a.y) ); +} + +template static inline +Point_<_Tp> operator * (const Point_<_Tp>& a, int b) +{ + return Point_<_Tp>( saturate_cast<_Tp>(a.x*b), saturate_cast<_Tp>(a.y*b) ); +} + +template static inline +Point_<_Tp> operator * (int a, const Point_<_Tp>& b) +{ + return Point_<_Tp>( saturate_cast<_Tp>(b.x*a), saturate_cast<_Tp>(b.y*a) ); +} + +template static inline +Point_<_Tp> operator * (const Point_<_Tp>& a, float b) +{ + return Point_<_Tp>( saturate_cast<_Tp>(a.x*b), saturate_cast<_Tp>(a.y*b) ); +} + +template static inline +Point_<_Tp> operator * (float a, const Point_<_Tp>& b) +{ + return Point_<_Tp>( saturate_cast<_Tp>(b.x*a), saturate_cast<_Tp>(b.y*a) ); +} + +template static inline +Point_<_Tp> operator * (const Point_<_Tp>& a, double b) +{ + return Point_<_Tp>( saturate_cast<_Tp>(a.x*b), saturate_cast<_Tp>(a.y*b) ); +} + +template static inline +Point_<_Tp> operator * (double a, const Point_<_Tp>& b) +{ + return Point_<_Tp>( saturate_cast<_Tp>(b.x*a), saturate_cast<_Tp>(b.y*a) ); +} + +template static inline +Point_<_Tp> operator * (const Matx<_Tp, 2, 2>& a, const Point_<_Tp>& b) +{ + Matx<_Tp, 2, 1> tmp = a * Vec<_Tp,2>(b.x, b.y); + return Point_<_Tp>(tmp.val[0], tmp.val[1]); +} + +template static inline +Point3_<_Tp> operator * (const Matx<_Tp, 3, 3>& a, const Point_<_Tp>& b) +{ + Matx<_Tp, 3, 1> tmp = a * Vec<_Tp,3>(b.x, b.y, 1); + return Point3_<_Tp>(tmp.val[0], tmp.val[1], tmp.val[2]); +} + +template static inline +Point_<_Tp> operator / (const Point_<_Tp>& a, int b) +{ + Point_<_Tp> tmp(a); + tmp /= b; + return tmp; +} + +template static inline +Point_<_Tp> operator / (const Point_<_Tp>& a, float b) +{ + Point_<_Tp> tmp(a); + tmp /= b; + return tmp; +} + +template static inline +Point_<_Tp> operator / (const Point_<_Tp>& a, double b) +{ + Point_<_Tp> tmp(a); + tmp /= b; + return tmp; +} + + +template static inline _AccTp normL2Sqr(const Point_& pt); +template static inline _AccTp normL2Sqr(const Point_& pt); +template static inline _AccTp normL2Sqr(const Point_& pt); +template static inline _AccTp normL2Sqr(const Point_& pt); + +template<> inline int normL2Sqr(const Point_& pt) { return pt.dot(pt); } +template<> inline int64 normL2Sqr(const Point_& pt) { return pt.dot(pt); } +template<> inline float normL2Sqr(const Point_& pt) { return pt.dot(pt); } +template<> inline double normL2Sqr(const Point_& pt) { return pt.dot(pt); } + +template<> inline double normL2Sqr(const Point_& pt) { return pt.ddot(pt); } +template<> inline double normL2Sqr(const Point_& pt) { return pt.ddot(pt); } + + + +//////////////////////////////// 3D Point /////////////////////////////// + +template inline +Point3_<_Tp>::Point3_() + : x(0), y(0), z(0) {} + +template inline +Point3_<_Tp>::Point3_(_Tp _x, _Tp _y, _Tp _z) + : x(_x), y(_y), z(_z) {} + +template inline +Point3_<_Tp>::Point3_(const Point_<_Tp>& pt) + : x(pt.x), y(pt.y), z(_Tp()) {} + +template inline +Point3_<_Tp>::Point3_(const Vec<_Tp, 3>& v) + : x(v[0]), y(v[1]), z(v[2]) {} + +template template inline +Point3_<_Tp>::operator Point3_<_Tp2>() const +{ + return Point3_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y), saturate_cast<_Tp2>(z)); +} + +template inline +Point3_<_Tp>::operator Vec<_Tp, 3>() const +{ + return Vec<_Tp, 3>(x, y, z); +} + +template inline +_Tp Point3_<_Tp>::dot(const Point3_& pt) const +{ + return saturate_cast<_Tp>(x*pt.x + y*pt.y + z*pt.z); +} + +template inline +double Point3_<_Tp>::ddot(const Point3_& pt) const +{ + return (double)x*pt.x + (double)y*pt.y + (double)z*pt.z; +} + +template inline +Point3_<_Tp> Point3_<_Tp>::cross(const Point3_<_Tp>& pt) const +{ + return Point3_<_Tp>(y*pt.z - z*pt.y, z*pt.x - x*pt.z, x*pt.y - y*pt.x); +} + + +template static inline +Point3_<_Tp>& operator += (Point3_<_Tp>& a, const Point3_<_Tp>& b) +{ + a.x += b.x; + a.y += b.y; + a.z += b.z; + return a; +} + +template static inline +Point3_<_Tp>& operator -= (Point3_<_Tp>& a, const Point3_<_Tp>& b) +{ + a.x -= b.x; + a.y -= b.y; + a.z -= b.z; + return a; +} + +template static inline +Point3_<_Tp>& operator *= (Point3_<_Tp>& a, int b) +{ + a.x = saturate_cast<_Tp>(a.x * b); + a.y = saturate_cast<_Tp>(a.y * b); + a.z = saturate_cast<_Tp>(a.z * b); + return a; +} + +template static inline +Point3_<_Tp>& operator *= (Point3_<_Tp>& a, float b) +{ + a.x = saturate_cast<_Tp>(a.x * b); + a.y = saturate_cast<_Tp>(a.y * b); + a.z = saturate_cast<_Tp>(a.z * b); + return a; +} + +template static inline +Point3_<_Tp>& operator *= (Point3_<_Tp>& a, double b) +{ + a.x = saturate_cast<_Tp>(a.x * b); + a.y = saturate_cast<_Tp>(a.y * b); + a.z = saturate_cast<_Tp>(a.z * b); + return a; +} + +template static inline +Point3_<_Tp>& operator /= (Point3_<_Tp>& a, int b) +{ + a.x = saturate_cast<_Tp>(a.x / b); + a.y = saturate_cast<_Tp>(a.y / b); + a.z = saturate_cast<_Tp>(a.z / b); + return a; +} + +template static inline +Point3_<_Tp>& operator /= (Point3_<_Tp>& a, float b) +{ + a.x = saturate_cast<_Tp>(a.x / b); + a.y = saturate_cast<_Tp>(a.y / b); + a.z = saturate_cast<_Tp>(a.z / b); + return a; +} + +template static inline +Point3_<_Tp>& operator /= (Point3_<_Tp>& a, double b) +{ + a.x = saturate_cast<_Tp>(a.x / b); + a.y = saturate_cast<_Tp>(a.y / b); + a.z = saturate_cast<_Tp>(a.z / b); + return a; +} + +template static inline +double norm(const Point3_<_Tp>& pt) +{ + return std::sqrt((double)pt.x*pt.x + (double)pt.y*pt.y + (double)pt.z*pt.z); +} + +template static inline +bool operator == (const Point3_<_Tp>& a, const Point3_<_Tp>& b) +{ + return a.x == b.x && a.y == b.y && a.z == b.z; +} + +template static inline +bool operator != (const Point3_<_Tp>& a, const Point3_<_Tp>& b) +{ + return a.x != b.x || a.y != b.y || a.z != b.z; +} + +template static inline +Point3_<_Tp> operator + (const Point3_<_Tp>& a, const Point3_<_Tp>& b) +{ + return Point3_<_Tp>( saturate_cast<_Tp>(a.x + b.x), saturate_cast<_Tp>(a.y + b.y), saturate_cast<_Tp>(a.z + b.z)); +} + +template static inline +Point3_<_Tp> operator - (const Point3_<_Tp>& a, const Point3_<_Tp>& b) +{ + return Point3_<_Tp>( saturate_cast<_Tp>(a.x - b.x), saturate_cast<_Tp>(a.y - b.y), saturate_cast<_Tp>(a.z - b.z)); +} + +template static inline +Point3_<_Tp> operator - (const Point3_<_Tp>& a) +{ + return Point3_<_Tp>( saturate_cast<_Tp>(-a.x), saturate_cast<_Tp>(-a.y), saturate_cast<_Tp>(-a.z) ); +} + +template static inline +Point3_<_Tp> operator * (const Point3_<_Tp>& a, int b) +{ + return Point3_<_Tp>( saturate_cast<_Tp>(a.x*b), saturate_cast<_Tp>(a.y*b), saturate_cast<_Tp>(a.z*b) ); +} + +template static inline +Point3_<_Tp> operator * (int a, const Point3_<_Tp>& b) +{ + return Point3_<_Tp>( saturate_cast<_Tp>(b.x * a), saturate_cast<_Tp>(b.y * a), saturate_cast<_Tp>(b.z * a) ); +} + +template static inline +Point3_<_Tp> operator * (const Point3_<_Tp>& a, float b) +{ + return Point3_<_Tp>( saturate_cast<_Tp>(a.x * b), saturate_cast<_Tp>(a.y * b), saturate_cast<_Tp>(a.z * b) ); +} + +template static inline +Point3_<_Tp> operator * (float a, const Point3_<_Tp>& b) +{ + return Point3_<_Tp>( saturate_cast<_Tp>(b.x * a), saturate_cast<_Tp>(b.y * a), saturate_cast<_Tp>(b.z * a) ); +} + +template static inline +Point3_<_Tp> operator * (const Point3_<_Tp>& a, double b) +{ + return Point3_<_Tp>( saturate_cast<_Tp>(a.x * b), saturate_cast<_Tp>(a.y * b), saturate_cast<_Tp>(a.z * b) ); +} + +template static inline +Point3_<_Tp> operator * (double a, const Point3_<_Tp>& b) +{ + return Point3_<_Tp>( saturate_cast<_Tp>(b.x * a), saturate_cast<_Tp>(b.y * a), saturate_cast<_Tp>(b.z * a) ); +} + +template static inline +Point3_<_Tp> operator * (const Matx<_Tp, 3, 3>& a, const Point3_<_Tp>& b) +{ + Matx<_Tp, 3, 1> tmp = a * Vec<_Tp,3>(b.x, b.y, b.z); + return Point3_<_Tp>(tmp.val[0], tmp.val[1], tmp.val[2]); +} + +template static inline +Matx<_Tp, 4, 1> operator * (const Matx<_Tp, 4, 4>& a, const Point3_<_Tp>& b) +{ + return a * Matx<_Tp, 4, 1>(b.x, b.y, b.z, 1); +} + +template static inline +Point3_<_Tp> operator / (const Point3_<_Tp>& a, int b) +{ + Point3_<_Tp> tmp(a); + tmp /= b; + return tmp; +} + +template static inline +Point3_<_Tp> operator / (const Point3_<_Tp>& a, float b) +{ + Point3_<_Tp> tmp(a); + tmp /= b; + return tmp; +} + +template static inline +Point3_<_Tp> operator / (const Point3_<_Tp>& a, double b) +{ + Point3_<_Tp> tmp(a); + tmp /= b; + return tmp; +} + + + +////////////////////////////////// Size ///////////////////////////////// + +template inline +Size_<_Tp>::Size_() + : width(0), height(0) {} + +template inline +Size_<_Tp>::Size_(_Tp _width, _Tp _height) + : width(_width), height(_height) {} + +template inline +Size_<_Tp>::Size_(const Point_<_Tp>& pt) + : width(pt.x), height(pt.y) {} + +template template inline +Size_<_Tp>::operator Size_<_Tp2>() const +{ + return Size_<_Tp2>(saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); +} + +template inline +_Tp Size_<_Tp>::area() const +{ + const _Tp result = width * height; + CV_DbgAssert(!std::numeric_limits<_Tp>::is_integer + || width == 0 || result / width == height); // make sure the result fits in the return value + return result; +} + +template inline +double Size_<_Tp>::aspectRatio() const +{ + return width / static_cast(height); +} + +template inline +bool Size_<_Tp>::empty() const +{ + return width <= 0 || height <= 0; +} + + +template static inline +Size_<_Tp>& operator *= (Size_<_Tp>& a, _Tp b) +{ + a.width *= b; + a.height *= b; + return a; +} + +template static inline +Size_<_Tp> operator * (const Size_<_Tp>& a, _Tp b) +{ + Size_<_Tp> tmp(a); + tmp *= b; + return tmp; +} + +template static inline +Size_<_Tp>& operator /= (Size_<_Tp>& a, _Tp b) +{ + a.width /= b; + a.height /= b; + return a; +} + +template static inline +Size_<_Tp> operator / (const Size_<_Tp>& a, _Tp b) +{ + Size_<_Tp> tmp(a); + tmp /= b; + return tmp; +} + +template static inline +Size_<_Tp>& operator += (Size_<_Tp>& a, const Size_<_Tp>& b) +{ + a.width += b.width; + a.height += b.height; + return a; +} + +template static inline +Size_<_Tp> operator + (const Size_<_Tp>& a, const Size_<_Tp>& b) +{ + Size_<_Tp> tmp(a); + tmp += b; + return tmp; +} + +template static inline +Size_<_Tp>& operator -= (Size_<_Tp>& a, const Size_<_Tp>& b) +{ + a.width -= b.width; + a.height -= b.height; + return a; +} + +template static inline +Size_<_Tp> operator - (const Size_<_Tp>& a, const Size_<_Tp>& b) +{ + Size_<_Tp> tmp(a); + tmp -= b; + return tmp; +} + +template static inline +bool operator == (const Size_<_Tp>& a, const Size_<_Tp>& b) +{ + return a.width == b.width && a.height == b.height; +} + +template static inline +bool operator != (const Size_<_Tp>& a, const Size_<_Tp>& b) +{ + return !(a == b); +} + + + +////////////////////////////////// Rect ///////////////////////////////// + +template inline +Rect_<_Tp>::Rect_() + : x(0), y(0), width(0), height(0) {} + +template inline +Rect_<_Tp>::Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height) + : x(_x), y(_y), width(_width), height(_height) {} + +template inline +Rect_<_Tp>::Rect_(const Point_<_Tp>& org, const Size_<_Tp>& sz) + : x(org.x), y(org.y), width(sz.width), height(sz.height) {} + +template inline +Rect_<_Tp>::Rect_(const Point_<_Tp>& pt1, const Point_<_Tp>& pt2) +{ + x = std::min(pt1.x, pt2.x); + y = std::min(pt1.y, pt2.y); + width = std::max(pt1.x, pt2.x) - x; + height = std::max(pt1.y, pt2.y) - y; +} + +template inline +Point_<_Tp> Rect_<_Tp>::tl() const +{ + return Point_<_Tp>(x,y); +} + +template inline +Point_<_Tp> Rect_<_Tp>::br() const +{ + return Point_<_Tp>(x + width, y + height); +} + +template inline +Size_<_Tp> Rect_<_Tp>::size() const +{ + return Size_<_Tp>(width, height); +} + +template inline +_Tp Rect_<_Tp>::area() const +{ + const _Tp result = width * height; + CV_DbgAssert(!std::numeric_limits<_Tp>::is_integer + || width == 0 || result / width == height); // make sure the result fits in the return value + return result; +} + +template inline +bool Rect_<_Tp>::empty() const +{ + return width <= 0 || height <= 0; +} + +template template inline +Rect_<_Tp>::operator Rect_<_Tp2>() const +{ + return Rect_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y), saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); +} + +template inline +bool Rect_<_Tp>::contains(const Point_<_Tp>& pt) const +{ + return x <= pt.x && pt.x < x + width && y <= pt.y && pt.y < y + height; +} + + +template static inline +Rect_<_Tp>& operator += ( Rect_<_Tp>& a, const Point_<_Tp>& b ) +{ + a.x += b.x; + a.y += b.y; + return a; +} + +template static inline +Rect_<_Tp>& operator -= ( Rect_<_Tp>& a, const Point_<_Tp>& b ) +{ + a.x -= b.x; + a.y -= b.y; + return a; +} + +template static inline +Rect_<_Tp>& operator += ( Rect_<_Tp>& a, const Size_<_Tp>& b ) +{ + a.width += b.width; + a.height += b.height; + return a; +} + +template static inline +Rect_<_Tp>& operator -= ( Rect_<_Tp>& a, const Size_<_Tp>& b ) +{ + const _Tp width = a.width - b.width; + const _Tp height = a.height - b.height; + CV_DbgAssert(width >= 0 && height >= 0); + a.width = width; + a.height = height; + return a; +} + +template static inline +Rect_<_Tp>& operator &= ( Rect_<_Tp>& a, const Rect_<_Tp>& b ) +{ + if (a.empty() || b.empty()) { + a = Rect(); + return a; + } + const Rect_<_Tp>& Rx_min = (a.x < b.x) ? a : b; + const Rect_<_Tp>& Rx_max = (a.x < b.x) ? b : a; + const Rect_<_Tp>& Ry_min = (a.y < b.y) ? a : b; + const Rect_<_Tp>& Ry_max = (a.y < b.y) ? b : a; + // Looking at the formula below, we will compute Rx_min.width - (Rx_max.x - Rx_min.x) + // but we want to avoid overflows. Rx_min.width >= 0 and (Rx_max.x - Rx_min.x) >= 0 + // by definition so the difference does not overflow. The only thing that can overflow + // is (Rx_max.x - Rx_min.x). And it can only overflow if Rx_min.x < 0. + // Let us first deal with the following case. + if ((Rx_min.x < 0 && Rx_min.x + Rx_min.width < Rx_max.x) || + (Ry_min.y < 0 && Ry_min.y + Ry_min.height < Ry_max.y)) { + a = Rect(); + return a; + } + // We now know that either Rx_min.x >= 0, or + // Rx_min.x < 0 && Rx_min.x + Rx_min.width >= Rx_max.x and therefore + // Rx_min.width >= (Rx_max.x - Rx_min.x) which means (Rx_max.x - Rx_min.x) + // is inferior to a valid int and therefore does not overflow. + a.width = std::min(Rx_min.width - (Rx_max.x - Rx_min.x), Rx_max.width); + a.height = std::min(Ry_min.height - (Ry_max.y - Ry_min.y), Ry_max.height); + a.x = Rx_max.x; + a.y = Ry_max.y; + if (a.empty()) + a = Rect(); + return a; +} + +template static inline +Rect_<_Tp>& operator |= ( Rect_<_Tp>& a, const Rect_<_Tp>& b ) +{ + if (a.empty()) { + a = b; + } + else if (!b.empty()) { + _Tp x1 = std::min(a.x, b.x); + _Tp y1 = std::min(a.y, b.y); + a.width = std::max(a.x + a.width, b.x + b.width) - x1; + a.height = std::max(a.y + a.height, b.y + b.height) - y1; + a.x = x1; + a.y = y1; + } + return a; +} + +template static inline +bool operator == (const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + return a.x == b.x && a.y == b.y && a.width == b.width && a.height == b.height; +} + +template static inline +bool operator != (const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + return a.x != b.x || a.y != b.y || a.width != b.width || a.height != b.height; +} + +template static inline +Rect_<_Tp> operator + (const Rect_<_Tp>& a, const Point_<_Tp>& b) +{ + return Rect_<_Tp>( a.x + b.x, a.y + b.y, a.width, a.height ); +} + +template static inline +Rect_<_Tp> operator - (const Rect_<_Tp>& a, const Point_<_Tp>& b) +{ + return Rect_<_Tp>( a.x - b.x, a.y - b.y, a.width, a.height ); +} + +template static inline +Rect_<_Tp> operator + (const Rect_<_Tp>& a, const Size_<_Tp>& b) +{ + return Rect_<_Tp>( a.x, a.y, a.width + b.width, a.height + b.height ); +} + +template static inline +Rect_<_Tp> operator - (const Rect_<_Tp>& a, const Size_<_Tp>& b) +{ + const _Tp width = a.width - b.width; + const _Tp height = a.height - b.height; + CV_DbgAssert(width >= 0 && height >= 0); + return Rect_<_Tp>( a.x, a.y, width, height ); +} + +template static inline +Rect_<_Tp> operator & (const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c &= b; +} + +template static inline +Rect_<_Tp> operator | (const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c |= b; +} + +/** + * @brief measure dissimilarity between two sample sets + * + * computes the complement of the Jaccard Index as described in . + * For rectangles this reduces to computing the intersection over the union. + */ +template static inline +double jaccardDistance(const Rect_<_Tp>& a, const Rect_<_Tp>& b) { + _Tp Aa = a.area(); + _Tp Ab = b.area(); + + if ((Aa + Ab) <= std::numeric_limits<_Tp>::epsilon()) { + // jaccard_index = 1 -> distance = 0 + return 0.0; + } + + double Aab = (a & b).area(); + // distance = 1 - jaccard_index + return 1.0 - Aab / (Aa + Ab - Aab); +} + +////////////////////////////// RotatedRect ////////////////////////////// + +inline +RotatedRect::RotatedRect() + : center(), size(), angle(0) {} + +inline +RotatedRect::RotatedRect(const Point2f& _center, const Size2f& _size, float _angle) + : center(_center), size(_size), angle(_angle) {} + +///////////////////////////////// Range ///////////////////////////////// + +inline +Range::Range() + : start(0), end(0) {} + +inline +Range::Range(int _start, int _end) + : start(_start), end(_end) {} + +inline +int Range::size() const +{ + return end - start; +} + +inline +bool Range::empty() const +{ + return start == end; +} + +inline +Range Range::all() +{ + return Range(INT_MIN, INT_MAX); +} + + +static inline +bool operator == (const Range& r1, const Range& r2) +{ + return r1.start == r2.start && r1.end == r2.end; +} + +static inline +bool operator != (const Range& r1, const Range& r2) +{ + return !(r1 == r2); +} + +static inline +bool operator !(const Range& r) +{ + return r.start == r.end; +} + +static inline +Range operator & (const Range& r1, const Range& r2) +{ + Range r(std::max(r1.start, r2.start), std::min(r1.end, r2.end)); + r.end = std::max(r.end, r.start); + return r; +} + +static inline +Range& operator &= (Range& r1, const Range& r2) +{ + r1 = r1 & r2; + return r1; +} + +static inline +Range operator + (const Range& r1, int delta) +{ + return Range(r1.start + delta, r1.end + delta); +} + +static inline +Range operator + (int delta, const Range& r1) +{ + return Range(r1.start + delta, r1.end + delta); +} + +static inline +Range operator - (const Range& r1, int delta) +{ + return r1 + (-delta); +} + + + +///////////////////////////////// Scalar //////////////////////////////// + +template inline +Scalar_<_Tp>::Scalar_() +{ + this->val[0] = this->val[1] = this->val[2] = this->val[3] = 0; +} + +template inline +Scalar_<_Tp>::Scalar_(_Tp v0, _Tp v1, _Tp v2, _Tp v3) +{ + this->val[0] = v0; + this->val[1] = v1; + this->val[2] = v2; + this->val[3] = v3; +} + +template inline +Scalar_<_Tp>::Scalar_(const Scalar_<_Tp>& s) : Vec<_Tp, 4>(s) { +} + +template inline +Scalar_<_Tp>::Scalar_(Scalar_<_Tp>&& s) CV_NOEXCEPT { + this->val[0] = std::move(s.val[0]); + this->val[1] = std::move(s.val[1]); + this->val[2] = std::move(s.val[2]); + this->val[3] = std::move(s.val[3]); +} + +template inline +Scalar_<_Tp>& Scalar_<_Tp>::operator=(const Scalar_<_Tp>& s) { + this->val[0] = s.val[0]; + this->val[1] = s.val[1]; + this->val[2] = s.val[2]; + this->val[3] = s.val[3]; + return *this; +} + +template inline +Scalar_<_Tp>& Scalar_<_Tp>::operator=(Scalar_<_Tp>&& s) CV_NOEXCEPT { + this->val[0] = std::move(s.val[0]); + this->val[1] = std::move(s.val[1]); + this->val[2] = std::move(s.val[2]); + this->val[3] = std::move(s.val[3]); + return *this; +} + +template template inline +Scalar_<_Tp>::Scalar_(const Vec<_Tp2, cn>& v) +{ + int i; + for( i = 0; i < (cn < 4 ? cn : 4); i++ ) + this->val[i] = cv::saturate_cast<_Tp>(v.val[i]); + for( ; i < 4; i++ ) + this->val[i] = 0; +} + +template inline +Scalar_<_Tp>::Scalar_(_Tp v0) +{ + this->val[0] = v0; + this->val[1] = this->val[2] = this->val[3] = 0; +} + +template inline +Scalar_<_Tp> Scalar_<_Tp>::all(_Tp v0) +{ + return Scalar_<_Tp>(v0, v0, v0, v0); +} + + +template inline +Scalar_<_Tp> Scalar_<_Tp>::mul(const Scalar_<_Tp>& a, double scale ) const +{ + return Scalar_<_Tp>(saturate_cast<_Tp>(this->val[0] * a.val[0] * scale), + saturate_cast<_Tp>(this->val[1] * a.val[1] * scale), + saturate_cast<_Tp>(this->val[2] * a.val[2] * scale), + saturate_cast<_Tp>(this->val[3] * a.val[3] * scale)); +} + +template inline +Scalar_<_Tp> Scalar_<_Tp>::conj() const +{ + return Scalar_<_Tp>(saturate_cast<_Tp>( this->val[0]), + saturate_cast<_Tp>(-this->val[1]), + saturate_cast<_Tp>(-this->val[2]), + saturate_cast<_Tp>(-this->val[3])); +} + +template inline +bool Scalar_<_Tp>::isReal() const +{ + return this->val[1] == 0 && this->val[2] == 0 && this->val[3] == 0; +} + + +template template inline +Scalar_<_Tp>::operator Scalar_() const +{ + return Scalar_(saturate_cast(this->val[0]), + saturate_cast(this->val[1]), + saturate_cast(this->val[2]), + saturate_cast(this->val[3])); +} + + +template static inline +Scalar_<_Tp>& operator += (Scalar_<_Tp>& a, const Scalar_<_Tp>& b) +{ + a.val[0] += b.val[0]; + a.val[1] += b.val[1]; + a.val[2] += b.val[2]; + a.val[3] += b.val[3]; + return a; +} + +template static inline +Scalar_<_Tp>& operator -= (Scalar_<_Tp>& a, const Scalar_<_Tp>& b) +{ + a.val[0] -= b.val[0]; + a.val[1] -= b.val[1]; + a.val[2] -= b.val[2]; + a.val[3] -= b.val[3]; + return a; +} + +template static inline +Scalar_<_Tp>& operator *= ( Scalar_<_Tp>& a, _Tp v ) +{ + a.val[0] *= v; + a.val[1] *= v; + a.val[2] *= v; + a.val[3] *= v; + return a; +} + +template static inline +bool operator == ( const Scalar_<_Tp>& a, const Scalar_<_Tp>& b ) +{ + return a.val[0] == b.val[0] && a.val[1] == b.val[1] && + a.val[2] == b.val[2] && a.val[3] == b.val[3]; +} + +template static inline +bool operator != ( const Scalar_<_Tp>& a, const Scalar_<_Tp>& b ) +{ + return a.val[0] != b.val[0] || a.val[1] != b.val[1] || + a.val[2] != b.val[2] || a.val[3] != b.val[3]; +} + +template static inline +Scalar_<_Tp> operator + (const Scalar_<_Tp>& a, const Scalar_<_Tp>& b) +{ + return Scalar_<_Tp>(a.val[0] + b.val[0], + a.val[1] + b.val[1], + a.val[2] + b.val[2], + a.val[3] + b.val[3]); +} + +template static inline +Scalar_<_Tp> operator - (const Scalar_<_Tp>& a, const Scalar_<_Tp>& b) +{ + return Scalar_<_Tp>(saturate_cast<_Tp>(a.val[0] - b.val[0]), + saturate_cast<_Tp>(a.val[1] - b.val[1]), + saturate_cast<_Tp>(a.val[2] - b.val[2]), + saturate_cast<_Tp>(a.val[3] - b.val[3])); +} + +template static inline +Scalar_<_Tp> operator * (const Scalar_<_Tp>& a, _Tp alpha) +{ + return Scalar_<_Tp>(a.val[0] * alpha, + a.val[1] * alpha, + a.val[2] * alpha, + a.val[3] * alpha); +} + +template static inline +Scalar_<_Tp> operator * (_Tp alpha, const Scalar_<_Tp>& a) +{ + return a*alpha; +} + +template static inline +Scalar_<_Tp> operator - (const Scalar_<_Tp>& a) +{ + return Scalar_<_Tp>(saturate_cast<_Tp>(-a.val[0]), + saturate_cast<_Tp>(-a.val[1]), + saturate_cast<_Tp>(-a.val[2]), + saturate_cast<_Tp>(-a.val[3])); +} + + +template static inline +Scalar_<_Tp> operator * (const Scalar_<_Tp>& a, const Scalar_<_Tp>& b) +{ + return Scalar_<_Tp>(saturate_cast<_Tp>(a[0]*b[0] - a[1]*b[1] - a[2]*b[2] - a[3]*b[3]), + saturate_cast<_Tp>(a[0]*b[1] + a[1]*b[0] + a[2]*b[3] - a[3]*b[2]), + saturate_cast<_Tp>(a[0]*b[2] - a[1]*b[3] + a[2]*b[0] + a[3]*b[1]), + saturate_cast<_Tp>(a[0]*b[3] + a[1]*b[2] - a[2]*b[1] + a[3]*b[0])); +} + +template static inline +Scalar_<_Tp>& operator *= (Scalar_<_Tp>& a, const Scalar_<_Tp>& b) +{ + a = a * b; + return a; +} + +template static inline +Scalar_<_Tp> operator / (const Scalar_<_Tp>& a, _Tp alpha) +{ + return Scalar_<_Tp>(a.val[0] / alpha, + a.val[1] / alpha, + a.val[2] / alpha, + a.val[3] / alpha); +} + +template static inline +Scalar_ operator / (const Scalar_& a, float alpha) +{ + float s = 1 / alpha; + return Scalar_(a.val[0] * s, a.val[1] * s, a.val[2] * s, a.val[3] * s); +} + +template static inline +Scalar_ operator / (const Scalar_& a, double alpha) +{ + double s = 1 / alpha; + return Scalar_(a.val[0] * s, a.val[1] * s, a.val[2] * s, a.val[3] * s); +} + +template static inline +Scalar_<_Tp>& operator /= (Scalar_<_Tp>& a, _Tp alpha) +{ + a = a / alpha; + return a; +} + +template static inline +Scalar_<_Tp> operator / (_Tp a, const Scalar_<_Tp>& b) +{ + _Tp s = a / (b[0]*b[0] + b[1]*b[1] + b[2]*b[2] + b[3]*b[3]); + return b.conj() * s; +} + +template static inline +Scalar_<_Tp> operator / (const Scalar_<_Tp>& a, const Scalar_<_Tp>& b) +{ + return a * ((_Tp)1 / b); +} + +template static inline +Scalar_<_Tp>& operator /= (Scalar_<_Tp>& a, const Scalar_<_Tp>& b) +{ + a = a / b; + return a; +} + +template static inline +Scalar operator * (const Matx<_Tp, 4, 4>& a, const Scalar& b) +{ + Matx c((Matx)a, b, Matx_MatMulOp()); + return reinterpret_cast(c); +} + +template<> inline +Scalar operator * (const Matx& a, const Scalar& b) +{ + Matx c(a, b, Matx_MatMulOp()); + return reinterpret_cast(c); +} + + + +//////////////////////////////// KeyPoint /////////////////////////////// + +inline +KeyPoint::KeyPoint() + : pt(0,0), size(0), angle(-1), response(0), octave(0), class_id(-1) {} + +inline +KeyPoint::KeyPoint(Point2f _pt, float _size, float _angle, float _response, int _octave, int _class_id) + : pt(_pt), size(_size), angle(_angle), response(_response), octave(_octave), class_id(_class_id) {} + +inline +KeyPoint::KeyPoint(float x, float y, float _size, float _angle, float _response, int _octave, int _class_id) + : pt(x, y), size(_size), angle(_angle), response(_response), octave(_octave), class_id(_class_id) {} + + + +///////////////////////////////// DMatch //////////////////////////////// + +inline +DMatch::DMatch() + : queryIdx(-1), trainIdx(-1), imgIdx(-1), distance(FLT_MAX) {} + +inline +DMatch::DMatch(int _queryIdx, int _trainIdx, float _distance) + : queryIdx(_queryIdx), trainIdx(_trainIdx), imgIdx(-1), distance(_distance) {} + +inline +DMatch::DMatch(int _queryIdx, int _trainIdx, int _imgIdx, float _distance) + : queryIdx(_queryIdx), trainIdx(_trainIdx), imgIdx(_imgIdx), distance(_distance) {} + +inline +bool DMatch::operator < (const DMatch &m) const +{ + return distance < m.distance; +} + + + +////////////////////////////// TermCriteria ///////////////////////////// + +inline +TermCriteria::TermCriteria() + : type(0), maxCount(0), epsilon(0) {} + +inline +TermCriteria::TermCriteria(int _type, int _maxCount, double _epsilon) + : type(_type), maxCount(_maxCount), epsilon(_epsilon) {} + +//! @endcond + +} // cv + +#endif //OPENCV_CORE_TYPES_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/types_c.h b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/types_c.h new file mode 100644 index 0000000..32f3c8c --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/types_c.h @@ -0,0 +1,2126 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_TYPES_H +#define OPENCV_CORE_TYPES_H + +#ifdef CV__ENABLE_C_API_CTORS // invalid C API ctors (must be removed) +#if defined(_WIN32) && !defined(CV__SKIP_MESSAGE_MALFORMED_C_API_CTORS) +#error "C API ctors don't work on Win32: https://github.com/opencv/opencv/issues/15990" +#endif +#endif + +//#define CV__VALIDATE_UNUNITIALIZED_VARS 1 // C++11 & GCC only + +#ifdef __cplusplus + +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#define CV_STRUCT_INITIALIZER {0,} +#else +#if defined(__GNUC__) && __GNUC__ == 4 // GCC 4.x warns on "= {}" initialization, fixed in GCC 5.0 +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif +#define CV_STRUCT_INITIALIZER {} +#endif + +#else +#define CV_STRUCT_INITIALIZER {0} +#endif + + +#ifdef HAVE_IPL +# ifndef __IPL_H__ +# if defined _WIN32 +# include +# else +# include +# endif +# endif +#elif defined __IPL_H__ +# define HAVE_IPL +#endif + +#include "opencv2/core/cvdef.h" + +#ifndef SKIP_INCLUDES +#include +#include +#include +#include +#endif // SKIP_INCLUDES + +#if defined _WIN32 +# define CV_CDECL __cdecl +# define CV_STDCALL __stdcall +#else +# define CV_CDECL +# define CV_STDCALL +#endif + +#ifndef CV_DEFAULT +# ifdef __cplusplus +# define CV_DEFAULT(val) = val +# else +# define CV_DEFAULT(val) +# endif +#endif + +#ifndef CV_EXTERN_C_FUNCPTR +# ifdef __cplusplus +# define CV_EXTERN_C_FUNCPTR(x) extern "C" { typedef x; } +# else +# define CV_EXTERN_C_FUNCPTR(x) typedef x +# endif +#endif + +#ifndef CVAPI +# define CVAPI(rettype) CV_EXTERN_C CV_EXPORTS rettype CV_CDECL +#endif + +#ifndef CV_IMPL +# define CV_IMPL CV_EXTERN_C +#endif + +#ifdef __cplusplus +# include "opencv2/core.hpp" +#endif + +/** @addtogroup core_c + @{ +*/ + +/** @brief This is the "metatype" used *only* as a function parameter. + +It denotes that the function accepts arrays of multiple types, such as IplImage*, CvMat* or even +CvSeq* sometimes. The particular array type is determined at runtime by analyzing the first 4 +bytes of the header. In C++ interface the role of CvArr is played by InputArray and OutputArray. + */ +typedef void CvArr; + +typedef int CVStatus; + +/** @see cv::Error::Code */ +enum { + CV_StsOk= 0, /**< everything is ok */ + CV_StsBackTrace= -1, /**< pseudo error for back trace */ + CV_StsError= -2, /**< unknown /unspecified error */ + CV_StsInternal= -3, /**< internal error (bad state) */ + CV_StsNoMem= -4, /**< insufficient memory */ + CV_StsBadArg= -5, /**< function arg/param is bad */ + CV_StsBadFunc= -6, /**< unsupported function */ + CV_StsNoConv= -7, /**< iter. didn't converge */ + CV_StsAutoTrace= -8, /**< tracing */ + CV_HeaderIsNull= -9, /**< image header is NULL */ + CV_BadImageSize= -10, /**< image size is invalid */ + CV_BadOffset= -11, /**< offset is invalid */ + CV_BadDataPtr= -12, /**/ + CV_BadStep= -13, /**< image step is wrong, this may happen for a non-continuous matrix */ + CV_BadModelOrChSeq= -14, /**/ + CV_BadNumChannels= -15, /**< bad number of channels, for example, some functions accept only single channel matrices */ + CV_BadNumChannel1U= -16, /**/ + CV_BadDepth= -17, /**< input image depth is not supported by the function */ + CV_BadAlphaChannel= -18, /**/ + CV_BadOrder= -19, /**< number of dimensions is out of range */ + CV_BadOrigin= -20, /**< incorrect input origin */ + CV_BadAlign= -21, /**< incorrect input align */ + CV_BadCallBack= -22, /**/ + CV_BadTileSize= -23, /**/ + CV_BadCOI= -24, /**< input COI is not supported */ + CV_BadROISize= -25, /**< incorrect input roi */ + CV_MaskIsTiled= -26, /**/ + CV_StsNullPtr= -27, /**< null pointer */ + CV_StsVecLengthErr= -28, /**< incorrect vector length */ + CV_StsFilterStructContentErr= -29, /**< incorrect filter structure content */ + CV_StsKernelStructContentErr= -30, /**< incorrect transform kernel content */ + CV_StsFilterOffsetErr= -31, /**< incorrect filter offset value */ + CV_StsBadSize= -201, /**< the input/output structure size is incorrect */ + CV_StsDivByZero= -202, /**< division by zero */ + CV_StsInplaceNotSupported= -203, /**< in-place operation is not supported */ + CV_StsObjectNotFound= -204, /**< request can't be completed */ + CV_StsUnmatchedFormats= -205, /**< formats of input/output arrays differ */ + CV_StsBadFlag= -206, /**< flag is wrong or not supported */ + CV_StsBadPoint= -207, /**< bad CvPoint */ + CV_StsBadMask= -208, /**< bad format of mask (neither 8uC1 nor 8sC1)*/ + CV_StsUnmatchedSizes= -209, /**< sizes of input/output structures do not match */ + CV_StsUnsupportedFormat= -210, /**< the data format/type is not supported by the function*/ + CV_StsOutOfRange= -211, /**< some of parameters are out of range */ + CV_StsParseError= -212, /**< invalid syntax/structure of the parsed file */ + CV_StsNotImplemented= -213, /**< the requested function/feature is not implemented */ + CV_StsBadMemBlock= -214, /**< an allocated block has been corrupted */ + CV_StsAssert= -215, /**< assertion failed */ + CV_GpuNotSupported= -216, /**< no CUDA support */ + CV_GpuApiCallError= -217, /**< GPU API call error */ + CV_OpenGlNotSupported= -218, /**< no OpenGL support */ + CV_OpenGlApiCallError= -219, /**< OpenGL API call error */ + CV_OpenCLApiCallError= -220, /**< OpenCL API call error */ + CV_OpenCLDoubleNotSupported= -221, + CV_OpenCLInitError= -222, /**< OpenCL initialization error */ + CV_OpenCLNoAMDBlasFft= -223 +}; + +/****************************************************************************************\ +* Common macros and inline functions * +\****************************************************************************************/ + +#define CV_SWAP(a,b,t) ((t) = (a), (a) = (b), (b) = (t)) + +/** min & max without jumps */ +#define CV_IMIN(a, b) ((a) ^ (((a)^(b)) & (((a) < (b)) - 1))) + +#define CV_IMAX(a, b) ((a) ^ (((a)^(b)) & (((a) > (b)) - 1))) + +/** absolute value without jumps */ +#ifndef __cplusplus +# define CV_IABS(a) (((a) ^ ((a) < 0 ? -1 : 0)) - ((a) < 0 ? -1 : 0)) +#else +# define CV_IABS(a) abs(a) +#endif +#define CV_CMP(a,b) (((a) > (b)) - ((a) < (b))) +#define CV_SIGN(a) CV_CMP((a),0) + +#define cvInvSqrt(value) ((float)(1./sqrt(value))) +#define cvSqrt(value) ((float)sqrt(value)) + + +/*************** Random number generation *******************/ + +typedef uint64 CvRNG; + +#define CV_RNG_COEFF 4164903690U + +/** @brief Initializes a random number generator state. + +The function initializes a random number generator and returns the state. The pointer to the state +can be then passed to the cvRandInt, cvRandReal and cvRandArr functions. In the current +implementation a multiply-with-carry generator is used. +@param seed 64-bit value used to initiate a random sequence +@sa the C++ class RNG replaced CvRNG. + */ +CV_INLINE CvRNG cvRNG( int64 seed CV_DEFAULT(-1)) +{ + CvRNG rng = seed ? (uint64)seed : (uint64)(int64)-1; + return rng; +} + +/** @brief Returns a 32-bit unsigned integer and updates RNG. + +The function returns a uniformly-distributed random 32-bit unsigned integer and updates the RNG +state. It is similar to the rand() function from the C runtime library, except that OpenCV functions +always generates a 32-bit random number, regardless of the platform. +@param rng CvRNG state initialized by cvRNG. + */ +CV_INLINE unsigned cvRandInt( CvRNG* rng ) +{ + uint64 temp = *rng; + temp = (uint64)(unsigned)temp*CV_RNG_COEFF + (temp >> 32); + *rng = temp; + return (unsigned)temp; +} + +/** @brief Returns a floating-point random number and updates RNG. + +The function returns a uniformly-distributed random floating-point number between 0 and 1 (1 is not +included). +@param rng RNG state initialized by cvRNG + */ +CV_INLINE double cvRandReal( CvRNG* rng ) +{ + return cvRandInt(rng)*2.3283064365386962890625e-10 /* 2^-32 */; +} + +/****************************************************************************************\ +* Image type (IplImage) * +\****************************************************************************************/ + +#ifndef HAVE_IPL + +/* + * The following definitions (until #endif) + * is an extract from IPL headers. + * Copyright (c) 1995 Intel Corporation. + */ +#define IPL_DEPTH_SIGN 0x80000000 + +#define IPL_DEPTH_1U 1 +#define IPL_DEPTH_8U 8 +#define IPL_DEPTH_16U 16 +#define IPL_DEPTH_32F 32 + +#define IPL_DEPTH_8S (IPL_DEPTH_SIGN| 8) +#define IPL_DEPTH_16S (IPL_DEPTH_SIGN|16) +#define IPL_DEPTH_32S (IPL_DEPTH_SIGN|32) + +#define IPL_DATA_ORDER_PIXEL 0 +#define IPL_DATA_ORDER_PLANE 1 + +#define IPL_ORIGIN_TL 0 +#define IPL_ORIGIN_BL 1 + +#define IPL_ALIGN_4BYTES 4 +#define IPL_ALIGN_8BYTES 8 +#define IPL_ALIGN_16BYTES 16 +#define IPL_ALIGN_32BYTES 32 + +#define IPL_ALIGN_DWORD IPL_ALIGN_4BYTES +#define IPL_ALIGN_QWORD IPL_ALIGN_8BYTES + +#define IPL_BORDER_CONSTANT 0 +#define IPL_BORDER_REPLICATE 1 +#define IPL_BORDER_REFLECT 2 +#define IPL_BORDER_WRAP 3 + +#ifdef __cplusplus +typedef struct _IplImage IplImage; +CV_EXPORTS _IplImage cvIplImage(const cv::Mat& m); +#endif + +/** The IplImage is taken from the Intel Image Processing Library, in which the format is native. OpenCV +only supports a subset of possible IplImage formats, as outlined in the parameter list above. + +In addition to the above restrictions, OpenCV handles ROIs differently. OpenCV functions require +that the image size or ROI size of all source and destination images match exactly. On the other +hand, the Intel Image Processing Library processes the area of intersection between the source and +destination images (or ROIs), allowing them to vary independently. +*/ +typedef struct +_IplImage +{ + int nSize; /**< sizeof(IplImage) */ + int ID; /**< version (=0)*/ + int nChannels; /**< Most of OpenCV functions support 1,2,3 or 4 channels */ + int alphaChannel; /**< Ignored by OpenCV */ + int depth; /**< Pixel depth in bits: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16S, + IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F are supported. */ + char colorModel[4]; /**< Ignored by OpenCV */ + char channelSeq[4]; /**< ditto */ + int dataOrder; /**< 0 - interleaved color channels, 1 - separate color channels. + cvCreateImage can only create interleaved images */ + int origin; /**< 0 - top-left origin, + 1 - bottom-left origin (Windows bitmaps style). */ + int align; /**< Alignment of image rows (4 or 8). + OpenCV ignores it and uses widthStep instead. */ + int width; /**< Image width in pixels. */ + int height; /**< Image height in pixels. */ + struct _IplROI *roi; /**< Image ROI. If NULL, the whole image is selected. */ + struct _IplImage *maskROI; /**< Must be NULL. */ + void *imageId; /**< " " */ + struct _IplTileInfo *tileInfo; /**< " " */ + int imageSize; /**< Image data size in bytes + (==image->height*image->widthStep + in case of interleaved data)*/ + char *imageData; /**< Pointer to aligned image data. */ + int widthStep; /**< Size of aligned image row in bytes. */ + int BorderMode[4]; /**< Ignored by OpenCV. */ + int BorderConst[4]; /**< Ditto. */ + char *imageDataOrigin; /**< Pointer to very origin of image data + (not necessarily aligned) - + needed for correct deallocation */ + +#if defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) + _IplImage() + { + memset(this, 0, sizeof(*this)); // valid for POD structure + nSize = sizeof(IplImage); + } + _IplImage(const cv::Mat& m) { *this = cvIplImage(m); } +#endif +} +IplImage; + +CV_INLINE IplImage cvIplImage() +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + IplImage self = CV_STRUCT_INITIALIZER; self.nSize = sizeof(IplImage); return self; +#else + return _IplImage(); +#endif +} + +typedef struct _IplTileInfo IplTileInfo; + +typedef struct _IplROI +{ + int coi; /**< 0 - no COI (all channels are selected), 1 - 0th channel is selected ...*/ + int xOffset; + int yOffset; + int width; + int height; +} +IplROI; + +typedef struct _IplConvKernel +{ + int nCols; + int nRows; + int anchorX; + int anchorY; + int *values; + int nShiftR; +} +IplConvKernel; + +typedef struct _IplConvKernelFP +{ + int nCols; + int nRows; + int anchorX; + int anchorY; + float *values; +} +IplConvKernelFP; + +#define IPL_IMAGE_HEADER 1 +#define IPL_IMAGE_DATA 2 +#define IPL_IMAGE_ROI 4 + +#endif/*HAVE_IPL*/ + +/** extra border mode */ +#define IPL_BORDER_REFLECT_101 4 +#define IPL_BORDER_TRANSPARENT 5 + +#define IPL_IMAGE_MAGIC_VAL ((int)sizeof(IplImage)) +#define CV_TYPE_NAME_IMAGE "opencv-image" + +#define CV_IS_IMAGE_HDR(img) \ + ((img) != NULL && ((const IplImage*)(img))->nSize == sizeof(IplImage)) + +#define CV_IS_IMAGE(img) \ + (CV_IS_IMAGE_HDR(img) && ((IplImage*)img)->imageData != NULL) + +/** for storing double-precision + floating point data in IplImage's */ +#define IPL_DEPTH_64F 64 + +/** get reference to pixel at (col,row), + for multi-channel images (col) should be multiplied by number of channels */ +#define CV_IMAGE_ELEM( image, elemtype, row, col ) \ + (((elemtype*)((image)->imageData + (image)->widthStep*(row)))[(col)]) + +/****************************************************************************************\ +* Matrix type (CvMat) * +\****************************************************************************************/ + +#define CV_AUTO_STEP 0x7fffffff +#define CV_WHOLE_ARR cvSlice( 0, 0x3fffffff ) + +#define CV_MAGIC_MASK 0xFFFF0000 +#define CV_MAT_MAGIC_VAL 0x42420000 +#define CV_TYPE_NAME_MAT "opencv-matrix" + +#ifdef __cplusplus +typedef struct CvMat CvMat; +CV_INLINE CvMat cvMat(const cv::Mat& m); +#endif + +/** Matrix elements are stored row by row. Element (i, j) (i - 0-based row index, j - 0-based column +index) of a matrix can be retrieved or modified using CV_MAT_ELEM macro: + + uchar pixval = CV_MAT_ELEM(grayimg, uchar, i, j) + CV_MAT_ELEM(cameraMatrix, float, 0, 2) = image.width*0.5f; + +To access multiple-channel matrices, you can use +CV_MAT_ELEM(matrix, type, i, j\*nchannels + channel_idx). + +@deprecated CvMat is now obsolete; consider using Mat instead. + */ +typedef struct CvMat +{ + int type; + int step; + + /* for internal use only */ + int* refcount; + int hdr_refcount; + + union + { + uchar* ptr; + short* s; + int* i; + float* fl; + double* db; + } data; + +#ifdef __cplusplus + union + { + int rows; + int height; + }; + + union + { + int cols; + int width; + }; +#else + int rows; + int cols; +#endif + +#if defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) + CvMat() {} + CvMat(const cv::Mat& m) { *this = cvMat(m); } +#endif +} +CvMat; + + +#define CV_IS_MAT_HDR(mat) \ + ((mat) != NULL && \ + (((const CvMat*)(mat))->type & CV_MAGIC_MASK) == CV_MAT_MAGIC_VAL && \ + ((const CvMat*)(mat))->cols > 0 && ((const CvMat*)(mat))->rows > 0) + +#define CV_IS_MAT_HDR_Z(mat) \ + ((mat) != NULL && \ + (((const CvMat*)(mat))->type & CV_MAGIC_MASK) == CV_MAT_MAGIC_VAL && \ + ((const CvMat*)(mat))->cols >= 0 && ((const CvMat*)(mat))->rows >= 0) + +#define CV_IS_MAT(mat) \ + (CV_IS_MAT_HDR(mat) && ((const CvMat*)(mat))->data.ptr != NULL) + +#define CV_IS_MASK_ARR(mat) \ + (((mat)->type & (CV_MAT_TYPE_MASK & ~CV_8SC1)) == 0) + +#define CV_ARE_TYPES_EQ(mat1, mat2) \ + ((((mat1)->type ^ (mat2)->type) & CV_MAT_TYPE_MASK) == 0) + +#define CV_ARE_CNS_EQ(mat1, mat2) \ + ((((mat1)->type ^ (mat2)->type) & CV_MAT_CN_MASK) == 0) + +#define CV_ARE_DEPTHS_EQ(mat1, mat2) \ + ((((mat1)->type ^ (mat2)->type) & CV_MAT_DEPTH_MASK) == 0) + +#define CV_ARE_SIZES_EQ(mat1, mat2) \ + ((mat1)->rows == (mat2)->rows && (mat1)->cols == (mat2)->cols) + +#define CV_IS_MAT_CONST(mat) \ + (((mat)->rows|(mat)->cols) == 1) + +#define IPL2CV_DEPTH(depth) \ + ((((CV_8U)+(CV_16U<<4)+(CV_32F<<8)+(CV_64F<<16)+(CV_8S<<20)+ \ + (CV_16S<<24)+(CV_32S<<28)) >> ((((depth) & 0xF0) >> 2) + \ + (((depth) & IPL_DEPTH_SIGN) ? 20 : 0))) & 15) + +/** Inline constructor. No data is allocated internally!!! + * (Use together with cvCreateData, or use cvCreateMat instead to + * get a matrix with allocated data): + */ +CV_INLINE CvMat cvMat( int rows, int cols, int type, void* data CV_DEFAULT(NULL)) +{ + CvMat m; + + assert( (unsigned)CV_MAT_DEPTH(type) <= CV_64F ); + type = CV_MAT_TYPE(type); + m.type = CV_MAT_MAGIC_VAL | CV_MAT_CONT_FLAG | type; + m.cols = cols; + m.rows = rows; + m.step = m.cols*CV_ELEM_SIZE(type); + m.data.ptr = (uchar*)data; + m.refcount = NULL; + m.hdr_refcount = 0; + + return m; +} + +#ifdef __cplusplus + +CV_INLINE CvMat cvMat(const cv::Mat& m) +{ + CvMat self; + CV_DbgAssert(m.dims <= 2); + self = cvMat(m.rows, m.dims == 1 ? 1 : m.cols, m.type(), m.data); + self.step = (int)m.step[0]; + self.type = (self.type & ~cv::Mat::CONTINUOUS_FLAG) | (m.flags & cv::Mat::CONTINUOUS_FLAG); + return self; +} +CV_INLINE CvMat cvMat() +{ +#if !defined(CV__ENABLE_C_API_CTORS) + CvMat self = CV_STRUCT_INITIALIZER; return self; +#else + return CvMat(); +#endif +} +CV_INLINE CvMat cvMat(const CvMat& m) +{ +#if !defined(CV__ENABLE_C_API_CTORS) + CvMat self = CV_STRUCT_INITIALIZER; memcpy(&self, &m, sizeof(self)); return self; +#else + return CvMat(m); +#endif +} + +#endif // __cplusplus + + +#define CV_MAT_ELEM_PTR_FAST( mat, row, col, pix_size ) \ + (assert( (unsigned)(row) < (unsigned)(mat).rows && \ + (unsigned)(col) < (unsigned)(mat).cols ), \ + (mat).data.ptr + (size_t)(mat).step*(row) + (pix_size)*(col)) + +#define CV_MAT_ELEM_PTR( mat, row, col ) \ + CV_MAT_ELEM_PTR_FAST( mat, row, col, CV_ELEM_SIZE((mat).type) ) + +#define CV_MAT_ELEM( mat, elemtype, row, col ) \ + (*(elemtype*)CV_MAT_ELEM_PTR_FAST( mat, row, col, sizeof(elemtype))) + +/** @brief Returns the particular element of single-channel floating-point matrix. + +The function is a fast replacement for cvGetReal2D in the case of single-channel floating-point +matrices. It is faster because it is inline, it does fewer checks for array type and array element +type, and it checks for the row and column ranges only in debug mode. +@param mat Input matrix +@param row The zero-based index of row +@param col The zero-based index of column + */ +CV_INLINE double cvmGet( const CvMat* mat, int row, int col ) +{ + int type; + + type = CV_MAT_TYPE(mat->type); + assert( (unsigned)row < (unsigned)mat->rows && + (unsigned)col < (unsigned)mat->cols ); + + if( type == CV_32FC1 ) + return ((float*)(void*)(mat->data.ptr + (size_t)mat->step*row))[col]; + else + { + assert( type == CV_64FC1 ); + return ((double*)(void*)(mat->data.ptr + (size_t)mat->step*row))[col]; + } +} + +/** @brief Sets a specific element of a single-channel floating-point matrix. + +The function is a fast replacement for cvSetReal2D in the case of single-channel floating-point +matrices. It is faster because it is inline, it does fewer checks for array type and array element +type, and it checks for the row and column ranges only in debug mode. +@param mat The matrix +@param row The zero-based index of row +@param col The zero-based index of column +@param value The new value of the matrix element + */ +CV_INLINE void cvmSet( CvMat* mat, int row, int col, double value ) +{ + int type; + type = CV_MAT_TYPE(mat->type); + assert( (unsigned)row < (unsigned)mat->rows && + (unsigned)col < (unsigned)mat->cols ); + + if( type == CV_32FC1 ) + ((float*)(void*)(mat->data.ptr + (size_t)mat->step*row))[col] = (float)value; + else + { + assert( type == CV_64FC1 ); + ((double*)(void*)(mat->data.ptr + (size_t)mat->step*row))[col] = value; + } +} + + +CV_INLINE int cvIplDepth( int type ) +{ + int depth = CV_MAT_DEPTH(type); + return CV_ELEM_SIZE1(depth)*8 | (depth == CV_8S || depth == CV_16S || + depth == CV_32S ? IPL_DEPTH_SIGN : 0); +} + + +/****************************************************************************************\ +* Multi-dimensional dense array (CvMatND) * +\****************************************************************************************/ + +#define CV_MATND_MAGIC_VAL 0x42430000 +#define CV_TYPE_NAME_MATND "opencv-nd-matrix" + +#define CV_MAX_DIM 32 + +#ifdef __cplusplus +typedef struct CvMatND CvMatND; +CV_EXPORTS CvMatND cvMatND(const cv::Mat& m); +#endif + +/** + @deprecated consider using cv::Mat instead + */ +typedef struct +CvMatND +{ + int type; + int dims; + + int* refcount; + int hdr_refcount; + + union + { + uchar* ptr; + float* fl; + double* db; + int* i; + short* s; + } data; + + struct + { + int size; + int step; + } + dim[CV_MAX_DIM]; + +#if defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) + CvMatND() {} + CvMatND(const cv::Mat& m) { *this = cvMatND(m); } +#endif +} +CvMatND; + + +CV_INLINE CvMatND cvMatND() +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvMatND self = CV_STRUCT_INITIALIZER; return self; +#else + return CvMatND(); +#endif +} + +#define CV_IS_MATND_HDR(mat) \ + ((mat) != NULL && (((const CvMatND*)(mat))->type & CV_MAGIC_MASK) == CV_MATND_MAGIC_VAL) + +#define CV_IS_MATND(mat) \ + (CV_IS_MATND_HDR(mat) && ((const CvMatND*)(mat))->data.ptr != NULL) + + +/****************************************************************************************\ +* Multi-dimensional sparse array (CvSparseMat) * +\****************************************************************************************/ + +#define CV_SPARSE_MAT_MAGIC_VAL 0x42440000 +#define CV_TYPE_NAME_SPARSE_MAT "opencv-sparse-matrix" + +struct CvSet; + +typedef struct CvSparseMat +{ + int type; + int dims; + int* refcount; + int hdr_refcount; + + struct CvSet* heap; + void** hashtable; + int hashsize; + int valoffset; + int idxoffset; + int size[CV_MAX_DIM]; + +#ifdef __cplusplus + CV_EXPORTS void copyToSparseMat(cv::SparseMat& m) const; +#endif +} +CvSparseMat; + +#ifdef __cplusplus +CV_EXPORTS CvSparseMat* cvCreateSparseMat(const cv::SparseMat& m); +#endif + +#define CV_IS_SPARSE_MAT_HDR(mat) \ + ((mat) != NULL && \ + (((const CvSparseMat*)(mat))->type & CV_MAGIC_MASK) == CV_SPARSE_MAT_MAGIC_VAL) + +#define CV_IS_SPARSE_MAT(mat) \ + CV_IS_SPARSE_MAT_HDR(mat) + +/**************** iteration through a sparse array *****************/ + +typedef struct CvSparseNode +{ + unsigned hashval; + struct CvSparseNode* next; +} +CvSparseNode; + +typedef struct CvSparseMatIterator +{ + CvSparseMat* mat; + CvSparseNode* node; + int curidx; +} +CvSparseMatIterator; + +#define CV_NODE_VAL(mat,node) ((void*)((uchar*)(node) + (mat)->valoffset)) +#define CV_NODE_IDX(mat,node) ((int*)((uchar*)(node) + (mat)->idxoffset)) + +/****************************************************************************************\ +* Histogram * +\****************************************************************************************/ + +typedef int CvHistType; + +#define CV_HIST_MAGIC_VAL 0x42450000 +#define CV_HIST_UNIFORM_FLAG (1 << 10) + +/** indicates whether bin ranges are set already or not */ +#define CV_HIST_RANGES_FLAG (1 << 11) + +#define CV_HIST_ARRAY 0 +#define CV_HIST_SPARSE 1 +#define CV_HIST_TREE CV_HIST_SPARSE + +/** should be used as a parameter only, + it turns to CV_HIST_UNIFORM_FLAG of hist->type */ +#define CV_HIST_UNIFORM 1 + +typedef struct CvHistogram +{ + int type; + CvArr* bins; + float thresh[CV_MAX_DIM][2]; /**< For uniform histograms. */ + float** thresh2; /**< For non-uniform histograms. */ + CvMatND mat; /**< Embedded matrix header for array histograms. */ +} +CvHistogram; + +#define CV_IS_HIST( hist ) \ + ((hist) != NULL && \ + (((CvHistogram*)(hist))->type & CV_MAGIC_MASK) == CV_HIST_MAGIC_VAL && \ + (hist)->bins != NULL) + +#define CV_IS_UNIFORM_HIST( hist ) \ + (((hist)->type & CV_HIST_UNIFORM_FLAG) != 0) + +#define CV_IS_SPARSE_HIST( hist ) \ + CV_IS_SPARSE_MAT((hist)->bins) + +#define CV_HIST_HAS_RANGES( hist ) \ + (((hist)->type & CV_HIST_RANGES_FLAG) != 0) + +/****************************************************************************************\ +* Other supplementary data type definitions * +\****************************************************************************************/ + +/*************************************** CvRect *****************************************/ +/** @sa Rect_ */ +typedef struct CvRect +{ + int x; + int y; + int width; + int height; + +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS + CvRect() __attribute__(( warning("Non-initialized variable") )) {}; + template CvRect(const std::initializer_list<_Tp> list) + { + CV_Assert(list.size() == 0 || list.size() == 4); + x = y = width = height = 0; + if (list.size() == 4) + { + x = list.begin()[0]; y = list.begin()[1]; width = list.begin()[2]; height = list.begin()[3]; + } + }; +#elif defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) + CvRect(int _x = 0, int _y = 0, int w = 0, int h = 0): x(_x), y(_y), width(w), height(h) {} + template + CvRect(const cv::Rect_<_Tp>& r): x(cv::saturate_cast(r.x)), y(cv::saturate_cast(r.y)), width(cv::saturate_cast(r.width)), height(cv::saturate_cast(r.height)) {} +#endif +#ifdef __cplusplus + template + operator cv::Rect_<_Tp>() const { return cv::Rect_<_Tp>((_Tp)x, (_Tp)y, (_Tp)width, (_Tp)height); } +#endif +} +CvRect; + +/** constructs CvRect structure. */ +CV_INLINE CvRect cvRect( int x, int y, int width, int height ) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvRect r = {x, y, width, height}; +#else + CvRect r(x, y , width, height); +#endif + return r; +} +#ifdef __cplusplus +CV_INLINE CvRect cvRect(const cv::Rect& rc) { return cvRect(rc.x, rc.y, rc.width, rc.height); } +#endif + +CV_INLINE IplROI cvRectToROI( CvRect rect, int coi ) +{ + IplROI roi; + roi.xOffset = rect.x; + roi.yOffset = rect.y; + roi.width = rect.width; + roi.height = rect.height; + roi.coi = coi; + + return roi; +} + + +CV_INLINE CvRect cvROIToRect( IplROI roi ) +{ + return cvRect( roi.xOffset, roi.yOffset, roi.width, roi.height ); +} + +/*********************************** CvTermCriteria *************************************/ + +#define CV_TERMCRIT_ITER 1 +#define CV_TERMCRIT_NUMBER CV_TERMCRIT_ITER +#define CV_TERMCRIT_EPS 2 + +/** @sa TermCriteria + */ +typedef struct CvTermCriteria +{ + int type; /**< may be combination of + CV_TERMCRIT_ITER + CV_TERMCRIT_EPS */ + int max_iter; + double epsilon; +#if defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) + CvTermCriteria(int _type = 0, int _iter = 0, double _eps = 0) : type(_type), max_iter(_iter), epsilon(_eps) {} + CvTermCriteria(const cv::TermCriteria& t) : type(t.type), max_iter(t.maxCount), epsilon(t.epsilon) {} +#endif +#ifdef __cplusplus + operator cv::TermCriteria() const { return cv::TermCriteria(type, max_iter, epsilon); } +#endif +} +CvTermCriteria; + +CV_INLINE CvTermCriteria cvTermCriteria( int type, int max_iter, double epsilon ) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvTermCriteria t = { type, max_iter, (float)epsilon}; +#else + CvTermCriteria t(type, max_iter, epsilon); +#endif + return t; +} +#ifdef __cplusplus +CV_INLINE CvTermCriteria cvTermCriteria(const cv::TermCriteria& t) { return cvTermCriteria(t.type, t.maxCount, t.epsilon); } +#endif + + +/******************************* CvPoint and variants ***********************************/ + +typedef struct CvPoint +{ + int x; + int y; + +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS + CvPoint() __attribute__(( warning("Non-initialized variable") )) {} + template CvPoint(const std::initializer_list<_Tp> list) + { + CV_Assert(list.size() == 0 || list.size() == 2); + x = y = 0; + if (list.size() == 2) + { + x = list.begin()[0]; y = list.begin()[1]; + } + }; +#elif defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) + CvPoint(int _x = 0, int _y = 0): x(_x), y(_y) {} + template + CvPoint(const cv::Point_<_Tp>& pt): x((int)pt.x), y((int)pt.y) {} +#endif +#ifdef __cplusplus + template + operator cv::Point_<_Tp>() const { return cv::Point_<_Tp>(cv::saturate_cast<_Tp>(x), cv::saturate_cast<_Tp>(y)); } +#endif +} +CvPoint; + +/** constructs CvPoint structure. */ +CV_INLINE CvPoint cvPoint( int x, int y ) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvPoint p = {x, y}; +#else + CvPoint p(x, y); +#endif + return p; +} +#ifdef __cplusplus +CV_INLINE CvPoint cvPoint(const cv::Point& pt) { return cvPoint(pt.x, pt.y); } +#endif + +typedef struct CvPoint2D32f +{ + float x; + float y; + +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS + CvPoint2D32f() __attribute__(( warning("Non-initialized variable") )) {} + template CvPoint2D32f(const std::initializer_list<_Tp> list) + { + CV_Assert(list.size() == 0 || list.size() == 2); + x = y = 0; + if (list.size() == 2) + { + x = list.begin()[0]; y = list.begin()[1]; + } + }; +#elif defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) + CvPoint2D32f(float _x = 0, float _y = 0): x(_x), y(_y) {} + template + CvPoint2D32f(const cv::Point_<_Tp>& pt): x((float)pt.x), y((float)pt.y) {} +#endif +#ifdef __cplusplus + template + operator cv::Point_<_Tp>() const { return cv::Point_<_Tp>(cv::saturate_cast<_Tp>(x), cv::saturate_cast<_Tp>(y)); } +#endif +} +CvPoint2D32f; + +/** constructs CvPoint2D32f structure. */ +CV_INLINE CvPoint2D32f cvPoint2D32f( double x, double y ) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvPoint2D32f p = { (float)x, (float)y }; +#else + CvPoint2D32f p((float)x, (float)y); +#endif + return p; +} + +#ifdef __cplusplus +template +CvPoint2D32f cvPoint2D32f(const cv::Point_<_Tp>& pt) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvPoint2D32f p = { (float)pt.x, (float)pt.y }; +#else + CvPoint2D32f p((float)pt.x, (float)pt.y); +#endif + return p; +} +#endif + +/** converts CvPoint to CvPoint2D32f. */ +CV_INLINE CvPoint2D32f cvPointTo32f( CvPoint point ) +{ + return cvPoint2D32f( (float)point.x, (float)point.y ); +} + +/** converts CvPoint2D32f to CvPoint. */ +CV_INLINE CvPoint cvPointFrom32f( CvPoint2D32f point ) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvPoint ipt = { cvRound(point.x), cvRound(point.y) }; +#else + CvPoint ipt(cvRound(point.x), cvRound(point.y)); +#endif + return ipt; +} + + +typedef struct CvPoint3D32f +{ + float x; + float y; + float z; + +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS + CvPoint3D32f() __attribute__(( warning("Non-initialized variable") )) {} + template CvPoint3D32f(const std::initializer_list<_Tp> list) + { + CV_Assert(list.size() == 0 || list.size() == 3); + x = y = z = 0; + if (list.size() == 3) + { + x = list.begin()[0]; y = list.begin()[1]; z = list.begin()[2]; + } + }; +#elif defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) + CvPoint3D32f(float _x = 0, float _y = 0, float _z = 0): x(_x), y(_y), z(_z) {} + template + CvPoint3D32f(const cv::Point3_<_Tp>& pt): x((float)pt.x), y((float)pt.y), z((float)pt.z) {} +#endif +#ifdef __cplusplus + template + operator cv::Point3_<_Tp>() const { return cv::Point3_<_Tp>(cv::saturate_cast<_Tp>(x), cv::saturate_cast<_Tp>(y), cv::saturate_cast<_Tp>(z)); } +#endif +} +CvPoint3D32f; + +/** constructs CvPoint3D32f structure. */ +CV_INLINE CvPoint3D32f cvPoint3D32f( double x, double y, double z ) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvPoint3D32f p = { (float)x, (float)y, (float)z }; +#else + CvPoint3D32f p((float)x, (float)y, (float)z); +#endif + return p; +} + +#ifdef __cplusplus +template +CvPoint3D32f cvPoint3D32f(const cv::Point3_<_Tp>& pt) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvPoint3D32f p = { (float)pt.x, (float)pt.y, (float)pt.z }; +#else + CvPoint3D32f p((float)pt.x, (float)pt.y, (float)pt.z); +#endif + return p; +} +#endif + + +typedef struct CvPoint2D64f +{ + double x; + double y; +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS + CvPoint2D64f() __attribute__(( warning("Non-initialized variable") )) {} + template CvPoint2D64f(const std::initializer_list<_Tp> list) + { + CV_Assert(list.size() == 0 || list.size() == 2); + x = y = 0; + if (list.size() == 2) + { + x = list.begin()[0]; y = list.begin()[1]; + } + }; +#endif +} +CvPoint2D64f; + +/** constructs CvPoint2D64f structure.*/ +CV_INLINE CvPoint2D64f cvPoint2D64f( double x, double y ) +{ + CvPoint2D64f p = { x, y }; + return p; +} + + +typedef struct CvPoint3D64f +{ + double x; + double y; + double z; +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS + CvPoint3D64f() __attribute__(( warning("Non-initialized variable") )) {} + template CvPoint3D64f(const std::initializer_list<_Tp> list) + { + CV_Assert(list.size() == 0 || list.size() == 3); + x = y = z = 0; + if (list.size() == 3) + { + x = list.begin()[0]; y = list.begin()[1]; z = list.begin()[2]; + } + }; +#endif +} +CvPoint3D64f; + +/** constructs CvPoint3D64f structure. */ +CV_INLINE CvPoint3D64f cvPoint3D64f( double x, double y, double z ) +{ + CvPoint3D64f p = { x, y, z }; + return p; +} + + +/******************************** CvSize's & CvBox **************************************/ + +typedef struct CvSize +{ + int width; + int height; + +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS + CvSize() __attribute__(( warning("Non-initialized variable") )) {} + template CvSize(const std::initializer_list<_Tp> list) + { + CV_Assert(list.size() == 0 || list.size() == 2); + width = 0; height = 0; + if (list.size() == 2) + { + width = list.begin()[0]; height = list.begin()[1]; + } + }; +#elif defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) + CvSize(int w = 0, int h = 0): width(w), height(h) {} + template + CvSize(const cv::Size_<_Tp>& sz): width(cv::saturate_cast(sz.width)), height(cv::saturate_cast(sz.height)) {} +#endif +#ifdef __cplusplus + template + operator cv::Size_<_Tp>() const { return cv::Size_<_Tp>(cv::saturate_cast<_Tp>(width), cv::saturate_cast<_Tp>(height)); } +#endif +} +CvSize; + +/** constructs CvSize structure. */ +CV_INLINE CvSize cvSize( int width, int height ) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvSize s = { width, height }; +#else + CvSize s(width, height); +#endif + return s; +} + +#ifdef __cplusplus +CV_INLINE CvSize cvSize(const cv::Size& sz) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvSize s = { sz.width, sz.height }; +#else + CvSize s(sz.width, sz.height); +#endif + return s; +} +#endif + +typedef struct CvSize2D32f +{ + float width; + float height; + +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS + CvSize2D32f() __attribute__(( warning("Non-initialized variable") )) {} + template CvSize2D32f(const std::initializer_list<_Tp> list) + { + CV_Assert(list.size() == 0 || list.size() == 2); + width = 0; height = 0; + if (list.size() == 2) + { + width = list.begin()[0]; height = list.begin()[1]; + } + }; +#elif defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) + CvSize2D32f(float w = 0, float h = 0): width(w), height(h) {} + template + CvSize2D32f(const cv::Size_<_Tp>& sz): width(cv::saturate_cast(sz.width)), height(cv::saturate_cast(sz.height)) {} +#endif +#ifdef __cplusplus + template + operator cv::Size_<_Tp>() const { return cv::Size_<_Tp>(cv::saturate_cast<_Tp>(width), cv::saturate_cast<_Tp>(height)); } +#endif +} +CvSize2D32f; + +/** constructs CvSize2D32f structure. */ +CV_INLINE CvSize2D32f cvSize2D32f( double width, double height ) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvSize2D32f s = { (float)width, (float)height }; +#else + CvSize2D32f s((float)width, (float)height); +#endif + return s; +} +#ifdef __cplusplus +template +CvSize2D32f cvSize2D32f(const cv::Size_<_Tp>& sz) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvSize2D32f s = { (float)sz.width, (float)sz.height }; +#else + CvSize2D32f s((float)sz.width, (float)sz.height); +#endif + return s; +} +#endif + +/** @sa RotatedRect + */ +typedef struct CvBox2D +{ + CvPoint2D32f center; /**< Center of the box. */ + CvSize2D32f size; /**< Box width and length. */ + float angle; /**< Angle between the horizontal axis */ + /**< and the first side (i.e. length) in degrees */ + +#if defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) + CvBox2D(CvPoint2D32f c = CvPoint2D32f(), CvSize2D32f s = CvSize2D32f(), float a = 0) : center(c), size(s), angle(a) {} + CvBox2D(const cv::RotatedRect& rr) : center(rr.center), size(rr.size), angle(rr.angle) {} +#endif +#ifdef __cplusplus + operator cv::RotatedRect() const { return cv::RotatedRect(center, size, angle); } +#endif +} +CvBox2D; + + +#ifdef __cplusplus +CV_INLINE CvBox2D cvBox2D(CvPoint2D32f c = CvPoint2D32f(), CvSize2D32f s = CvSize2D32f(), float a = 0) +{ + CvBox2D self; + self.center = c; + self.size = s; + self.angle = a; + return self; +} +CV_INLINE CvBox2D cvBox2D(const cv::RotatedRect& rr) +{ + CvBox2D self; + self.center = cvPoint2D32f(rr.center); + self.size = cvSize2D32f(rr.size); + self.angle = rr.angle; + return self; +} +#endif + + +/** Line iterator state: */ +typedef struct CvLineIterator +{ + /** Pointer to the current point: */ + uchar* ptr; + + /* Bresenham algorithm state: */ + int err; + int plus_delta; + int minus_delta; + int plus_step; + int minus_step; +} +CvLineIterator; + + + +/************************************* CvSlice ******************************************/ +#define CV_WHOLE_SEQ_END_INDEX 0x3fffffff +#define CV_WHOLE_SEQ cvSlice(0, CV_WHOLE_SEQ_END_INDEX) + +typedef struct CvSlice +{ + int start_index, end_index; + +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS + CvSlice() __attribute__(( warning("Non-initialized variable") )) {} + template CvSlice(const std::initializer_list<_Tp> list) + { + CV_Assert(list.size() == 0 || list.size() == 2); + start_index = end_index = 0; + if (list.size() == 2) + { + start_index = list.begin()[0]; end_index = list.begin()[1]; + } + }; +#endif +#if defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) && !defined(__CUDACC__) + CvSlice(int start = 0, int end = 0) : start_index(start), end_index(end) {} + CvSlice(const cv::Range& r) { *this = (r.start != INT_MIN && r.end != INT_MAX) ? CvSlice(r.start, r.end) : CvSlice(0, CV_WHOLE_SEQ_END_INDEX); } + operator cv::Range() const { return (start_index == 0 && end_index == CV_WHOLE_SEQ_END_INDEX ) ? cv::Range::all() : cv::Range(start_index, end_index); } +#endif +} +CvSlice; + +CV_INLINE CvSlice cvSlice( int start, int end ) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) && !defined(__CUDACC__)) + CvSlice slice = { start, end }; +#else + CvSlice slice(start, end); +#endif + return slice; +} + +#if defined(__cplusplus) +CV_INLINE CvSlice cvSlice(const cv::Range& r) +{ + CvSlice slice = (r.start != INT_MIN && r.end != INT_MAX) ? cvSlice(r.start, r.end) : cvSlice(0, CV_WHOLE_SEQ_END_INDEX); + return slice; +} +#endif + + +/************************************* CvScalar *****************************************/ +/** @sa Scalar_ + */ +typedef struct CvScalar +{ + double val[4]; + +#ifdef CV__VALIDATE_UNUNITIALIZED_VARS + CvScalar() __attribute__(( warning("Non-initialized variable") )) {} + CvScalar(const std::initializer_list list) + { + CV_Assert(list.size() == 0 || list.size() == 4); + val[0] = val[1] = val[2] = val[3] = 0; + if (list.size() == 4) + { + val[0] = list.begin()[0]; val[1] = list.begin()[1]; val[2] = list.begin()[2]; val[3] = list.begin()[3]; + } + }; +#elif defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus) + CvScalar() {} + CvScalar(double d0, double d1 = 0, double d2 = 0, double d3 = 0) { val[0] = d0; val[1] = d1; val[2] = d2; val[3] = d3; } + template + CvScalar(const cv::Scalar_<_Tp>& s) { val[0] = s.val[0]; val[1] = s.val[1]; val[2] = s.val[2]; val[3] = s.val[3]; } + template + CvScalar(const cv::Vec<_Tp, cn>& v) + { + int i; + for( i = 0; i < (cn < 4 ? cn : 4); i++ ) val[i] = v.val[i]; + for( ; i < 4; i++ ) val[i] = 0; + } +#endif +#ifdef __cplusplus + template + operator cv::Scalar_<_Tp>() const { return cv::Scalar_<_Tp>(cv::saturate_cast<_Tp>(val[0]), cv::saturate_cast<_Tp>(val[1]), cv::saturate_cast<_Tp>(val[2]), cv::saturate_cast<_Tp>(val[3])); } +#endif +} +CvScalar; + +CV_INLINE CvScalar cvScalar( double val0, double val1 CV_DEFAULT(0), + double val2 CV_DEFAULT(0), double val3 CV_DEFAULT(0)) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvScalar scalar = CV_STRUCT_INITIALIZER; +#else + CvScalar scalar; +#endif + scalar.val[0] = val0; scalar.val[1] = val1; + scalar.val[2] = val2; scalar.val[3] = val3; + return scalar; +} + +#ifdef __cplusplus +CV_INLINE CvScalar cvScalar() +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvScalar scalar = CV_STRUCT_INITIALIZER; +#else + CvScalar scalar; +#endif + scalar.val[0] = scalar.val[1] = scalar.val[2] = scalar.val[3] = 0; + return scalar; +} +CV_INLINE CvScalar cvScalar(const cv::Scalar& s) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvScalar scalar = CV_STRUCT_INITIALIZER; +#else + CvScalar scalar; +#endif + scalar.val[0] = s.val[0]; + scalar.val[1] = s.val[1]; + scalar.val[2] = s.val[2]; + scalar.val[3] = s.val[3]; + return scalar; +} +#endif + +CV_INLINE CvScalar cvRealScalar( double val0 ) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvScalar scalar = CV_STRUCT_INITIALIZER; +#else + CvScalar scalar; +#endif + scalar.val[0] = val0; + scalar.val[1] = scalar.val[2] = scalar.val[3] = 0; + return scalar; +} + +CV_INLINE CvScalar cvScalarAll( double val0123 ) +{ +#if !(defined(CV__ENABLE_C_API_CTORS) && defined(__cplusplus)) + CvScalar scalar = CV_STRUCT_INITIALIZER; +#else + CvScalar scalar; +#endif + scalar.val[0] = val0123; + scalar.val[1] = val0123; + scalar.val[2] = val0123; + scalar.val[3] = val0123; + return scalar; +} + +/****************************************************************************************\ +* Dynamic Data structures * +\****************************************************************************************/ + +/******************************** Memory storage ****************************************/ + +typedef struct CvMemBlock +{ + struct CvMemBlock* prev; + struct CvMemBlock* next; +} +CvMemBlock; + +#define CV_STORAGE_MAGIC_VAL 0x42890000 + +typedef struct CvMemStorage +{ + int signature; + CvMemBlock* bottom; /**< First allocated block. */ + CvMemBlock* top; /**< Current memory block - top of the stack. */ + struct CvMemStorage* parent; /**< We get new blocks from parent as needed. */ + int block_size; /**< Block size. */ + int free_space; /**< Remaining free space in current block. */ +} +CvMemStorage; + +#define CV_IS_STORAGE(storage) \ + ((storage) != NULL && \ + (((CvMemStorage*)(storage))->signature & CV_MAGIC_MASK) == CV_STORAGE_MAGIC_VAL) + + +typedef struct CvMemStoragePos +{ + CvMemBlock* top; + int free_space; +} +CvMemStoragePos; + + +/*********************************** Sequence *******************************************/ + +typedef struct CvSeqBlock +{ + struct CvSeqBlock* prev; /**< Previous sequence block. */ + struct CvSeqBlock* next; /**< Next sequence block. */ + int start_index; /**< Index of the first element in the block + */ + /**< sequence->first->start_index. */ + int count; /**< Number of elements in the block. */ + schar* data; /**< Pointer to the first element of the block. */ +} +CvSeqBlock; + + +#define CV_TREE_NODE_FIELDS(node_type) \ + int flags; /**< Miscellaneous flags. */ \ + int header_size; /**< Size of sequence header. */ \ + struct node_type* h_prev; /**< Previous sequence. */ \ + struct node_type* h_next; /**< Next sequence. */ \ + struct node_type* v_prev; /**< 2nd previous sequence. */ \ + struct node_type* v_next /**< 2nd next sequence. */ + +/** + Read/Write sequence. + Elements can be dynamically inserted to or deleted from the sequence. +*/ +#define CV_SEQUENCE_FIELDS() \ + CV_TREE_NODE_FIELDS(CvSeq); \ + int total; /**< Total number of elements. */ \ + int elem_size; /**< Size of sequence element in bytes. */ \ + schar* block_max; /**< Maximal bound of the last block. */ \ + schar* ptr; /**< Current write pointer. */ \ + int delta_elems; /**< Grow seq this many at a time. */ \ + CvMemStorage* storage; /**< Where the seq is stored. */ \ + CvSeqBlock* free_blocks; /**< Free blocks list. */ \ + CvSeqBlock* first; /**< Pointer to the first sequence block. */ + +typedef struct CvSeq +{ + CV_SEQUENCE_FIELDS() +} +CvSeq; + +#define CV_TYPE_NAME_SEQ "opencv-sequence" +#define CV_TYPE_NAME_SEQ_TREE "opencv-sequence-tree" + +/*************************************** Set ********************************************/ +/** @brief Set + Order is not preserved. There can be gaps between sequence elements. + After the element has been inserted it stays in the same place all the time. + The MSB(most-significant or sign bit) of the first field (flags) is 0 iff the element exists. +*/ +#define CV_SET_ELEM_FIELDS(elem_type) \ + int flags; \ + struct elem_type* next_free; + +typedef struct CvSetElem +{ + CV_SET_ELEM_FIELDS(CvSetElem) +} +CvSetElem; + +#define CV_SET_FIELDS() \ + CV_SEQUENCE_FIELDS() \ + CvSetElem* free_elems; \ + int active_count; + +typedef struct CvSet +{ + CV_SET_FIELDS() +} +CvSet; + + +#define CV_SET_ELEM_IDX_MASK ((1 << 26) - 1) +#define CV_SET_ELEM_FREE_FLAG (1 << (sizeof(int)*8-1)) + +/** Checks whether the element pointed by ptr belongs to a set or not */ +#define CV_IS_SET_ELEM( ptr ) (((CvSetElem*)(ptr))->flags >= 0) + +/************************************* Graph ********************************************/ + +/** @name Graph + +We represent a graph as a set of vertices. Vertices contain their adjacency lists (more exactly, +pointers to first incoming or outcoming edge (or 0 if isolated vertex)). Edges are stored in +another set. There is a singly-linked list of incoming/outcoming edges for each vertex. + +Each edge consists of: + +- Two pointers to the starting and ending vertices (vtx[0] and vtx[1] respectively). + + A graph may be oriented or not. In the latter case, edges between vertex i to vertex j are not +distinguished during search operations. + +- Two pointers to next edges for the starting and ending vertices, where next[0] points to the +next edge in the vtx[0] adjacency list and next[1] points to the next edge in the vtx[1] +adjacency list. + +@see CvGraphEdge, CvGraphVtx, CvGraphVtx2D, CvGraph +@{ +*/ +#define CV_GRAPH_EDGE_FIELDS() \ + int flags; \ + float weight; \ + struct CvGraphEdge* next[2]; \ + struct CvGraphVtx* vtx[2]; + + +#define CV_GRAPH_VERTEX_FIELDS() \ + int flags; \ + struct CvGraphEdge* first; + + +typedef struct CvGraphEdge +{ + CV_GRAPH_EDGE_FIELDS() +} +CvGraphEdge; + +typedef struct CvGraphVtx +{ + CV_GRAPH_VERTEX_FIELDS() +} +CvGraphVtx; + +typedef struct CvGraphVtx2D +{ + CV_GRAPH_VERTEX_FIELDS() + CvPoint2D32f* ptr; +} +CvGraphVtx2D; + +/** + Graph is "derived" from the set (this is set a of vertices) + and includes another set (edges) +*/ +#define CV_GRAPH_FIELDS() \ + CV_SET_FIELDS() \ + CvSet* edges; + +typedef struct CvGraph +{ + CV_GRAPH_FIELDS() +} +CvGraph; + +#define CV_TYPE_NAME_GRAPH "opencv-graph" + +/** @} */ + +/*********************************** Chain/Contour *************************************/ + +typedef struct CvChain +{ + CV_SEQUENCE_FIELDS() + CvPoint origin; +} +CvChain; + +#define CV_CONTOUR_FIELDS() \ + CV_SEQUENCE_FIELDS() \ + CvRect rect; \ + int color; \ + int reserved[3]; + +typedef struct CvContour +{ + CV_CONTOUR_FIELDS() +} +CvContour; + +typedef CvContour CvPoint2DSeq; + +/****************************************************************************************\ +* Sequence types * +\****************************************************************************************/ + +#define CV_SEQ_MAGIC_VAL 0x42990000 + +#define CV_IS_SEQ(seq) \ + ((seq) != NULL && (((CvSeq*)(seq))->flags & CV_MAGIC_MASK) == CV_SEQ_MAGIC_VAL) + +#define CV_SET_MAGIC_VAL 0x42980000 +#define CV_IS_SET(set) \ + ((set) != NULL && (((CvSeq*)(set))->flags & CV_MAGIC_MASK) == CV_SET_MAGIC_VAL) + +#define CV_SEQ_ELTYPE_BITS 12 +#define CV_SEQ_ELTYPE_MASK ((1 << CV_SEQ_ELTYPE_BITS) - 1) + +#define CV_SEQ_ELTYPE_POINT CV_32SC2 /**< (x,y) */ +#define CV_SEQ_ELTYPE_CODE CV_8UC1 /**< freeman code: 0..7 */ +#define CV_SEQ_ELTYPE_GENERIC 0 +#define CV_SEQ_ELTYPE_PTR CV_MAKE_TYPE(CV_8U, 8 /*sizeof(void*)*/) +#define CV_SEQ_ELTYPE_PPOINT CV_SEQ_ELTYPE_PTR /**< &(x,y) */ +#define CV_SEQ_ELTYPE_INDEX CV_32SC1 /**< #(x,y) */ +#define CV_SEQ_ELTYPE_GRAPH_EDGE 0 /**< &next_o, &next_d, &vtx_o, &vtx_d */ +#define CV_SEQ_ELTYPE_GRAPH_VERTEX 0 /**< first_edge, &(x,y) */ +#define CV_SEQ_ELTYPE_TRIAN_ATR 0 /**< vertex of the binary tree */ +#define CV_SEQ_ELTYPE_CONNECTED_COMP 0 /**< connected component */ +#define CV_SEQ_ELTYPE_POINT3D CV_32FC3 /**< (x,y,z) */ + +#define CV_SEQ_KIND_BITS 2 +#define CV_SEQ_KIND_MASK (((1 << CV_SEQ_KIND_BITS) - 1)<flags & CV_SEQ_ELTYPE_MASK) +#define CV_SEQ_KIND( seq ) ((seq)->flags & CV_SEQ_KIND_MASK ) + +/** flag checking */ +#define CV_IS_SEQ_INDEX( seq ) ((CV_SEQ_ELTYPE(seq) == CV_SEQ_ELTYPE_INDEX) && \ + (CV_SEQ_KIND(seq) == CV_SEQ_KIND_GENERIC)) + +#define CV_IS_SEQ_CURVE( seq ) (CV_SEQ_KIND(seq) == CV_SEQ_KIND_CURVE) +#define CV_IS_SEQ_CLOSED( seq ) (((seq)->flags & CV_SEQ_FLAG_CLOSED) != 0) +#define CV_IS_SEQ_CONVEX( seq ) 0 +#define CV_IS_SEQ_HOLE( seq ) (((seq)->flags & CV_SEQ_FLAG_HOLE) != 0) +#define CV_IS_SEQ_SIMPLE( seq ) 1 + +/** type checking macros */ +#define CV_IS_SEQ_POINT_SET( seq ) \ + ((CV_SEQ_ELTYPE(seq) == CV_32SC2 || CV_SEQ_ELTYPE(seq) == CV_32FC2)) + +#define CV_IS_SEQ_POINT_SUBSET( seq ) \ + (CV_IS_SEQ_INDEX( seq ) || CV_SEQ_ELTYPE(seq) == CV_SEQ_ELTYPE_PPOINT) + +#define CV_IS_SEQ_POLYLINE( seq ) \ + (CV_SEQ_KIND(seq) == CV_SEQ_KIND_CURVE && CV_IS_SEQ_POINT_SET(seq)) + +#define CV_IS_SEQ_POLYGON( seq ) \ + (CV_IS_SEQ_POLYLINE(seq) && CV_IS_SEQ_CLOSED(seq)) + +#define CV_IS_SEQ_CHAIN( seq ) \ + (CV_SEQ_KIND(seq) == CV_SEQ_KIND_CURVE && (seq)->elem_size == 1) + +#define CV_IS_SEQ_CONTOUR( seq ) \ + (CV_IS_SEQ_CLOSED(seq) && (CV_IS_SEQ_POLYLINE(seq) || CV_IS_SEQ_CHAIN(seq))) + +#define CV_IS_SEQ_CHAIN_CONTOUR( seq ) \ + (CV_IS_SEQ_CHAIN( seq ) && CV_IS_SEQ_CLOSED( seq )) + +#define CV_IS_SEQ_POLYGON_TREE( seq ) \ + (CV_SEQ_ELTYPE (seq) == CV_SEQ_ELTYPE_TRIAN_ATR && \ + CV_SEQ_KIND( seq ) == CV_SEQ_KIND_BIN_TREE ) + +#define CV_IS_GRAPH( seq ) \ + (CV_IS_SET(seq) && CV_SEQ_KIND((CvSet*)(seq)) == CV_SEQ_KIND_GRAPH) + +#define CV_IS_GRAPH_ORIENTED( seq ) \ + (((seq)->flags & CV_GRAPH_FLAG_ORIENTED) != 0) + +#define CV_IS_SUBDIV2D( seq ) \ + (CV_IS_SET(seq) && CV_SEQ_KIND((CvSet*)(seq)) == CV_SEQ_KIND_SUBDIV2D) + +/****************************************************************************************/ +/* Sequence writer & reader */ +/****************************************************************************************/ + +#define CV_SEQ_WRITER_FIELDS() \ + int header_size; \ + CvSeq* seq; /**< the sequence written */ \ + CvSeqBlock* block; /**< current block */ \ + schar* ptr; /**< pointer to free space */ \ + schar* block_min; /**< pointer to the beginning of block*/\ + schar* block_max; /**< pointer to the end of block */ + +typedef struct CvSeqWriter +{ + CV_SEQ_WRITER_FIELDS() +} +CvSeqWriter; + + +#define CV_SEQ_READER_FIELDS() \ + int header_size; \ + CvSeq* seq; /**< sequence, beign read */ \ + CvSeqBlock* block; /**< current block */ \ + schar* ptr; /**< pointer to element be read next */ \ + schar* block_min; /**< pointer to the beginning of block */\ + schar* block_max; /**< pointer to the end of block */ \ + int delta_index;/**< = seq->first->start_index */ \ + schar* prev_elem; /**< pointer to previous element */ + +typedef struct CvSeqReader +{ + CV_SEQ_READER_FIELDS() +} +CvSeqReader; + +/****************************************************************************************/ +/* Operations on sequences */ +/****************************************************************************************/ + +#define CV_SEQ_ELEM( seq, elem_type, index ) \ +/** assert gives some guarantee that parameter is valid */ \ +( assert(sizeof((seq)->first[0]) == sizeof(CvSeqBlock) && \ + (seq)->elem_size == sizeof(elem_type)), \ + (elem_type*)((seq)->first && (unsigned)index < \ + (unsigned)((seq)->first->count) ? \ + (seq)->first->data + (index) * sizeof(elem_type) : \ + cvGetSeqElem( (CvSeq*)(seq), (index) ))) +#define CV_GET_SEQ_ELEM( elem_type, seq, index ) CV_SEQ_ELEM( (seq), elem_type, (index) ) + +/** Add element to sequence: */ +#define CV_WRITE_SEQ_ELEM_VAR( elem_ptr, writer ) \ +{ \ + if( (writer).ptr >= (writer).block_max ) \ + { \ + cvCreateSeqBlock( &writer); \ + } \ + memcpy((writer).ptr, elem_ptr, (writer).seq->elem_size);\ + (writer).ptr += (writer).seq->elem_size; \ +} + +#define CV_WRITE_SEQ_ELEM( elem, writer ) \ +{ \ + assert( (writer).seq->elem_size == sizeof(elem)); \ + if( (writer).ptr >= (writer).block_max ) \ + { \ + cvCreateSeqBlock( &writer); \ + } \ + assert( (writer).ptr <= (writer).block_max - sizeof(elem));\ + memcpy((writer).ptr, &(elem), sizeof(elem)); \ + (writer).ptr += sizeof(elem); \ +} + + +/** Move reader position forward: */ +#define CV_NEXT_SEQ_ELEM( elem_size, reader ) \ +{ \ + if( ((reader).ptr += (elem_size)) >= (reader).block_max ) \ + { \ + cvChangeSeqBlock( &(reader), 1 ); \ + } \ +} + + +/** Move reader position backward: */ +#define CV_PREV_SEQ_ELEM( elem_size, reader ) \ +{ \ + if( ((reader).ptr -= (elem_size)) < (reader).block_min ) \ + { \ + cvChangeSeqBlock( &(reader), -1 ); \ + } \ +} + +/** Read element and move read position forward: */ +#define CV_READ_SEQ_ELEM( elem, reader ) \ +{ \ + assert( (reader).seq->elem_size == sizeof(elem)); \ + memcpy( &(elem), (reader).ptr, sizeof((elem))); \ + CV_NEXT_SEQ_ELEM( sizeof(elem), reader ) \ +} + +/** Read element and move read position backward: */ +#define CV_REV_READ_SEQ_ELEM( elem, reader ) \ +{ \ + assert( (reader).seq->elem_size == sizeof(elem)); \ + memcpy(&(elem), (reader).ptr, sizeof((elem))); \ + CV_PREV_SEQ_ELEM( sizeof(elem), reader ) \ +} + + +#define CV_READ_CHAIN_POINT( _pt, reader ) \ +{ \ + (_pt) = (reader).pt; \ + if( (reader).ptr ) \ + { \ + CV_READ_SEQ_ELEM( (reader).code, (reader)); \ + assert( ((reader).code & ~7) == 0 ); \ + (reader).pt.x += (reader).deltas[(int)(reader).code][0]; \ + (reader).pt.y += (reader).deltas[(int)(reader).code][1]; \ + } \ +} + +#define CV_CURRENT_POINT( reader ) (*((CvPoint*)((reader).ptr))) +#define CV_PREV_POINT( reader ) (*((CvPoint*)((reader).prev_elem))) + +#define CV_READ_EDGE( pt1, pt2, reader ) \ +{ \ + assert( sizeof(pt1) == sizeof(CvPoint) && \ + sizeof(pt2) == sizeof(CvPoint) && \ + reader.seq->elem_size == sizeof(CvPoint)); \ + (pt1) = CV_PREV_POINT( reader ); \ + (pt2) = CV_CURRENT_POINT( reader ); \ + (reader).prev_elem = (reader).ptr; \ + CV_NEXT_SEQ_ELEM( sizeof(CvPoint), (reader)); \ +} + +/************ Graph macros ************/ + +/** Return next graph edge for given vertex: */ +#define CV_NEXT_GRAPH_EDGE( edge, vertex ) \ + (assert((edge)->vtx[0] == (vertex) || (edge)->vtx[1] == (vertex)), \ + (edge)->next[(edge)->vtx[1] == (vertex)]) + + + +/****************************************************************************************\ +* Data structures for persistence (a.k.a serialization) functionality * +\****************************************************************************************/ + +#if 0 + +/** "black box" file storage */ +typedef struct CvFileStorage CvFileStorage; + +/** Storage flags: */ +#define CV_STORAGE_READ 0 +#define CV_STORAGE_WRITE 1 +#define CV_STORAGE_WRITE_TEXT CV_STORAGE_WRITE +#define CV_STORAGE_WRITE_BINARY CV_STORAGE_WRITE +#define CV_STORAGE_APPEND 2 +#define CV_STORAGE_MEMORY 4 +#define CV_STORAGE_FORMAT_MASK (7<<3) +#define CV_STORAGE_FORMAT_AUTO 0 +#define CV_STORAGE_FORMAT_XML 8 +#define CV_STORAGE_FORMAT_YAML 16 +#define CV_STORAGE_FORMAT_JSON 24 +#define CV_STORAGE_BASE64 64 +#define CV_STORAGE_WRITE_BASE64 (CV_STORAGE_BASE64 | CV_STORAGE_WRITE) + +/** @brief List of attributes. : + +In the current implementation, attributes are used to pass extra parameters when writing user +objects (see cvWrite). XML attributes inside tags are not supported, aside from the object type +specification (type_id attribute). +@see cvAttrList, cvAttrValue + */ +typedef struct CvAttrList +{ + const char** attr; /**< NULL-terminated array of (attribute_name,attribute_value) pairs. */ + struct CvAttrList* next; /**< Pointer to next chunk of the attributes list. */ +} +CvAttrList; + +/** initializes CvAttrList structure */ +CV_INLINE CvAttrList cvAttrList( const char** attr CV_DEFAULT(NULL), + CvAttrList* next CV_DEFAULT(NULL) ) +{ + CvAttrList l; + l.attr = attr; + l.next = next; + + return l; +} + +struct CvTypeInfo; + +#define CV_NODE_NONE 0 +#define CV_NODE_INT 1 +#define CV_NODE_INTEGER CV_NODE_INT +#define CV_NODE_REAL 2 +#define CV_NODE_FLOAT CV_NODE_REAL +#define CV_NODE_STR 3 +#define CV_NODE_STRING CV_NODE_STR +#define CV_NODE_REF 4 /**< not used */ +#define CV_NODE_SEQ 5 +#define CV_NODE_MAP 6 +#define CV_NODE_TYPE_MASK 7 + +#define CV_NODE_TYPE(flags) ((flags) & CV_NODE_TYPE_MASK) + +/** file node flags */ +#define CV_NODE_FLOW 8 /**= CV_NODE_SEQ) +#define CV_NODE_IS_FLOW(flags) (((flags) & CV_NODE_FLOW) != 0) +#define CV_NODE_IS_EMPTY(flags) (((flags) & CV_NODE_EMPTY) != 0) +#define CV_NODE_IS_USER(flags) (((flags) & CV_NODE_USER) != 0) +#define CV_NODE_HAS_NAME(flags) (((flags) & CV_NODE_NAMED) != 0) + +#define CV_NODE_SEQ_SIMPLE 256 +#define CV_NODE_SEQ_IS_SIMPLE(seq) (((seq)->flags & CV_NODE_SEQ_SIMPLE) != 0) + +typedef struct CvString +{ + int len; + char* ptr; +} +CvString; + +/** All the keys (names) of elements in the read file storage + are stored in the hash to speed up the lookup operations: */ +typedef struct CvStringHashNode +{ + unsigned hashval; + CvString str; + struct CvStringHashNode* next; +} +CvStringHashNode; + +typedef struct CvGenericHash CvFileNodeHash; + +/** Basic element of the file storage - scalar or collection: */ +typedef struct CvFileNode +{ + int tag; + struct CvTypeInfo* info; /**< type information + (only for user-defined object, for others it is 0) */ + union + { + double f; /**< scalar floating-point number */ + int i; /**< scalar integer number */ + CvString str; /**< text string */ + CvSeq* seq; /**< sequence (ordered collection of file nodes) */ + CvFileNodeHash* map; /**< map (collection of named file nodes) */ + } data; +} +CvFileNode; + +#ifdef __cplusplus +extern "C" { +#endif +typedef int (CV_CDECL *CvIsInstanceFunc)( const void* struct_ptr ); +typedef void (CV_CDECL *CvReleaseFunc)( void** struct_dblptr ); +typedef void* (CV_CDECL *CvReadFunc)( CvFileStorage* storage, CvFileNode* node ); +typedef void (CV_CDECL *CvWriteFunc)( CvFileStorage* storage, const char* name, + const void* struct_ptr, CvAttrList attributes ); +typedef void* (CV_CDECL *CvCloneFunc)( const void* struct_ptr ); +#ifdef __cplusplus +} +#endif + +/** @brief Type information + +The structure contains information about one of the standard or user-defined types. Instances of the +type may or may not contain a pointer to the corresponding CvTypeInfo structure. In any case, there +is a way to find the type info structure for a given object using the cvTypeOf function. +Alternatively, type info can be found by type name using cvFindType, which is used when an object +is read from file storage. The user can register a new type with cvRegisterType that adds the type +information structure into the beginning of the type list. Thus, it is possible to create +specialized types from generic standard types and override the basic methods. + */ +typedef struct CvTypeInfo +{ + int flags; /**< not used */ + int header_size; /**< sizeof(CvTypeInfo) */ + struct CvTypeInfo* prev; /**< previous registered type in the list */ + struct CvTypeInfo* next; /**< next registered type in the list */ + const char* type_name; /**< type name, written to file storage */ + CvIsInstanceFunc is_instance; /**< checks if the passed object belongs to the type */ + CvReleaseFunc release; /**< releases object (memory etc.) */ + CvReadFunc read; /**< reads object from file storage */ + CvWriteFunc write; /**< writes object to file storage */ + CvCloneFunc clone; /**< creates a copy of the object */ +} +CvTypeInfo; +#endif + +/** @} */ + +#endif /*OPENCV_CORE_TYPES_H*/ + +/* End of file. */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utility.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utility.hpp new file mode 100644 index 0000000..108c0d9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utility.hpp @@ -0,0 +1,1229 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_CORE_UTILITY_H +#define OPENCV_CORE_UTILITY_H + +#ifndef __cplusplus +# error utility.hpp header must be compiled as C++ +#endif + +#if defined(check) +# warning Detected Apple 'check' macro definition, it can cause build conflicts. Please, include this header before any Apple headers. +#endif + +#include "opencv2/core.hpp" +#include + +#include + +#if !defined(_M_CEE) +#include // std::mutex, std::lock_guard +#endif + +namespace cv +{ + +//! @addtogroup core_utils +//! @{ + +/** @brief Automatically Allocated Buffer Class + + The class is used for temporary buffers in functions and methods. + If a temporary buffer is usually small (a few K's of memory), + but its size depends on the parameters, it makes sense to create a small + fixed-size array on stack and use it if it's large enough. If the required buffer size + is larger than the fixed size, another buffer of sufficient size is allocated dynamically + and released after the processing. Therefore, in typical cases, when the buffer size is small, + there is no overhead associated with malloc()/free(). + At the same time, there is no limit on the size of processed data. + + This is what AutoBuffer does. The template takes 2 parameters - type of the buffer elements and + the number of stack-allocated elements. Here is how the class is used: + + \code + void my_func(const cv::Mat& m) + { + cv::AutoBuffer buf(1000); // create automatic buffer containing 1000 floats + + buf.allocate(m.rows); // if m.rows <= 1000, the pre-allocated buffer is used, + // otherwise the buffer of "m.rows" floats will be allocated + // dynamically and deallocated in cv::AutoBuffer destructor + ... + } + \endcode +*/ +#ifdef OPENCV_ENABLE_MEMORY_SANITIZER +template class AutoBuffer +#else +template class AutoBuffer +#endif +{ +public: + typedef _Tp value_type; + + //! the default constructor + AutoBuffer(); + //! constructor taking the real buffer size + explicit AutoBuffer(size_t _size); + + //! the copy constructor + AutoBuffer(const AutoBuffer<_Tp, fixed_size>& buf); + //! the assignment operator + AutoBuffer<_Tp, fixed_size>& operator = (const AutoBuffer<_Tp, fixed_size>& buf); + + //! destructor. calls deallocate() + ~AutoBuffer(); + + //! allocates the new buffer of size _size. if the _size is small enough, stack-allocated buffer is used + void allocate(size_t _size); + //! deallocates the buffer if it was dynamically allocated + void deallocate(); + //! resizes the buffer and preserves the content + void resize(size_t _size); + //! returns the current buffer size + size_t size() const; + //! returns pointer to the real buffer, stack-allocated or heap-allocated + inline _Tp* data() { return ptr; } + //! returns read-only pointer to the real buffer, stack-allocated or heap-allocated + inline const _Tp* data() const { return ptr; } + +#if !defined(OPENCV_DISABLE_DEPRECATED_COMPATIBILITY) // use to .data() calls instead + //! returns pointer to the real buffer, stack-allocated or heap-allocated + operator _Tp* () { return ptr; } + //! returns read-only pointer to the real buffer, stack-allocated or heap-allocated + operator const _Tp* () const { return ptr; } +#else + //! returns a reference to the element at specified location. No bounds checking is performed in Release builds. + inline _Tp& operator[] (size_t i) { CV_DbgCheckLT(i, sz, "out of range"); return ptr[i]; } + //! returns a reference to the element at specified location. No bounds checking is performed in Release builds. + inline const _Tp& operator[] (size_t i) const { CV_DbgCheckLT(i, sz, "out of range"); return ptr[i]; } +#endif + +protected: + //! pointer to the real buffer, can point to buf if the buffer is small enough + _Tp* ptr; + //! size of the real buffer + size_t sz; + //! pre-allocated buffer. At least 1 element to confirm C++ standard requirements + _Tp buf[(fixed_size > 0) ? fixed_size : 1]; +}; + +/** @brief Sets/resets the break-on-error mode. + +When the break-on-error mode is set, the default error handler issues a hardware exception, which +can make debugging more convenient. + +\return the previous state + */ +CV_EXPORTS bool setBreakOnError(bool flag); + +extern "C" typedef int (*ErrorCallback)( int status, const char* func_name, + const char* err_msg, const char* file_name, + int line, void* userdata ); + + +/** @brief Sets the new error handler and the optional user data. + + The function sets the new error handler, called from cv::error(). + + \param errCallback the new error handler. If NULL, the default error handler is used. + \param userdata the optional user data pointer, passed to the callback. + \param prevUserdata the optional output parameter where the previous user data pointer is stored + + \return the previous error handler +*/ +CV_EXPORTS ErrorCallback redirectError( ErrorCallback errCallback, void* userdata=0, void** prevUserdata=0); + +CV_EXPORTS String tempfile( const char* suffix = 0); +CV_EXPORTS void glob(String pattern, std::vector& result, bool recursive = false); + +/** @brief OpenCV will try to set the number of threads for the next parallel region. + +If threads == 0, OpenCV will disable threading optimizations and run all it's functions +sequentially. Passing threads \< 0 will reset threads number to system default. This function must +be called outside of parallel region. + +OpenCV will try to run its functions with specified threads number, but some behaviour differs from +framework: +- `TBB` - User-defined parallel constructions will run with the same threads number, if + another is not specified. If later on user creates his own scheduler, OpenCV will use it. +- `OpenMP` - No special defined behaviour. +- `Concurrency` - If threads == 1, OpenCV will disable threading optimizations and run its + functions sequentially. +- `GCD` - Supports only values \<= 0. +- `C=` - No special defined behaviour. +@param nthreads Number of threads used by OpenCV. +@sa getNumThreads, getThreadNum + */ +CV_EXPORTS_W void setNumThreads(int nthreads); + +/** @brief Returns the number of threads used by OpenCV for parallel regions. + +Always returns 1 if OpenCV is built without threading support. + +The exact meaning of return value depends on the threading framework used by OpenCV library: +- `TBB` - The number of threads, that OpenCV will try to use for parallel regions. If there is + any tbb::thread_scheduler_init in user code conflicting with OpenCV, then function returns + default number of threads used by TBB library. +- `OpenMP` - An upper bound on the number of threads that could be used to form a new team. +- `Concurrency` - The number of threads, that OpenCV will try to use for parallel regions. +- `GCD` - Unsupported; returns the GCD thread pool limit (512) for compatibility. +- `C=` - The number of threads, that OpenCV will try to use for parallel regions, if before + called setNumThreads with threads \> 0, otherwise returns the number of logical CPUs, + available for the process. +@sa setNumThreads, getThreadNum + */ +CV_EXPORTS_W int getNumThreads(); + +/** @brief Returns the index of the currently executed thread within the current parallel region. Always +returns 0 if called outside of parallel region. + +@deprecated Current implementation doesn't corresponding to this documentation. + +The exact meaning of the return value depends on the threading framework used by OpenCV library: +- `TBB` - Unsupported with current 4.1 TBB release. Maybe will be supported in future. +- `OpenMP` - The thread number, within the current team, of the calling thread. +- `Concurrency` - An ID for the virtual processor that the current context is executing on (0 + for master thread and unique number for others, but not necessary 1,2,3,...). +- `GCD` - System calling thread's ID. Never returns 0 inside parallel region. +- `C=` - The index of the current parallel task. +@sa setNumThreads, getNumThreads + */ +CV_EXPORTS_W int getThreadNum(); + +/** @brief Returns full configuration time cmake output. + +Returned value is raw cmake output including version control system revision, compiler version, +compiler flags, enabled modules and third party libraries, etc. Output format depends on target +architecture. + */ +CV_EXPORTS_W const String& getBuildInformation(); + +/** @brief Returns library version string + +For example "3.4.1-dev". + +@sa getMajorVersion, getMinorVersion, getRevisionVersion +*/ +CV_EXPORTS_W String getVersionString(); + +/** @brief Returns major library version */ +CV_EXPORTS_W int getVersionMajor(); + +/** @brief Returns minor library version */ +CV_EXPORTS_W int getVersionMinor(); + +/** @brief Returns revision field of the library version */ +CV_EXPORTS_W int getVersionRevision(); + +/** @brief Returns the number of ticks. + +The function returns the number of ticks after the certain event (for example, when the machine was +turned on). It can be used to initialize RNG or to measure a function execution time by reading the +tick count before and after the function call. +@sa getTickFrequency, TickMeter + */ +CV_EXPORTS_W int64 getTickCount(); + +/** @brief Returns the number of ticks per second. + +The function returns the number of ticks per second. That is, the following code computes the +execution time in seconds: +@code + double t = (double)getTickCount(); + // do something ... + t = ((double)getTickCount() - t)/getTickFrequency(); +@endcode +@sa getTickCount, TickMeter + */ +CV_EXPORTS_W double getTickFrequency(); + +/** @brief a Class to measure passing time. + +The class computes passing time by counting the number of ticks per second. That is, the following code computes the +execution time in seconds: +@snippet snippets/core_various.cpp TickMeter_total + +It is also possible to compute the average time over multiple runs: +@snippet snippets/core_various.cpp TickMeter_average + +@sa getTickCount, getTickFrequency +*/ +class CV_EXPORTS_W TickMeter +{ +public: + //! the default constructor + CV_WRAP TickMeter() + { + reset(); + } + + //! starts counting ticks. + CV_WRAP void start() + { + startTime = cv::getTickCount(); + } + + //! stops counting ticks. + CV_WRAP void stop() + { + int64 time = cv::getTickCount(); + if (startTime == 0) + return; + ++counter; + sumTime += (time - startTime); + startTime = 0; + } + + //! returns counted ticks. + CV_WRAP int64 getTimeTicks() const + { + return sumTime; + } + + //! returns passed time in microseconds. + CV_WRAP double getTimeMicro() const + { + return getTimeMilli()*1e3; + } + + //! returns passed time in milliseconds. + CV_WRAP double getTimeMilli() const + { + return getTimeSec()*1e3; + } + + //! returns passed time in seconds. + CV_WRAP double getTimeSec() const + { + return (double)getTimeTicks() / getTickFrequency(); + } + + //! returns internal counter value. + CV_WRAP int64 getCounter() const + { + return counter; + } + + //! returns average FPS (frames per second) value. + CV_WRAP double getFPS() const + { + const double sec = getTimeSec(); + if (sec < DBL_EPSILON) + return 0.; + return counter / sec; + } + + //! returns average time in seconds + CV_WRAP double getAvgTimeSec() const + { + if (counter <= 0) + return 0.; + return getTimeSec() / counter; + } + + //! returns average time in milliseconds + CV_WRAP double getAvgTimeMilli() const + { + return getAvgTimeSec() * 1e3; + } + + //! resets internal values. + CV_WRAP void reset() + { + startTime = 0; + sumTime = 0; + counter = 0; + } + +private: + int64 counter; + int64 sumTime; + int64 startTime; +}; + +/** @brief output operator +@code +TickMeter tm; +tm.start(); +// do something ... +tm.stop(); +std::cout << tm; +@endcode +*/ + +static inline +std::ostream& operator << (std::ostream& out, const TickMeter& tm) +{ + return out << tm.getTimeSec() << "sec"; +} + +/** @brief Returns the number of CPU ticks. + +The function returns the current number of CPU ticks on some architectures (such as x86, x64, +PowerPC). On other platforms the function is equivalent to getTickCount. It can also be used for +very accurate time measurements, as well as for RNG initialization. Note that in case of multi-CPU +systems a thread, from which getCPUTickCount is called, can be suspended and resumed at another CPU +with its own counter. So, theoretically (and practically) the subsequent calls to the function do +not necessary return the monotonously increasing values. Also, since a modern CPU varies the CPU +frequency depending on the load, the number of CPU clocks spent in some code cannot be directly +converted to time units. Therefore, getTickCount is generally a preferable solution for measuring +execution time. + */ +CV_EXPORTS_W int64 getCPUTickCount(); + +/** @brief Returns true if the specified feature is supported by the host hardware. + +The function returns true if the host hardware supports the specified feature. When user calls +setUseOptimized(false), the subsequent calls to checkHardwareSupport() will return false until +setUseOptimized(true) is called. This way user can dynamically switch on and off the optimized code +in OpenCV. +@param feature The feature of interest, one of cv::CpuFeatures + */ +CV_EXPORTS_W bool checkHardwareSupport(int feature); + +/** @brief Returns feature name by ID + +Returns empty string if feature is not defined +*/ +CV_EXPORTS_W String getHardwareFeatureName(int feature); + +/** @brief Returns list of CPU features enabled during compilation. + +Returned value is a string containing space separated list of CPU features with following markers: + +- no markers - baseline features +- prefix `*` - features enabled in dispatcher +- suffix `?` - features enabled but not available in HW + +Example: `SSE SSE2 SSE3 *SSE4.1 *SSE4.2 *FP16 *AVX *AVX2 *AVX512-SKX?` +*/ +CV_EXPORTS_W std::string getCPUFeaturesLine(); + +/** @brief Returns the number of logical CPUs available for the process. + */ +CV_EXPORTS_W int getNumberOfCPUs(); + + +/** @brief Aligns a pointer to the specified number of bytes. + +The function returns the aligned pointer of the same type as the input pointer: +\f[\texttt{(_Tp*)(((size_t)ptr + n-1) & -n)}\f] +@param ptr Aligned pointer. +@param n Alignment size that must be a power of two. + */ +template static inline _Tp* alignPtr(_Tp* ptr, int n=(int)sizeof(_Tp)) +{ + CV_DbgAssert((n & (n - 1)) == 0); // n is a power of 2 + return (_Tp*)(((size_t)ptr + n-1) & -n); +} + +/** @brief Aligns a buffer size to the specified number of bytes. + +The function returns the minimum number that is greater than or equal to sz and is divisible by n : +\f[\texttt{(sz + n-1) & -n}\f] +@param sz Buffer size to align. +@param n Alignment size that must be a power of two. + */ +static inline size_t alignSize(size_t sz, int n) +{ + CV_DbgAssert((n & (n - 1)) == 0); // n is a power of 2 + return (sz + n-1) & -n; +} + +/** @brief Integer division with result round up. + +Use this function instead of `ceil((float)a / b)` expressions. + +@sa alignSize +*/ +static inline int divUp(int a, unsigned int b) +{ + CV_DbgAssert(a >= 0); + return (a + b - 1) / b; +} +/** @overload */ +static inline size_t divUp(size_t a, unsigned int b) +{ + return (a + b - 1) / b; +} + +/** @brief Round first value up to the nearest multiple of second value. + +Use this function instead of `ceil((float)a / b) * b` expressions. + +@sa divUp +*/ +static inline int roundUp(int a, unsigned int b) +{ + CV_DbgAssert(a >= 0); + return a + b - 1 - (a + b -1) % b; +} +/** @overload */ +static inline size_t roundUp(size_t a, unsigned int b) +{ + return a + b - 1 - (a + b - 1) % b; +} + +/** @brief Alignment check of passed values + +Usage: `isAligned(...)` + +@note Alignment(N) must be a power of 2 (2**k, 2^k) +*/ +template static inline +bool isAligned(const T& data) +{ + CV_StaticAssert((N & (N - 1)) == 0, ""); // power of 2 + return (((size_t)data) & (N - 1)) == 0; +} +/** @overload */ +template static inline +bool isAligned(const void* p1) +{ + return isAligned((size_t)p1); +} +/** @overload */ +template static inline +bool isAligned(const void* p1, const void* p2) +{ + return isAligned(((size_t)p1)|((size_t)p2)); +} +/** @overload */ +template static inline +bool isAligned(const void* p1, const void* p2, const void* p3) +{ + return isAligned(((size_t)p1)|((size_t)p2)|((size_t)p3)); +} +/** @overload */ +template static inline +bool isAligned(const void* p1, const void* p2, const void* p3, const void* p4) +{ + return isAligned(((size_t)p1)|((size_t)p2)|((size_t)p3)|((size_t)p4)); +} + +/** @brief Enables or disables the optimized code. + +The function can be used to dynamically turn on and off optimized dispatched code (code that uses SSE4.2, AVX/AVX2, +and other instructions on the platforms that support it). It sets a global flag that is further +checked by OpenCV functions. Since the flag is not checked in the inner OpenCV loops, it is only +safe to call the function on the very top level in your application where you can be sure that no +other OpenCV function is currently executed. + +By default, the optimized code is enabled unless you disable it in CMake. The current status can be +retrieved using useOptimized. +@param onoff The boolean flag specifying whether the optimized code should be used (onoff=true) +or not (onoff=false). + */ +CV_EXPORTS_W void setUseOptimized(bool onoff); + +/** @brief Returns the status of optimized code usage. + +The function returns true if the optimized code is enabled. Otherwise, it returns false. + */ +CV_EXPORTS_W bool useOptimized(); + +static inline size_t getElemSize(int type) { return (size_t)CV_ELEM_SIZE(type); } + +/////////////////////////////// Parallel Primitives ////////////////////////////////// + +/** @brief Base class for parallel data processors + +@ingroup core_parallel +*/ +class CV_EXPORTS ParallelLoopBody +{ +public: + virtual ~ParallelLoopBody(); + virtual void operator() (const Range& range) const = 0; +}; + +/** @brief Parallel data processor + +@ingroup core_parallel +*/ +CV_EXPORTS void parallel_for_(const Range& range, const ParallelLoopBody& body, double nstripes=-1.); + +//! @ingroup core_parallel +class ParallelLoopBodyLambdaWrapper : public ParallelLoopBody +{ +private: + std::function m_functor; +public: + inline + ParallelLoopBodyLambdaWrapper(std::function functor) + : m_functor(functor) + { + // nothing + } + + virtual void operator() (const cv::Range& range) const CV_OVERRIDE + { + m_functor(range); + } +}; + +//! @ingroup core_parallel +static inline +void parallel_for_(const Range& range, std::function functor, double nstripes=-1.) +{ + parallel_for_(range, ParallelLoopBodyLambdaWrapper(functor), nstripes); +} + + +/////////////////////////////// forEach method of cv::Mat //////////////////////////// +template inline +void Mat::forEach_impl(const Functor& operation) { + if (false) { + operation(*reinterpret_cast<_Tp*>(0), reinterpret_cast(0)); + // If your compiler fails in this line. + // Please check that your functor signature is + // (_Tp&, const int*) <- multi-dimensional + // or (_Tp&, void*) <- in case you don't need current idx. + } + + CV_Assert(!empty()); + CV_Assert(this->total() / this->size[this->dims - 1] <= INT_MAX); + const int LINES = static_cast(this->total() / this->size[this->dims - 1]); + + class PixelOperationWrapper :public ParallelLoopBody + { + public: + PixelOperationWrapper(Mat_<_Tp>* const frame, const Functor& _operation) + : mat(frame), op(_operation) {} + virtual ~PixelOperationWrapper(){} + // ! Overloaded virtual operator + // convert range call to row call. + virtual void operator()(const Range &range) const CV_OVERRIDE + { + const int DIMS = mat->dims; + const int COLS = mat->size[DIMS - 1]; + if (DIMS <= 2) { + for (int row = range.start; row < range.end; ++row) { + this->rowCall2(row, COLS); + } + } else { + std::vector idx(DIMS); /// idx is modified in this->rowCall + idx[DIMS - 2] = range.start - 1; + + for (int line_num = range.start; line_num < range.end; ++line_num) { + idx[DIMS - 2]++; + for (int i = DIMS - 2; i >= 0; --i) { + if (idx[i] >= mat->size[i]) { + idx[i - 1] += idx[i] / mat->size[i]; + idx[i] %= mat->size[i]; + continue; // carry-over; + } + else { + break; + } + } + this->rowCall(&idx[0], COLS, DIMS); + } + } + } + private: + Mat_<_Tp>* const mat; + const Functor op; + // ! Call operator for each elements in this row. + inline void rowCall(int* const idx, const int COLS, const int DIMS) const { + int &col = idx[DIMS - 1]; + col = 0; + _Tp* pixel = &(mat->template at<_Tp>(idx)); + + while (col < COLS) { + op(*pixel, const_cast(idx)); + pixel++; col++; + } + col = 0; + } + // ! Call operator for each elements in this row. 2d mat special version. + inline void rowCall2(const int row, const int COLS) const { + union Index{ + int body[2]; + operator const int*() const { + return reinterpret_cast(this); + } + int& operator[](const int i) { + return body[i]; + } + } idx = {{row, 0}}; + // Special union is needed to avoid + // "error: array subscript is above array bounds [-Werror=array-bounds]" + // when call the functor `op` such that access idx[3]. + + _Tp* pixel = &(mat->template at<_Tp>(idx)); + const _Tp* const pixel_end = pixel + COLS; + while(pixel < pixel_end) { + op(*pixel++, static_cast(idx)); + idx[1]++; + } + } + PixelOperationWrapper& operator=(const PixelOperationWrapper &) { + CV_Assert(false); + // We can not remove this implementation because Visual Studio warning C4822. + return *this; + } + }; + + parallel_for_(cv::Range(0, LINES), PixelOperationWrapper(reinterpret_cast*>(this), operation)); +} + +/////////////////////////// Synchronization Primitives /////////////////////////////// + +#if !defined(_M_CEE) +#ifndef OPENCV_DISABLE_THREAD_SUPPORT +typedef std::recursive_mutex Mutex; +typedef std::lock_guard AutoLock; +#else // OPENCV_DISABLE_THREAD_SUPPORT +// Custom (failing) implementation of `std::recursive_mutex`. +struct Mutex { + void lock(){ + CV_Error(cv::Error::StsNotImplemented, + "cv::Mutex is disabled by OPENCV_DISABLE_THREAD_SUPPORT=ON"); + } + void unlock(){ + CV_Error(cv::Error::StsNotImplemented, + "cv::Mutex is disabled by OPENCV_DISABLE_THREAD_SUPPORT=ON"); + } +}; +// Stub for cv::AutoLock when threads are disabled. +struct AutoLock { + AutoLock(Mutex &) { } +}; +#endif // OPENCV_DISABLE_THREAD_SUPPORT +#endif // !defined(_M_CEE) + + +/** @brief Designed for command line parsing + +The sample below demonstrates how to use CommandLineParser: +@code + CommandLineParser parser(argc, argv, keys); + parser.about("Application name v1.0.0"); + + if (parser.has("help")) + { + parser.printMessage(); + return 0; + } + + int N = parser.get("N"); + double fps = parser.get("fps"); + String path = parser.get("path"); + + use_time_stamp = parser.has("timestamp"); + + String img1 = parser.get(0); + String img2 = parser.get(1); + + int repeat = parser.get(2); + + if (!parser.check()) + { + parser.printErrors(); + return 0; + } +@endcode + +### Keys syntax + +The keys parameter is a string containing several blocks, each one is enclosed in curly braces and +describes one argument. Each argument contains three parts separated by the `|` symbol: + +-# argument names is a space-separated list of option synonyms (to mark argument as positional, prefix it with the `@` symbol) +-# default value will be used if the argument was not provided (can be empty) +-# help message (can be empty) + +For example: + +@code{.cpp} + const String keys = + "{help h usage ? | | print this message }" + "{@image1 | | image1 for compare }" + "{@image2 || image2 for compare }" + "{@repeat |1 | number }" + "{path |. | path to file }" + "{fps | -1.0 | fps for output video }" + "{N count |100 | count of objects }" + "{ts timestamp | | use time stamp }" + ; +} +@endcode + +Note that there are no default values for `help` and `timestamp` so we can check their presence using the `has()` method. +Arguments with default values are considered to be always present. Use the `get()` method in these cases to check their +actual value instead. + +String keys like `get("@image1")` return the empty string `""` by default - even with an empty default value. +Use the special `` default value to enforce that the returned string must not be empty. (like in `get("@image2")`) + +### Usage + +For the described keys: + +@code{.sh} + # Good call (3 positional parameters: image1, image2 and repeat; N is 200, ts is true) + $ ./app -N=200 1.png 2.jpg 19 -ts + + # Bad call + $ ./app -fps=aaa + ERRORS: + Parameter 'fps': can not convert: [aaa] to [double] +@endcode + */ +class CV_EXPORTS CommandLineParser +{ +public: + + /** @brief Constructor + + Initializes command line parser object + + @param argc number of command line arguments (from main()) + @param argv array of command line arguments (from main()) + @param keys string describing acceptable command line parameters (see class description for syntax) + */ + CommandLineParser(int argc, const char* const argv[], const String& keys); + + /** @brief Copy constructor */ + CommandLineParser(const CommandLineParser& parser); + + /** @brief Assignment operator */ + CommandLineParser& operator = (const CommandLineParser& parser); + + /** @brief Destructor */ + ~CommandLineParser(); + + /** @brief Returns application path + + This method returns the path to the executable from the command line (`argv[0]`). + + For example, if the application has been started with such a command: + @code{.sh} + $ ./bin/my-executable + @endcode + this method will return `./bin`. + */ + String getPathToApplication() const; + + /** @brief Access arguments by name + + Returns argument converted to selected type. If the argument is not known or can not be + converted to selected type, the error flag is set (can be checked with @ref check). + + For example, define: + @code{.cpp} + String keys = "{N count||}"; + @endcode + + Call: + @code{.sh} + $ ./my-app -N=20 + # or + $ ./my-app --count=20 + @endcode + + Access: + @code{.cpp} + int N = parser.get("N"); + @endcode + + @param name name of the argument + @param space_delete remove spaces from the left and right of the string + @tparam T the argument will be converted to this type if possible + + @note You can access positional arguments by their `@`-prefixed name: + @code{.cpp} + parser.get("@image"); + @endcode + */ + template + T get(const String& name, bool space_delete = true) const + { + T val = T(); + getByName(name, space_delete, ParamType::type, (void*)&val); + return val; + } + + /** @brief Access positional arguments by index + + Returns argument converted to selected type. Indexes are counted from zero. + + For example, define: + @code{.cpp} + String keys = "{@arg1||}{@arg2||}" + @endcode + + Call: + @code{.sh} + ./my-app abc qwe + @endcode + + Access arguments: + @code{.cpp} + String val_1 = parser.get(0); // returns "abc", arg1 + String val_2 = parser.get(1); // returns "qwe", arg2 + @endcode + + @param index index of the argument + @param space_delete remove spaces from the left and right of the string + @tparam T the argument will be converted to this type if possible + */ + template + T get(int index, bool space_delete = true) const + { + T val = T(); + getByIndex(index, space_delete, ParamType::type, (void*)&val); + return val; + } + + /** @brief Check if field was provided in the command line + + @param name argument name to check + */ + bool has(const String& name) const; + + /** @brief Check for parsing errors + + Returns false if error occurred while accessing the parameters (bad conversion, missing arguments, + etc.). Call @ref printErrors to print error messages list. + */ + bool check() const; + + /** @brief Set the about message + + The about message will be shown when @ref printMessage is called, right before arguments table. + */ + void about(const String& message); + + /** @brief Print help message + + This method will print standard help message containing the about message and arguments description. + + @sa about + */ + void printMessage() const; + + /** @brief Print list of errors occurred + + @sa check + */ + void printErrors() const; + +protected: + void getByName(const String& name, bool space_delete, Param type, void* dst) const; + void getByIndex(int index, bool space_delete, Param type, void* dst) const; + + struct Impl; + Impl* impl; +}; + +//! @} core_utils + +//! @cond IGNORED + +/////////////////////////////// AutoBuffer implementation //////////////////////////////////////// + +template inline +AutoBuffer<_Tp, fixed_size>::AutoBuffer() +{ + ptr = buf; + sz = fixed_size; +} + +template inline +AutoBuffer<_Tp, fixed_size>::AutoBuffer(size_t _size) +{ + ptr = buf; + sz = fixed_size; + allocate(_size); +} + +template inline +AutoBuffer<_Tp, fixed_size>::AutoBuffer(const AutoBuffer<_Tp, fixed_size>& abuf ) +{ + ptr = buf; + sz = fixed_size; + allocate(abuf.size()); + for( size_t i = 0; i < sz; i++ ) + ptr[i] = abuf.ptr[i]; +} + +template inline AutoBuffer<_Tp, fixed_size>& +AutoBuffer<_Tp, fixed_size>::operator = (const AutoBuffer<_Tp, fixed_size>& abuf) +{ + if( this != &abuf ) + { + deallocate(); + allocate(abuf.size()); + for( size_t i = 0; i < sz; i++ ) + ptr[i] = abuf.ptr[i]; + } + return *this; +} + +template inline +AutoBuffer<_Tp, fixed_size>::~AutoBuffer() +{ deallocate(); } + +template inline void +AutoBuffer<_Tp, fixed_size>::allocate(size_t _size) +{ + if(_size <= sz) + { + sz = _size; + return; + } + deallocate(); + sz = _size; + if(_size > fixed_size) + { + ptr = new _Tp[_size]; + } +} + +template inline void +AutoBuffer<_Tp, fixed_size>::deallocate() +{ + if( ptr != buf ) + { + delete[] ptr; + ptr = buf; + sz = fixed_size; + } +} + +template inline void +AutoBuffer<_Tp, fixed_size>::resize(size_t _size) +{ + if(_size <= sz) + { + sz = _size; + return; + } + size_t i, prevsize = sz, minsize = MIN(prevsize, _size); + _Tp* prevptr = ptr; + + ptr = _size > fixed_size ? new _Tp[_size] : buf; + sz = _size; + + if( ptr != prevptr ) + for( i = 0; i < minsize; i++ ) + ptr[i] = prevptr[i]; + for( i = prevsize; i < _size; i++ ) + ptr[i] = _Tp(); + + if( prevptr != buf ) + delete[] prevptr; +} + +template inline size_t +AutoBuffer<_Tp, fixed_size>::size() const +{ return sz; } + +//! @endcond + + +// Basic Node class for tree building +template +class CV_EXPORTS Node +{ +public: + Node() + { + m_pParent = 0; + } + Node(OBJECT& payload) : m_payload(payload) + { + m_pParent = 0; + } + ~Node() + { + removeChilds(); + if (m_pParent) + { + int idx = m_pParent->findChild(this); + if (idx >= 0) + m_pParent->m_childs.erase(m_pParent->m_childs.begin() + idx); + } + } + + Node* findChild(OBJECT& payload) const + { + for(size_t i = 0; i < this->m_childs.size(); i++) + { + if(this->m_childs[i]->m_payload == payload) + return this->m_childs[i]; + } + return NULL; + } + + int findChild(Node *pNode) const + { + for (size_t i = 0; i < this->m_childs.size(); i++) + { + if(this->m_childs[i] == pNode) + return (int)i; + } + return -1; + } + + void addChild(Node *pNode) + { + if(!pNode) + return; + + CV_Assert(pNode->m_pParent == 0); + pNode->m_pParent = this; + this->m_childs.push_back(pNode); + } + + void removeChilds() + { + for(size_t i = 0; i < m_childs.size(); i++) + { + m_childs[i]->m_pParent = 0; // avoid excessive parent vector trimming + delete m_childs[i]; + } + m_childs.clear(); + } + + int getDepth() + { + int count = 0; + Node *pParent = m_pParent; + while(pParent) count++, pParent = pParent->m_pParent; + return count; + } + +public: + OBJECT m_payload; + Node* m_pParent; + std::vector*> m_childs; +}; + + +namespace samples { + +//! @addtogroup core_utils_samples +// This section describes utility functions for OpenCV samples. +// +// @note Implementation of these utilities is not thread-safe. +// +//! @{ + +/** @brief Try to find requested data file + +Search directories: + +1. Directories passed via `addSamplesDataSearchPath()` +2. OPENCV_SAMPLES_DATA_PATH_HINT environment variable +3. OPENCV_SAMPLES_DATA_PATH environment variable + If parameter value is not empty and nothing is found then stop searching. +4. Detects build/install path based on: + a. current working directory (CWD) + b. and/or binary module location (opencv_core/opencv_world, doesn't work with static linkage) +5. Scan `/{,data,samples/data}` directories if build directory is detected or the current directory is in source tree. +6. Scan `/share/OpenCV` directory if install directory is detected. + +@see cv::utils::findDataFile + +@param relative_path Relative path to data file +@param required Specify "file not found" handling. + If true, function prints information message and raises cv::Exception. + If false, function returns empty result +@param silentMode Disables messages +@return Returns path (absolute or relative to the current directory) or empty string if file is not found +*/ +CV_EXPORTS_W cv::String findFile(const cv::String& relative_path, bool required = true, bool silentMode = false); + +CV_EXPORTS_W cv::String findFileOrKeep(const cv::String& relative_path, bool silentMode = false); + +inline cv::String findFileOrKeep(const cv::String& relative_path, bool silentMode) +{ + cv::String res = findFile(relative_path, false, silentMode); + if (res.empty()) + return relative_path; + return res; +} + +/** @brief Override search data path by adding new search location + +Use this only to override default behavior +Passed paths are used in LIFO order. + +@param path Path to used samples data +*/ +CV_EXPORTS_W void addSamplesDataSearchPath(const cv::String& path); + +/** @brief Append samples search data sub directory + +General usage is to add OpenCV modules name (`/modules//samples/data` -> `/samples/data` + `modules//samples/data`). +Passed subdirectories are used in LIFO order. + +@param subdir samples data sub directory +*/ +CV_EXPORTS_W void addSamplesDataSearchSubDirectory(const cv::String& subdir); + +//! @} +} // namespace samples + +namespace utils { + +CV_EXPORTS int getThreadID(); + +} // namespace + +} //namespace cv + +#ifdef CV_COLLECT_IMPL_DATA +#include "opencv2/core/utils/instrumentation.hpp" +#else +/// Collect implementation data on OpenCV function call. Requires ENABLE_IMPL_COLLECTION build option. +#define CV_IMPL_ADD(impl) +#endif + +#endif //OPENCV_CORE_UTILITY_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/allocator_stats.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/allocator_stats.hpp new file mode 100644 index 0000000..79e9338 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/allocator_stats.hpp @@ -0,0 +1,29 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_ALLOCATOR_STATS_HPP +#define OPENCV_CORE_ALLOCATOR_STATS_HPP + +#include "../cvdef.h" + +namespace cv { namespace utils { + +class AllocatorStatisticsInterface +{ +protected: + AllocatorStatisticsInterface() {} + virtual ~AllocatorStatisticsInterface() {} +public: + virtual uint64_t getCurrentUsage() const = 0; + virtual uint64_t getTotalUsage() const = 0; + virtual uint64_t getNumberOfAllocations() const = 0; + virtual uint64_t getPeakUsage() const = 0; + + /** set peak usage = current usage */ + virtual void resetPeakUsage() = 0; +}; + +}} // namespace + +#endif // OPENCV_CORE_ALLOCATOR_STATS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/allocator_stats.impl.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/allocator_stats.impl.hpp new file mode 100644 index 0000000..eb5ecde --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/allocator_stats.impl.hpp @@ -0,0 +1,158 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_ALLOCATOR_STATS_IMPL_HPP +#define OPENCV_CORE_ALLOCATOR_STATS_IMPL_HPP + +#include "./allocator_stats.hpp" + +//#define OPENCV_DISABLE_ALLOCATOR_STATS + +#ifdef CV_CXX11 + +#include + +#ifndef OPENCV_ALLOCATOR_STATS_COUNTER_TYPE +#if defined(__GNUC__) && (\ + (defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 4) || \ + (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)) \ + ) +#define OPENCV_ALLOCATOR_STATS_COUNTER_TYPE int +#endif +#endif + +#ifndef OPENCV_ALLOCATOR_STATS_COUNTER_TYPE +#define OPENCV_ALLOCATOR_STATS_COUNTER_TYPE long long +#endif + +#else // CV_CXX11 + +#ifndef OPENCV_ALLOCATOR_STATS_COUNTER_TYPE +#define OPENCV_ALLOCATOR_STATS_COUNTER_TYPE int // CV_XADD supports int only +#endif + +#endif // CV_CXX11 + +namespace cv { namespace utils { + +#ifdef CV__ALLOCATOR_STATS_LOG +namespace { +#endif + +class AllocatorStatistics : public AllocatorStatisticsInterface +{ +#ifdef OPENCV_DISABLE_ALLOCATOR_STATS + +public: + AllocatorStatistics() {} + ~AllocatorStatistics() CV_OVERRIDE {} + + uint64_t getCurrentUsage() const CV_OVERRIDE { return 0; } + uint64_t getTotalUsage() const CV_OVERRIDE { return 0; } + uint64_t getNumberOfAllocations() const CV_OVERRIDE { return 0; } + uint64_t getPeakUsage() const CV_OVERRIDE { return 0; } + + /** set peak usage = current usage */ + void resetPeakUsage() CV_OVERRIDE {}; + + void onAllocate(size_t /*sz*/) {} + void onFree(size_t /*sz*/) {} + +#elif defined(CV_CXX11) + +protected: + typedef OPENCV_ALLOCATOR_STATS_COUNTER_TYPE counter_t; + std::atomic curr, total, total_allocs, peak; +public: + AllocatorStatistics() {} + ~AllocatorStatistics() CV_OVERRIDE {} + + uint64_t getCurrentUsage() const CV_OVERRIDE { return (uint64_t)curr.load(); } + uint64_t getTotalUsage() const CV_OVERRIDE { return (uint64_t)total.load(); } + uint64_t getNumberOfAllocations() const CV_OVERRIDE { return (uint64_t)total_allocs.load(); } + uint64_t getPeakUsage() const CV_OVERRIDE { return (uint64_t)peak.load(); } + + /** set peak usage = current usage */ + void resetPeakUsage() CV_OVERRIDE { peak.store(curr.load()); } + + // Controller interface + void onAllocate(size_t sz) + { +#ifdef CV__ALLOCATOR_STATS_LOG + CV__ALLOCATOR_STATS_LOG(cv::format("allocate: %lld (curr=%lld)", (long long int)sz, (long long int)curr.load())); +#endif + + counter_t new_curr = curr.fetch_add((counter_t)sz) + (counter_t)sz; + + // peak = std::max((uint64_t)peak, new_curr); + auto prev_peak = peak.load(); + while (prev_peak < new_curr) + { + if (peak.compare_exchange_weak(prev_peak, new_curr)) + break; + } + // end of peak = max(...) + + total += (counter_t)sz; + total_allocs++; + } + void onFree(size_t sz) + { +#ifdef CV__ALLOCATOR_STATS_LOG + CV__ALLOCATOR_STATS_LOG(cv::format("free: %lld (curr=%lld)", (long long int)sz, (long long int)curr.load())); +#endif + curr -= (counter_t)sz; + } + +#else // non C++11 + +protected: + typedef OPENCV_ALLOCATOR_STATS_COUNTER_TYPE counter_t; + volatile counter_t curr, total, total_allocs, peak; // overflow is possible, CV_XADD operates with 'int' only +public: + AllocatorStatistics() + : curr(0), total(0), total_allocs(0), peak(0) + {} + ~AllocatorStatistics() CV_OVERRIDE {} + + uint64_t getCurrentUsage() const CV_OVERRIDE { return (uint64_t)curr; } + uint64_t getTotalUsage() const CV_OVERRIDE { return (uint64_t)total; } + uint64_t getNumberOfAllocations() const CV_OVERRIDE { return (uint64_t)total_allocs; } + uint64_t getPeakUsage() const CV_OVERRIDE { return (uint64_t)peak; } + + void resetPeakUsage() CV_OVERRIDE { peak = curr; } + + // Controller interface + void onAllocate(size_t sz) + { +#ifdef CV__ALLOCATOR_STATS_LOG + CV__ALLOCATOR_STATS_LOG(cv::format("allocate: %lld (curr=%lld)", (long long int)sz, (long long int)curr)); +#endif + + counter_t new_curr = (counter_t)CV_XADD(&curr, (counter_t)sz) + (counter_t)sz; + + peak = std::max((counter_t)peak, new_curr); // non-thread safe + + //CV_XADD(&total, (uint64_t)sz); // overflow with int, non-reliable... + total += sz; + + CV_XADD(&total_allocs, (counter_t)1); + } + void onFree(size_t sz) + { +#ifdef CV__ALLOCATOR_STATS_LOG + CV__ALLOCATOR_STATS_LOG(cv::format("free: %lld (curr=%lld)", (long long int)sz, (long long int)curr)); +#endif + CV_XADD(&curr, (counter_t)-sz); + } +#endif +}; + +#ifdef CV__ALLOCATOR_STATS_LOG +} // namespace +#endif + +}} // namespace + +#endif // OPENCV_CORE_ALLOCATOR_STATS_IMPL_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/filesystem.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/filesystem.hpp new file mode 100644 index 0000000..a98d220 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/filesystem.hpp @@ -0,0 +1,82 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_UTILS_FILESYSTEM_HPP +#define OPENCV_UTILS_FILESYSTEM_HPP + +namespace cv { namespace utils { namespace fs { + + +CV_EXPORTS bool exists(const cv::String& path); +CV_EXPORTS bool isDirectory(const cv::String& path); + +CV_EXPORTS void remove_all(const cv::String& path); + + +CV_EXPORTS cv::String getcwd(); + +/** @brief Converts path p to a canonical absolute path + * Symlinks are processed if there is support for them on running platform. + * + * @param path input path. Target file/directory should exist. + */ +CV_EXPORTS cv::String canonical(const cv::String& path); + +/** Join path components */ +CV_EXPORTS cv::String join(const cv::String& base, const cv::String& path); + +/** Get parent directory */ +CV_EXPORTS cv::String getParent(const cv::String &path); +CV_EXPORTS std::wstring getParent(const std::wstring& path); + +/** + * Generate a list of all files that match the globbing pattern. + * + * Result entries are prefixed by base directory path. + * + * @param directory base directory + * @param pattern filter pattern (based on '*'/'?' symbols). Use empty string to disable filtering and return all results + * @param[out] result result of globing. + * @param recursive scan nested directories too + * @param includeDirectories include directories into results list + */ +CV_EXPORTS void glob(const cv::String& directory, const cv::String& pattern, + CV_OUT std::vector& result, + bool recursive = false, bool includeDirectories = false); + +/** + * Generate a list of all files that match the globbing pattern. + * + * @param directory base directory + * @param pattern filter pattern (based on '*'/'?' symbols). Use empty string to disable filtering and return all results + * @param[out] result globbing result with relative paths from base directory + * @param recursive scan nested directories too + * @param includeDirectories include directories into results list + */ +CV_EXPORTS void glob_relative(const cv::String& directory, const cv::String& pattern, + CV_OUT std::vector& result, + bool recursive = false, bool includeDirectories = false); + + +CV_EXPORTS bool createDirectory(const cv::String& path); +CV_EXPORTS bool createDirectories(const cv::String& path); + +#ifdef __OPENCV_BUILD +// TODO +//CV_EXPORTS cv::String getTempDirectory(); + +/** + * @brief Returns directory to store OpenCV cache files + * Create sub-directory in common OpenCV cache directory if it doesn't exist. + * @param sub_directory_name name of sub-directory. NULL or "" value asks to return root cache directory. + * @param configuration_name optional name of configuration parameter name which overrides default behavior. + * @return Path to cache directory. Returns empty string if cache directories support is not available. Returns "disabled" if cache disabled by user. + */ +CV_EXPORTS cv::String getCacheDirectory(const char* sub_directory_name, const char* configuration_name = NULL); + +#endif + +}}} // namespace + +#endif // OPENCV_UTILS_FILESYSTEM_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/fp_control_utils.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/fp_control_utils.hpp new file mode 100644 index 0000000..930bc5d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/fp_control_utils.hpp @@ -0,0 +1,69 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_FP_CONTROL_UTILS_HPP +#define OPENCV_CORE_FP_CONTROL_UTILS_HPP + +namespace cv { + +namespace details { + +struct FPDenormalsModeState +{ + uint32_t reserved[16]; // 64-bytes +}; // FPDenormalsModeState + +CV_EXPORTS void setFPDenormalsIgnoreHint(bool ignore, CV_OUT FPDenormalsModeState& state); +CV_EXPORTS int saveFPDenormalsState(CV_OUT FPDenormalsModeState& state); +CV_EXPORTS bool restoreFPDenormalsState(const FPDenormalsModeState& state); + +class FPDenormalsIgnoreHintScope +{ +public: + inline explicit FPDenormalsIgnoreHintScope(bool ignore = true) + { + details::setFPDenormalsIgnoreHint(ignore, saved_state); + } + + inline explicit FPDenormalsIgnoreHintScope(const FPDenormalsModeState& state) + { + details::saveFPDenormalsState(saved_state); + details::restoreFPDenormalsState(state); + } + + inline ~FPDenormalsIgnoreHintScope() + { + details::restoreFPDenormalsState(saved_state); + } + +protected: + FPDenormalsModeState saved_state; +}; // FPDenormalsIgnoreHintScope + +class FPDenormalsIgnoreHintScopeNOOP +{ +public: + inline FPDenormalsIgnoreHintScopeNOOP(bool ignore = true) { CV_UNUSED(ignore); } + inline FPDenormalsIgnoreHintScopeNOOP(const FPDenormalsModeState& state) { CV_UNUSED(state); } + inline ~FPDenormalsIgnoreHintScopeNOOP() { } +}; // FPDenormalsIgnoreHintScopeNOOP + +} // namespace details + + +// Should depend on target compilation architecture only +// Note: previously added archs should NOT be removed to preserve ABI compatibility +#if defined(OPENCV_SUPPORTS_FP_DENORMALS_HINT) + // preserve configuration overloading through ports +#elif defined(__i386__) || defined(__x86_64__) || defined(_M_X64) || defined(_X86_) +typedef details::FPDenormalsIgnoreHintScope FPDenormalsIgnoreHintScope; +#define OPENCV_SUPPORTS_FP_DENORMALS_HINT 1 +#else +#define OPENCV_SUPPORTS_FP_DENORMALS_HINT 0 +typedef details::FPDenormalsIgnoreHintScopeNOOP FPDenormalsIgnoreHintScope; +#endif + +} // namespace cv + +#endif // OPENCV_CORE_FP_CONTROL_UTILS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/instrumentation.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/instrumentation.hpp new file mode 100644 index 0000000..3639867 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/instrumentation.hpp @@ -0,0 +1,125 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_UTILS_INSTR_HPP +#define OPENCV_UTILS_INSTR_HPP + +#include +#include + +namespace cv { + +//! @addtogroup core_utils +//! @{ + +#ifdef CV_COLLECT_IMPL_DATA +CV_EXPORTS void setImpl(int flags); // set implementation flags and reset storage arrays +CV_EXPORTS void addImpl(int flag, const char* func = 0); // add implementation and function name to storage arrays +// Get stored implementation flags and functions names arrays +// Each implementation entry correspond to function name entry, so you can find which implementation was executed in which function +CV_EXPORTS int getImpl(std::vector &impl, std::vector &funName); + +CV_EXPORTS bool useCollection(); // return implementation collection state +CV_EXPORTS void setUseCollection(bool flag); // set implementation collection state + +#define CV_IMPL_PLAIN 0x01 // native CPU OpenCV implementation +#define CV_IMPL_OCL 0x02 // OpenCL implementation +#define CV_IMPL_IPP 0x04 // IPP implementation +#define CV_IMPL_MT 0x10 // multithreaded implementation + +#undef CV_IMPL_ADD +#define CV_IMPL_ADD(impl) \ + if(cv::useCollection()) \ + { \ + cv::addImpl(impl, CV_Func); \ + } +#endif + +// Instrumentation external interface +namespace instr +{ + +#if !defined OPENCV_ABI_CHECK + +enum TYPE +{ + TYPE_GENERAL = 0, // OpenCV API function, e.g. exported function + TYPE_MARKER, // Information marker + TYPE_WRAPPER, // Wrapper function for implementation + TYPE_FUN, // Simple function call +}; + +enum IMPL +{ + IMPL_PLAIN = 0, + IMPL_IPP, + IMPL_OPENCL, +}; + +struct NodeDataTls +{ + NodeDataTls() + { + m_ticksTotal = 0; + } + uint64 m_ticksTotal; +}; + +class CV_EXPORTS NodeData +{ +public: + NodeData(const char* funName = 0, const char* fileName = NULL, int lineNum = 0, void* retAddress = NULL, bool alwaysExpand = false, cv::instr::TYPE instrType = TYPE_GENERAL, cv::instr::IMPL implType = IMPL_PLAIN); + NodeData(NodeData &ref); + ~NodeData(); + NodeData& operator=(const NodeData&); + + cv::String m_funName; + cv::instr::TYPE m_instrType; + cv::instr::IMPL m_implType; + const char* m_fileName; + int m_lineNum; + void* m_retAddress; + bool m_alwaysExpand; + bool m_funError; + + volatile int m_counter; + volatile uint64 m_ticksTotal; + TLSDataAccumulator m_tls; + int m_threads; + + // No synchronization + double getTotalMs() const { return ((double)m_ticksTotal / cv::getTickFrequency()) * 1000; } + double getMeanMs() const { return (((double)m_ticksTotal/m_counter) / cv::getTickFrequency()) * 1000; } +}; +bool operator==(const NodeData& lhs, const NodeData& rhs); + +typedef Node InstrNode; + +CV_EXPORTS InstrNode* getTrace(); + +#endif // !defined OPENCV_ABI_CHECK + + +CV_EXPORTS bool useInstrumentation(); +CV_EXPORTS void setUseInstrumentation(bool flag); +CV_EXPORTS void resetTrace(); + +enum FLAGS +{ + FLAGS_NONE = 0, + FLAGS_MAPPING = 0x01, + FLAGS_EXPAND_SAME_NAMES = 0x02, +}; + +CV_EXPORTS void setFlags(FLAGS modeFlags); +static inline void setFlags(int modeFlags) { setFlags((FLAGS)modeFlags); } +CV_EXPORTS FLAGS getFlags(); + +} // namespace instr + +//! @} + +} // namespace + +#endif // OPENCV_UTILS_TLS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/logger.defines.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/logger.defines.hpp new file mode 100644 index 0000000..7d73f02 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/logger.defines.hpp @@ -0,0 +1,42 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_LOGGER_DEFINES_HPP +#define OPENCV_LOGGER_DEFINES_HPP + +//! @addtogroup core_logging +//! @{ + +// Supported logging levels and their semantic +#define CV_LOG_LEVEL_SILENT 0 //!< for using in setLogLevel() call +#define CV_LOG_LEVEL_FATAL 1 //!< Fatal (critical) error (unrecoverable internal error) +#define CV_LOG_LEVEL_ERROR 2 //!< Error message +#define CV_LOG_LEVEL_WARN 3 //!< Warning message +#define CV_LOG_LEVEL_INFO 4 //!< Info message +#define CV_LOG_LEVEL_DEBUG 5 //!< Debug message. Disabled in the "Release" build. +#define CV_LOG_LEVEL_VERBOSE 6 //!< Verbose (trace) messages. Requires verbosity level. Disabled in the "Release" build. + +namespace cv { +namespace utils { +namespace logging { + +//! Supported logging levels and their semantic +enum LogLevel { + LOG_LEVEL_SILENT = 0, //!< for using in setLogVevel() call + LOG_LEVEL_FATAL = 1, //!< Fatal (critical) error (unrecoverable internal error) + LOG_LEVEL_ERROR = 2, //!< Error message + LOG_LEVEL_WARNING = 3, //!< Warning message + LOG_LEVEL_INFO = 4, //!< Info message + LOG_LEVEL_DEBUG = 5, //!< Debug message. Disabled in the "Release" build. + LOG_LEVEL_VERBOSE = 6, //!< Verbose (trace) messages. Requires verbosity level. Disabled in the "Release" build. +#ifndef CV_DOXYGEN + ENUM_LOG_LEVEL_FORCE_INT = INT_MAX +#endif +}; + +}}} // namespace + +//! @} + +#endif // OPENCV_LOGGER_DEFINES_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/logger.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/logger.hpp new file mode 100644 index 0000000..accb860 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/logger.hpp @@ -0,0 +1,218 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_LOGGER_HPP +#define OPENCV_LOGGER_HPP + +#include +#include +#include // INT_MAX + +#include "logger.defines.hpp" +#include "logtag.hpp" + +namespace cv { +namespace utils { +namespace logging { + +//! @addtogroup core_logging +//! @{ + +/** Set global logging level +@return previous logging level +*/ +CV_EXPORTS LogLevel setLogLevel(LogLevel logLevel); +/** Get global logging level */ +CV_EXPORTS LogLevel getLogLevel(); + +CV_EXPORTS void registerLogTag(cv::utils::logging::LogTag* plogtag); + +CV_EXPORTS void setLogTagLevel(const char* tag, cv::utils::logging::LogLevel level); + +CV_EXPORTS cv::utils::logging::LogLevel getLogTagLevel(const char* tag); + +namespace internal { + +/** Get global log tag */ +CV_EXPORTS cv::utils::logging::LogTag* getGlobalLogTag(); + +/** Write log message */ +CV_EXPORTS void writeLogMessage(LogLevel logLevel, const char* message); + +/** Write log message */ +CV_EXPORTS void writeLogMessageEx(LogLevel logLevel, const char* tag, const char* file, int line, const char* func, const char* message); + +} // namespace + +struct LogTagAuto + : public LogTag +{ + inline LogTagAuto(const char* _name, LogLevel _level) + : LogTag(_name, _level) + { + registerLogTag(this); + } +}; + +/** + * \def CV_LOG_STRIP_LEVEL + * + * Define CV_LOG_STRIP_LEVEL=CV_LOG_LEVEL_[DEBUG|INFO|WARN|ERROR|FATAL|SILENT] to compile out anything at that and before that logging level + */ +#ifndef CV_LOG_STRIP_LEVEL +# if defined NDEBUG +# define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_DEBUG +# else +# define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_VERBOSE +# endif +#endif + +#define CV_LOGTAG_PTR_CAST(expr) static_cast(expr) + +// CV_LOGTAG_EXPAND_NAME is intended to be re-defined (undef and then define again) +// to allows logging users to use a shorter name argument when calling +// CV_LOG_WITH_TAG or its related macros such as CV_LOG_INFO. +// +// This macro is intended to modify the tag argument as a string (token), via +// preprocessor token pasting or metaprogramming techniques. A typical usage +// is to apply a prefix, such as +// ...... #define CV_LOGTAG_EXPAND_NAME(tag) cv_logtag_##tag +// +// It is permitted to re-define to a hard-coded expression, ignoring the tag. +// This would work identically like the CV_LOGTAG_FALLBACK macro. +// +// Important: When the logging macro is called with tag being NULL, a user-defined +// CV_LOGTAG_EXPAND_NAME may expand it into cv_logtag_0, cv_logtag_NULL, or +// cv_logtag_nullptr. Use with care. Also be mindful of C++ symbol redefinitions. +// +// If there is significant amount of logging code with tag being NULL, it is +// recommended to use (re-define) CV_LOGTAG_FALLBACK to inject locally a default +// tag at the beginning of a compilation unit, to minimize lines of code changes. +// +#define CV_LOGTAG_EXPAND_NAME(tag) tag + +// CV_LOGTAG_FALLBACK is intended to be re-defined (undef and then define again) +// by any other compilation units to provide a log tag when the logging statement +// does not specify one. The macro needs to expand into a C++ expression that can +// be static_cast into (cv::utils::logging::LogTag*). Null (nullptr) is permitted. +#define CV_LOGTAG_FALLBACK nullptr + +// CV_LOGTAG_GLOBAL is the tag used when a log tag is not specified in the logging +// statement nor the compilation unit. The macro needs to expand into a C++ +// expression that can be static_cast into (cv::utils::logging::LogTag*). Must be +// non-null. Do not re-define. +#define CV_LOGTAG_GLOBAL cv::utils::logging::internal::getGlobalLogTag() + +#define CV_LOG_WITH_TAG(tag, msgLevel, extra_check0, extra_check1, ...) \ + for(;;) { \ + extra_check0; \ + const auto cv_temp_msglevel = (cv::utils::logging::LogLevel)(msgLevel); \ + if (cv_temp_msglevel >= (CV_LOG_STRIP_LEVEL)) break; \ + auto cv_temp_logtagptr = CV_LOGTAG_PTR_CAST(CV_LOGTAG_EXPAND_NAME(tag)); \ + if (!cv_temp_logtagptr) cv_temp_logtagptr = CV_LOGTAG_PTR_CAST(CV_LOGTAG_FALLBACK); \ + if (!cv_temp_logtagptr) cv_temp_logtagptr = CV_LOGTAG_PTR_CAST(CV_LOGTAG_GLOBAL); \ + if (cv_temp_logtagptr && (cv_temp_msglevel > cv_temp_logtagptr->level)) break; \ + extra_check1; \ + std::stringstream cv_temp_logstream; \ + cv_temp_logstream << __VA_ARGS__; \ + cv::utils::logging::internal::writeLogMessageEx( \ + cv_temp_msglevel, \ + (cv_temp_logtagptr ? cv_temp_logtagptr->name : nullptr), \ + __FILE__, \ + __LINE__, \ + CV_Func, \ + cv_temp_logstream.str().c_str()); \ + break; \ + } + +#define CV_LOG_FATAL(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_FATAL, , , __VA_ARGS__) +#define CV_LOG_ERROR(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_ERROR, , , __VA_ARGS__) +#define CV_LOG_WARNING(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_WARNING, , , __VA_ARGS__) +#define CV_LOG_INFO(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_INFO, , , __VA_ARGS__) +#define CV_LOG_DEBUG(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_DEBUG, , , __VA_ARGS__) +#define CV_LOG_VERBOSE(tag, v, ...) CV_LOG_WITH_TAG(tag, (cv::utils::logging::LOG_LEVEL_VERBOSE + (int)(v)), , , __VA_ARGS__) + +#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_INFO +#undef CV_LOG_INFO +#define CV_LOG_INFO(tag, ...) +#endif + +#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_DEBUG +#undef CV_LOG_DEBUG +#define CV_LOG_DEBUG(tag, ...) +#endif + +#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_VERBOSE +#undef CV_LOG_VERBOSE +#define CV_LOG_VERBOSE(tag, v, ...) +#endif + +//! @cond IGNORED +#define CV__LOG_ONCE_CHECK_PRE \ + static bool _cv_log_once_ ## __LINE__ = false; \ + if (_cv_log_once_ ## __LINE__) break; + +#define CV__LOG_ONCE_CHECK_POST \ + _cv_log_once_ ## __LINE__ = true; + +#define CV__LOG_IF_CHECK(logging_cond) \ + if (!(logging_cond)) break; + +//! @endcond + + +// CV_LOG_ONCE_XXX macros + +#define CV_LOG_ONCE_ERROR(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_ERROR, CV__LOG_ONCE_CHECK_PRE, CV__LOG_ONCE_CHECK_POST, __VA_ARGS__) +#define CV_LOG_ONCE_WARNING(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_WARNING, CV__LOG_ONCE_CHECK_PRE, CV__LOG_ONCE_CHECK_POST, __VA_ARGS__) +#define CV_LOG_ONCE_INFO(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_INFO, CV__LOG_ONCE_CHECK_PRE, CV__LOG_ONCE_CHECK_POST, __VA_ARGS__) +#define CV_LOG_ONCE_DEBUG(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_DEBUG, CV__LOG_ONCE_CHECK_PRE, CV__LOG_ONCE_CHECK_POST, __VA_ARGS__) +#define CV_LOG_ONCE_VERBOSE(tag, v, ...) CV_LOG_WITH_TAG(tag, (cv::utils::logging::LOG_LEVEL_VERBOSE + (int)(v)), CV__LOG_ONCE_CHECK_PRE, CV__LOG_ONCE_CHECK_POST, __VA_ARGS__) + +#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_INFO +#undef CV_LOG_ONCE_INFO +#define CV_LOG_ONCE_INFO(tag, ...) +#endif + +#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_DEBUG +#undef CV_LOG_ONCE_DEBUG +#define CV_LOG_ONCE_DEBUG(tag, ...) +#endif + +#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_VERBOSE +#undef CV_LOG_ONCE_VERBOSE +#define CV_LOG_ONCE_VERBOSE(tag, v, ...) +#endif + + +// CV_LOG_IF_XXX macros + +#define CV_LOG_IF_FATAL(tag, logging_cond, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_FATAL, , CV__LOG_IF_CHECK(logging_cond), __VA_ARGS__) +#define CV_LOG_IF_ERROR(tag, logging_cond, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_ERROR, , CV__LOG_IF_CHECK(logging_cond), __VA_ARGS__) +#define CV_LOG_IF_WARNING(tag, logging_cond, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_WARNING, , CV__LOG_IF_CHECK(logging_cond), __VA_ARGS__) +#define CV_LOG_IF_INFO(tag, logging_cond, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_INFO, , CV__LOG_IF_CHECK(logging_cond), __VA_ARGS__) +#define CV_LOG_IF_DEBUG(tag, logging_cond, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_DEBUG, , CV__LOG_IF_CHECK(logging_cond), __VA_ARGS__) +#define CV_LOG_IF_VERBOSE(tag, v, logging_cond, ...) CV_LOG_WITH_TAG(tag, (cv::utils::logging::LOG_LEVEL_VERBOSE + (int)(v)), , CV__LOG_IF_CHECK(logging_cond), __VA_ARGS__) + +#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_INFO +#undef CV_LOG_IF_INFO +#define CV_LOG_IF_INFO(tag, logging_cond, ...) +#endif + +#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_DEBUG +#undef CV_LOG_IF_DEBUG +#define CV_LOG_IF_DEBUG(tag, logging_cond, ...) +#endif + +#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_VERBOSE +#undef CV_LOG_IF_VERBOSE +#define CV_LOG_IF_VERBOSE(tag, v, logging_cond, ...) +#endif + + +//! @} + +}}} // namespace + +#endif // OPENCV_LOGGER_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/logtag.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/logtag.hpp new file mode 100644 index 0000000..4089720 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/logtag.hpp @@ -0,0 +1,28 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_LOGTAG_HPP +#define OPENCV_CORE_LOGTAG_HPP + +#include "opencv2/core/cvstd.hpp" +#include "logger.defines.hpp" + +namespace cv { +namespace utils { +namespace logging { + +struct LogTag +{ + const char* name; + LogLevel level; + + inline LogTag(const char* _name, LogLevel _level) + : name(_name) + , level(_level) + {} +}; + +}}} + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/tls.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/tls.hpp new file mode 100644 index 0000000..124caeb --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/tls.hpp @@ -0,0 +1,235 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_UTILS_TLS_HPP +#define OPENCV_UTILS_TLS_HPP + +#ifndef OPENCV_CORE_UTILITY_H +#error "tls.hpp must be included after opencv2/core/utility.hpp or opencv2/core.hpp" +#endif + +namespace cv { + +//! @addtogroup core_utils +//! @{ + +namespace details { class TlsStorage; } + +/** TLS container base implementation + * + * Don't use directly. + * + * @sa TLSData, TLSDataAccumulator templates + */ +class CV_EXPORTS TLSDataContainer +{ +protected: + TLSDataContainer(); + virtual ~TLSDataContainer(); + + /// @deprecated use detachData() instead + void gatherData(std::vector &data) const; + /// get TLS data and detach all data from threads (similar to cleanup() call) + void detachData(std::vector& data); + + void* getData() const; + void release(); + +protected: + virtual void* createDataInstance() const = 0; + virtual void deleteDataInstance(void* pData) const = 0; + +private: + int key_; + + friend class cv::details::TlsStorage; // core/src/system.cpp + +public: + void cleanup(); //!< Release created TLS data container objects. It is similar to release() call, but it keeps TLS container valid. + +private: + // Disable copy/assign (noncopyable pattern) + TLSDataContainer(TLSDataContainer &) = delete; + TLSDataContainer& operator =(const TLSDataContainer &) = delete; +}; + + +/** @brief Simple TLS data class + * + * @sa TLSDataAccumulator + */ +template +class TLSData : protected TLSDataContainer +{ +public: + inline TLSData() {} + inline ~TLSData() { release(); } + + inline T* get() const { return (T*)getData(); } //!< Get data associated with key + inline T& getRef() const { T* ptr = (T*)getData(); CV_DbgAssert(ptr); return *ptr; } //!< Get data associated with key + + /// Release associated thread data + inline void cleanup() + { + TLSDataContainer::cleanup(); + } + +protected: + /// Wrapper to allocate data by template + virtual void* createDataInstance() const CV_OVERRIDE { return new T; } + /// Wrapper to release data by template + virtual void deleteDataInstance(void* pData) const CV_OVERRIDE { delete (T*)pData; } +}; + + +/// TLS data accumulator with gathering methods +template +class TLSDataAccumulator : public TLSData +{ + mutable cv::Mutex mutex; + mutable std::vector dataFromTerminatedThreads; + std::vector detachedData; + bool cleanupMode; +public: + TLSDataAccumulator() : cleanupMode(false) {} + ~TLSDataAccumulator() + { + release(); + } + + /** @brief Get data from all threads + * @deprecated replaced by detachData() + * + * Lifetime of vector data is valid until next detachData()/cleanup()/release() calls + * + * @param[out] data result buffer (should be empty) + */ + void gather(std::vector &data) const + { + CV_Assert(cleanupMode == false); // state is not valid + CV_Assert(data.empty()); + { + std::vector &dataVoid = reinterpret_cast&>(data); + TLSDataContainer::gatherData(dataVoid); + } + { + AutoLock lock(mutex); + data.reserve(data.size() + dataFromTerminatedThreads.size()); + for (typename std::vector::const_iterator i = dataFromTerminatedThreads.begin(); i != dataFromTerminatedThreads.end(); ++i) + { + data.push_back((T*)*i); + } + } + } + + /** @brief Get and detach data from all threads + * + * Call cleanupDetachedData() when returned vector is not needed anymore. + * + * @return Vector with associated data. Content is preserved (including lifetime of attached data pointers) until next detachData()/cleanupDetachedData()/cleanup()/release() calls + */ + std::vector& detachData() + { + CV_Assert(cleanupMode == false); // state is not valid + std::vector dataVoid; + { + TLSDataContainer::detachData(dataVoid); + } + { + AutoLock lock(mutex); + detachedData.reserve(dataVoid.size() + dataFromTerminatedThreads.size()); + for (typename std::vector::const_iterator i = dataFromTerminatedThreads.begin(); i != dataFromTerminatedThreads.end(); ++i) + { + detachedData.push_back((T*)*i); + } + dataFromTerminatedThreads.clear(); + for (typename std::vector::const_iterator i = dataVoid.begin(); i != dataVoid.end(); ++i) + { + detachedData.push_back((T*)(void*)*i); + } + } + dataVoid.clear(); + return detachedData; + } + + /// Release associated thread data returned by detachData() call + void cleanupDetachedData() + { + AutoLock lock(mutex); + cleanupMode = true; + _cleanupDetachedData(); + cleanupMode = false; + } + + /// Release associated thread data + void cleanup() + { + cleanupMode = true; + TLSDataContainer::cleanup(); + + AutoLock lock(mutex); + _cleanupDetachedData(); + _cleanupTerminatedData(); + cleanupMode = false; + } + + /// Release associated thread data and free TLS key + void release() + { + cleanupMode = true; + TLSDataContainer::release(); + { + AutoLock lock(mutex); + _cleanupDetachedData(); + _cleanupTerminatedData(); + } + } + +protected: + // synchronized + void _cleanupDetachedData() + { + for (typename std::vector::iterator i = detachedData.begin(); i != detachedData.end(); ++i) + { + deleteDataInstance((T*)*i); + } + detachedData.clear(); + } + + // synchronized + void _cleanupTerminatedData() + { + for (typename std::vector::iterator i = dataFromTerminatedThreads.begin(); i != dataFromTerminatedThreads.end(); ++i) + { + deleteDataInstance((T*)*i); + } + dataFromTerminatedThreads.clear(); + } + +protected: + virtual void* createDataInstance() const CV_OVERRIDE + { + // Note: we can collect all allocated data here, but this would require raced mutex locks + return new T; + } + virtual void deleteDataInstance(void* pData) const CV_OVERRIDE + { + if (cleanupMode) + { + delete (T*)pData; + } + else + { + AutoLock lock(mutex); + dataFromTerminatedThreads.push_back((T*)pData); + } + } +}; + + +//! @} + +} // namespace + +#endif // OPENCV_UTILS_TLS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/trace.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/trace.hpp new file mode 100644 index 0000000..ef5d35b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/utils/trace.hpp @@ -0,0 +1,252 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_TRACE_HPP +#define OPENCV_TRACE_HPP + +#include + +namespace cv { +namespace utils { +namespace trace { + +//! @addtogroup core_logging +//! @{ + +//! Macro to trace function +#define CV_TRACE_FUNCTION() + +#define CV_TRACE_FUNCTION_SKIP_NESTED() + +//! Trace code scope. +//! @note Dynamic names are not supported in this macro (on stack or heap). Use string literals here only, like "initialize". +#define CV_TRACE_REGION(name_as_static_string_literal) +//! mark completed of the current opened region and create new one +//! @note Dynamic names are not supported in this macro (on stack or heap). Use string literals here only, like "step1". +#define CV_TRACE_REGION_NEXT(name_as_static_string_literal) + +//! Macro to trace argument value +#define CV_TRACE_ARG(arg_id) + +//! Macro to trace argument value (expanded version) +#define CV_TRACE_ARG_VALUE(arg_id, arg_name, value) + +//! @cond IGNORED +#define CV_TRACE_NS cv::utils::trace + +#if !defined(OPENCV_DISABLE_TRACE) && defined(__EMSCRIPTEN__) +#define OPENCV_DISABLE_TRACE 1 +#endif + +namespace details { + +#ifndef __OPENCV_TRACE +# if defined __OPENCV_BUILD && !defined __OPENCV_TESTS && !defined __OPENCV_APPS +# define __OPENCV_TRACE 1 +# else +# define __OPENCV_TRACE 0 +# endif +#endif + +#ifndef CV_TRACE_FILENAME +# define CV_TRACE_FILENAME __FILE__ +#endif + +#ifndef CV__TRACE_FUNCTION +# if defined _MSC_VER +# define CV__TRACE_FUNCTION __FUNCSIG__ +# elif defined __GNUC__ +# define CV__TRACE_FUNCTION __PRETTY_FUNCTION__ +# else +# define CV__TRACE_FUNCTION "" +# endif +#endif + +//! Thread-local instance (usually allocated on stack) +class CV_EXPORTS Region +{ +public: + struct LocationExtraData; + struct LocationStaticStorage + { + LocationExtraData** ppExtra; //< implementation specific data + const char* name; //< region name (function name or other custom name) + const char* filename; //< source code filename + int line; //< source code line + int flags; //< flags (implementation code path: Plain, IPP, OpenCL) + }; + + Region(const LocationStaticStorage& location); + inline ~Region() + { + if (implFlags != 0) + destroy(); + CV_DbgAssert(implFlags == 0); + CV_DbgAssert(pImpl == NULL); + } + + class Impl; + Impl* pImpl; // NULL if current region is not active + int implFlags; // see RegionFlag, 0 if region is ignored + + bool isActive() const { return pImpl != NULL; } + + void destroy(); +private: + Region(const Region&); // disabled + Region& operator= (const Region&); // disabled +}; + +//! Specify region flags +enum RegionLocationFlag { + REGION_FLAG_FUNCTION = (1 << 0), //< region is function (=1) / nested named region (=0) + REGION_FLAG_APP_CODE = (1 << 1), //< region is Application code (=1) / OpenCV library code (=0) + REGION_FLAG_SKIP_NESTED = (1 << 2), //< avoid processing of nested regions + + REGION_FLAG_IMPL_IPP = (1 << 16), //< region is part of IPP code path + REGION_FLAG_IMPL_OPENCL = (2 << 16), //< region is part of OpenCL code path + REGION_FLAG_IMPL_OPENVX = (3 << 16), //< region is part of OpenVX code path + + REGION_FLAG_IMPL_MASK = (15 << 16), + + REGION_FLAG_REGION_FORCE = (1 << 30), + REGION_FLAG_REGION_NEXT = (1 << 31), //< close previous region (see #CV_TRACE_REGION_NEXT macro) + + ENUM_REGION_FLAG_FORCE_INT = INT_MAX +}; + +struct CV_EXPORTS TraceArg { +public: + struct ExtraData; + ExtraData** ppExtra; + const char* name; + int flags; +}; +/** @brief Add meta information to current region (function) + * See CV_TRACE_ARG macro + * @param arg argument information structure (global static cache) + * @param value argument value (can by dynamic string literal in case of string, static allocation is not required) + */ +CV_EXPORTS void traceArg(const TraceArg& arg, const char* value); +//! @overload +CV_EXPORTS void traceArg(const TraceArg& arg, int value); +//! @overload +CV_EXPORTS void traceArg(const TraceArg& arg, int64 value); +//! @overload +CV_EXPORTS void traceArg(const TraceArg& arg, double value); + +#define CV__TRACE_LOCATION_VARNAME(loc_id) CVAUX_CONCAT(CVAUX_CONCAT(__cv_trace_location_, loc_id), __LINE__) +#define CV__TRACE_LOCATION_EXTRA_VARNAME(loc_id) CVAUX_CONCAT(CVAUX_CONCAT(__cv_trace_location_extra_, loc_id) , __LINE__) + +#define CV__TRACE_DEFINE_LOCATION_(loc_id, name, flags) \ + static CV_TRACE_NS::details::Region::LocationExtraData* CV__TRACE_LOCATION_EXTRA_VARNAME(loc_id) = 0; \ + static const CV_TRACE_NS::details::Region::LocationStaticStorage \ + CV__TRACE_LOCATION_VARNAME(loc_id) = { &(CV__TRACE_LOCATION_EXTRA_VARNAME(loc_id)), name, CV_TRACE_FILENAME, __LINE__, flags}; + +#define CV__TRACE_DEFINE_LOCATION_FN(name, flags) CV__TRACE_DEFINE_LOCATION_(fn, name, ((flags) | CV_TRACE_NS::details::REGION_FLAG_FUNCTION)) + + +#define CV__TRACE_OPENCV_FUNCTION() \ + CV__TRACE_DEFINE_LOCATION_FN(CV__TRACE_FUNCTION, 0); \ + const CV_TRACE_NS::details::Region __region_fn(CV__TRACE_LOCATION_VARNAME(fn)); + +#define CV__TRACE_OPENCV_FUNCTION_NAME(name) \ + CV__TRACE_DEFINE_LOCATION_FN(name, 0); \ + const CV_TRACE_NS::details::Region __region_fn(CV__TRACE_LOCATION_VARNAME(fn)); + +#define CV__TRACE_APP_FUNCTION() \ + CV__TRACE_DEFINE_LOCATION_FN(CV__TRACE_FUNCTION, CV_TRACE_NS::details::REGION_FLAG_APP_CODE); \ + const CV_TRACE_NS::details::Region __region_fn(CV__TRACE_LOCATION_VARNAME(fn)); + +#define CV__TRACE_APP_FUNCTION_NAME(name) \ + CV__TRACE_DEFINE_LOCATION_FN(name, CV_TRACE_NS::details::REGION_FLAG_APP_CODE); \ + const CV_TRACE_NS::details::Region __region_fn(CV__TRACE_LOCATION_VARNAME(fn)); + + +#define CV__TRACE_OPENCV_FUNCTION_SKIP_NESTED() \ + CV__TRACE_DEFINE_LOCATION_FN(CV__TRACE_FUNCTION, CV_TRACE_NS::details::REGION_FLAG_SKIP_NESTED); \ + const CV_TRACE_NS::details::Region __region_fn(CV__TRACE_LOCATION_VARNAME(fn)); + +#define CV__TRACE_OPENCV_FUNCTION_NAME_SKIP_NESTED(name) \ + CV__TRACE_DEFINE_LOCATION_FN(name, CV_TRACE_NS::details::REGION_FLAG_SKIP_NESTED); \ + const CV_TRACE_NS::details::Region __region_fn(CV__TRACE_LOCATION_VARNAME(fn)); + +#define CV__TRACE_APP_FUNCTION_SKIP_NESTED() \ + CV__TRACE_DEFINE_LOCATION_FN(CV__TRACE_FUNCTION, CV_TRACE_NS::details::REGION_FLAG_SKIP_NESTED | CV_TRACE_NS::details::REGION_FLAG_APP_CODE); \ + const CV_TRACE_NS::details::Region __region_fn(CV__TRACE_LOCATION_VARNAME(fn)); + + +#define CV__TRACE_REGION_(name_as_static_string_literal, flags) \ + CV__TRACE_DEFINE_LOCATION_(region, name_as_static_string_literal, flags); \ + CV_TRACE_NS::details::Region CVAUX_CONCAT(__region_, __LINE__)(CV__TRACE_LOCATION_VARNAME(region)); + +#define CV__TRACE_REGION(name_as_static_string_literal) CV__TRACE_REGION_(name_as_static_string_literal, 0) +#define CV__TRACE_REGION_NEXT(name_as_static_string_literal) CV__TRACE_REGION_(name_as_static_string_literal, CV_TRACE_NS::details::REGION_FLAG_REGION_NEXT) + +#define CV__TRACE_ARG_VARNAME(arg_id) CVAUX_CONCAT(__cv_trace_arg_ ## arg_id, __LINE__) +#define CV__TRACE_ARG_EXTRA_VARNAME(arg_id) CVAUX_CONCAT(__cv_trace_arg_extra_ ## arg_id, __LINE__) + +#define CV__TRACE_DEFINE_ARG_(arg_id, name, flags) \ + static CV_TRACE_NS::details::TraceArg::ExtraData* CV__TRACE_ARG_EXTRA_VARNAME(arg_id) = 0; \ + static const CV_TRACE_NS::details::TraceArg \ + CV__TRACE_ARG_VARNAME(arg_id) = { &(CV__TRACE_ARG_EXTRA_VARNAME(arg_id)), name, flags }; + +#define CV__TRACE_ARG_VALUE(arg_id, arg_name, value) \ + CV__TRACE_DEFINE_ARG_(arg_id, arg_name, 0); \ + CV_TRACE_NS::details::traceArg((CV__TRACE_ARG_VARNAME(arg_id)), value); + +#define CV__TRACE_ARG(arg_id) CV_TRACE_ARG_VALUE(arg_id, #arg_id, (arg_id)) + +} // namespace + +#ifndef OPENCV_DISABLE_TRACE +#undef CV_TRACE_FUNCTION +#undef CV_TRACE_FUNCTION_SKIP_NESTED +#if __OPENCV_TRACE +#define CV_TRACE_FUNCTION CV__TRACE_OPENCV_FUNCTION +#define CV_TRACE_FUNCTION_SKIP_NESTED CV__TRACE_OPENCV_FUNCTION_SKIP_NESTED +#else +#define CV_TRACE_FUNCTION CV__TRACE_APP_FUNCTION +#define CV_TRACE_FUNCTION_SKIP_NESTED CV__TRACE_APP_FUNCTION_SKIP_NESTED +#endif + +#undef CV_TRACE_REGION +#define CV_TRACE_REGION CV__TRACE_REGION + +#undef CV_TRACE_REGION_NEXT +#define CV_TRACE_REGION_NEXT CV__TRACE_REGION_NEXT + +#undef CV_TRACE_ARG_VALUE +#define CV_TRACE_ARG_VALUE(arg_id, arg_name, value) \ + if (__region_fn.isActive()) \ + { \ + CV__TRACE_ARG_VALUE(arg_id, arg_name, value); \ + } + +#undef CV_TRACE_ARG +#define CV_TRACE_ARG CV__TRACE_ARG + +#endif // OPENCV_DISABLE_TRACE + +#ifdef OPENCV_TRACE_VERBOSE +#define CV_TRACE_FUNCTION_VERBOSE CV_TRACE_FUNCTION +#define CV_TRACE_REGION_VERBOSE CV_TRACE_REGION +#define CV_TRACE_REGION_NEXT_VERBOSE CV_TRACE_REGION_NEXT +#define CV_TRACE_ARG_VALUE_VERBOSE CV_TRACE_ARG_VALUE +#define CV_TRACE_ARG_VERBOSE CV_TRACE_ARG +#else +#define CV_TRACE_FUNCTION_VERBOSE(...) +#define CV_TRACE_REGION_VERBOSE(...) +#define CV_TRACE_REGION_NEXT_VERBOSE(...) +#define CV_TRACE_ARG_VALUE_VERBOSE(...) +#define CV_TRACE_ARG_VERBOSE(...) +#endif + +//! @endcond + +//! @} + +}}} // namespace + +#endif // OPENCV_TRACE_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/va_intel.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/va_intel.hpp new file mode 100644 index 0000000..b37ce75 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/va_intel.hpp @@ -0,0 +1,75 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +// Copyright (C) 2015, Itseez, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. + +#ifndef OPENCV_CORE_VA_INTEL_HPP +#define OPENCV_CORE_VA_INTEL_HPP + +#ifndef __cplusplus +# error va_intel.hpp header must be compiled as C++ +#endif + +#include "opencv2/core.hpp" +#include "ocl.hpp" + +#if defined(HAVE_VA) +# include "va/va.h" +#else // HAVE_VA +# if !defined(_VA_H_) + typedef void* VADisplay; + typedef unsigned int VASurfaceID; +# endif // !_VA_H_ +#endif // HAVE_VA + +namespace cv { namespace va_intel { + +/** @addtogroup core_va_intel +This section describes Intel VA-API/OpenCL (CL-VA) interoperability. + +To enable basic VA interoperability build OpenCV with libva library integration enabled: `-DWITH_VA=ON` (corresponding dev package should be installed). + +To enable advanced CL-VA interoperability support on Intel HW, enable option: `-DWITH_VA_INTEL=ON` (OpenCL integration should be enabled which is the default setting). Special runtime environment should be set up in order to use this feature: correct combination of [libva](https://github.com/intel/libva), [OpenCL runtime](https://github.com/intel/compute-runtime) and [media driver](https://github.com/intel/media-driver) should be installed. + +Check usage example for details: samples/va_intel/va_intel_interop.cpp +*/ +//! @{ + +/////////////////// CL-VA Interoperability Functions /////////////////// + +namespace ocl { +using namespace cv::ocl; + +// TODO static functions in the Context class +/** @brief Creates OpenCL context from VA. +@param display - VADisplay for which CL interop should be established. +@param tryInterop - try to set up for interoperability, if true; set up for use slow copy if false. +@return Returns reference to OpenCL Context + */ +CV_EXPORTS Context& initializeContextFromVA(VADisplay display, bool tryInterop = true); + +} // namespace cv::va_intel::ocl + +/** @brief Converts InputArray to VASurfaceID object. +@param display - VADisplay object. +@param src - source InputArray. +@param surface - destination VASurfaceID object. +@param size - size of image represented by VASurfaceID object. + */ +CV_EXPORTS void convertToVASurface(VADisplay display, InputArray src, VASurfaceID surface, Size size); + +/** @brief Converts VASurfaceID object to OutputArray. +@param display - VADisplay object. +@param surface - source VASurfaceID object. +@param size - size of image represented by VASurfaceID object. +@param dst - destination OutputArray. + */ +CV_EXPORTS void convertFromVASurface(VADisplay display, VASurfaceID surface, Size size, OutputArray dst); + +//! @} + +}} // namespace cv::va_intel + +#endif /* OPENCV_CORE_VA_INTEL_HPP */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/version.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/version.hpp new file mode 100644 index 0000000..7b129b6 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/version.hpp @@ -0,0 +1,26 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_VERSION_HPP +#define OPENCV_VERSION_HPP + +#define CV_VERSION_MAJOR 4 +#define CV_VERSION_MINOR 6 +#define CV_VERSION_REVISION 0 +#define CV_VERSION_STATUS "" + +#define CVAUX_STR_EXP(__A) #__A +#define CVAUX_STR(__A) CVAUX_STR_EXP(__A) + +#define CVAUX_STRW_EXP(__A) L ## #__A +#define CVAUX_STRW(__A) CVAUX_STRW_EXP(__A) + +#define CV_VERSION CVAUX_STR(CV_VERSION_MAJOR) "." CVAUX_STR(CV_VERSION_MINOR) "." CVAUX_STR(CV_VERSION_REVISION) CV_VERSION_STATUS + +/* old style version constants*/ +#define CV_MAJOR_VERSION CV_VERSION_MAJOR +#define CV_MINOR_VERSION CV_VERSION_MINOR +#define CV_SUBMINOR_VERSION CV_VERSION_REVISION + +#endif // OPENCV_VERSION_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/vsx_utils.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/vsx_utils.hpp new file mode 100644 index 0000000..79a1074 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/core/vsx_utils.hpp @@ -0,0 +1,1047 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + +#ifndef OPENCV_HAL_VSX_UTILS_HPP +#define OPENCV_HAL_VSX_UTILS_HPP + +#include "opencv2/core/cvdef.h" + +#ifndef SKIP_INCLUDES +# include +#endif + +//! @addtogroup core_utils_vsx +//! @{ +#if CV_VSX + +#define __VSX_S16__(c, v) (c){v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v} +#define __VSX_S8__(c, v) (c){v, v, v, v, v, v, v, v} +#define __VSX_S4__(c, v) (c){v, v, v, v} +#define __VSX_S2__(c, v) (c){v, v} + +typedef __vector unsigned char vec_uchar16; +#define vec_uchar16_set(...) (vec_uchar16){__VA_ARGS__} +#define vec_uchar16_sp(c) (__VSX_S16__(vec_uchar16, (unsigned char)c)) +#define vec_uchar16_c(v) ((vec_uchar16)(v)) +#define vec_uchar16_z vec_uchar16_sp(0) + +typedef __vector signed char vec_char16; +#define vec_char16_set(...) (vec_char16){__VA_ARGS__} +#define vec_char16_sp(c) (__VSX_S16__(vec_char16, (signed char)c)) +#define vec_char16_c(v) ((vec_char16)(v)) +#define vec_char16_z vec_char16_sp(0) + +typedef __vector unsigned short vec_ushort8; +#define vec_ushort8_set(...) (vec_ushort8){__VA_ARGS__} +#define vec_ushort8_sp(c) (__VSX_S8__(vec_ushort8, (unsigned short)c)) +#define vec_ushort8_c(v) ((vec_ushort8)(v)) +#define vec_ushort8_z vec_ushort8_sp(0) + +typedef __vector signed short vec_short8; +#define vec_short8_set(...) (vec_short8){__VA_ARGS__} +#define vec_short8_sp(c) (__VSX_S8__(vec_short8, (signed short)c)) +#define vec_short8_c(v) ((vec_short8)(v)) +#define vec_short8_z vec_short8_sp(0) + +typedef __vector unsigned int vec_uint4; +#define vec_uint4_set(...) (vec_uint4){__VA_ARGS__} +#define vec_uint4_sp(c) (__VSX_S4__(vec_uint4, (unsigned int)c)) +#define vec_uint4_c(v) ((vec_uint4)(v)) +#define vec_uint4_z vec_uint4_sp(0) + +typedef __vector signed int vec_int4; +#define vec_int4_set(...) (vec_int4){__VA_ARGS__} +#define vec_int4_sp(c) (__VSX_S4__(vec_int4, (signed int)c)) +#define vec_int4_c(v) ((vec_int4)(v)) +#define vec_int4_z vec_int4_sp(0) + +typedef __vector float vec_float4; +#define vec_float4_set(...) (vec_float4){__VA_ARGS__} +#define vec_float4_sp(c) (__VSX_S4__(vec_float4, c)) +#define vec_float4_c(v) ((vec_float4)(v)) +#define vec_float4_z vec_float4_sp(0) + +typedef __vector unsigned long long vec_udword2; +#define vec_udword2_set(...) (vec_udword2){__VA_ARGS__} +#define vec_udword2_sp(c) (__VSX_S2__(vec_udword2, (unsigned long long)c)) +#define vec_udword2_c(v) ((vec_udword2)(v)) +#define vec_udword2_z vec_udword2_sp(0) + +typedef __vector signed long long vec_dword2; +#define vec_dword2_set(...) (vec_dword2){__VA_ARGS__} +#define vec_dword2_sp(c) (__VSX_S2__(vec_dword2, (signed long long)c)) +#define vec_dword2_c(v) ((vec_dword2)(v)) +#define vec_dword2_z vec_dword2_sp(0) + +typedef __vector double vec_double2; +#define vec_double2_set(...) (vec_double2){__VA_ARGS__} +#define vec_double2_c(v) ((vec_double2)(v)) +#define vec_double2_sp(c) (__VSX_S2__(vec_double2, c)) +#define vec_double2_z vec_double2_sp(0) + +#define vec_bchar16 __vector __bool char +#define vec_bchar16_set(...) (vec_bchar16){__VA_ARGS__} +#define vec_bchar16_c(v) ((vec_bchar16)(v)) + +#define vec_bshort8 __vector __bool short +#define vec_bshort8_set(...) (vec_bshort8){__VA_ARGS__} +#define vec_bshort8_c(v) ((vec_bshort8)(v)) + +#define vec_bint4 __vector __bool int +#define vec_bint4_set(...) (vec_bint4){__VA_ARGS__} +#define vec_bint4_c(v) ((vec_bint4)(v)) + +#define vec_bdword2 __vector __bool long long +#define vec_bdword2_set(...) (vec_bdword2){__VA_ARGS__} +#define vec_bdword2_c(v) ((vec_bdword2)(v)) + +#define VSX_FINLINE(tp) extern inline tp __attribute__((always_inline)) + +#define VSX_REDIRECT_1RG(rt, rg, fnm, fn2) \ +VSX_FINLINE(rt) fnm(const rg& a) { return fn2(a); } + +#define VSX_REDIRECT_2RG(rt, rg, fnm, fn2) \ +VSX_FINLINE(rt) fnm(const rg& a, const rg& b) { return fn2(a, b); } + +/* + * GCC VSX compatibility +**/ +#if defined(__GNUG__) && !defined(__clang__) + +// inline asm helper +#define VSX_IMPL_1RG(rt, rg, opc, fnm) \ +VSX_FINLINE(rt) fnm(const rg& a) \ +{ rt rs; __asm__ __volatile__(#opc" %x0,%x1" : "=wa" (rs) : "wa" (a)); return rs; } + +#define VSX_IMPL_1VRG(rt, rg, opc, fnm) \ +VSX_FINLINE(rt) fnm(const rg& a) \ +{ rt rs; __asm__ __volatile__(#opc" %0,%1" : "=v" (rs) : "v" (a)); return rs; } + +#define VSX_IMPL_2VRG_F(rt, rg, fopc, fnm) \ +VSX_FINLINE(rt) fnm(const rg& a, const rg& b) \ +{ rt rs; __asm__ __volatile__(fopc : "=v" (rs) : "v" (a), "v" (b)); return rs; } + +#define VSX_IMPL_2VRG(rt, rg, opc, fnm) VSX_IMPL_2VRG_F(rt, rg, #opc" %0,%1,%2", fnm) + +#if __GNUG__ < 8 + + // Support for int4 -> dword2 expanding multiply was added in GCC 8. + #ifdef vec_mule + #undef vec_mule + #endif + #ifdef vec_mulo + #undef vec_mulo + #endif + + VSX_REDIRECT_2RG(vec_ushort8, vec_uchar16, vec_mule, __builtin_vec_mule) + VSX_REDIRECT_2RG(vec_short8, vec_char16, vec_mule, __builtin_vec_mule) + VSX_REDIRECT_2RG(vec_int4, vec_short8, vec_mule, __builtin_vec_mule) + VSX_REDIRECT_2RG(vec_uint4, vec_ushort8, vec_mule, __builtin_vec_mule) + VSX_REDIRECT_2RG(vec_ushort8, vec_uchar16, vec_mulo, __builtin_vec_mulo) + VSX_REDIRECT_2RG(vec_short8, vec_char16, vec_mulo, __builtin_vec_mulo) + VSX_REDIRECT_2RG(vec_int4, vec_short8, vec_mulo, __builtin_vec_mulo) + VSX_REDIRECT_2RG(vec_uint4, vec_ushort8, vec_mulo, __builtin_vec_mulo) + + // dword2 support arrived in ISA 2.07 and GCC 8+ + VSX_IMPL_2VRG(vec_dword2, vec_int4, vmulosw, vec_mule) + VSX_IMPL_2VRG(vec_udword2, vec_uint4, vmulouw, vec_mule) + VSX_IMPL_2VRG(vec_dword2, vec_int4, vmulesw, vec_mulo) + VSX_IMPL_2VRG(vec_udword2, vec_uint4, vmuleuw, vec_mulo) + +#endif + +#if __GNUG__ < 7 +// up to GCC 6 vec_mul only supports precisions and llong +# ifdef vec_mul +# undef vec_mul +# endif +/* + * there's no a direct instruction for supporting 8-bit, 16-bit multiplication in ISA 2.07, + * XLC Implement it by using instruction "multiply even", "multiply odd" and "permute" +**/ +# define VSX_IMPL_MULH(Tvec, cperm) \ + VSX_FINLINE(Tvec) vec_mul(const Tvec& a, const Tvec& b) \ + { \ + static const vec_uchar16 ev_od = {cperm}; \ + return vec_perm((Tvec)vec_mule(a, b), (Tvec)vec_mulo(a, b), ev_od); \ + } + #define VSX_IMPL_MULH_P16 0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30 + VSX_IMPL_MULH(vec_char16, VSX_IMPL_MULH_P16) + VSX_IMPL_MULH(vec_uchar16, VSX_IMPL_MULH_P16) + #define VSX_IMPL_MULH_P8 0, 1, 16, 17, 4, 5, 20, 21, 8, 9, 24, 25, 12, 13, 28, 29 + VSX_IMPL_MULH(vec_short8, VSX_IMPL_MULH_P8) + VSX_IMPL_MULH(vec_ushort8, VSX_IMPL_MULH_P8) + // vmuluwm can be used for unsigned or signed integers, that's what they said + VSX_IMPL_2VRG(vec_int4, vec_int4, vmuluwm, vec_mul) + VSX_IMPL_2VRG(vec_uint4, vec_uint4, vmuluwm, vec_mul) + // redirect to GCC builtin vec_mul, since it already supports precisions and llong + VSX_REDIRECT_2RG(vec_float4, vec_float4, vec_mul, __builtin_vec_mul) + VSX_REDIRECT_2RG(vec_double2, vec_double2, vec_mul, __builtin_vec_mul) + VSX_REDIRECT_2RG(vec_dword2, vec_dword2, vec_mul, __builtin_vec_mul) + VSX_REDIRECT_2RG(vec_udword2, vec_udword2, vec_mul, __builtin_vec_mul) +#endif // __GNUG__ < 7 + +#if __GNUG__ < 6 +/* + * Instruction "compare greater than or equal" in ISA 2.07 only supports single + * and double precision. + * In XLC and new versions of GCC implement integers by using instruction "greater than" and NOR. +**/ +# ifdef vec_cmpge +# undef vec_cmpge +# endif +# ifdef vec_cmple +# undef vec_cmple +# endif +# define vec_cmple(a, b) vec_cmpge(b, a) +# define VSX_IMPL_CMPGE(rt, rg, opc, fnm) \ + VSX_IMPL_2VRG_F(rt, rg, #opc" %0,%2,%1\n\t xxlnor %x0,%x0,%x0", fnm) + + VSX_IMPL_CMPGE(vec_bchar16, vec_char16, vcmpgtsb, vec_cmpge) + VSX_IMPL_CMPGE(vec_bchar16, vec_uchar16, vcmpgtub, vec_cmpge) + VSX_IMPL_CMPGE(vec_bshort8, vec_short8, vcmpgtsh, vec_cmpge) + VSX_IMPL_CMPGE(vec_bshort8, vec_ushort8, vcmpgtuh, vec_cmpge) + VSX_IMPL_CMPGE(vec_bint4, vec_int4, vcmpgtsw, vec_cmpge) + VSX_IMPL_CMPGE(vec_bint4, vec_uint4, vcmpgtuw, vec_cmpge) + VSX_IMPL_CMPGE(vec_bdword2, vec_dword2, vcmpgtsd, vec_cmpge) + VSX_IMPL_CMPGE(vec_bdword2, vec_udword2, vcmpgtud, vec_cmpge) + +// redirect to GCC builtin cmpge, since it already supports precisions + VSX_REDIRECT_2RG(vec_bint4, vec_float4, vec_cmpge, __builtin_vec_cmpge) + VSX_REDIRECT_2RG(vec_bdword2, vec_double2, vec_cmpge, __builtin_vec_cmpge) + +// up to gcc5 vec_nor doesn't support bool long long +# undef vec_nor + template + VSX_REDIRECT_2RG(T, T, vec_nor, __builtin_vec_nor) + + VSX_FINLINE(vec_bdword2) vec_nor(const vec_bdword2& a, const vec_bdword2& b) + { return vec_bdword2_c(__builtin_vec_nor(vec_dword2_c(a), vec_dword2_c(b))); } + +// vec_packs doesn't support double words in gcc4 and old versions of gcc5 +# undef vec_packs + VSX_REDIRECT_2RG(vec_char16, vec_short8, vec_packs, __builtin_vec_packs) + VSX_REDIRECT_2RG(vec_uchar16, vec_ushort8, vec_packs, __builtin_vec_packs) + VSX_REDIRECT_2RG(vec_short8, vec_int4, vec_packs, __builtin_vec_packs) + VSX_REDIRECT_2RG(vec_ushort8, vec_uint4, vec_packs, __builtin_vec_packs) + + VSX_IMPL_2VRG_F(vec_int4, vec_dword2, "vpksdss %0,%2,%1", vec_packs) + VSX_IMPL_2VRG_F(vec_uint4, vec_udword2, "vpkudus %0,%2,%1", vec_packs) +#endif // __GNUG__ < 6 + +#if __GNUG__ < 5 +// vec_xxpermdi in gcc4 missing little-endian supports just like clang +# define vec_permi(a, b, c) vec_xxpermdi(b, a, (3 ^ (((c) & 1) << 1 | (c) >> 1))) +// same as vec_xxpermdi +# undef vec_vbpermq + VSX_IMPL_2VRG(vec_udword2, vec_uchar16, vbpermq, vec_vbpermq) + VSX_IMPL_2VRG(vec_dword2, vec_char16, vbpermq, vec_vbpermq) +#else +# define vec_permi vec_xxpermdi +#endif // __GNUG__ < 5 + +// shift left double by word immediate +#ifndef vec_sldw +# define vec_sldw __builtin_vsx_xxsldwi +#endif + +// vector population count +VSX_IMPL_1VRG(vec_uchar16, vec_uchar16, vpopcntb, vec_popcntu) +VSX_IMPL_1VRG(vec_uchar16, vec_char16, vpopcntb, vec_popcntu) +VSX_IMPL_1VRG(vec_ushort8, vec_ushort8, vpopcnth, vec_popcntu) +VSX_IMPL_1VRG(vec_ushort8, vec_short8, vpopcnth, vec_popcntu) +VSX_IMPL_1VRG(vec_uint4, vec_uint4, vpopcntw, vec_popcntu) +VSX_IMPL_1VRG(vec_uint4, vec_int4, vpopcntw, vec_popcntu) +VSX_IMPL_1VRG(vec_udword2, vec_udword2, vpopcntd, vec_popcntu) +VSX_IMPL_1VRG(vec_udword2, vec_dword2, vpopcntd, vec_popcntu) + +// converts between single and double-precision +VSX_REDIRECT_1RG(vec_float4, vec_double2, vec_cvfo, __builtin_vsx_xvcvdpsp) +VSX_REDIRECT_1RG(vec_double2, vec_float4, vec_cvfo, __builtin_vsx_xvcvspdp) + +// converts word and doubleword to double-precision +#undef vec_ctd +VSX_IMPL_1RG(vec_double2, vec_int4, xvcvsxwdp, vec_ctdo) +VSX_IMPL_1RG(vec_double2, vec_uint4, xvcvuxwdp, vec_ctdo) +VSX_IMPL_1RG(vec_double2, vec_dword2, xvcvsxddp, vec_ctd) +VSX_IMPL_1RG(vec_double2, vec_udword2, xvcvuxddp, vec_ctd) + +// converts word and doubleword to single-precision +#undef vec_ctf +VSX_IMPL_1RG(vec_float4, vec_int4, xvcvsxwsp, vec_ctf) +VSX_IMPL_1RG(vec_float4, vec_uint4, xvcvuxwsp, vec_ctf) +VSX_IMPL_1RG(vec_float4, vec_dword2, xvcvsxdsp, vec_ctfo) +VSX_IMPL_1RG(vec_float4, vec_udword2, xvcvuxdsp, vec_ctfo) + +// converts single and double precision to signed word +#undef vec_cts +VSX_IMPL_1RG(vec_int4, vec_double2, xvcvdpsxws, vec_ctso) +VSX_IMPL_1RG(vec_int4, vec_float4, xvcvspsxws, vec_cts) + +// converts single and double precision to unsigned word +#undef vec_ctu +VSX_IMPL_1RG(vec_uint4, vec_double2, xvcvdpuxws, vec_ctuo) +VSX_IMPL_1RG(vec_uint4, vec_float4, xvcvspuxws, vec_ctu) + +// converts single and double precision to signed doubleword +#undef vec_ctsl +VSX_IMPL_1RG(vec_dword2, vec_double2, xvcvdpsxds, vec_ctsl) +VSX_IMPL_1RG(vec_dword2, vec_float4, xvcvspsxds, vec_ctslo) + +// converts single and double precision to unsigned doubleword +#undef vec_ctul +VSX_IMPL_1RG(vec_udword2, vec_double2, xvcvdpuxds, vec_ctul) +VSX_IMPL_1RG(vec_udword2, vec_float4, xvcvspuxds, vec_ctulo) + +// just in case if GCC doesn't define it +#ifndef vec_xl +# define vec_xl vec_vsx_ld +# define vec_xst vec_vsx_st +#endif + +#endif // GCC VSX compatibility + +/* + * CLANG VSX compatibility +**/ +#if defined(__clang__) && !defined(__IBMCPP__) + +/* + * CLANG doesn't support %x in the inline asm template which fixes register number + * when using any of the register constraints wa, wd, wf + * + * For more explanation checkout PowerPC and IBM RS6000 in https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html + * Also there's already an open bug https://bugs.llvm.org/show_bug.cgi?id=31837 + * + * So we're not able to use inline asm and only use built-in functions that CLANG supports + * and use __builtin_convertvector if clang missing any of vector conversions built-in functions + * + * todo: clang asm template bug is fixed, need to reconsider the current workarounds. +*/ + +// convert vector helper +#define VSX_IMPL_CONVERT(rt, rg, fnm) \ +VSX_FINLINE(rt) fnm(const rg& a) { return __builtin_convertvector(a, rt); } + +#ifndef vec_permi +#if __clang_major__ < 5 +// implement vec_permi in a dirty way +# define VSX_IMPL_CLANG_4_PERMI(Tvec) \ + VSX_FINLINE(Tvec) vec_permi(const Tvec& a, const Tvec& b, unsigned const char c) \ + { \ + switch (c) \ + { \ + case 0: \ + return vec_mergeh(a, b); \ + case 1: \ + return vec_mergel(vec_mergeh(a, a), b); \ + case 2: \ + return vec_mergeh(vec_mergel(a, a), b); \ + default: \ + return vec_mergel(a, b); \ + } \ + } + VSX_IMPL_CLANG_4_PERMI(vec_udword2) + VSX_IMPL_CLANG_4_PERMI(vec_dword2) + VSX_IMPL_CLANG_4_PERMI(vec_double2) + +// vec_xxsldwi is missing in clang 4 +# define vec_xxsldwi(a, b, c) vec_sld(a, b, (c) * 4) +#else +// vec_xxpermdi is missing little-endian supports in clang 4 just like gcc4 +# define vec_permi(a, b, c) vec_xxpermdi(b, a, (3 ^ (((c) & 1) << 1 | (c) >> 1))) +#endif // __clang_major__ < 5 +#endif + +// shift left double by word immediate +#ifndef vec_sldw +# define vec_sldw vec_xxsldwi +#endif + +#if __clang_major__ < 13 +// Implement vec_rsqrt since clang only supports vec_rsqrte +#ifndef vec_rsqrt + VSX_FINLINE(vec_float4) vec_rsqrt(const vec_float4& a) + { return vec_div(vec_float4_sp(1), vec_sqrt(a)); } + + VSX_FINLINE(vec_double2) vec_rsqrt(const vec_double2& a) + { return vec_div(vec_double2_sp(1), vec_sqrt(a)); } +#endif + +// vec_promote missing support for doubleword +VSX_FINLINE(vec_dword2) vec_promote(long long a, int b) +{ + vec_dword2 ret = vec_dword2_z; + ret[b & 1] = a; + return ret; +} + +VSX_FINLINE(vec_udword2) vec_promote(unsigned long long a, int b) +{ + vec_udword2 ret = vec_udword2_z; + ret[b & 1] = a; + return ret; +} +#endif + +// vec_popcnt should return unsigned but clang has different thought just like gcc in vec_vpopcnt +#define VSX_IMPL_POPCNTU(Tvec, Tvec2, ucast) \ +VSX_FINLINE(Tvec) vec_popcntu(const Tvec2& a) \ +{ return ucast(vec_popcnt(a)); } +VSX_IMPL_POPCNTU(vec_uchar16, vec_char16, vec_uchar16_c); +VSX_IMPL_POPCNTU(vec_ushort8, vec_short8, vec_ushort8_c); +VSX_IMPL_POPCNTU(vec_uint4, vec_int4, vec_uint4_c); +VSX_IMPL_POPCNTU(vec_udword2, vec_dword2, vec_udword2_c); +// redirect unsigned types +VSX_REDIRECT_1RG(vec_uchar16, vec_uchar16, vec_popcntu, vec_popcnt) +VSX_REDIRECT_1RG(vec_ushort8, vec_ushort8, vec_popcntu, vec_popcnt) +VSX_REDIRECT_1RG(vec_uint4, vec_uint4, vec_popcntu, vec_popcnt) +VSX_REDIRECT_1RG(vec_udword2, vec_udword2, vec_popcntu, vec_popcnt) + +// converts between single and double precision +VSX_REDIRECT_1RG(vec_float4, vec_double2, vec_cvfo, __builtin_vsx_xvcvdpsp) +VSX_REDIRECT_1RG(vec_double2, vec_float4, vec_cvfo, __builtin_vsx_xvcvspdp) + +// converts word and doubleword to double-precision +#ifdef vec_ctd +# undef vec_ctd +#endif +VSX_REDIRECT_1RG(vec_double2, vec_int4, vec_ctdo, __builtin_vsx_xvcvsxwdp) +VSX_REDIRECT_1RG(vec_double2, vec_uint4, vec_ctdo, __builtin_vsx_xvcvuxwdp) + +VSX_IMPL_CONVERT(vec_double2, vec_dword2, vec_ctd) +VSX_IMPL_CONVERT(vec_double2, vec_udword2, vec_ctd) + +// converts word and doubleword to single-precision +#if __clang_major__ > 4 +# undef vec_ctf +#endif +VSX_IMPL_CONVERT(vec_float4, vec_int4, vec_ctf) +VSX_IMPL_CONVERT(vec_float4, vec_uint4, vec_ctf) +VSX_REDIRECT_1RG(vec_float4, vec_dword2, vec_ctfo, __builtin_vsx_xvcvsxdsp) +VSX_REDIRECT_1RG(vec_float4, vec_udword2, vec_ctfo, __builtin_vsx_xvcvuxdsp) + +// converts single and double precision to signed word +#if __clang_major__ > 4 +# undef vec_cts +#endif +VSX_REDIRECT_1RG(vec_int4, vec_double2, vec_ctso, __builtin_vsx_xvcvdpsxws) +VSX_IMPL_CONVERT(vec_int4, vec_float4, vec_cts) + +// converts single and double precision to unsigned word +#if __clang_major__ > 4 +# undef vec_ctu +#endif +VSX_REDIRECT_1RG(vec_uint4, vec_double2, vec_ctuo, __builtin_vsx_xvcvdpuxws) +VSX_IMPL_CONVERT(vec_uint4, vec_float4, vec_ctu) + +// converts single and double precision to signed doubleword +#ifdef vec_ctsl +# undef vec_ctsl +#endif +VSX_IMPL_CONVERT(vec_dword2, vec_double2, vec_ctsl) +// __builtin_convertvector unable to convert, xvcvspsxds is missing on it +VSX_FINLINE(vec_dword2) vec_ctslo(const vec_float4& a) +{ return vec_ctsl(vec_cvfo(a)); } + +// converts single and double precision to unsigned doubleword +#ifdef vec_ctul +# undef vec_ctul +#endif +VSX_IMPL_CONVERT(vec_udword2, vec_double2, vec_ctul) +// __builtin_convertvector unable to convert, xvcvspuxds is missing on it +VSX_FINLINE(vec_udword2) vec_ctulo(const vec_float4& a) +{ return vec_ctul(vec_cvfo(a)); } + +#endif // CLANG VSX compatibility + +/* + * Common GCC, CLANG compatibility +**/ +#if defined(__GNUG__) && !defined(__IBMCPP__) + +#ifdef vec_cvf +# undef vec_cvf +#endif + +#define VSX_IMPL_CONV_EVEN_4_2(rt, rg, fnm, fn2) \ +VSX_FINLINE(rt) fnm(const rg& a) \ +{ return fn2(vec_sldw(a, a, 1)); } + +VSX_IMPL_CONV_EVEN_4_2(vec_double2, vec_float4, vec_cvf, vec_cvfo) +VSX_IMPL_CONV_EVEN_4_2(vec_double2, vec_int4, vec_ctd, vec_ctdo) +VSX_IMPL_CONV_EVEN_4_2(vec_double2, vec_uint4, vec_ctd, vec_ctdo) + +VSX_IMPL_CONV_EVEN_4_2(vec_dword2, vec_float4, vec_ctsl, vec_ctslo) +VSX_IMPL_CONV_EVEN_4_2(vec_udword2, vec_float4, vec_ctul, vec_ctulo) + +#define VSX_IMPL_CONV_EVEN_2_4(rt, rg, fnm, fn2) \ +VSX_FINLINE(rt) fnm(const rg& a) \ +{ \ + rt v4 = fn2(a); \ + return vec_sldw(v4, v4, 3); \ +} + +VSX_IMPL_CONV_EVEN_2_4(vec_float4, vec_double2, vec_cvf, vec_cvfo) +VSX_IMPL_CONV_EVEN_2_4(vec_float4, vec_dword2, vec_ctf, vec_ctfo) +VSX_IMPL_CONV_EVEN_2_4(vec_float4, vec_udword2, vec_ctf, vec_ctfo) + +VSX_IMPL_CONV_EVEN_2_4(vec_int4, vec_double2, vec_cts, vec_ctso) +VSX_IMPL_CONV_EVEN_2_4(vec_uint4, vec_double2, vec_ctu, vec_ctuo) + +// Only for Eigen! +/* + * changing behavior of conversion intrinsics for gcc has effect on Eigen + * so we redefine old behavior again only on gcc, clang +*/ +#if !defined(__clang__) || __clang_major__ > 4 + // ignoring second arg since Eigen only truncates toward zero +# define VSX_IMPL_CONV_2VARIANT(rt, rg, fnm, fn2) \ + VSX_FINLINE(rt) fnm(const rg& a, int only_truncate) \ + { \ + assert(only_truncate == 0); \ + CV_UNUSED(only_truncate); \ + return fn2(a); \ + } + VSX_IMPL_CONV_2VARIANT(vec_int4, vec_float4, vec_cts, vec_cts) + VSX_IMPL_CONV_2VARIANT(vec_uint4, vec_float4, vec_ctu, vec_ctu) + VSX_IMPL_CONV_2VARIANT(vec_float4, vec_int4, vec_ctf, vec_ctf) + VSX_IMPL_CONV_2VARIANT(vec_float4, vec_uint4, vec_ctf, vec_ctf) + // define vec_cts for converting double precision to signed doubleword + // which isn't compatible with xlc but its okay since Eigen only uses it for gcc + VSX_IMPL_CONV_2VARIANT(vec_dword2, vec_double2, vec_cts, vec_ctsl) +#endif // Eigen + +#endif // Common GCC, CLANG compatibility + +/* + * XLC VSX compatibility +**/ +#if defined(__IBMCPP__) + +// vector population count +#define vec_popcntu vec_popcnt + +// overload and redirect with setting second arg to zero +// since we only support conversions without the second arg +#define VSX_IMPL_OVERLOAD_Z2(rt, rg, fnm) \ +VSX_FINLINE(rt) fnm(const rg& a) { return fnm(a, 0); } + +VSX_IMPL_OVERLOAD_Z2(vec_double2, vec_int4, vec_ctd) +VSX_IMPL_OVERLOAD_Z2(vec_double2, vec_uint4, vec_ctd) +VSX_IMPL_OVERLOAD_Z2(vec_double2, vec_dword2, vec_ctd) +VSX_IMPL_OVERLOAD_Z2(vec_double2, vec_udword2, vec_ctd) + +VSX_IMPL_OVERLOAD_Z2(vec_float4, vec_int4, vec_ctf) +VSX_IMPL_OVERLOAD_Z2(vec_float4, vec_uint4, vec_ctf) +VSX_IMPL_OVERLOAD_Z2(vec_float4, vec_dword2, vec_ctf) +VSX_IMPL_OVERLOAD_Z2(vec_float4, vec_udword2, vec_ctf) + +VSX_IMPL_OVERLOAD_Z2(vec_int4, vec_double2, vec_cts) +VSX_IMPL_OVERLOAD_Z2(vec_int4, vec_float4, vec_cts) + +VSX_IMPL_OVERLOAD_Z2(vec_uint4, vec_double2, vec_ctu) +VSX_IMPL_OVERLOAD_Z2(vec_uint4, vec_float4, vec_ctu) + +VSX_IMPL_OVERLOAD_Z2(vec_dword2, vec_double2, vec_ctsl) +VSX_IMPL_OVERLOAD_Z2(vec_dword2, vec_float4, vec_ctsl) + +VSX_IMPL_OVERLOAD_Z2(vec_udword2, vec_double2, vec_ctul) +VSX_IMPL_OVERLOAD_Z2(vec_udword2, vec_float4, vec_ctul) + +// fixme: implement conversions of odd-numbered elements in a dirty way +// since xlc doesn't support VSX registers operand in inline asm. +#define VSX_IMPL_CONV_ODD_4_2(rt, rg, fnm, fn2) \ +VSX_FINLINE(rt) fnm(const rg& a) { return fn2(vec_sldw(a, a, 3)); } + +VSX_IMPL_CONV_ODD_4_2(vec_double2, vec_float4, vec_cvfo, vec_cvf) +VSX_IMPL_CONV_ODD_4_2(vec_double2, vec_int4, vec_ctdo, vec_ctd) +VSX_IMPL_CONV_ODD_4_2(vec_double2, vec_uint4, vec_ctdo, vec_ctd) + +VSX_IMPL_CONV_ODD_4_2(vec_dword2, vec_float4, vec_ctslo, vec_ctsl) +VSX_IMPL_CONV_ODD_4_2(vec_udword2, vec_float4, vec_ctulo, vec_ctul) + +#define VSX_IMPL_CONV_ODD_2_4(rt, rg, fnm, fn2) \ +VSX_FINLINE(rt) fnm(const rg& a) \ +{ \ + rt v4 = fn2(a); \ + return vec_sldw(v4, v4, 1); \ +} + +VSX_IMPL_CONV_ODD_2_4(vec_float4, vec_double2, vec_cvfo, vec_cvf) +VSX_IMPL_CONV_ODD_2_4(vec_float4, vec_dword2, vec_ctfo, vec_ctf) +VSX_IMPL_CONV_ODD_2_4(vec_float4, vec_udword2, vec_ctfo, vec_ctf) + +VSX_IMPL_CONV_ODD_2_4(vec_int4, vec_double2, vec_ctso, vec_cts) +VSX_IMPL_CONV_ODD_2_4(vec_uint4, vec_double2, vec_ctuo, vec_ctu) + +#endif // XLC VSX compatibility + +// ignore GCC warning that caused by -Wunused-but-set-variable in rare cases +#if defined(__GNUG__) && !defined(__clang__) +# define VSX_UNUSED(Tvec) Tvec __attribute__((__unused__)) +#else // CLANG, XLC +# define VSX_UNUSED(Tvec) Tvec +#endif + +// gcc can find his way in casting log int and XLC, CLANG ambiguous +#if defined(__clang__) || defined(__IBMCPP__) + VSX_FINLINE(vec_udword2) vec_splats(uint64 v) + { return vec_splats((unsigned long long) v); } + + VSX_FINLINE(vec_dword2) vec_splats(int64 v) + { return vec_splats((long long) v); } + + VSX_FINLINE(vec_udword2) vec_promote(uint64 a, int b) + { return vec_promote((unsigned long long) a, b); } + + VSX_FINLINE(vec_dword2) vec_promote(int64 a, int b) + { return vec_promote((long long) a, b); } +#endif + +/* + * implement vsx_ld(offset, pointer), vsx_st(vector, offset, pointer) + * load and set using offset depend on the pointer type + * + * implement vsx_ldf(offset, pointer), vsx_stf(vector, offset, pointer) + * load and set using offset depend on fixed bytes size + * + * Note: In clang vec_xl and vec_xst fails to load unaligned addresses + * so we are using vec_vsx_ld, vec_vsx_st instead +*/ + +#if defined(__clang__) && !defined(__IBMCPP__) +# define vsx_ldf vec_vsx_ld +# define vsx_stf vec_vsx_st +#else // GCC , XLC +# define vsx_ldf vec_xl +# define vsx_stf vec_xst +#endif + +#define VSX_OFFSET(o, p) ((o) * sizeof(*(p))) +#define vsx_ld(o, p) vsx_ldf(VSX_OFFSET(o, p), p) +#define vsx_st(v, o, p) vsx_stf(v, VSX_OFFSET(o, p), p) + +/* + * implement vsx_ld2(offset, pointer), vsx_st2(vector, offset, pointer) to load and store double words + * In GCC vec_xl and vec_xst it maps to vec_vsx_ld, vec_vsx_st which doesn't support long long + * and in CLANG we are using vec_vsx_ld, vec_vsx_st because vec_xl, vec_xst fails to load unaligned addresses + * + * In XLC vec_xl and vec_xst fail to cast int64(long int) to long long +*/ +#if (defined(__GNUG__) || defined(__clang__)) && !defined(__IBMCPP__) + VSX_FINLINE(vec_udword2) vsx_ld2(long o, const uint64* p) + { return vec_udword2_c(vsx_ldf(VSX_OFFSET(o, p), (unsigned int*)p)); } + + VSX_FINLINE(vec_dword2) vsx_ld2(long o, const int64* p) + { return vec_dword2_c(vsx_ldf(VSX_OFFSET(o, p), (int*)p)); } + + VSX_FINLINE(void) vsx_st2(const vec_udword2& vec, long o, uint64* p) + { vsx_stf(vec_uint4_c(vec), VSX_OFFSET(o, p), (unsigned int*)p); } + + VSX_FINLINE(void) vsx_st2(const vec_dword2& vec, long o, int64* p) + { vsx_stf(vec_int4_c(vec), VSX_OFFSET(o, p), (int*)p); } +#else // XLC + VSX_FINLINE(vec_udword2) vsx_ld2(long o, const uint64* p) + { return vsx_ldf(VSX_OFFSET(o, p), (unsigned long long*)p); } + + VSX_FINLINE(vec_dword2) vsx_ld2(long o, const int64* p) + { return vsx_ldf(VSX_OFFSET(o, p), (long long*)p); } + + VSX_FINLINE(void) vsx_st2(const vec_udword2& vec, long o, uint64* p) + { vsx_stf(vec, VSX_OFFSET(o, p), (unsigned long long*)p); } + + VSX_FINLINE(void) vsx_st2(const vec_dword2& vec, long o, int64* p) + { vsx_stf(vec, VSX_OFFSET(o, p), (long long*)p); } +#endif + +// Store lower 8 byte +#define vec_st_l8(v, p) *((uint64*)(p)) = vec_extract(vec_udword2_c(v), 0) + +// Store higher 8 byte +#define vec_st_h8(v, p) *((uint64*)(p)) = vec_extract(vec_udword2_c(v), 1) + +// Load 64-bits of integer data to lower part +#define VSX_IMPL_LOAD_L8(Tvec, Tp) \ +VSX_FINLINE(Tvec) vec_ld_l8(const Tp *p) \ +{ return ((Tvec)vec_promote(*((uint64*)p), 0)); } + +VSX_IMPL_LOAD_L8(vec_uchar16, uchar) +VSX_IMPL_LOAD_L8(vec_char16, schar) +VSX_IMPL_LOAD_L8(vec_ushort8, ushort) +VSX_IMPL_LOAD_L8(vec_short8, short) +VSX_IMPL_LOAD_L8(vec_uint4, uint) +VSX_IMPL_LOAD_L8(vec_int4, int) +VSX_IMPL_LOAD_L8(vec_float4, float) +VSX_IMPL_LOAD_L8(vec_udword2, uint64) +VSX_IMPL_LOAD_L8(vec_dword2, int64) +VSX_IMPL_LOAD_L8(vec_double2, double) + +// logical not +#define vec_not(a) vec_nor(a, a) + +// power9 yaya +// not equal +#ifndef vec_cmpne +# define vec_cmpne(a, b) vec_not(vec_cmpeq(a, b)) +#endif + +// absolute difference +#ifndef _ARCH_PWR9 +# undef vec_absd +# define vec_absd(a, b) vec_sub(vec_max(a, b), vec_min(a, b)) +#endif + +/* + * Implement vec_unpacklu and vec_unpackhu + * since vec_unpackl, vec_unpackh only support signed integers +**/ +#define VSX_IMPL_UNPACKU(rt, rg, zero) \ +VSX_FINLINE(rt) vec_unpacklu(const rg& a) \ +{ return (rt)(vec_mergel(a, zero)); } \ +VSX_FINLINE(rt) vec_unpackhu(const rg& a) \ +{ return (rt)(vec_mergeh(a, zero)); } + +VSX_IMPL_UNPACKU(vec_ushort8, vec_uchar16, vec_uchar16_z) +VSX_IMPL_UNPACKU(vec_uint4, vec_ushort8, vec_ushort8_z) +VSX_IMPL_UNPACKU(vec_udword2, vec_uint4, vec_uint4_z) + +/* + * Implement vec_mergesqe and vec_mergesqo + * Merges the sequence values of even and odd elements of two vectors +*/ +#define VSX_IMPL_PERM(rt, fnm, ...) \ +VSX_FINLINE(rt) fnm(const rt& a, const rt& b) \ +{ static const vec_uchar16 perm = {__VA_ARGS__}; return vec_perm(a, b, perm); } + +// 16 +#define perm16_mergesqe 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30 +#define perm16_mergesqo 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31 +VSX_IMPL_PERM(vec_uchar16, vec_mergesqe, perm16_mergesqe) +VSX_IMPL_PERM(vec_uchar16, vec_mergesqo, perm16_mergesqo) +VSX_IMPL_PERM(vec_char16, vec_mergesqe, perm16_mergesqe) +VSX_IMPL_PERM(vec_char16, vec_mergesqo, perm16_mergesqo) +// 8 +#define perm8_mergesqe 0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25, 28, 29 +#define perm8_mergesqo 2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23, 26, 27, 30, 31 +VSX_IMPL_PERM(vec_ushort8, vec_mergesqe, perm8_mergesqe) +VSX_IMPL_PERM(vec_ushort8, vec_mergesqo, perm8_mergesqo) +VSX_IMPL_PERM(vec_short8, vec_mergesqe, perm8_mergesqe) +VSX_IMPL_PERM(vec_short8, vec_mergesqo, perm8_mergesqo) +// 4 +#define perm4_mergesqe 0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27 +#define perm4_mergesqo 4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31 +VSX_IMPL_PERM(vec_uint4, vec_mergesqe, perm4_mergesqe) +VSX_IMPL_PERM(vec_uint4, vec_mergesqo, perm4_mergesqo) +VSX_IMPL_PERM(vec_int4, vec_mergesqe, perm4_mergesqe) +VSX_IMPL_PERM(vec_int4, vec_mergesqo, perm4_mergesqo) +VSX_IMPL_PERM(vec_float4, vec_mergesqe, perm4_mergesqe) +VSX_IMPL_PERM(vec_float4, vec_mergesqo, perm4_mergesqo) +// 2 +VSX_REDIRECT_2RG(vec_double2, vec_double2, vec_mergesqe, vec_mergeh) +VSX_REDIRECT_2RG(vec_double2, vec_double2, vec_mergesqo, vec_mergel) +VSX_REDIRECT_2RG(vec_dword2, vec_dword2, vec_mergesqe, vec_mergeh) +VSX_REDIRECT_2RG(vec_dword2, vec_dword2, vec_mergesqo, vec_mergel) +VSX_REDIRECT_2RG(vec_udword2, vec_udword2, vec_mergesqe, vec_mergeh) +VSX_REDIRECT_2RG(vec_udword2, vec_udword2, vec_mergesqo, vec_mergel) + +/* + * Implement vec_mergesqh and vec_mergesql + * Merges the sequence most and least significant halves of two vectors +*/ +#define VSX_IMPL_MERGESQHL(Tvec) \ +VSX_FINLINE(Tvec) vec_mergesqh(const Tvec& a, const Tvec& b) \ +{ return (Tvec)vec_mergeh(vec_udword2_c(a), vec_udword2_c(b)); } \ +VSX_FINLINE(Tvec) vec_mergesql(const Tvec& a, const Tvec& b) \ +{ return (Tvec)vec_mergel(vec_udword2_c(a), vec_udword2_c(b)); } +VSX_IMPL_MERGESQHL(vec_uchar16) +VSX_IMPL_MERGESQHL(vec_char16) +VSX_IMPL_MERGESQHL(vec_ushort8) +VSX_IMPL_MERGESQHL(vec_short8) +VSX_IMPL_MERGESQHL(vec_uint4) +VSX_IMPL_MERGESQHL(vec_int4) +VSX_IMPL_MERGESQHL(vec_float4) +VSX_REDIRECT_2RG(vec_udword2, vec_udword2, vec_mergesqh, vec_mergeh) +VSX_REDIRECT_2RG(vec_udword2, vec_udword2, vec_mergesql, vec_mergel) +VSX_REDIRECT_2RG(vec_dword2, vec_dword2, vec_mergesqh, vec_mergeh) +VSX_REDIRECT_2RG(vec_dword2, vec_dword2, vec_mergesql, vec_mergel) +VSX_REDIRECT_2RG(vec_double2, vec_double2, vec_mergesqh, vec_mergeh) +VSX_REDIRECT_2RG(vec_double2, vec_double2, vec_mergesql, vec_mergel) + + +// 2 and 4 channels interleave for all types except 2 lanes +#define VSX_IMPL_ST_INTERLEAVE(Tp, Tvec) \ +VSX_FINLINE(void) vec_st_interleave(const Tvec& a, const Tvec& b, Tp* ptr) \ +{ \ + vsx_stf(vec_mergeh(a, b), 0, ptr); \ + vsx_stf(vec_mergel(a, b), 16, ptr); \ +} \ +VSX_FINLINE(void) vec_st_interleave(const Tvec& a, const Tvec& b, \ + const Tvec& c, const Tvec& d, Tp* ptr) \ +{ \ + Tvec ac = vec_mergeh(a, c); \ + Tvec bd = vec_mergeh(b, d); \ + vsx_stf(vec_mergeh(ac, bd), 0, ptr); \ + vsx_stf(vec_mergel(ac, bd), 16, ptr); \ + ac = vec_mergel(a, c); \ + bd = vec_mergel(b, d); \ + vsx_stf(vec_mergeh(ac, bd), 32, ptr); \ + vsx_stf(vec_mergel(ac, bd), 48, ptr); \ +} +VSX_IMPL_ST_INTERLEAVE(uchar, vec_uchar16) +VSX_IMPL_ST_INTERLEAVE(schar, vec_char16) +VSX_IMPL_ST_INTERLEAVE(ushort, vec_ushort8) +VSX_IMPL_ST_INTERLEAVE(short, vec_short8) +VSX_IMPL_ST_INTERLEAVE(uint, vec_uint4) +VSX_IMPL_ST_INTERLEAVE(int, vec_int4) +VSX_IMPL_ST_INTERLEAVE(float, vec_float4) + +// 2 and 4 channels deinterleave for 16 lanes +#define VSX_IMPL_ST_DINTERLEAVE_8(Tp, Tvec) \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b) \ +{ \ + Tvec v0 = vsx_ld(0, ptr); \ + Tvec v1 = vsx_ld(16, ptr); \ + a = vec_mergesqe(v0, v1); \ + b = vec_mergesqo(v0, v1); \ +} \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b, \ + Tvec& c, Tvec& d) \ +{ \ + Tvec v0 = vsx_ld(0, ptr); \ + Tvec v1 = vsx_ld(16, ptr); \ + Tvec v2 = vsx_ld(32, ptr); \ + Tvec v3 = vsx_ld(48, ptr); \ + Tvec m0 = vec_mergesqe(v0, v1); \ + Tvec m1 = vec_mergesqe(v2, v3); \ + a = vec_mergesqe(m0, m1); \ + c = vec_mergesqo(m0, m1); \ + m0 = vec_mergesqo(v0, v1); \ + m1 = vec_mergesqo(v2, v3); \ + b = vec_mergesqe(m0, m1); \ + d = vec_mergesqo(m0, m1); \ +} +VSX_IMPL_ST_DINTERLEAVE_8(uchar, vec_uchar16) +VSX_IMPL_ST_DINTERLEAVE_8(schar, vec_char16) + +// 2 and 4 channels deinterleave for 8 lanes +#define VSX_IMPL_ST_DINTERLEAVE_16(Tp, Tvec) \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b) \ +{ \ + Tvec v0 = vsx_ld(0, ptr); \ + Tvec v1 = vsx_ld(8, ptr); \ + a = vec_mergesqe(v0, v1); \ + b = vec_mergesqo(v0, v1); \ +} \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b, \ + Tvec& c, Tvec& d) \ +{ \ + Tvec v0 = vsx_ld(0, ptr); \ + Tvec v1 = vsx_ld(8, ptr); \ + Tvec m0 = vec_mergeh(v0, v1); \ + Tvec m1 = vec_mergel(v0, v1); \ + Tvec ab0 = vec_mergeh(m0, m1); \ + Tvec cd0 = vec_mergel(m0, m1); \ + v0 = vsx_ld(16, ptr); \ + v1 = vsx_ld(24, ptr); \ + m0 = vec_mergeh(v0, v1); \ + m1 = vec_mergel(v0, v1); \ + Tvec ab1 = vec_mergeh(m0, m1); \ + Tvec cd1 = vec_mergel(m0, m1); \ + a = vec_mergesqh(ab0, ab1); \ + b = vec_mergesql(ab0, ab1); \ + c = vec_mergesqh(cd0, cd1); \ + d = vec_mergesql(cd0, cd1); \ +} +VSX_IMPL_ST_DINTERLEAVE_16(ushort, vec_ushort8) +VSX_IMPL_ST_DINTERLEAVE_16(short, vec_short8) + +// 2 and 4 channels deinterleave for 4 lanes +#define VSX_IMPL_ST_DINTERLEAVE_32(Tp, Tvec) \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b) \ +{ \ + a = vsx_ld(0, ptr); \ + b = vsx_ld(4, ptr); \ + Tvec m0 = vec_mergeh(a, b); \ + Tvec m1 = vec_mergel(a, b); \ + a = vec_mergeh(m0, m1); \ + b = vec_mergel(m0, m1); \ +} \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b, \ + Tvec& c, Tvec& d) \ +{ \ + Tvec v0 = vsx_ld(0, ptr); \ + Tvec v1 = vsx_ld(4, ptr); \ + Tvec v2 = vsx_ld(8, ptr); \ + Tvec v3 = vsx_ld(12, ptr); \ + Tvec m0 = vec_mergeh(v0, v2); \ + Tvec m1 = vec_mergeh(v1, v3); \ + a = vec_mergeh(m0, m1); \ + b = vec_mergel(m0, m1); \ + m0 = vec_mergel(v0, v2); \ + m1 = vec_mergel(v1, v3); \ + c = vec_mergeh(m0, m1); \ + d = vec_mergel(m0, m1); \ +} +VSX_IMPL_ST_DINTERLEAVE_32(uint, vec_uint4) +VSX_IMPL_ST_DINTERLEAVE_32(int, vec_int4) +VSX_IMPL_ST_DINTERLEAVE_32(float, vec_float4) + +// 2 and 4 channels interleave and deinterleave for 2 lanes +#define VSX_IMPL_ST_D_INTERLEAVE_64(Tp, Tvec, ld_func, st_func) \ +VSX_FINLINE(void) vec_st_interleave(const Tvec& a, const Tvec& b, Tp* ptr) \ +{ \ + st_func(vec_mergeh(a, b), 0, ptr); \ + st_func(vec_mergel(a, b), 2, ptr); \ +} \ +VSX_FINLINE(void) vec_st_interleave(const Tvec& a, const Tvec& b, \ + const Tvec& c, const Tvec& d, Tp* ptr) \ +{ \ + st_func(vec_mergeh(a, b), 0, ptr); \ + st_func(vec_mergeh(c, d), 2, ptr); \ + st_func(vec_mergel(a, b), 4, ptr); \ + st_func(vec_mergel(c, d), 6, ptr); \ +} \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b) \ +{ \ + Tvec m0 = ld_func(0, ptr); \ + Tvec m1 = ld_func(2, ptr); \ + a = vec_mergeh(m0, m1); \ + b = vec_mergel(m0, m1); \ +} \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b, \ + Tvec& c, Tvec& d) \ +{ \ + Tvec v0 = ld_func(0, ptr); \ + Tvec v1 = ld_func(2, ptr); \ + Tvec v2 = ld_func(4, ptr); \ + Tvec v3 = ld_func(6, ptr); \ + a = vec_mergeh(v0, v2); \ + b = vec_mergel(v0, v2); \ + c = vec_mergeh(v1, v3); \ + d = vec_mergel(v1, v3); \ +} +VSX_IMPL_ST_D_INTERLEAVE_64(int64, vec_dword2, vsx_ld2, vsx_st2) +VSX_IMPL_ST_D_INTERLEAVE_64(uint64, vec_udword2, vsx_ld2, vsx_st2) +VSX_IMPL_ST_D_INTERLEAVE_64(double, vec_double2, vsx_ld, vsx_st) + +/* 3 channels */ +#define VSX_IMPL_ST_INTERLEAVE_3CH_16(Tp, Tvec) \ +VSX_FINLINE(void) vec_st_interleave(const Tvec& a, const Tvec& b, \ + const Tvec& c, Tp* ptr) \ +{ \ + static const vec_uchar16 a12 = {0, 16, 0, 1, 17, 0, 2, 18, 0, 3, 19, 0, 4, 20, 0, 5}; \ + static const vec_uchar16 a123 = {0, 1, 16, 3, 4, 17, 6, 7, 18, 9, 10, 19, 12, 13, 20, 15}; \ + vsx_st(vec_perm(vec_perm(a, b, a12), c, a123), 0, ptr); \ + static const vec_uchar16 b12 = {21, 0, 6, 22, 0, 7, 23, 0, 8, 24, 0, 9, 25, 0, 10, 26}; \ + static const vec_uchar16 b123 = {0, 21, 2, 3, 22, 5, 6, 23, 8, 9, 24, 11, 12, 25, 14, 15}; \ + vsx_st(vec_perm(vec_perm(a, b, b12), c, b123), 16, ptr); \ + static const vec_uchar16 c12 = {0, 11, 27, 0, 12, 28, 0, 13, 29, 0, 14, 30, 0, 15, 31, 0}; \ + static const vec_uchar16 c123 = {26, 1, 2, 27, 4, 5, 28, 7, 8, 29, 10, 11, 30, 13, 14, 31}; \ + vsx_st(vec_perm(vec_perm(a, b, c12), c, c123), 32, ptr); \ +} \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b, Tvec& c) \ +{ \ + Tvec v1 = vsx_ld(0, ptr); \ + Tvec v2 = vsx_ld(16, ptr); \ + Tvec v3 = vsx_ld(32, ptr); \ + static const vec_uchar16 a12_perm = {0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 0, 0, 0, 0, 0}; \ + static const vec_uchar16 a123_perm = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 17, 20, 23, 26, 29}; \ + a = vec_perm(vec_perm(v1, v2, a12_perm), v3, a123_perm); \ + static const vec_uchar16 b12_perm = {1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 0, 0, 0, 0, 0}; \ + static const vec_uchar16 b123_perm = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 18, 21, 24, 27, 30}; \ + b = vec_perm(vec_perm(v1, v2, b12_perm), v3, b123_perm); \ + static const vec_uchar16 c12_perm = {2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 0, 0, 0, 0, 0, 0}; \ + static const vec_uchar16 c123_perm = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 19, 22, 25, 28, 31}; \ + c = vec_perm(vec_perm(v1, v2, c12_perm), v3, c123_perm); \ +} +VSX_IMPL_ST_INTERLEAVE_3CH_16(uchar, vec_uchar16) +VSX_IMPL_ST_INTERLEAVE_3CH_16(schar, vec_char16) + +#define VSX_IMPL_ST_INTERLEAVE_3CH_8(Tp, Tvec) \ +VSX_FINLINE(void) vec_st_interleave(const Tvec& a, const Tvec& b, \ + const Tvec& c, Tp* ptr) \ +{ \ + static const vec_uchar16 a12 = {0, 1, 16, 17, 0, 0, 2, 3, 18, 19, 0, 0, 4, 5, 20, 21}; \ + static const vec_uchar16 a123 = {0, 1, 2, 3, 16, 17, 6, 7, 8, 9, 18, 19, 12, 13, 14, 15}; \ + vsx_st(vec_perm(vec_perm(a, b, a12), c, a123), 0, ptr); \ + static const vec_uchar16 b12 = {0, 0, 6, 7, 22, 23, 0, 0, 8, 9, 24, 25, 0, 0, 10, 11}; \ + static const vec_uchar16 b123 = {20, 21, 2, 3, 4, 5, 22, 23, 8, 9, 10, 11, 24, 25, 14, 15}; \ + vsx_st(vec_perm(vec_perm(a, b, b12), c, b123), 8, ptr); \ + static const vec_uchar16 c12 = {26, 27, 0, 0, 12, 13, 28, 29, 0, 0, 14, 15, 30, 31, 0, 0}; \ + static const vec_uchar16 c123 = {0, 1, 26, 27, 4, 5, 6, 7, 28, 29, 10, 11, 12, 13, 30, 31}; \ + vsx_st(vec_perm(vec_perm(a, b, c12), c, c123), 16, ptr); \ +} \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b, Tvec& c) \ +{ \ + Tvec v1 = vsx_ld(0, ptr); \ + Tvec v2 = vsx_ld(8, ptr); \ + Tvec v3 = vsx_ld(16, ptr); \ + static const vec_uchar16 a12_perm = {0, 1, 6, 7, 12, 13, 18, 19, 24, 25, 30, 31, 0, 0, 0, 0}; \ + static const vec_uchar16 a123_perm = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 20, 21, 26, 27}; \ + a = vec_perm(vec_perm(v1, v2, a12_perm), v3, a123_perm); \ + static const vec_uchar16 b12_perm = {2, 3, 8, 9, 14, 15, 20, 21, 26, 27, 0, 0, 0, 0, 0, 0}; \ + static const vec_uchar16 b123_perm = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 22, 23, 28, 29}; \ + b = vec_perm(vec_perm(v1, v2, b12_perm), v3, b123_perm); \ + static const vec_uchar16 c12_perm = {4, 5, 10, 11, 16, 17, 22, 23, 28, 29, 0, 0, 0, 0, 0, 0}; \ + static const vec_uchar16 c123_perm = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 18, 19, 24, 25, 30, 31}; \ + c = vec_perm(vec_perm(v1, v2, c12_perm), v3, c123_perm); \ +} +VSX_IMPL_ST_INTERLEAVE_3CH_8(ushort, vec_ushort8) +VSX_IMPL_ST_INTERLEAVE_3CH_8(short, vec_short8) + +#define VSX_IMPL_ST_INTERLEAVE_3CH_4(Tp, Tvec) \ +VSX_FINLINE(void) vec_st_interleave(const Tvec& a, const Tvec& b, \ + const Tvec& c, Tp* ptr) \ +{ \ + Tvec hbc = vec_mergeh(b, c); \ + static const vec_uchar16 ahbc = {0, 1, 2, 3, 16, 17, 18, 19, 20, 21, 22, 23, 4, 5, 6, 7}; \ + vsx_st(vec_perm(a, hbc, ahbc), 0, ptr); \ + Tvec lab = vec_mergel(a, b); \ + vsx_st(vec_sld(lab, hbc, 8), 4, ptr); \ + static const vec_uchar16 clab = {8, 9, 10, 11, 24, 25, 26, 27, 28, 29, 30, 31, 12, 13, 14, 15};\ + vsx_st(vec_perm(c, lab, clab), 8, ptr); \ +} \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, Tvec& b, Tvec& c) \ +{ \ + Tvec v1 = vsx_ld(0, ptr); \ + Tvec v2 = vsx_ld(4, ptr); \ + Tvec v3 = vsx_ld(8, ptr); \ + static const vec_uchar16 flp = {0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19, 28, 29, 30, 31}; \ + a = vec_perm(v1, vec_sld(v3, v2, 8), flp); \ + static const vec_uchar16 flp2 = {28, 29, 30, 31, 0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19}; \ + b = vec_perm(v2, vec_sld(v1, v3, 8), flp2); \ + c = vec_perm(vec_sld(v2, v1, 8), v3, flp); \ +} +VSX_IMPL_ST_INTERLEAVE_3CH_4(uint, vec_uint4) +VSX_IMPL_ST_INTERLEAVE_3CH_4(int, vec_int4) +VSX_IMPL_ST_INTERLEAVE_3CH_4(float, vec_float4) + +#define VSX_IMPL_ST_INTERLEAVE_3CH_2(Tp, Tvec, ld_func, st_func) \ +VSX_FINLINE(void) vec_st_interleave(const Tvec& a, const Tvec& b, \ + const Tvec& c, Tp* ptr) \ +{ \ + st_func(vec_mergeh(a, b), 0, ptr); \ + st_func(vec_permi(c, a, 1), 2, ptr); \ + st_func(vec_mergel(b, c), 4, ptr); \ +} \ +VSX_FINLINE(void) vec_ld_deinterleave(const Tp* ptr, Tvec& a, \ + Tvec& b, Tvec& c) \ +{ \ + Tvec v1 = ld_func(0, ptr); \ + Tvec v2 = ld_func(2, ptr); \ + Tvec v3 = ld_func(4, ptr); \ + a = vec_permi(v1, v2, 1); \ + b = vec_permi(v1, v3, 2); \ + c = vec_permi(v2, v3, 1); \ +} +VSX_IMPL_ST_INTERLEAVE_3CH_2(int64, vec_dword2, vsx_ld2, vsx_st2) +VSX_IMPL_ST_INTERLEAVE_3CH_2(uint64, vec_udword2, vsx_ld2, vsx_st2) +VSX_IMPL_ST_INTERLEAVE_3CH_2(double, vec_double2, vsx_ld, vsx_st) + +#endif // CV_VSX + +//! @} + +#endif // OPENCV_HAL_VSX_UTILS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/cvconfig.h b/duix-sdk/src/main/cpp/third/arm/include/opencv2/cvconfig.h new file mode 100644 index 0000000..ceeeb8d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/cvconfig.h @@ -0,0 +1,149 @@ +#ifndef OPENCV_CVCONFIG_H_INCLUDED +#define OPENCV_CVCONFIG_H_INCLUDED + +/* OpenCV compiled as static or dynamic libs */ +/* #undef BUILD_SHARED_LIBS */ + +/* OpenCV intrinsics optimized code */ +#define CV_ENABLE_INTRINSICS + +/* OpenCV additional optimized code */ +/* #undef CV_DISABLE_OPTIMIZATION */ + +/* Compile for 'real' NVIDIA GPU architectures */ +#define CUDA_ARCH_BIN "" + +/* NVIDIA GPU features are used */ +#define CUDA_ARCH_FEATURES "" + +/* Compile for 'virtual' NVIDIA PTX architectures */ +#define CUDA_ARCH_PTX "" + +/* AMD's Basic Linear Algebra Subprograms Library*/ +/* #undef HAVE_CLAMDBLAS */ + +/* AMD's OpenCL Fast Fourier Transform Library*/ +/* #undef HAVE_CLAMDFFT */ + +/* Clp support */ +/* #undef HAVE_CLP */ + +/* NVIDIA CUDA Runtime API*/ +/* #undef HAVE_CUDA */ + +/* NVIDIA CUDA Basic Linear Algebra Subprograms (BLAS) API*/ +/* #undef HAVE_CUBLAS */ + +/* NVIDIA CUDA Deep Neural Network (cuDNN) API*/ +/* #undef HAVE_CUDNN */ + +/* NVIDIA CUDA Fast Fourier Transform (FFT) API*/ +/* #undef HAVE_CUFFT */ + +/* DirectX */ +/* #undef HAVE_DIRECTX */ +/* #undef HAVE_DIRECTX_NV12 */ +/* #undef HAVE_D3D11 */ +/* #undef HAVE_D3D10 */ +/* #undef HAVE_D3D9 */ + +/* Eigen Matrix & Linear Algebra Library */ +/* #undef HAVE_EIGEN */ + +/* Geospatial Data Abstraction Library */ +/* #undef HAVE_GDAL */ + +/* Halide support */ +/* #undef HAVE_HALIDE */ + +/* Vulkan support */ +/* #undef HAVE_VULKAN */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_INTTYPES_H */ + +/* Intel Integrated Performance Primitives */ +/* #undef HAVE_IPP */ +/* #undef HAVE_IPP_ICV */ +/* #undef HAVE_IPP_IW */ +/* #undef HAVE_IPP_IW_LL */ + +/* JPEG-2000 codec */ +/* #undef HAVE_OPENJPEG */ +/* #undef HAVE_JASPER */ + +/* IJG JPEG codec */ +/* #undef HAVE_JPEG */ + +/* libpng/png.h needs to be included */ +/* #undef HAVE_LIBPNG_PNG_H */ + +/* GDCM DICOM codec */ +/* #undef HAVE_GDCM */ + +/* NVIDIA Video Decoding API*/ +/* #undef HAVE_NVCUVID */ +/* #undef HAVE_NVCUVID_HEADER */ +/* #undef HAVE_DYNLINK_NVCUVID_HEADER */ + +/* NVIDIA Video Encoding API*/ +/* #undef HAVE_NVCUVENC */ + +/* OpenCL Support */ +/* #undef HAVE_OPENCL */ +/* #undef HAVE_OPENCL_STATIC */ +/* #undef HAVE_OPENCL_SVM */ + +/* NVIDIA OpenCL D3D Extensions support */ +/* #undef HAVE_OPENCL_D3D11_NV */ + +/* OpenEXR codec */ +/* #undef HAVE_OPENEXR */ + +/* OpenGL support*/ +/* #undef HAVE_OPENGL */ + +/* PNG codec */ +/* #undef HAVE_PNG */ + +/* Posix threads (pthreads) */ +#define HAVE_PTHREAD + +/* parallel_for with pthreads */ +/* #undef HAVE_PTHREADS_PF */ + +/* Intel Threading Building Blocks */ +/* #undef HAVE_TBB */ + +/* Ste||ar Group High Performance ParallelX */ +/* #undef HAVE_HPX */ + +/* TIFF codec */ +/* #undef HAVE_TIFF */ + +/* Define if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* VA library (libva) */ +/* #undef HAVE_VA */ + +/* Intel VA-API/OpenCL */ +/* #undef HAVE_VA_INTEL */ + +/* Lapack */ +/* #undef HAVE_LAPACK */ + +/* Library was compiled with functions instrumentation */ +/* #undef ENABLE_INSTRUMENTATION */ + +/* OpenVX */ +/* #undef HAVE_OPENVX */ + +/* OpenCV trace utilities */ +/* #undef OPENCV_TRACE */ + +/* Library QR-code decoding */ +/* #undef HAVE_QUIRC */ + +#endif // OPENCV_CVCONFIG_H_INCLUDED diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/features2d.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/features2d.hpp new file mode 100644 index 0000000..952d24c --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/features2d.hpp @@ -0,0 +1,1535 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_FEATURES_2D_HPP +#define OPENCV_FEATURES_2D_HPP + +#include "opencv2/opencv_modules.hpp" +#include "opencv2/core.hpp" + +#ifdef HAVE_OPENCV_FLANN +#include "opencv2/flann/miniflann.hpp" +#endif + +/** + @defgroup features2d 2D Features Framework + @{ + @defgroup features2d_main Feature Detection and Description + @defgroup features2d_match Descriptor Matchers + +Matchers of keypoint descriptors in OpenCV have wrappers with a common interface that enables you to +easily switch between different algorithms solving the same problem. This section is devoted to +matching descriptors that are represented as vectors in a multidimensional space. All objects that +implement vector descriptor matchers inherit the DescriptorMatcher interface. + + @defgroup features2d_draw Drawing Function of Keypoints and Matches + @defgroup features2d_category Object Categorization + +This section describes approaches based on local 2D features and used to categorize objects. + + @defgroup feature2d_hal Hardware Acceleration Layer + @{ + @defgroup features2d_hal_interface Interface + @} + @} + */ + +namespace cv +{ + +//! @addtogroup features2d_main +//! @{ + +// //! writes vector of keypoints to the file storage +// CV_EXPORTS void write(FileStorage& fs, const String& name, const std::vector& keypoints); +// //! reads vector of keypoints from the specified file storage node +// CV_EXPORTS void read(const FileNode& node, CV_OUT std::vector& keypoints); + +/** @brief A class filters a vector of keypoints. + + Because now it is difficult to provide a convenient interface for all usage scenarios of the + keypoints filter class, it has only several needed by now static methods. + */ +class CV_EXPORTS KeyPointsFilter +{ +public: + KeyPointsFilter(){} + + /* + * Remove keypoints within borderPixels of an image edge. + */ + static void runByImageBorder( std::vector& keypoints, Size imageSize, int borderSize ); + /* + * Remove keypoints of sizes out of range. + */ + static void runByKeypointSize( std::vector& keypoints, float minSize, + float maxSize=FLT_MAX ); + /* + * Remove keypoints from some image by mask for pixels of this image. + */ + static void runByPixelsMask( std::vector& keypoints, const Mat& mask ); + /* + * Remove duplicated keypoints. + */ + static void removeDuplicated( std::vector& keypoints ); + /* + * Remove duplicated keypoints and sort the remaining keypoints + */ + static void removeDuplicatedSorted( std::vector& keypoints ); + + /* + * Retain the specified number of the best keypoints (according to the response) + */ + static void retainBest( std::vector& keypoints, int npoints ); +}; + + +/************************************ Base Classes ************************************/ + +/** @brief Abstract base class for 2D image feature detectors and descriptor extractors +*/ +#ifdef __EMSCRIPTEN__ +class CV_EXPORTS_W Feature2D : public Algorithm +#else +class CV_EXPORTS_W Feature2D : public virtual Algorithm +#endif +{ +public: + virtual ~Feature2D(); + + /** @brief Detects keypoints in an image (first variant) or image set (second variant). + + @param image Image. + @param keypoints The detected keypoints. In the second variant of the method keypoints[i] is a set + of keypoints detected in images[i] . + @param mask Mask specifying where to look for keypoints (optional). It must be a 8-bit integer + matrix with non-zero values in the region of interest. + */ + CV_WRAP virtual void detect( InputArray image, + CV_OUT std::vector& keypoints, + InputArray mask=noArray() ); + + /** @overload + @param images Image set. + @param keypoints The detected keypoints. In the second variant of the method keypoints[i] is a set + of keypoints detected in images[i] . + @param masks Masks for each input image specifying where to look for keypoints (optional). + masks[i] is a mask for images[i]. + */ + CV_WRAP virtual void detect( InputArrayOfArrays images, + CV_OUT std::vector >& keypoints, + InputArrayOfArrays masks=noArray() ); + + /** @brief Computes the descriptors for a set of keypoints detected in an image (first variant) or image set + (second variant). + + @param image Image. + @param keypoints Input collection of keypoints. Keypoints for which a descriptor cannot be + computed are removed. Sometimes new keypoints can be added, for example: SIFT duplicates keypoint + with several dominant orientations (for each orientation). + @param descriptors Computed descriptors. In the second variant of the method descriptors[i] are + descriptors computed for a keypoints[i]. Row j is the keypoints (or keypoints[i]) is the + descriptor for keypoint j-th keypoint. + */ + CV_WRAP virtual void compute( InputArray image, + CV_OUT CV_IN_OUT std::vector& keypoints, + OutputArray descriptors ); + + /** @overload + + @param images Image set. + @param keypoints Input collection of keypoints. Keypoints for which a descriptor cannot be + computed are removed. Sometimes new keypoints can be added, for example: SIFT duplicates keypoint + with several dominant orientations (for each orientation). + @param descriptors Computed descriptors. In the second variant of the method descriptors[i] are + descriptors computed for a keypoints[i]. Row j is the keypoints (or keypoints[i]) is the + descriptor for keypoint j-th keypoint. + */ + CV_WRAP virtual void compute( InputArrayOfArrays images, + CV_OUT CV_IN_OUT std::vector >& keypoints, + OutputArrayOfArrays descriptors ); + + /** Detects keypoints and computes the descriptors */ + CV_WRAP virtual void detectAndCompute( InputArray image, InputArray mask, + CV_OUT std::vector& keypoints, + OutputArray descriptors, + bool useProvidedKeypoints=false ); + + CV_WRAP virtual int descriptorSize() const; + CV_WRAP virtual int descriptorType() const; + CV_WRAP virtual int defaultNorm() const; + + CV_WRAP void write( const String& fileName ) const; + + CV_WRAP void read( const String& fileName ); + + virtual void write( FileStorage&) const CV_OVERRIDE; + + // see corresponding cv::Algorithm method + CV_WRAP virtual void read( const FileNode&) CV_OVERRIDE; + + //! Return true if detector object is empty + CV_WRAP virtual bool empty() const CV_OVERRIDE; + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; + + // see corresponding cv::Algorithm method + CV_WRAP inline void write(const Ptr& fs, const String& name = String()) const { Algorithm::write(fs, name); } +}; + +/** Feature detectors in OpenCV have wrappers with a common interface that enables you to easily switch +between different algorithms solving the same problem. All objects that implement keypoint detectors +inherit the FeatureDetector interface. */ +typedef Feature2D FeatureDetector; + +/** Extractors of keypoint descriptors in OpenCV have wrappers with a common interface that enables you +to easily switch between different algorithms solving the same problem. This section is devoted to +computing descriptors represented as vectors in a multidimensional space. All objects that implement +the vector descriptor extractors inherit the DescriptorExtractor interface. + */ +typedef Feature2D DescriptorExtractor; + + +/** @brief Class for implementing the wrapper which makes detectors and extractors to be affine invariant, +described as ASIFT in @cite YM11 . +*/ +class CV_EXPORTS_W AffineFeature : public Feature2D +{ +public: + /** + @param backend The detector/extractor you want to use as backend. + @param maxTilt The highest power index of tilt factor. 5 is used in the paper as tilt sampling range n. + @param minTilt The lowest power index of tilt factor. 0 is used in the paper. + @param tiltStep Tilt sampling step \f$\delta_t\f$ in Algorithm 1 in the paper. + @param rotateStepBase Rotation sampling step factor b in Algorithm 1 in the paper. + */ + CV_WRAP static Ptr create(const Ptr& backend, + int maxTilt = 5, int minTilt = 0, float tiltStep = 1.4142135623730951f, float rotateStepBase = 72); + + CV_WRAP virtual void setViewParams(const std::vector& tilts, const std::vector& rolls) = 0; + CV_WRAP virtual void getViewParams(std::vector& tilts, std::vector& rolls) const = 0; + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; +}; + +typedef AffineFeature AffineFeatureDetector; +typedef AffineFeature AffineDescriptorExtractor; + + +/** @brief Class for extracting keypoints and computing descriptors using the Scale Invariant Feature Transform +(SIFT) algorithm by D. Lowe @cite Lowe04 . +*/ +class CV_EXPORTS_W SIFT : public Feature2D +{ +public: + /** + @param nfeatures The number of best features to retain. The features are ranked by their scores + (measured in SIFT algorithm as the local contrast) + + @param nOctaveLayers The number of layers in each octave. 3 is the value used in D. Lowe paper. The + number of octaves is computed automatically from the image resolution. + + @param contrastThreshold The contrast threshold used to filter out weak features in semi-uniform + (low-contrast) regions. The larger the threshold, the less features are produced by the detector. + + @note The contrast threshold will be divided by nOctaveLayers when the filtering is applied. When + nOctaveLayers is set to default and if you want to use the value used in D. Lowe paper, 0.03, set + this argument to 0.09. + + @param edgeThreshold The threshold used to filter out edge-like features. Note that the its meaning + is different from the contrastThreshold, i.e. the larger the edgeThreshold, the less features are + filtered out (more features are retained). + + @param sigma The sigma of the Gaussian applied to the input image at the octave \#0. If your image + is captured with a weak camera with soft lenses, you might want to reduce the number. + */ + CV_WRAP static Ptr create(int nfeatures = 0, int nOctaveLayers = 3, + double contrastThreshold = 0.04, double edgeThreshold = 10, + double sigma = 1.6); + + /** @brief Create SIFT with specified descriptorType. + @param nfeatures The number of best features to retain. The features are ranked by their scores + (measured in SIFT algorithm as the local contrast) + + @param nOctaveLayers The number of layers in each octave. 3 is the value used in D. Lowe paper. The + number of octaves is computed automatically from the image resolution. + + @param contrastThreshold The contrast threshold used to filter out weak features in semi-uniform + (low-contrast) regions. The larger the threshold, the less features are produced by the detector. + + @note The contrast threshold will be divided by nOctaveLayers when the filtering is applied. When + nOctaveLayers is set to default and if you want to use the value used in D. Lowe paper, 0.03, set + this argument to 0.09. + + @param edgeThreshold The threshold used to filter out edge-like features. Note that the its meaning + is different from the contrastThreshold, i.e. the larger the edgeThreshold, the less features are + filtered out (more features are retained). + + @param sigma The sigma of the Gaussian applied to the input image at the octave \#0. If your image + is captured with a weak camera with soft lenses, you might want to reduce the number. + + @param descriptorType The type of descriptors. Only CV_32F and CV_8U are supported. + */ + CV_WRAP static Ptr create(int nfeatures, int nOctaveLayers, + double contrastThreshold, double edgeThreshold, + double sigma, int descriptorType); + + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; +}; + +typedef SIFT SiftFeatureDetector; +typedef SIFT SiftDescriptorExtractor; + + +/** @brief Class implementing the BRISK keypoint detector and descriptor extractor, described in @cite LCS11 . + */ +class CV_EXPORTS_W BRISK : public Feature2D +{ +public: + /** @brief The BRISK constructor + + @param thresh AGAST detection threshold score. + @param octaves detection octaves. Use 0 to do single scale. + @param patternScale apply this scale to the pattern used for sampling the neighbourhood of a + keypoint. + */ + CV_WRAP static Ptr create(int thresh=30, int octaves=3, float patternScale=1.0f); + + /** @brief The BRISK constructor for a custom pattern + + @param radiusList defines the radii (in pixels) where the samples around a keypoint are taken (for + keypoint scale 1). + @param numberList defines the number of sampling points on the sampling circle. Must be the same + size as radiusList.. + @param dMax threshold for the short pairings used for descriptor formation (in pixels for keypoint + scale 1). + @param dMin threshold for the long pairings used for orientation determination (in pixels for + keypoint scale 1). + @param indexChange index remapping of the bits. */ + CV_WRAP static Ptr create(const std::vector &radiusList, const std::vector &numberList, + float dMax=5.85f, float dMin=8.2f, const std::vector& indexChange=std::vector()); + + /** @brief The BRISK constructor for a custom pattern, detection threshold and octaves + + @param thresh AGAST detection threshold score. + @param octaves detection octaves. Use 0 to do single scale. + @param radiusList defines the radii (in pixels) where the samples around a keypoint are taken (for + keypoint scale 1). + @param numberList defines the number of sampling points on the sampling circle. Must be the same + size as radiusList.. + @param dMax threshold for the short pairings used for descriptor formation (in pixels for keypoint + scale 1). + @param dMin threshold for the long pairings used for orientation determination (in pixels for + keypoint scale 1). + @param indexChange index remapping of the bits. */ + CV_WRAP static Ptr create(int thresh, int octaves, const std::vector &radiusList, + const std::vector &numberList, float dMax=5.85f, float dMin=8.2f, + const std::vector& indexChange=std::vector()); + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; + + /** @brief Set detection threshold. + @param threshold AGAST detection threshold score. + */ + CV_WRAP virtual void setThreshold(int threshold) { CV_UNUSED(threshold); return; } + CV_WRAP virtual int getThreshold() const { return -1; } + + /** @brief Set detection octaves. + @param octaves detection octaves. Use 0 to do single scale. + */ + CV_WRAP virtual void setOctaves(int octaves) { CV_UNUSED(octaves); return; } + CV_WRAP virtual int getOctaves() const { return -1; } +}; + +/** @brief Class implementing the ORB (*oriented BRIEF*) keypoint detector and descriptor extractor + +described in @cite RRKB11 . The algorithm uses FAST in pyramids to detect stable keypoints, selects +the strongest features using FAST or Harris response, finds their orientation using first-order +moments and computes the descriptors using BRIEF (where the coordinates of random point pairs (or +k-tuples) are rotated according to the measured orientation). + */ +class CV_EXPORTS_W ORB : public Feature2D +{ +public: + enum ScoreType { HARRIS_SCORE=0, FAST_SCORE=1 }; + static const int kBytes = 32; + + /** @brief The ORB constructor + + @param nfeatures The maximum number of features to retain. + @param scaleFactor Pyramid decimation ratio, greater than 1. scaleFactor==2 means the classical + pyramid, where each next level has 4x less pixels than the previous, but such a big scale factor + will degrade feature matching scores dramatically. On the other hand, too close to 1 scale factor + will mean that to cover certain scale range you will need more pyramid levels and so the speed + will suffer. + @param nlevels The number of pyramid levels. The smallest level will have linear size equal to + input_image_linear_size/pow(scaleFactor, nlevels - firstLevel). + @param edgeThreshold This is size of the border where the features are not detected. It should + roughly match the patchSize parameter. + @param firstLevel The level of pyramid to put source image to. Previous layers are filled + with upscaled source image. + @param WTA_K The number of points that produce each element of the oriented BRIEF descriptor. The + default value 2 means the BRIEF where we take a random point pair and compare their brightnesses, + so we get 0/1 response. Other possible values are 3 and 4. For example, 3 means that we take 3 + random points (of course, those point coordinates are random, but they are generated from the + pre-defined seed, so each element of BRIEF descriptor is computed deterministically from the pixel + rectangle), find point of maximum brightness and output index of the winner (0, 1 or 2). Such + output will occupy 2 bits, and therefore it will need a special variant of Hamming distance, + denoted as NORM_HAMMING2 (2 bits per bin). When WTA_K=4, we take 4 random points to compute each + bin (that will also occupy 2 bits with possible values 0, 1, 2 or 3). + @param scoreType The default HARRIS_SCORE means that Harris algorithm is used to rank features + (the score is written to KeyPoint::score and is used to retain best nfeatures features); + FAST_SCORE is alternative value of the parameter that produces slightly less stable keypoints, + but it is a little faster to compute. + @param patchSize size of the patch used by the oriented BRIEF descriptor. Of course, on smaller + pyramid layers the perceived image area covered by a feature will be larger. + @param fastThreshold the fast threshold + */ + CV_WRAP static Ptr create(int nfeatures=500, float scaleFactor=1.2f, int nlevels=8, int edgeThreshold=31, + int firstLevel=0, int WTA_K=2, ORB::ScoreType scoreType=ORB::HARRIS_SCORE, int patchSize=31, int fastThreshold=20); + + CV_WRAP virtual void setMaxFeatures(int maxFeatures) = 0; + CV_WRAP virtual int getMaxFeatures() const = 0; + + CV_WRAP virtual void setScaleFactor(double scaleFactor) = 0; + CV_WRAP virtual double getScaleFactor() const = 0; + + CV_WRAP virtual void setNLevels(int nlevels) = 0; + CV_WRAP virtual int getNLevels() const = 0; + + CV_WRAP virtual void setEdgeThreshold(int edgeThreshold) = 0; + CV_WRAP virtual int getEdgeThreshold() const = 0; + + CV_WRAP virtual void setFirstLevel(int firstLevel) = 0; + CV_WRAP virtual int getFirstLevel() const = 0; + + CV_WRAP virtual void setWTA_K(int wta_k) = 0; + CV_WRAP virtual int getWTA_K() const = 0; + + CV_WRAP virtual void setScoreType(ORB::ScoreType scoreType) = 0; + CV_WRAP virtual ORB::ScoreType getScoreType() const = 0; + + CV_WRAP virtual void setPatchSize(int patchSize) = 0; + CV_WRAP virtual int getPatchSize() const = 0; + + CV_WRAP virtual void setFastThreshold(int fastThreshold) = 0; + CV_WRAP virtual int getFastThreshold() const = 0; + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; +}; + +/** @brief Maximally stable extremal region extractor + +The class encapsulates all the parameters of the %MSER extraction algorithm (see [wiki +article](http://en.wikipedia.org/wiki/Maximally_stable_extremal_regions)). + +- there are two different implementation of %MSER: one for grey image, one for color image + +- the grey image algorithm is taken from: @cite nister2008linear ; the paper claims to be faster +than union-find method; it actually get 1.5~2m/s on my centrino L7200 1.2GHz laptop. + +- the color image algorithm is taken from: @cite forssen2007maximally ; it should be much slower +than grey image method ( 3~4 times ) + +- (Python) A complete example showing the use of the %MSER detector can be found at samples/python/mser.py +*/ +class CV_EXPORTS_W MSER : public Feature2D +{ +public: + /** @brief Full constructor for %MSER detector + + @param delta it compares \f$(size_{i}-size_{i-delta})/size_{i-delta}\f$ + @param min_area prune the area which smaller than minArea + @param max_area prune the area which bigger than maxArea + @param max_variation prune the area have similar size to its children + @param min_diversity for color image, trace back to cut off mser with diversity less than min_diversity + @param max_evolution for color image, the evolution steps + @param area_threshold for color image, the area threshold to cause re-initialize + @param min_margin for color image, ignore too small margin + @param edge_blur_size for color image, the aperture size for edge blur + */ + CV_WRAP static Ptr create( int delta=5, int min_area=60, int max_area=14400, + double max_variation=0.25, double min_diversity=.2, + int max_evolution=200, double area_threshold=1.01, + double min_margin=0.003, int edge_blur_size=5 ); + + /** @brief Detect %MSER regions + + @param image input image (8UC1, 8UC3 or 8UC4, must be greater or equal than 3x3) + @param msers resulting list of point sets + @param bboxes resulting bounding boxes + */ + CV_WRAP virtual void detectRegions( InputArray image, + CV_OUT std::vector >& msers, + CV_OUT std::vector& bboxes ) = 0; + + CV_WRAP virtual void setDelta(int delta) = 0; + CV_WRAP virtual int getDelta() const = 0; + + CV_WRAP virtual void setMinArea(int minArea) = 0; + CV_WRAP virtual int getMinArea() const = 0; + + CV_WRAP virtual void setMaxArea(int maxArea) = 0; + CV_WRAP virtual int getMaxArea() const = 0; + + CV_WRAP virtual void setPass2Only(bool f) = 0; + CV_WRAP virtual bool getPass2Only() const = 0; + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; +}; + +//! @} features2d_main + +//! @addtogroup features2d_main +//! @{ + +/** @brief Wrapping class for feature detection using the FAST method. : + */ +class CV_EXPORTS_W FastFeatureDetector : public Feature2D +{ +public: + enum DetectorType + { + TYPE_5_8 = 0, TYPE_7_12 = 1, TYPE_9_16 = 2 + }; + enum + { + THRESHOLD = 10000, NONMAX_SUPPRESSION=10001, FAST_N=10002 + }; + + + CV_WRAP static Ptr create( int threshold=10, + bool nonmaxSuppression=true, + FastFeatureDetector::DetectorType type=FastFeatureDetector::TYPE_9_16 ); + + CV_WRAP virtual void setThreshold(int threshold) = 0; + CV_WRAP virtual int getThreshold() const = 0; + + CV_WRAP virtual void setNonmaxSuppression(bool f) = 0; + CV_WRAP virtual bool getNonmaxSuppression() const = 0; + + CV_WRAP virtual void setType(FastFeatureDetector::DetectorType type) = 0; + CV_WRAP virtual FastFeatureDetector::DetectorType getType() const = 0; + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; +}; + +/** @overload */ +CV_EXPORTS void FAST( InputArray image, CV_OUT std::vector& keypoints, + int threshold, bool nonmaxSuppression=true ); + +/** @brief Detects corners using the FAST algorithm + +@param image grayscale image where keypoints (corners) are detected. +@param keypoints keypoints detected on the image. +@param threshold threshold on difference between intensity of the central pixel and pixels of a +circle around this pixel. +@param nonmaxSuppression if true, non-maximum suppression is applied to detected corners +(keypoints). +@param type one of the three neighborhoods as defined in the paper: +FastFeatureDetector::TYPE_9_16, FastFeatureDetector::TYPE_7_12, +FastFeatureDetector::TYPE_5_8 + +Detects corners using the FAST algorithm by @cite Rosten06 . + +@note In Python API, types are given as cv.FAST_FEATURE_DETECTOR_TYPE_5_8, +cv.FAST_FEATURE_DETECTOR_TYPE_7_12 and cv.FAST_FEATURE_DETECTOR_TYPE_9_16. For corner +detection, use cv.FAST.detect() method. + */ +CV_EXPORTS void FAST( InputArray image, CV_OUT std::vector& keypoints, + int threshold, bool nonmaxSuppression, FastFeatureDetector::DetectorType type ); + +//! @} features2d_main + +//! @addtogroup features2d_main +//! @{ + +/** @brief Wrapping class for feature detection using the AGAST method. : + */ +class CV_EXPORTS_W AgastFeatureDetector : public Feature2D +{ +public: + enum DetectorType + { + AGAST_5_8 = 0, AGAST_7_12d = 1, AGAST_7_12s = 2, OAST_9_16 = 3, + }; + + enum + { + THRESHOLD = 10000, NONMAX_SUPPRESSION = 10001, + }; + + CV_WRAP static Ptr create( int threshold=10, + bool nonmaxSuppression=true, + AgastFeatureDetector::DetectorType type = AgastFeatureDetector::OAST_9_16); + + CV_WRAP virtual void setThreshold(int threshold) = 0; + CV_WRAP virtual int getThreshold() const = 0; + + CV_WRAP virtual void setNonmaxSuppression(bool f) = 0; + CV_WRAP virtual bool getNonmaxSuppression() const = 0; + + CV_WRAP virtual void setType(AgastFeatureDetector::DetectorType type) = 0; + CV_WRAP virtual AgastFeatureDetector::DetectorType getType() const = 0; + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; +}; + +/** @overload */ +CV_EXPORTS void AGAST( InputArray image, CV_OUT std::vector& keypoints, + int threshold, bool nonmaxSuppression=true ); + +/** @brief Detects corners using the AGAST algorithm + +@param image grayscale image where keypoints (corners) are detected. +@param keypoints keypoints detected on the image. +@param threshold threshold on difference between intensity of the central pixel and pixels of a +circle around this pixel. +@param nonmaxSuppression if true, non-maximum suppression is applied to detected corners +(keypoints). +@param type one of the four neighborhoods as defined in the paper: +AgastFeatureDetector::AGAST_5_8, AgastFeatureDetector::AGAST_7_12d, +AgastFeatureDetector::AGAST_7_12s, AgastFeatureDetector::OAST_9_16 + +For non-Intel platforms, there is a tree optimised variant of AGAST with same numerical results. +The 32-bit binary tree tables were generated automatically from original code using perl script. +The perl script and examples of tree generation are placed in features2d/doc folder. +Detects corners using the AGAST algorithm by @cite mair2010_agast . + + */ +CV_EXPORTS void AGAST( InputArray image, CV_OUT std::vector& keypoints, + int threshold, bool nonmaxSuppression, AgastFeatureDetector::DetectorType type ); + +/** @brief Wrapping class for feature detection using the goodFeaturesToTrack function. : + */ +class CV_EXPORTS_W GFTTDetector : public Feature2D +{ +public: + CV_WRAP static Ptr create( int maxCorners=1000, double qualityLevel=0.01, double minDistance=1, + int blockSize=3, bool useHarrisDetector=false, double k=0.04 ); + CV_WRAP static Ptr create( int maxCorners, double qualityLevel, double minDistance, + int blockSize, int gradiantSize, bool useHarrisDetector=false, double k=0.04 ); + CV_WRAP virtual void setMaxFeatures(int maxFeatures) = 0; + CV_WRAP virtual int getMaxFeatures() const = 0; + + CV_WRAP virtual void setQualityLevel(double qlevel) = 0; + CV_WRAP virtual double getQualityLevel() const = 0; + + CV_WRAP virtual void setMinDistance(double minDistance) = 0; + CV_WRAP virtual double getMinDistance() const = 0; + + CV_WRAP virtual void setBlockSize(int blockSize) = 0; + CV_WRAP virtual int getBlockSize() const = 0; + + CV_WRAP virtual void setHarrisDetector(bool val) = 0; + CV_WRAP virtual bool getHarrisDetector() const = 0; + + CV_WRAP virtual void setK(double k) = 0; + CV_WRAP virtual double getK() const = 0; + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; +}; + +/** @brief Class for extracting blobs from an image. : + +The class implements a simple algorithm for extracting blobs from an image: + +1. Convert the source image to binary images by applying thresholding with several thresholds from + minThreshold (inclusive) to maxThreshold (exclusive) with distance thresholdStep between + neighboring thresholds. +2. Extract connected components from every binary image by findContours and calculate their + centers. +3. Group centers from several binary images by their coordinates. Close centers form one group that + corresponds to one blob, which is controlled by the minDistBetweenBlobs parameter. +4. From the groups, estimate final centers of blobs and their radiuses and return as locations and + sizes of keypoints. + +This class performs several filtrations of returned blobs. You should set filterBy\* to true/false +to turn on/off corresponding filtration. Available filtrations: + +- **By color**. This filter compares the intensity of a binary image at the center of a blob to +blobColor. If they differ, the blob is filtered out. Use blobColor = 0 to extract dark blobs +and blobColor = 255 to extract light blobs. +- **By area**. Extracted blobs have an area between minArea (inclusive) and maxArea (exclusive). +- **By circularity**. Extracted blobs have circularity +(\f$\frac{4*\pi*Area}{perimeter * perimeter}\f$) between minCircularity (inclusive) and +maxCircularity (exclusive). +- **By ratio of the minimum inertia to maximum inertia**. Extracted blobs have this ratio +between minInertiaRatio (inclusive) and maxInertiaRatio (exclusive). +- **By convexity**. Extracted blobs have convexity (area / area of blob convex hull) between +minConvexity (inclusive) and maxConvexity (exclusive). + +Default values of parameters are tuned to extract dark circular blobs. + */ +class CV_EXPORTS_W SimpleBlobDetector : public Feature2D +{ +public: + struct CV_EXPORTS_W_SIMPLE Params + { + CV_WRAP Params(); + CV_PROP_RW float thresholdStep; + CV_PROP_RW float minThreshold; + CV_PROP_RW float maxThreshold; + CV_PROP_RW size_t minRepeatability; + CV_PROP_RW float minDistBetweenBlobs; + + CV_PROP_RW bool filterByColor; + CV_PROP_RW uchar blobColor; + + CV_PROP_RW bool filterByArea; + CV_PROP_RW float minArea, maxArea; + + CV_PROP_RW bool filterByCircularity; + CV_PROP_RW float minCircularity, maxCircularity; + + CV_PROP_RW bool filterByInertia; + CV_PROP_RW float minInertiaRatio, maxInertiaRatio; + + CV_PROP_RW bool filterByConvexity; + CV_PROP_RW float minConvexity, maxConvexity; + + void read( const FileNode& fn ); + void write( FileStorage& fs ) const; + }; + + CV_WRAP static Ptr + create(const SimpleBlobDetector::Params ¶meters = SimpleBlobDetector::Params()); + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; +}; + +//! @} features2d_main + +//! @addtogroup features2d_main +//! @{ + +/** @brief Class implementing the KAZE keypoint detector and descriptor extractor, described in @cite ABD12 . + +@note AKAZE descriptor can only be used with KAZE or AKAZE keypoints .. [ABD12] KAZE Features. Pablo +F. Alcantarilla, Adrien Bartoli and Andrew J. Davison. In European Conference on Computer Vision +(ECCV), Fiorenze, Italy, October 2012. +*/ +class CV_EXPORTS_W KAZE : public Feature2D +{ +public: + enum DiffusivityType + { + DIFF_PM_G1 = 0, + DIFF_PM_G2 = 1, + DIFF_WEICKERT = 2, + DIFF_CHARBONNIER = 3 + }; + + /** @brief The KAZE constructor + + @param extended Set to enable extraction of extended (128-byte) descriptor. + @param upright Set to enable use of upright descriptors (non rotation-invariant). + @param threshold Detector response threshold to accept point + @param nOctaves Maximum octave evolution of the image + @param nOctaveLayers Default number of sublevels per scale level + @param diffusivity Diffusivity type. DIFF_PM_G1, DIFF_PM_G2, DIFF_WEICKERT or + DIFF_CHARBONNIER + */ + CV_WRAP static Ptr create(bool extended=false, bool upright=false, + float threshold = 0.001f, + int nOctaves = 4, int nOctaveLayers = 4, + KAZE::DiffusivityType diffusivity = KAZE::DIFF_PM_G2); + + CV_WRAP virtual void setExtended(bool extended) = 0; + CV_WRAP virtual bool getExtended() const = 0; + + CV_WRAP virtual void setUpright(bool upright) = 0; + CV_WRAP virtual bool getUpright() const = 0; + + CV_WRAP virtual void setThreshold(double threshold) = 0; + CV_WRAP virtual double getThreshold() const = 0; + + CV_WRAP virtual void setNOctaves(int octaves) = 0; + CV_WRAP virtual int getNOctaves() const = 0; + + CV_WRAP virtual void setNOctaveLayers(int octaveLayers) = 0; + CV_WRAP virtual int getNOctaveLayers() const = 0; + + CV_WRAP virtual void setDiffusivity(KAZE::DiffusivityType diff) = 0; + CV_WRAP virtual KAZE::DiffusivityType getDiffusivity() const = 0; + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; +}; + +/** @brief Class implementing the AKAZE keypoint detector and descriptor extractor, described in @cite ANB13. + +@details AKAZE descriptors can only be used with KAZE or AKAZE keypoints. This class is thread-safe. + +@note When you need descriptors use Feature2D::detectAndCompute, which +provides better performance. When using Feature2D::detect followed by +Feature2D::compute scale space pyramid is computed twice. + +@note AKAZE implements T-API. When image is passed as UMat some parts of the algorithm +will use OpenCL. + +@note [ANB13] Fast Explicit Diffusion for Accelerated Features in Nonlinear +Scale Spaces. Pablo F. Alcantarilla, Jesús Nuevo and Adrien Bartoli. In +British Machine Vision Conference (BMVC), Bristol, UK, September 2013. + +*/ +class CV_EXPORTS_W AKAZE : public Feature2D +{ +public: + // AKAZE descriptor type + enum DescriptorType + { + DESCRIPTOR_KAZE_UPRIGHT = 2, ///< Upright descriptors, not invariant to rotation + DESCRIPTOR_KAZE = 3, + DESCRIPTOR_MLDB_UPRIGHT = 4, ///< Upright descriptors, not invariant to rotation + DESCRIPTOR_MLDB = 5 + }; + + /** @brief The AKAZE constructor + + @param descriptor_type Type of the extracted descriptor: DESCRIPTOR_KAZE, + DESCRIPTOR_KAZE_UPRIGHT, DESCRIPTOR_MLDB or DESCRIPTOR_MLDB_UPRIGHT. + @param descriptor_size Size of the descriptor in bits. 0 -\> Full size + @param descriptor_channels Number of channels in the descriptor (1, 2, 3) + @param threshold Detector response threshold to accept point + @param nOctaves Maximum octave evolution of the image + @param nOctaveLayers Default number of sublevels per scale level + @param diffusivity Diffusivity type. DIFF_PM_G1, DIFF_PM_G2, DIFF_WEICKERT or + DIFF_CHARBONNIER + */ + CV_WRAP static Ptr create(AKAZE::DescriptorType descriptor_type = AKAZE::DESCRIPTOR_MLDB, + int descriptor_size = 0, int descriptor_channels = 3, + float threshold = 0.001f, int nOctaves = 4, + int nOctaveLayers = 4, KAZE::DiffusivityType diffusivity = KAZE::DIFF_PM_G2); + + CV_WRAP virtual void setDescriptorType(AKAZE::DescriptorType dtype) = 0; + CV_WRAP virtual AKAZE::DescriptorType getDescriptorType() const = 0; + + CV_WRAP virtual void setDescriptorSize(int dsize) = 0; + CV_WRAP virtual int getDescriptorSize() const = 0; + + CV_WRAP virtual void setDescriptorChannels(int dch) = 0; + CV_WRAP virtual int getDescriptorChannels() const = 0; + + CV_WRAP virtual void setThreshold(double threshold) = 0; + CV_WRAP virtual double getThreshold() const = 0; + + CV_WRAP virtual void setNOctaves(int octaves) = 0; + CV_WRAP virtual int getNOctaves() const = 0; + + CV_WRAP virtual void setNOctaveLayers(int octaveLayers) = 0; + CV_WRAP virtual int getNOctaveLayers() const = 0; + + CV_WRAP virtual void setDiffusivity(KAZE::DiffusivityType diff) = 0; + CV_WRAP virtual KAZE::DiffusivityType getDiffusivity() const = 0; + CV_WRAP virtual String getDefaultName() const CV_OVERRIDE; +}; + +//! @} features2d_main + +/****************************************************************************************\ +* Distance * +\****************************************************************************************/ + +template +struct CV_EXPORTS Accumulator +{ + typedef T Type; +}; + +template<> struct Accumulator { typedef float Type; }; +template<> struct Accumulator { typedef float Type; }; +template<> struct Accumulator { typedef float Type; }; +template<> struct Accumulator { typedef float Type; }; + +/* + * Squared Euclidean distance functor + */ +template +struct CV_EXPORTS SL2 +{ + static const NormTypes normType = NORM_L2SQR; + typedef T ValueType; + typedef typename Accumulator::Type ResultType; + + ResultType operator()( const T* a, const T* b, int size ) const + { + return normL2Sqr(a, b, size); + } +}; + +/* + * Euclidean distance functor + */ +template +struct L2 +{ + static const NormTypes normType = NORM_L2; + typedef T ValueType; + typedef typename Accumulator::Type ResultType; + + ResultType operator()( const T* a, const T* b, int size ) const + { + return (ResultType)std::sqrt((double)normL2Sqr(a, b, size)); + } +}; + +/* + * Manhattan distance (city block distance) functor + */ +template +struct L1 +{ + static const NormTypes normType = NORM_L1; + typedef T ValueType; + typedef typename Accumulator::Type ResultType; + + ResultType operator()( const T* a, const T* b, int size ) const + { + return normL1(a, b, size); + } +}; + +/****************************************************************************************\ +* DescriptorMatcher * +\****************************************************************************************/ + +//! @addtogroup features2d_match +//! @{ + +/** @brief Abstract base class for matching keypoint descriptors. + +It has two groups of match methods: for matching descriptors of an image with another image or with +an image set. + */ +class CV_EXPORTS_W DescriptorMatcher : public Algorithm +{ +public: + enum MatcherType + { + FLANNBASED = 1, + BRUTEFORCE = 2, + BRUTEFORCE_L1 = 3, + BRUTEFORCE_HAMMING = 4, + BRUTEFORCE_HAMMINGLUT = 5, + BRUTEFORCE_SL2 = 6 + }; + + virtual ~DescriptorMatcher(); + + /** @brief Adds descriptors to train a CPU(trainDescCollectionis) or GPU(utrainDescCollectionis) descriptor + collection. + + If the collection is not empty, the new descriptors are added to existing train descriptors. + + @param descriptors Descriptors to add. Each descriptors[i] is a set of descriptors from the same + train image. + */ + CV_WRAP virtual void add( InputArrayOfArrays descriptors ); + + /** @brief Returns a constant link to the train descriptor collection trainDescCollection . + */ + CV_WRAP const std::vector& getTrainDescriptors() const; + + /** @brief Clears the train descriptor collections. + */ + CV_WRAP virtual void clear() CV_OVERRIDE; + + /** @brief Returns true if there are no train descriptors in the both collections. + */ + CV_WRAP virtual bool empty() const CV_OVERRIDE; + + /** @brief Returns true if the descriptor matcher supports masking permissible matches. + */ + CV_WRAP virtual bool isMaskSupported() const = 0; + + /** @brief Trains a descriptor matcher + + Trains a descriptor matcher (for example, the flann index). In all methods to match, the method + train() is run every time before matching. Some descriptor matchers (for example, BruteForceMatcher) + have an empty implementation of this method. Other matchers really train their inner structures (for + example, FlannBasedMatcher trains flann::Index ). + */ + CV_WRAP virtual void train(); + + /** @brief Finds the best match for each descriptor from a query set. + + @param queryDescriptors Query set of descriptors. + @param trainDescriptors Train set of descriptors. This set is not added to the train descriptors + collection stored in the class object. + @param matches Matches. If a query descriptor is masked out in mask , no match is added for this + descriptor. So, matches size may be smaller than the query descriptors count. + @param mask Mask specifying permissible matches between an input query and train matrices of + descriptors. + + In the first variant of this method, the train descriptors are passed as an input argument. In the + second variant of the method, train descriptors collection that was set by DescriptorMatcher::add is + used. Optional mask (or masks) can be passed to specify which query and training descriptors can be + matched. Namely, queryDescriptors[i] can be matched with trainDescriptors[j] only if + mask.at\(i,j) is non-zero. + */ + CV_WRAP void match( InputArray queryDescriptors, InputArray trainDescriptors, + CV_OUT std::vector& matches, InputArray mask=noArray() ) const; + + /** @brief Finds the k best matches for each descriptor from a query set. + + @param queryDescriptors Query set of descriptors. + @param trainDescriptors Train set of descriptors. This set is not added to the train descriptors + collection stored in the class object. + @param mask Mask specifying permissible matches between an input query and train matrices of + descriptors. + @param matches Matches. Each matches[i] is k or less matches for the same query descriptor. + @param k Count of best matches found per each query descriptor or less if a query descriptor has + less than k possible matches in total. + @param compactResult Parameter used when the mask (or masks) is not empty. If compactResult is + false, the matches vector has the same size as queryDescriptors rows. If compactResult is true, + the matches vector does not contain matches for fully masked-out query descriptors. + + These extended variants of DescriptorMatcher::match methods find several best matches for each query + descriptor. The matches are returned in the distance increasing order. See DescriptorMatcher::match + for the details about query and train descriptors. + */ + CV_WRAP void knnMatch( InputArray queryDescriptors, InputArray trainDescriptors, + CV_OUT std::vector >& matches, int k, + InputArray mask=noArray(), bool compactResult=false ) const; + + /** @brief For each query descriptor, finds the training descriptors not farther than the specified distance. + + @param queryDescriptors Query set of descriptors. + @param trainDescriptors Train set of descriptors. This set is not added to the train descriptors + collection stored in the class object. + @param matches Found matches. + @param compactResult Parameter used when the mask (or masks) is not empty. If compactResult is + false, the matches vector has the same size as queryDescriptors rows. If compactResult is true, + the matches vector does not contain matches for fully masked-out query descriptors. + @param maxDistance Threshold for the distance between matched descriptors. Distance means here + metric distance (e.g. Hamming distance), not the distance between coordinates (which is measured + in Pixels)! + @param mask Mask specifying permissible matches between an input query and train matrices of + descriptors. + + For each query descriptor, the methods find such training descriptors that the distance between the + query descriptor and the training descriptor is equal or smaller than maxDistance. Found matches are + returned in the distance increasing order. + */ + CV_WRAP void radiusMatch( InputArray queryDescriptors, InputArray trainDescriptors, + CV_OUT std::vector >& matches, float maxDistance, + InputArray mask=noArray(), bool compactResult=false ) const; + + /** @overload + @param queryDescriptors Query set of descriptors. + @param matches Matches. If a query descriptor is masked out in mask , no match is added for this + descriptor. So, matches size may be smaller than the query descriptors count. + @param masks Set of masks. Each masks[i] specifies permissible matches between the input query + descriptors and stored train descriptors from the i-th image trainDescCollection[i]. + */ + CV_WRAP void match( InputArray queryDescriptors, CV_OUT std::vector& matches, + InputArrayOfArrays masks=noArray() ); + /** @overload + @param queryDescriptors Query set of descriptors. + @param matches Matches. Each matches[i] is k or less matches for the same query descriptor. + @param k Count of best matches found per each query descriptor or less if a query descriptor has + less than k possible matches in total. + @param masks Set of masks. Each masks[i] specifies permissible matches between the input query + descriptors and stored train descriptors from the i-th image trainDescCollection[i]. + @param compactResult Parameter used when the mask (or masks) is not empty. If compactResult is + false, the matches vector has the same size as queryDescriptors rows. If compactResult is true, + the matches vector does not contain matches for fully masked-out query descriptors. + */ + CV_WRAP void knnMatch( InputArray queryDescriptors, CV_OUT std::vector >& matches, int k, + InputArrayOfArrays masks=noArray(), bool compactResult=false ); + /** @overload + @param queryDescriptors Query set of descriptors. + @param matches Found matches. + @param maxDistance Threshold for the distance between matched descriptors. Distance means here + metric distance (e.g. Hamming distance), not the distance between coordinates (which is measured + in Pixels)! + @param masks Set of masks. Each masks[i] specifies permissible matches between the input query + descriptors and stored train descriptors from the i-th image trainDescCollection[i]. + @param compactResult Parameter used when the mask (or masks) is not empty. If compactResult is + false, the matches vector has the same size as queryDescriptors rows. If compactResult is true, + the matches vector does not contain matches for fully masked-out query descriptors. + */ + CV_WRAP void radiusMatch( InputArray queryDescriptors, CV_OUT std::vector >& matches, float maxDistance, + InputArrayOfArrays masks=noArray(), bool compactResult=false ); + + + CV_WRAP void write( const String& fileName ) const + { + FileStorage fs(fileName, FileStorage::WRITE); + write(fs); + } + + CV_WRAP void read( const String& fileName ) + { + FileStorage fs(fileName, FileStorage::READ); + read(fs.root()); + } + // Reads matcher object from a file node + // see corresponding cv::Algorithm method + CV_WRAP virtual void read( const FileNode& ) CV_OVERRIDE; + // Writes matcher object to a file storage + virtual void write( FileStorage& ) const CV_OVERRIDE; + + /** @brief Clones the matcher. + + @param emptyTrainData If emptyTrainData is false, the method creates a deep copy of the object, + that is, copies both parameters and train data. If emptyTrainData is true, the method creates an + object copy with the current parameters but with empty train data. + */ + CV_WRAP CV_NODISCARD_STD virtual Ptr clone( bool emptyTrainData=false ) const = 0; + + /** @brief Creates a descriptor matcher of a given type with the default parameters (using default + constructor). + + @param descriptorMatcherType Descriptor matcher type. Now the following matcher types are + supported: + - `BruteForce` (it uses L2 ) + - `BruteForce-L1` + - `BruteForce-Hamming` + - `BruteForce-Hamming(2)` + - `FlannBased` + */ + CV_WRAP static Ptr create( const String& descriptorMatcherType ); + + CV_WRAP static Ptr create( const DescriptorMatcher::MatcherType& matcherType ); + + + // see corresponding cv::Algorithm method + CV_WRAP inline void write(const Ptr& fs, const String& name = String()) const { Algorithm::write(fs, name); } + +protected: + /** + * Class to work with descriptors from several images as with one merged matrix. + * It is used e.g. in FlannBasedMatcher. + */ + class CV_EXPORTS DescriptorCollection + { + public: + DescriptorCollection(); + DescriptorCollection( const DescriptorCollection& collection ); + virtual ~DescriptorCollection(); + + // Vector of matrices "descriptors" will be merged to one matrix "mergedDescriptors" here. + void set( const std::vector& descriptors ); + virtual void clear(); + + const Mat& getDescriptors() const; + Mat getDescriptor( int imgIdx, int localDescIdx ) const; + Mat getDescriptor( int globalDescIdx ) const; + void getLocalIdx( int globalDescIdx, int& imgIdx, int& localDescIdx ) const; + + int size() const; + + protected: + Mat mergedDescriptors; + std::vector startIdxs; + }; + + //! In fact the matching is implemented only by the following two methods. These methods suppose + //! that the class object has been trained already. Public match methods call these methods + //! after calling train(). + virtual void knnMatchImpl( InputArray queryDescriptors, std::vector >& matches, int k, + InputArrayOfArrays masks=noArray(), bool compactResult=false ) = 0; + virtual void radiusMatchImpl( InputArray queryDescriptors, std::vector >& matches, float maxDistance, + InputArrayOfArrays masks=noArray(), bool compactResult=false ) = 0; + + static bool isPossibleMatch( InputArray mask, int queryIdx, int trainIdx ); + static bool isMaskedOut( InputArrayOfArrays masks, int queryIdx ); + + CV_NODISCARD_STD static Mat clone_op( Mat m ) { return m.clone(); } + void checkMasks( InputArrayOfArrays masks, int queryDescriptorsCount ) const; + + //! Collection of descriptors from train images. + std::vector trainDescCollection; + std::vector utrainDescCollection; +}; + +/** @brief Brute-force descriptor matcher. + +For each descriptor in the first set, this matcher finds the closest descriptor in the second set +by trying each one. This descriptor matcher supports masking permissible matches of descriptor +sets. + */ +class CV_EXPORTS_W BFMatcher : public DescriptorMatcher +{ +public: + /** @brief Brute-force matcher constructor (obsolete). Please use BFMatcher.create() + * + * + */ + CV_WRAP BFMatcher( int normType=NORM_L2, bool crossCheck=false ); + + virtual ~BFMatcher() {} + + virtual bool isMaskSupported() const CV_OVERRIDE { return true; } + + /** @brief Brute-force matcher create method. + @param normType One of NORM_L1, NORM_L2, NORM_HAMMING, NORM_HAMMING2. L1 and L2 norms are + preferable choices for SIFT and SURF descriptors, NORM_HAMMING should be used with ORB, BRISK and + BRIEF, NORM_HAMMING2 should be used with ORB when WTA_K==3 or 4 (see ORB::ORB constructor + description). + @param crossCheck If it is false, this is will be default BFMatcher behaviour when it finds the k + nearest neighbors for each query descriptor. If crossCheck==true, then the knnMatch() method with + k=1 will only return pairs (i,j) such that for i-th query descriptor the j-th descriptor in the + matcher's collection is the nearest and vice versa, i.e. the BFMatcher will only return consistent + pairs. Such technique usually produces best results with minimal number of outliers when there are + enough matches. This is alternative to the ratio test, used by D. Lowe in SIFT paper. + */ + CV_WRAP static Ptr create( int normType=NORM_L2, bool crossCheck=false ) ; + + CV_NODISCARD_STD virtual Ptr clone( bool emptyTrainData=false ) const CV_OVERRIDE; +protected: + virtual void knnMatchImpl( InputArray queryDescriptors, std::vector >& matches, int k, + InputArrayOfArrays masks=noArray(), bool compactResult=false ) CV_OVERRIDE; + virtual void radiusMatchImpl( InputArray queryDescriptors, std::vector >& matches, float maxDistance, + InputArrayOfArrays masks=noArray(), bool compactResult=false ) CV_OVERRIDE; + + int normType; + bool crossCheck; +}; + +#if defined(HAVE_OPENCV_FLANN) || defined(CV_DOXYGEN) + +/** @brief Flann-based descriptor matcher. + +This matcher trains cv::flann::Index on a train descriptor collection and calls its nearest search +methods to find the best matches. So, this matcher may be faster when matching a large train +collection than the brute force matcher. FlannBasedMatcher does not support masking permissible +matches of descriptor sets because flann::Index does not support this. : + */ +class CV_EXPORTS_W FlannBasedMatcher : public DescriptorMatcher +{ +public: + CV_WRAP FlannBasedMatcher( const Ptr& indexParams=makePtr(), + const Ptr& searchParams=makePtr() ); + + virtual void add( InputArrayOfArrays descriptors ) CV_OVERRIDE; + virtual void clear() CV_OVERRIDE; + + // Reads matcher object from a file node + virtual void read( const FileNode& ) CV_OVERRIDE; + // Writes matcher object to a file storage + virtual void write( FileStorage& ) const CV_OVERRIDE; + + virtual void train() CV_OVERRIDE; + virtual bool isMaskSupported() const CV_OVERRIDE; + + CV_WRAP static Ptr create(); + + CV_NODISCARD_STD virtual Ptr clone( bool emptyTrainData=false ) const CV_OVERRIDE; +protected: + static void convertToDMatches( const DescriptorCollection& descriptors, + const Mat& indices, const Mat& distances, + std::vector >& matches ); + + virtual void knnMatchImpl( InputArray queryDescriptors, std::vector >& matches, int k, + InputArrayOfArrays masks=noArray(), bool compactResult=false ) CV_OVERRIDE; + virtual void radiusMatchImpl( InputArray queryDescriptors, std::vector >& matches, float maxDistance, + InputArrayOfArrays masks=noArray(), bool compactResult=false ) CV_OVERRIDE; + + Ptr indexParams; + Ptr searchParams; + Ptr flannIndex; + + DescriptorCollection mergedDescriptors; + int addedDescCount; +}; + +#endif + +//! @} features2d_match + +/****************************************************************************************\ +* Drawing functions * +\****************************************************************************************/ + +//! @addtogroup features2d_draw +//! @{ + +enum struct DrawMatchesFlags +{ + DEFAULT = 0, //!< Output image matrix will be created (Mat::create), + //!< i.e. existing memory of output image may be reused. + //!< Two source image, matches and single keypoints will be drawn. + //!< For each keypoint only the center point will be drawn (without + //!< the circle around keypoint with keypoint size and orientation). + DRAW_OVER_OUTIMG = 1, //!< Output image matrix will not be created (Mat::create). + //!< Matches will be drawn on existing content of output image. + NOT_DRAW_SINGLE_POINTS = 2, //!< Single keypoints will not be drawn. + DRAW_RICH_KEYPOINTS = 4 //!< For each keypoint the circle around keypoint with keypoint size and + //!< orientation will be drawn. +}; +CV_ENUM_FLAGS(DrawMatchesFlags) + +/** @brief Draws keypoints. + +@param image Source image. +@param keypoints Keypoints from the source image. +@param outImage Output image. Its content depends on the flags value defining what is drawn in the +output image. See possible flags bit values below. +@param color Color of keypoints. +@param flags Flags setting drawing features. Possible flags bit values are defined by +DrawMatchesFlags. See details above in drawMatches . + +@note +For Python API, flags are modified as cv.DRAW_MATCHES_FLAGS_DEFAULT, +cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS, cv.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG, +cv.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS + */ +CV_EXPORTS_W void drawKeypoints( InputArray image, const std::vector& keypoints, InputOutputArray outImage, + const Scalar& color=Scalar::all(-1), DrawMatchesFlags flags=DrawMatchesFlags::DEFAULT ); + +/** @brief Draws the found matches of keypoints from two images. + +@param img1 First source image. +@param keypoints1 Keypoints from the first source image. +@param img2 Second source image. +@param keypoints2 Keypoints from the second source image. +@param matches1to2 Matches from the first image to the second one, which means that keypoints1[i] +has a corresponding point in keypoints2[matches[i]] . +@param outImg Output image. Its content depends on the flags value defining what is drawn in the +output image. See possible flags bit values below. +@param matchColor Color of matches (lines and connected keypoints). If matchColor==Scalar::all(-1) +, the color is generated randomly. +@param singlePointColor Color of single keypoints (circles), which means that keypoints do not +have the matches. If singlePointColor==Scalar::all(-1) , the color is generated randomly. +@param matchesMask Mask determining which matches are drawn. If the mask is empty, all matches are +drawn. +@param flags Flags setting drawing features. Possible flags bit values are defined by +DrawMatchesFlags. + +This function draws matches of keypoints from two images in the output image. Match is a line +connecting two keypoints (circles). See cv::DrawMatchesFlags. + */ +CV_EXPORTS_W void drawMatches( InputArray img1, const std::vector& keypoints1, + InputArray img2, const std::vector& keypoints2, + const std::vector& matches1to2, InputOutputArray outImg, + const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1), + const std::vector& matchesMask=std::vector(), DrawMatchesFlags flags=DrawMatchesFlags::DEFAULT ); + +/** @overload */ +CV_EXPORTS_W void drawMatches( InputArray img1, const std::vector& keypoints1, + InputArray img2, const std::vector& keypoints2, + const std::vector& matches1to2, InputOutputArray outImg, + const int matchesThickness, const Scalar& matchColor=Scalar::all(-1), + const Scalar& singlePointColor=Scalar::all(-1), const std::vector& matchesMask=std::vector(), + DrawMatchesFlags flags=DrawMatchesFlags::DEFAULT ); + +CV_EXPORTS_AS(drawMatchesKnn) void drawMatches( InputArray img1, const std::vector& keypoints1, + InputArray img2, const std::vector& keypoints2, + const std::vector >& matches1to2, InputOutputArray outImg, + const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1), + const std::vector >& matchesMask=std::vector >(), DrawMatchesFlags flags=DrawMatchesFlags::DEFAULT ); + +//! @} features2d_draw + +/****************************************************************************************\ +* Functions to evaluate the feature detectors and [generic] descriptor extractors * +\****************************************************************************************/ + +CV_EXPORTS void evaluateFeatureDetector( const Mat& img1, const Mat& img2, const Mat& H1to2, + std::vector* keypoints1, std::vector* keypoints2, + float& repeatability, int& correspCount, + const Ptr& fdetector=Ptr() ); + +CV_EXPORTS void computeRecallPrecisionCurve( const std::vector >& matches1to2, + const std::vector >& correctMatches1to2Mask, + std::vector& recallPrecisionCurve ); + +CV_EXPORTS float getRecall( const std::vector& recallPrecisionCurve, float l_precision ); +CV_EXPORTS int getNearestPoint( const std::vector& recallPrecisionCurve, float l_precision ); + +/****************************************************************************************\ +* Bag of visual words * +\****************************************************************************************/ + +//! @addtogroup features2d_category +//! @{ + +/** @brief Abstract base class for training the *bag of visual words* vocabulary from a set of descriptors. + +For details, see, for example, *Visual Categorization with Bags of Keypoints* by Gabriella Csurka, +Christopher R. Dance, Lixin Fan, Jutta Willamowski, Cedric Bray, 2004. : + */ +class CV_EXPORTS_W BOWTrainer +{ +public: + BOWTrainer(); + virtual ~BOWTrainer(); + + /** @brief Adds descriptors to a training set. + + @param descriptors Descriptors to add to a training set. Each row of the descriptors matrix is a + descriptor. + + The training set is clustered using clustermethod to construct the vocabulary. + */ + CV_WRAP void add( const Mat& descriptors ); + + /** @brief Returns a training set of descriptors. + */ + CV_WRAP const std::vector& getDescriptors() const; + + /** @brief Returns the count of all descriptors stored in the training set. + */ + CV_WRAP int descriptorsCount() const; + + CV_WRAP virtual void clear(); + + /** @overload */ + CV_WRAP virtual Mat cluster() const = 0; + + /** @brief Clusters train descriptors. + + @param descriptors Descriptors to cluster. Each row of the descriptors matrix is a descriptor. + Descriptors are not added to the inner train descriptor set. + + The vocabulary consists of cluster centers. So, this method returns the vocabulary. In the first + variant of the method, train descriptors stored in the object are clustered. In the second variant, + input descriptors are clustered. + */ + CV_WRAP virtual Mat cluster( const Mat& descriptors ) const = 0; + +protected: + std::vector descriptors; + int size; +}; + +/** @brief kmeans -based class to train visual vocabulary using the *bag of visual words* approach. : + */ +class CV_EXPORTS_W BOWKMeansTrainer : public BOWTrainer +{ +public: + /** @brief The constructor. + + @see cv::kmeans + */ + CV_WRAP BOWKMeansTrainer( int clusterCount, const TermCriteria& termcrit=TermCriteria(), + int attempts=3, int flags=KMEANS_PP_CENTERS ); + virtual ~BOWKMeansTrainer(); + + // Returns trained vocabulary (i.e. cluster centers). + CV_WRAP virtual Mat cluster() const CV_OVERRIDE; + CV_WRAP virtual Mat cluster( const Mat& descriptors ) const CV_OVERRIDE; + +protected: + + int clusterCount; + TermCriteria termcrit; + int attempts; + int flags; +}; + +/** @brief Class to compute an image descriptor using the *bag of visual words*. + +Such a computation consists of the following steps: + +1. Compute descriptors for a given image and its keypoints set. +2. Find the nearest visual words from the vocabulary for each keypoint descriptor. +3. Compute the bag-of-words image descriptor as is a normalized histogram of vocabulary words +encountered in the image. The i-th bin of the histogram is a frequency of i-th word of the +vocabulary in the given image. + */ +class CV_EXPORTS_W BOWImgDescriptorExtractor +{ +public: + /** @brief The constructor. + + @param dextractor Descriptor extractor that is used to compute descriptors for an input image and + its keypoints. + @param dmatcher Descriptor matcher that is used to find the nearest word of the trained vocabulary + for each keypoint descriptor of the image. + */ + CV_WRAP BOWImgDescriptorExtractor( const Ptr& dextractor, + const Ptr& dmatcher ); + /** @overload */ + BOWImgDescriptorExtractor( const Ptr& dmatcher ); + virtual ~BOWImgDescriptorExtractor(); + + /** @brief Sets a visual vocabulary. + + @param vocabulary Vocabulary (can be trained using the inheritor of BOWTrainer ). Each row of the + vocabulary is a visual word (cluster center). + */ + CV_WRAP void setVocabulary( const Mat& vocabulary ); + + /** @brief Returns the set vocabulary. + */ + CV_WRAP const Mat& getVocabulary() const; + + /** @brief Computes an image descriptor using the set visual vocabulary. + + @param image Image, for which the descriptor is computed. + @param keypoints Keypoints detected in the input image. + @param imgDescriptor Computed output image descriptor. + @param pointIdxsOfClusters Indices of keypoints that belong to the cluster. This means that + pointIdxsOfClusters[i] are keypoint indices that belong to the i -th cluster (word of vocabulary) + returned if it is non-zero. + @param descriptors Descriptors of the image keypoints that are returned if they are non-zero. + */ + void compute( InputArray image, std::vector& keypoints, OutputArray imgDescriptor, + std::vector >* pointIdxsOfClusters=0, Mat* descriptors=0 ); + /** @overload + @param keypointDescriptors Computed descriptors to match with vocabulary. + @param imgDescriptor Computed output image descriptor. + @param pointIdxsOfClusters Indices of keypoints that belong to the cluster. This means that + pointIdxsOfClusters[i] are keypoint indices that belong to the i -th cluster (word of vocabulary) + returned if it is non-zero. + */ + void compute( InputArray keypointDescriptors, OutputArray imgDescriptor, + std::vector >* pointIdxsOfClusters=0 ); + // compute() is not constant because DescriptorMatcher::match is not constant + + CV_WRAP_AS(compute) void compute2( const Mat& image, std::vector& keypoints, CV_OUT Mat& imgDescriptor ) + { compute(image,keypoints,imgDescriptor); } + + /** @brief Returns an image descriptor size if the vocabulary is set. Otherwise, it returns 0. + */ + CV_WRAP int descriptorSize() const; + + /** @brief Returns an image descriptor type. + */ + CV_WRAP int descriptorType() const; + +protected: + Mat vocabulary; + Ptr dextractor; + Ptr dmatcher; +}; + +//! @} features2d_category + +//! @} features2d + +} /* namespace cv */ + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/features2d/features2d.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/features2d/features2d.hpp new file mode 100644 index 0000000..e81df0a --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/features2d/features2d.hpp @@ -0,0 +1,48 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifdef __OPENCV_BUILD +#error this is a compatibility header which should not be used inside the OpenCV library +#endif + +#include "opencv2/features2d.hpp" diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/features2d/hal/interface.h b/duix-sdk/src/main/cpp/third/arm/include/opencv2/features2d/hal/interface.h new file mode 100644 index 0000000..bc3b084 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/features2d/hal/interface.h @@ -0,0 +1,33 @@ +#ifndef OPENCV_FEATURE2D_HAL_INTERFACE_H +#define OPENCV_FEATURE2D_HAL_INTERFACE_H + +#include "opencv2/core/cvdef.h" +//! @addtogroup features2d_hal_interface +//! @{ + +//! @name Fast feature detector types +//! @sa cv::FastFeatureDetector +//! @{ +#define CV_HAL_TYPE_5_8 0 +#define CV_HAL_TYPE_7_12 1 +#define CV_HAL_TYPE_9_16 2 +//! @} + +//! @name Key point +//! @sa cv::KeyPoint +//! @{ +struct CV_EXPORTS cvhalKeyPoint +{ + float x; + float y; + float size; + float angle; + float response; + int octave; + int class_id; +}; +//! @} + +//! @} + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/highgui.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/highgui.hpp new file mode 100644 index 0000000..21560ee --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/highgui.hpp @@ -0,0 +1,17 @@ +// +// Copyright (C) 2021 nihui +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include "opencv2/highgui/highgui.hpp" diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/highgui/highgui.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/highgui/highgui.hpp new file mode 100644 index 0000000..b337fb6 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/highgui/highgui.hpp @@ -0,0 +1,62 @@ +// +// Copyright (C) 2021 nihui +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef OPENCV_HIGHGUI_HPP +#define OPENCV_HIGHGUI_HPP + +#include "opencv2/core.hpp" + +enum +{ + CV_LOAD_IMAGE_UNCHANGED = -1, + CV_LOAD_IMAGE_GRAYSCALE = 0, + CV_LOAD_IMAGE_COLOR = 1, +}; + +enum +{ + CV_IMWRITE_JPEG_QUALITY = 1 +}; + +namespace cv { + +enum ImreadModes +{ + IMREAD_UNCHANGED = -1, + IMREAD_GRAYSCALE = 0, + IMREAD_COLOR = 1 +}; + +enum ImwriteFlags +{ + IMWRITE_JPEG_QUALITY = 1 +}; + +CV_EXPORTS_W Mat imread(const String& filename, int flags = IMREAD_COLOR); + +CV_EXPORTS_W bool imwrite(const String& filename, InputArray img, const std::vector& params = std::vector()); + +CV_EXPORTS_W Mat imdecode(InputArray buf, int flags); + +CV_EXPORTS_W bool imencode(const String& ext, InputArray img, CV_OUT std::vector& buf, const std::vector& params = std::vector()); + +CV_EXPORTS_W void imshow(const String& winname, InputArray mat); + +CV_EXPORTS_W int waitKey(int delay = 0); + +} // namespace cv + +#endif // OPENCV_HIGHGUI_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc.hpp new file mode 100644 index 0000000..3e0180a --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc.hpp @@ -0,0 +1,5005 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_IMGPROC_HPP +#define OPENCV_IMGPROC_HPP + +#include "opencv2/core.hpp" + +/** + @defgroup imgproc Image Processing + +This module includes image-processing functions. + + @{ + @defgroup imgproc_filter Image Filtering + +Functions and classes described in this section are used to perform various linear or non-linear +filtering operations on 2D images (represented as Mat's). It means that for each pixel location +\f$(x,y)\f$ in the source image (normally, rectangular), its neighborhood is considered and used to +compute the response. In case of a linear filter, it is a weighted sum of pixel values. In case of +morphological operations, it is the minimum or maximum values, and so on. The computed response is +stored in the destination image at the same location \f$(x,y)\f$. It means that the output image +will be of the same size as the input image. Normally, the functions support multi-channel arrays, +in which case every channel is processed independently. Therefore, the output image will also have +the same number of channels as the input one. + +Another common feature of the functions and classes described in this section is that, unlike +simple arithmetic functions, they need to extrapolate values of some non-existing pixels. For +example, if you want to smooth an image using a Gaussian \f$3 \times 3\f$ filter, then, when +processing the left-most pixels in each row, you need pixels to the left of them, that is, outside +of the image. You can let these pixels be the same as the left-most image pixels ("replicated +border" extrapolation method), or assume that all the non-existing pixels are zeros ("constant +border" extrapolation method), and so on. OpenCV enables you to specify the extrapolation method. +For details, see #BorderTypes + +@anchor filter_depths +### Depth combinations +Input depth (src.depth()) | Output depth (ddepth) +--------------------------|---------------------- +CV_8U | -1/CV_16S/CV_32F/CV_64F +CV_16U/CV_16S | -1/CV_32F/CV_64F +CV_32F | -1/CV_32F/CV_64F +CV_64F | -1/CV_64F + +@note when ddepth=-1, the output image will have the same depth as the source. + + @defgroup imgproc_transform Geometric Image Transformations + +The functions in this section perform various geometrical transformations of 2D images. They do not +change the image content but deform the pixel grid and map this deformed grid to the destination +image. In fact, to avoid sampling artifacts, the mapping is done in the reverse order, from +destination to the source. That is, for each pixel \f$(x, y)\f$ of the destination image, the +functions compute coordinates of the corresponding "donor" pixel in the source image and copy the +pixel value: + +\f[\texttt{dst} (x,y)= \texttt{src} (f_x(x,y), f_y(x,y))\f] + +In case when you specify the forward mapping \f$\left: \texttt{src} \rightarrow +\texttt{dst}\f$, the OpenCV functions first compute the corresponding inverse mapping +\f$\left: \texttt{dst} \rightarrow \texttt{src}\f$ and then use the above formula. + +The actual implementations of the geometrical transformations, from the most generic remap and to +the simplest and the fastest resize, need to solve two main problems with the above formula: + +- Extrapolation of non-existing pixels. Similarly to the filtering functions described in the +previous section, for some \f$(x,y)\f$, either one of \f$f_x(x,y)\f$, or \f$f_y(x,y)\f$, or both +of them may fall outside of the image. In this case, an extrapolation method needs to be used. +OpenCV provides the same selection of extrapolation methods as in the filtering functions. In +addition, it provides the method #BORDER_TRANSPARENT. This means that the corresponding pixels in +the destination image will not be modified at all. + +- Interpolation of pixel values. Usually \f$f_x(x,y)\f$ and \f$f_y(x,y)\f$ are floating-point +numbers. This means that \f$\left\f$ can be either an affine or perspective +transformation, or radial lens distortion correction, and so on. So, a pixel value at fractional +coordinates needs to be retrieved. In the simplest case, the coordinates can be just rounded to the +nearest integer coordinates and the corresponding pixel can be used. This is called a +nearest-neighbor interpolation. However, a better result can be achieved by using more +sophisticated [interpolation methods](http://en.wikipedia.org/wiki/Multivariate_interpolation) , +where a polynomial function is fit into some neighborhood of the computed pixel \f$(f_x(x,y), +f_y(x,y))\f$, and then the value of the polynomial at \f$(f_x(x,y), f_y(x,y))\f$ is taken as the +interpolated pixel value. In OpenCV, you can choose between several interpolation methods. See +#resize for details. + +@note The geometrical transformations do not work with `CV_8S` or `CV_32S` images. + + @defgroup imgproc_misc Miscellaneous Image Transformations + @defgroup imgproc_draw Drawing Functions + +Drawing functions work with matrices/images of arbitrary depth. The boundaries of the shapes can be +rendered with antialiasing (implemented only for 8-bit images for now). All the functions include +the parameter color that uses an RGB value (that may be constructed with the Scalar constructor ) +for color images and brightness for grayscale images. For color images, the channel ordering is +normally *Blue, Green, Red*. This is what imshow, imread, and imwrite expect. So, if you form a +color using the Scalar constructor, it should look like: + +\f[\texttt{Scalar} (blue \_ component, green \_ component, red \_ component[, alpha \_ component])\f] + +If you are using your own image rendering and I/O functions, you can use any channel ordering. The +drawing functions process each channel independently and do not depend on the channel order or even +on the used color space. The whole image can be converted from BGR to RGB or to a different color +space using cvtColor . + +If a drawn figure is partially or completely outside the image, the drawing functions clip it. Also, +many drawing functions can handle pixel coordinates specified with sub-pixel accuracy. This means +that the coordinates can be passed as fixed-point numbers encoded as integers. The number of +fractional bits is specified by the shift parameter and the real point coordinates are calculated as +\f$\texttt{Point}(x,y)\rightarrow\texttt{Point2f}(x*2^{-shift},y*2^{-shift})\f$ . This feature is +especially effective when rendering antialiased shapes. + +@note The functions do not support alpha-transparency when the target image is 4-channel. In this +case, the color[3] is simply copied to the repainted pixels. Thus, if you want to paint +semi-transparent shapes, you can paint them in a separate buffer and then blend it with the main +image. + + @defgroup imgproc_color_conversions Color Space Conversions + @defgroup imgproc_colormap ColorMaps in OpenCV + +The human perception isn't built for observing fine changes in grayscale images. Human eyes are more +sensitive to observing changes between colors, so you often need to recolor your grayscale images to +get a clue about them. OpenCV now comes with various colormaps to enhance the visualization in your +computer vision application. + +In OpenCV you only need applyColorMap to apply a colormap on a given image. The following sample +code reads the path to an image from command line, applies a Jet colormap on it and shows the +result: + +@include snippets/imgproc_applyColorMap.cpp + +@see #ColormapTypes + + @defgroup imgproc_subdiv2d Planar Subdivision + +The Subdiv2D class described in this section is used to perform various planar subdivision on +a set of 2D points (represented as vector of Point2f). OpenCV subdivides a plane into triangles +using the Delaunay's algorithm, which corresponds to the dual graph of the Voronoi diagram. +In the figure below, the Delaunay's triangulation is marked with black lines and the Voronoi +diagram with red lines. + +![Delaunay triangulation (black) and Voronoi (red)](pics/delaunay_voronoi.png) + +The subdivisions can be used for the 3D piece-wise transformation of a plane, morphing, fast +location of points on the plane, building special graphs (such as NNG,RNG), and so forth. + + @defgroup imgproc_hist Histograms + @defgroup imgproc_shape Structural Analysis and Shape Descriptors + @defgroup imgproc_motion Motion Analysis and Object Tracking + @defgroup imgproc_feature Feature Detection + @defgroup imgproc_object Object Detection + @defgroup imgproc_segmentation Image Segmentation + @defgroup imgproc_c C API + @defgroup imgproc_hal Hardware Acceleration Layer + @{ + @defgroup imgproc_hal_functions Functions + @defgroup imgproc_hal_interface Interface + @} + @} +*/ + +namespace cv +{ + +/** @addtogroup imgproc +@{ +*/ + +//! @addtogroup imgproc_filter +//! @{ + +enum SpecialFilter { + FILTER_SCHARR = -1 +}; + +//! type of morphological operation +enum MorphTypes{ + MORPH_ERODE = 0, //!< see #erode + MORPH_DILATE = 1, //!< see #dilate + MORPH_OPEN = 2, //!< an opening operation + //!< \f[\texttt{dst} = \mathrm{open} ( \texttt{src} , \texttt{element} )= \mathrm{dilate} ( \mathrm{erode} ( \texttt{src} , \texttt{element} ))\f] + MORPH_CLOSE = 3, //!< a closing operation + //!< \f[\texttt{dst} = \mathrm{close} ( \texttt{src} , \texttt{element} )= \mathrm{erode} ( \mathrm{dilate} ( \texttt{src} , \texttt{element} ))\f] + MORPH_GRADIENT = 4, //!< a morphological gradient + //!< \f[\texttt{dst} = \mathrm{morph\_grad} ( \texttt{src} , \texttt{element} )= \mathrm{dilate} ( \texttt{src} , \texttt{element} )- \mathrm{erode} ( \texttt{src} , \texttt{element} )\f] + MORPH_TOPHAT = 5, //!< "top hat" + //!< \f[\texttt{dst} = \mathrm{tophat} ( \texttt{src} , \texttt{element} )= \texttt{src} - \mathrm{open} ( \texttt{src} , \texttt{element} )\f] + MORPH_BLACKHAT = 6, //!< "black hat" + //!< \f[\texttt{dst} = \mathrm{blackhat} ( \texttt{src} , \texttt{element} )= \mathrm{close} ( \texttt{src} , \texttt{element} )- \texttt{src}\f] + MORPH_HITMISS = 7 //!< "hit or miss" + //!< .- Only supported for CV_8UC1 binary images. A tutorial can be found in the documentation +}; + +//! shape of the structuring element +enum MorphShapes { + MORPH_RECT = 0, //!< a rectangular structuring element: \f[E_{ij}=1\f] + MORPH_CROSS = 1, //!< a cross-shaped structuring element: + //!< \f[E_{ij} = \begin{cases} 1 & \texttt{if } {i=\texttt{anchor.y } {or } {j=\texttt{anchor.x}}} \\0 & \texttt{otherwise} \end{cases}\f] + MORPH_ELLIPSE = 2 //!< an elliptic structuring element, that is, a filled ellipse inscribed + //!< into the rectangle Rect(0, 0, esize.width, 0.esize.height) +}; + +//! @} imgproc_filter + +//! @addtogroup imgproc_transform +//! @{ + +//! interpolation algorithm +enum InterpolationFlags{ + /** nearest neighbor interpolation */ + INTER_NEAREST = 0, + /** bilinear interpolation */ + INTER_LINEAR = 1, + /** bicubic interpolation */ + INTER_CUBIC = 2, + /** resampling using pixel area relation. It may be a preferred method for image decimation, as + it gives moire'-free results. But when the image is zoomed, it is similar to the INTER_NEAREST + method. */ + INTER_AREA = 3, + /** Lanczos interpolation over 8x8 neighborhood */ + INTER_LANCZOS4 = 4, + /** Bit exact bilinear interpolation */ + INTER_LINEAR_EXACT = 5, + /** Bit exact nearest neighbor interpolation. This will produce same results as + the nearest neighbor method in PIL, scikit-image or Matlab. */ + INTER_NEAREST_EXACT = 6, + /** mask for interpolation codes */ + INTER_MAX = 7, + /** flag, fills all of the destination image pixels. If some of them correspond to outliers in the + source image, they are set to zero */ + WARP_FILL_OUTLIERS = 8, + /** flag, inverse transformation + + For example, #linearPolar or #logPolar transforms: + - flag is __not__ set: \f$dst( \rho , \phi ) = src(x,y)\f$ + - flag is set: \f$dst(x,y) = src( \rho , \phi )\f$ + */ + WARP_INVERSE_MAP = 16 +}; + +/** \brief Specify the polar mapping mode +@sa warpPolar +*/ +enum WarpPolarMode +{ + WARP_POLAR_LINEAR = 0, ///< Remaps an image to/from polar space. + WARP_POLAR_LOG = 256 ///< Remaps an image to/from semilog-polar space. +}; + +enum InterpolationMasks { + INTER_BITS = 5, + INTER_BITS2 = INTER_BITS * 2, + INTER_TAB_SIZE = 1 << INTER_BITS, + INTER_TAB_SIZE2 = INTER_TAB_SIZE * INTER_TAB_SIZE + }; + +//! @} imgproc_transform + +//! @addtogroup imgproc_misc +//! @{ + +//! Distance types for Distance Transform and M-estimators +//! @see distanceTransform, fitLine +enum DistanceTypes { + DIST_USER = -1, //!< User defined distance + DIST_L1 = 1, //!< distance = |x1-x2| + |y1-y2| + DIST_L2 = 2, //!< the simple euclidean distance + DIST_C = 3, //!< distance = max(|x1-x2|,|y1-y2|) + DIST_L12 = 4, //!< L1-L2 metric: distance = 2(sqrt(1+x*x/2) - 1)) + DIST_FAIR = 5, //!< distance = c^2(|x|/c-log(1+|x|/c)), c = 1.3998 + DIST_WELSCH = 6, //!< distance = c^2/2(1-exp(-(x/c)^2)), c = 2.9846 + DIST_HUBER = 7 //!< distance = |x| \texttt{thresh}\)}{0}{otherwise}\f] + THRESH_BINARY_INV = 1, //!< \f[\texttt{dst} (x,y) = \fork{0}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{\texttt{maxval}}{otherwise}\f] + THRESH_TRUNC = 2, //!< \f[\texttt{dst} (x,y) = \fork{\texttt{threshold}}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{\texttt{src}(x,y)}{otherwise}\f] + THRESH_TOZERO = 3, //!< \f[\texttt{dst} (x,y) = \fork{\texttt{src}(x,y)}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{0}{otherwise}\f] + THRESH_TOZERO_INV = 4, //!< \f[\texttt{dst} (x,y) = \fork{0}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{\texttt{src}(x,y)}{otherwise}\f] + THRESH_MASK = 7, + THRESH_OTSU = 8, //!< flag, use Otsu algorithm to choose the optimal threshold value + THRESH_TRIANGLE = 16 //!< flag, use Triangle algorithm to choose the optimal threshold value +}; + +//! adaptive threshold algorithm +//! @see adaptiveThreshold +enum AdaptiveThresholdTypes { + /** the threshold value \f$T(x,y)\f$ is a mean of the \f$\texttt{blockSize} \times + \texttt{blockSize}\f$ neighborhood of \f$(x, y)\f$ minus C */ + ADAPTIVE_THRESH_MEAN_C = 0, + /** the threshold value \f$T(x, y)\f$ is a weighted sum (cross-correlation with a Gaussian + window) of the \f$\texttt{blockSize} \times \texttt{blockSize}\f$ neighborhood of \f$(x, y)\f$ + minus C . The default sigma (standard deviation) is used for the specified blockSize . See + #getGaussianKernel*/ + ADAPTIVE_THRESH_GAUSSIAN_C = 1 +}; + +//! class of the pixel in GrabCut algorithm +enum GrabCutClasses { + GC_BGD = 0, //!< an obvious background pixels + GC_FGD = 1, //!< an obvious foreground (object) pixel + GC_PR_BGD = 2, //!< a possible background pixel + GC_PR_FGD = 3 //!< a possible foreground pixel +}; + +//! GrabCut algorithm flags +enum GrabCutModes { + /** The function initializes the state and the mask using the provided rectangle. After that it + runs iterCount iterations of the algorithm. */ + GC_INIT_WITH_RECT = 0, + /** The function initializes the state using the provided mask. Note that GC_INIT_WITH_RECT + and GC_INIT_WITH_MASK can be combined. Then, all the pixels outside of the ROI are + automatically initialized with GC_BGD .*/ + GC_INIT_WITH_MASK = 1, + /** The value means that the algorithm should just resume. */ + GC_EVAL = 2, + /** The value means that the algorithm should just run the grabCut algorithm (a single iteration) with the fixed model */ + GC_EVAL_FREEZE_MODEL = 3 +}; + +//! distanceTransform algorithm flags +enum DistanceTransformLabelTypes { + /** each connected component of zeros in src (as well as all the non-zero pixels closest to the + connected component) will be assigned the same label */ + DIST_LABEL_CCOMP = 0, + /** each zero pixel (and all the non-zero pixels closest to it) gets its own label. */ + DIST_LABEL_PIXEL = 1 +}; + +//! floodfill algorithm flags +enum FloodFillFlags { + /** If set, the difference between the current pixel and seed pixel is considered. Otherwise, + the difference between neighbor pixels is considered (that is, the range is floating). */ + FLOODFILL_FIXED_RANGE = 1 << 16, + /** If set, the function does not change the image ( newVal is ignored), and only fills the + mask with the value specified in bits 8-16 of flags as described above. This option only make + sense in function variants that have the mask parameter. */ + FLOODFILL_MASK_ONLY = 1 << 17 +}; + +//! @} imgproc_misc + +//! @addtogroup imgproc_shape +//! @{ + +//! connected components statistics +enum ConnectedComponentsTypes { + CC_STAT_LEFT = 0, //!< The leftmost (x) coordinate which is the inclusive start of the bounding + //!< box in the horizontal direction. + CC_STAT_TOP = 1, //!< The topmost (y) coordinate which is the inclusive start of the bounding + //!< box in the vertical direction. + CC_STAT_WIDTH = 2, //!< The horizontal size of the bounding box + CC_STAT_HEIGHT = 3, //!< The vertical size of the bounding box + CC_STAT_AREA = 4, //!< The total area (in pixels) of the connected component +#ifndef CV_DOXYGEN + CC_STAT_MAX = 5 //!< Max enumeration value. Used internally only for memory allocation +#endif +}; + +//! connected components algorithm +enum ConnectedComponentsAlgorithmsTypes { + CCL_DEFAULT = -1, //!< Spaghetti @cite Bolelli2019 algorithm for 8-way connectivity, Spaghetti4C @cite Bolelli2021 algorithm for 4-way connectivity. + CCL_WU = 0, //!< SAUF @cite Wu2009 algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity. The parallel implementation described in @cite Bolelli2017 is available for SAUF. + CCL_GRANA = 1, //!< BBDT @cite Grana2010 algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity. The parallel implementation described in @cite Bolelli2017 is available for both BBDT and SAUF. + CCL_BOLELLI = 2, //!< Spaghetti @cite Bolelli2019 algorithm for 8-way connectivity, Spaghetti4C @cite Bolelli2021 algorithm for 4-way connectivity. The parallel implementation described in @cite Bolelli2017 is available for both Spaghetti and Spaghetti4C. + CCL_SAUF = 3, //!< Same as CCL_WU. It is preferable to use the flag with the name of the algorithm (CCL_SAUF) rather than the one with the name of the first author (CCL_WU). + CCL_BBDT = 4, //!< Same as CCL_GRANA. It is preferable to use the flag with the name of the algorithm (CCL_BBDT) rather than the one with the name of the first author (CCL_GRANA). + CCL_SPAGHETTI = 5, //!< Same as CCL_BOLELLI. It is preferable to use the flag with the name of the algorithm (CCL_SPAGHETTI) rather than the one with the name of the first author (CCL_BOLELLI). +}; + +//! mode of the contour retrieval algorithm +enum RetrievalModes { + /** retrieves only the extreme outer contours. It sets `hierarchy[i][2]=hierarchy[i][3]=-1` for + all the contours. */ + RETR_EXTERNAL = 0, + /** retrieves all of the contours without establishing any hierarchical relationships. */ + RETR_LIST = 1, + /** retrieves all of the contours and organizes them into a two-level hierarchy. At the top + level, there are external boundaries of the components. At the second level, there are + boundaries of the holes. If there is another contour inside a hole of a connected component, it + is still put at the top level. */ + RETR_CCOMP = 2, + /** retrieves all of the contours and reconstructs a full hierarchy of nested contours.*/ + RETR_TREE = 3, + RETR_FLOODFILL = 4 //!< +}; + +//! the contour approximation algorithm +enum ContourApproximationModes { + /** stores absolutely all the contour points. That is, any 2 subsequent points (x1,y1) and + (x2,y2) of the contour will be either horizontal, vertical or diagonal neighbors, that is, + max(abs(x1-x2),abs(y2-y1))==1. */ + CHAIN_APPROX_NONE = 1, + /** compresses horizontal, vertical, and diagonal segments and leaves only their end points. + For example, an up-right rectangular contour is encoded with 4 points. */ + CHAIN_APPROX_SIMPLE = 2, + /** applies one of the flavors of the Teh-Chin chain approximation algorithm @cite TehChin89 */ + CHAIN_APPROX_TC89_L1 = 3, + /** applies one of the flavors of the Teh-Chin chain approximation algorithm @cite TehChin89 */ + CHAIN_APPROX_TC89_KCOS = 4 +}; + +/** @brief Shape matching methods + +\f$A\f$ denotes object1,\f$B\f$ denotes object2 + +\f$\begin{array}{l} m^A_i = \mathrm{sign} (h^A_i) \cdot \log{h^A_i} \\ m^B_i = \mathrm{sign} (h^B_i) \cdot \log{h^B_i} \end{array}\f$ + +and \f$h^A_i, h^B_i\f$ are the Hu moments of \f$A\f$ and \f$B\f$ , respectively. +*/ +enum ShapeMatchModes { + CONTOURS_MATCH_I1 =1, //!< \f[I_1(A,B) = \sum _{i=1...7} \left | \frac{1}{m^A_i} - \frac{1}{m^B_i} \right |\f] + CONTOURS_MATCH_I2 =2, //!< \f[I_2(A,B) = \sum _{i=1...7} \left | m^A_i - m^B_i \right |\f] + CONTOURS_MATCH_I3 =3 //!< \f[I_3(A,B) = \max _{i=1...7} \frac{ \left| m^A_i - m^B_i \right| }{ \left| m^A_i \right| }\f] +}; + +//! @} imgproc_shape + +//! @addtogroup imgproc_feature +//! @{ + +//! Variants of a Hough transform +enum HoughModes { + + /** classical or standard Hough transform. Every line is represented by two floating-point + numbers \f$(\rho, \theta)\f$ , where \f$\rho\f$ is a distance between (0,0) point and the line, + and \f$\theta\f$ is the angle between x-axis and the normal to the line. Thus, the matrix must + be (the created sequence will be) of CV_32FC2 type */ + HOUGH_STANDARD = 0, + /** probabilistic Hough transform (more efficient in case if the picture contains a few long + linear segments). It returns line segments rather than the whole line. Each segment is + represented by starting and ending points, and the matrix must be (the created sequence will + be) of the CV_32SC4 type. */ + HOUGH_PROBABILISTIC = 1, + /** multi-scale variant of the classical Hough transform. The lines are encoded the same way as + HOUGH_STANDARD. */ + HOUGH_MULTI_SCALE = 2, + HOUGH_GRADIENT = 3, //!< basically *21HT*, described in @cite Yuen90 + HOUGH_GRADIENT_ALT = 4, //!< variation of HOUGH_GRADIENT to get better accuracy +}; + +//! Variants of Line Segment %Detector +enum LineSegmentDetectorModes { + LSD_REFINE_NONE = 0, //!< No refinement applied + LSD_REFINE_STD = 1, //!< Standard refinement is applied. E.g. breaking arches into smaller straighter line approximations. + LSD_REFINE_ADV = 2 //!< Advanced refinement. Number of false alarms is calculated, lines are + //!< refined through increase of precision, decrement in size, etc. +}; + +//! @} imgproc_feature + +/** Histogram comparison methods + @ingroup imgproc_hist +*/ +enum HistCompMethods { + /** Correlation + \f[d(H_1,H_2) = \frac{\sum_I (H_1(I) - \bar{H_1}) (H_2(I) - \bar{H_2})}{\sqrt{\sum_I(H_1(I) - \bar{H_1})^2 \sum_I(H_2(I) - \bar{H_2})^2}}\f] + where + \f[\bar{H_k} = \frac{1}{N} \sum _J H_k(J)\f] + and \f$N\f$ is a total number of histogram bins. */ + HISTCMP_CORREL = 0, + /** Chi-Square + \f[d(H_1,H_2) = \sum _I \frac{\left(H_1(I)-H_2(I)\right)^2}{H_1(I)}\f] */ + HISTCMP_CHISQR = 1, + /** Intersection + \f[d(H_1,H_2) = \sum _I \min (H_1(I), H_2(I))\f] */ + HISTCMP_INTERSECT = 2, + /** Bhattacharyya distance + (In fact, OpenCV computes Hellinger distance, which is related to Bhattacharyya coefficient.) + \f[d(H_1,H_2) = \sqrt{1 - \frac{1}{\sqrt{\bar{H_1} \bar{H_2} N^2}} \sum_I \sqrt{H_1(I) \cdot H_2(I)}}\f] */ + HISTCMP_BHATTACHARYYA = 3, + HISTCMP_HELLINGER = HISTCMP_BHATTACHARYYA, //!< Synonym for HISTCMP_BHATTACHARYYA + /** Alternative Chi-Square + \f[d(H_1,H_2) = 2 * \sum _I \frac{\left(H_1(I)-H_2(I)\right)^2}{H_1(I)+H_2(I)}\f] + This alternative formula is regularly used for texture comparison. See e.g. @cite Puzicha1997 */ + HISTCMP_CHISQR_ALT = 4, + /** Kullback-Leibler divergence + \f[d(H_1,H_2) = \sum _I H_1(I) \log \left(\frac{H_1(I)}{H_2(I)}\right)\f] */ + HISTCMP_KL_DIV = 5 +}; + +/** the color conversion codes +@see @ref imgproc_color_conversions +@ingroup imgproc_color_conversions + */ +enum ColorConversionCodes { + COLOR_BGR2BGRA = 0, //!< add alpha channel to RGB or BGR image + COLOR_RGB2RGBA = COLOR_BGR2BGRA, + + COLOR_BGRA2BGR = 1, //!< remove alpha channel from RGB or BGR image + COLOR_RGBA2RGB = COLOR_BGRA2BGR, + + COLOR_BGR2RGBA = 2, //!< convert between RGB and BGR color spaces (with or without alpha channel) + COLOR_RGB2BGRA = COLOR_BGR2RGBA, + + COLOR_RGBA2BGR = 3, + COLOR_BGRA2RGB = COLOR_RGBA2BGR, + + COLOR_BGR2RGB = 4, + COLOR_RGB2BGR = COLOR_BGR2RGB, + + COLOR_BGRA2RGBA = 5, + COLOR_RGBA2BGRA = COLOR_BGRA2RGBA, + + COLOR_BGR2GRAY = 6, //!< convert between RGB/BGR and grayscale, @ref color_convert_rgb_gray "color conversions" + COLOR_RGB2GRAY = 7, + COLOR_GRAY2BGR = 8, + COLOR_GRAY2RGB = COLOR_GRAY2BGR, + COLOR_GRAY2BGRA = 9, + COLOR_GRAY2RGBA = COLOR_GRAY2BGRA, + COLOR_BGRA2GRAY = 10, + COLOR_RGBA2GRAY = 11, + + COLOR_BGR2BGR565 = 12, //!< convert between RGB/BGR and BGR565 (16-bit images) + COLOR_RGB2BGR565 = 13, + COLOR_BGR5652BGR = 14, + COLOR_BGR5652RGB = 15, + COLOR_BGRA2BGR565 = 16, + COLOR_RGBA2BGR565 = 17, + COLOR_BGR5652BGRA = 18, + COLOR_BGR5652RGBA = 19, + + COLOR_GRAY2BGR565 = 20, //!< convert between grayscale to BGR565 (16-bit images) + COLOR_BGR5652GRAY = 21, + + COLOR_BGR2BGR555 = 22, //!< convert between RGB/BGR and BGR555 (16-bit images) + COLOR_RGB2BGR555 = 23, + COLOR_BGR5552BGR = 24, + COLOR_BGR5552RGB = 25, + COLOR_BGRA2BGR555 = 26, + COLOR_RGBA2BGR555 = 27, + COLOR_BGR5552BGRA = 28, + COLOR_BGR5552RGBA = 29, + + COLOR_GRAY2BGR555 = 30, //!< convert between grayscale and BGR555 (16-bit images) + COLOR_BGR5552GRAY = 31, + + COLOR_BGR2XYZ = 32, //!< convert RGB/BGR to CIE XYZ, @ref color_convert_rgb_xyz "color conversions" + COLOR_RGB2XYZ = 33, + COLOR_XYZ2BGR = 34, + COLOR_XYZ2RGB = 35, + + COLOR_BGR2YCrCb = 36, //!< convert RGB/BGR to luma-chroma (aka YCC), @ref color_convert_rgb_ycrcb "color conversions" + COLOR_RGB2YCrCb = 37, + COLOR_YCrCb2BGR = 38, + COLOR_YCrCb2RGB = 39, + + COLOR_BGR2HSV = 40, //!< convert RGB/BGR to HSV (hue saturation value) with H range 0..180 if 8 bit image, @ref color_convert_rgb_hsv "color conversions" + COLOR_RGB2HSV = 41, + + COLOR_BGR2Lab = 44, //!< convert RGB/BGR to CIE Lab, @ref color_convert_rgb_lab "color conversions" + COLOR_RGB2Lab = 45, + + COLOR_BGR2Luv = 50, //!< convert RGB/BGR to CIE Luv, @ref color_convert_rgb_luv "color conversions" + COLOR_RGB2Luv = 51, + COLOR_BGR2HLS = 52, //!< convert RGB/BGR to HLS (hue lightness saturation) with H range 0..180 if 8 bit image, @ref color_convert_rgb_hls "color conversions" + COLOR_RGB2HLS = 53, + + COLOR_HSV2BGR = 54, //!< backward conversions HSV to RGB/BGR with H range 0..180 if 8 bit image + COLOR_HSV2RGB = 55, + + COLOR_Lab2BGR = 56, + COLOR_Lab2RGB = 57, + COLOR_Luv2BGR = 58, + COLOR_Luv2RGB = 59, + COLOR_HLS2BGR = 60, //!< backward conversions HLS to RGB/BGR with H range 0..180 if 8 bit image + COLOR_HLS2RGB = 61, + + COLOR_BGR2HSV_FULL = 66, //!< convert RGB/BGR to HSV (hue saturation value) with H range 0..255 if 8 bit image, @ref color_convert_rgb_hsv "color conversions" + COLOR_RGB2HSV_FULL = 67, + COLOR_BGR2HLS_FULL = 68, //!< convert RGB/BGR to HLS (hue lightness saturation) with H range 0..255 if 8 bit image, @ref color_convert_rgb_hls "color conversions" + COLOR_RGB2HLS_FULL = 69, + + COLOR_HSV2BGR_FULL = 70, //!< backward conversions HSV to RGB/BGR with H range 0..255 if 8 bit image + COLOR_HSV2RGB_FULL = 71, + COLOR_HLS2BGR_FULL = 72, //!< backward conversions HLS to RGB/BGR with H range 0..255 if 8 bit image + COLOR_HLS2RGB_FULL = 73, + + COLOR_LBGR2Lab = 74, + COLOR_LRGB2Lab = 75, + COLOR_LBGR2Luv = 76, + COLOR_LRGB2Luv = 77, + + COLOR_Lab2LBGR = 78, + COLOR_Lab2LRGB = 79, + COLOR_Luv2LBGR = 80, + COLOR_Luv2LRGB = 81, + + COLOR_BGR2YUV = 82, //!< convert between RGB/BGR and YUV + COLOR_RGB2YUV = 83, + COLOR_YUV2BGR = 84, + COLOR_YUV2RGB = 85, + + //! YUV 4:2:0 family to RGB + COLOR_YUV2RGB_NV12 = 90, + COLOR_YUV2BGR_NV12 = 91, + COLOR_YUV2RGB_NV21 = 92, + COLOR_YUV2BGR_NV21 = 93, + COLOR_YUV420sp2RGB = COLOR_YUV2RGB_NV21, + COLOR_YUV420sp2BGR = COLOR_YUV2BGR_NV21, + + COLOR_YUV2RGBA_NV12 = 94, + COLOR_YUV2BGRA_NV12 = 95, + COLOR_YUV2RGBA_NV21 = 96, + COLOR_YUV2BGRA_NV21 = 97, + COLOR_YUV420sp2RGBA = COLOR_YUV2RGBA_NV21, + COLOR_YUV420sp2BGRA = COLOR_YUV2BGRA_NV21, + + COLOR_YUV2RGB_YV12 = 98, + COLOR_YUV2BGR_YV12 = 99, + COLOR_YUV2RGB_IYUV = 100, + COLOR_YUV2BGR_IYUV = 101, + COLOR_YUV2RGB_I420 = COLOR_YUV2RGB_IYUV, + COLOR_YUV2BGR_I420 = COLOR_YUV2BGR_IYUV, + COLOR_YUV420p2RGB = COLOR_YUV2RGB_YV12, + COLOR_YUV420p2BGR = COLOR_YUV2BGR_YV12, + + COLOR_YUV2RGBA_YV12 = 102, + COLOR_YUV2BGRA_YV12 = 103, + COLOR_YUV2RGBA_IYUV = 104, + COLOR_YUV2BGRA_IYUV = 105, + COLOR_YUV2RGBA_I420 = COLOR_YUV2RGBA_IYUV, + COLOR_YUV2BGRA_I420 = COLOR_YUV2BGRA_IYUV, + COLOR_YUV420p2RGBA = COLOR_YUV2RGBA_YV12, + COLOR_YUV420p2BGRA = COLOR_YUV2BGRA_YV12, + + COLOR_YUV2GRAY_420 = 106, + COLOR_YUV2GRAY_NV21 = COLOR_YUV2GRAY_420, + COLOR_YUV2GRAY_NV12 = COLOR_YUV2GRAY_420, + COLOR_YUV2GRAY_YV12 = COLOR_YUV2GRAY_420, + COLOR_YUV2GRAY_IYUV = COLOR_YUV2GRAY_420, + COLOR_YUV2GRAY_I420 = COLOR_YUV2GRAY_420, + COLOR_YUV420sp2GRAY = COLOR_YUV2GRAY_420, + COLOR_YUV420p2GRAY = COLOR_YUV2GRAY_420, + + //! YUV 4:2:2 family to RGB + COLOR_YUV2RGB_UYVY = 107, + COLOR_YUV2BGR_UYVY = 108, + //COLOR_YUV2RGB_VYUY = 109, + //COLOR_YUV2BGR_VYUY = 110, + COLOR_YUV2RGB_Y422 = COLOR_YUV2RGB_UYVY, + COLOR_YUV2BGR_Y422 = COLOR_YUV2BGR_UYVY, + COLOR_YUV2RGB_UYNV = COLOR_YUV2RGB_UYVY, + COLOR_YUV2BGR_UYNV = COLOR_YUV2BGR_UYVY, + + COLOR_YUV2RGBA_UYVY = 111, + COLOR_YUV2BGRA_UYVY = 112, + //COLOR_YUV2RGBA_VYUY = 113, + //COLOR_YUV2BGRA_VYUY = 114, + COLOR_YUV2RGBA_Y422 = COLOR_YUV2RGBA_UYVY, + COLOR_YUV2BGRA_Y422 = COLOR_YUV2BGRA_UYVY, + COLOR_YUV2RGBA_UYNV = COLOR_YUV2RGBA_UYVY, + COLOR_YUV2BGRA_UYNV = COLOR_YUV2BGRA_UYVY, + + COLOR_YUV2RGB_YUY2 = 115, + COLOR_YUV2BGR_YUY2 = 116, + COLOR_YUV2RGB_YVYU = 117, + COLOR_YUV2BGR_YVYU = 118, + COLOR_YUV2RGB_YUYV = COLOR_YUV2RGB_YUY2, + COLOR_YUV2BGR_YUYV = COLOR_YUV2BGR_YUY2, + COLOR_YUV2RGB_YUNV = COLOR_YUV2RGB_YUY2, + COLOR_YUV2BGR_YUNV = COLOR_YUV2BGR_YUY2, + + COLOR_YUV2RGBA_YUY2 = 119, + COLOR_YUV2BGRA_YUY2 = 120, + COLOR_YUV2RGBA_YVYU = 121, + COLOR_YUV2BGRA_YVYU = 122, + COLOR_YUV2RGBA_YUYV = COLOR_YUV2RGBA_YUY2, + COLOR_YUV2BGRA_YUYV = COLOR_YUV2BGRA_YUY2, + COLOR_YUV2RGBA_YUNV = COLOR_YUV2RGBA_YUY2, + COLOR_YUV2BGRA_YUNV = COLOR_YUV2BGRA_YUY2, + + COLOR_YUV2GRAY_UYVY = 123, + COLOR_YUV2GRAY_YUY2 = 124, + //CV_YUV2GRAY_VYUY = CV_YUV2GRAY_UYVY, + COLOR_YUV2GRAY_Y422 = COLOR_YUV2GRAY_UYVY, + COLOR_YUV2GRAY_UYNV = COLOR_YUV2GRAY_UYVY, + COLOR_YUV2GRAY_YVYU = COLOR_YUV2GRAY_YUY2, + COLOR_YUV2GRAY_YUYV = COLOR_YUV2GRAY_YUY2, + COLOR_YUV2GRAY_YUNV = COLOR_YUV2GRAY_YUY2, + + //! alpha premultiplication + COLOR_RGBA2mRGBA = 125, + COLOR_mRGBA2RGBA = 126, + + //! RGB to YUV 4:2:0 family + COLOR_RGB2YUV_I420 = 127, + COLOR_BGR2YUV_I420 = 128, + COLOR_RGB2YUV_IYUV = COLOR_RGB2YUV_I420, + COLOR_BGR2YUV_IYUV = COLOR_BGR2YUV_I420, + + COLOR_RGBA2YUV_I420 = 129, + COLOR_BGRA2YUV_I420 = 130, + COLOR_RGBA2YUV_IYUV = COLOR_RGBA2YUV_I420, + COLOR_BGRA2YUV_IYUV = COLOR_BGRA2YUV_I420, + COLOR_RGB2YUV_YV12 = 131, + COLOR_BGR2YUV_YV12 = 132, + COLOR_RGBA2YUV_YV12 = 133, + COLOR_BGRA2YUV_YV12 = 134, + + //! Demosaicing, see @ref color_convert_bayer "color conversions" for additional information + COLOR_BayerBG2BGR = 46, //!< equivalent to RGGB Bayer pattern + COLOR_BayerGB2BGR = 47, //!< equivalent to GRBG Bayer pattern + COLOR_BayerRG2BGR = 48, //!< equivalent to BGGR Bayer pattern + COLOR_BayerGR2BGR = 49, //!< equivalent to GBRG Bayer pattern + + COLOR_BayerRGGB2BGR = COLOR_BayerBG2BGR, + COLOR_BayerGRBG2BGR = COLOR_BayerGB2BGR, + COLOR_BayerBGGR2BGR = COLOR_BayerRG2BGR, + COLOR_BayerGBRG2BGR = COLOR_BayerGR2BGR, + + COLOR_BayerRGGB2RGB = COLOR_BayerBGGR2BGR, + COLOR_BayerGRBG2RGB = COLOR_BayerGBRG2BGR, + COLOR_BayerBGGR2RGB = COLOR_BayerRGGB2BGR, + COLOR_BayerGBRG2RGB = COLOR_BayerGRBG2BGR, + + COLOR_BayerBG2RGB = COLOR_BayerRG2BGR, //!< equivalent to RGGB Bayer pattern + COLOR_BayerGB2RGB = COLOR_BayerGR2BGR, //!< equivalent to GRBG Bayer pattern + COLOR_BayerRG2RGB = COLOR_BayerBG2BGR, //!< equivalent to BGGR Bayer pattern + COLOR_BayerGR2RGB = COLOR_BayerGB2BGR, //!< equivalent to GBRG Bayer pattern + + COLOR_BayerBG2GRAY = 86, //!< equivalent to RGGB Bayer pattern + COLOR_BayerGB2GRAY = 87, //!< equivalent to GRBG Bayer pattern + COLOR_BayerRG2GRAY = 88, //!< equivalent to BGGR Bayer pattern + COLOR_BayerGR2GRAY = 89, //!< equivalent to GBRG Bayer pattern + + COLOR_BayerRGGB2GRAY = COLOR_BayerBG2GRAY, + COLOR_BayerGRBG2GRAY = COLOR_BayerGB2GRAY, + COLOR_BayerBGGR2GRAY = COLOR_BayerRG2GRAY, + COLOR_BayerGBRG2GRAY = COLOR_BayerGR2GRAY, + + //! Demosaicing using Variable Number of Gradients + COLOR_BayerBG2BGR_VNG = 62, //!< equivalent to RGGB Bayer pattern + COLOR_BayerGB2BGR_VNG = 63, //!< equivalent to GRBG Bayer pattern + COLOR_BayerRG2BGR_VNG = 64, //!< equivalent to BGGR Bayer pattern + COLOR_BayerGR2BGR_VNG = 65, //!< equivalent to GBRG Bayer pattern + + COLOR_BayerRGGB2BGR_VNG = COLOR_BayerBG2BGR_VNG, + COLOR_BayerGRBG2BGR_VNG = COLOR_BayerGB2BGR_VNG, + COLOR_BayerBGGR2BGR_VNG = COLOR_BayerRG2BGR_VNG, + COLOR_BayerGBRG2BGR_VNG = COLOR_BayerGR2BGR_VNG, + + COLOR_BayerRGGB2RGB_VNG = COLOR_BayerBGGR2BGR_VNG, + COLOR_BayerGRBG2RGB_VNG = COLOR_BayerGBRG2BGR_VNG, + COLOR_BayerBGGR2RGB_VNG = COLOR_BayerRGGB2BGR_VNG, + COLOR_BayerGBRG2RGB_VNG = COLOR_BayerGRBG2BGR_VNG, + + COLOR_BayerBG2RGB_VNG = COLOR_BayerRG2BGR_VNG, //!< equivalent to RGGB Bayer pattern + COLOR_BayerGB2RGB_VNG = COLOR_BayerGR2BGR_VNG, //!< equivalent to GRBG Bayer pattern + COLOR_BayerRG2RGB_VNG = COLOR_BayerBG2BGR_VNG, //!< equivalent to BGGR Bayer pattern + COLOR_BayerGR2RGB_VNG = COLOR_BayerGB2BGR_VNG, //!< equivalent to GBRG Bayer pattern + + //! Edge-Aware Demosaicing + COLOR_BayerBG2BGR_EA = 135, //!< equivalent to RGGB Bayer pattern + COLOR_BayerGB2BGR_EA = 136, //!< equivalent to GRBG Bayer pattern + COLOR_BayerRG2BGR_EA = 137, //!< equivalent to BGGR Bayer pattern + COLOR_BayerGR2BGR_EA = 138, //!< equivalent to GBRG Bayer pattern + + COLOR_BayerRGGB2BGR_EA = COLOR_BayerBG2BGR_EA, + COLOR_BayerGRBG2BGR_EA = COLOR_BayerGB2BGR_EA, + COLOR_BayerBGGR2BGR_EA = COLOR_BayerRG2BGR_EA, + COLOR_BayerGBRG2BGR_EA = COLOR_BayerGR2BGR_EA, + + COLOR_BayerRGGB2RGB_EA = COLOR_BayerBGGR2BGR_EA, + COLOR_BayerGRBG2RGB_EA = COLOR_BayerGBRG2BGR_EA, + COLOR_BayerBGGR2RGB_EA = COLOR_BayerRGGB2BGR_EA, + COLOR_BayerGBRG2RGB_EA = COLOR_BayerGRBG2BGR_EA, + + COLOR_BayerBG2RGB_EA = COLOR_BayerRG2BGR_EA, //!< equivalent to RGGB Bayer pattern + COLOR_BayerGB2RGB_EA = COLOR_BayerGR2BGR_EA, //!< equivalent to GRBG Bayer pattern + COLOR_BayerRG2RGB_EA = COLOR_BayerBG2BGR_EA, //!< equivalent to BGGR Bayer pattern + COLOR_BayerGR2RGB_EA = COLOR_BayerGB2BGR_EA, //!< equivalent to GBRG Bayer pattern + + //! Demosaicing with alpha channel + COLOR_BayerBG2BGRA = 139, //!< equivalent to RGGB Bayer pattern + COLOR_BayerGB2BGRA = 140, //!< equivalent to GRBG Bayer pattern + COLOR_BayerRG2BGRA = 141, //!< equivalent to BGGR Bayer pattern + COLOR_BayerGR2BGRA = 142, //!< equivalent to GBRG Bayer pattern + + COLOR_BayerRGGB2BGRA = COLOR_BayerBG2BGRA, + COLOR_BayerGRBG2BGRA = COLOR_BayerGB2BGRA, + COLOR_BayerBGGR2BGRA = COLOR_BayerRG2BGRA, + COLOR_BayerGBRG2BGRA = COLOR_BayerGR2BGRA, + + COLOR_BayerRGGB2RGBA = COLOR_BayerBGGR2BGRA, + COLOR_BayerGRBG2RGBA = COLOR_BayerGBRG2BGRA, + COLOR_BayerBGGR2RGBA = COLOR_BayerRGGB2BGRA, + COLOR_BayerGBRG2RGBA = COLOR_BayerGRBG2BGRA, + + COLOR_BayerBG2RGBA = COLOR_BayerRG2BGRA, //!< equivalent to RGGB Bayer pattern + COLOR_BayerGB2RGBA = COLOR_BayerGR2BGRA, //!< equivalent to GRBG Bayer pattern + COLOR_BayerRG2RGBA = COLOR_BayerBG2BGRA, //!< equivalent to BGGR Bayer pattern + COLOR_BayerGR2RGBA = COLOR_BayerGB2BGRA, //!< equivalent to GBRG Bayer pattern + + COLOR_COLORCVT_MAX = 143 +}; + +//! @addtogroup imgproc_shape +//! @{ + +//! types of intersection between rectangles +enum RectanglesIntersectTypes { + INTERSECT_NONE = 0, //!< No intersection + INTERSECT_PARTIAL = 1, //!< There is a partial intersection + INTERSECT_FULL = 2 //!< One of the rectangle is fully enclosed in the other +}; + +/** types of line +@ingroup imgproc_draw +*/ +enum LineTypes { + FILLED = -1, + LINE_4 = 4, //!< 4-connected line + LINE_8 = 8, //!< 8-connected line + LINE_AA = 16 //!< antialiased line +}; + +/** Only a subset of Hershey fonts are supported +@ingroup imgproc_draw +*/ +enum HersheyFonts { + FONT_HERSHEY_SIMPLEX = 0, //!< normal size sans-serif font + FONT_HERSHEY_PLAIN = 1, //!< small size sans-serif font + FONT_HERSHEY_DUPLEX = 2, //!< normal size sans-serif font (more complex than FONT_HERSHEY_SIMPLEX) + FONT_HERSHEY_COMPLEX = 3, //!< normal size serif font + FONT_HERSHEY_TRIPLEX = 4, //!< normal size serif font (more complex than FONT_HERSHEY_COMPLEX) + FONT_HERSHEY_COMPLEX_SMALL = 5, //!< smaller version of FONT_HERSHEY_COMPLEX + FONT_HERSHEY_SCRIPT_SIMPLEX = 6, //!< hand-writing style font + FONT_HERSHEY_SCRIPT_COMPLEX = 7, //!< more complex variant of FONT_HERSHEY_SCRIPT_SIMPLEX + FONT_ITALIC = 16 //!< flag for italic font +}; + +/** Possible set of marker types used for the cv::drawMarker function +@ingroup imgproc_draw +*/ +enum MarkerTypes +{ + MARKER_CROSS = 0, //!< A crosshair marker shape + MARKER_TILTED_CROSS = 1, //!< A 45 degree tilted crosshair marker shape + MARKER_STAR = 2, //!< A star marker shape, combination of cross and tilted cross + MARKER_DIAMOND = 3, //!< A diamond marker shape + MARKER_SQUARE = 4, //!< A square marker shape + MARKER_TRIANGLE_UP = 5, //!< An upwards pointing triangle marker shape + MARKER_TRIANGLE_DOWN = 6 //!< A downwards pointing triangle marker shape +}; + +/** @brief finds arbitrary template in the grayscale image using Generalized Hough Transform +*/ +class CV_EXPORTS_W GeneralizedHough : public Algorithm +{ +public: + //! set template to search + CV_WRAP virtual void setTemplate(InputArray templ, Point templCenter = Point(-1, -1)) = 0; + CV_WRAP virtual void setTemplate(InputArray edges, InputArray dx, InputArray dy, Point templCenter = Point(-1, -1)) = 0; + + //! find template on image + CV_WRAP virtual void detect(InputArray image, OutputArray positions, OutputArray votes = noArray()) = 0; + CV_WRAP virtual void detect(InputArray edges, InputArray dx, InputArray dy, OutputArray positions, OutputArray votes = noArray()) = 0; + + //! Canny low threshold. + CV_WRAP virtual void setCannyLowThresh(int cannyLowThresh) = 0; + CV_WRAP virtual int getCannyLowThresh() const = 0; + + //! Canny high threshold. + CV_WRAP virtual void setCannyHighThresh(int cannyHighThresh) = 0; + CV_WRAP virtual int getCannyHighThresh() const = 0; + + //! Minimum distance between the centers of the detected objects. + CV_WRAP virtual void setMinDist(double minDist) = 0; + CV_WRAP virtual double getMinDist() const = 0; + + //! Inverse ratio of the accumulator resolution to the image resolution. + CV_WRAP virtual void setDp(double dp) = 0; + CV_WRAP virtual double getDp() const = 0; + + //! Maximal size of inner buffers. + CV_WRAP virtual void setMaxBufferSize(int maxBufferSize) = 0; + CV_WRAP virtual int getMaxBufferSize() const = 0; +}; + +/** @brief finds arbitrary template in the grayscale image using Generalized Hough Transform + +Detects position only without translation and rotation @cite Ballard1981 . +*/ +class CV_EXPORTS_W GeneralizedHoughBallard : public GeneralizedHough +{ +public: + //! R-Table levels. + CV_WRAP virtual void setLevels(int levels) = 0; + CV_WRAP virtual int getLevels() const = 0; + + //! The accumulator threshold for the template centers at the detection stage. The smaller it is, the more false positions may be detected. + CV_WRAP virtual void setVotesThreshold(int votesThreshold) = 0; + CV_WRAP virtual int getVotesThreshold() const = 0; +}; + +/** @brief finds arbitrary template in the grayscale image using Generalized Hough Transform + +Detects position, translation and rotation @cite Guil1999 . +*/ +class CV_EXPORTS_W GeneralizedHoughGuil : public GeneralizedHough +{ +public: + //! Angle difference in degrees between two points in feature. + CV_WRAP virtual void setXi(double xi) = 0; + CV_WRAP virtual double getXi() const = 0; + + //! Feature table levels. + CV_WRAP virtual void setLevels(int levels) = 0; + CV_WRAP virtual int getLevels() const = 0; + + //! Maximal difference between angles that treated as equal. + CV_WRAP virtual void setAngleEpsilon(double angleEpsilon) = 0; + CV_WRAP virtual double getAngleEpsilon() const = 0; + + //! Minimal rotation angle to detect in degrees. + CV_WRAP virtual void setMinAngle(double minAngle) = 0; + CV_WRAP virtual double getMinAngle() const = 0; + + //! Maximal rotation angle to detect in degrees. + CV_WRAP virtual void setMaxAngle(double maxAngle) = 0; + CV_WRAP virtual double getMaxAngle() const = 0; + + //! Angle step in degrees. + CV_WRAP virtual void setAngleStep(double angleStep) = 0; + CV_WRAP virtual double getAngleStep() const = 0; + + //! Angle votes threshold. + CV_WRAP virtual void setAngleThresh(int angleThresh) = 0; + CV_WRAP virtual int getAngleThresh() const = 0; + + //! Minimal scale to detect. + CV_WRAP virtual void setMinScale(double minScale) = 0; + CV_WRAP virtual double getMinScale() const = 0; + + //! Maximal scale to detect. + CV_WRAP virtual void setMaxScale(double maxScale) = 0; + CV_WRAP virtual double getMaxScale() const = 0; + + //! Scale step. + CV_WRAP virtual void setScaleStep(double scaleStep) = 0; + CV_WRAP virtual double getScaleStep() const = 0; + + //! Scale votes threshold. + CV_WRAP virtual void setScaleThresh(int scaleThresh) = 0; + CV_WRAP virtual int getScaleThresh() const = 0; + + //! Position votes threshold. + CV_WRAP virtual void setPosThresh(int posThresh) = 0; + CV_WRAP virtual int getPosThresh() const = 0; +}; + +//! @} imgproc_shape + +//! @addtogroup imgproc_hist +//! @{ + +/** @brief Base class for Contrast Limited Adaptive Histogram Equalization. +*/ +class CV_EXPORTS_W CLAHE : public Algorithm +{ +public: + /** @brief Equalizes the histogram of a grayscale image using Contrast Limited Adaptive Histogram Equalization. + + @param src Source image of type CV_8UC1 or CV_16UC1. + @param dst Destination image. + */ + CV_WRAP virtual void apply(InputArray src, OutputArray dst) = 0; + + /** @brief Sets threshold for contrast limiting. + + @param clipLimit threshold value. + */ + CV_WRAP virtual void setClipLimit(double clipLimit) = 0; + + //! Returns threshold value for contrast limiting. + CV_WRAP virtual double getClipLimit() const = 0; + + /** @brief Sets size of grid for histogram equalization. Input image will be divided into + equally sized rectangular tiles. + + @param tileGridSize defines the number of tiles in row and column. + */ + CV_WRAP virtual void setTilesGridSize(Size tileGridSize) = 0; + + //!@brief Returns Size defines the number of tiles in row and column. + CV_WRAP virtual Size getTilesGridSize() const = 0; + + CV_WRAP virtual void collectGarbage() = 0; +}; + +//! @} imgproc_hist + +//! @addtogroup imgproc_subdiv2d +//! @{ + +class CV_EXPORTS_W Subdiv2D +{ +public: + /** Subdiv2D point location cases */ + enum { PTLOC_ERROR = -2, //!< Point location error + PTLOC_OUTSIDE_RECT = -1, //!< Point outside the subdivision bounding rect + PTLOC_INSIDE = 0, //!< Point inside some facet + PTLOC_VERTEX = 1, //!< Point coincides with one of the subdivision vertices + PTLOC_ON_EDGE = 2 //!< Point on some edge + }; + + /** Subdiv2D edge type navigation (see: getEdge()) */ + enum { NEXT_AROUND_ORG = 0x00, + NEXT_AROUND_DST = 0x22, + PREV_AROUND_ORG = 0x11, + PREV_AROUND_DST = 0x33, + NEXT_AROUND_LEFT = 0x13, + NEXT_AROUND_RIGHT = 0x31, + PREV_AROUND_LEFT = 0x20, + PREV_AROUND_RIGHT = 0x02 + }; + + /** creates an empty Subdiv2D object. + To create a new empty Delaunay subdivision you need to use the #initDelaunay function. + */ + CV_WRAP Subdiv2D(); + + /** @overload + + @param rect Rectangle that includes all of the 2D points that are to be added to the subdivision. + + The function creates an empty Delaunay subdivision where 2D points can be added using the function + insert() . All of the points to be added must be within the specified rectangle, otherwise a runtime + error is raised. + */ + CV_WRAP Subdiv2D(Rect rect); + + /** @brief Creates a new empty Delaunay subdivision + + @param rect Rectangle that includes all of the 2D points that are to be added to the subdivision. + + */ + CV_WRAP void initDelaunay(Rect rect); + + /** @brief Insert a single point into a Delaunay triangulation. + + @param pt Point to insert. + + The function inserts a single point into a subdivision and modifies the subdivision topology + appropriately. If a point with the same coordinates exists already, no new point is added. + @returns the ID of the point. + + @note If the point is outside of the triangulation specified rect a runtime error is raised. + */ + CV_WRAP int insert(Point2f pt); + + /** @brief Insert multiple points into a Delaunay triangulation. + + @param ptvec Points to insert. + + The function inserts a vector of points into a subdivision and modifies the subdivision topology + appropriately. + */ + CV_WRAP void insert(const std::vector& ptvec); + + /** @brief Returns the location of a point within a Delaunay triangulation. + + @param pt Point to locate. + @param edge Output edge that the point belongs to or is located to the right of it. + @param vertex Optional output vertex the input point coincides with. + + The function locates the input point within the subdivision and gives one of the triangle edges + or vertices. + + @returns an integer which specify one of the following five cases for point location: + - The point falls into some facet. The function returns #PTLOC_INSIDE and edge will contain one of + edges of the facet. + - The point falls onto the edge. The function returns #PTLOC_ON_EDGE and edge will contain this edge. + - The point coincides with one of the subdivision vertices. The function returns #PTLOC_VERTEX and + vertex will contain a pointer to the vertex. + - The point is outside the subdivision reference rectangle. The function returns #PTLOC_OUTSIDE_RECT + and no pointers are filled. + - One of input arguments is invalid. A runtime error is raised or, if silent or "parent" error + processing mode is selected, #PTLOC_ERROR is returned. + */ + CV_WRAP int locate(Point2f pt, CV_OUT int& edge, CV_OUT int& vertex); + + /** @brief Finds the subdivision vertex closest to the given point. + + @param pt Input point. + @param nearestPt Output subdivision vertex point. + + The function is another function that locates the input point within the subdivision. It finds the + subdivision vertex that is the closest to the input point. It is not necessarily one of vertices + of the facet containing the input point, though the facet (located using locate() ) is used as a + starting point. + + @returns vertex ID. + */ + CV_WRAP int findNearest(Point2f pt, CV_OUT Point2f* nearestPt = 0); + + /** @brief Returns a list of all edges. + + @param edgeList Output vector. + + The function gives each edge as a 4 numbers vector, where each two are one of the edge + vertices. i.e. org_x = v[0], org_y = v[1], dst_x = v[2], dst_y = v[3]. + */ + CV_WRAP void getEdgeList(CV_OUT std::vector& edgeList) const; + + /** @brief Returns a list of the leading edge ID connected to each triangle. + + @param leadingEdgeList Output vector. + + The function gives one edge ID for each triangle. + */ + CV_WRAP void getLeadingEdgeList(CV_OUT std::vector& leadingEdgeList) const; + + /** @brief Returns a list of all triangles. + + @param triangleList Output vector. + + The function gives each triangle as a 6 numbers vector, where each two are one of the triangle + vertices. i.e. p1_x = v[0], p1_y = v[1], p2_x = v[2], p2_y = v[3], p3_x = v[4], p3_y = v[5]. + */ + CV_WRAP void getTriangleList(CV_OUT std::vector& triangleList) const; + + /** @brief Returns a list of all Voronoi facets. + + @param idx Vector of vertices IDs to consider. For all vertices you can pass empty vector. + @param facetList Output vector of the Voronoi facets. + @param facetCenters Output vector of the Voronoi facets center points. + + */ + CV_WRAP void getVoronoiFacetList(const std::vector& idx, CV_OUT std::vector >& facetList, + CV_OUT std::vector& facetCenters); + + /** @brief Returns vertex location from vertex ID. + + @param vertex vertex ID. + @param firstEdge Optional. The first edge ID which is connected to the vertex. + @returns vertex (x,y) + + */ + CV_WRAP Point2f getVertex(int vertex, CV_OUT int* firstEdge = 0) const; + + /** @brief Returns one of the edges related to the given edge. + + @param edge Subdivision edge ID. + @param nextEdgeType Parameter specifying which of the related edges to return. + The following values are possible: + - NEXT_AROUND_ORG next around the edge origin ( eOnext on the picture below if e is the input edge) + - NEXT_AROUND_DST next around the edge vertex ( eDnext ) + - PREV_AROUND_ORG previous around the edge origin (reversed eRnext ) + - PREV_AROUND_DST previous around the edge destination (reversed eLnext ) + - NEXT_AROUND_LEFT next around the left facet ( eLnext ) + - NEXT_AROUND_RIGHT next around the right facet ( eRnext ) + - PREV_AROUND_LEFT previous around the left facet (reversed eOnext ) + - PREV_AROUND_RIGHT previous around the right facet (reversed eDnext ) + + ![sample output](pics/quadedge.png) + + @returns edge ID related to the input edge. + */ + CV_WRAP int getEdge( int edge, int nextEdgeType ) const; + + /** @brief Returns next edge around the edge origin. + + @param edge Subdivision edge ID. + + @returns an integer which is next edge ID around the edge origin: eOnext on the + picture above if e is the input edge). + */ + CV_WRAP int nextEdge(int edge) const; + + /** @brief Returns another edge of the same quad-edge. + + @param edge Subdivision edge ID. + @param rotate Parameter specifying which of the edges of the same quad-edge as the input + one to return. The following values are possible: + - 0 - the input edge ( e on the picture below if e is the input edge) + - 1 - the rotated edge ( eRot ) + - 2 - the reversed edge (reversed e (in green)) + - 3 - the reversed rotated edge (reversed eRot (in green)) + + @returns one of the edges ID of the same quad-edge as the input edge. + */ + CV_WRAP int rotateEdge(int edge, int rotate) const; + CV_WRAP int symEdge(int edge) const; + + /** @brief Returns the edge origin. + + @param edge Subdivision edge ID. + @param orgpt Output vertex location. + + @returns vertex ID. + */ + CV_WRAP int edgeOrg(int edge, CV_OUT Point2f* orgpt = 0) const; + + /** @brief Returns the edge destination. + + @param edge Subdivision edge ID. + @param dstpt Output vertex location. + + @returns vertex ID. + */ + CV_WRAP int edgeDst(int edge, CV_OUT Point2f* dstpt = 0) const; + +protected: + int newEdge(); + void deleteEdge(int edge); + int newPoint(Point2f pt, bool isvirtual, int firstEdge = 0); + void deletePoint(int vtx); + void setEdgePoints( int edge, int orgPt, int dstPt ); + void splice( int edgeA, int edgeB ); + int connectEdges( int edgeA, int edgeB ); + void swapEdges( int edge ); + int isRightOf(Point2f pt, int edge) const; + void calcVoronoi(); + void clearVoronoi(); + void checkSubdiv() const; + + struct CV_EXPORTS Vertex + { + Vertex(); + Vertex(Point2f pt, bool isvirtual, int firstEdge=0); + bool isvirtual() const; + bool isfree() const; + + int firstEdge; + int type; + Point2f pt; + }; + + struct CV_EXPORTS QuadEdge + { + QuadEdge(); + QuadEdge(int edgeidx); + bool isfree() const; + + int next[4]; + int pt[4]; + }; + + //! All of the vertices + std::vector vtx; + //! All of the edges + std::vector qedges; + int freeQEdge; + int freePoint; + bool validGeometry; + + int recentEdge; + //! Top left corner of the bounding rect + Point2f topLeft; + //! Bottom right corner of the bounding rect + Point2f bottomRight; +}; + +//! @} imgproc_subdiv2d + +//! @addtogroup imgproc_feature +//! @{ + +/** @example samples/cpp/lsd_lines.cpp +An example using the LineSegmentDetector +\image html building_lsd.png "Sample output image" width=434 height=300 +*/ + +/** @brief Line segment detector class + +following the algorithm described at @cite Rafael12 . + +@note Implementation has been removed from OpenCV version 3.4.6 to 3.4.15 and version 4.1.0 to 4.5.3 due original code license conflict. +restored again after [Computation of a NFA](https://github.com/rafael-grompone-von-gioi/binomial_nfa) code published under the MIT license. +*/ +class CV_EXPORTS_W LineSegmentDetector : public Algorithm +{ +public: + + /** @brief Finds lines in the input image. + + This is the output of the default parameters of the algorithm on the above shown image. + + ![image](pics/building_lsd.png) + + @param image A grayscale (CV_8UC1) input image. If only a roi needs to be selected, use: + `lsd_ptr-\>detect(image(roi), lines, ...); lines += Scalar(roi.x, roi.y, roi.x, roi.y);` + @param lines A vector of Vec4f elements specifying the beginning and ending point of a line. Where + Vec4f is (x1, y1, x2, y2), point 1 is the start, point 2 - end. Returned lines are strictly + oriented depending on the gradient. + @param width Vector of widths of the regions, where the lines are found. E.g. Width of line. + @param prec Vector of precisions with which the lines are found. + @param nfa Vector containing number of false alarms in the line region, with precision of 10%. The + bigger the value, logarithmically better the detection. + - -1 corresponds to 10 mean false alarms + - 0 corresponds to 1 mean false alarm + - 1 corresponds to 0.1 mean false alarms + This vector will be calculated only when the objects type is #LSD_REFINE_ADV. + */ + CV_WRAP virtual void detect(InputArray image, OutputArray lines, + OutputArray width = noArray(), OutputArray prec = noArray(), + OutputArray nfa = noArray()) = 0; + + /** @brief Draws the line segments on a given image. + @param image The image, where the lines will be drawn. Should be bigger or equal to the image, + where the lines were found. + @param lines A vector of the lines that needed to be drawn. + */ + CV_WRAP virtual void drawSegments(InputOutputArray image, InputArray lines) = 0; + + /** @brief Draws two groups of lines in blue and red, counting the non overlapping (mismatching) pixels. + + @param size The size of the image, where lines1 and lines2 were found. + @param lines1 The first group of lines that needs to be drawn. It is visualized in blue color. + @param lines2 The second group of lines. They visualized in red color. + @param image Optional image, where the lines will be drawn. The image should be color(3-channel) + in order for lines1 and lines2 to be drawn in the above mentioned colors. + */ + CV_WRAP virtual int compareSegments(const Size& size, InputArray lines1, InputArray lines2, InputOutputArray image = noArray()) = 0; + + virtual ~LineSegmentDetector() { } +}; + +/** @brief Creates a smart pointer to a LineSegmentDetector object and initializes it. + +The LineSegmentDetector algorithm is defined using the standard values. Only advanced users may want +to edit those, as to tailor it for their own application. + +@param refine The way found lines will be refined, see #LineSegmentDetectorModes +@param scale The scale of the image that will be used to find the lines. Range (0..1]. +@param sigma_scale Sigma for Gaussian filter. It is computed as sigma = sigma_scale/scale. +@param quant Bound to the quantization error on the gradient norm. +@param ang_th Gradient angle tolerance in degrees. +@param log_eps Detection threshold: -log10(NFA) \> log_eps. Used only when advance refinement is chosen. +@param density_th Minimal density of aligned region points in the enclosing rectangle. +@param n_bins Number of bins in pseudo-ordering of gradient modulus. + */ +CV_EXPORTS_W Ptr createLineSegmentDetector( + int refine = LSD_REFINE_STD, double scale = 0.8, + double sigma_scale = 0.6, double quant = 2.0, double ang_th = 22.5, + double log_eps = 0, double density_th = 0.7, int n_bins = 1024); + +//! @} imgproc_feature + +//! @addtogroup imgproc_filter +//! @{ + +/** @brief Returns Gaussian filter coefficients. + +The function computes and returns the \f$\texttt{ksize} \times 1\f$ matrix of Gaussian filter +coefficients: + +\f[G_i= \alpha *e^{-(i-( \texttt{ksize} -1)/2)^2/(2* \texttt{sigma}^2)},\f] + +where \f$i=0..\texttt{ksize}-1\f$ and \f$\alpha\f$ is the scale factor chosen so that \f$\sum_i G_i=1\f$. + +Two of such generated kernels can be passed to sepFilter2D. Those functions automatically recognize +smoothing kernels (a symmetrical kernel with sum of weights equal to 1) and handle them accordingly. +You may also use the higher-level GaussianBlur. +@param ksize Aperture size. It should be odd ( \f$\texttt{ksize} \mod 2 = 1\f$ ) and positive. +@param sigma Gaussian standard deviation. If it is non-positive, it is computed from ksize as +`sigma = 0.3*((ksize-1)*0.5 - 1) + 0.8`. +@param ktype Type of filter coefficients. It can be CV_32F or CV_64F . +@sa sepFilter2D, getDerivKernels, getStructuringElement, GaussianBlur + */ +CV_EXPORTS_W Mat getGaussianKernel( int ksize, double sigma, int ktype = CV_64F ); + +/** @brief Returns filter coefficients for computing spatial image derivatives. + +The function computes and returns the filter coefficients for spatial image derivatives. When +`ksize=FILTER_SCHARR`, the Scharr \f$3 \times 3\f$ kernels are generated (see #Scharr). Otherwise, Sobel +kernels are generated (see #Sobel). The filters are normally passed to #sepFilter2D or to + +@param kx Output matrix of row filter coefficients. It has the type ktype . +@param ky Output matrix of column filter coefficients. It has the type ktype . +@param dx Derivative order in respect of x. +@param dy Derivative order in respect of y. +@param ksize Aperture size. It can be FILTER_SCHARR, 1, 3, 5, or 7. +@param normalize Flag indicating whether to normalize (scale down) the filter coefficients or not. +Theoretically, the coefficients should have the denominator \f$=2^{ksize*2-dx-dy-2}\f$. If you are +going to filter floating-point images, you are likely to use the normalized kernels. But if you +compute derivatives of an 8-bit image, store the results in a 16-bit image, and wish to preserve +all the fractional bits, you may want to set normalize=false . +@param ktype Type of filter coefficients. It can be CV_32f or CV_64F . + */ +CV_EXPORTS_W void getDerivKernels( OutputArray kx, OutputArray ky, + int dx, int dy, int ksize, + bool normalize = false, int ktype = CV_32F ); + +/** @brief Returns Gabor filter coefficients. + +For more details about gabor filter equations and parameters, see: [Gabor +Filter](http://en.wikipedia.org/wiki/Gabor_filter). + +@param ksize Size of the filter returned. +@param sigma Standard deviation of the gaussian envelope. +@param theta Orientation of the normal to the parallel stripes of a Gabor function. +@param lambd Wavelength of the sinusoidal factor. +@param gamma Spatial aspect ratio. +@param psi Phase offset. +@param ktype Type of filter coefficients. It can be CV_32F or CV_64F . + */ +CV_EXPORTS_W Mat getGaborKernel( Size ksize, double sigma, double theta, double lambd, + double gamma, double psi = CV_PI*0.5, int ktype = CV_64F ); + +//! returns "magic" border value for erosion and dilation. It is automatically transformed to Scalar::all(-DBL_MAX) for dilation. +static inline Scalar morphologyDefaultBorderValue() { return Scalar::all(DBL_MAX); } + +/** @brief Returns a structuring element of the specified size and shape for morphological operations. + +The function constructs and returns the structuring element that can be further passed to #erode, +#dilate or #morphologyEx. But you can also construct an arbitrary binary mask yourself and use it as +the structuring element. + +@param shape Element shape that could be one of #MorphShapes +@param ksize Size of the structuring element. +@param anchor Anchor position within the element. The default value \f$(-1, -1)\f$ means that the +anchor is at the center. Note that only the shape of a cross-shaped element depends on the anchor +position. In other cases the anchor just regulates how much the result of the morphological +operation is shifted. + */ +CV_EXPORTS_W Mat getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1)); + +/** @example samples/cpp/tutorial_code/ImgProc/Smoothing/Smoothing.cpp +Sample code for simple filters +![Sample screenshot](Smoothing_Tutorial_Result_Median_Filter.jpg) +Check @ref tutorial_gausian_median_blur_bilateral_filter "the corresponding tutorial" for more details + */ + +/** @brief Blurs an image using the median filter. + +The function smoothes an image using the median filter with the \f$\texttt{ksize} \times +\texttt{ksize}\f$ aperture. Each channel of a multi-channel image is processed independently. +In-place operation is supported. + +@note The median filter uses #BORDER_REPLICATE internally to cope with border pixels, see #BorderTypes + +@param src input 1-, 3-, or 4-channel image; when ksize is 3 or 5, the image depth should be +CV_8U, CV_16U, or CV_32F, for larger aperture sizes, it can only be CV_8U. +@param dst destination array of the same size and type as src. +@param ksize aperture linear size; it must be odd and greater than 1, for example: 3, 5, 7 ... +@sa bilateralFilter, blur, boxFilter, GaussianBlur + */ +CV_EXPORTS_W void medianBlur( InputArray src, OutputArray dst, int ksize ); + +/** @brief Blurs an image using a Gaussian filter. + +The function convolves the source image with the specified Gaussian kernel. In-place filtering is +supported. + +@param src input image; the image can have any number of channels, which are processed +independently, but the depth should be CV_8U, CV_16U, CV_16S, CV_32F or CV_64F. +@param dst output image of the same size and type as src. +@param ksize Gaussian kernel size. ksize.width and ksize.height can differ but they both must be +positive and odd. Or, they can be zero's and then they are computed from sigma. +@param sigmaX Gaussian kernel standard deviation in X direction. +@param sigmaY Gaussian kernel standard deviation in Y direction; if sigmaY is zero, it is set to be +equal to sigmaX, if both sigmas are zeros, they are computed from ksize.width and ksize.height, +respectively (see #getGaussianKernel for details); to fully control the result regardless of +possible future modifications of all this semantics, it is recommended to specify all of ksize, +sigmaX, and sigmaY. +@param borderType pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not supported. + +@sa sepFilter2D, filter2D, blur, boxFilter, bilateralFilter, medianBlur + */ +CV_EXPORTS_W void GaussianBlur( InputArray src, OutputArray dst, Size ksize, + double sigmaX, double sigmaY = 0, + int borderType = BORDER_DEFAULT ); + +/** @brief Applies the bilateral filter to an image. + +The function applies bilateral filtering to the input image, as described in +http://www.dai.ed.ac.uk/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html +bilateralFilter can reduce unwanted noise very well while keeping edges fairly sharp. However, it is +very slow compared to most filters. + +_Sigma values_: For simplicity, you can set the 2 sigma values to be the same. If they are small (\< +10), the filter will not have much effect, whereas if they are large (\> 150), they will have a very +strong effect, making the image look "cartoonish". + +_Filter size_: Large filters (d \> 5) are very slow, so it is recommended to use d=5 for real-time +applications, and perhaps d=9 for offline applications that need heavy noise filtering. + +This filter does not work inplace. +@param src Source 8-bit or floating-point, 1-channel or 3-channel image. +@param dst Destination image of the same size and type as src . +@param d Diameter of each pixel neighborhood that is used during filtering. If it is non-positive, +it is computed from sigmaSpace. +@param sigmaColor Filter sigma in the color space. A larger value of the parameter means that +farther colors within the pixel neighborhood (see sigmaSpace) will be mixed together, resulting +in larger areas of semi-equal color. +@param sigmaSpace Filter sigma in the coordinate space. A larger value of the parameter means that +farther pixels will influence each other as long as their colors are close enough (see sigmaColor +). When d\>0, it specifies the neighborhood size regardless of sigmaSpace. Otherwise, d is +proportional to sigmaSpace. +@param borderType border mode used to extrapolate pixels outside of the image, see #BorderTypes + */ +CV_EXPORTS_W void bilateralFilter( InputArray src, OutputArray dst, int d, + double sigmaColor, double sigmaSpace, + int borderType = BORDER_DEFAULT ); + +/** @brief Blurs an image using the box filter. + +The function smooths an image using the kernel: + +\f[\texttt{K} = \alpha \begin{bmatrix} 1 & 1 & 1 & \cdots & 1 & 1 \\ 1 & 1 & 1 & \cdots & 1 & 1 \\ \hdotsfor{6} \\ 1 & 1 & 1 & \cdots & 1 & 1 \end{bmatrix}\f] + +where + +\f[\alpha = \begin{cases} \frac{1}{\texttt{ksize.width*ksize.height}} & \texttt{when } \texttt{normalize=true} \\1 & \texttt{otherwise}\end{cases}\f] + +Unnormalized box filter is useful for computing various integral characteristics over each pixel +neighborhood, such as covariance matrices of image derivatives (used in dense optical flow +algorithms, and so on). If you need to compute pixel sums over variable-size windows, use #integral. + +@param src input image. +@param dst output image of the same size and type as src. +@param ddepth the output image depth (-1 to use src.depth()). +@param ksize blurring kernel size. +@param anchor anchor point; default value Point(-1,-1) means that the anchor is at the kernel +center. +@param normalize flag, specifying whether the kernel is normalized by its area or not. +@param borderType border mode used to extrapolate pixels outside of the image, see #BorderTypes. #BORDER_WRAP is not supported. +@sa blur, bilateralFilter, GaussianBlur, medianBlur, integral + */ +CV_EXPORTS_W void boxFilter( InputArray src, OutputArray dst, int ddepth, + Size ksize, Point anchor = Point(-1,-1), + bool normalize = true, + int borderType = BORDER_DEFAULT ); + +/** @brief Calculates the normalized sum of squares of the pixel values overlapping the filter. + +For every pixel \f$ (x, y) \f$ in the source image, the function calculates the sum of squares of those neighboring +pixel values which overlap the filter placed over the pixel \f$ (x, y) \f$. + +The unnormalized square box filter can be useful in computing local image statistics such as the local +variance and standard deviation around the neighborhood of a pixel. + +@param src input image +@param dst output image of the same size and type as src +@param ddepth the output image depth (-1 to use src.depth()) +@param ksize kernel size +@param anchor kernel anchor point. The default value of Point(-1, -1) denotes that the anchor is at the kernel +center. +@param normalize flag, specifying whether the kernel is to be normalized by it's area or not. +@param borderType border mode used to extrapolate pixels outside of the image, see #BorderTypes. #BORDER_WRAP is not supported. +@sa boxFilter +*/ +CV_EXPORTS_W void sqrBoxFilter( InputArray src, OutputArray dst, int ddepth, + Size ksize, Point anchor = Point(-1, -1), + bool normalize = true, + int borderType = BORDER_DEFAULT ); + +/** @brief Blurs an image using the normalized box filter. + +The function smooths an image using the kernel: + +\f[\texttt{K} = \frac{1}{\texttt{ksize.width*ksize.height}} \begin{bmatrix} 1 & 1 & 1 & \cdots & 1 & 1 \\ 1 & 1 & 1 & \cdots & 1 & 1 \\ \hdotsfor{6} \\ 1 & 1 & 1 & \cdots & 1 & 1 \\ \end{bmatrix}\f] + +The call `blur(src, dst, ksize, anchor, borderType)` is equivalent to `boxFilter(src, dst, src.type(), ksize, +anchor, true, borderType)`. + +@param src input image; it can have any number of channels, which are processed independently, but +the depth should be CV_8U, CV_16U, CV_16S, CV_32F or CV_64F. +@param dst output image of the same size and type as src. +@param ksize blurring kernel size. +@param anchor anchor point; default value Point(-1,-1) means that the anchor is at the kernel +center. +@param borderType border mode used to extrapolate pixels outside of the image, see #BorderTypes. #BORDER_WRAP is not supported. +@sa boxFilter, bilateralFilter, GaussianBlur, medianBlur + */ +CV_EXPORTS_W void blur( InputArray src, OutputArray dst, + Size ksize, Point anchor = Point(-1,-1), + int borderType = BORDER_DEFAULT ); + +/** @brief Convolves an image with the kernel. + +The function applies an arbitrary linear filter to an image. In-place operation is supported. When +the aperture is partially outside the image, the function interpolates outlier pixel values +according to the specified border mode. + +The function does actually compute correlation, not the convolution: + +\f[\texttt{dst} (x,y) = \sum _{ \substack{0\leq x' < \texttt{kernel.cols}\\{0\leq y' < \texttt{kernel.rows}}}} \texttt{kernel} (x',y')* \texttt{src} (x+x'- \texttt{anchor.x} ,y+y'- \texttt{anchor.y} )\f] + +That is, the kernel is not mirrored around the anchor point. If you need a real convolution, flip +the kernel using #flip and set the new anchor to `(kernel.cols - anchor.x - 1, kernel.rows - +anchor.y - 1)`. + +The function uses the DFT-based algorithm in case of sufficiently large kernels (~`11 x 11` or +larger) and the direct algorithm for small kernels. + +@param src input image. +@param dst output image of the same size and the same number of channels as src. +@param ddepth desired depth of the destination image, see @ref filter_depths "combinations" +@param kernel convolution kernel (or rather a correlation kernel), a single-channel floating point +matrix; if you want to apply different kernels to different channels, split the image into +separate color planes using split and process them individually. +@param anchor anchor of the kernel that indicates the relative position of a filtered point within +the kernel; the anchor should lie within the kernel; default value (-1,-1) means that the anchor +is at the kernel center. +@param delta optional value added to the filtered pixels before storing them in dst. +@param borderType pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not supported. +@sa sepFilter2D, dft, matchTemplate + */ +CV_EXPORTS_W void filter2D( InputArray src, OutputArray dst, int ddepth, + InputArray kernel, Point anchor = Point(-1,-1), + double delta = 0, int borderType = BORDER_DEFAULT ); + +/** @brief Applies a separable linear filter to an image. + +The function applies a separable linear filter to the image. That is, first, every row of src is +filtered with the 1D kernel kernelX. Then, every column of the result is filtered with the 1D +kernel kernelY. The final result shifted by delta is stored in dst . + +@param src Source image. +@param dst Destination image of the same size and the same number of channels as src . +@param ddepth Destination image depth, see @ref filter_depths "combinations" +@param kernelX Coefficients for filtering each row. +@param kernelY Coefficients for filtering each column. +@param anchor Anchor position within the kernel. The default value \f$(-1,-1)\f$ means that the anchor +is at the kernel center. +@param delta Value added to the filtered results before storing them. +@param borderType Pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not supported. +@sa filter2D, Sobel, GaussianBlur, boxFilter, blur + */ +CV_EXPORTS_W void sepFilter2D( InputArray src, OutputArray dst, int ddepth, + InputArray kernelX, InputArray kernelY, + Point anchor = Point(-1,-1), + double delta = 0, int borderType = BORDER_DEFAULT ); + +/** @example samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp +Sample code using Sobel and/or Scharr OpenCV functions to make a simple Edge Detector +![Sample screenshot](Sobel_Derivatives_Tutorial_Result.jpg) +Check @ref tutorial_sobel_derivatives "the corresponding tutorial" for more details +*/ + +/** @brief Calculates the first, second, third, or mixed image derivatives using an extended Sobel operator. + +In all cases except one, the \f$\texttt{ksize} \times \texttt{ksize}\f$ separable kernel is used to +calculate the derivative. When \f$\texttt{ksize = 1}\f$, the \f$3 \times 1\f$ or \f$1 \times 3\f$ +kernel is used (that is, no Gaussian smoothing is done). `ksize = 1` can only be used for the first +or the second x- or y- derivatives. + +There is also the special value `ksize = #FILTER_SCHARR (-1)` that corresponds to the \f$3\times3\f$ Scharr +filter that may give more accurate results than the \f$3\times3\f$ Sobel. The Scharr aperture is + +\f[\vecthreethree{-3}{0}{3}{-10}{0}{10}{-3}{0}{3}\f] + +for the x-derivative, or transposed for the y-derivative. + +The function calculates an image derivative by convolving the image with the appropriate kernel: + +\f[\texttt{dst} = \frac{\partial^{xorder+yorder} \texttt{src}}{\partial x^{xorder} \partial y^{yorder}}\f] + +The Sobel operators combine Gaussian smoothing and differentiation, so the result is more or less +resistant to the noise. Most often, the function is called with ( xorder = 1, yorder = 0, ksize = 3) +or ( xorder = 0, yorder = 1, ksize = 3) to calculate the first x- or y- image derivative. The first +case corresponds to a kernel of: + +\f[\vecthreethree{-1}{0}{1}{-2}{0}{2}{-1}{0}{1}\f] + +The second case corresponds to a kernel of: + +\f[\vecthreethree{-1}{-2}{-1}{0}{0}{0}{1}{2}{1}\f] + +@param src input image. +@param dst output image of the same size and the same number of channels as src . +@param ddepth output image depth, see @ref filter_depths "combinations"; in the case of + 8-bit input images it will result in truncated derivatives. +@param dx order of the derivative x. +@param dy order of the derivative y. +@param ksize size of the extended Sobel kernel; it must be 1, 3, 5, or 7. +@param scale optional scale factor for the computed derivative values; by default, no scaling is +applied (see #getDerivKernels for details). +@param delta optional delta value that is added to the results prior to storing them in dst. +@param borderType pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not supported. +@sa Scharr, Laplacian, sepFilter2D, filter2D, GaussianBlur, cartToPolar + */ +CV_EXPORTS_W void Sobel( InputArray src, OutputArray dst, int ddepth, + int dx, int dy, int ksize = 3, + double scale = 1, double delta = 0, + int borderType = BORDER_DEFAULT ); + +/** @brief Calculates the first order image derivative in both x and y using a Sobel operator + +Equivalent to calling: + +@code +Sobel( src, dx, CV_16SC1, 1, 0, 3 ); +Sobel( src, dy, CV_16SC1, 0, 1, 3 ); +@endcode + +@param src input image. +@param dx output image with first-order derivative in x. +@param dy output image with first-order derivative in y. +@param ksize size of Sobel kernel. It must be 3. +@param borderType pixel extrapolation method, see #BorderTypes. + Only #BORDER_DEFAULT=#BORDER_REFLECT_101 and #BORDER_REPLICATE are supported. + +@sa Sobel + */ + +CV_EXPORTS_W void spatialGradient( InputArray src, OutputArray dx, + OutputArray dy, int ksize = 3, + int borderType = BORDER_DEFAULT ); + +/** @brief Calculates the first x- or y- image derivative using Scharr operator. + +The function computes the first x- or y- spatial image derivative using the Scharr operator. The +call + +\f[\texttt{Scharr(src, dst, ddepth, dx, dy, scale, delta, borderType)}\f] + +is equivalent to + +\f[\texttt{Sobel(src, dst, ddepth, dx, dy, FILTER_SCHARR, scale, delta, borderType)} .\f] + +@param src input image. +@param dst output image of the same size and the same number of channels as src. +@param ddepth output image depth, see @ref filter_depths "combinations" +@param dx order of the derivative x. +@param dy order of the derivative y. +@param scale optional scale factor for the computed derivative values; by default, no scaling is +applied (see #getDerivKernels for details). +@param delta optional delta value that is added to the results prior to storing them in dst. +@param borderType pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not supported. +@sa cartToPolar + */ +CV_EXPORTS_W void Scharr( InputArray src, OutputArray dst, int ddepth, + int dx, int dy, double scale = 1, double delta = 0, + int borderType = BORDER_DEFAULT ); + +/** @example samples/cpp/laplace.cpp +An example using Laplace transformations for edge detection +*/ + +/** @brief Calculates the Laplacian of an image. + +The function calculates the Laplacian of the source image by adding up the second x and y +derivatives calculated using the Sobel operator: + +\f[\texttt{dst} = \Delta \texttt{src} = \frac{\partial^2 \texttt{src}}{\partial x^2} + \frac{\partial^2 \texttt{src}}{\partial y^2}\f] + +This is done when `ksize > 1`. When `ksize == 1`, the Laplacian is computed by filtering the image +with the following \f$3 \times 3\f$ aperture: + +\f[\vecthreethree {0}{1}{0}{1}{-4}{1}{0}{1}{0}\f] + +@param src Source image. +@param dst Destination image of the same size and the same number of channels as src . +@param ddepth Desired depth of the destination image. +@param ksize Aperture size used to compute the second-derivative filters. See #getDerivKernels for +details. The size must be positive and odd. +@param scale Optional scale factor for the computed Laplacian values. By default, no scaling is +applied. See #getDerivKernels for details. +@param delta Optional delta value that is added to the results prior to storing them in dst . +@param borderType Pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not supported. +@sa Sobel, Scharr + */ +CV_EXPORTS_W void Laplacian( InputArray src, OutputArray dst, int ddepth, + int ksize = 1, double scale = 1, double delta = 0, + int borderType = BORDER_DEFAULT ); + +//! @} imgproc_filter + +//! @addtogroup imgproc_feature +//! @{ + +/** @example samples/cpp/edge.cpp +This program demonstrates usage of the Canny edge detector + +Check @ref tutorial_canny_detector "the corresponding tutorial" for more details +*/ + +/** @brief Finds edges in an image using the Canny algorithm @cite Canny86 . + +The function finds edges in the input image and marks them in the output map edges using the +Canny algorithm. The smallest value between threshold1 and threshold2 is used for edge linking. The +largest value is used to find initial segments of strong edges. See + + +@param image 8-bit input image. +@param edges output edge map; single channels 8-bit image, which has the same size as image . +@param threshold1 first threshold for the hysteresis procedure. +@param threshold2 second threshold for the hysteresis procedure. +@param apertureSize aperture size for the Sobel operator. +@param L2gradient a flag, indicating whether a more accurate \f$L_2\f$ norm +\f$=\sqrt{(dI/dx)^2 + (dI/dy)^2}\f$ should be used to calculate the image gradient magnitude ( +L2gradient=true ), or whether the default \f$L_1\f$ norm \f$=|dI/dx|+|dI/dy|\f$ is enough ( +L2gradient=false ). + */ +CV_EXPORTS_W void Canny( InputArray image, OutputArray edges, + double threshold1, double threshold2, + int apertureSize = 3, bool L2gradient = false ); + +/** \overload + +Finds edges in an image using the Canny algorithm with custom image gradient. + +@param dx 16-bit x derivative of input image (CV_16SC1 or CV_16SC3). +@param dy 16-bit y derivative of input image (same type as dx). +@param edges output edge map; single channels 8-bit image, which has the same size as image . +@param threshold1 first threshold for the hysteresis procedure. +@param threshold2 second threshold for the hysteresis procedure. +@param L2gradient a flag, indicating whether a more accurate \f$L_2\f$ norm +\f$=\sqrt{(dI/dx)^2 + (dI/dy)^2}\f$ should be used to calculate the image gradient magnitude ( +L2gradient=true ), or whether the default \f$L_1\f$ norm \f$=|dI/dx|+|dI/dy|\f$ is enough ( +L2gradient=false ). + */ +CV_EXPORTS_W void Canny( InputArray dx, InputArray dy, + OutputArray edges, + double threshold1, double threshold2, + bool L2gradient = false ); + +/** @brief Calculates the minimal eigenvalue of gradient matrices for corner detection. + +The function is similar to cornerEigenValsAndVecs but it calculates and stores only the minimal +eigenvalue of the covariance matrix of derivatives, that is, \f$\min(\lambda_1, \lambda_2)\f$ in terms +of the formulae in the cornerEigenValsAndVecs description. + +@param src Input single-channel 8-bit or floating-point image. +@param dst Image to store the minimal eigenvalues. It has the type CV_32FC1 and the same size as +src . +@param blockSize Neighborhood size (see the details on #cornerEigenValsAndVecs ). +@param ksize Aperture parameter for the Sobel operator. +@param borderType Pixel extrapolation method. See #BorderTypes. #BORDER_WRAP is not supported. + */ +CV_EXPORTS_W void cornerMinEigenVal( InputArray src, OutputArray dst, + int blockSize, int ksize = 3, + int borderType = BORDER_DEFAULT ); + +/** @brief Harris corner detector. + +The function runs the Harris corner detector on the image. Similarly to cornerMinEigenVal and +cornerEigenValsAndVecs , for each pixel \f$(x, y)\f$ it calculates a \f$2\times2\f$ gradient covariance +matrix \f$M^{(x,y)}\f$ over a \f$\texttt{blockSize} \times \texttt{blockSize}\f$ neighborhood. Then, it +computes the following characteristic: + +\f[\texttt{dst} (x,y) = \mathrm{det} M^{(x,y)} - k \cdot \left ( \mathrm{tr} M^{(x,y)} \right )^2\f] + +Corners in the image can be found as the local maxima of this response map. + +@param src Input single-channel 8-bit or floating-point image. +@param dst Image to store the Harris detector responses. It has the type CV_32FC1 and the same +size as src . +@param blockSize Neighborhood size (see the details on #cornerEigenValsAndVecs ). +@param ksize Aperture parameter for the Sobel operator. +@param k Harris detector free parameter. See the formula above. +@param borderType Pixel extrapolation method. See #BorderTypes. #BORDER_WRAP is not supported. + */ +CV_EXPORTS_W void cornerHarris( InputArray src, OutputArray dst, int blockSize, + int ksize, double k, + int borderType = BORDER_DEFAULT ); + +/** @brief Calculates eigenvalues and eigenvectors of image blocks for corner detection. + +For every pixel \f$p\f$ , the function cornerEigenValsAndVecs considers a blockSize \f$\times\f$ blockSize +neighborhood \f$S(p)\f$ . It calculates the covariation matrix of derivatives over the neighborhood as: + +\f[M = \begin{bmatrix} \sum _{S(p)}(dI/dx)^2 & \sum _{S(p)}dI/dx dI/dy \\ \sum _{S(p)}dI/dx dI/dy & \sum _{S(p)}(dI/dy)^2 \end{bmatrix}\f] + +where the derivatives are computed using the Sobel operator. + +After that, it finds eigenvectors and eigenvalues of \f$M\f$ and stores them in the destination image as +\f$(\lambda_1, \lambda_2, x_1, y_1, x_2, y_2)\f$ where + +- \f$\lambda_1, \lambda_2\f$ are the non-sorted eigenvalues of \f$M\f$ +- \f$x_1, y_1\f$ are the eigenvectors corresponding to \f$\lambda_1\f$ +- \f$x_2, y_2\f$ are the eigenvectors corresponding to \f$\lambda_2\f$ + +The output of the function can be used for robust edge or corner detection. + +@param src Input single-channel 8-bit or floating-point image. +@param dst Image to store the results. It has the same size as src and the type CV_32FC(6) . +@param blockSize Neighborhood size (see details below). +@param ksize Aperture parameter for the Sobel operator. +@param borderType Pixel extrapolation method. See #BorderTypes. #BORDER_WRAP is not supported. + +@sa cornerMinEigenVal, cornerHarris, preCornerDetect + */ +CV_EXPORTS_W void cornerEigenValsAndVecs( InputArray src, OutputArray dst, + int blockSize, int ksize, + int borderType = BORDER_DEFAULT ); + +/** @brief Calculates a feature map for corner detection. + +The function calculates the complex spatial derivative-based function of the source image + +\f[\texttt{dst} = (D_x \texttt{src} )^2 \cdot D_{yy} \texttt{src} + (D_y \texttt{src} )^2 \cdot D_{xx} \texttt{src} - 2 D_x \texttt{src} \cdot D_y \texttt{src} \cdot D_{xy} \texttt{src}\f] + +where \f$D_x\f$,\f$D_y\f$ are the first image derivatives, \f$D_{xx}\f$,\f$D_{yy}\f$ are the second image +derivatives, and \f$D_{xy}\f$ is the mixed derivative. + +The corners can be found as local maximums of the functions, as shown below: +@code + Mat corners, dilated_corners; + preCornerDetect(image, corners, 3); + // dilation with 3x3 rectangular structuring element + dilate(corners, dilated_corners, Mat(), 1); + Mat corner_mask = corners == dilated_corners; +@endcode + +@param src Source single-channel 8-bit of floating-point image. +@param dst Output image that has the type CV_32F and the same size as src . +@param ksize %Aperture size of the Sobel . +@param borderType Pixel extrapolation method. See #BorderTypes. #BORDER_WRAP is not supported. + */ +CV_EXPORTS_W void preCornerDetect( InputArray src, OutputArray dst, int ksize, + int borderType = BORDER_DEFAULT ); + +/** @brief Refines the corner locations. + +The function iterates to find the sub-pixel accurate location of corners or radial saddle +points as described in @cite forstner1987fast, and as shown on the figure below. + +![image](pics/cornersubpix.png) + +Sub-pixel accurate corner locator is based on the observation that every vector from the center \f$q\f$ +to a point \f$p\f$ located within a neighborhood of \f$q\f$ is orthogonal to the image gradient at \f$p\f$ +subject to image and measurement noise. Consider the expression: + +\f[\epsilon _i = {DI_{p_i}}^T \cdot (q - p_i)\f] + +where \f${DI_{p_i}}\f$ is an image gradient at one of the points \f$p_i\f$ in a neighborhood of \f$q\f$ . The +value of \f$q\f$ is to be found so that \f$\epsilon_i\f$ is minimized. A system of equations may be set up +with \f$\epsilon_i\f$ set to zero: + +\f[\sum _i(DI_{p_i} \cdot {DI_{p_i}}^T) \cdot q - \sum _i(DI_{p_i} \cdot {DI_{p_i}}^T \cdot p_i)\f] + +where the gradients are summed within a neighborhood ("search window") of \f$q\f$ . Calling the first +gradient term \f$G\f$ and the second gradient term \f$b\f$ gives: + +\f[q = G^{-1} \cdot b\f] + +The algorithm sets the center of the neighborhood window at this new center \f$q\f$ and then iterates +until the center stays within a set threshold. + +@param image Input single-channel, 8-bit or float image. +@param corners Initial coordinates of the input corners and refined coordinates provided for +output. +@param winSize Half of the side length of the search window. For example, if winSize=Size(5,5) , +then a \f$(5*2+1) \times (5*2+1) = 11 \times 11\f$ search window is used. +@param zeroZone Half of the size of the dead region in the middle of the search zone over which +the summation in the formula below is not done. It is used sometimes to avoid possible +singularities of the autocorrelation matrix. The value of (-1,-1) indicates that there is no such +a size. +@param criteria Criteria for termination of the iterative process of corner refinement. That is, +the process of corner position refinement stops either after criteria.maxCount iterations or when +the corner position moves by less than criteria.epsilon on some iteration. + */ +CV_EXPORTS_W void cornerSubPix( InputArray image, InputOutputArray corners, + Size winSize, Size zeroZone, + TermCriteria criteria ); + +/** @brief Determines strong corners on an image. + +The function finds the most prominent corners in the image or in the specified image region, as +described in @cite Shi94 + +- Function calculates the corner quality measure at every source image pixel using the + #cornerMinEigenVal or #cornerHarris . +- Function performs a non-maximum suppression (the local maximums in *3 x 3* neighborhood are + retained). +- The corners with the minimal eigenvalue less than + \f$\texttt{qualityLevel} \cdot \max_{x,y} qualityMeasureMap(x,y)\f$ are rejected. +- The remaining corners are sorted by the quality measure in the descending order. +- Function throws away each corner for which there is a stronger corner at a distance less than + maxDistance. + +The function can be used to initialize a point-based tracker of an object. + +@note If the function is called with different values A and B of the parameter qualityLevel , and +A \> B, the vector of returned corners with qualityLevel=A will be the prefix of the output vector +with qualityLevel=B . + +@param image Input 8-bit or floating-point 32-bit, single-channel image. +@param corners Output vector of detected corners. +@param maxCorners Maximum number of corners to return. If there are more corners than are found, +the strongest of them is returned. `maxCorners <= 0` implies that no limit on the maximum is set +and all detected corners are returned. +@param qualityLevel Parameter characterizing the minimal accepted quality of image corners. The +parameter value is multiplied by the best corner quality measure, which is the minimal eigenvalue +(see #cornerMinEigenVal ) or the Harris function response (see #cornerHarris ). The corners with the +quality measure less than the product are rejected. For example, if the best corner has the +quality measure = 1500, and the qualityLevel=0.01 , then all the corners with the quality measure +less than 15 are rejected. +@param minDistance Minimum possible Euclidean distance between the returned corners. +@param mask Optional region of interest. If the image is not empty (it needs to have the type +CV_8UC1 and the same size as image ), it specifies the region in which the corners are detected. +@param blockSize Size of an average block for computing a derivative covariation matrix over each +pixel neighborhood. See cornerEigenValsAndVecs . +@param useHarrisDetector Parameter indicating whether to use a Harris detector (see #cornerHarris) +or #cornerMinEigenVal. +@param k Free parameter of the Harris detector. + +@sa cornerMinEigenVal, cornerHarris, calcOpticalFlowPyrLK, estimateRigidTransform, + */ + +CV_EXPORTS_W void goodFeaturesToTrack( InputArray image, OutputArray corners, + int maxCorners, double qualityLevel, double minDistance, + InputArray mask = noArray(), int blockSize = 3, + bool useHarrisDetector = false, double k = 0.04 ); + +CV_EXPORTS_W void goodFeaturesToTrack( InputArray image, OutputArray corners, + int maxCorners, double qualityLevel, double minDistance, + InputArray mask, int blockSize, + int gradientSize, bool useHarrisDetector = false, + double k = 0.04 ); + +/** @brief Same as above, but returns also quality measure of the detected corners. + +@param image Input 8-bit or floating-point 32-bit, single-channel image. +@param corners Output vector of detected corners. +@param maxCorners Maximum number of corners to return. If there are more corners than are found, +the strongest of them is returned. `maxCorners <= 0` implies that no limit on the maximum is set +and all detected corners are returned. +@param qualityLevel Parameter characterizing the minimal accepted quality of image corners. The +parameter value is multiplied by the best corner quality measure, which is the minimal eigenvalue +(see #cornerMinEigenVal ) or the Harris function response (see #cornerHarris ). The corners with the +quality measure less than the product are rejected. For example, if the best corner has the +quality measure = 1500, and the qualityLevel=0.01 , then all the corners with the quality measure +less than 15 are rejected. +@param minDistance Minimum possible Euclidean distance between the returned corners. +@param mask Region of interest. If the image is not empty (it needs to have the type +CV_8UC1 and the same size as image ), it specifies the region in which the corners are detected. +@param cornersQuality Output vector of quality measure of the detected corners. +@param blockSize Size of an average block for computing a derivative covariation matrix over each +pixel neighborhood. See cornerEigenValsAndVecs . +@param gradientSize Aperture parameter for the Sobel operator used for derivatives computation. +See cornerEigenValsAndVecs . +@param useHarrisDetector Parameter indicating whether to use a Harris detector (see #cornerHarris) +or #cornerMinEigenVal. +@param k Free parameter of the Harris detector. + */ +CV_EXPORTS CV_WRAP_AS(goodFeaturesToTrackWithQuality) void goodFeaturesToTrack( + InputArray image, OutputArray corners, + int maxCorners, double qualityLevel, double minDistance, + InputArray mask, OutputArray cornersQuality, int blockSize = 3, + int gradientSize = 3, bool useHarrisDetector = false, double k = 0.04); + +/** @example samples/cpp/tutorial_code/ImgTrans/houghlines.cpp +An example using the Hough line detector +![Sample input image](Hough_Lines_Tutorial_Original_Image.jpg) ![Output image](Hough_Lines_Tutorial_Result.jpg) +*/ + +/** @brief Finds lines in a binary image using the standard Hough transform. + +The function implements the standard or standard multi-scale Hough transform algorithm for line +detection. See for a good explanation of Hough +transform. + +@param image 8-bit, single-channel binary source image. The image may be modified by the function. +@param lines Output vector of lines. Each line is represented by a 2 or 3 element vector +\f$(\rho, \theta)\f$ or \f$(\rho, \theta, \textrm{votes})\f$ . \f$\rho\f$ is the distance from the coordinate origin \f$(0,0)\f$ (top-left corner of +the image). \f$\theta\f$ is the line rotation angle in radians ( +\f$0 \sim \textrm{vertical line}, \pi/2 \sim \textrm{horizontal line}\f$ ). +\f$\textrm{votes}\f$ is the value of accumulator. +@param rho Distance resolution of the accumulator in pixels. +@param theta Angle resolution of the accumulator in radians. +@param threshold Accumulator threshold parameter. Only those lines are returned that get enough +votes ( \f$>\texttt{threshold}\f$ ). +@param srn For the multi-scale Hough transform, it is a divisor for the distance resolution rho . +The coarse accumulator distance resolution is rho and the accurate accumulator resolution is +rho/srn . If both srn=0 and stn=0 , the classical Hough transform is used. Otherwise, both these +parameters should be positive. +@param stn For the multi-scale Hough transform, it is a divisor for the distance resolution theta. +@param min_theta For standard and multi-scale Hough transform, minimum angle to check for lines. +Must fall between 0 and max_theta. +@param max_theta For standard and multi-scale Hough transform, maximum angle to check for lines. +Must fall between min_theta and CV_PI. + */ +CV_EXPORTS_W void HoughLines( InputArray image, OutputArray lines, + double rho, double theta, int threshold, + double srn = 0, double stn = 0, + double min_theta = 0, double max_theta = CV_PI ); + +/** @brief Finds line segments in a binary image using the probabilistic Hough transform. + +The function implements the probabilistic Hough transform algorithm for line detection, described +in @cite Matas00 + +See the line detection example below: +@include snippets/imgproc_HoughLinesP.cpp +This is a sample picture the function parameters have been tuned for: + +![image](pics/building.jpg) + +And this is the output of the above program in case of the probabilistic Hough transform: + +![image](pics/houghp.png) + +@param image 8-bit, single-channel binary source image. The image may be modified by the function. +@param lines Output vector of lines. Each line is represented by a 4-element vector +\f$(x_1, y_1, x_2, y_2)\f$ , where \f$(x_1,y_1)\f$ and \f$(x_2, y_2)\f$ are the ending points of each detected +line segment. +@param rho Distance resolution of the accumulator in pixels. +@param theta Angle resolution of the accumulator in radians. +@param threshold Accumulator threshold parameter. Only those lines are returned that get enough +votes ( \f$>\texttt{threshold}\f$ ). +@param minLineLength Minimum line length. Line segments shorter than that are rejected. +@param maxLineGap Maximum allowed gap between points on the same line to link them. + +@sa LineSegmentDetector + */ +CV_EXPORTS_W void HoughLinesP( InputArray image, OutputArray lines, + double rho, double theta, int threshold, + double minLineLength = 0, double maxLineGap = 0 ); + +/** @brief Finds lines in a set of points using the standard Hough transform. + +The function finds lines in a set of points using a modification of the Hough transform. +@include snippets/imgproc_HoughLinesPointSet.cpp +@param point Input vector of points. Each vector must be encoded as a Point vector \f$(x,y)\f$. Type must be CV_32FC2 or CV_32SC2. +@param lines Output vector of found lines. Each vector is encoded as a vector \f$(votes, rho, theta)\f$. +The larger the value of 'votes', the higher the reliability of the Hough line. +@param lines_max Max count of Hough lines. +@param threshold Accumulator threshold parameter. Only those lines are returned that get enough +votes ( \f$>\texttt{threshold}\f$ ). +@param min_rho Minimum value for \f$\rho\f$ for the accumulator (Note: \f$\rho\f$ can be negative. The absolute value \f$|\rho|\f$ is the distance of a line to the origin.). +@param max_rho Maximum value for \f$\rho\f$ for the accumulator. +@param rho_step Distance resolution of the accumulator. +@param min_theta Minimum angle value of the accumulator in radians. +@param max_theta Maximum angle value of the accumulator in radians. +@param theta_step Angle resolution of the accumulator in radians. + */ +CV_EXPORTS_W void HoughLinesPointSet( InputArray point, OutputArray lines, int lines_max, int threshold, + double min_rho, double max_rho, double rho_step, + double min_theta, double max_theta, double theta_step ); + +/** @example samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp +An example using the Hough circle detector +*/ + +/** @brief Finds circles in a grayscale image using the Hough transform. + +The function finds circles in a grayscale image using a modification of the Hough transform. + +Example: : +@include snippets/imgproc_HoughLinesCircles.cpp + +@note Usually the function detects the centers of circles well. However, it may fail to find correct +radii. You can assist to the function by specifying the radius range ( minRadius and maxRadius ) if +you know it. Or, in the case of #HOUGH_GRADIENT method you may set maxRadius to a negative number +to return centers only without radius search, and find the correct radius using an additional procedure. + +It also helps to smooth image a bit unless it's already soft. For example, +GaussianBlur() with 7x7 kernel and 1.5x1.5 sigma or similar blurring may help. + +@param image 8-bit, single-channel, grayscale input image. +@param circles Output vector of found circles. Each vector is encoded as 3 or 4 element +floating-point vector \f$(x, y, radius)\f$ or \f$(x, y, radius, votes)\f$ . +@param method Detection method, see #HoughModes. The available methods are #HOUGH_GRADIENT and #HOUGH_GRADIENT_ALT. +@param dp Inverse ratio of the accumulator resolution to the image resolution. For example, if +dp=1 , the accumulator has the same resolution as the input image. If dp=2 , the accumulator has +half as big width and height. For #HOUGH_GRADIENT_ALT the recommended value is dp=1.5, +unless some small very circles need to be detected. +@param minDist Minimum distance between the centers of the detected circles. If the parameter is +too small, multiple neighbor circles may be falsely detected in addition to a true one. If it is +too large, some circles may be missed. +@param param1 First method-specific parameter. In case of #HOUGH_GRADIENT and #HOUGH_GRADIENT_ALT, +it is the higher threshold of the two passed to the Canny edge detector (the lower one is twice smaller). +Note that #HOUGH_GRADIENT_ALT uses #Scharr algorithm to compute image derivatives, so the threshold value +shough normally be higher, such as 300 or normally exposed and contrasty images. +@param param2 Second method-specific parameter. In case of #HOUGH_GRADIENT, it is the +accumulator threshold for the circle centers at the detection stage. The smaller it is, the more +false circles may be detected. Circles, corresponding to the larger accumulator values, will be +returned first. In the case of #HOUGH_GRADIENT_ALT algorithm, this is the circle "perfectness" measure. +The closer it to 1, the better shaped circles algorithm selects. In most cases 0.9 should be fine. +If you want get better detection of small circles, you may decrease it to 0.85, 0.8 or even less. +But then also try to limit the search range [minRadius, maxRadius] to avoid many false circles. +@param minRadius Minimum circle radius. +@param maxRadius Maximum circle radius. If <= 0, uses the maximum image dimension. If < 0, #HOUGH_GRADIENT returns +centers without finding the radius. #HOUGH_GRADIENT_ALT always computes circle radiuses. + +@sa fitEllipse, minEnclosingCircle + */ +CV_EXPORTS_W void HoughCircles( InputArray image, OutputArray circles, + int method, double dp, double minDist, + double param1 = 100, double param2 = 100, + int minRadius = 0, int maxRadius = 0 ); + +//! @} imgproc_feature + +//! @addtogroup imgproc_filter +//! @{ + +/** @example samples/cpp/tutorial_code/ImgProc/Morphology_2.cpp +Advanced morphology Transformations sample code +![Sample screenshot](Morphology_2_Tutorial_Result.jpg) +Check @ref tutorial_opening_closing_hats "the corresponding tutorial" for more details +*/ + +/** @brief Erodes an image by using a specific structuring element. + +The function erodes the source image using the specified structuring element that determines the +shape of a pixel neighborhood over which the minimum is taken: + +\f[\texttt{dst} (x,y) = \min _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f] + +The function supports the in-place mode. Erosion can be applied several ( iterations ) times. In +case of multi-channel images, each channel is processed independently. + +@param src input image; the number of channels can be arbitrary, but the depth should be one of +CV_8U, CV_16U, CV_16S, CV_32F or CV_64F. +@param dst output image of the same size and type as src. +@param kernel structuring element used for erosion; if `element=Mat()`, a `3 x 3` rectangular +structuring element is used. Kernel can be created using #getStructuringElement. +@param anchor position of the anchor within the element; default value (-1, -1) means that the +anchor is at the element center. +@param iterations number of times erosion is applied. +@param borderType pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not supported. +@param borderValue border value in case of a constant border +@sa dilate, morphologyEx, getStructuringElement + */ +CV_EXPORTS_W void erode( InputArray src, OutputArray dst, InputArray kernel, + Point anchor = Point(-1,-1), int iterations = 1, + int borderType = BORDER_CONSTANT, + const Scalar& borderValue = morphologyDefaultBorderValue() ); + +/** @example samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp +Erosion and Dilation sample code +![Sample Screenshot-Erosion](Morphology_1_Tutorial_Erosion_Result.jpg)![Sample Screenshot-Dilation](Morphology_1_Tutorial_Dilation_Result.jpg) +Check @ref tutorial_erosion_dilatation "the corresponding tutorial" for more details +*/ + +/** @brief Dilates an image by using a specific structuring element. + +The function dilates the source image using the specified structuring element that determines the +shape of a pixel neighborhood over which the maximum is taken: +\f[\texttt{dst} (x,y) = \max _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f] + +The function supports the in-place mode. Dilation can be applied several ( iterations ) times. In +case of multi-channel images, each channel is processed independently. + +@param src input image; the number of channels can be arbitrary, but the depth should be one of +CV_8U, CV_16U, CV_16S, CV_32F or CV_64F. +@param dst output image of the same size and type as src. +@param kernel structuring element used for dilation; if elemenat=Mat(), a 3 x 3 rectangular +structuring element is used. Kernel can be created using #getStructuringElement +@param anchor position of the anchor within the element; default value (-1, -1) means that the +anchor is at the element center. +@param iterations number of times dilation is applied. +@param borderType pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not suported. +@param borderValue border value in case of a constant border +@sa erode, morphologyEx, getStructuringElement + */ +CV_EXPORTS_W void dilate( InputArray src, OutputArray dst, InputArray kernel, + Point anchor = Point(-1,-1), int iterations = 1, + int borderType = BORDER_CONSTANT, + const Scalar& borderValue = morphologyDefaultBorderValue() ); + +/** @brief Performs advanced morphological transformations. + +The function cv::morphologyEx can perform advanced morphological transformations using an erosion and dilation as +basic operations. + +Any of the operations can be done in-place. In case of multi-channel images, each channel is +processed independently. + +@param src Source image. The number of channels can be arbitrary. The depth should be one of +CV_8U, CV_16U, CV_16S, CV_32F or CV_64F. +@param dst Destination image of the same size and type as source image. +@param op Type of a morphological operation, see #MorphTypes +@param kernel Structuring element. It can be created using #getStructuringElement. +@param anchor Anchor position with the kernel. Negative values mean that the anchor is at the +kernel center. +@param iterations Number of times erosion and dilation are applied. +@param borderType Pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not supported. +@param borderValue Border value in case of a constant border. The default value has a special +meaning. +@sa dilate, erode, getStructuringElement +@note The number of iterations is the number of times erosion or dilatation operation will be applied. +For instance, an opening operation (#MORPH_OPEN) with two iterations is equivalent to apply +successively: erode -> erode -> dilate -> dilate (and not erode -> dilate -> erode -> dilate). + */ +CV_EXPORTS_W void morphologyEx( InputArray src, OutputArray dst, + int op, InputArray kernel, + Point anchor = Point(-1,-1), int iterations = 1, + int borderType = BORDER_CONSTANT, + const Scalar& borderValue = morphologyDefaultBorderValue() ); + +//! @} imgproc_filter + +//! @addtogroup imgproc_transform +//! @{ + +/** @brief Resizes an image. + +The function resize resizes the image src down to or up to the specified size. Note that the +initial dst type or size are not taken into account. Instead, the size and type are derived from +the `src`,`dsize`,`fx`, and `fy`. If you want to resize src so that it fits the pre-created dst, +you may call the function as follows: +@code + // explicitly specify dsize=dst.size(); fx and fy will be computed from that. + resize(src, dst, dst.size(), 0, 0, interpolation); +@endcode +If you want to decimate the image by factor of 2 in each direction, you can call the function this +way: +@code + // specify fx and fy and let the function compute the destination image size. + resize(src, dst, Size(), 0.5, 0.5, interpolation); +@endcode +To shrink an image, it will generally look best with #INTER_AREA interpolation, whereas to +enlarge an image, it will generally look best with #INTER_CUBIC (slow) or #INTER_LINEAR +(faster but still looks OK). + +@param src input image. +@param dst output image; it has the size dsize (when it is non-zero) or the size computed from +src.size(), fx, and fy; the type of dst is the same as of src. +@param dsize output image size; if it equals zero (`None` in Python), it is computed as: + \f[\texttt{dsize = Size(round(fx*src.cols), round(fy*src.rows))}\f] + Either dsize or both fx and fy must be non-zero. +@param fx scale factor along the horizontal axis; when it equals 0, it is computed as +\f[\texttt{(double)dsize.width/src.cols}\f] +@param fy scale factor along the vertical axis; when it equals 0, it is computed as +\f[\texttt{(double)dsize.height/src.rows}\f] +@param interpolation interpolation method, see #InterpolationFlags + +@sa warpAffine, warpPerspective, remap + */ +CV_EXPORTS_W void resize( InputArray src, OutputArray dst, + Size dsize, double fx = 0, double fy = 0, + int interpolation = INTER_LINEAR ); + +/** @brief Applies an affine transformation to an image. + +The function warpAffine transforms the source image using the specified matrix: + +\f[\texttt{dst} (x,y) = \texttt{src} ( \texttt{M} _{11} x + \texttt{M} _{12} y + \texttt{M} _{13}, \texttt{M} _{21} x + \texttt{M} _{22} y + \texttt{M} _{23})\f] + +when the flag #WARP_INVERSE_MAP is set. Otherwise, the transformation is first inverted +with #invertAffineTransform and then put in the formula above instead of M. The function cannot +operate in-place. + +@param src input image. +@param dst output image that has the size dsize and the same type as src . +@param M \f$2\times 3\f$ transformation matrix. +@param dsize size of the output image. +@param flags combination of interpolation methods (see #InterpolationFlags) and the optional +flag #WARP_INVERSE_MAP that means that M is the inverse transformation ( +\f$\texttt{dst}\rightarrow\texttt{src}\f$ ). +@param borderMode pixel extrapolation method (see #BorderTypes); when +borderMode=#BORDER_TRANSPARENT, it means that the pixels in the destination image corresponding to +the "outliers" in the source image are not modified by the function. +@param borderValue value used in case of a constant border; by default, it is 0. + +@sa warpPerspective, resize, remap, getRectSubPix, transform + */ +CV_EXPORTS_W void warpAffine( InputArray src, OutputArray dst, + InputArray M, Size dsize, + int flags = INTER_LINEAR, + int borderMode = BORDER_CONSTANT, + const Scalar& borderValue = Scalar()); + +/** @example samples/cpp/warpPerspective_demo.cpp +An example program shows using cv::getPerspectiveTransform and cv::warpPerspective for image warping +*/ + +/** @brief Applies a perspective transformation to an image. + +The function warpPerspective transforms the source image using the specified matrix: + +\f[\texttt{dst} (x,y) = \texttt{src} \left ( \frac{M_{11} x + M_{12} y + M_{13}}{M_{31} x + M_{32} y + M_{33}} , + \frac{M_{21} x + M_{22} y + M_{23}}{M_{31} x + M_{32} y + M_{33}} \right )\f] + +when the flag #WARP_INVERSE_MAP is set. Otherwise, the transformation is first inverted with invert +and then put in the formula above instead of M. The function cannot operate in-place. + +@param src input image. +@param dst output image that has the size dsize and the same type as src . +@param M \f$3\times 3\f$ transformation matrix. +@param dsize size of the output image. +@param flags combination of interpolation methods (#INTER_LINEAR or #INTER_NEAREST) and the +optional flag #WARP_INVERSE_MAP, that sets M as the inverse transformation ( +\f$\texttt{dst}\rightarrow\texttt{src}\f$ ). +@param borderMode pixel extrapolation method (#BORDER_CONSTANT or #BORDER_REPLICATE). +@param borderValue value used in case of a constant border; by default, it equals 0. + +@sa warpAffine, resize, remap, getRectSubPix, perspectiveTransform + */ +CV_EXPORTS_W void warpPerspective( InputArray src, OutputArray dst, + InputArray M, Size dsize, + int flags = INTER_LINEAR, + int borderMode = BORDER_CONSTANT, + const Scalar& borderValue = Scalar()); + +/** @brief Applies a generic geometrical transformation to an image. + +The function remap transforms the source image using the specified map: + +\f[\texttt{dst} (x,y) = \texttt{src} (map_x(x,y),map_y(x,y))\f] + +where values of pixels with non-integer coordinates are computed using one of available +interpolation methods. \f$map_x\f$ and \f$map_y\f$ can be encoded as separate floating-point maps +in \f$map_1\f$ and \f$map_2\f$ respectively, or interleaved floating-point maps of \f$(x,y)\f$ in +\f$map_1\f$, or fixed-point maps created by using #convertMaps. The reason you might want to +convert from floating to fixed-point representations of a map is that they can yield much faster +(\~2x) remapping operations. In the converted case, \f$map_1\f$ contains pairs (cvFloor(x), +cvFloor(y)) and \f$map_2\f$ contains indices in a table of interpolation coefficients. + +This function cannot operate in-place. + +@param src Source image. +@param dst Destination image. It has the same size as map1 and the same type as src . +@param map1 The first map of either (x,y) points or just x values having the type CV_16SC2 , +CV_32FC1, or CV_32FC2. See #convertMaps for details on converting a floating point +representation to fixed-point for speed. +@param map2 The second map of y values having the type CV_16UC1, CV_32FC1, or none (empty map +if map1 is (x,y) points), respectively. +@param interpolation Interpolation method (see #InterpolationFlags). The methods #INTER_AREA +and #INTER_LINEAR_EXACT are not supported by this function. +@param borderMode Pixel extrapolation method (see #BorderTypes). When +borderMode=#BORDER_TRANSPARENT, it means that the pixels in the destination image that +corresponds to the "outliers" in the source image are not modified by the function. +@param borderValue Value used in case of a constant border. By default, it is 0. +@note +Due to current implementation limitations the size of an input and output images should be less than 32767x32767. + */ +CV_EXPORTS_W void remap( InputArray src, OutputArray dst, + InputArray map1, InputArray map2, + int interpolation, int borderMode = BORDER_CONSTANT, + const Scalar& borderValue = Scalar()); + +/** @brief Converts image transformation maps from one representation to another. + +The function converts a pair of maps for remap from one representation to another. The following +options ( (map1.type(), map2.type()) \f$\rightarrow\f$ (dstmap1.type(), dstmap2.type()) ) are +supported: + +- \f$\texttt{(CV_32FC1, CV_32FC1)} \rightarrow \texttt{(CV_16SC2, CV_16UC1)}\f$. This is the +most frequently used conversion operation, in which the original floating-point maps (see #remap) +are converted to a more compact and much faster fixed-point representation. The first output array +contains the rounded coordinates and the second array (created only when nninterpolation=false ) +contains indices in the interpolation tables. + +- \f$\texttt{(CV_32FC2)} \rightarrow \texttt{(CV_16SC2, CV_16UC1)}\f$. The same as above but +the original maps are stored in one 2-channel matrix. + +- Reverse conversion. Obviously, the reconstructed floating-point maps will not be exactly the same +as the originals. + +@param map1 The first input map of type CV_16SC2, CV_32FC1, or CV_32FC2 . +@param map2 The second input map of type CV_16UC1, CV_32FC1, or none (empty matrix), +respectively. +@param dstmap1 The first output map that has the type dstmap1type and the same size as src . +@param dstmap2 The second output map. +@param dstmap1type Type of the first output map that should be CV_16SC2, CV_32FC1, or +CV_32FC2 . +@param nninterpolation Flag indicating whether the fixed-point maps are used for the +nearest-neighbor or for a more complex interpolation. + +@sa remap, undistort, initUndistortRectifyMap + */ +CV_EXPORTS_W void convertMaps( InputArray map1, InputArray map2, + OutputArray dstmap1, OutputArray dstmap2, + int dstmap1type, bool nninterpolation = false ); + +/** @brief Calculates an affine matrix of 2D rotation. + +The function calculates the following matrix: + +\f[\begin{bmatrix} \alpha & \beta & (1- \alpha ) \cdot \texttt{center.x} - \beta \cdot \texttt{center.y} \\ - \beta & \alpha & \beta \cdot \texttt{center.x} + (1- \alpha ) \cdot \texttt{center.y} \end{bmatrix}\f] + +where + +\f[\begin{array}{l} \alpha = \texttt{scale} \cdot \cos \texttt{angle} , \\ \beta = \texttt{scale} \cdot \sin \texttt{angle} \end{array}\f] + +The transformation maps the rotation center to itself. If this is not the target, adjust the shift. + +@param center Center of the rotation in the source image. +@param angle Rotation angle in degrees. Positive values mean counter-clockwise rotation (the +coordinate origin is assumed to be the top-left corner). +@param scale Isotropic scale factor. + +@sa getAffineTransform, warpAffine, transform + */ +CV_EXPORTS_W Mat getRotationMatrix2D(Point2f center, double angle, double scale); + +/** @sa getRotationMatrix2D */ +CV_EXPORTS Matx23d getRotationMatrix2D_(Point2f center, double angle, double scale); + +inline +Mat getRotationMatrix2D(Point2f center, double angle, double scale) +{ + return Mat(getRotationMatrix2D_(center, angle, scale), true); +} + +/** @brief Calculates an affine transform from three pairs of the corresponding points. + +The function calculates the \f$2 \times 3\f$ matrix of an affine transform so that: + +\f[\begin{bmatrix} x'_i \\ y'_i \end{bmatrix} = \texttt{map_matrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix}\f] + +where + +\f[dst(i)=(x'_i,y'_i), src(i)=(x_i, y_i), i=0,1,2\f] + +@param src Coordinates of triangle vertices in the source image. +@param dst Coordinates of the corresponding triangle vertices in the destination image. + +@sa warpAffine, transform + */ +CV_EXPORTS Mat getAffineTransform( const Point2f src[], const Point2f dst[] ); + +/** @brief Inverts an affine transformation. + +The function computes an inverse affine transformation represented by \f$2 \times 3\f$ matrix M: + +\f[\begin{bmatrix} a_{11} & a_{12} & b_1 \\ a_{21} & a_{22} & b_2 \end{bmatrix}\f] + +The result is also a \f$2 \times 3\f$ matrix of the same type as M. + +@param M Original affine transformation. +@param iM Output reverse affine transformation. + */ +CV_EXPORTS_W void invertAffineTransform( InputArray M, OutputArray iM ); + +/** @brief Calculates a perspective transform from four pairs of the corresponding points. + +The function calculates the \f$3 \times 3\f$ matrix of a perspective transform so that: + +\f[\begin{bmatrix} t_i x'_i \\ t_i y'_i \\ t_i \end{bmatrix} = \texttt{map_matrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix}\f] + +where + +\f[dst(i)=(x'_i,y'_i), src(i)=(x_i, y_i), i=0,1,2,3\f] + +@param src Coordinates of quadrangle vertices in the source image. +@param dst Coordinates of the corresponding quadrangle vertices in the destination image. +@param solveMethod method passed to cv::solve (#DecompTypes) + +@sa findHomography, warpPerspective, perspectiveTransform + */ +CV_EXPORTS_W Mat getPerspectiveTransform(InputArray src, InputArray dst, int solveMethod = DECOMP_LU); + +/** @overload */ +CV_EXPORTS Mat getPerspectiveTransform(const Point2f src[], const Point2f dst[], int solveMethod = DECOMP_LU); + + +CV_EXPORTS_W Mat getAffineTransform( InputArray src, InputArray dst ); + +/** @brief Retrieves a pixel rectangle from an image with sub-pixel accuracy. + +The function getRectSubPix extracts pixels from src: + +\f[patch(x, y) = src(x + \texttt{center.x} - ( \texttt{dst.cols} -1)*0.5, y + \texttt{center.y} - ( \texttt{dst.rows} -1)*0.5)\f] + +where the values of the pixels at non-integer coordinates are retrieved using bilinear +interpolation. Every channel of multi-channel images is processed independently. Also +the image should be a single channel or three channel image. While the center of the +rectangle must be inside the image, parts of the rectangle may be outside. + +@param image Source image. +@param patchSize Size of the extracted patch. +@param center Floating point coordinates of the center of the extracted rectangle within the +source image. The center must be inside the image. +@param patch Extracted patch that has the size patchSize and the same number of channels as src . +@param patchType Depth of the extracted pixels. By default, they have the same depth as src . + +@sa warpAffine, warpPerspective + */ +CV_EXPORTS_W void getRectSubPix( InputArray image, Size patchSize, + Point2f center, OutputArray patch, int patchType = -1 ); + +/** @example samples/cpp/polar_transforms.cpp +An example using the cv::linearPolar and cv::logPolar operations +*/ + +/** @brief Remaps an image to semilog-polar coordinates space. + +@deprecated This function produces same result as cv::warpPolar(src, dst, src.size(), center, maxRadius, flags+WARP_POLAR_LOG); + +@internal +Transform the source image using the following transformation (See @ref polar_remaps_reference_image "Polar remaps reference image d)"): +\f[\begin{array}{l} + dst( \rho , \phi ) = src(x,y) \\ + dst.size() \leftarrow src.size() +\end{array}\f] + +where +\f[\begin{array}{l} + I = (dx,dy) = (x - center.x,y - center.y) \\ + \rho = M \cdot log_e(\texttt{magnitude} (I)) ,\\ + \phi = Kangle \cdot \texttt{angle} (I) \\ +\end{array}\f] + +and +\f[\begin{array}{l} + M = src.cols / log_e(maxRadius) \\ + Kangle = src.rows / 2\Pi \\ +\end{array}\f] + +The function emulates the human "foveal" vision and can be used for fast scale and +rotation-invariant template matching, for object tracking and so forth. +@param src Source image +@param dst Destination image. It will have same size and type as src. +@param center The transformation center; where the output precision is maximal +@param M Magnitude scale parameter. It determines the radius of the bounding circle to transform too. +@param flags A combination of interpolation methods, see #InterpolationFlags + +@note +- The function can not operate in-place. +- To calculate magnitude and angle in degrees #cartToPolar is used internally thus angles are measured from 0 to 360 with accuracy about 0.3 degrees. + +@sa cv::linearPolar +@endinternal +*/ +CV_EXPORTS_W void logPolar( InputArray src, OutputArray dst, + Point2f center, double M, int flags ); + +/** @brief Remaps an image to polar coordinates space. + +@deprecated This function produces same result as cv::warpPolar(src, dst, src.size(), center, maxRadius, flags) + +@internal +Transform the source image using the following transformation (See @ref polar_remaps_reference_image "Polar remaps reference image c)"): +\f[\begin{array}{l} + dst( \rho , \phi ) = src(x,y) \\ + dst.size() \leftarrow src.size() +\end{array}\f] + +where +\f[\begin{array}{l} + I = (dx,dy) = (x - center.x,y - center.y) \\ + \rho = Kmag \cdot \texttt{magnitude} (I) ,\\ + \phi = angle \cdot \texttt{angle} (I) +\end{array}\f] + +and +\f[\begin{array}{l} + Kx = src.cols / maxRadius \\ + Ky = src.rows / 2\Pi +\end{array}\f] + + +@param src Source image +@param dst Destination image. It will have same size and type as src. +@param center The transformation center; +@param maxRadius The radius of the bounding circle to transform. It determines the inverse magnitude scale parameter too. +@param flags A combination of interpolation methods, see #InterpolationFlags + +@note +- The function can not operate in-place. +- To calculate magnitude and angle in degrees #cartToPolar is used internally thus angles are measured from 0 to 360 with accuracy about 0.3 degrees. + +@sa cv::logPolar +@endinternal +*/ +CV_EXPORTS_W void linearPolar( InputArray src, OutputArray dst, + Point2f center, double maxRadius, int flags ); + + +/** \brief Remaps an image to polar or semilog-polar coordinates space + +@anchor polar_remaps_reference_image +![Polar remaps reference](pics/polar_remap_doc.png) + +Transform the source image using the following transformation: +\f[ +dst(\rho , \phi ) = src(x,y) +\f] + +where +\f[ +\begin{array}{l} +\vec{I} = (x - center.x, \;y - center.y) \\ +\phi = Kangle \cdot \texttt{angle} (\vec{I}) \\ +\rho = \left\{\begin{matrix} +Klin \cdot \texttt{magnitude} (\vec{I}) & default \\ +Klog \cdot log_e(\texttt{magnitude} (\vec{I})) & if \; semilog \\ +\end{matrix}\right. +\end{array} +\f] + +and +\f[ +\begin{array}{l} +Kangle = dsize.height / 2\Pi \\ +Klin = dsize.width / maxRadius \\ +Klog = dsize.width / log_e(maxRadius) \\ +\end{array} +\f] + + +\par Linear vs semilog mapping + +Polar mapping can be linear or semi-log. Add one of #WarpPolarMode to `flags` to specify the polar mapping mode. + +Linear is the default mode. + +The semilog mapping emulates the human "foveal" vision that permit very high acuity on the line of sight (central vision) +in contrast to peripheral vision where acuity is minor. + +\par Option on `dsize`: + +- if both values in `dsize <=0 ` (default), +the destination image will have (almost) same area of source bounding circle: +\f[\begin{array}{l} +dsize.area \leftarrow (maxRadius^2 \cdot \Pi) \\ +dsize.width = \texttt{cvRound}(maxRadius) \\ +dsize.height = \texttt{cvRound}(maxRadius \cdot \Pi) \\ +\end{array}\f] + + +- if only `dsize.height <= 0`, +the destination image area will be proportional to the bounding circle area but scaled by `Kx * Kx`: +\f[\begin{array}{l} +dsize.height = \texttt{cvRound}(dsize.width \cdot \Pi) \\ +\end{array} +\f] + +- if both values in `dsize > 0 `, +the destination image will have the given size therefore the area of the bounding circle will be scaled to `dsize`. + + +\par Reverse mapping + +You can get reverse mapping adding #WARP_INVERSE_MAP to `flags` +\snippet polar_transforms.cpp InverseMap + +In addiction, to calculate the original coordinate from a polar mapped coordinate \f$(rho, phi)->(x, y)\f$: +\snippet polar_transforms.cpp InverseCoordinate + +@param src Source image. +@param dst Destination image. It will have same type as src. +@param dsize The destination image size (see description for valid options). +@param center The transformation center. +@param maxRadius The radius of the bounding circle to transform. It determines the inverse magnitude scale parameter too. +@param flags A combination of interpolation methods, #InterpolationFlags + #WarpPolarMode. + - Add #WARP_POLAR_LINEAR to select linear polar mapping (default) + - Add #WARP_POLAR_LOG to select semilog polar mapping + - Add #WARP_INVERSE_MAP for reverse mapping. +@note +- The function can not operate in-place. +- To calculate magnitude and angle in degrees #cartToPolar is used internally thus angles are measured from 0 to 360 with accuracy about 0.3 degrees. +- This function uses #remap. Due to current implementation limitations the size of an input and output images should be less than 32767x32767. + +@sa cv::remap +*/ +CV_EXPORTS_W void warpPolar(InputArray src, OutputArray dst, Size dsize, + Point2f center, double maxRadius, int flags); + + +//! @} imgproc_transform + +//! @addtogroup imgproc_misc +//! @{ + +/** @brief Calculates the integral of an image. + +The function calculates one or more integral images for the source image as follows: + +\f[\texttt{sum} (X,Y) = \sum _{x + +Calculates the cross-power spectrum of two supplied source arrays. The arrays are padded if needed +with getOptimalDFTSize. + +The function performs the following equations: +- First it applies a Hanning window (see ) to each +image to remove possible edge effects. This window is cached until the array size changes to speed +up processing time. +- Next it computes the forward DFTs of each source array: +\f[\mathbf{G}_a = \mathcal{F}\{src_1\}, \; \mathbf{G}_b = \mathcal{F}\{src_2\}\f] +where \f$\mathcal{F}\f$ is the forward DFT. +- It then computes the cross-power spectrum of each frequency domain array: +\f[R = \frac{ \mathbf{G}_a \mathbf{G}_b^*}{|\mathbf{G}_a \mathbf{G}_b^*|}\f] +- Next the cross-correlation is converted back into the time domain via the inverse DFT: +\f[r = \mathcal{F}^{-1}\{R\}\f] +- Finally, it computes the peak location and computes a 5x5 weighted centroid around the peak to +achieve sub-pixel accuracy. +\f[(\Delta x, \Delta y) = \texttt{weightedCentroid} \{\arg \max_{(x, y)}\{r\}\}\f] +- If non-zero, the response parameter is computed as the sum of the elements of r within the 5x5 +centroid around the peak location. It is normalized to a maximum of 1 (meaning there is a single +peak) and will be smaller when there are multiple peaks. + +@param src1 Source floating point array (CV_32FC1 or CV_64FC1) +@param src2 Source floating point array (CV_32FC1 or CV_64FC1) +@param window Floating point array with windowing coefficients to reduce edge effects (optional). +@param response Signal power within the 5x5 centroid around the peak, between 0 and 1 (optional). +@returns detected phase shift (sub-pixel) between the two arrays. + +@sa dft, getOptimalDFTSize, idft, mulSpectrums createHanningWindow + */ +CV_EXPORTS_W Point2d phaseCorrelate(InputArray src1, InputArray src2, + InputArray window = noArray(), CV_OUT double* response = 0); + +/** @brief This function computes a Hanning window coefficients in two dimensions. + +See (http://en.wikipedia.org/wiki/Hann_function) and (http://en.wikipedia.org/wiki/Window_function) +for more information. + +An example is shown below: +@code + // create hanning window of size 100x100 and type CV_32F + Mat hann; + createHanningWindow(hann, Size(100, 100), CV_32F); +@endcode +@param dst Destination array to place Hann coefficients in +@param winSize The window size specifications (both width and height must be > 1) +@param type Created array type + */ +CV_EXPORTS_W void createHanningWindow(OutputArray dst, Size winSize, int type); + +/** @brief Performs the per-element division of the first Fourier spectrum by the second Fourier spectrum. + +The function cv::divSpectrums performs the per-element division of the first array by the second array. +The arrays are CCS-packed or complex matrices that are results of a real or complex Fourier transform. + +@param a first input array. +@param b second input array of the same size and type as src1 . +@param c output array of the same size and type as src1 . +@param flags operation flags; currently, the only supported flag is cv::DFT_ROWS, which indicates that +each row of src1 and src2 is an independent 1D Fourier spectrum. If you do not want to use this flag, then simply add a `0` as value. +@param conjB optional flag that conjugates the second input array before the multiplication (true) +or not (false). +*/ +CV_EXPORTS_W void divSpectrums(InputArray a, InputArray b, OutputArray c, + int flags, bool conjB = false); + +//! @} imgproc_motion + +//! @addtogroup imgproc_misc +//! @{ + +/** @brief Applies a fixed-level threshold to each array element. + +The function applies fixed-level thresholding to a multiple-channel array. The function is typically +used to get a bi-level (binary) image out of a grayscale image ( #compare could be also used for +this purpose) or for removing a noise, that is, filtering out pixels with too small or too large +values. There are several types of thresholding supported by the function. They are determined by +type parameter. + +Also, the special values #THRESH_OTSU or #THRESH_TRIANGLE may be combined with one of the +above values. In these cases, the function determines the optimal threshold value using the Otsu's +or Triangle algorithm and uses it instead of the specified thresh. + +@note Currently, the Otsu's and Triangle methods are implemented only for 8-bit single-channel images. + +@param src input array (multiple-channel, 8-bit or 32-bit floating point). +@param dst output array of the same size and type and the same number of channels as src. +@param thresh threshold value. +@param maxval maximum value to use with the #THRESH_BINARY and #THRESH_BINARY_INV thresholding +types. +@param type thresholding type (see #ThresholdTypes). +@return the computed threshold value if Otsu's or Triangle methods used. + +@sa adaptiveThreshold, findContours, compare, min, max + */ +CV_EXPORTS_W double threshold( InputArray src, OutputArray dst, + double thresh, double maxval, int type ); + + +/** @brief Applies an adaptive threshold to an array. + +The function transforms a grayscale image to a binary image according to the formulae: +- **THRESH_BINARY** + \f[dst(x,y) = \fork{\texttt{maxValue}}{if \(src(x,y) > T(x,y)\)}{0}{otherwise}\f] +- **THRESH_BINARY_INV** + \f[dst(x,y) = \fork{0}{if \(src(x,y) > T(x,y)\)}{\texttt{maxValue}}{otherwise}\f] +where \f$T(x,y)\f$ is a threshold calculated individually for each pixel (see adaptiveMethod parameter). + +The function can process the image in-place. + +@param src Source 8-bit single-channel image. +@param dst Destination image of the same size and the same type as src. +@param maxValue Non-zero value assigned to the pixels for which the condition is satisfied +@param adaptiveMethod Adaptive thresholding algorithm to use, see #AdaptiveThresholdTypes. +The #BORDER_REPLICATE | #BORDER_ISOLATED is used to process boundaries. +@param thresholdType Thresholding type that must be either #THRESH_BINARY or #THRESH_BINARY_INV, +see #ThresholdTypes. +@param blockSize Size of a pixel neighborhood that is used to calculate a threshold value for the +pixel: 3, 5, 7, and so on. +@param C Constant subtracted from the mean or weighted mean (see the details below). Normally, it +is positive but may be zero or negative as well. + +@sa threshold, blur, GaussianBlur + */ +CV_EXPORTS_W void adaptiveThreshold( InputArray src, OutputArray dst, + double maxValue, int adaptiveMethod, + int thresholdType, int blockSize, double C ); + +//! @} imgproc_misc + +//! @addtogroup imgproc_filter +//! @{ + +/** @example samples/cpp/tutorial_code/ImgProc/Pyramids/Pyramids.cpp +An example using pyrDown and pyrUp functions +*/ + +/** @brief Blurs an image and downsamples it. + +By default, size of the output image is computed as `Size((src.cols+1)/2, (src.rows+1)/2)`, but in +any case, the following conditions should be satisfied: + +\f[\begin{array}{l} | \texttt{dstsize.width} *2-src.cols| \leq 2 \\ | \texttt{dstsize.height} *2-src.rows| \leq 2 \end{array}\f] + +The function performs the downsampling step of the Gaussian pyramid construction. First, it +convolves the source image with the kernel: + +\f[\frac{1}{256} \begin{bmatrix} 1 & 4 & 6 & 4 & 1 \\ 4 & 16 & 24 & 16 & 4 \\ 6 & 24 & 36 & 24 & 6 \\ 4 & 16 & 24 & 16 & 4 \\ 1 & 4 & 6 & 4 & 1 \end{bmatrix}\f] + +Then, it downsamples the image by rejecting even rows and columns. + +@param src input image. +@param dst output image; it has the specified size and the same type as src. +@param dstsize size of the output image. +@param borderType Pixel extrapolation method, see #BorderTypes (#BORDER_CONSTANT isn't supported) + */ +CV_EXPORTS_W void pyrDown( InputArray src, OutputArray dst, + const Size& dstsize = Size(), int borderType = BORDER_DEFAULT ); + +/** @brief Upsamples an image and then blurs it. + +By default, size of the output image is computed as `Size(src.cols\*2, (src.rows\*2)`, but in any +case, the following conditions should be satisfied: + +\f[\begin{array}{l} | \texttt{dstsize.width} -src.cols*2| \leq ( \texttt{dstsize.width} \mod 2) \\ | \texttt{dstsize.height} -src.rows*2| \leq ( \texttt{dstsize.height} \mod 2) \end{array}\f] + +The function performs the upsampling step of the Gaussian pyramid construction, though it can +actually be used to construct the Laplacian pyramid. First, it upsamples the source image by +injecting even zero rows and columns and then convolves the result with the same kernel as in +pyrDown multiplied by 4. + +@param src input image. +@param dst output image. It has the specified size and the same type as src . +@param dstsize size of the output image. +@param borderType Pixel extrapolation method, see #BorderTypes (only #BORDER_DEFAULT is supported) + */ +CV_EXPORTS_W void pyrUp( InputArray src, OutputArray dst, + const Size& dstsize = Size(), int borderType = BORDER_DEFAULT ); + +/** @brief Constructs the Gaussian pyramid for an image. + +The function constructs a vector of images and builds the Gaussian pyramid by recursively applying +pyrDown to the previously built pyramid layers, starting from `dst[0]==src`. + +@param src Source image. Check pyrDown for the list of supported types. +@param dst Destination vector of maxlevel+1 images of the same type as src. dst[0] will be the +same as src. dst[1] is the next pyramid layer, a smoothed and down-sized src, and so on. +@param maxlevel 0-based index of the last (the smallest) pyramid layer. It must be non-negative. +@param borderType Pixel extrapolation method, see #BorderTypes (#BORDER_CONSTANT isn't supported) + */ +CV_EXPORTS void buildPyramid( InputArray src, OutputArrayOfArrays dst, + int maxlevel, int borderType = BORDER_DEFAULT ); + +//! @} imgproc_filter + +//! @addtogroup imgproc_hist +//! @{ + +/** @example samples/cpp/demhist.cpp +An example for creating histograms of an image +*/ + +/** @brief Calculates a histogram of a set of arrays. + +The function cv::calcHist calculates the histogram of one or more arrays. The elements of a tuple used +to increment a histogram bin are taken from the corresponding input arrays at the same location. The +sample below shows how to compute a 2D Hue-Saturation histogram for a color image. : +@include snippets/imgproc_calcHist.cpp + +@param images Source arrays. They all should have the same depth, CV_8U, CV_16U or CV_32F , and the same +size. Each of them can have an arbitrary number of channels. +@param nimages Number of source images. +@param channels List of the dims channels used to compute the histogram. The first array channels +are numerated from 0 to images[0].channels()-1 , the second array channels are counted from +images[0].channels() to images[0].channels() + images[1].channels()-1, and so on. +@param mask Optional mask. If the matrix is not empty, it must be an 8-bit array of the same size +as images[i] . The non-zero mask elements mark the array elements counted in the histogram. +@param hist Output histogram, which is a dense or sparse dims -dimensional array. +@param dims Histogram dimensionality that must be positive and not greater than CV_MAX_DIMS +(equal to 32 in the current OpenCV version). +@param histSize Array of histogram sizes in each dimension. +@param ranges Array of the dims arrays of the histogram bin boundaries in each dimension. When the +histogram is uniform ( uniform =true), then for each dimension i it is enough to specify the lower +(inclusive) boundary \f$L_0\f$ of the 0-th histogram bin and the upper (exclusive) boundary +\f$U_{\texttt{histSize}[i]-1}\f$ for the last histogram bin histSize[i]-1 . That is, in case of a +uniform histogram each of ranges[i] is an array of 2 elements. When the histogram is not uniform ( +uniform=false ), then each of ranges[i] contains histSize[i]+1 elements: +\f$L_0, U_0=L_1, U_1=L_2, ..., U_{\texttt{histSize[i]}-2}=L_{\texttt{histSize[i]}-1}, U_{\texttt{histSize[i]}-1}\f$ +. The array elements, that are not between \f$L_0\f$ and \f$U_{\texttt{histSize[i]}-1}\f$ , are not +counted in the histogram. +@param uniform Flag indicating whether the histogram is uniform or not (see above). +@param accumulate Accumulation flag. If it is set, the histogram is not cleared in the beginning +when it is allocated. This feature enables you to compute a single histogram from several sets of +arrays, or to update the histogram in time. +*/ +CV_EXPORTS void calcHist( const Mat* images, int nimages, + const int* channels, InputArray mask, + OutputArray hist, int dims, const int* histSize, + const float** ranges, bool uniform = true, bool accumulate = false ); + +/** @overload + +this variant uses %SparseMat for output +*/ +CV_EXPORTS void calcHist( const Mat* images, int nimages, + const int* channels, InputArray mask, + SparseMat& hist, int dims, + const int* histSize, const float** ranges, + bool uniform = true, bool accumulate = false ); + +/** @overload */ +CV_EXPORTS_W void calcHist( InputArrayOfArrays images, + const std::vector& channels, + InputArray mask, OutputArray hist, + const std::vector& histSize, + const std::vector& ranges, + bool accumulate = false ); + +/** @brief Calculates the back projection of a histogram. + +The function cv::calcBackProject calculates the back project of the histogram. That is, similarly to +#calcHist , at each location (x, y) the function collects the values from the selected channels +in the input images and finds the corresponding histogram bin. But instead of incrementing it, the +function reads the bin value, scales it by scale , and stores in backProject(x,y) . In terms of +statistics, the function computes probability of each element value in respect with the empirical +probability distribution represented by the histogram. See how, for example, you can find and track +a bright-colored object in a scene: + +- Before tracking, show the object to the camera so that it covers almost the whole frame. +Calculate a hue histogram. The histogram may have strong maximums, corresponding to the dominant +colors in the object. + +- When tracking, calculate a back projection of a hue plane of each input video frame using that +pre-computed histogram. Threshold the back projection to suppress weak colors. It may also make +sense to suppress pixels with non-sufficient color saturation and too dark or too bright pixels. + +- Find connected components in the resulting picture and choose, for example, the largest +component. + +This is an approximate algorithm of the CamShift color object tracker. + +@param images Source arrays. They all should have the same depth, CV_8U, CV_16U or CV_32F , and the same +size. Each of them can have an arbitrary number of channels. +@param nimages Number of source images. +@param channels The list of channels used to compute the back projection. The number of channels +must match the histogram dimensionality. The first array channels are numerated from 0 to +images[0].channels()-1 , the second array channels are counted from images[0].channels() to +images[0].channels() + images[1].channels()-1, and so on. +@param hist Input histogram that can be dense or sparse. +@param backProject Destination back projection array that is a single-channel array of the same +size and depth as images[0] . +@param ranges Array of arrays of the histogram bin boundaries in each dimension. See #calcHist . +@param scale Optional scale factor for the output back projection. +@param uniform Flag indicating whether the histogram is uniform or not (see above). + +@sa calcHist, compareHist + */ +CV_EXPORTS void calcBackProject( const Mat* images, int nimages, + const int* channels, InputArray hist, + OutputArray backProject, const float** ranges, + double scale = 1, bool uniform = true ); + +/** @overload */ +CV_EXPORTS void calcBackProject( const Mat* images, int nimages, + const int* channels, const SparseMat& hist, + OutputArray backProject, const float** ranges, + double scale = 1, bool uniform = true ); + +/** @overload */ +CV_EXPORTS_W void calcBackProject( InputArrayOfArrays images, const std::vector& channels, + InputArray hist, OutputArray dst, + const std::vector& ranges, + double scale ); + +/** @brief Compares two histograms. + +The function cv::compareHist compares two dense or two sparse histograms using the specified method. + +The function returns \f$d(H_1, H_2)\f$ . + +While the function works well with 1-, 2-, 3-dimensional dense histograms, it may not be suitable +for high-dimensional sparse histograms. In such histograms, because of aliasing and sampling +problems, the coordinates of non-zero histogram bins can slightly shift. To compare such histograms +or more general sparse configurations of weighted points, consider using the #EMD function. + +@param H1 First compared histogram. +@param H2 Second compared histogram of the same size as H1 . +@param method Comparison method, see #HistCompMethods + */ +CV_EXPORTS_W double compareHist( InputArray H1, InputArray H2, int method ); + +/** @overload */ +CV_EXPORTS double compareHist( const SparseMat& H1, const SparseMat& H2, int method ); + +/** @brief Equalizes the histogram of a grayscale image. + +The function equalizes the histogram of the input image using the following algorithm: + +- Calculate the histogram \f$H\f$ for src . +- Normalize the histogram so that the sum of histogram bins is 255. +- Compute the integral of the histogram: +\f[H'_i = \sum _{0 \le j < i} H(j)\f] +- Transform the image using \f$H'\f$ as a look-up table: \f$\texttt{dst}(x,y) = H'(\texttt{src}(x,y))\f$ + +The algorithm normalizes the brightness and increases the contrast of the image. + +@param src Source 8-bit single channel image. +@param dst Destination image of the same size and type as src . + */ +CV_EXPORTS_W void equalizeHist( InputArray src, OutputArray dst ); + +/** @brief Creates a smart pointer to a cv::CLAHE class and initializes it. + +@param clipLimit Threshold for contrast limiting. +@param tileGridSize Size of grid for histogram equalization. Input image will be divided into +equally sized rectangular tiles. tileGridSize defines the number of tiles in row and column. + */ +CV_EXPORTS_W Ptr createCLAHE(double clipLimit = 40.0, Size tileGridSize = Size(8, 8)); + +/** @brief Computes the "minimal work" distance between two weighted point configurations. + +The function computes the earth mover distance and/or a lower boundary of the distance between the +two weighted point configurations. One of the applications described in @cite RubnerSept98, +@cite Rubner2000 is multi-dimensional histogram comparison for image retrieval. EMD is a transportation +problem that is solved using some modification of a simplex algorithm, thus the complexity is +exponential in the worst case, though, on average it is much faster. In the case of a real metric +the lower boundary can be calculated even faster (using linear-time algorithm) and it can be used +to determine roughly whether the two signatures are far enough so that they cannot relate to the +same object. + +@param signature1 First signature, a \f$\texttt{size1}\times \texttt{dims}+1\f$ floating-point matrix. +Each row stores the point weight followed by the point coordinates. The matrix is allowed to have +a single column (weights only) if the user-defined cost matrix is used. The weights must be +non-negative and have at least one non-zero value. +@param signature2 Second signature of the same format as signature1 , though the number of rows +may be different. The total weights may be different. In this case an extra "dummy" point is added +to either signature1 or signature2. The weights must be non-negative and have at least one non-zero +value. +@param distType Used metric. See #DistanceTypes. +@param cost User-defined \f$\texttt{size1}\times \texttt{size2}\f$ cost matrix. Also, if a cost matrix +is used, lower boundary lowerBound cannot be calculated because it needs a metric function. +@param lowerBound Optional input/output parameter: lower boundary of a distance between the two +signatures that is a distance between mass centers. The lower boundary may not be calculated if +the user-defined cost matrix is used, the total weights of point configurations are not equal, or +if the signatures consist of weights only (the signature matrices have a single column). You +**must** initialize \*lowerBound . If the calculated distance between mass centers is greater or +equal to \*lowerBound (it means that the signatures are far enough), the function does not +calculate EMD. In any case \*lowerBound is set to the calculated distance between mass centers on +return. Thus, if you want to calculate both distance between mass centers and EMD, \*lowerBound +should be set to 0. +@param flow Resultant \f$\texttt{size1} \times \texttt{size2}\f$ flow matrix: \f$\texttt{flow}_{i,j}\f$ is +a flow from \f$i\f$ -th point of signature1 to \f$j\f$ -th point of signature2 . + */ +CV_EXPORTS float EMD( InputArray signature1, InputArray signature2, + int distType, InputArray cost=noArray(), + float* lowerBound = 0, OutputArray flow = noArray() ); + +CV_EXPORTS_AS(EMD) float wrapperEMD( InputArray signature1, InputArray signature2, + int distType, InputArray cost=noArray(), + CV_IN_OUT Ptr lowerBound = Ptr(), OutputArray flow = noArray() ); + +//! @} imgproc_hist + +//! @addtogroup imgproc_segmentation +//! @{ + +/** @example samples/cpp/watershed.cpp +An example using the watershed algorithm +*/ + +/** @brief Performs a marker-based image segmentation using the watershed algorithm. + +The function implements one of the variants of watershed, non-parametric marker-based segmentation +algorithm, described in @cite Meyer92 . + +Before passing the image to the function, you have to roughly outline the desired regions in the +image markers with positive (\>0) indices. So, every region is represented as one or more connected +components with the pixel values 1, 2, 3, and so on. Such markers can be retrieved from a binary +mask using #findContours and #drawContours (see the watershed.cpp demo). The markers are "seeds" of +the future image regions. All the other pixels in markers , whose relation to the outlined regions +is not known and should be defined by the algorithm, should be set to 0's. In the function output, +each pixel in markers is set to a value of the "seed" components or to -1 at boundaries between the +regions. + +@note Any two neighbor connected components are not necessarily separated by a watershed boundary +(-1's pixels); for example, they can touch each other in the initial marker image passed to the +function. + +@param image Input 8-bit 3-channel image. +@param markers Input/output 32-bit single-channel image (map) of markers. It should have the same +size as image . + +@sa findContours + */ +CV_EXPORTS_W void watershed( InputArray image, InputOutputArray markers ); + +//! @} imgproc_segmentation + +//! @addtogroup imgproc_filter +//! @{ + +/** @brief Performs initial step of meanshift segmentation of an image. + +The function implements the filtering stage of meanshift segmentation, that is, the output of the +function is the filtered "posterized" image with color gradients and fine-grain texture flattened. +At every pixel (X,Y) of the input image (or down-sized input image, see below) the function executes +meanshift iterations, that is, the pixel (X,Y) neighborhood in the joint space-color hyperspace is +considered: + +\f[(x,y): X- \texttt{sp} \le x \le X+ \texttt{sp} , Y- \texttt{sp} \le y \le Y+ \texttt{sp} , ||(R,G,B)-(r,g,b)|| \le \texttt{sr}\f] + +where (R,G,B) and (r,g,b) are the vectors of color components at (X,Y) and (x,y), respectively +(though, the algorithm does not depend on the color space used, so any 3-component color space can +be used instead). Over the neighborhood the average spatial value (X',Y') and average color vector +(R',G',B') are found and they act as the neighborhood center on the next iteration: + +\f[(X,Y)~(X',Y'), (R,G,B)~(R',G',B').\f] + +After the iterations over, the color components of the initial pixel (that is, the pixel from where +the iterations started) are set to the final value (average color at the last iteration): + +\f[I(X,Y) <- (R*,G*,B*)\f] + +When maxLevel \> 0, the gaussian pyramid of maxLevel+1 levels is built, and the above procedure is +run on the smallest layer first. After that, the results are propagated to the larger layer and the +iterations are run again only on those pixels where the layer colors differ by more than sr from the +lower-resolution layer of the pyramid. That makes boundaries of color regions sharper. Note that the +results will be actually different from the ones obtained by running the meanshift procedure on the +whole original image (i.e. when maxLevel==0). + +@param src The source 8-bit, 3-channel image. +@param dst The destination image of the same format and the same size as the source. +@param sp The spatial window radius. +@param sr The color window radius. +@param maxLevel Maximum level of the pyramid for the segmentation. +@param termcrit Termination criteria: when to stop meanshift iterations. + */ +CV_EXPORTS_W void pyrMeanShiftFiltering( InputArray src, OutputArray dst, + double sp, double sr, int maxLevel = 1, + TermCriteria termcrit=TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS,5,1) ); + +//! @} + +//! @addtogroup imgproc_segmentation +//! @{ + +/** @example samples/cpp/grabcut.cpp +An example using the GrabCut algorithm +![Sample Screenshot](grabcut_output1.jpg) +*/ + +/** @brief Runs the GrabCut algorithm. + +The function implements the [GrabCut image segmentation algorithm](http://en.wikipedia.org/wiki/GrabCut). + +@param img Input 8-bit 3-channel image. +@param mask Input/output 8-bit single-channel mask. The mask is initialized by the function when +mode is set to #GC_INIT_WITH_RECT. Its elements may have one of the #GrabCutClasses. +@param rect ROI containing a segmented object. The pixels outside of the ROI are marked as +"obvious background". The parameter is only used when mode==#GC_INIT_WITH_RECT . +@param bgdModel Temporary array for the background model. Do not modify it while you are +processing the same image. +@param fgdModel Temporary arrays for the foreground model. Do not modify it while you are +processing the same image. +@param iterCount Number of iterations the algorithm should make before returning the result. Note +that the result can be refined with further calls with mode==#GC_INIT_WITH_MASK or +mode==GC_EVAL . +@param mode Operation mode that could be one of the #GrabCutModes + */ +CV_EXPORTS_W void grabCut( InputArray img, InputOutputArray mask, Rect rect, + InputOutputArray bgdModel, InputOutputArray fgdModel, + int iterCount, int mode = GC_EVAL ); + +//! @} imgproc_segmentation + +//! @addtogroup imgproc_misc +//! @{ + +/** @example samples/cpp/distrans.cpp +An example on using the distance transform +*/ + +/** @brief Calculates the distance to the closest zero pixel for each pixel of the source image. + +The function cv::distanceTransform calculates the approximate or precise distance from every binary +image pixel to the nearest zero pixel. For zero image pixels, the distance will obviously be zero. + +When maskSize == #DIST_MASK_PRECISE and distanceType == #DIST_L2 , the function runs the +algorithm described in @cite Felzenszwalb04 . This algorithm is parallelized with the TBB library. + +In other cases, the algorithm @cite Borgefors86 is used. This means that for a pixel the function +finds the shortest path to the nearest zero pixel consisting of basic shifts: horizontal, vertical, +diagonal, or knight's move (the latest is available for a \f$5\times 5\f$ mask). The overall +distance is calculated as a sum of these basic distances. Since the distance function should be +symmetric, all of the horizontal and vertical shifts must have the same cost (denoted as a ), all +the diagonal shifts must have the same cost (denoted as `b`), and all knight's moves must have the +same cost (denoted as `c`). For the #DIST_C and #DIST_L1 types, the distance is calculated +precisely, whereas for #DIST_L2 (Euclidean distance) the distance can be calculated only with a +relative error (a \f$5\times 5\f$ mask gives more accurate results). For `a`,`b`, and `c`, OpenCV +uses the values suggested in the original paper: +- DIST_L1: `a = 1, b = 2` +- DIST_L2: + - `3 x 3`: `a=0.955, b=1.3693` + - `5 x 5`: `a=1, b=1.4, c=2.1969` +- DIST_C: `a = 1, b = 1` + +Typically, for a fast, coarse distance estimation #DIST_L2, a \f$3\times 3\f$ mask is used. For a +more accurate distance estimation #DIST_L2, a \f$5\times 5\f$ mask or the precise algorithm is used. +Note that both the precise and the approximate algorithms are linear on the number of pixels. + +This variant of the function does not only compute the minimum distance for each pixel \f$(x, y)\f$ +but also identifies the nearest connected component consisting of zero pixels +(labelType==#DIST_LABEL_CCOMP) or the nearest zero pixel (labelType==#DIST_LABEL_PIXEL). Index of the +component/pixel is stored in `labels(x, y)`. When labelType==#DIST_LABEL_CCOMP, the function +automatically finds connected components of zero pixels in the input image and marks them with +distinct labels. When labelType==#DIST_LABEL_PIXEL, the function scans through the input image and +marks all the zero pixels with distinct labels. + +In this mode, the complexity is still linear. That is, the function provides a very fast way to +compute the Voronoi diagram for a binary image. Currently, the second variant can use only the +approximate distance transform algorithm, i.e. maskSize=#DIST_MASK_PRECISE is not supported +yet. + +@param src 8-bit, single-channel (binary) source image. +@param dst Output image with calculated distances. It is a 8-bit or 32-bit floating-point, +single-channel image of the same size as src. +@param labels Output 2D array of labels (the discrete Voronoi diagram). It has the type +CV_32SC1 and the same size as src. +@param distanceType Type of distance, see #DistanceTypes +@param maskSize Size of the distance transform mask, see #DistanceTransformMasks. +#DIST_MASK_PRECISE is not supported by this variant. In case of the #DIST_L1 or #DIST_C distance type, +the parameter is forced to 3 because a \f$3\times 3\f$ mask gives the same result as \f$5\times +5\f$ or any larger aperture. +@param labelType Type of the label array to build, see #DistanceTransformLabelTypes. + */ +CV_EXPORTS_AS(distanceTransformWithLabels) void distanceTransform( InputArray src, OutputArray dst, + OutputArray labels, int distanceType, int maskSize, + int labelType = DIST_LABEL_CCOMP ); + +/** @overload +@param src 8-bit, single-channel (binary) source image. +@param dst Output image with calculated distances. It is a 8-bit or 32-bit floating-point, +single-channel image of the same size as src . +@param distanceType Type of distance, see #DistanceTypes +@param maskSize Size of the distance transform mask, see #DistanceTransformMasks. In case of the +#DIST_L1 or #DIST_C distance type, the parameter is forced to 3 because a \f$3\times 3\f$ mask gives +the same result as \f$5\times 5\f$ or any larger aperture. +@param dstType Type of output image. It can be CV_8U or CV_32F. Type CV_8U can be used only for +the first variant of the function and distanceType == #DIST_L1. +*/ +CV_EXPORTS_W void distanceTransform( InputArray src, OutputArray dst, + int distanceType, int maskSize, int dstType=CV_32F); + +/** @brief Fills a connected component with the given color. + +The function cv::floodFill fills a connected component starting from the seed point with the specified +color. The connectivity is determined by the color/brightness closeness of the neighbor pixels. The +pixel at \f$(x,y)\f$ is considered to belong to the repainted domain if: + +- in case of a grayscale image and floating range +\f[\texttt{src} (x',y')- \texttt{loDiff} \leq \texttt{src} (x,y) \leq \texttt{src} (x',y')+ \texttt{upDiff}\f] + + +- in case of a grayscale image and fixed range +\f[\texttt{src} ( \texttt{seedPoint} .x, \texttt{seedPoint} .y)- \texttt{loDiff} \leq \texttt{src} (x,y) \leq \texttt{src} ( \texttt{seedPoint} .x, \texttt{seedPoint} .y)+ \texttt{upDiff}\f] + + +- in case of a color image and floating range +\f[\texttt{src} (x',y')_r- \texttt{loDiff} _r \leq \texttt{src} (x,y)_r \leq \texttt{src} (x',y')_r+ \texttt{upDiff} _r,\f] +\f[\texttt{src} (x',y')_g- \texttt{loDiff} _g \leq \texttt{src} (x,y)_g \leq \texttt{src} (x',y')_g+ \texttt{upDiff} _g\f] +and +\f[\texttt{src} (x',y')_b- \texttt{loDiff} _b \leq \texttt{src} (x,y)_b \leq \texttt{src} (x',y')_b+ \texttt{upDiff} _b\f] + + +- in case of a color image and fixed range +\f[\texttt{src} ( \texttt{seedPoint} .x, \texttt{seedPoint} .y)_r- \texttt{loDiff} _r \leq \texttt{src} (x,y)_r \leq \texttt{src} ( \texttt{seedPoint} .x, \texttt{seedPoint} .y)_r+ \texttt{upDiff} _r,\f] +\f[\texttt{src} ( \texttt{seedPoint} .x, \texttt{seedPoint} .y)_g- \texttt{loDiff} _g \leq \texttt{src} (x,y)_g \leq \texttt{src} ( \texttt{seedPoint} .x, \texttt{seedPoint} .y)_g+ \texttt{upDiff} _g\f] +and +\f[\texttt{src} ( \texttt{seedPoint} .x, \texttt{seedPoint} .y)_b- \texttt{loDiff} _b \leq \texttt{src} (x,y)_b \leq \texttt{src} ( \texttt{seedPoint} .x, \texttt{seedPoint} .y)_b+ \texttt{upDiff} _b\f] + + +where \f$src(x',y')\f$ is the value of one of pixel neighbors that is already known to belong to the +component. That is, to be added to the connected component, a color/brightness of the pixel should +be close enough to: +- Color/brightness of one of its neighbors that already belong to the connected component in case +of a floating range. +- Color/brightness of the seed point in case of a fixed range. + +Use these functions to either mark a connected component with the specified color in-place, or build +a mask and then extract the contour, or copy the region to another image, and so on. + +@param image Input/output 1- or 3-channel, 8-bit, or floating-point image. It is modified by the +function unless the #FLOODFILL_MASK_ONLY flag is set in the second variant of the function. See +the details below. +@param mask Operation mask that should be a single-channel 8-bit image, 2 pixels wider and 2 pixels +taller than image. If an empty Mat is passed it will be created automatically. Since this is both an +input and output parameter, you must take responsibility of initializing it. +Flood-filling cannot go across non-zero pixels in the input mask. For example, +an edge detector output can be used as a mask to stop filling at edges. On output, pixels in the +mask corresponding to filled pixels in the image are set to 1 or to the specified value in flags +as described below. Additionally, the function fills the border of the mask with ones to simplify +internal processing. It is therefore possible to use the same mask in multiple calls to the function +to make sure the filled areas do not overlap. +@param seedPoint Starting point. +@param newVal New value of the repainted domain pixels. +@param loDiff Maximal lower brightness/color difference between the currently observed pixel and +one of its neighbors belonging to the component, or a seed pixel being added to the component. +@param upDiff Maximal upper brightness/color difference between the currently observed pixel and +one of its neighbors belonging to the component, or a seed pixel being added to the component. +@param rect Optional output parameter set by the function to the minimum bounding rectangle of the +repainted domain. +@param flags Operation flags. The first 8 bits contain a connectivity value. The default value of +4 means that only the four nearest neighbor pixels (those that share an edge) are considered. A +connectivity value of 8 means that the eight nearest neighbor pixels (those that share a corner) +will be considered. The next 8 bits (8-16) contain a value between 1 and 255 with which to fill +the mask (the default value is 1). For example, 4 | ( 255 \<\< 8 ) will consider 4 nearest +neighbours and fill the mask with a value of 255. The following additional options occupy higher +bits and therefore may be further combined with the connectivity and mask fill values using +bit-wise or (|), see #FloodFillFlags. + +@note Since the mask is larger than the filled image, a pixel \f$(x, y)\f$ in image corresponds to the +pixel \f$(x+1, y+1)\f$ in the mask . + +@sa findContours + */ +CV_EXPORTS_W int floodFill( InputOutputArray image, InputOutputArray mask, + Point seedPoint, Scalar newVal, CV_OUT Rect* rect=0, + Scalar loDiff = Scalar(), Scalar upDiff = Scalar(), + int flags = 4 ); + +/** @example samples/cpp/ffilldemo.cpp +An example using the FloodFill technique +*/ + +/** @overload + +variant without `mask` parameter +*/ +CV_EXPORTS int floodFill( InputOutputArray image, + Point seedPoint, Scalar newVal, CV_OUT Rect* rect = 0, + Scalar loDiff = Scalar(), Scalar upDiff = Scalar(), + int flags = 4 ); + +//! Performs linear blending of two images: +//! \f[ \texttt{dst}(i,j) = \texttt{weights1}(i,j)*\texttt{src1}(i,j) + \texttt{weights2}(i,j)*\texttt{src2}(i,j) \f] +//! @param src1 It has a type of CV_8UC(n) or CV_32FC(n), where n is a positive integer. +//! @param src2 It has the same type and size as src1. +//! @param weights1 It has a type of CV_32FC1 and the same size with src1. +//! @param weights2 It has a type of CV_32FC1 and the same size with src1. +//! @param dst It is created if it does not have the same size and type with src1. +CV_EXPORTS_W void blendLinear(InputArray src1, InputArray src2, InputArray weights1, InputArray weights2, OutputArray dst); + +//! @} imgproc_misc + +//! @addtogroup imgproc_color_conversions +//! @{ + +/** @brief Converts an image from one color space to another. + +The function converts an input image from one color space to another. In case of a transformation +to-from RGB color space, the order of the channels should be specified explicitly (RGB or BGR). Note +that the default color format in OpenCV is often referred to as RGB but it is actually BGR (the +bytes are reversed). So the first byte in a standard (24-bit) color image will be an 8-bit Blue +component, the second byte will be Green, and the third byte will be Red. The fourth, fifth, and +sixth bytes would then be the second pixel (Blue, then Green, then Red), and so on. + +The conventional ranges for R, G, and B channel values are: +- 0 to 255 for CV_8U images +- 0 to 65535 for CV_16U images +- 0 to 1 for CV_32F images + +In case of linear transformations, the range does not matter. But in case of a non-linear +transformation, an input RGB image should be normalized to the proper value range to get the correct +results, for example, for RGB \f$\rightarrow\f$ L\*u\*v\* transformation. For example, if you have a +32-bit floating-point image directly converted from an 8-bit image without any scaling, then it will +have the 0..255 value range instead of 0..1 assumed by the function. So, before calling #cvtColor , +you need first to scale the image down: +@code + img *= 1./255; + cvtColor(img, img, COLOR_BGR2Luv); +@endcode +If you use #cvtColor with 8-bit images, the conversion will have some information lost. For many +applications, this will not be noticeable but it is recommended to use 32-bit images in applications +that need the full range of colors or that convert an image before an operation and then convert +back. + +If conversion adds the alpha channel, its value will set to the maximum of corresponding channel +range: 255 for CV_8U, 65535 for CV_16U, 1 for CV_32F. + +@param src input image: 8-bit unsigned, 16-bit unsigned ( CV_16UC... ), or single-precision +floating-point. +@param dst output image of the same size and depth as src. +@param code color space conversion code (see #ColorConversionCodes). +@param dstCn number of channels in the destination image; if the parameter is 0, the number of the +channels is derived automatically from src and code. + +@see @ref imgproc_color_conversions + */ +CV_EXPORTS_W void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 ); + +/** @brief Converts an image from one color space to another where the source image is +stored in two planes. + +This function only supports YUV420 to RGB conversion as of now. + +@param src1: 8-bit image (#CV_8U) of the Y plane. +@param src2: image containing interleaved U/V plane. +@param dst: output image. +@param code: Specifies the type of conversion. It can take any of the following values: +- #COLOR_YUV2BGR_NV12 +- #COLOR_YUV2RGB_NV12 +- #COLOR_YUV2BGRA_NV12 +- #COLOR_YUV2RGBA_NV12 +- #COLOR_YUV2BGR_NV21 +- #COLOR_YUV2RGB_NV21 +- #COLOR_YUV2BGRA_NV21 +- #COLOR_YUV2RGBA_NV21 +*/ +CV_EXPORTS_W void cvtColorTwoPlane( InputArray src1, InputArray src2, OutputArray dst, int code ); + +/** @brief main function for all demosaicing processes + +@param src input image: 8-bit unsigned or 16-bit unsigned. +@param dst output image of the same size and depth as src. +@param code Color space conversion code (see the description below). +@param dstCn number of channels in the destination image; if the parameter is 0, the number of the +channels is derived automatically from src and code. + +The function can do the following transformations: + +- Demosaicing using bilinear interpolation + + #COLOR_BayerBG2BGR , #COLOR_BayerGB2BGR , #COLOR_BayerRG2BGR , #COLOR_BayerGR2BGR + + #COLOR_BayerBG2GRAY , #COLOR_BayerGB2GRAY , #COLOR_BayerRG2GRAY , #COLOR_BayerGR2GRAY + +- Demosaicing using Variable Number of Gradients. + + #COLOR_BayerBG2BGR_VNG , #COLOR_BayerGB2BGR_VNG , #COLOR_BayerRG2BGR_VNG , #COLOR_BayerGR2BGR_VNG + +- Edge-Aware Demosaicing. + + #COLOR_BayerBG2BGR_EA , #COLOR_BayerGB2BGR_EA , #COLOR_BayerRG2BGR_EA , #COLOR_BayerGR2BGR_EA + +- Demosaicing with alpha channel + + #COLOR_BayerBG2BGRA , #COLOR_BayerGB2BGRA , #COLOR_BayerRG2BGRA , #COLOR_BayerGR2BGRA + +@sa cvtColor +*/ +CV_EXPORTS_W void demosaicing(InputArray src, OutputArray dst, int code, int dstCn = 0); + +//! @} imgproc_color_conversions + +//! @addtogroup imgproc_shape +//! @{ + +/** @brief Calculates all of the moments up to the third order of a polygon or rasterized shape. + +The function computes moments, up to the 3rd order, of a vector shape or a rasterized shape. The +results are returned in the structure cv::Moments. + +@param array Raster image (single-channel, 8-bit or floating-point 2D array) or an array ( +\f$1 \times N\f$ or \f$N \times 1\f$ ) of 2D points (Point or Point2f ). +@param binaryImage If it is true, all non-zero image pixels are treated as 1's. The parameter is +used for images only. +@returns moments. + +@note Only applicable to contour moments calculations from Python bindings: Note that the numpy +type for the input array should be either np.int32 or np.float32. + +@sa contourArea, arcLength + */ +CV_EXPORTS_W Moments moments( InputArray array, bool binaryImage = false ); + +/** @brief Calculates seven Hu invariants. + +The function calculates seven Hu invariants (introduced in @cite Hu62; see also +) defined as: + +\f[\begin{array}{l} hu[0]= \eta _{20}+ \eta _{02} \\ hu[1]=( \eta _{20}- \eta _{02})^{2}+4 \eta _{11}^{2} \\ hu[2]=( \eta _{30}-3 \eta _{12})^{2}+ (3 \eta _{21}- \eta _{03})^{2} \\ hu[3]=( \eta _{30}+ \eta _{12})^{2}+ ( \eta _{21}+ \eta _{03})^{2} \\ hu[4]=( \eta _{30}-3 \eta _{12})( \eta _{30}+ \eta _{12})[( \eta _{30}+ \eta _{12})^{2}-3( \eta _{21}+ \eta _{03})^{2}]+(3 \eta _{21}- \eta _{03})( \eta _{21}+ \eta _{03})[3( \eta _{30}+ \eta _{12})^{2}-( \eta _{21}+ \eta _{03})^{2}] \\ hu[5]=( \eta _{20}- \eta _{02})[( \eta _{30}+ \eta _{12})^{2}- ( \eta _{21}+ \eta _{03})^{2}]+4 \eta _{11}( \eta _{30}+ \eta _{12})( \eta _{21}+ \eta _{03}) \\ hu[6]=(3 \eta _{21}- \eta _{03})( \eta _{21}+ \eta _{03})[3( \eta _{30}+ \eta _{12})^{2}-( \eta _{21}+ \eta _{03})^{2}]-( \eta _{30}-3 \eta _{12})( \eta _{21}+ \eta _{03})[3( \eta _{30}+ \eta _{12})^{2}-( \eta _{21}+ \eta _{03})^{2}] \\ \end{array}\f] + +where \f$\eta_{ji}\f$ stands for \f$\texttt{Moments::nu}_{ji}\f$ . + +These values are proved to be invariants to the image scale, rotation, and reflection except the +seventh one, whose sign is changed by reflection. This invariance is proved with the assumption of +infinite image resolution. In case of raster images, the computed Hu invariants for the original and +transformed images are a bit different. + +@param moments Input moments computed with moments . +@param hu Output Hu invariants. + +@sa matchShapes + */ +CV_EXPORTS void HuMoments( const Moments& moments, double hu[7] ); + +/** @overload */ +CV_EXPORTS_W void HuMoments( const Moments& m, OutputArray hu ); + +//! @} imgproc_shape + +//! @addtogroup imgproc_object +//! @{ + +//! type of the template matching operation +enum TemplateMatchModes { + TM_SQDIFF = 0, /*!< \f[R(x,y)= \sum _{x',y'} (T(x',y')-I(x+x',y+y'))^2\f] + with mask: + \f[R(x,y)= \sum _{x',y'} \left( (T(x',y')-I(x+x',y+y')) \cdot + M(x',y') \right)^2\f] */ + TM_SQDIFF_NORMED = 1, /*!< \f[R(x,y)= \frac{\sum_{x',y'} (T(x',y')-I(x+x',y+y'))^2}{\sqrt{\sum_{ + x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}}\f] + with mask: + \f[R(x,y)= \frac{\sum _{x',y'} \left( (T(x',y')-I(x+x',y+y')) \cdot + M(x',y') \right)^2}{\sqrt{\sum_{x',y'} \left( T(x',y') \cdot + M(x',y') \right)^2 \cdot \sum_{x',y'} \left( I(x+x',y+y') \cdot + M(x',y') \right)^2}}\f] */ + TM_CCORR = 2, /*!< \f[R(x,y)= \sum _{x',y'} (T(x',y') \cdot I(x+x',y+y'))\f] + with mask: + \f[R(x,y)= \sum _{x',y'} (T(x',y') \cdot I(x+x',y+y') \cdot M(x',y') + ^2)\f] */ + TM_CCORR_NORMED = 3, /*!< \f[R(x,y)= \frac{\sum_{x',y'} (T(x',y') \cdot I(x+x',y+y'))}{\sqrt{ + \sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}}\f] + with mask: + \f[R(x,y)= \frac{\sum_{x',y'} (T(x',y') \cdot I(x+x',y+y') \cdot + M(x',y')^2)}{\sqrt{\sum_{x',y'} \left( T(x',y') \cdot M(x',y') + \right)^2 \cdot \sum_{x',y'} \left( I(x+x',y+y') \cdot M(x',y') + \right)^2}}\f] */ + TM_CCOEFF = 4, /*!< \f[R(x,y)= \sum _{x',y'} (T'(x',y') \cdot I'(x+x',y+y'))\f] + where + \f[\begin{array}{l} T'(x',y')=T(x',y') - 1/(w \cdot h) \cdot \sum _{ + x'',y''} T(x'',y'') \\ I'(x+x',y+y')=I(x+x',y+y') - 1/(w \cdot h) + \cdot \sum _{x'',y''} I(x+x'',y+y'') \end{array}\f] + with mask: + \f[\begin{array}{l} T'(x',y')=M(x',y') \cdot \left( T(x',y') - + \frac{1}{\sum _{x'',y''} M(x'',y'')} \cdot \sum _{x'',y''} + (T(x'',y'') \cdot M(x'',y'')) \right) \\ I'(x+x',y+y')=M(x',y') + \cdot \left( I(x+x',y+y') - \frac{1}{\sum _{x'',y''} M(x'',y'')} + \cdot \sum _{x'',y''} (I(x+x'',y+y'') \cdot M(x'',y'')) \right) + \end{array} \f] */ + TM_CCOEFF_NORMED = 5 /*!< \f[R(x,y)= \frac{ \sum_{x',y'} (T'(x',y') \cdot I'(x+x',y+y')) }{ + \sqrt{\sum_{x',y'}T'(x',y')^2 \cdot \sum_{x',y'} I'(x+x',y+y')^2} + }\f] */ +}; + +/** @example samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp +An example using Template Matching algorithm +*/ + +/** @brief Compares a template against overlapped image regions. + +The function slides through image , compares the overlapped patches of size \f$w \times h\f$ against +templ using the specified method and stores the comparison results in result . #TemplateMatchModes +describes the formulae for the available comparison methods ( \f$I\f$ denotes image, \f$T\f$ +template, \f$R\f$ result, \f$M\f$ the optional mask ). The summation is done over template and/or +the image patch: \f$x' = 0...w-1, y' = 0...h-1\f$ + +After the function finishes the comparison, the best matches can be found as global minimums (when +#TM_SQDIFF was used) or maximums (when #TM_CCORR or #TM_CCOEFF was used) using the +#minMaxLoc function. In case of a color image, template summation in the numerator and each sum in +the denominator is done over all of the channels and separate mean values are used for each channel. +That is, the function can take a color template and a color image. The result will still be a +single-channel image, which is easier to analyze. + +@param image Image where the search is running. It must be 8-bit or 32-bit floating-point. +@param templ Searched template. It must be not greater than the source image and have the same +data type. +@param result Map of comparison results. It must be single-channel 32-bit floating-point. If image +is \f$W \times H\f$ and templ is \f$w \times h\f$ , then result is \f$(W-w+1) \times (H-h+1)\f$ . +@param method Parameter specifying the comparison method, see #TemplateMatchModes +@param mask Optional mask. It must have the same size as templ. It must either have the same number + of channels as template or only one channel, which is then used for all template and + image channels. If the data type is #CV_8U, the mask is interpreted as a binary mask, + meaning only elements where mask is nonzero are used and are kept unchanged independent + of the actual mask value (weight equals 1). For data tpye #CV_32F, the mask values are + used as weights. The exact formulas are documented in #TemplateMatchModes. + */ +CV_EXPORTS_W void matchTemplate( InputArray image, InputArray templ, + OutputArray result, int method, InputArray mask = noArray() ); + +//! @} + +//! @addtogroup imgproc_shape +//! @{ + +/** @example samples/cpp/connected_components.cpp +This program demonstrates connected components and use of the trackbar +*/ + +/** @brief computes the connected components labeled image of boolean image + +image with 4 or 8 way connectivity - returns N, the total number of labels [0, N-1] where 0 +represents the background label. ltype specifies the output label image type, an important +consideration based on the total number of labels or alternatively the total number of pixels in +the source image. ccltype specifies the connected components labeling algorithm to use, currently +Bolelli (Spaghetti) @cite Bolelli2019, Grana (BBDT) @cite Grana2010 and Wu's (SAUF) @cite Wu2009 algorithms +are supported, see the #ConnectedComponentsAlgorithmsTypes for details. Note that SAUF algorithm forces +a row major ordering of labels while Spaghetti and BBDT do not. +This function uses parallel version of the algorithms if at least one allowed +parallel framework is enabled and if the rows of the image are at least twice the number returned by #getNumberOfCPUs. + +@param image the 8-bit single-channel image to be labeled +@param labels destination labeled image +@param connectivity 8 or 4 for 8-way or 4-way connectivity respectively +@param ltype output image label type. Currently CV_32S and CV_16U are supported. +@param ccltype connected components algorithm type (see the #ConnectedComponentsAlgorithmsTypes). +*/ +CV_EXPORTS_AS(connectedComponentsWithAlgorithm) int connectedComponents(InputArray image, OutputArray labels, + int connectivity, int ltype, int ccltype); + + +/** @overload + +@param image the 8-bit single-channel image to be labeled +@param labels destination labeled image +@param connectivity 8 or 4 for 8-way or 4-way connectivity respectively +@param ltype output image label type. Currently CV_32S and CV_16U are supported. +*/ +CV_EXPORTS_W int connectedComponents(InputArray image, OutputArray labels, + int connectivity = 8, int ltype = CV_32S); + + +/** @brief computes the connected components labeled image of boolean image and also produces a statistics output for each label + +image with 4 or 8 way connectivity - returns N, the total number of labels [0, N-1] where 0 +represents the background label. ltype specifies the output label image type, an important +consideration based on the total number of labels or alternatively the total number of pixels in +the source image. ccltype specifies the connected components labeling algorithm to use, currently +Bolelli (Spaghetti) @cite Bolelli2019, Grana (BBDT) @cite Grana2010 and Wu's (SAUF) @cite Wu2009 algorithms +are supported, see the #ConnectedComponentsAlgorithmsTypes for details. Note that SAUF algorithm forces +a row major ordering of labels while Spaghetti and BBDT do not. +This function uses parallel version of the algorithms (statistics included) if at least one allowed +parallel framework is enabled and if the rows of the image are at least twice the number returned by #getNumberOfCPUs. + +@param image the 8-bit single-channel image to be labeled +@param labels destination labeled image +@param stats statistics output for each label, including the background label. +Statistics are accessed via stats(label, COLUMN) where COLUMN is one of +#ConnectedComponentsTypes, selecting the statistic. The data type is CV_32S. +@param centroids centroid output for each label, including the background label. Centroids are +accessed via centroids(label, 0) for x and centroids(label, 1) for y. The data type CV_64F. +@param connectivity 8 or 4 for 8-way or 4-way connectivity respectively +@param ltype output image label type. Currently CV_32S and CV_16U are supported. +@param ccltype connected components algorithm type (see #ConnectedComponentsAlgorithmsTypes). +*/ +CV_EXPORTS_AS(connectedComponentsWithStatsWithAlgorithm) int connectedComponentsWithStats(InputArray image, OutputArray labels, + OutputArray stats, OutputArray centroids, + int connectivity, int ltype, int ccltype); + +/** @overload +@param image the 8-bit single-channel image to be labeled +@param labels destination labeled image +@param stats statistics output for each label, including the background label. +Statistics are accessed via stats(label, COLUMN) where COLUMN is one of +#ConnectedComponentsTypes, selecting the statistic. The data type is CV_32S. +@param centroids centroid output for each label, including the background label. Centroids are +accessed via centroids(label, 0) for x and centroids(label, 1) for y. The data type CV_64F. +@param connectivity 8 or 4 for 8-way or 4-way connectivity respectively +@param ltype output image label type. Currently CV_32S and CV_16U are supported. +*/ +CV_EXPORTS_W int connectedComponentsWithStats(InputArray image, OutputArray labels, + OutputArray stats, OutputArray centroids, + int connectivity = 8, int ltype = CV_32S); + + +/** @brief Finds contours in a binary image. + +The function retrieves contours from the binary image using the algorithm @cite Suzuki85 . The contours +are a useful tool for shape analysis and object detection and recognition. See squares.cpp in the +OpenCV sample directory. +@note Since opencv 3.2 source image is not modified by this function. + +@param image Source, an 8-bit single-channel image. Non-zero pixels are treated as 1's. Zero +pixels remain 0's, so the image is treated as binary . You can use #compare, #inRange, #threshold , +#adaptiveThreshold, #Canny, and others to create a binary image out of a grayscale or color one. +If mode equals to #RETR_CCOMP or #RETR_FLOODFILL, the input can also be a 32-bit integer image of labels (CV_32SC1). +@param contours Detected contours. Each contour is stored as a vector of points (e.g. +std::vector >). +@param hierarchy Optional output vector (e.g. std::vector), containing information about the image topology. It has +as many elements as the number of contours. For each i-th contour contours[i], the elements +hierarchy[i][0] , hierarchy[i][1] , hierarchy[i][2] , and hierarchy[i][3] are set to 0-based indices +in contours of the next and previous contours at the same hierarchical level, the first child +contour and the parent contour, respectively. If for the contour i there are no next, previous, +parent, or nested contours, the corresponding elements of hierarchy[i] will be negative. +@note In Python, hierarchy is nested inside a top level array. Use hierarchy[0][i] to access hierarchical elements of i-th contour. +@param mode Contour retrieval mode, see #RetrievalModes +@param method Contour approximation method, see #ContourApproximationModes +@param offset Optional offset by which every contour point is shifted. This is useful if the +contours are extracted from the image ROI and then they should be analyzed in the whole image +context. + */ +CV_EXPORTS_W void findContours( InputArray image, OutputArrayOfArrays contours, + OutputArray hierarchy, int mode, + int method, Point offset = Point()); + +/** @overload */ +CV_EXPORTS void findContours( InputArray image, OutputArrayOfArrays contours, + int mode, int method, Point offset = Point()); + +/** @example samples/cpp/squares.cpp +A program using pyramid scaling, Canny, contours and contour simplification to find +squares in a list of images (pic1-6.png). Returns sequence of squares detected on the image. +*/ + +/** @example samples/tapi/squares.cpp +A program using pyramid scaling, Canny, contours and contour simplification to find +squares in the input image. +*/ + +/** @brief Approximates a polygonal curve(s) with the specified precision. + +The function cv::approxPolyDP approximates a curve or a polygon with another curve/polygon with less +vertices so that the distance between them is less or equal to the specified precision. It uses the +Douglas-Peucker algorithm + +@param curve Input vector of a 2D point stored in std::vector or Mat +@param approxCurve Result of the approximation. The type should match the type of the input curve. +@param epsilon Parameter specifying the approximation accuracy. This is the maximum distance +between the original curve and its approximation. +@param closed If true, the approximated curve is closed (its first and last vertices are +connected). Otherwise, it is not closed. + */ +CV_EXPORTS_W void approxPolyDP( InputArray curve, + OutputArray approxCurve, + double epsilon, bool closed ); + +/** @brief Calculates a contour perimeter or a curve length. + +The function computes a curve length or a closed contour perimeter. + +@param curve Input vector of 2D points, stored in std::vector or Mat. +@param closed Flag indicating whether the curve is closed or not. + */ +CV_EXPORTS_W double arcLength( InputArray curve, bool closed ); + +/** @brief Calculates the up-right bounding rectangle of a point set or non-zero pixels of gray-scale image. + +The function calculates and returns the minimal up-right bounding rectangle for the specified point set or +non-zero pixels of gray-scale image. + +@param array Input gray-scale image or 2D point set, stored in std::vector or Mat. + */ +CV_EXPORTS_W Rect boundingRect( InputArray array ); + +/** @brief Calculates a contour area. + +The function computes a contour area. Similarly to moments , the area is computed using the Green +formula. Thus, the returned area and the number of non-zero pixels, if you draw the contour using +#drawContours or #fillPoly , can be different. Also, the function will most certainly give a wrong +results for contours with self-intersections. + +Example: +@code + vector contour; + contour.push_back(Point2f(0, 0)); + contour.push_back(Point2f(10, 0)); + contour.push_back(Point2f(10, 10)); + contour.push_back(Point2f(5, 4)); + + double area0 = contourArea(contour); + vector approx; + approxPolyDP(contour, approx, 5, true); + double area1 = contourArea(approx); + + cout << "area0 =" << area0 << endl << + "area1 =" << area1 << endl << + "approx poly vertices" << approx.size() << endl; +@endcode +@param contour Input vector of 2D points (contour vertices), stored in std::vector or Mat. +@param oriented Oriented area flag. If it is true, the function returns a signed area value, +depending on the contour orientation (clockwise or counter-clockwise). Using this feature you can +determine orientation of a contour by taking the sign of an area. By default, the parameter is +false, which means that the absolute value is returned. + */ +CV_EXPORTS_W double contourArea( InputArray contour, bool oriented = false ); + +/** @brief Finds a rotated rectangle of the minimum area enclosing the input 2D point set. + +The function calculates and returns the minimum-area bounding rectangle (possibly rotated) for a +specified point set. Developer should keep in mind that the returned RotatedRect can contain negative +indices when data is close to the containing Mat element boundary. + +@param points Input vector of 2D points, stored in std::vector\<\> or Mat + */ +CV_EXPORTS_W RotatedRect minAreaRect( InputArray points ); + +/** @brief Finds the four vertices of a rotated rect. Useful to draw the rotated rectangle. + +The function finds the four vertices of a rotated rectangle. This function is useful to draw the +rectangle. In C++, instead of using this function, you can directly use RotatedRect::points method. Please +visit the @ref tutorial_bounding_rotated_ellipses "tutorial on Creating Bounding rotated boxes and ellipses for contours" for more information. + +@param box The input rotated rectangle. It may be the output of +@param points The output array of four vertices of rectangles. + */ +CV_EXPORTS_W void boxPoints(RotatedRect box, OutputArray points); + +/** @brief Finds a circle of the minimum area enclosing a 2D point set. + +The function finds the minimal enclosing circle of a 2D point set using an iterative algorithm. + +@param points Input vector of 2D points, stored in std::vector\<\> or Mat +@param center Output center of the circle. +@param radius Output radius of the circle. + */ +CV_EXPORTS_W void minEnclosingCircle( InputArray points, + CV_OUT Point2f& center, CV_OUT float& radius ); + +/** @example samples/cpp/minarea.cpp +*/ + +/** @brief Finds a triangle of minimum area enclosing a 2D point set and returns its area. + +The function finds a triangle of minimum area enclosing the given set of 2D points and returns its +area. The output for a given 2D point set is shown in the image below. 2D points are depicted in +*red* and the enclosing triangle in *yellow*. + +![Sample output of the minimum enclosing triangle function](pics/minenclosingtriangle.png) + +The implementation of the algorithm is based on O'Rourke's @cite ORourke86 and Klee and Laskowski's +@cite KleeLaskowski85 papers. O'Rourke provides a \f$\theta(n)\f$ algorithm for finding the minimal +enclosing triangle of a 2D convex polygon with n vertices. Since the #minEnclosingTriangle function +takes a 2D point set as input an additional preprocessing step of computing the convex hull of the +2D point set is required. The complexity of the #convexHull function is \f$O(n log(n))\f$ which is higher +than \f$\theta(n)\f$. Thus the overall complexity of the function is \f$O(n log(n))\f$. + +@param points Input vector of 2D points with depth CV_32S or CV_32F, stored in std::vector\<\> or Mat +@param triangle Output vector of three 2D points defining the vertices of the triangle. The depth +of the OutputArray must be CV_32F. + */ +CV_EXPORTS_W double minEnclosingTriangle( InputArray points, CV_OUT OutputArray triangle ); + +/** @brief Compares two shapes. + +The function compares two shapes. All three implemented methods use the Hu invariants (see #HuMoments) + +@param contour1 First contour or grayscale image. +@param contour2 Second contour or grayscale image. +@param method Comparison method, see #ShapeMatchModes +@param parameter Method-specific parameter (not supported now). + */ +CV_EXPORTS_W double matchShapes( InputArray contour1, InputArray contour2, + int method, double parameter ); + +/** @example samples/cpp/convexhull.cpp +An example using the convexHull functionality +*/ + +/** @brief Finds the convex hull of a point set. + +The function cv::convexHull finds the convex hull of a 2D point set using the Sklansky's algorithm @cite Sklansky82 +that has *O(N logN)* complexity in the current implementation. + +@param points Input 2D point set, stored in std::vector or Mat. +@param hull Output convex hull. It is either an integer vector of indices or vector of points. In +the first case, the hull elements are 0-based indices of the convex hull points in the original +array (since the set of convex hull points is a subset of the original point set). In the second +case, hull elements are the convex hull points themselves. +@param clockwise Orientation flag. If it is true, the output convex hull is oriented clockwise. +Otherwise, it is oriented counter-clockwise. The assumed coordinate system has its X axis pointing +to the right, and its Y axis pointing upwards. +@param returnPoints Operation flag. In case of a matrix, when the flag is true, the function +returns convex hull points. Otherwise, it returns indices of the convex hull points. When the +output array is std::vector, the flag is ignored, and the output depends on the type of the +vector: std::vector\ implies returnPoints=false, std::vector\ implies +returnPoints=true. + +@note `points` and `hull` should be different arrays, inplace processing isn't supported. + +Check @ref tutorial_hull "the corresponding tutorial" for more details. + +useful links: + +https://www.learnopencv.com/convex-hull-using-opencv-in-python-and-c/ + */ +CV_EXPORTS_W void convexHull( InputArray points, OutputArray hull, + bool clockwise = false, bool returnPoints = true ); + +/** @brief Finds the convexity defects of a contour. + +The figure below displays convexity defects of a hand contour: + +![image](pics/defects.png) + +@param contour Input contour. +@param convexhull Convex hull obtained using convexHull that should contain indices of the contour +points that make the hull. +@param convexityDefects The output vector of convexity defects. In C++ and the new Python/Java +interface each convexity defect is represented as 4-element integer vector (a.k.a. #Vec4i): +(start_index, end_index, farthest_pt_index, fixpt_depth), where indices are 0-based indices +in the original contour of the convexity defect beginning, end and the farthest point, and +fixpt_depth is fixed-point approximation (with 8 fractional bits) of the distance between the +farthest contour point and the hull. That is, to get the floating-point value of the depth will be +fixpt_depth/256.0. + */ +CV_EXPORTS_W void convexityDefects( InputArray contour, InputArray convexhull, OutputArray convexityDefects ); + +/** @brief Tests a contour convexity. + +The function tests whether the input contour is convex or not. The contour must be simple, that is, +without self-intersections. Otherwise, the function output is undefined. + +@param contour Input vector of 2D points, stored in std::vector\<\> or Mat + */ +CV_EXPORTS_W bool isContourConvex( InputArray contour ); + +/** @example samples/cpp/intersectExample.cpp +Examples of how intersectConvexConvex works +*/ + +/** @brief Finds intersection of two convex polygons + +@param p1 First polygon +@param p2 Second polygon +@param p12 Output polygon describing the intersecting area +@param handleNested When true, an intersection is found if one of the polygons is fully enclosed in the other. +When false, no intersection is found. If the polygons share a side or the vertex of one polygon lies on an edge +of the other, they are not considered nested and an intersection will be found regardless of the value of handleNested. + +@returns Absolute value of area of intersecting polygon + +@note intersectConvexConvex doesn't confirm that both polygons are convex and will return invalid results if they aren't. + */ +CV_EXPORTS_W float intersectConvexConvex( InputArray p1, InputArray p2, + OutputArray p12, bool handleNested = true ); + +/** @example samples/cpp/fitellipse.cpp +An example using the fitEllipse technique +*/ + +/** @brief Fits an ellipse around a set of 2D points. + +The function calculates the ellipse that fits (in a least-squares sense) a set of 2D points best of +all. It returns the rotated rectangle in which the ellipse is inscribed. The first algorithm described by @cite Fitzgibbon95 +is used. Developer should keep in mind that it is possible that the returned +ellipse/rotatedRect data contains negative indices, due to the data points being close to the +border of the containing Mat element. + +@param points Input 2D point set, stored in std::vector\<\> or Mat + */ +CV_EXPORTS_W RotatedRect fitEllipse( InputArray points ); + +/** @brief Fits an ellipse around a set of 2D points. + + The function calculates the ellipse that fits a set of 2D points. + It returns the rotated rectangle in which the ellipse is inscribed. + The Approximate Mean Square (AMS) proposed by @cite Taubin1991 is used. + + For an ellipse, this basis set is \f$ \chi= \left(x^2, x y, y^2, x, y, 1\right) \f$, + which is a set of six free coefficients \f$ A^T=\left\{A_{\text{xx}},A_{\text{xy}},A_{\text{yy}},A_x,A_y,A_0\right\} \f$. + However, to specify an ellipse, all that is needed is five numbers; the major and minor axes lengths \f$ (a,b) \f$, + the position \f$ (x_0,y_0) \f$, and the orientation \f$ \theta \f$. This is because the basis set includes lines, + quadratics, parabolic and hyperbolic functions as well as elliptical functions as possible fits. + If the fit is found to be a parabolic or hyperbolic function then the standard #fitEllipse method is used. + The AMS method restricts the fit to parabolic, hyperbolic and elliptical curves + by imposing the condition that \f$ A^T ( D_x^T D_x + D_y^T D_y) A = 1 \f$ where + the matrices \f$ Dx \f$ and \f$ Dy \f$ are the partial derivatives of the design matrix \f$ D \f$ with + respect to x and y. The matrices are formed row by row applying the following to + each of the points in the set: + \f{align*}{ + D(i,:)&=\left\{x_i^2, x_i y_i, y_i^2, x_i, y_i, 1\right\} & + D_x(i,:)&=\left\{2 x_i,y_i,0,1,0,0\right\} & + D_y(i,:)&=\left\{0,x_i,2 y_i,0,1,0\right\} + \f} + The AMS method minimizes the cost function + \f{equation*}{ + \epsilon ^2=\frac{ A^T D^T D A }{ A^T (D_x^T D_x + D_y^T D_y) A^T } + \f} + + The minimum cost is found by solving the generalized eigenvalue problem. + + \f{equation*}{ + D^T D A = \lambda \left( D_x^T D_x + D_y^T D_y\right) A + \f} + + @param points Input 2D point set, stored in std::vector\<\> or Mat + */ +CV_EXPORTS_W RotatedRect fitEllipseAMS( InputArray points ); + + +/** @brief Fits an ellipse around a set of 2D points. + + The function calculates the ellipse that fits a set of 2D points. + It returns the rotated rectangle in which the ellipse is inscribed. + The Direct least square (Direct) method by @cite Fitzgibbon1999 is used. + + For an ellipse, this basis set is \f$ \chi= \left(x^2, x y, y^2, x, y, 1\right) \f$, + which is a set of six free coefficients \f$ A^T=\left\{A_{\text{xx}},A_{\text{xy}},A_{\text{yy}},A_x,A_y,A_0\right\} \f$. + However, to specify an ellipse, all that is needed is five numbers; the major and minor axes lengths \f$ (a,b) \f$, + the position \f$ (x_0,y_0) \f$, and the orientation \f$ \theta \f$. This is because the basis set includes lines, + quadratics, parabolic and hyperbolic functions as well as elliptical functions as possible fits. + The Direct method confines the fit to ellipses by ensuring that \f$ 4 A_{xx} A_{yy}- A_{xy}^2 > 0 \f$. + The condition imposed is that \f$ 4 A_{xx} A_{yy}- A_{xy}^2=1 \f$ which satisfies the inequality + and as the coefficients can be arbitrarily scaled is not overly restrictive. + + \f{equation*}{ + \epsilon ^2= A^T D^T D A \quad \text{with} \quad A^T C A =1 \quad \text{and} \quad C=\left(\begin{matrix} + 0 & 0 & 2 & 0 & 0 & 0 \\ + 0 & -1 & 0 & 0 & 0 & 0 \\ + 2 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 0 + \end{matrix} \right) + \f} + + The minimum cost is found by solving the generalized eigenvalue problem. + + \f{equation*}{ + D^T D A = \lambda \left( C\right) A + \f} + + The system produces only one positive eigenvalue \f$ \lambda\f$ which is chosen as the solution + with its eigenvector \f$\mathbf{u}\f$. These are used to find the coefficients + + \f{equation*}{ + A = \sqrt{\frac{1}{\mathbf{u}^T C \mathbf{u}}} \mathbf{u} + \f} + The scaling factor guarantees that \f$A^T C A =1\f$. + + @param points Input 2D point set, stored in std::vector\<\> or Mat + */ +CV_EXPORTS_W RotatedRect fitEllipseDirect( InputArray points ); + +/** @brief Fits a line to a 2D or 3D point set. + +The function fitLine fits a line to a 2D or 3D point set by minimizing \f$\sum_i \rho(r_i)\f$ where +\f$r_i\f$ is a distance between the \f$i^{th}\f$ point, the line and \f$\rho(r)\f$ is a distance function, one +of the following: +- DIST_L2 +\f[\rho (r) = r^2/2 \quad \text{(the simplest and the fastest least-squares method)}\f] +- DIST_L1 +\f[\rho (r) = r\f] +- DIST_L12 +\f[\rho (r) = 2 \cdot ( \sqrt{1 + \frac{r^2}{2}} - 1)\f] +- DIST_FAIR +\f[\rho \left (r \right ) = C^2 \cdot \left ( \frac{r}{C} - \log{\left(1 + \frac{r}{C}\right)} \right ) \quad \text{where} \quad C=1.3998\f] +- DIST_WELSCH +\f[\rho \left (r \right ) = \frac{C^2}{2} \cdot \left ( 1 - \exp{\left(-\left(\frac{r}{C}\right)^2\right)} \right ) \quad \text{where} \quad C=2.9846\f] +- DIST_HUBER +\f[\rho (r) = \fork{r^2/2}{if \(r < C\)}{C \cdot (r-C/2)}{otherwise} \quad \text{where} \quad C=1.345\f] + +The algorithm is based on the M-estimator ( ) technique +that iteratively fits the line using the weighted least-squares algorithm. After each iteration the +weights \f$w_i\f$ are adjusted to be inversely proportional to \f$\rho(r_i)\f$ . + +@param points Input vector of 2D or 3D points, stored in std::vector\<\> or Mat. +@param line Output line parameters. In case of 2D fitting, it should be a vector of 4 elements +(like Vec4f) - (vx, vy, x0, y0), where (vx, vy) is a normalized vector collinear to the line and +(x0, y0) is a point on the line. In case of 3D fitting, it should be a vector of 6 elements (like +Vec6f) - (vx, vy, vz, x0, y0, z0), where (vx, vy, vz) is a normalized vector collinear to the line +and (x0, y0, z0) is a point on the line. +@param distType Distance used by the M-estimator, see #DistanceTypes +@param param Numerical parameter ( C ) for some types of distances. If it is 0, an optimal value +is chosen. +@param reps Sufficient accuracy for the radius (distance between the coordinate origin and the line). +@param aeps Sufficient accuracy for the angle. 0.01 would be a good default value for reps and aeps. + */ +CV_EXPORTS_W void fitLine( InputArray points, OutputArray line, int distType, + double param, double reps, double aeps ); + +/** @brief Performs a point-in-contour test. + +The function determines whether the point is inside a contour, outside, or lies on an edge (or +coincides with a vertex). It returns positive (inside), negative (outside), or zero (on an edge) +value, correspondingly. When measureDist=false , the return value is +1, -1, and 0, respectively. +Otherwise, the return value is a signed distance between the point and the nearest contour edge. + +See below a sample output of the function where each image pixel is tested against the contour: + +![sample output](pics/pointpolygon.png) + +@param contour Input contour. +@param pt Point tested against the contour. +@param measureDist If true, the function estimates the signed distance from the point to the +nearest contour edge. Otherwise, the function only checks if the point is inside a contour or not. + */ +CV_EXPORTS_W double pointPolygonTest( InputArray contour, Point2f pt, bool measureDist ); + +/** @brief Finds out if there is any intersection between two rotated rectangles. + +If there is then the vertices of the intersecting region are returned as well. + +Below are some examples of intersection configurations. The hatched pattern indicates the +intersecting region and the red vertices are returned by the function. + +![intersection examples](pics/intersection.png) + +@param rect1 First rectangle +@param rect2 Second rectangle +@param intersectingRegion The output array of the vertices of the intersecting region. It returns +at most 8 vertices. Stored as std::vector\ or cv::Mat as Mx1 of type CV_32FC2. +@returns One of #RectanglesIntersectTypes + */ +CV_EXPORTS_W int rotatedRectangleIntersection( const RotatedRect& rect1, const RotatedRect& rect2, OutputArray intersectingRegion ); + +/** @brief Creates a smart pointer to a cv::GeneralizedHoughBallard class and initializes it. +*/ +CV_EXPORTS_W Ptr createGeneralizedHoughBallard(); + +/** @brief Creates a smart pointer to a cv::GeneralizedHoughGuil class and initializes it. +*/ +CV_EXPORTS_W Ptr createGeneralizedHoughGuil(); + +//! @} imgproc_shape + +//! @addtogroup imgproc_colormap +//! @{ + +//! GNU Octave/MATLAB equivalent colormaps +enum ColormapTypes +{ + COLORMAP_AUTUMN = 0, //!< ![autumn](pics/colormaps/colorscale_autumn.jpg) + COLORMAP_BONE = 1, //!< ![bone](pics/colormaps/colorscale_bone.jpg) + COLORMAP_JET = 2, //!< ![jet](pics/colormaps/colorscale_jet.jpg) + COLORMAP_WINTER = 3, //!< ![winter](pics/colormaps/colorscale_winter.jpg) + COLORMAP_RAINBOW = 4, //!< ![rainbow](pics/colormaps/colorscale_rainbow.jpg) + COLORMAP_OCEAN = 5, //!< ![ocean](pics/colormaps/colorscale_ocean.jpg) + COLORMAP_SUMMER = 6, //!< ![summer](pics/colormaps/colorscale_summer.jpg) + COLORMAP_SPRING = 7, //!< ![spring](pics/colormaps/colorscale_spring.jpg) + COLORMAP_COOL = 8, //!< ![cool](pics/colormaps/colorscale_cool.jpg) + COLORMAP_HSV = 9, //!< ![HSV](pics/colormaps/colorscale_hsv.jpg) + COLORMAP_PINK = 10, //!< ![pink](pics/colormaps/colorscale_pink.jpg) + COLORMAP_HOT = 11, //!< ![hot](pics/colormaps/colorscale_hot.jpg) + COLORMAP_PARULA = 12, //!< ![parula](pics/colormaps/colorscale_parula.jpg) + COLORMAP_MAGMA = 13, //!< ![magma](pics/colormaps/colorscale_magma.jpg) + COLORMAP_INFERNO = 14, //!< ![inferno](pics/colormaps/colorscale_inferno.jpg) + COLORMAP_PLASMA = 15, //!< ![plasma](pics/colormaps/colorscale_plasma.jpg) + COLORMAP_VIRIDIS = 16, //!< ![viridis](pics/colormaps/colorscale_viridis.jpg) + COLORMAP_CIVIDIS = 17, //!< ![cividis](pics/colormaps/colorscale_cividis.jpg) + COLORMAP_TWILIGHT = 18, //!< ![twilight](pics/colormaps/colorscale_twilight.jpg) + COLORMAP_TWILIGHT_SHIFTED = 19, //!< ![twilight shifted](pics/colormaps/colorscale_twilight_shifted.jpg) + COLORMAP_TURBO = 20, //!< ![turbo](pics/colormaps/colorscale_turbo.jpg) + COLORMAP_DEEPGREEN = 21 //!< ![deepgreen](pics/colormaps/colorscale_deepgreen.jpg) +}; + +/** @example samples/cpp/falsecolor.cpp +An example using applyColorMap function +*/ + +/** @brief Applies a GNU Octave/MATLAB equivalent colormap on a given image. + +@param src The source image, grayscale or colored of type CV_8UC1 or CV_8UC3. +@param dst The result is the colormapped source image. Note: Mat::create is called on dst. +@param colormap The colormap to apply, see #ColormapTypes +*/ +CV_EXPORTS_W void applyColorMap(InputArray src, OutputArray dst, int colormap); + +/** @brief Applies a user colormap on a given image. + +@param src The source image, grayscale or colored of type CV_8UC1 or CV_8UC3. +@param dst The result is the colormapped source image. Note: Mat::create is called on dst. +@param userColor The colormap to apply of type CV_8UC1 or CV_8UC3 and size 256 +*/ +CV_EXPORTS_W void applyColorMap(InputArray src, OutputArray dst, InputArray userColor); + +//! @} imgproc_colormap + +//! @addtogroup imgproc_draw +//! @{ + + +/** OpenCV color channel order is BGR[A] */ +#define CV_RGB(r, g, b) cv::Scalar((b), (g), (r), 0) + +/** @brief Draws a line segment connecting two points. + +The function line draws the line segment between pt1 and pt2 points in the image. The line is +clipped by the image boundaries. For non-antialiased lines with integer coordinates, the 8-connected +or 4-connected Bresenham algorithm is used. Thick lines are drawn with rounding endings. Antialiased +lines are drawn using Gaussian filtering. + +@param img Image. +@param pt1 First point of the line segment. +@param pt2 Second point of the line segment. +@param color Line color. +@param thickness Line thickness. +@param lineType Type of the line. See #LineTypes. +@param shift Number of fractional bits in the point coordinates. + */ +CV_EXPORTS_W void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, + int thickness = 1, int lineType = LINE_8, int shift = 0); + +/** @brief Draws an arrow segment pointing from the first point to the second one. + +The function cv::arrowedLine draws an arrow between pt1 and pt2 points in the image. See also #line. + +@param img Image. +@param pt1 The point the arrow starts from. +@param pt2 The point the arrow points to. +@param color Line color. +@param thickness Line thickness. +@param line_type Type of the line. See #LineTypes +@param shift Number of fractional bits in the point coordinates. +@param tipLength The length of the arrow tip in relation to the arrow length + */ +CV_EXPORTS_W void arrowedLine(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, + int thickness=1, int line_type=8, int shift=0, double tipLength=0.1); + +/** @brief Draws a simple, thick, or filled up-right rectangle. + +The function cv::rectangle draws a rectangle outline or a filled rectangle whose two opposite corners +are pt1 and pt2. + +@param img Image. +@param pt1 Vertex of the rectangle. +@param pt2 Vertex of the rectangle opposite to pt1 . +@param color Rectangle color or brightness (grayscale image). +@param thickness Thickness of lines that make up the rectangle. Negative values, like #FILLED, +mean that the function has to draw a filled rectangle. +@param lineType Type of the line. See #LineTypes +@param shift Number of fractional bits in the point coordinates. + */ +CV_EXPORTS_W void rectangle(InputOutputArray img, Point pt1, Point pt2, + const Scalar& color, int thickness = 1, + int lineType = LINE_8, int shift = 0); + +/** @overload + +use `rec` parameter as alternative specification of the drawn rectangle: `r.tl() and +r.br()-Point(1,1)` are opposite corners +*/ +CV_EXPORTS_W void rectangle(InputOutputArray img, Rect rec, + const Scalar& color, int thickness = 1, + int lineType = LINE_8, int shift = 0); + +/** @example samples/cpp/tutorial_code/ImgProc/basic_drawing/Drawing_2.cpp +An example using drawing functions +*/ + +/** @brief Draws a circle. + +The function cv::circle draws a simple or filled circle with a given center and radius. +@param img Image where the circle is drawn. +@param center Center of the circle. +@param radius Radius of the circle. +@param color Circle color. +@param thickness Thickness of the circle outline, if positive. Negative values, like #FILLED, +mean that a filled circle is to be drawn. +@param lineType Type of the circle boundary. See #LineTypes +@param shift Number of fractional bits in the coordinates of the center and in the radius value. + */ +CV_EXPORTS_W void circle(InputOutputArray img, Point center, int radius, + const Scalar& color, int thickness = 1, + int lineType = LINE_8, int shift = 0); + +/** @brief Draws a simple or thick elliptic arc or fills an ellipse sector. + +The function cv::ellipse with more parameters draws an ellipse outline, a filled ellipse, an elliptic +arc, or a filled ellipse sector. The drawing code uses general parametric form. +A piecewise-linear curve is used to approximate the elliptic arc +boundary. If you need more control of the ellipse rendering, you can retrieve the curve using +#ellipse2Poly and then render it with #polylines or fill it with #fillPoly. If you use the first +variant of the function and want to draw the whole ellipse, not an arc, pass `startAngle=0` and +`endAngle=360`. If `startAngle` is greater than `endAngle`, they are swapped. The figure below explains +the meaning of the parameters to draw the blue arc. + +![Parameters of Elliptic Arc](pics/ellipse.svg) + +@param img Image. +@param center Center of the ellipse. +@param axes Half of the size of the ellipse main axes. +@param angle Ellipse rotation angle in degrees. +@param startAngle Starting angle of the elliptic arc in degrees. +@param endAngle Ending angle of the elliptic arc in degrees. +@param color Ellipse color. +@param thickness Thickness of the ellipse arc outline, if positive. Otherwise, this indicates that +a filled ellipse sector is to be drawn. +@param lineType Type of the ellipse boundary. See #LineTypes +@param shift Number of fractional bits in the coordinates of the center and values of axes. + */ +CV_EXPORTS_W void ellipse(InputOutputArray img, Point center, Size axes, + double angle, double startAngle, double endAngle, + const Scalar& color, int thickness = 1, + int lineType = LINE_8, int shift = 0); + +/** @overload +@param img Image. +@param box Alternative ellipse representation via RotatedRect. This means that the function draws +an ellipse inscribed in the rotated rectangle. +@param color Ellipse color. +@param thickness Thickness of the ellipse arc outline, if positive. Otherwise, this indicates that +a filled ellipse sector is to be drawn. +@param lineType Type of the ellipse boundary. See #LineTypes +*/ +CV_EXPORTS_W void ellipse(InputOutputArray img, const RotatedRect& box, const Scalar& color, + int thickness = 1, int lineType = LINE_8); + +/* ----------------------------------------------------------------------------------------- */ +/* ADDING A SET OF PREDEFINED MARKERS WHICH COULD BE USED TO HIGHLIGHT POSITIONS IN AN IMAGE */ +/* ----------------------------------------------------------------------------------------- */ + +/** @brief Draws a marker on a predefined position in an image. + +The function cv::drawMarker draws a marker on a given position in the image. For the moment several +marker types are supported, see #MarkerTypes for more information. + +@param img Image. +@param position The point where the crosshair is positioned. +@param color Line color. +@param markerType The specific type of marker you want to use, see #MarkerTypes +@param thickness Line thickness. +@param line_type Type of the line, See #LineTypes +@param markerSize The length of the marker axis [default = 20 pixels] + */ +CV_EXPORTS_W void drawMarker(InputOutputArray img, Point position, const Scalar& color, + int markerType = MARKER_CROSS, int markerSize=20, int thickness=1, + int line_type=8); + +/* ----------------------------------------------------------------------------------------- */ +/* END OF MARKER SECTION */ +/* ----------------------------------------------------------------------------------------- */ + +/** @brief Fills a convex polygon. + +The function cv::fillConvexPoly draws a filled convex polygon. This function is much faster than the +function #fillPoly . It can fill not only convex polygons but any monotonic polygon without +self-intersections, that is, a polygon whose contour intersects every horizontal line (scan line) +twice at the most (though, its top-most and/or the bottom edge could be horizontal). + +@param img Image. +@param points Polygon vertices. +@param color Polygon color. +@param lineType Type of the polygon boundaries. See #LineTypes +@param shift Number of fractional bits in the vertex coordinates. + */ +CV_EXPORTS_W void fillConvexPoly(InputOutputArray img, InputArray points, + const Scalar& color, int lineType = LINE_8, + int shift = 0); + +/** @overload */ +CV_EXPORTS void fillConvexPoly(InputOutputArray img, const Point* pts, int npts, + const Scalar& color, int lineType = LINE_8, + int shift = 0); + +/** @example samples/cpp/tutorial_code/ImgProc/basic_drawing/Drawing_1.cpp +An example using drawing functions +Check @ref tutorial_random_generator_and_text "the corresponding tutorial" for more details +*/ + +/** @brief Fills the area bounded by one or more polygons. + +The function cv::fillPoly fills an area bounded by several polygonal contours. The function can fill +complex areas, for example, areas with holes, contours with self-intersections (some of their +parts), and so forth. + +@param img Image. +@param pts Array of polygons where each polygon is represented as an array of points. +@param color Polygon color. +@param lineType Type of the polygon boundaries. See #LineTypes +@param shift Number of fractional bits in the vertex coordinates. +@param offset Optional offset of all points of the contours. + */ +CV_EXPORTS_W void fillPoly(InputOutputArray img, InputArrayOfArrays pts, + const Scalar& color, int lineType = LINE_8, int shift = 0, + Point offset = Point() ); + +/** @overload */ +CV_EXPORTS void fillPoly(InputOutputArray img, const Point** pts, + const int* npts, int ncontours, + const Scalar& color, int lineType = LINE_8, int shift = 0, + Point offset = Point() ); + +/** @brief Draws several polygonal curves. + +@param img Image. +@param pts Array of polygonal curves. +@param isClosed Flag indicating whether the drawn polylines are closed or not. If they are closed, +the function draws a line from the last vertex of each curve to its first vertex. +@param color Polyline color. +@param thickness Thickness of the polyline edges. +@param lineType Type of the line segments. See #LineTypes +@param shift Number of fractional bits in the vertex coordinates. + +The function cv::polylines draws one or more polygonal curves. + */ +CV_EXPORTS_W void polylines(InputOutputArray img, InputArrayOfArrays pts, + bool isClosed, const Scalar& color, + int thickness = 1, int lineType = LINE_8, int shift = 0 ); + +/** @overload */ +CV_EXPORTS void polylines(InputOutputArray img, const Point* const* pts, const int* npts, + int ncontours, bool isClosed, const Scalar& color, + int thickness = 1, int lineType = LINE_8, int shift = 0 ); + +/** @example samples/cpp/contours2.cpp +An example program illustrates the use of cv::findContours and cv::drawContours +\image html WindowsQtContoursOutput.png "Screenshot of the program" +*/ + +/** @example samples/cpp/segment_objects.cpp +An example using drawContours to clean up a background segmentation result +*/ + +/** @brief Draws contours outlines or filled contours. + +The function draws contour outlines in the image if \f$\texttt{thickness} \ge 0\f$ or fills the area +bounded by the contours if \f$\texttt{thickness}<0\f$ . The example below shows how to retrieve +connected components from the binary image and label them: : +@include snippets/imgproc_drawContours.cpp + +@param image Destination image. +@param contours All the input contours. Each contour is stored as a point vector. +@param contourIdx Parameter indicating a contour to draw. If it is negative, all the contours are drawn. +@param color Color of the contours. +@param thickness Thickness of lines the contours are drawn with. If it is negative (for example, +thickness=#FILLED ), the contour interiors are drawn. +@param lineType Line connectivity. See #LineTypes +@param hierarchy Optional information about hierarchy. It is only needed if you want to draw only +some of the contours (see maxLevel ). +@param maxLevel Maximal level for drawn contours. If it is 0, only the specified contour is drawn. +If it is 1, the function draws the contour(s) and all the nested contours. If it is 2, the function +draws the contours, all the nested contours, all the nested-to-nested contours, and so on. This +parameter is only taken into account when there is hierarchy available. +@param offset Optional contour shift parameter. Shift all the drawn contours by the specified +\f$\texttt{offset}=(dx,dy)\f$ . +@note When thickness=#FILLED, the function is designed to handle connected components with holes correctly +even when no hierarchy data is provided. This is done by analyzing all the outlines together +using even-odd rule. This may give incorrect results if you have a joint collection of separately retrieved +contours. In order to solve this problem, you need to call #drawContours separately for each sub-group +of contours, or iterate over the collection using contourIdx parameter. + */ +CV_EXPORTS_W void drawContours( InputOutputArray image, InputArrayOfArrays contours, + int contourIdx, const Scalar& color, + int thickness = 1, int lineType = LINE_8, + InputArray hierarchy = noArray(), + int maxLevel = INT_MAX, Point offset = Point() ); + +/** @brief Clips the line against the image rectangle. + +The function cv::clipLine calculates a part of the line segment that is entirely within the specified +rectangle. It returns false if the line segment is completely outside the rectangle. Otherwise, +it returns true . +@param imgSize Image size. The image rectangle is Rect(0, 0, imgSize.width, imgSize.height) . +@param pt1 First line point. +@param pt2 Second line point. + */ +CV_EXPORTS bool clipLine(Size imgSize, CV_IN_OUT Point& pt1, CV_IN_OUT Point& pt2); + +/** @overload +@param imgSize Image size. The image rectangle is Rect(0, 0, imgSize.width, imgSize.height) . +@param pt1 First line point. +@param pt2 Second line point. +*/ +CV_EXPORTS bool clipLine(Size2l imgSize, CV_IN_OUT Point2l& pt1, CV_IN_OUT Point2l& pt2); + +/** @overload +@param imgRect Image rectangle. +@param pt1 First line point. +@param pt2 Second line point. +*/ +CV_EXPORTS_W bool clipLine(Rect imgRect, CV_OUT CV_IN_OUT Point& pt1, CV_OUT CV_IN_OUT Point& pt2); + +/** @brief Approximates an elliptic arc with a polyline. + +The function ellipse2Poly computes the vertices of a polyline that approximates the specified +elliptic arc. It is used by #ellipse. If `arcStart` is greater than `arcEnd`, they are swapped. + +@param center Center of the arc. +@param axes Half of the size of the ellipse main axes. See #ellipse for details. +@param angle Rotation angle of the ellipse in degrees. See #ellipse for details. +@param arcStart Starting angle of the elliptic arc in degrees. +@param arcEnd Ending angle of the elliptic arc in degrees. +@param delta Angle between the subsequent polyline vertices. It defines the approximation +accuracy. +@param pts Output vector of polyline vertices. + */ +CV_EXPORTS_W void ellipse2Poly( Point center, Size axes, int angle, + int arcStart, int arcEnd, int delta, + CV_OUT std::vector& pts ); + +/** @overload +@param center Center of the arc. +@param axes Half of the size of the ellipse main axes. See #ellipse for details. +@param angle Rotation angle of the ellipse in degrees. See #ellipse for details. +@param arcStart Starting angle of the elliptic arc in degrees. +@param arcEnd Ending angle of the elliptic arc in degrees. +@param delta Angle between the subsequent polyline vertices. It defines the approximation accuracy. +@param pts Output vector of polyline vertices. +*/ +CV_EXPORTS void ellipse2Poly(Point2d center, Size2d axes, int angle, + int arcStart, int arcEnd, int delta, + CV_OUT std::vector& pts); + +/** @brief Draws a text string. + +The function cv::putText renders the specified text string in the image. Symbols that cannot be rendered +using the specified font are replaced by question marks. See #getTextSize for a text rendering code +example. + +@param img Image. +@param text Text string to be drawn. +@param org Bottom-left corner of the text string in the image. +@param fontFace Font type, see #HersheyFonts. +@param fontScale Font scale factor that is multiplied by the font-specific base size. +@param color Text color. +@param thickness Thickness of the lines used to draw a text. +@param lineType Line type. See #LineTypes +@param bottomLeftOrigin When true, the image data origin is at the bottom-left corner. Otherwise, +it is at the top-left corner. + */ +CV_EXPORTS_W void putText( InputOutputArray img, const String& text, Point org, + int fontFace, double fontScale, Scalar color, + int thickness = 1, int lineType = LINE_8, + bool bottomLeftOrigin = false ); + +/** @brief Calculates the width and height of a text string. + +The function cv::getTextSize calculates and returns the size of a box that contains the specified text. +That is, the following code renders some text, the tight box surrounding it, and the baseline: : +@code + String text = "Funny text inside the box"; + int fontFace = FONT_HERSHEY_SCRIPT_SIMPLEX; + double fontScale = 2; + int thickness = 3; + + Mat img(600, 800, CV_8UC3, Scalar::all(0)); + + int baseline=0; + Size textSize = getTextSize(text, fontFace, + fontScale, thickness, &baseline); + baseline += thickness; + + // center the text + Point textOrg((img.cols - textSize.width)/2, + (img.rows + textSize.height)/2); + + // draw the box + rectangle(img, textOrg + Point(0, baseline), + textOrg + Point(textSize.width, -textSize.height), + Scalar(0,0,255)); + // ... and the baseline first + line(img, textOrg + Point(0, thickness), + textOrg + Point(textSize.width, thickness), + Scalar(0, 0, 255)); + + // then put the text itself + putText(img, text, textOrg, fontFace, fontScale, + Scalar::all(255), thickness, 8); +@endcode + +@param text Input text string. +@param fontFace Font to use, see #HersheyFonts. +@param fontScale Font scale factor that is multiplied by the font-specific base size. +@param thickness Thickness of lines used to render the text. See #putText for details. +@param[out] baseLine y-coordinate of the baseline relative to the bottom-most text +point. +@return The size of a box that contains the specified text. + +@see putText + */ +CV_EXPORTS_W Size getTextSize(const String& text, int fontFace, + double fontScale, int thickness, + CV_OUT int* baseLine); + + +/** @brief Calculates the font-specific size to use to achieve a given height in pixels. + +@param fontFace Font to use, see cv::HersheyFonts. +@param pixelHeight Pixel height to compute the fontScale for +@param thickness Thickness of lines used to render the text.See putText for details. +@return The fontSize to use for cv::putText + +@see cv::putText +*/ +CV_EXPORTS_W double getFontScaleFromHeight(const int fontFace, + const int pixelHeight, + const int thickness = 1); + +/** @brief Class for iterating over all pixels on a raster line segment. + +The class LineIterator is used to get each pixel of a raster line connecting +two specified points. +It can be treated as a versatile implementation of the Bresenham algorithm +where you can stop at each pixel and do some extra processing, for +example, grab pixel values along the line or draw a line with an effect +(for example, with XOR operation). + +The number of pixels along the line is stored in LineIterator::count. +The method LineIterator::pos returns the current position in the image: + +@code{.cpp} +// grabs pixels along the line (pt1, pt2) +// from 8-bit 3-channel image to the buffer +LineIterator it(img, pt1, pt2, 8); +LineIterator it2 = it; +vector buf(it.count); + +for(int i = 0; i < it.count; i++, ++it) + buf[i] = *(const Vec3b*)*it; + +// alternative way of iterating through the line +for(int i = 0; i < it2.count; i++, ++it2) +{ + Vec3b val = img.at(it2.pos()); + CV_Assert(buf[i] == val); +} +@endcode +*/ +class CV_EXPORTS LineIterator +{ +public: + /** @brief Initializes iterator object for the given line and image. + + The returned iterator can be used to traverse all pixels on a line that + connects the given two points. + The line will be clipped on the image boundaries. + + @param img Underlying image. + @param pt1 First endpoint of the line. + @param pt2 The other endpoint of the line. + @param connectivity Pixel connectivity of the iterator. Valid values are 4 (iterator can move + up, down, left and right) and 8 (iterator can also move diagonally). + @param leftToRight If true, the line is traversed from the leftmost endpoint to the rightmost + endpoint. Otherwise, the line is traversed from \p pt1 to \p pt2. + */ + LineIterator( const Mat& img, Point pt1, Point pt2, + int connectivity = 8, bool leftToRight = false ) + { + init(&img, Rect(0, 0, img.cols, img.rows), pt1, pt2, connectivity, leftToRight); + ptmode = false; + } + LineIterator( Point pt1, Point pt2, + int connectivity = 8, bool leftToRight = false ) + { + init(0, Rect(std::min(pt1.x, pt2.x), + std::min(pt1.y, pt2.y), + std::max(pt1.x, pt2.x) - std::min(pt1.x, pt2.x) + 1, + std::max(pt1.y, pt2.y) - std::min(pt1.y, pt2.y) + 1), + pt1, pt2, connectivity, leftToRight); + ptmode = true; + } + LineIterator( Size boundingAreaSize, Point pt1, Point pt2, + int connectivity = 8, bool leftToRight = false ) + { + init(0, Rect(0, 0, boundingAreaSize.width, boundingAreaSize.height), + pt1, pt2, connectivity, leftToRight); + ptmode = true; + } + LineIterator( Rect boundingAreaRect, Point pt1, Point pt2, + int connectivity = 8, bool leftToRight = false ) + { + init(0, boundingAreaRect, pt1, pt2, connectivity, leftToRight); + ptmode = true; + } + void init(const Mat* img, Rect boundingAreaRect, Point pt1, Point pt2, int connectivity, bool leftToRight); + + /** @brief Returns pointer to the current pixel. + */ + uchar* operator *(); + + /** @brief Moves iterator to the next pixel on the line. + + This is the prefix version (++it). + */ + LineIterator& operator ++(); + + /** @brief Moves iterator to the next pixel on the line. + + This is the postfix version (it++). + */ + LineIterator operator ++(int); + + /** @brief Returns coordinates of the current pixel. + */ + Point pos() const; + + uchar* ptr; + const uchar* ptr0; + int step, elemSize; + int err, count; + int minusDelta, plusDelta; + int minusStep, plusStep; + int minusShift, plusShift; + Point p; + bool ptmode; +}; + +//! @cond IGNORED + +// === LineIterator implementation === + +inline +uchar* LineIterator::operator *() +{ + return ptmode ? 0 : ptr; +} + +inline +LineIterator& LineIterator::operator ++() +{ + int mask = err < 0 ? -1 : 0; + err += minusDelta + (plusDelta & mask); + if(!ptmode) + { + ptr += minusStep + (plusStep & mask); + } + else + { + p.x += minusShift + (plusShift & mask); + p.y += minusStep + (plusStep & mask); + } + return *this; +} + +inline +LineIterator LineIterator::operator ++(int) +{ + LineIterator it = *this; + ++(*this); + return it; +} + +inline +Point LineIterator::pos() const +{ + if(!ptmode) + { + size_t offset = (size_t)(ptr - ptr0); + int y = (int)(offset/step); + int x = (int)((offset - (size_t)y*step)/elemSize); + return Point(x, y); + } + return p; +} + +//! @endcond + +//! @} imgproc_draw + +//! @} imgproc + +} // cv + + +#include "./imgproc/segmentation.hpp" + + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/bindings.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/bindings.hpp new file mode 100644 index 0000000..c69527a --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/bindings.hpp @@ -0,0 +1,34 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_IMGPROC_BINDINGS_HPP +#define OPENCV_IMGPROC_BINDINGS_HPP + +// This file contains special overloads for OpenCV bindings +// No need to use these functions in C++ code. + +namespace cv { + +/** @brief Finds lines in a binary image using the standard Hough transform and get accumulator. + * + * @note This function is for bindings use only. Use original function in C++ code + * + * @sa HoughLines + */ +CV_WRAP static inline +void HoughLinesWithAccumulator( + InputArray image, OutputArray lines, + double rho, double theta, int threshold, + double srn = 0, double stn = 0, + double min_theta = 0, double max_theta = CV_PI +) +{ + std::vector lines_acc; + HoughLines(image, lines_acc, rho, theta, threshold, srn, stn, min_theta, max_theta); + Mat(lines_acc).copyTo(lines); +} + +} // namespace + +#endif // OPENCV_IMGPROC_BINDINGS_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/detail/gcgraph.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/detail/gcgraph.hpp new file mode 100644 index 0000000..f17c6e7 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/detail/gcgraph.hpp @@ -0,0 +1,395 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_IMGPROC_DETAIL_GCGRAPH_HPP +#define OPENCV_IMGPROC_DETAIL_GCGRAPH_HPP + +//! @cond IGNORED + +namespace cv { namespace detail { +template class GCGraph +{ +public: + GCGraph(); + GCGraph( unsigned int vtxCount, unsigned int edgeCount ); + ~GCGraph(); + void create( unsigned int vtxCount, unsigned int edgeCount ); + int addVtx(); + void addEdges( int i, int j, TWeight w, TWeight revw ); + void addTermWeights( int i, TWeight sourceW, TWeight sinkW ); + TWeight maxFlow(); + bool inSourceSegment( int i ); +private: + class Vtx + { + public: + Vtx *next; // initialized and used in maxFlow() only + int parent; + int first; + int ts; + int dist; + TWeight weight; + uchar t; + }; + class Edge + { + public: + int dst; + int next; + TWeight weight; + }; + + std::vector vtcs; + std::vector edges; + TWeight flow; +}; + +template +GCGraph::GCGraph() +{ + flow = 0; +} +template +GCGraph::GCGraph( unsigned int vtxCount, unsigned int edgeCount ) +{ + create( vtxCount, edgeCount ); +} +template +GCGraph::~GCGraph() +{ +} +template +void GCGraph::create( unsigned int vtxCount, unsigned int edgeCount ) +{ + vtcs.reserve( vtxCount ); + edges.reserve( edgeCount + 2 ); + flow = 0; +} + +template +int GCGraph::addVtx() +{ + Vtx v; + memset( &v, 0, sizeof(Vtx)); + vtcs.push_back(v); + return (int)vtcs.size() - 1; +} + +template +void GCGraph::addEdges( int i, int j, TWeight w, TWeight revw ) +{ + CV_Assert( i>=0 && i<(int)vtcs.size() ); + CV_Assert( j>=0 && j<(int)vtcs.size() ); + CV_Assert( w>=0 && revw>=0 ); + CV_Assert( i != j ); + + if( !edges.size() ) + edges.resize( 2 ); + + Edge fromI, toI; + fromI.dst = j; + fromI.next = vtcs[i].first; + fromI.weight = w; + vtcs[i].first = (int)edges.size(); + edges.push_back( fromI ); + + toI.dst = i; + toI.next = vtcs[j].first; + toI.weight = revw; + vtcs[j].first = (int)edges.size(); + edges.push_back( toI ); +} + +template +void GCGraph::addTermWeights( int i, TWeight sourceW, TWeight sinkW ) +{ + CV_Assert( i>=0 && i<(int)vtcs.size() ); + + TWeight dw = vtcs[i].weight; + if( dw > 0 ) + sourceW += dw; + else + sinkW -= dw; + flow += (sourceW < sinkW) ? sourceW : sinkW; + vtcs[i].weight = sourceW - sinkW; +} + +template +TWeight GCGraph::maxFlow() +{ + CV_Assert(!vtcs.empty()); + CV_Assert(!edges.empty()); + const int TERMINAL = -1, ORPHAN = -2; + Vtx stub, *nilNode = &stub, *first = nilNode, *last = nilNode; + int curr_ts = 0; + stub.next = nilNode; + Vtx *vtxPtr = &vtcs[0]; + Edge *edgePtr = &edges[0]; + + std::vector orphans; + + // initialize the active queue and the graph vertices + for( int i = 0; i < (int)vtcs.size(); i++ ) + { + Vtx* v = vtxPtr + i; + v->ts = 0; + if( v->weight != 0 ) + { + last = last->next = v; + v->dist = 1; + v->parent = TERMINAL; + v->t = v->weight < 0; + } + else + v->parent = 0; + } + first = first->next; + last->next = nilNode; + nilNode->next = 0; + + // run the search-path -> augment-graph -> restore-trees loop + for(;;) + { + Vtx* v, *u; + int e0 = -1, ei = 0, ej = 0; + TWeight minWeight, weight; + uchar vt; + + // grow S & T search trees, find an edge connecting them + while( first != nilNode ) + { + v = first; + if( v->parent ) + { + vt = v->t; + for( ei = v->first; ei != 0; ei = edgePtr[ei].next ) + { + if( edgePtr[ei^vt].weight == 0 ) + continue; + u = vtxPtr+edgePtr[ei].dst; + if( !u->parent ) + { + u->t = vt; + u->parent = ei ^ 1; + u->ts = v->ts; + u->dist = v->dist + 1; + if( !u->next ) + { + u->next = nilNode; + last = last->next = u; + } + continue; + } + + if( u->t != vt ) + { + e0 = ei ^ vt; + break; + } + + if( u->dist > v->dist+1 && u->ts <= v->ts ) + { + // reassign the parent + u->parent = ei ^ 1; + u->ts = v->ts; + u->dist = v->dist + 1; + } + } + if( e0 > 0 ) + break; + } + // exclude the vertex from the active list + first = first->next; + v->next = 0; + } + + if( e0 <= 0 ) + break; + + // find the minimum edge weight along the path + minWeight = edgePtr[e0].weight; + CV_Assert( minWeight > 0 ); + // k = 1: source tree, k = 0: destination tree + for( int k = 1; k >= 0; k-- ) + { + for( v = vtxPtr+edgePtr[e0^k].dst;; v = vtxPtr+edgePtr[ei].dst ) + { + if( (ei = v->parent) < 0 ) + break; + weight = edgePtr[ei^k].weight; + minWeight = MIN(minWeight, weight); + CV_Assert( minWeight > 0 ); + } + weight = fabs(v->weight); + minWeight = MIN(minWeight, weight); + CV_Assert( minWeight > 0 ); + } + + // modify weights of the edges along the path and collect orphans + edgePtr[e0].weight -= minWeight; + edgePtr[e0^1].weight += minWeight; + flow += minWeight; + + // k = 1: source tree, k = 0: destination tree + for( int k = 1; k >= 0; k-- ) + { + for( v = vtxPtr+edgePtr[e0^k].dst;; v = vtxPtr+edgePtr[ei].dst ) + { + if( (ei = v->parent) < 0 ) + break; + edgePtr[ei^(k^1)].weight += minWeight; + if( (edgePtr[ei^k].weight -= minWeight) == 0 ) + { + orphans.push_back(v); + v->parent = ORPHAN; + } + } + + v->weight = v->weight + minWeight*(1-k*2); + if( v->weight == 0 ) + { + orphans.push_back(v); + v->parent = ORPHAN; + } + } + + // restore the search trees by finding new parents for the orphans + curr_ts++; + while( !orphans.empty() ) + { + Vtx* v2 = orphans.back(); + orphans.pop_back(); + + int d, minDist = INT_MAX; + e0 = 0; + vt = v2->t; + + for( ei = v2->first; ei != 0; ei = edgePtr[ei].next ) + { + if( edgePtr[ei^(vt^1)].weight == 0 ) + continue; + u = vtxPtr+edgePtr[ei].dst; + if( u->t != vt || u->parent == 0 ) + continue; + // compute the distance to the tree root + for( d = 0;; ) + { + if( u->ts == curr_ts ) + { + d += u->dist; + break; + } + ej = u->parent; + d++; + if( ej < 0 ) + { + if( ej == ORPHAN ) + d = INT_MAX-1; + else + { + u->ts = curr_ts; + u->dist = 1; + } + break; + } + u = vtxPtr+edgePtr[ej].dst; + } + + // update the distance + if( ++d < INT_MAX ) + { + if( d < minDist ) + { + minDist = d; + e0 = ei; + } + for( u = vtxPtr+edgePtr[ei].dst; u->ts != curr_ts; u = vtxPtr+edgePtr[u->parent].dst ) + { + u->ts = curr_ts; + u->dist = --d; + } + } + } + + if( (v2->parent = e0) > 0 ) + { + v2->ts = curr_ts; + v2->dist = minDist; + continue; + } + + /* no parent is found */ + v2->ts = 0; + for( ei = v2->first; ei != 0; ei = edgePtr[ei].next ) + { + u = vtxPtr+edgePtr[ei].dst; + ej = u->parent; + if( u->t != vt || !ej ) + continue; + if( edgePtr[ei^(vt^1)].weight && !u->next ) + { + u->next = nilNode; + last = last->next = u; + } + if( ej > 0 && vtxPtr+edgePtr[ej].dst == v2 ) + { + orphans.push_back(u); + u->parent = ORPHAN; + } + } + } + } + return flow; +} + +template +bool GCGraph::inSourceSegment( int i ) +{ + CV_Assert( i>=0 && i<(int)vtcs.size() ); + return vtcs[i].t == 0; +} + +}} // namespace detail, cv + + +//! @endcond + +#endif // OPENCV_IMGPROC_DETAIL_GCGRAPH_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/hal/hal.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/hal/hal.hpp new file mode 100644 index 0000000..f129012 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/hal/hal.hpp @@ -0,0 +1,246 @@ +#ifndef CV_IMGPROC_HAL_HPP +#define CV_IMGPROC_HAL_HPP + +#include "opencv2/core/cvdef.h" +#include "opencv2/core/cvstd.hpp" +#include "opencv2/core/hal/interface.h" + +namespace cv { namespace hal { + +//! @addtogroup imgproc_hal_functions +//! @{ + +//--------------------------- +//! @cond IGNORED + +struct CV_EXPORTS Filter2D +{ + CV_DEPRECATED static Ptr create(uchar * , size_t , int , + int , int , + int , int , + int , int , + int , double , + int , int , + bool , bool ); + virtual void apply(uchar * , size_t , + uchar * , size_t , + int , int , + int , int , + int , int ) = 0; + virtual ~Filter2D() {} +}; + +struct CV_EXPORTS SepFilter2D +{ + CV_DEPRECATED static Ptr create(int , int , int , + uchar * , int , + uchar * , int , + int , int , + double , int ); + virtual void apply(uchar * , size_t , + uchar * , size_t , + int , int , + int , int , + int , int ) = 0; + virtual ~SepFilter2D() {} +}; + + +struct CV_EXPORTS Morph +{ + CV_DEPRECATED static Ptr create(int , int , int , int , int , + int , uchar * , size_t , + int , int , + int , int , + int , const double *, + int , bool , bool ); + virtual void apply(uchar * , size_t , uchar * , size_t , int , int , + int , int , int , int , + int , int , int , int ) = 0; + virtual ~Morph() {} +}; + +//! @endcond +//--------------------------- + +CV_EXPORTS void filter2D(int stype, int dtype, int kernel_type, + uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int full_width, int full_height, + int offset_x, int offset_y, + uchar * kernel_data, size_t kernel_step, + int kernel_width, int kernel_height, + int anchor_x, int anchor_y, + double delta, int borderType, + bool isSubmatrix); + +CV_EXPORTS void sepFilter2D(int stype, int dtype, int ktype, + uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int full_width, int full_height, + int offset_x, int offset_y, + uchar * kernelx_data, int kernelx_len, + uchar * kernely_data, int kernely_len, + int anchor_x, int anchor_y, + double delta, int borderType); + +CV_EXPORTS void morph(int op, int src_type, int dst_type, + uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int roi_width, int roi_height, int roi_x, int roi_y, + int roi_width2, int roi_height2, int roi_x2, int roi_y2, + int kernel_type, uchar * kernel_data, size_t kernel_step, + int kernel_width, int kernel_height, int anchor_x, int anchor_y, + int borderType, const double borderValue[4], + int iterations, bool isSubmatrix); + + +CV_EXPORTS void resize(int src_type, + const uchar * src_data, size_t src_step, int src_width, int src_height, + uchar * dst_data, size_t dst_step, int dst_width, int dst_height, + double inv_scale_x, double inv_scale_y, int interpolation); + +CV_EXPORTS void warpAffine(int src_type, + const uchar * src_data, size_t src_step, int src_width, int src_height, + uchar * dst_data, size_t dst_step, int dst_width, int dst_height, + const double M[6], int interpolation, int borderType, const double borderValue[4]); + +CV_EXPORTS void warpPerspective(int src_type, + const uchar * src_data, size_t src_step, int src_width, int src_height, + uchar * dst_data, size_t dst_step, int dst_width, int dst_height, + const double M[9], int interpolation, int borderType, const double borderValue[4]); + +CV_EXPORTS void cvtBGRtoBGR(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int scn, int dcn, bool swapBlue); + +CV_EXPORTS void cvtBGRtoBGR5x5(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int scn, bool swapBlue, int greenBits); + +CV_EXPORTS void cvtBGR5x5toBGR(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int dcn, bool swapBlue, int greenBits); + +CV_EXPORTS void cvtBGRtoGray(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int scn, bool swapBlue); + +CV_EXPORTS void cvtGraytoBGR(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int dcn); + +CV_EXPORTS void cvtBGR5x5toGray(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int greenBits); + +CV_EXPORTS void cvtGraytoBGR5x5(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int greenBits); +CV_EXPORTS void cvtBGRtoYUV(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int scn, bool swapBlue, bool isCbCr); + +CV_EXPORTS void cvtYUVtoBGR(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int dcn, bool swapBlue, bool isCbCr); + +CV_EXPORTS void cvtBGRtoXYZ(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int scn, bool swapBlue); + +CV_EXPORTS void cvtXYZtoBGR(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int dcn, bool swapBlue); + +CV_EXPORTS void cvtBGRtoHSV(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int scn, bool swapBlue, bool isFullRange, bool isHSV); + +CV_EXPORTS void cvtHSVtoBGR(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int dcn, bool swapBlue, bool isFullRange, bool isHSV); + +CV_EXPORTS void cvtBGRtoLab(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int scn, bool swapBlue, bool isLab, bool srgb); + +CV_EXPORTS void cvtLabtoBGR(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int depth, int dcn, bool swapBlue, bool isLab, bool srgb); + +CV_EXPORTS void cvtTwoPlaneYUVtoBGR(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int dst_width, int dst_height, + int dcn, bool swapBlue, int uIdx); + +//! Separate Y and UV planes +CV_EXPORTS void cvtTwoPlaneYUVtoBGR(const uchar * y_data, const uchar * uv_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int dst_width, int dst_height, + int dcn, bool swapBlue, int uIdx); + +CV_EXPORTS void cvtTwoPlaneYUVtoBGR(const uchar * y_data, size_t y_step, const uchar * uv_data, size_t uv_step, + uchar * dst_data, size_t dst_step, + int dst_width, int dst_height, + int dcn, bool swapBlue, int uIdx); + +CV_EXPORTS void cvtThreePlaneYUVtoBGR(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int dst_width, int dst_height, + int dcn, bool swapBlue, int uIdx); + +CV_EXPORTS void cvtBGRtoThreePlaneYUV(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int scn, bool swapBlue, int uIdx); + +//! Separate Y and UV planes +CV_EXPORTS void cvtBGRtoTwoPlaneYUV(const uchar * src_data, size_t src_step, + uchar * y_data, uchar * uv_data, size_t dst_step, + int width, int height, + int scn, bool swapBlue, int uIdx); + +CV_EXPORTS void cvtOnePlaneYUVtoBGR(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height, + int dcn, bool swapBlue, int uIdx, int ycn); + +CV_EXPORTS void cvtRGBAtoMultipliedRGBA(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height); + +CV_EXPORTS void cvtMultipliedRGBAtoRGBA(const uchar * src_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int width, int height); + +CV_EXPORTS void integral(int depth, int sdepth, int sqdepth, + const uchar* src, size_t srcstep, + uchar* sum, size_t sumstep, + uchar* sqsum, size_t sqsumstep, + uchar* tilted, size_t tstep, + int width, int height, int cn); + +//! @} + +}} + +#endif // CV_IMGPROC_HAL_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/hal/interface.h b/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/hal/interface.h new file mode 100644 index 0000000..f8dbcfe --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/hal/interface.h @@ -0,0 +1,46 @@ +#ifndef OPENCV_IMGPROC_HAL_INTERFACE_H +#define OPENCV_IMGPROC_HAL_INTERFACE_H + +//! @addtogroup imgproc_hal_interface +//! @{ + +//! @name Interpolation modes +//! @sa cv::InterpolationFlags +//! @{ +#define CV_HAL_INTER_NEAREST 0 +#define CV_HAL_INTER_LINEAR 1 +#define CV_HAL_INTER_CUBIC 2 +#define CV_HAL_INTER_AREA 3 +#define CV_HAL_INTER_LANCZOS4 4 +//! @} + +//! @name Morphology operations +//! @sa cv::MorphTypes +//! @{ +#define CV_HAL_MORPH_ERODE 0 +#define CV_HAL_MORPH_DILATE 1 +//! @} + +//! @name Threshold types +//! @sa cv::ThresholdTypes +//! @{ +#define CV_HAL_THRESH_BINARY 0 +#define CV_HAL_THRESH_BINARY_INV 1 +#define CV_HAL_THRESH_TRUNC 2 +#define CV_HAL_THRESH_TOZERO 3 +#define CV_HAL_THRESH_TOZERO_INV 4 +#define CV_HAL_THRESH_MASK 7 +#define CV_HAL_THRESH_OTSU 8 +#define CV_HAL_THRESH_TRIANGLE 16 +//! @} + +//! @name Adaptive threshold algorithm +//! @sa cv::AdaptiveThresholdTypes +//! @{ +#define CV_HAL_ADAPTIVE_THRESH_MEAN_C 0 +#define CV_HAL_ADAPTIVE_THRESH_GAUSSIAN_C 1 +//! @} + +//! @} + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/imgproc.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/imgproc.hpp new file mode 100644 index 0000000..4175bd0 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/imgproc.hpp @@ -0,0 +1,48 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifdef __OPENCV_BUILD +#error this is a compatibility header which should not be used inside the OpenCV library +#endif + +#include "opencv2/imgproc.hpp" diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/imgproc_c.h b/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/imgproc_c.h new file mode 100644 index 0000000..86dc119 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/imgproc_c.h @@ -0,0 +1,1177 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_IMGPROC_IMGPROC_C_H +#define OPENCV_IMGPROC_IMGPROC_C_H + +#include "opencv2/imgproc/types_c.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup imgproc_c +@{ +*/ + +/*********************** Background statistics accumulation *****************************/ + +/** @brief Adds image to accumulator +@see cv::accumulate +*/ +CVAPI(void) cvAcc( const CvArr* image, CvArr* sum, + const CvArr* mask CV_DEFAULT(NULL) ); + +/** @brief Adds squared image to accumulator +@see cv::accumulateSquare +*/ +CVAPI(void) cvSquareAcc( const CvArr* image, CvArr* sqsum, + const CvArr* mask CV_DEFAULT(NULL) ); + +/** @brief Adds a product of two images to accumulator +@see cv::accumulateProduct +*/ +CVAPI(void) cvMultiplyAcc( const CvArr* image1, const CvArr* image2, CvArr* acc, + const CvArr* mask CV_DEFAULT(NULL) ); + +/** @brief Adds image to accumulator with weights: acc = acc*(1-alpha) + image*alpha +@see cv::accumulateWeighted +*/ +CVAPI(void) cvRunningAvg( const CvArr* image, CvArr* acc, double alpha, + const CvArr* mask CV_DEFAULT(NULL) ); + +/****************************************************************************************\ +* Image Processing * +\****************************************************************************************/ + +/** Copies source 2D array inside of the larger destination array and + makes a border of the specified type (IPL_BORDER_*) around the copied area. */ +CVAPI(void) cvCopyMakeBorder( const CvArr* src, CvArr* dst, CvPoint offset, + int bordertype, CvScalar value CV_DEFAULT(cvScalarAll(0))); + +/** @brief Smooths the image in one of several ways. + +@param src The source image +@param dst The destination image +@param smoothtype Type of the smoothing, see SmoothMethod_c +@param size1 The first parameter of the smoothing operation, the aperture width. Must be a +positive odd number (1, 3, 5, ...) +@param size2 The second parameter of the smoothing operation, the aperture height. Ignored by +CV_MEDIAN and CV_BILATERAL methods. In the case of simple scaled/non-scaled and Gaussian blur if +size2 is zero, it is set to size1. Otherwise it must be a positive odd number. +@param sigma1 In the case of a Gaussian parameter this parameter may specify Gaussian \f$\sigma\f$ +(standard deviation). If it is zero, it is calculated from the kernel size: +\f[\sigma = 0.3 (n/2 - 1) + 0.8 \quad \text{where} \quad n= \begin{array}{l l} \mbox{\texttt{size1} for horizontal kernel} \\ \mbox{\texttt{size2} for vertical kernel} \end{array}\f] +Using standard sigma for small kernels ( \f$3\times 3\f$ to \f$7\times 7\f$ ) gives better speed. If +sigma1 is not zero, while size1 and size2 are zeros, the kernel size is calculated from the +sigma (to provide accurate enough operation). +@param sigma2 additional parameter for bilateral filtering + +@see cv::GaussianBlur, cv::blur, cv::medianBlur, cv::bilateralFilter. + */ +CVAPI(void) cvSmooth( const CvArr* src, CvArr* dst, + int smoothtype CV_DEFAULT(CV_GAUSSIAN), + int size1 CV_DEFAULT(3), + int size2 CV_DEFAULT(0), + double sigma1 CV_DEFAULT(0), + double sigma2 CV_DEFAULT(0)); + +/** @brief Convolves an image with the kernel. + +@param src input image. +@param dst output image of the same size and the same number of channels as src. +@param kernel convolution kernel (or rather a correlation kernel), a single-channel floating point +matrix; if you want to apply different kernels to different channels, split the image into +separate color planes using split and process them individually. +@param anchor anchor of the kernel that indicates the relative position of a filtered point within +the kernel; the anchor should lie within the kernel; default value (-1,-1) means that the anchor +is at the kernel center. + +@see cv::filter2D + */ +CVAPI(void) cvFilter2D( const CvArr* src, CvArr* dst, const CvMat* kernel, + CvPoint anchor CV_DEFAULT(cvPoint(-1,-1))); + +/** @brief Finds integral image: SUM(X,Y) = sum(x \texttt{hist1}(I)\)}{\frac{\texttt{hist2}(I) \cdot \texttt{scale}}{\texttt{hist1}(I)}}{if \(\texttt{hist1}(I) \ne 0\) and \(\texttt{hist2}(I) \le \texttt{hist1}(I)\)}\f] + +@param hist1 First histogram (the divisor). +@param hist2 Second histogram. +@param dst_hist Destination histogram. +@param scale Scale factor for the destination histogram. + */ +CVAPI(void) cvCalcProbDensity( const CvHistogram* hist1, const CvHistogram* hist2, + CvHistogram* dst_hist, double scale CV_DEFAULT(255) ); + +/** @brief equalizes histogram of 8-bit single-channel image +@see cv::equalizeHist +*/ +CVAPI(void) cvEqualizeHist( const CvArr* src, CvArr* dst ); + + +/** @brief Applies distance transform to binary image +@see cv::distanceTransform +*/ +CVAPI(void) cvDistTransform( const CvArr* src, CvArr* dst, + int distance_type CV_DEFAULT(CV_DIST_L2), + int mask_size CV_DEFAULT(3), + const float* mask CV_DEFAULT(NULL), + CvArr* labels CV_DEFAULT(NULL), + int labelType CV_DEFAULT(CV_DIST_LABEL_CCOMP)); + + +/** @brief Applies fixed-level threshold to grayscale image. + + This is a basic operation applied before retrieving contours +@see cv::threshold +*/ +CVAPI(double) cvThreshold( const CvArr* src, CvArr* dst, + double threshold, double max_value, + int threshold_type ); + +/** @brief Applies adaptive threshold to grayscale image. + + The two parameters for methods CV_ADAPTIVE_THRESH_MEAN_C and + CV_ADAPTIVE_THRESH_GAUSSIAN_C are: + neighborhood size (3, 5, 7 etc.), + and a constant subtracted from mean (...,-3,-2,-1,0,1,2,3,...) +@see cv::adaptiveThreshold +*/ +CVAPI(void) cvAdaptiveThreshold( const CvArr* src, CvArr* dst, double max_value, + int adaptive_method CV_DEFAULT(CV_ADAPTIVE_THRESH_MEAN_C), + int threshold_type CV_DEFAULT(CV_THRESH_BINARY), + int block_size CV_DEFAULT(3), + double param1 CV_DEFAULT(5)); + +/** @brief Fills the connected component until the color difference gets large enough +@see cv::floodFill +*/ +CVAPI(void) cvFloodFill( CvArr* image, CvPoint seed_point, + CvScalar new_val, CvScalar lo_diff CV_DEFAULT(cvScalarAll(0)), + CvScalar up_diff CV_DEFAULT(cvScalarAll(0)), + CvConnectedComp* comp CV_DEFAULT(NULL), + int flags CV_DEFAULT(4), + CvArr* mask CV_DEFAULT(NULL)); + +/****************************************************************************************\ +* Feature detection * +\****************************************************************************************/ + +/** @brief Runs canny edge detector +@see cv::Canny +*/ +CVAPI(void) cvCanny( const CvArr* image, CvArr* edges, double threshold1, + double threshold2, int aperture_size CV_DEFAULT(3) ); + +/** @brief Calculates constraint image for corner detection + + Dx^2 * Dyy + Dxx * Dy^2 - 2 * Dx * Dy * Dxy. + Applying threshold to the result gives coordinates of corners +@see cv::preCornerDetect +*/ +CVAPI(void) cvPreCornerDetect( const CvArr* image, CvArr* corners, + int aperture_size CV_DEFAULT(3) ); + +/** @brief Calculates eigen values and vectors of 2x2 + gradient covariation matrix at every image pixel +@see cv::cornerEigenValsAndVecs +*/ +CVAPI(void) cvCornerEigenValsAndVecs( const CvArr* image, CvArr* eigenvv, + int block_size, int aperture_size CV_DEFAULT(3) ); + +/** @brief Calculates minimal eigenvalue for 2x2 gradient covariation matrix at + every image pixel +@see cv::cornerMinEigenVal +*/ +CVAPI(void) cvCornerMinEigenVal( const CvArr* image, CvArr* eigenval, + int block_size, int aperture_size CV_DEFAULT(3) ); + +/** @brief Harris corner detector: + + Calculates det(M) - k*(trace(M)^2), where M is 2x2 gradient covariation matrix for each pixel +@see cv::cornerHarris +*/ +CVAPI(void) cvCornerHarris( const CvArr* image, CvArr* harris_response, + int block_size, int aperture_size CV_DEFAULT(3), + double k CV_DEFAULT(0.04) ); + +/** @brief Adjust corner position using some sort of gradient search +@see cv::cornerSubPix +*/ +CVAPI(void) cvFindCornerSubPix( const CvArr* image, CvPoint2D32f* corners, + int count, CvSize win, CvSize zero_zone, + CvTermCriteria criteria ); + +/** @brief Finds a sparse set of points within the selected region + that seem to be easy to track +@see cv::goodFeaturesToTrack +*/ +CVAPI(void) cvGoodFeaturesToTrack( const CvArr* image, CvArr* eig_image, + CvArr* temp_image, CvPoint2D32f* corners, + int* corner_count, double quality_level, + double min_distance, + const CvArr* mask CV_DEFAULT(NULL), + int block_size CV_DEFAULT(3), + int use_harris CV_DEFAULT(0), + double k CV_DEFAULT(0.04) ); + +/** @brief Finds lines on binary image using one of several methods. + + line_storage is either memory storage or 1 x _max number of lines_ CvMat, its + number of columns is changed by the function. + method is one of CV_HOUGH_*; + rho, theta and threshold are used for each of those methods; + param1 ~ line length, param2 ~ line gap - for probabilistic, + param1 ~ srn, param2 ~ stn - for multi-scale +@see cv::HoughLines +*/ +CVAPI(CvSeq*) cvHoughLines2( CvArr* image, void* line_storage, int method, + double rho, double theta, int threshold, + double param1 CV_DEFAULT(0), double param2 CV_DEFAULT(0), + double min_theta CV_DEFAULT(0), double max_theta CV_DEFAULT(CV_PI)); + +/** @brief Finds circles in the image +@see cv::HoughCircles +*/ +CVAPI(CvSeq*) cvHoughCircles( CvArr* image, void* circle_storage, + int method, double dp, double min_dist, + double param1 CV_DEFAULT(100), + double param2 CV_DEFAULT(100), + int min_radius CV_DEFAULT(0), + int max_radius CV_DEFAULT(0)); + +/** @brief Fits a line into set of 2d or 3d points in a robust way (M-estimator technique) +@see cv::fitLine +*/ +CVAPI(void) cvFitLine( const CvArr* points, int dist_type, double param, + double reps, double aeps, float* line ); + +/****************************************************************************************\ +* Drawing * +\****************************************************************************************/ + +/****************************************************************************************\ +* Drawing functions work with images/matrices of arbitrary type. * +* For color images the channel order is BGR[A] * +* Antialiasing is supported only for 8-bit image now. * +* All the functions include parameter color that means rgb value (that may be * +* constructed with CV_RGB macro) for color images and brightness * +* for grayscale images. * +* If a drawn figure is partially or completely outside of the image, it is clipped.* +\****************************************************************************************/ + +#define CV_FILLED -1 + +#define CV_AA 16 + +/** @brief Draws 4-connected, 8-connected or antialiased line segment connecting two points +@see cv::line +*/ +CVAPI(void) cvLine( CvArr* img, CvPoint pt1, CvPoint pt2, + CvScalar color, int thickness CV_DEFAULT(1), + int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0) ); + +/** @brief Draws a rectangle given two opposite corners of the rectangle (pt1 & pt2) + + if thickness<0 (e.g. thickness == CV_FILLED), the filled box is drawn +@see cv::rectangle +*/ +CVAPI(void) cvRectangle( CvArr* img, CvPoint pt1, CvPoint pt2, + CvScalar color, int thickness CV_DEFAULT(1), + int line_type CV_DEFAULT(8), + int shift CV_DEFAULT(0)); + +/** @brief Draws a rectangle specified by a CvRect structure +@see cv::rectangle +*/ +CVAPI(void) cvRectangleR( CvArr* img, CvRect r, + CvScalar color, int thickness CV_DEFAULT(1), + int line_type CV_DEFAULT(8), + int shift CV_DEFAULT(0)); + + +/** @brief Draws a circle with specified center and radius. + + Thickness works in the same way as with cvRectangle +@see cv::circle +*/ +CVAPI(void) cvCircle( CvArr* img, CvPoint center, int radius, + CvScalar color, int thickness CV_DEFAULT(1), + int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0)); + +/** @brief Draws ellipse outline, filled ellipse, elliptic arc or filled elliptic sector + + depending on _thickness_, _start_angle_ and _end_angle_ parameters. The resultant figure + is rotated by _angle_. All the angles are in degrees +@see cv::ellipse +*/ +CVAPI(void) cvEllipse( CvArr* img, CvPoint center, CvSize axes, + double angle, double start_angle, double end_angle, + CvScalar color, int thickness CV_DEFAULT(1), + int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0)); + +CV_INLINE void cvEllipseBox( CvArr* img, CvBox2D box, CvScalar color, + int thickness CV_DEFAULT(1), + int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0) ) +{ + CvSize axes = cvSize( + cvRound(box.size.width*0.5), + cvRound(box.size.height*0.5) + ); + + cvEllipse( img, cvPointFrom32f( box.center ), axes, box.angle, + 0, 360, color, thickness, line_type, shift ); +} + +/** @brief Fills convex or monotonous polygon. +@see cv::fillConvexPoly +*/ +CVAPI(void) cvFillConvexPoly( CvArr* img, const CvPoint* pts, int npts, CvScalar color, + int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0)); + +/** @brief Fills an area bounded by one or more arbitrary polygons +@see cv::fillPoly +*/ +CVAPI(void) cvFillPoly( CvArr* img, CvPoint** pts, const int* npts, + int contours, CvScalar color, + int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0) ); + +/** @brief Draws one or more polygonal curves +@see cv::polylines +*/ +CVAPI(void) cvPolyLine( CvArr* img, CvPoint** pts, const int* npts, int contours, + int is_closed, CvScalar color, int thickness CV_DEFAULT(1), + int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0) ); + +#define cvDrawRect cvRectangle +#define cvDrawLine cvLine +#define cvDrawCircle cvCircle +#define cvDrawEllipse cvEllipse +#define cvDrawPolyLine cvPolyLine + +/** @brief Clips the line segment connecting *pt1 and *pt2 + by the rectangular window + + (0<=xptr will point to pt1 (or pt2, see left_to_right description) location in +the image. Returns the number of pixels on the line between the ending points. +@see cv::LineIterator +*/ +CVAPI(int) cvInitLineIterator( const CvArr* image, CvPoint pt1, CvPoint pt2, + CvLineIterator* line_iterator, + int connectivity CV_DEFAULT(8), + int left_to_right CV_DEFAULT(0)); + +#define CV_NEXT_LINE_POINT( line_iterator ) \ +{ \ + int _line_iterator_mask = (line_iterator).err < 0 ? -1 : 0; \ + (line_iterator).err += (line_iterator).minus_delta + \ + ((line_iterator).plus_delta & _line_iterator_mask); \ + (line_iterator).ptr += (line_iterator).minus_step + \ + ((line_iterator).plus_step & _line_iterator_mask); \ +} + + +#define CV_FONT_HERSHEY_SIMPLEX 0 +#define CV_FONT_HERSHEY_PLAIN 1 +#define CV_FONT_HERSHEY_DUPLEX 2 +#define CV_FONT_HERSHEY_COMPLEX 3 +#define CV_FONT_HERSHEY_TRIPLEX 4 +#define CV_FONT_HERSHEY_COMPLEX_SMALL 5 +#define CV_FONT_HERSHEY_SCRIPT_SIMPLEX 6 +#define CV_FONT_HERSHEY_SCRIPT_COMPLEX 7 + +#define CV_FONT_ITALIC 16 + +#define CV_FONT_VECTOR0 CV_FONT_HERSHEY_SIMPLEX + + +/** Font structure */ +typedef struct CvFont +{ + const char* nameFont; //Qt:nameFont + CvScalar color; //Qt:ColorFont -> cvScalar(blue_component, green_component, red_component[, alpha_component]) + int font_face; //Qt: bool italic /** =CV_FONT_* */ + const int* ascii; //!< font data and metrics + const int* greek; + const int* cyrillic; + float hscale, vscale; + float shear; //!< slope coefficient: 0 - normal, >0 - italic + int thickness; //!< Qt: weight /** letters thickness */ + float dx; //!< horizontal interval between letters + int line_type; //!< Qt: PointSize +} +CvFont; + +/** @brief Initializes font structure (OpenCV 1.x API). + +The function initializes the font structure that can be passed to text rendering functions. + +@param font Pointer to the font structure initialized by the function +@param font_face Font name identifier. See cv::HersheyFonts and corresponding old CV_* identifiers. +@param hscale Horizontal scale. If equal to 1.0f , the characters have the original width +depending on the font type. If equal to 0.5f , the characters are of half the original width. +@param vscale Vertical scale. If equal to 1.0f , the characters have the original height depending +on the font type. If equal to 0.5f , the characters are of half the original height. +@param shear Approximate tangent of the character slope relative to the vertical line. A zero +value means a non-italic font, 1.0f means about a 45 degree slope, etc. +@param thickness Thickness of the text strokes +@param line_type Type of the strokes, see line description + +@sa cvPutText + */ +CVAPI(void) cvInitFont( CvFont* font, int font_face, + double hscale, double vscale, + double shear CV_DEFAULT(0), + int thickness CV_DEFAULT(1), + int line_type CV_DEFAULT(8)); + +CV_INLINE CvFont cvFont( double scale, int thickness CV_DEFAULT(1) ) +{ + CvFont font; + cvInitFont( &font, CV_FONT_HERSHEY_PLAIN, scale, scale, 0, thickness, CV_AA ); + return font; +} + +/** @brief Renders text stroke with specified font and color at specified location. + CvFont should be initialized with cvInitFont +@see cvInitFont, cvGetTextSize, cvFont, cv::putText +*/ +CVAPI(void) cvPutText( CvArr* img, const char* text, CvPoint org, + const CvFont* font, CvScalar color ); + +/** @brief Calculates bounding box of text stroke (useful for alignment) +@see cv::getTextSize +*/ +CVAPI(void) cvGetTextSize( const char* text_string, const CvFont* font, + CvSize* text_size, int* baseline ); + +/** @brief Unpacks color value + +if arrtype is CV_8UC?, _color_ is treated as packed color value, otherwise the first channels +(depending on arrtype) of destination scalar are set to the same value = _color_ +*/ +CVAPI(CvScalar) cvColorToScalar( double packed_color, int arrtype ); + +/** @brief Returns the polygon points which make up the given ellipse. + +The ellipse is define by the box of size 'axes' rotated 'angle' around the 'center'. A partial +sweep of the ellipse arc can be done by specifying arc_start and arc_end to be something other than +0 and 360, respectively. The input array 'pts' must be large enough to hold the result. The total +number of points stored into 'pts' is returned by this function. +@see cv::ellipse2Poly +*/ +CVAPI(int) cvEllipse2Poly( CvPoint center, CvSize axes, + int angle, int arc_start, int arc_end, CvPoint * pts, int delta ); + +/** @brief Draws contour outlines or filled interiors on the image +@see cv::drawContours +*/ +CVAPI(void) cvDrawContours( CvArr *img, CvSeq* contour, + CvScalar external_color, CvScalar hole_color, + int max_level, int thickness CV_DEFAULT(1), + int line_type CV_DEFAULT(8), + CvPoint offset CV_DEFAULT(cvPoint(0,0))); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/segmentation.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/segmentation.hpp new file mode 100644 index 0000000..c40d501 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/segmentation.hpp @@ -0,0 +1,141 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_IMGPROC_SEGMENTATION_HPP +#define OPENCV_IMGPROC_SEGMENTATION_HPP + +#include "opencv2/imgproc.hpp" + +namespace cv { + +namespace segmentation { + +//! @addtogroup imgproc_segmentation +//! @{ + + +/** @brief Intelligent Scissors image segmentation + * + * This class is used to find the path (contour) between two points + * which can be used for image segmentation. + * + * Usage example: + * @snippet snippets/imgproc_segmentation.cpp usage_example_intelligent_scissors + * + * Reference: "Intelligent Scissors for Image Composition" + * algorithm designed by Eric N. Mortensen and William A. Barrett, Brigham Young University + * @cite Mortensen95intelligentscissors + */ +class CV_EXPORTS_W_SIMPLE IntelligentScissorsMB +{ +public: + CV_WRAP + IntelligentScissorsMB(); + + /** @brief Specify weights of feature functions + * + * Consider keeping weights normalized (sum of weights equals to 1.0) + * Discrete dynamic programming (DP) goal is minimization of costs between pixels. + * + * @param weight_non_edge Specify cost of non-edge pixels (default: 0.43f) + * @param weight_gradient_direction Specify cost of gradient direction function (default: 0.43f) + * @param weight_gradient_magnitude Specify cost of gradient magnitude function (default: 0.14f) + */ + CV_WRAP + IntelligentScissorsMB& setWeights(float weight_non_edge, float weight_gradient_direction, float weight_gradient_magnitude); + + /** @brief Specify gradient magnitude max value threshold + * + * Zero limit value is used to disable gradient magnitude thresholding (default behavior, as described in original article). + * Otherwize pixels with `gradient magnitude >= threshold` have zero cost. + * + * @note Thresholding should be used for images with irregular regions (to avoid stuck on parameters from high-contract areas, like embedded logos). + * + * @param gradient_magnitude_threshold_max Specify gradient magnitude max value threshold (default: 0, disabled) + */ + CV_WRAP + IntelligentScissorsMB& setGradientMagnitudeMaxLimit(float gradient_magnitude_threshold_max = 0.0f); + + /** @brief Switch to "Laplacian Zero-Crossing" edge feature extractor and specify its parameters + * + * This feature extractor is used by default according to article. + * + * Implementation has additional filtering for regions with low-amplitude noise. + * This filtering is enabled through parameter of minimal gradient amplitude (use some small value 4, 8, 16). + * + * @note Current implementation of this feature extractor is based on processing of grayscale images (color image is converted to grayscale image first). + * + * @note Canny edge detector is a bit slower, but provides better results (especially on color images): use setEdgeFeatureCannyParameters(). + * + * @param gradient_magnitude_min_value Minimal gradient magnitude value for edge pixels (default: 0, check is disabled) + */ + CV_WRAP + IntelligentScissorsMB& setEdgeFeatureZeroCrossingParameters(float gradient_magnitude_min_value = 0.0f); + + /** @brief Switch edge feature extractor to use Canny edge detector + * + * @note "Laplacian Zero-Crossing" feature extractor is used by default (following to original article) + * + * @sa Canny + */ + CV_WRAP + IntelligentScissorsMB& setEdgeFeatureCannyParameters( + double threshold1, double threshold2, + int apertureSize = 3, bool L2gradient = false + ); + + /** @brief Specify input image and extract image features + * + * @param image input image. Type is #CV_8UC1 / #CV_8UC3 + */ + CV_WRAP + IntelligentScissorsMB& applyImage(InputArray image); + + /** @brief Specify custom features of input image + * + * Customized advanced variant of applyImage() call. + * + * @param non_edge Specify cost of non-edge pixels. Type is CV_8UC1. Expected values are `{0, 1}`. + * @param gradient_direction Specify gradient direction feature. Type is CV_32FC2. Values are expected to be normalized: `x^2 + y^2 == 1` + * @param gradient_magnitude Specify cost of gradient magnitude function: Type is CV_32FC1. Values should be in range `[0, 1]`. + * @param image **Optional parameter**. Must be specified if subset of features is specified (non-specified features are calculated internally) + */ + CV_WRAP + IntelligentScissorsMB& applyImageFeatures( + InputArray non_edge, InputArray gradient_direction, InputArray gradient_magnitude, + InputArray image = noArray() + ); + + /** @brief Prepares a map of optimal paths for the given source point on the image + * + * @note applyImage() / applyImageFeatures() must be called before this call + * + * @param sourcePt The source point used to find the paths + */ + CV_WRAP void buildMap(const Point& sourcePt); + + /** @brief Extracts optimal contour for the given target point on the image + * + * @note buildMap() must be called before this call + * + * @param targetPt The target point + * @param[out] contour The list of pixels which contains optimal path between the source and the target points of the image. Type is CV_32SC2 (compatible with `std::vector`) + * @param backward Flag to indicate reverse order of retrived pixels (use "true" value to fetch points from the target to the source point) + */ + CV_WRAP void getContour(const Point& targetPt, OutputArray contour, bool backward = false) const; + +#ifndef CV_DOXYGEN + struct Impl; + inline Impl* getImpl() const { return impl.get(); } +protected: + std::shared_ptr impl; +#endif +}; + +//! @} + +} // namespace segmentation +} // namespace cv + +#endif // OPENCV_IMGPROC_SEGMENTATION_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/types_c.h b/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/types_c.h new file mode 100644 index 0000000..d3e55f5 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/imgproc/types_c.h @@ -0,0 +1,659 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_IMGPROC_TYPES_C_H +#define OPENCV_IMGPROC_TYPES_C_H + +#include "opencv2/core/core_c.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup imgproc_c + @{ +*/ + +/** Connected component structure */ +typedef struct CvConnectedComp +{ + double area; /** DBL_EPSILON ? 1./std::sqrt(am00) : 0; + } + operator cv::Moments() const + { + return cv::Moments(m00, m10, m01, m20, m11, m02, m30, m21, m12, m03); + } +#endif +} +CvMoments; + +#ifdef __cplusplus +} // extern "C" + +CV_INLINE CvMoments cvMoments() +{ +#if !defined(CV__ENABLE_C_API_CTORS) + CvMoments self = CV_STRUCT_INITIALIZER; return self; +#else + return CvMoments(); +#endif +} + +CV_INLINE CvMoments cvMoments(const cv::Moments& m) +{ +#if !defined(CV__ENABLE_C_API_CTORS) + double am00 = std::abs(m.m00); + CvMoments self = { + m.m00, m.m10, m.m01, m.m20, m.m11, m.m02, m.m30, m.m21, m.m12, m.m03, + m.mu20, m.mu11, m.mu02, m.mu30, m.mu21, m.mu12, m.mu03, + am00 > DBL_EPSILON ? 1./std::sqrt(am00) : 0 + }; + return self; +#else + return CvMoments(m); +#endif +} + +extern "C" { +#endif // __cplusplus + +/** Hu invariants */ +typedef struct CvHuMoments +{ + double hu1, hu2, hu3, hu4, hu5, hu6, hu7; /**< Hu invariants */ +} +CvHuMoments; + +/** Template matching methods */ +enum +{ + CV_TM_SQDIFF =0, + CV_TM_SQDIFF_NORMED =1, + CV_TM_CCORR =2, + CV_TM_CCORR_NORMED =3, + CV_TM_CCOEFF =4, + CV_TM_CCOEFF_NORMED =5 +}; + +typedef float (CV_CDECL * CvDistanceFunction)( const float* a, const float* b, void* user_param ); + +/** Contour retrieval modes */ +enum +{ + CV_RETR_EXTERNAL=0, + CV_RETR_LIST=1, + CV_RETR_CCOMP=2, + CV_RETR_TREE=3, + CV_RETR_FLOODFILL=4 +}; + +/** Contour approximation methods */ +enum +{ + CV_CHAIN_CODE=0, + CV_CHAIN_APPROX_NONE=1, + CV_CHAIN_APPROX_SIMPLE=2, + CV_CHAIN_APPROX_TC89_L1=3, + CV_CHAIN_APPROX_TC89_KCOS=4, + CV_LINK_RUNS=5 +}; + +/* +Internal structure that is used for sequential retrieving contours from the image. +It supports both hierarchical and plane variants of Suzuki algorithm. +*/ +typedef struct _CvContourScanner* CvContourScanner; + +/** Freeman chain reader state */ +typedef struct CvChainPtReader +{ + CV_SEQ_READER_FIELDS() + char code; + CvPoint pt; + schar deltas[8][2]; +} +CvChainPtReader; + +/** initializes 8-element array for fast access to 3x3 neighborhood of a pixel */ +#define CV_INIT_3X3_DELTAS( deltas, step, nch ) \ + ((deltas)[0] = (nch), (deltas)[1] = -(step) + (nch), \ + (deltas)[2] = -(step), (deltas)[3] = -(step) - (nch), \ + (deltas)[4] = -(nch), (deltas)[5] = (step) - (nch), \ + (deltas)[6] = (step), (deltas)[7] = (step) + (nch)) + + +/** Contour approximation algorithms */ +enum +{ + CV_POLY_APPROX_DP = 0 +}; + +/** Shape matching methods */ +enum +{ + CV_CONTOURS_MATCH_I1 =1, //!< \f[I_1(A,B) = \sum _{i=1...7} \left | \frac{1}{m^A_i} - \frac{1}{m^B_i} \right |\f] + CV_CONTOURS_MATCH_I2 =2, //!< \f[I_2(A,B) = \sum _{i=1...7} \left | m^A_i - m^B_i \right |\f] + CV_CONTOURS_MATCH_I3 =3 //!< \f[I_3(A,B) = \max _{i=1...7} \frac{ \left| m^A_i - m^B_i \right| }{ \left| m^A_i \right| }\f] +}; + +/** Shape orientation */ +enum +{ + CV_CLOCKWISE =1, + CV_COUNTER_CLOCKWISE =2 +}; + + +/** Convexity defect */ +typedef struct CvConvexityDefect +{ + CvPoint* start; /**< point of the contour where the defect begins */ + CvPoint* end; /**< point of the contour where the defect ends */ + CvPoint* depth_point; /**< the farthest from the convex hull point within the defect */ + float depth; /**< distance between the farthest point and the convex hull */ +} CvConvexityDefect; + + +/** Histogram comparison methods */ +enum +{ + CV_COMP_CORREL =0, + CV_COMP_CHISQR =1, + CV_COMP_INTERSECT =2, + CV_COMP_BHATTACHARYYA =3, + CV_COMP_HELLINGER =CV_COMP_BHATTACHARYYA, + CV_COMP_CHISQR_ALT =4, + CV_COMP_KL_DIV =5 +}; + +/** Mask size for distance transform */ +enum +{ + CV_DIST_MASK_3 =3, + CV_DIST_MASK_5 =5, + CV_DIST_MASK_PRECISE =0 +}; + +/** Content of output label array: connected components or pixels */ +enum +{ + CV_DIST_LABEL_CCOMP = 0, + CV_DIST_LABEL_PIXEL = 1 +}; + +/** Distance types for Distance Transform and M-estimators */ +enum +{ + CV_DIST_USER =-1, /**< User defined distance */ + CV_DIST_L1 =1, /**< distance = |x1-x2| + |y1-y2| */ + CV_DIST_L2 =2, /**< the simple euclidean distance */ + CV_DIST_C =3, /**< distance = max(|x1-x2|,|y1-y2|) */ + CV_DIST_L12 =4, /**< L1-L2 metric: distance = 2(sqrt(1+x*x/2) - 1)) */ + CV_DIST_FAIR =5, /**< distance = c^2(|x|/c-log(1+|x|/c)), c = 1.3998 */ + CV_DIST_WELSCH =6, /**< distance = c^2/2(1-exp(-(x/c)^2)), c = 2.9846 */ + CV_DIST_HUBER =7 /**< distance = |x| threshold ? max_value : 0 */ + CV_THRESH_BINARY_INV =1, /**< value = value > threshold ? 0 : max_value */ + CV_THRESH_TRUNC =2, /**< value = value > threshold ? threshold : value */ + CV_THRESH_TOZERO =3, /**< value = value > threshold ? value : 0 */ + CV_THRESH_TOZERO_INV =4, /**< value = value > threshold ? 0 : value */ + CV_THRESH_MASK =7, + CV_THRESH_OTSU =8, /**< use Otsu algorithm to choose the optimal threshold value; + combine the flag with one of the above CV_THRESH_* values */ + CV_THRESH_TRIANGLE =16 /**< use Triangle algorithm to choose the optimal threshold value; + combine the flag with one of the above CV_THRESH_* values, but not + with CV_THRESH_OTSU */ +}; + +/** Adaptive threshold methods */ +enum +{ + CV_ADAPTIVE_THRESH_MEAN_C =0, + CV_ADAPTIVE_THRESH_GAUSSIAN_C =1 +}; + +/** FloodFill flags */ +enum +{ + CV_FLOODFILL_FIXED_RANGE =(1 << 16), + CV_FLOODFILL_MASK_ONLY =(1 << 17) +}; + + +/** Canny edge detector flags */ +enum +{ + CV_CANNY_L2_GRADIENT =(1 << 31) +}; + +/** Variants of a Hough transform */ +enum +{ + CV_HOUGH_STANDARD =0, + CV_HOUGH_PROBABILISTIC =1, + CV_HOUGH_MULTI_SCALE =2, + CV_HOUGH_GRADIENT =3 +}; + + +/* Fast search data structures */ +struct CvFeatureTree; +struct CvLSH; +struct CvLSHOperations; + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/opencv.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/opencv.hpp new file mode 100644 index 0000000..d17b94a --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/opencv.hpp @@ -0,0 +1,95 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009-2010, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_ALL_HPP +#define OPENCV_ALL_HPP + +// File that defines what modules where included during the build of OpenCV +// These are purely the defines of the correct HAVE_OPENCV_modulename values +#include "opencv2/opencv_modules.hpp" + +// Then the list of defines is checked to include the correct headers +// Core library is always included --> without no OpenCV functionality available +#include "opencv2/core.hpp" + +// Then the optional modules are checked +#ifdef HAVE_OPENCV_CALIB3D +#include "opencv2/calib3d.hpp" +#endif +#ifdef HAVE_OPENCV_FEATURES2D +#include "opencv2/features2d.hpp" +#endif +#ifdef HAVE_OPENCV_DNN +#include "opencv2/dnn.hpp" +#endif +#ifdef HAVE_OPENCV_FLANN +#include "opencv2/flann.hpp" +#endif +#ifdef HAVE_OPENCV_HIGHGUI +#include "opencv2/highgui.hpp" +#endif +#ifdef HAVE_OPENCV_IMGCODECS +#include "opencv2/imgcodecs.hpp" +#endif +#ifdef HAVE_OPENCV_IMGPROC +#include "opencv2/imgproc.hpp" +#endif +#ifdef HAVE_OPENCV_ML +#include "opencv2/ml.hpp" +#endif +#ifdef HAVE_OPENCV_OBJDETECT +#include "opencv2/objdetect.hpp" +#endif +#ifdef HAVE_OPENCV_PHOTO +#include "opencv2/photo.hpp" +#endif +#ifdef HAVE_OPENCV_STITCHING +#include "opencv2/stitching.hpp" +#endif +#ifdef HAVE_OPENCV_VIDEO +#include "opencv2/video.hpp" +#endif +#ifdef HAVE_OPENCV_VIDEOIO +#include "opencv2/videoio.hpp" +#endif + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/opencv_modules.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/opencv_modules.hpp new file mode 100644 index 0000000..5fafd9c --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/opencv_modules.hpp @@ -0,0 +1,20 @@ +/* + * ** File generated automatically, do not modify ** + * + * This file defines the list of modules available in current build configuration + * + * +*/ + +// This definition means that OpenCV is built with enabled non-free code. +// For example, patented algorithms for non-profit/non-commercial use only. +/* #undef OPENCV_ENABLE_NONFREE */ + +#define HAVE_OPENCV_CORE +#define HAVE_OPENCV_FEATURES2D +#define HAVE_OPENCV_HIGHGUI +#define HAVE_OPENCV_IMGPROC +#define HAVE_OPENCV_PHOTO +#define HAVE_OPENCV_VIDEO + + diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/photo.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/photo.hpp new file mode 100644 index 0000000..c2e89a3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/photo.hpp @@ -0,0 +1,858 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2008-2012, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_PHOTO_HPP +#define OPENCV_PHOTO_HPP + +#include "opencv2/core.hpp" +#include "opencv2/imgproc.hpp" + +/** +@defgroup photo Computational Photography + +This module includes photo processing algorithms +@{ + @defgroup photo_inpaint Inpainting + @defgroup photo_denoise Denoising + @defgroup photo_hdr HDR imaging + +This section describes high dynamic range imaging algorithms namely tonemapping, exposure alignment, +camera calibration with multiple exposures and exposure fusion. + + @defgroup photo_decolor Contrast Preserving Decolorization + +Useful links: + +http://www.cse.cuhk.edu.hk/leojia/projects/color2gray/index.html + + @defgroup photo_clone Seamless Cloning + +Useful links: + +https://www.learnopencv.com/seamless-cloning-using-opencv-python-cpp + + @defgroup photo_render Non-Photorealistic Rendering + +Useful links: + +http://www.inf.ufrgs.br/~eslgastal/DomainTransform + +https://www.learnopencv.com/non-photorealistic-rendering-using-opencv-python-c/ + + @defgroup photo_c C API +@} + */ + +namespace cv +{ + +//! @addtogroup photo +//! @{ + +//! @addtogroup photo_inpaint +//! @{ +//! the inpainting algorithm +enum +{ + INPAINT_NS = 0, //!< Use Navier-Stokes based method + INPAINT_TELEA = 1 //!< Use the algorithm proposed by Alexandru Telea @cite Telea04 +}; + +/** @brief Restores the selected region in an image using the region neighborhood. + +@param src Input 8-bit, 16-bit unsigned or 32-bit float 1-channel or 8-bit 3-channel image. +@param inpaintMask Inpainting mask, 8-bit 1-channel image. Non-zero pixels indicate the area that +needs to be inpainted. +@param dst Output image with the same size and type as src . +@param inpaintRadius Radius of a circular neighborhood of each point inpainted that is considered +by the algorithm. +@param flags Inpainting method that could be cv::INPAINT_NS or cv::INPAINT_TELEA + +The function reconstructs the selected image area from the pixel near the area boundary. The +function may be used to remove dust and scratches from a scanned photo, or to remove undesirable +objects from still images or video. See for more details. + +@note + - An example using the inpainting technique can be found at + opencv_source_code/samples/cpp/inpaint.cpp + - (Python) An example using the inpainting technique can be found at + opencv_source_code/samples/python/inpaint.py + */ +CV_EXPORTS_W void inpaint( InputArray src, InputArray inpaintMask, + OutputArray dst, double inpaintRadius, int flags ); + +//! @} photo_inpaint + +//! @addtogroup photo_denoise +//! @{ + +/** @brief Perform image denoising using Non-local Means Denoising algorithm + with several computational +optimizations. Noise expected to be a gaussian white noise + +@param src Input 8-bit 1-channel, 2-channel, 3-channel or 4-channel image. +@param dst Output image with the same size and type as src . +@param templateWindowSize Size in pixels of the template patch that is used to compute weights. +Should be odd. Recommended value 7 pixels +@param searchWindowSize Size in pixels of the window that is used to compute weighted average for +given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater +denoising time. Recommended value 21 pixels +@param h Parameter regulating filter strength. Big h value perfectly removes noise but also +removes image details, smaller h value preserves details but also preserves some noise + +This function expected to be applied to grayscale images. For colored images look at +fastNlMeansDenoisingColored. Advanced usage of this functions can be manual denoising of colored +image in different colorspaces. Such approach is used in fastNlMeansDenoisingColored by converting +image to CIELAB colorspace and then separately denoise L and AB components with different h +parameter. + */ +CV_EXPORTS_W void fastNlMeansDenoising( InputArray src, OutputArray dst, float h = 3, + int templateWindowSize = 7, int searchWindowSize = 21); + +/** @brief Perform image denoising using Non-local Means Denoising algorithm + with several computational +optimizations. Noise expected to be a gaussian white noise + +@param src Input 8-bit or 16-bit (only with NORM_L1) 1-channel, +2-channel, 3-channel or 4-channel image. +@param dst Output image with the same size and type as src . +@param templateWindowSize Size in pixels of the template patch that is used to compute weights. +Should be odd. Recommended value 7 pixels +@param searchWindowSize Size in pixels of the window that is used to compute weighted average for +given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater +denoising time. Recommended value 21 pixels +@param h Array of parameters regulating filter strength, either one +parameter applied to all channels or one per channel in dst. Big h value +perfectly removes noise but also removes image details, smaller h +value preserves details but also preserves some noise +@param normType Type of norm used for weight calculation. Can be either NORM_L2 or NORM_L1 + +This function expected to be applied to grayscale images. For colored images look at +fastNlMeansDenoisingColored. Advanced usage of this functions can be manual denoising of colored +image in different colorspaces. Such approach is used in fastNlMeansDenoisingColored by converting +image to CIELAB colorspace and then separately denoise L and AB components with different h +parameter. + */ +CV_EXPORTS_W void fastNlMeansDenoising( InputArray src, OutputArray dst, + const std::vector& h, + int templateWindowSize = 7, int searchWindowSize = 21, + int normType = NORM_L2); + +/** @brief Modification of fastNlMeansDenoising function for colored images + +@param src Input 8-bit 3-channel image. +@param dst Output image with the same size and type as src . +@param templateWindowSize Size in pixels of the template patch that is used to compute weights. +Should be odd. Recommended value 7 pixels +@param searchWindowSize Size in pixels of the window that is used to compute weighted average for +given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater +denoising time. Recommended value 21 pixels +@param h Parameter regulating filter strength for luminance component. Bigger h value perfectly +removes noise but also removes image details, smaller h value preserves details but also preserves +some noise +@param hColor The same as h but for color components. For most images value equals 10 +will be enough to remove colored noise and do not distort colors + +The function converts image to CIELAB colorspace and then separately denoise L and AB components +with given h parameters using fastNlMeansDenoising function. + */ +CV_EXPORTS_W void fastNlMeansDenoisingColored( InputArray src, OutputArray dst, + float h = 3, float hColor = 3, + int templateWindowSize = 7, int searchWindowSize = 21); + +/** @brief Modification of fastNlMeansDenoising function for images sequence where consecutive images have been +captured in small period of time. For example video. This version of the function is for grayscale +images or for manual manipulation with colorspaces. For more details see + + +@param srcImgs Input 8-bit 1-channel, 2-channel, 3-channel or +4-channel images sequence. All images should have the same type and +size. +@param imgToDenoiseIndex Target image to denoise index in srcImgs sequence +@param temporalWindowSize Number of surrounding images to use for target image denoising. Should +be odd. Images from imgToDenoiseIndex - temporalWindowSize / 2 to +imgToDenoiseIndex - temporalWindowSize / 2 from srcImgs will be used to denoise +srcImgs[imgToDenoiseIndex] image. +@param dst Output image with the same size and type as srcImgs images. +@param templateWindowSize Size in pixels of the template patch that is used to compute weights. +Should be odd. Recommended value 7 pixels +@param searchWindowSize Size in pixels of the window that is used to compute weighted average for +given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater +denoising time. Recommended value 21 pixels +@param h Parameter regulating filter strength. Bigger h value +perfectly removes noise but also removes image details, smaller h +value preserves details but also preserves some noise + */ +CV_EXPORTS_W void fastNlMeansDenoisingMulti( InputArrayOfArrays srcImgs, OutputArray dst, + int imgToDenoiseIndex, int temporalWindowSize, + float h = 3, int templateWindowSize = 7, int searchWindowSize = 21); + +/** @brief Modification of fastNlMeansDenoising function for images sequence where consecutive images have been +captured in small period of time. For example video. This version of the function is for grayscale +images or for manual manipulation with colorspaces. For more details see + + +@param srcImgs Input 8-bit or 16-bit (only with NORM_L1) 1-channel, +2-channel, 3-channel or 4-channel images sequence. All images should +have the same type and size. +@param imgToDenoiseIndex Target image to denoise index in srcImgs sequence +@param temporalWindowSize Number of surrounding images to use for target image denoising. Should +be odd. Images from imgToDenoiseIndex - temporalWindowSize / 2 to +imgToDenoiseIndex - temporalWindowSize / 2 from srcImgs will be used to denoise +srcImgs[imgToDenoiseIndex] image. +@param dst Output image with the same size and type as srcImgs images. +@param templateWindowSize Size in pixels of the template patch that is used to compute weights. +Should be odd. Recommended value 7 pixels +@param searchWindowSize Size in pixels of the window that is used to compute weighted average for +given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater +denoising time. Recommended value 21 pixels +@param h Array of parameters regulating filter strength, either one +parameter applied to all channels or one per channel in dst. Big h value +perfectly removes noise but also removes image details, smaller h +value preserves details but also preserves some noise +@param normType Type of norm used for weight calculation. Can be either NORM_L2 or NORM_L1 + */ +CV_EXPORTS_W void fastNlMeansDenoisingMulti( InputArrayOfArrays srcImgs, OutputArray dst, + int imgToDenoiseIndex, int temporalWindowSize, + const std::vector& h, + int templateWindowSize = 7, int searchWindowSize = 21, + int normType = NORM_L2); + +/** @brief Modification of fastNlMeansDenoisingMulti function for colored images sequences + +@param srcImgs Input 8-bit 3-channel images sequence. All images should have the same type and +size. +@param imgToDenoiseIndex Target image to denoise index in srcImgs sequence +@param temporalWindowSize Number of surrounding images to use for target image denoising. Should +be odd. Images from imgToDenoiseIndex - temporalWindowSize / 2 to +imgToDenoiseIndex - temporalWindowSize / 2 from srcImgs will be used to denoise +srcImgs[imgToDenoiseIndex] image. +@param dst Output image with the same size and type as srcImgs images. +@param templateWindowSize Size in pixels of the template patch that is used to compute weights. +Should be odd. Recommended value 7 pixels +@param searchWindowSize Size in pixels of the window that is used to compute weighted average for +given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater +denoising time. Recommended value 21 pixels +@param h Parameter regulating filter strength for luminance component. Bigger h value perfectly +removes noise but also removes image details, smaller h value preserves details but also preserves +some noise. +@param hColor The same as h but for color components. + +The function converts images to CIELAB colorspace and then separately denoise L and AB components +with given h parameters using fastNlMeansDenoisingMulti function. + */ +CV_EXPORTS_W void fastNlMeansDenoisingColoredMulti( InputArrayOfArrays srcImgs, OutputArray dst, + int imgToDenoiseIndex, int temporalWindowSize, + float h = 3, float hColor = 3, + int templateWindowSize = 7, int searchWindowSize = 21); + +/** @brief Primal-dual algorithm is an algorithm for solving special types of variational problems (that is, +finding a function to minimize some functional). As the image denoising, in particular, may be seen +as the variational problem, primal-dual algorithm then can be used to perform denoising and this is +exactly what is implemented. + +It should be noted, that this implementation was taken from the July 2013 blog entry +@cite MA13 , which also contained (slightly more general) ready-to-use source code on Python. +Subsequently, that code was rewritten on C++ with the usage of openCV by Vadim Pisarevsky at the end +of July 2013 and finally it was slightly adapted by later authors. + +Although the thorough discussion and justification of the algorithm involved may be found in +@cite ChambolleEtAl, it might make sense to skim over it here, following @cite MA13 . To begin +with, we consider the 1-byte gray-level images as the functions from the rectangular domain of +pixels (it may be seen as set +\f$\left\{(x,y)\in\mathbb{N}\times\mathbb{N}\mid 1\leq x\leq n,\;1\leq y\leq m\right\}\f$ for some +\f$m,\;n\in\mathbb{N}\f$) into \f$\{0,1,\dots,255\}\f$. We shall denote the noised images as \f$f_i\f$ and with +this view, given some image \f$x\f$ of the same size, we may measure how bad it is by the formula + +\f[\left\|\left\|\nabla x\right\|\right\| + \lambda\sum_i\left\|\left\|x-f_i\right\|\right\|\f] + +\f$\|\|\cdot\|\|\f$ here denotes \f$L_2\f$-norm and as you see, the first addend states that we want our +image to be smooth (ideally, having zero gradient, thus being constant) and the second states that +we want our result to be close to the observations we've got. If we treat \f$x\f$ as a function, this is +exactly the functional what we seek to minimize and here the Primal-Dual algorithm comes into play. + +@param observations This array should contain one or more noised versions of the image that is to +be restored. +@param result Here the denoised image will be stored. There is no need to do pre-allocation of +storage space, as it will be automatically allocated, if necessary. +@param lambda Corresponds to \f$\lambda\f$ in the formulas above. As it is enlarged, the smooth +(blurred) images are treated more favorably than detailed (but maybe more noised) ones. Roughly +speaking, as it becomes smaller, the result will be more blur but more sever outliers will be +removed. +@param niters Number of iterations that the algorithm will run. Of course, as more iterations as +better, but it is hard to quantitatively refine this statement, so just use the default and +increase it if the results are poor. + */ +CV_EXPORTS_W void denoise_TVL1(const std::vector& observations,Mat& result, double lambda=1.0, int niters=30); + +//! @} photo_denoise + +//! @addtogroup photo_hdr +//! @{ + +enum { LDR_SIZE = 256 }; + +/** @brief Base class for tonemapping algorithms - tools that are used to map HDR image to 8-bit range. + */ +class CV_EXPORTS_W Tonemap : public Algorithm +{ +public: + /** @brief Tonemaps image + + @param src source image - CV_32FC3 Mat (float 32 bits 3 channels) + @param dst destination image - CV_32FC3 Mat with values in [0, 1] range + */ + CV_WRAP virtual void process(InputArray src, OutputArray dst) = 0; + + CV_WRAP virtual float getGamma() const = 0; + CV_WRAP virtual void setGamma(float gamma) = 0; +}; + +/** @brief Creates simple linear mapper with gamma correction + +@param gamma positive value for gamma correction. Gamma value of 1.0 implies no correction, gamma +equal to 2.2f is suitable for most displays. +Generally gamma \> 1 brightens the image and gamma \< 1 darkens it. + */ +CV_EXPORTS_W Ptr createTonemap(float gamma = 1.0f); + +/** @brief Adaptive logarithmic mapping is a fast global tonemapping algorithm that scales the image in +logarithmic domain. + +Since it's a global operator the same function is applied to all the pixels, it is controlled by the +bias parameter. + +Optional saturation enhancement is possible as described in @cite FL02 . + +For more information see @cite DM03 . + */ +class CV_EXPORTS_W TonemapDrago : public Tonemap +{ +public: + + CV_WRAP virtual float getSaturation() const = 0; + CV_WRAP virtual void setSaturation(float saturation) = 0; + + CV_WRAP virtual float getBias() const = 0; + CV_WRAP virtual void setBias(float bias) = 0; +}; + +/** @brief Creates TonemapDrago object + +@param gamma gamma value for gamma correction. See createTonemap +@param saturation positive saturation enhancement value. 1.0 preserves saturation, values greater +than 1 increase saturation and values less than 1 decrease it. +@param bias value for bias function in [0, 1] range. Values from 0.7 to 0.9 usually give best +results, default value is 0.85. + */ +CV_EXPORTS_W Ptr createTonemapDrago(float gamma = 1.0f, float saturation = 1.0f, float bias = 0.85f); + + +/** @brief This is a global tonemapping operator that models human visual system. + +Mapping function is controlled by adaptation parameter, that is computed using light adaptation and +color adaptation. + +For more information see @cite RD05 . + */ +class CV_EXPORTS_W TonemapReinhard : public Tonemap +{ +public: + CV_WRAP virtual float getIntensity() const = 0; + CV_WRAP virtual void setIntensity(float intensity) = 0; + + CV_WRAP virtual float getLightAdaptation() const = 0; + CV_WRAP virtual void setLightAdaptation(float light_adapt) = 0; + + CV_WRAP virtual float getColorAdaptation() const = 0; + CV_WRAP virtual void setColorAdaptation(float color_adapt) = 0; +}; + +/** @brief Creates TonemapReinhard object + +@param gamma gamma value for gamma correction. See createTonemap +@param intensity result intensity in [-8, 8] range. Greater intensity produces brighter results. +@param light_adapt light adaptation in [0, 1] range. If 1 adaptation is based only on pixel +value, if 0 it's global, otherwise it's a weighted mean of this two cases. +@param color_adapt chromatic adaptation in [0, 1] range. If 1 channels are treated independently, +if 0 adaptation level is the same for each channel. + */ +CV_EXPORTS_W Ptr +createTonemapReinhard(float gamma = 1.0f, float intensity = 0.0f, float light_adapt = 1.0f, float color_adapt = 0.0f); + +/** @brief This algorithm transforms image to contrast using gradients on all levels of gaussian pyramid, +transforms contrast values to HVS response and scales the response. After this the image is +reconstructed from new contrast values. + +For more information see @cite MM06 . + */ +class CV_EXPORTS_W TonemapMantiuk : public Tonemap +{ +public: + CV_WRAP virtual float getScale() const = 0; + CV_WRAP virtual void setScale(float scale) = 0; + + CV_WRAP virtual float getSaturation() const = 0; + CV_WRAP virtual void setSaturation(float saturation) = 0; +}; + +/** @brief Creates TonemapMantiuk object + +@param gamma gamma value for gamma correction. See createTonemap +@param scale contrast scale factor. HVS response is multiplied by this parameter, thus compressing +dynamic range. Values from 0.6 to 0.9 produce best results. +@param saturation saturation enhancement value. See createTonemapDrago + */ +CV_EXPORTS_W Ptr +createTonemapMantiuk(float gamma = 1.0f, float scale = 0.7f, float saturation = 1.0f); + +/** @brief The base class for algorithms that align images of the same scene with different exposures + */ +class CV_EXPORTS_W AlignExposures : public Algorithm +{ +public: + /** @brief Aligns images + + @param src vector of input images + @param dst vector of aligned images + @param times vector of exposure time values for each image + @param response 256x1 matrix with inverse camera response function for each pixel value, it should + have the same number of channels as images. + */ + CV_WRAP virtual void process(InputArrayOfArrays src, std::vector& dst, + InputArray times, InputArray response) = 0; +}; + +/** @brief This algorithm converts images to median threshold bitmaps (1 for pixels brighter than median +luminance and 0 otherwise) and than aligns the resulting bitmaps using bit operations. + +It is invariant to exposure, so exposure values and camera response are not necessary. + +In this implementation new image regions are filled with zeros. + +For more information see @cite GW03 . + */ +class CV_EXPORTS_W AlignMTB : public AlignExposures +{ +public: + CV_WRAP virtual void process(InputArrayOfArrays src, std::vector& dst, + InputArray times, InputArray response) CV_OVERRIDE = 0; + + /** @brief Short version of process, that doesn't take extra arguments. + + @param src vector of input images + @param dst vector of aligned images + */ + CV_WRAP virtual void process(InputArrayOfArrays src, std::vector& dst) = 0; + + /** @brief Calculates shift between two images, i. e. how to shift the second image to correspond it with the + first. + + @param img0 first image + @param img1 second image + */ + CV_WRAP virtual Point calculateShift(InputArray img0, InputArray img1) = 0; + /** @brief Helper function, that shift Mat filling new regions with zeros. + + @param src input image + @param dst result image + @param shift shift value + */ + CV_WRAP virtual void shiftMat(InputArray src, OutputArray dst, const Point shift) = 0; + /** @brief Computes median threshold and exclude bitmaps of given image. + + @param img input image + @param tb median threshold bitmap + @param eb exclude bitmap + */ + CV_WRAP virtual void computeBitmaps(InputArray img, OutputArray tb, OutputArray eb) = 0; + + CV_WRAP virtual int getMaxBits() const = 0; + CV_WRAP virtual void setMaxBits(int max_bits) = 0; + + CV_WRAP virtual int getExcludeRange() const = 0; + CV_WRAP virtual void setExcludeRange(int exclude_range) = 0; + + CV_WRAP virtual bool getCut() const = 0; + CV_WRAP virtual void setCut(bool value) = 0; +}; + +/** @brief Creates AlignMTB object + +@param max_bits logarithm to the base 2 of maximal shift in each dimension. Values of 5 and 6 are +usually good enough (31 and 63 pixels shift respectively). +@param exclude_range range for exclusion bitmap that is constructed to suppress noise around the +median value. +@param cut if true cuts images, otherwise fills the new regions with zeros. + */ +CV_EXPORTS_W Ptr createAlignMTB(int max_bits = 6, int exclude_range = 4, bool cut = true); + +/** @brief The base class for camera response calibration algorithms. + */ +class CV_EXPORTS_W CalibrateCRF : public Algorithm +{ +public: + /** @brief Recovers inverse camera response. + + @param src vector of input images + @param dst 256x1 matrix with inverse camera response function + @param times vector of exposure time values for each image + */ + CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst, InputArray times) = 0; +}; + +/** @brief Inverse camera response function is extracted for each brightness value by minimizing an objective +function as linear system. Objective function is constructed using pixel values on the same position +in all images, extra term is added to make the result smoother. + +For more information see @cite DM97 . + */ +class CV_EXPORTS_W CalibrateDebevec : public CalibrateCRF +{ +public: + CV_WRAP virtual float getLambda() const = 0; + CV_WRAP virtual void setLambda(float lambda) = 0; + + CV_WRAP virtual int getSamples() const = 0; + CV_WRAP virtual void setSamples(int samples) = 0; + + CV_WRAP virtual bool getRandom() const = 0; + CV_WRAP virtual void setRandom(bool random) = 0; +}; + +/** @brief Creates CalibrateDebevec object + +@param samples number of pixel locations to use +@param lambda smoothness term weight. Greater values produce smoother results, but can alter the +response. +@param random if true sample pixel locations are chosen at random, otherwise they form a +rectangular grid. + */ +CV_EXPORTS_W Ptr createCalibrateDebevec(int samples = 70, float lambda = 10.0f, bool random = false); + +/** @brief Inverse camera response function is extracted for each brightness value by minimizing an objective +function as linear system. This algorithm uses all image pixels. + +For more information see @cite RB99 . + */ +class CV_EXPORTS_W CalibrateRobertson : public CalibrateCRF +{ +public: + CV_WRAP virtual int getMaxIter() const = 0; + CV_WRAP virtual void setMaxIter(int max_iter) = 0; + + CV_WRAP virtual float getThreshold() const = 0; + CV_WRAP virtual void setThreshold(float threshold) = 0; + + CV_WRAP virtual Mat getRadiance() const = 0; +}; + +/** @brief Creates CalibrateRobertson object + +@param max_iter maximal number of Gauss-Seidel solver iterations. +@param threshold target difference between results of two successive steps of the minimization. + */ +CV_EXPORTS_W Ptr createCalibrateRobertson(int max_iter = 30, float threshold = 0.01f); + +/** @brief The base class algorithms that can merge exposure sequence to a single image. + */ +class CV_EXPORTS_W MergeExposures : public Algorithm +{ +public: + /** @brief Merges images. + + @param src vector of input images + @param dst result image + @param times vector of exposure time values for each image + @param response 256x1 matrix with inverse camera response function for each pixel value, it should + have the same number of channels as images. + */ + CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst, + InputArray times, InputArray response) = 0; +}; + +/** @brief The resulting HDR image is calculated as weighted average of the exposures considering exposure +values and camera response. + +For more information see @cite DM97 . + */ +class CV_EXPORTS_W MergeDebevec : public MergeExposures +{ +public: + CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst, + InputArray times, InputArray response) CV_OVERRIDE = 0; + CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst, InputArray times) = 0; +}; + +/** @brief Creates MergeDebevec object + */ +CV_EXPORTS_W Ptr createMergeDebevec(); + +/** @brief Pixels are weighted using contrast, saturation and well-exposedness measures, than images are +combined using laplacian pyramids. + +The resulting image weight is constructed as weighted average of contrast, saturation and +well-exposedness measures. + +The resulting image doesn't require tonemapping and can be converted to 8-bit image by multiplying +by 255, but it's recommended to apply gamma correction and/or linear tonemapping. + +For more information see @cite MK07 . + */ +class CV_EXPORTS_W MergeMertens : public MergeExposures +{ +public: + CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst, + InputArray times, InputArray response) CV_OVERRIDE = 0; + /** @brief Short version of process, that doesn't take extra arguments. + + @param src vector of input images + @param dst result image + */ + CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst) = 0; + + CV_WRAP virtual float getContrastWeight() const = 0; + CV_WRAP virtual void setContrastWeight(float contrast_weiht) = 0; + + CV_WRAP virtual float getSaturationWeight() const = 0; + CV_WRAP virtual void setSaturationWeight(float saturation_weight) = 0; + + CV_WRAP virtual float getExposureWeight() const = 0; + CV_WRAP virtual void setExposureWeight(float exposure_weight) = 0; +}; + +/** @brief Creates MergeMertens object + +@param contrast_weight contrast measure weight. See MergeMertens. +@param saturation_weight saturation measure weight +@param exposure_weight well-exposedness measure weight + */ +CV_EXPORTS_W Ptr +createMergeMertens(float contrast_weight = 1.0f, float saturation_weight = 1.0f, float exposure_weight = 0.0f); + +/** @brief The resulting HDR image is calculated as weighted average of the exposures considering exposure +values and camera response. + +For more information see @cite RB99 . + */ +class CV_EXPORTS_W MergeRobertson : public MergeExposures +{ +public: + CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst, + InputArray times, InputArray response) CV_OVERRIDE = 0; + CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst, InputArray times) = 0; +}; + +/** @brief Creates MergeRobertson object + */ +CV_EXPORTS_W Ptr createMergeRobertson(); + +//! @} photo_hdr + +//! @addtogroup photo_decolor +//! @{ + +/** @brief Transforms a color image to a grayscale image. It is a basic tool in digital printing, stylized +black-and-white photograph rendering, and in many single channel image processing applications +@cite CL12 . + +@param src Input 8-bit 3-channel image. +@param grayscale Output 8-bit 1-channel image. +@param color_boost Output 8-bit 3-channel image. + +This function is to be applied on color images. + */ +CV_EXPORTS_W void decolor( InputArray src, OutputArray grayscale, OutputArray color_boost); + +//! @} photo_decolor + +//! @addtogroup photo_clone +//! @{ + + +//! seamlessClone algorithm flags +enum +{ + /** The power of the method is fully expressed when inserting objects with complex outlines into a new background*/ + NORMAL_CLONE = 1, + /** The classic method, color-based selection and alpha masking might be time consuming and often leaves an undesirable + halo. Seamless cloning, even averaged with the original image, is not effective. Mixed seamless cloning based on a loose selection proves effective.*/ + MIXED_CLONE = 2, + /** Monochrome transfer allows the user to easily replace certain features of one object by alternative features.*/ + MONOCHROME_TRANSFER = 3}; + + +/** @example samples/cpp/tutorial_code/photo/seamless_cloning/cloning_demo.cpp +An example using seamlessClone function +*/ +/** @brief Image editing tasks concern either global changes (color/intensity corrections, filters, +deformations) or local changes concerned to a selection. Here we are interested in achieving local +changes, ones that are restricted to a region manually selected (ROI), in a seamless and effortless +manner. The extent of the changes ranges from slight distortions to complete replacement by novel +content @cite PM03 . + +@param src Input 8-bit 3-channel image. +@param dst Input 8-bit 3-channel image. +@param mask Input 8-bit 1 or 3-channel image. +@param p Point in dst image where object is placed. +@param blend Output image with the same size and type as dst. +@param flags Cloning method that could be cv::NORMAL_CLONE, cv::MIXED_CLONE or cv::MONOCHROME_TRANSFER + */ +CV_EXPORTS_W void seamlessClone( InputArray src, InputArray dst, InputArray mask, Point p, + OutputArray blend, int flags); + +/** @brief Given an original color image, two differently colored versions of this image can be mixed +seamlessly. + +@param src Input 8-bit 3-channel image. +@param mask Input 8-bit 1 or 3-channel image. +@param dst Output image with the same size and type as src . +@param red_mul R-channel multiply factor. +@param green_mul G-channel multiply factor. +@param blue_mul B-channel multiply factor. + +Multiplication factor is between .5 to 2.5. + */ +CV_EXPORTS_W void colorChange(InputArray src, InputArray mask, OutputArray dst, float red_mul = 1.0f, + float green_mul = 1.0f, float blue_mul = 1.0f); + +/** @brief Applying an appropriate non-linear transformation to the gradient field inside the selection and +then integrating back with a Poisson solver, modifies locally the apparent illumination of an image. + +@param src Input 8-bit 3-channel image. +@param mask Input 8-bit 1 or 3-channel image. +@param dst Output image with the same size and type as src. +@param alpha Value ranges between 0-2. +@param beta Value ranges between 0-2. + +This is useful to highlight under-exposed foreground objects or to reduce specular reflections. + */ +CV_EXPORTS_W void illuminationChange(InputArray src, InputArray mask, OutputArray dst, + float alpha = 0.2f, float beta = 0.4f); + +/** @brief By retaining only the gradients at edge locations, before integrating with the Poisson solver, one +washes out the texture of the selected region, giving its contents a flat aspect. Here Canny Edge %Detector is used. + +@param src Input 8-bit 3-channel image. +@param mask Input 8-bit 1 or 3-channel image. +@param dst Output image with the same size and type as src. +@param low_threshold %Range from 0 to 100. +@param high_threshold Value \> 100. +@param kernel_size The size of the Sobel kernel to be used. + +@note +The algorithm assumes that the color of the source image is close to that of the destination. This +assumption means that when the colors don't match, the source image color gets tinted toward the +color of the destination image. + */ +CV_EXPORTS_W void textureFlattening(InputArray src, InputArray mask, OutputArray dst, + float low_threshold = 30, float high_threshold = 45, + int kernel_size = 3); + +//! @} photo_clone + +//! @addtogroup photo_render +//! @{ + +//! Edge preserving filters +enum +{ + RECURS_FILTER = 1, //!< Recursive Filtering + NORMCONV_FILTER = 2 //!< Normalized Convolution Filtering +}; + +/** @brief Filtering is the fundamental operation in image and video processing. Edge-preserving smoothing +filters are used in many different applications @cite EM11 . + +@param src Input 8-bit 3-channel image. +@param dst Output 8-bit 3-channel image. +@param flags Edge preserving filters: cv::RECURS_FILTER or cv::NORMCONV_FILTER +@param sigma_s %Range between 0 to 200. +@param sigma_r %Range between 0 to 1. + */ +CV_EXPORTS_W void edgePreservingFilter(InputArray src, OutputArray dst, int flags = 1, + float sigma_s = 60, float sigma_r = 0.4f); + +/** @brief This filter enhances the details of a particular image. + +@param src Input 8-bit 3-channel image. +@param dst Output image with the same size and type as src. +@param sigma_s %Range between 0 to 200. +@param sigma_r %Range between 0 to 1. + */ +CV_EXPORTS_W void detailEnhance(InputArray src, OutputArray dst, float sigma_s = 10, + float sigma_r = 0.15f); + +/** @example samples/cpp/tutorial_code/photo/non_photorealistic_rendering/npr_demo.cpp +An example using non-photorealistic line drawing functions +*/ +/** @brief Pencil-like non-photorealistic line drawing + +@param src Input 8-bit 3-channel image. +@param dst1 Output 8-bit 1-channel image. +@param dst2 Output image with the same size and type as src. +@param sigma_s %Range between 0 to 200. +@param sigma_r %Range between 0 to 1. +@param shade_factor %Range between 0 to 0.1. + */ +CV_EXPORTS_W void pencilSketch(InputArray src, OutputArray dst1, OutputArray dst2, + float sigma_s = 60, float sigma_r = 0.07f, float shade_factor = 0.02f); + +/** @brief Stylization aims to produce digital imagery with a wide variety of effects not focused on +photorealism. Edge-aware filters are ideal for stylization, as they can abstract regions of low +contrast while preserving, or enhancing, high-contrast features. + +@param src Input 8-bit 3-channel image. +@param dst Output image with the same size and type as src. +@param sigma_s %Range between 0 to 200. +@param sigma_r %Range between 0 to 1. + */ +CV_EXPORTS_W void stylization(InputArray src, OutputArray dst, float sigma_s = 60, + float sigma_r = 0.45f); + +//! @} photo_render + +//! @} photo + +} // cv + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/photo/cuda.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/photo/cuda.hpp new file mode 100644 index 0000000..a2f3816 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/photo/cuda.hpp @@ -0,0 +1,132 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2008-2012, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_PHOTO_CUDA_HPP +#define OPENCV_PHOTO_CUDA_HPP + +#include "opencv2/core/cuda.hpp" + +namespace cv { namespace cuda { + +//! @addtogroup photo_denoise +//! @{ + +/** @brief Performs pure non local means denoising without any simplification, and thus it is not fast. + +@param src Source image. Supports only CV_8UC1, CV_8UC2 and CV_8UC3. +@param dst Destination image. +@param h Filter sigma regulating filter strength for color. +@param search_window Size of search window. +@param block_size Size of block used for computing weights. +@param borderMode Border type. See borderInterpolate for details. BORDER_REFLECT101 , +BORDER_REPLICATE , BORDER_CONSTANT , BORDER_REFLECT and BORDER_WRAP are supported for now. +@param stream Stream for the asynchronous version. + +@sa + fastNlMeansDenoising + */ +CV_EXPORTS void nonLocalMeans(InputArray src, OutputArray dst, + float h, + int search_window = 21, + int block_size = 7, + int borderMode = BORDER_DEFAULT, + Stream& stream = Stream::Null()); + +/** @brief Perform image denoising using Non-local Means Denoising algorithm + with several computational +optimizations. Noise expected to be a gaussian white noise + +@param src Input 8-bit 1-channel, 2-channel or 3-channel image. +@param dst Output image with the same size and type as src . +@param h Parameter regulating filter strength. Big h value perfectly removes noise but also +removes image details, smaller h value preserves details but also preserves some noise +@param search_window Size in pixels of the window that is used to compute weighted average for +given pixel. Should be odd. Affect performance linearly: greater search_window - greater +denoising time. Recommended value 21 pixels +@param block_size Size in pixels of the template patch that is used to compute weights. Should be +odd. Recommended value 7 pixels +@param stream Stream for the asynchronous invocations. + +This function expected to be applied to grayscale images. For colored images look at +FastNonLocalMeansDenoising::labMethod. + +@sa + fastNlMeansDenoising + */ +CV_EXPORTS void fastNlMeansDenoising(InputArray src, OutputArray dst, + float h, + int search_window = 21, + int block_size = 7, + Stream& stream = Stream::Null()); + +/** @brief Modification of fastNlMeansDenoising function for colored images + +@param src Input 8-bit 3-channel image. +@param dst Output image with the same size and type as src . +@param h_luminance Parameter regulating filter strength. Big h value perfectly removes noise but +also removes image details, smaller h value preserves details but also preserves some noise +@param photo_render float The same as h but for color components. For most images value equals 10 will be +enough to remove colored noise and do not distort colors +@param search_window Size in pixels of the window that is used to compute weighted average for +given pixel. Should be odd. Affect performance linearly: greater search_window - greater +denoising time. Recommended value 21 pixels +@param block_size Size in pixels of the template patch that is used to compute weights. Should be +odd. Recommended value 7 pixels +@param stream Stream for the asynchronous invocations. + +The function converts image to CIELAB colorspace and then separately denoise L and AB components +with given h parameters using FastNonLocalMeansDenoising::simpleMethod function. + +@sa + fastNlMeansDenoisingColored + */ +CV_EXPORTS void fastNlMeansDenoisingColored(InputArray src, OutputArray dst, + float h_luminance, float photo_render, + int search_window = 21, + int block_size = 7, + Stream& stream = Stream::Null()); + +//! @} photo + +}} // namespace cv { namespace cuda { + +#endif /* OPENCV_PHOTO_CUDA_HPP */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/photo/legacy/constants_c.h b/duix-sdk/src/main/cpp/third/arm/include/opencv2/photo/legacy/constants_c.h new file mode 100644 index 0000000..ec1d440 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/photo/legacy/constants_c.h @@ -0,0 +1,14 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_PHOTO_LEGACY_CONSTANTS_H +#define OPENCV_PHOTO_LEGACY_CONSTANTS_H + +enum InpaintingModes +{ + CV_INPAINT_NS =0, + CV_INPAINT_TELEA =1 +}; + +#endif // OPENCV_PHOTO_LEGACY_CONSTANTS_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/photo/photo.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/photo/photo.hpp new file mode 100644 index 0000000..8af5e9f --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/photo/photo.hpp @@ -0,0 +1,48 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifdef __OPENCV_BUILD +#error this is a compatibility header which should not be used inside the OpenCV library +#endif + +#include "opencv2/photo.hpp" diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/video.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/video.hpp new file mode 100644 index 0000000..a3dde60 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/video.hpp @@ -0,0 +1,59 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_VIDEO_HPP +#define OPENCV_VIDEO_HPP + +/** + @defgroup video Video Analysis + @{ + @defgroup video_motion Motion Analysis + @defgroup video_track Object Tracking + @defgroup video_c C API + @} +*/ + +#include "opencv2/video/tracking.hpp" +#include "opencv2/video/background_segm.hpp" + +#endif //OPENCV_VIDEO_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/video/background_segm.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/video/background_segm.hpp new file mode 100644 index 0000000..e1dfa15 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/video/background_segm.hpp @@ -0,0 +1,317 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_BACKGROUND_SEGM_HPP +#define OPENCV_BACKGROUND_SEGM_HPP + +#include "opencv2/core.hpp" + +namespace cv +{ + +//! @addtogroup video_motion +//! @{ + +/** @brief Base class for background/foreground segmentation. : + +The class is only used to define the common interface for the whole family of background/foreground +segmentation algorithms. + */ +class CV_EXPORTS_W BackgroundSubtractor : public Algorithm +{ +public: + /** @brief Computes a foreground mask. + + @param image Next video frame. + @param fgmask The output foreground mask as an 8-bit binary image. + @param learningRate The value between 0 and 1 that indicates how fast the background model is + learnt. Negative parameter value makes the algorithm to use some automatically chosen learning + rate. 0 means that the background model is not updated at all, 1 means that the background model + is completely reinitialized from the last frame. + */ + CV_WRAP virtual void apply(InputArray image, OutputArray fgmask, double learningRate=-1) = 0; + + /** @brief Computes a background image. + + @param backgroundImage The output background image. + + @note Sometimes the background image can be very blurry, as it contain the average background + statistics. + */ + CV_WRAP virtual void getBackgroundImage(OutputArray backgroundImage) const = 0; +}; + + +/** @brief Gaussian Mixture-based Background/Foreground Segmentation Algorithm. + +The class implements the Gaussian mixture model background subtraction described in @cite Zivkovic2004 +and @cite Zivkovic2006 . + */ +class CV_EXPORTS_W BackgroundSubtractorMOG2 : public BackgroundSubtractor +{ +public: + /** @brief Returns the number of last frames that affect the background model + */ + CV_WRAP virtual int getHistory() const = 0; + /** @brief Sets the number of last frames that affect the background model + */ + CV_WRAP virtual void setHistory(int history) = 0; + + /** @brief Returns the number of gaussian components in the background model + */ + CV_WRAP virtual int getNMixtures() const = 0; + /** @brief Sets the number of gaussian components in the background model. + + The model needs to be reinitalized to reserve memory. + */ + CV_WRAP virtual void setNMixtures(int nmixtures) = 0;//needs reinitialization! + + /** @brief Returns the "background ratio" parameter of the algorithm + + If a foreground pixel keeps semi-constant value for about backgroundRatio\*history frames, it's + considered background and added to the model as a center of a new component. It corresponds to TB + parameter in the paper. + */ + CV_WRAP virtual double getBackgroundRatio() const = 0; + /** @brief Sets the "background ratio" parameter of the algorithm + */ + CV_WRAP virtual void setBackgroundRatio(double ratio) = 0; + + /** @brief Returns the variance threshold for the pixel-model match + + The main threshold on the squared Mahalanobis distance to decide if the sample is well described by + the background model or not. Related to Cthr from the paper. + */ + CV_WRAP virtual double getVarThreshold() const = 0; + /** @brief Sets the variance threshold for the pixel-model match + */ + CV_WRAP virtual void setVarThreshold(double varThreshold) = 0; + + /** @brief Returns the variance threshold for the pixel-model match used for new mixture component generation + + Threshold for the squared Mahalanobis distance that helps decide when a sample is close to the + existing components (corresponds to Tg in the paper). If a pixel is not close to any component, it + is considered foreground or added as a new component. 3 sigma =\> Tg=3\*3=9 is default. A smaller Tg + value generates more components. A higher Tg value may result in a small number of components but + they can grow too large. + */ + CV_WRAP virtual double getVarThresholdGen() const = 0; + /** @brief Sets the variance threshold for the pixel-model match used for new mixture component generation + */ + CV_WRAP virtual void setVarThresholdGen(double varThresholdGen) = 0; + + /** @brief Returns the initial variance of each gaussian component + */ + CV_WRAP virtual double getVarInit() const = 0; + /** @brief Sets the initial variance of each gaussian component + */ + CV_WRAP virtual void setVarInit(double varInit) = 0; + + CV_WRAP virtual double getVarMin() const = 0; + CV_WRAP virtual void setVarMin(double varMin) = 0; + + CV_WRAP virtual double getVarMax() const = 0; + CV_WRAP virtual void setVarMax(double varMax) = 0; + + /** @brief Returns the complexity reduction threshold + + This parameter defines the number of samples needed to accept to prove the component exists. CT=0.05 + is a default value for all the samples. By setting CT=0 you get an algorithm very similar to the + standard Stauffer&Grimson algorithm. + */ + CV_WRAP virtual double getComplexityReductionThreshold() const = 0; + /** @brief Sets the complexity reduction threshold + */ + CV_WRAP virtual void setComplexityReductionThreshold(double ct) = 0; + + /** @brief Returns the shadow detection flag + + If true, the algorithm detects shadows and marks them. See createBackgroundSubtractorMOG2 for + details. + */ + CV_WRAP virtual bool getDetectShadows() const = 0; + /** @brief Enables or disables shadow detection + */ + CV_WRAP virtual void setDetectShadows(bool detectShadows) = 0; + + /** @brief Returns the shadow value + + Shadow value is the value used to mark shadows in the foreground mask. Default value is 127. Value 0 + in the mask always means background, 255 means foreground. + */ + CV_WRAP virtual int getShadowValue() const = 0; + /** @brief Sets the shadow value + */ + CV_WRAP virtual void setShadowValue(int value) = 0; + + /** @brief Returns the shadow threshold + + A shadow is detected if pixel is a darker version of the background. The shadow threshold (Tau in + the paper) is a threshold defining how much darker the shadow can be. Tau= 0.5 means that if a pixel + is more than twice darker then it is not shadow. See Prati, Mikic, Trivedi and Cucchiara, + *Detecting Moving Shadows...*, IEEE PAMI,2003. + */ + CV_WRAP virtual double getShadowThreshold() const = 0; + /** @brief Sets the shadow threshold + */ + CV_WRAP virtual void setShadowThreshold(double threshold) = 0; + + /** @brief Computes a foreground mask. + + @param image Next video frame. Floating point frame will be used without scaling and should be in range \f$[0,255]\f$. + @param fgmask The output foreground mask as an 8-bit binary image. + @param learningRate The value between 0 and 1 that indicates how fast the background model is + learnt. Negative parameter value makes the algorithm to use some automatically chosen learning + rate. 0 means that the background model is not updated at all, 1 means that the background model + is completely reinitialized from the last frame. + */ + CV_WRAP virtual void apply(InputArray image, OutputArray fgmask, double learningRate=-1) CV_OVERRIDE = 0; +}; + +/** @brief Creates MOG2 Background Subtractor + +@param history Length of the history. +@param varThreshold Threshold on the squared Mahalanobis distance between the pixel and the model +to decide whether a pixel is well described by the background model. This parameter does not +affect the background update. +@param detectShadows If true, the algorithm will detect shadows and mark them. It decreases the +speed a bit, so if you do not need this feature, set the parameter to false. + */ +CV_EXPORTS_W Ptr + createBackgroundSubtractorMOG2(int history=500, double varThreshold=16, + bool detectShadows=true); + +/** @brief K-nearest neighbours - based Background/Foreground Segmentation Algorithm. + +The class implements the K-nearest neighbours background subtraction described in @cite Zivkovic2006 . +Very efficient if number of foreground pixels is low. + */ +class CV_EXPORTS_W BackgroundSubtractorKNN : public BackgroundSubtractor +{ +public: + /** @brief Returns the number of last frames that affect the background model + */ + CV_WRAP virtual int getHistory() const = 0; + /** @brief Sets the number of last frames that affect the background model + */ + CV_WRAP virtual void setHistory(int history) = 0; + + /** @brief Returns the number of data samples in the background model + */ + CV_WRAP virtual int getNSamples() const = 0; + /** @brief Sets the number of data samples in the background model. + + The model needs to be reinitalized to reserve memory. + */ + CV_WRAP virtual void setNSamples(int _nN) = 0;//needs reinitialization! + + /** @brief Returns the threshold on the squared distance between the pixel and the sample + + The threshold on the squared distance between the pixel and the sample to decide whether a pixel is + close to a data sample. + */ + CV_WRAP virtual double getDist2Threshold() const = 0; + /** @brief Sets the threshold on the squared distance + */ + CV_WRAP virtual void setDist2Threshold(double _dist2Threshold) = 0; + + /** @brief Returns the number of neighbours, the k in the kNN. + + K is the number of samples that need to be within dist2Threshold in order to decide that that + pixel is matching the kNN background model. + */ + CV_WRAP virtual int getkNNSamples() const = 0; + /** @brief Sets the k in the kNN. How many nearest neighbours need to match. + */ + CV_WRAP virtual void setkNNSamples(int _nkNN) = 0; + + /** @brief Returns the shadow detection flag + + If true, the algorithm detects shadows and marks them. See createBackgroundSubtractorKNN for + details. + */ + CV_WRAP virtual bool getDetectShadows() const = 0; + /** @brief Enables or disables shadow detection + */ + CV_WRAP virtual void setDetectShadows(bool detectShadows) = 0; + + /** @brief Returns the shadow value + + Shadow value is the value used to mark shadows in the foreground mask. Default value is 127. Value 0 + in the mask always means background, 255 means foreground. + */ + CV_WRAP virtual int getShadowValue() const = 0; + /** @brief Sets the shadow value + */ + CV_WRAP virtual void setShadowValue(int value) = 0; + + /** @brief Returns the shadow threshold + + A shadow is detected if pixel is a darker version of the background. The shadow threshold (Tau in + the paper) is a threshold defining how much darker the shadow can be. Tau= 0.5 means that if a pixel + is more than twice darker then it is not shadow. See Prati, Mikic, Trivedi and Cucchiara, + *Detecting Moving Shadows...*, IEEE PAMI,2003. + */ + CV_WRAP virtual double getShadowThreshold() const = 0; + /** @brief Sets the shadow threshold + */ + CV_WRAP virtual void setShadowThreshold(double threshold) = 0; +}; + +/** @brief Creates KNN Background Subtractor + +@param history Length of the history. +@param dist2Threshold Threshold on the squared distance between the pixel and the sample to decide +whether a pixel is close to that sample. This parameter does not affect the background update. +@param detectShadows If true, the algorithm will detect shadows and mark them. It decreases the +speed a bit, so if you do not need this feature, set the parameter to false. + */ +CV_EXPORTS_W Ptr + createBackgroundSubtractorKNN(int history=500, double dist2Threshold=400.0, + bool detectShadows=true); + +//! @} video_motion + +} // cv + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/video/detail/tracking.detail.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/video/detail/tracking.detail.hpp new file mode 100644 index 0000000..1e61079 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/video/detail/tracking.detail.hpp @@ -0,0 +1,406 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_VIDEO_DETAIL_TRACKING_HPP +#define OPENCV_VIDEO_DETAIL_TRACKING_HPP + +/* + * Partially based on: + * ==================================================================================================================== + * - [AAM] S. Salti, A. Cavallaro, L. Di Stefano, Adaptive Appearance Modeling for Video Tracking: Survey and Evaluation + * - [AMVOT] X. Li, W. Hu, C. Shen, Z. Zhang, A. Dick, A. van den Hengel, A Survey of Appearance Models in Visual Object Tracking + * + * This Tracking API has been designed with PlantUML. If you modify this API please change UML files under modules/tracking/doc/uml + * + */ + +#include "opencv2/core.hpp" + +namespace cv { +namespace detail { +inline namespace tracking { + +/** @addtogroup tracking_detail +@{ +*/ + +/************************************ TrackerFeature Base Classes ************************************/ + +/** @brief Abstract base class for TrackerFeature that represents the feature. +*/ +class CV_EXPORTS TrackerFeature +{ +public: + virtual ~TrackerFeature(); + + /** @brief Compute the features in the images collection + @param images The images + @param response The output response + */ + void compute(const std::vector& images, Mat& response); + +protected: + virtual bool computeImpl(const std::vector& images, Mat& response) = 0; +}; + +/** @brief Class that manages the extraction and selection of features + +@cite AAM Feature Extraction and Feature Set Refinement (Feature Processing and Feature Selection). +See table I and section III C @cite AMVOT Appearance modelling -\> Visual representation (Table II, +section 3.1 - 3.2) + +TrackerFeatureSet is an aggregation of TrackerFeature + +@sa + TrackerFeature + +*/ +class CV_EXPORTS TrackerFeatureSet +{ +public: + TrackerFeatureSet(); + + ~TrackerFeatureSet(); + + /** @brief Extract features from the images collection + @param images The input images + */ + void extraction(const std::vector& images); + + /** @brief Add TrackerFeature in the collection. Return true if TrackerFeature is added, false otherwise + @param feature The TrackerFeature class + */ + bool addTrackerFeature(const Ptr& feature); + + /** @brief Get the TrackerFeature collection (TrackerFeature name, TrackerFeature pointer) + */ + const std::vector>& getTrackerFeatures() const; + + /** @brief Get the responses + @note Be sure to call extraction before getResponses Example TrackerFeatureSet::getResponses + */ + const std::vector& getResponses() const; + +private: + void clearResponses(); + bool blockAddTrackerFeature; + + std::vector> features; // list of features + std::vector responses; // list of response after compute +}; + +/************************************ TrackerSampler Base Classes ************************************/ + +/** @brief Abstract base class for TrackerSamplerAlgorithm that represents the algorithm for the specific +sampler. +*/ +class CV_EXPORTS TrackerSamplerAlgorithm +{ +public: + virtual ~TrackerSamplerAlgorithm(); + + /** @brief Computes the regions starting from a position in an image. + + Return true if samples are computed, false otherwise + + @param image The current frame + @param boundingBox The bounding box from which regions can be calculated + + @param sample The computed samples @cite AAM Fig. 1 variable Sk + */ + virtual bool sampling(const Mat& image, const Rect& boundingBox, std::vector& sample) = 0; +}; + +/** + * \brief Class that manages the sampler in order to select regions for the update the model of the tracker + * [AAM] Sampling e Labeling. See table I and section III B + */ + +/** @brief Class that manages the sampler in order to select regions for the update the model of the tracker + +@cite AAM Sampling e Labeling. See table I and section III B + +TrackerSampler is an aggregation of TrackerSamplerAlgorithm +@sa + TrackerSamplerAlgorithm + */ +class CV_EXPORTS TrackerSampler +{ +public: + TrackerSampler(); + + ~TrackerSampler(); + + /** @brief Computes the regions starting from a position in an image + @param image The current frame + @param boundingBox The bounding box from which regions can be calculated + */ + void sampling(const Mat& image, Rect boundingBox); + + /** @brief Return the collection of the TrackerSamplerAlgorithm + */ + const std::vector>& getSamplers() const; + + /** @brief Return the samples from all TrackerSamplerAlgorithm, @cite AAM Fig. 1 variable Sk + */ + const std::vector& getSamples() const; + + /** @brief Add TrackerSamplerAlgorithm in the collection. Return true if sampler is added, false otherwise + @param sampler The TrackerSamplerAlgorithm + */ + bool addTrackerSamplerAlgorithm(const Ptr& sampler); + +private: + std::vector> samplers; + std::vector samples; + bool blockAddTrackerSampler; + + void clearSamples(); +}; + +/************************************ TrackerModel Base Classes ************************************/ + +/** @brief Abstract base class for TrackerTargetState that represents a possible state of the target. + +See @cite AAM \f$\hat{x}^{i}_{k}\f$ all the states candidates. + +Inherits this class with your Target state, In own implementation you can add scale variation, +width, height, orientation, etc. +*/ +class CV_EXPORTS TrackerTargetState +{ +public: + virtual ~TrackerTargetState() {}; + /** @brief Get the position + * @return The position + */ + Point2f getTargetPosition() const; + + /** @brief Set the position + * @param position The position + */ + void setTargetPosition(const Point2f& position); + /** @brief Get the width of the target + * @return The width of the target + */ + int getTargetWidth() const; + + /** @brief Set the width of the target + * @param width The width of the target + */ + void setTargetWidth(int width); + /** @brief Get the height of the target + * @return The height of the target + */ + int getTargetHeight() const; + + /** @brief Set the height of the target + * @param height The height of the target + */ + void setTargetHeight(int height); + +protected: + Point2f targetPosition; + int targetWidth; + int targetHeight; +}; + +/** @brief Represents the model of the target at frame \f$k\f$ (all states and scores) + +See @cite AAM The set of the pair \f$\langle \hat{x}^{i}_{k}, C^{i}_{k} \rangle\f$ +@sa TrackerTargetState +*/ +typedef std::vector, float>> ConfidenceMap; + +/** @brief Represents the estimate states for all frames + +@cite AAM \f$x_{k}\f$ is the trajectory of the target up to time \f$k\f$ + +@sa TrackerTargetState +*/ +typedef std::vector> Trajectory; + +/** @brief Abstract base class for TrackerStateEstimator that estimates the most likely target state. + +See @cite AAM State estimator + +See @cite AMVOT Statistical modeling (Fig. 3), Table III (generative) - IV (discriminative) - V (hybrid) +*/ +class CV_EXPORTS TrackerStateEstimator +{ +public: + virtual ~TrackerStateEstimator(); + + /** @brief Estimate the most likely target state, return the estimated state + @param confidenceMaps The overall appearance model as a list of :cConfidenceMap + */ + Ptr estimate(const std::vector& confidenceMaps); + + /** @brief Update the ConfidenceMap with the scores + @param confidenceMaps The overall appearance model as a list of :cConfidenceMap + */ + void update(std::vector& confidenceMaps); + + /** @brief Create TrackerStateEstimator by tracker state estimator type + @param trackeStateEstimatorType The TrackerStateEstimator name + + The modes available now: + + - "BOOSTING" -- Boosting-based discriminative appearance models. See @cite AMVOT section 4.4 + + The modes available soon: + + - "SVM" -- SVM-based discriminative appearance models. See @cite AMVOT section 4.5 + */ + static Ptr create(const String& trackeStateEstimatorType); + + /** @brief Get the name of the specific TrackerStateEstimator + */ + String getClassName() const; + +protected: + virtual Ptr estimateImpl(const std::vector& confidenceMaps) = 0; + virtual void updateImpl(std::vector& confidenceMaps) = 0; + String className; +}; + +/** @brief Abstract class that represents the model of the target. + +It must be instantiated by specialized tracker + +See @cite AAM Ak + +Inherits this with your TrackerModel +*/ +class CV_EXPORTS TrackerModel +{ +public: + TrackerModel(); + + virtual ~TrackerModel(); + + /** @brief Set TrackerEstimator, return true if the tracker state estimator is added, false otherwise + @param trackerStateEstimator The TrackerStateEstimator + @note You can add only one TrackerStateEstimator + */ + bool setTrackerStateEstimator(Ptr trackerStateEstimator); + + /** @brief Estimate the most likely target location + + @cite AAM ME, Model Estimation table I + @param responses Features extracted from TrackerFeatureSet + */ + void modelEstimation(const std::vector& responses); + + /** @brief Update the model + + @cite AAM MU, Model Update table I + */ + void modelUpdate(); + + /** @brief Run the TrackerStateEstimator, return true if is possible to estimate a new state, false otherwise + */ + bool runStateEstimator(); + + /** @brief Set the current TrackerTargetState in the Trajectory + @param lastTargetState The current TrackerTargetState + */ + void setLastTargetState(const Ptr& lastTargetState); + + /** @brief Get the last TrackerTargetState from Trajectory + */ + Ptr getLastTargetState() const; + + /** @brief Get the list of the ConfidenceMap + */ + const std::vector& getConfidenceMaps() const; + + /** @brief Get the last ConfidenceMap for the current frame + */ + const ConfidenceMap& getLastConfidenceMap() const; + + /** @brief Get the TrackerStateEstimator + */ + Ptr getTrackerStateEstimator() const; + +private: + void clearCurrentConfidenceMap(); + +protected: + std::vector confidenceMaps; + Ptr stateEstimator; + ConfidenceMap currentConfidenceMap; + Trajectory trajectory; + int maxCMLength; + + virtual void modelEstimationImpl(const std::vector& responses) = 0; + virtual void modelUpdateImpl() = 0; +}; + +/************************************ Specific TrackerStateEstimator Classes ************************************/ + +// None + +/************************************ Specific TrackerSamplerAlgorithm Classes ************************************/ + +/** @brief TrackerSampler based on CSC (current state centered), used by MIL algorithm TrackerMIL + */ +class CV_EXPORTS TrackerSamplerCSC : public TrackerSamplerAlgorithm +{ +public: + ~TrackerSamplerCSC(); + + enum MODE + { + MODE_INIT_POS = 1, //!< mode for init positive samples + MODE_INIT_NEG = 2, //!< mode for init negative samples + MODE_TRACK_POS = 3, //!< mode for update positive samples + MODE_TRACK_NEG = 4, //!< mode for update negative samples + MODE_DETECT = 5 //!< mode for detect samples + }; + + struct CV_EXPORTS Params + { + Params(); + float initInRad; //!< radius for gathering positive instances during init + float trackInPosRad; //!< radius for gathering positive instances during tracking + float searchWinSize; //!< size of search window + int initMaxNegNum; //!< # negative samples to use during init + int trackMaxPosNum; //!< # positive samples to use during training + int trackMaxNegNum; //!< # negative samples to use during training + }; + + /** @brief Constructor + @param parameters TrackerSamplerCSC parameters TrackerSamplerCSC::Params + */ + TrackerSamplerCSC(const TrackerSamplerCSC::Params& parameters = TrackerSamplerCSC::Params()); + + /** @brief Set the sampling mode of TrackerSamplerCSC + @param samplingMode The sampling mode + + The modes are: + + - "MODE_INIT_POS = 1" -- for the positive sampling in initialization step + - "MODE_INIT_NEG = 2" -- for the negative sampling in initialization step + - "MODE_TRACK_POS = 3" -- for the positive sampling in update step + - "MODE_TRACK_NEG = 4" -- for the negative sampling in update step + - "MODE_DETECT = 5" -- for the sampling in detection step + */ + void setMode(int samplingMode); + + bool sampling(const Mat& image, const Rect& boundingBox, std::vector& sample) CV_OVERRIDE; + +private: + Params params; + int mode; + RNG rng; + + std::vector sampleImage(const Mat& img, int x, int y, int w, int h, float inrad, float outrad = 0, int maxnum = 1000000); +}; + +//! @} + +}}} // namespace cv::detail::tracking + +#endif // OPENCV_VIDEO_DETAIL_TRACKING_HPP diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/video/legacy/constants_c.h b/duix-sdk/src/main/cpp/third/arm/include/opencv2/video/legacy/constants_c.h new file mode 100644 index 0000000..1a98f52 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/video/legacy/constants_c.h @@ -0,0 +1,16 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_VIDEO_LEGACY_CONSTANTS_H +#define OPENCV_VIDEO_LEGACY_CONSTANTS_H + +enum +{ + CV_LKFLOW_PYR_A_READY = 1, + CV_LKFLOW_PYR_B_READY = 2, + CV_LKFLOW_INITIAL_GUESSES = 4, + CV_LKFLOW_GET_MIN_EIGENVALS = 8 +}; + +#endif // OPENCV_VIDEO_LEGACY_CONSTANTS_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/video/tracking.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/video/tracking.hpp new file mode 100644 index 0000000..7ec6bc5 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/video/tracking.hpp @@ -0,0 +1,857 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifndef OPENCV_TRACKING_HPP +#define OPENCV_TRACKING_HPP + +#include "opencv2/core.hpp" +#include "opencv2/imgproc.hpp" + +namespace cv +{ + +//! @addtogroup video_track +//! @{ + +enum { OPTFLOW_USE_INITIAL_FLOW = 4, + OPTFLOW_LK_GET_MIN_EIGENVALS = 8, + OPTFLOW_FARNEBACK_GAUSSIAN = 256 + }; + +/** @brief Finds an object center, size, and orientation. + +@param probImage Back projection of the object histogram. See calcBackProject. +@param window Initial search window. +@param criteria Stop criteria for the underlying meanShift. +returns +(in old interfaces) Number of iterations CAMSHIFT took to converge +The function implements the CAMSHIFT object tracking algorithm @cite Bradski98 . First, it finds an +object center using meanShift and then adjusts the window size and finds the optimal rotation. The +function returns the rotated rectangle structure that includes the object position, size, and +orientation. The next position of the search window can be obtained with RotatedRect::boundingRect() + +See the OpenCV sample camshiftdemo.c that tracks colored objects. + +@note +- (Python) A sample explaining the camshift tracking algorithm can be found at + opencv_source_code/samples/python/camshift.py + */ +CV_EXPORTS_W RotatedRect CamShift( InputArray probImage, CV_IN_OUT Rect& window, + TermCriteria criteria ); +/** @example samples/cpp/camshiftdemo.cpp +An example using the mean-shift tracking algorithm +*/ + +/** @brief Finds an object on a back projection image. + +@param probImage Back projection of the object histogram. See calcBackProject for details. +@param window Initial search window. +@param criteria Stop criteria for the iterative search algorithm. +returns +: Number of iterations CAMSHIFT took to converge. +The function implements the iterative object search algorithm. It takes the input back projection of +an object and the initial position. The mass center in window of the back projection image is +computed and the search window center shifts to the mass center. The procedure is repeated until the +specified number of iterations criteria.maxCount is done or until the window center shifts by less +than criteria.epsilon. The algorithm is used inside CamShift and, unlike CamShift , the search +window size or orientation do not change during the search. You can simply pass the output of +calcBackProject to this function. But better results can be obtained if you pre-filter the back +projection and remove the noise. For example, you can do this by retrieving connected components +with findContours , throwing away contours with small area ( contourArea ), and rendering the +remaining contours with drawContours. + + */ +CV_EXPORTS_W int meanShift( InputArray probImage, CV_IN_OUT Rect& window, TermCriteria criteria ); + +/** @brief Constructs the image pyramid which can be passed to calcOpticalFlowPyrLK. + +@param img 8-bit input image. +@param pyramid output pyramid. +@param winSize window size of optical flow algorithm. Must be not less than winSize argument of +calcOpticalFlowPyrLK. It is needed to calculate required padding for pyramid levels. +@param maxLevel 0-based maximal pyramid level number. +@param withDerivatives set to precompute gradients for the every pyramid level. If pyramid is +constructed without the gradients then calcOpticalFlowPyrLK will calculate them internally. +@param pyrBorder the border mode for pyramid layers. +@param derivBorder the border mode for gradients. +@param tryReuseInputImage put ROI of input image into the pyramid if possible. You can pass false +to force data copying. +@return number of levels in constructed pyramid. Can be less than maxLevel. + */ +CV_EXPORTS_W int buildOpticalFlowPyramid( InputArray img, OutputArrayOfArrays pyramid, + Size winSize, int maxLevel, bool withDerivatives = true, + int pyrBorder = BORDER_REFLECT_101, + int derivBorder = BORDER_CONSTANT, + bool tryReuseInputImage = true ); + +/** @example samples/cpp/lkdemo.cpp +An example using the Lucas-Kanade optical flow algorithm +*/ + +/** @brief Calculates an optical flow for a sparse feature set using the iterative Lucas-Kanade method with +pyramids. + +@param prevImg first 8-bit input image or pyramid constructed by buildOpticalFlowPyramid. +@param nextImg second input image or pyramid of the same size and the same type as prevImg. +@param prevPts vector of 2D points for which the flow needs to be found; point coordinates must be +single-precision floating-point numbers. +@param nextPts output vector of 2D points (with single-precision floating-point coordinates) +containing the calculated new positions of input features in the second image; when +OPTFLOW_USE_INITIAL_FLOW flag is passed, the vector must have the same size as in the input. +@param status output status vector (of unsigned chars); each element of the vector is set to 1 if +the flow for the corresponding features has been found, otherwise, it is set to 0. +@param err output vector of errors; each element of the vector is set to an error for the +corresponding feature, type of the error measure can be set in flags parameter; if the flow wasn't +found then the error is not defined (use the status parameter to find such cases). +@param winSize size of the search window at each pyramid level. +@param maxLevel 0-based maximal pyramid level number; if set to 0, pyramids are not used (single +level), if set to 1, two levels are used, and so on; if pyramids are passed to input then +algorithm will use as many levels as pyramids have but no more than maxLevel. +@param criteria parameter, specifying the termination criteria of the iterative search algorithm +(after the specified maximum number of iterations criteria.maxCount or when the search window +moves by less than criteria.epsilon. +@param flags operation flags: + - **OPTFLOW_USE_INITIAL_FLOW** uses initial estimations, stored in nextPts; if the flag is + not set, then prevPts is copied to nextPts and is considered the initial estimate. + - **OPTFLOW_LK_GET_MIN_EIGENVALS** use minimum eigen values as an error measure (see + minEigThreshold description); if the flag is not set, then L1 distance between patches + around the original and a moved point, divided by number of pixels in a window, is used as a + error measure. +@param minEigThreshold the algorithm calculates the minimum eigen value of a 2x2 normal matrix of +optical flow equations (this matrix is called a spatial gradient matrix in @cite Bouguet00), divided +by number of pixels in a window; if this value is less than minEigThreshold, then a corresponding +feature is filtered out and its flow is not processed, so it allows to remove bad points and get a +performance boost. + +The function implements a sparse iterative version of the Lucas-Kanade optical flow in pyramids. See +@cite Bouguet00 . The function is parallelized with the TBB library. + +@note + +- An example using the Lucas-Kanade optical flow algorithm can be found at + opencv_source_code/samples/cpp/lkdemo.cpp +- (Python) An example using the Lucas-Kanade optical flow algorithm can be found at + opencv_source_code/samples/python/lk_track.py +- (Python) An example using the Lucas-Kanade tracker for homography matching can be found at + opencv_source_code/samples/python/lk_homography.py + */ +CV_EXPORTS_W void calcOpticalFlowPyrLK( InputArray prevImg, InputArray nextImg, + InputArray prevPts, InputOutputArray nextPts, + OutputArray status, OutputArray err, + Size winSize = Size(21,21), int maxLevel = 3, + TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01), + int flags = 0, double minEigThreshold = 1e-4 ); + +/** @brief Computes a dense optical flow using the Gunnar Farneback's algorithm. + +@param prev first 8-bit single-channel input image. +@param next second input image of the same size and the same type as prev. +@param flow computed flow image that has the same size as prev and type CV_32FC2. +@param pyr_scale parameter, specifying the image scale (\<1) to build pyramids for each image; +pyr_scale=0.5 means a classical pyramid, where each next layer is twice smaller than the previous +one. +@param levels number of pyramid layers including the initial image; levels=1 means that no extra +layers are created and only the original images are used. +@param winsize averaging window size; larger values increase the algorithm robustness to image +noise and give more chances for fast motion detection, but yield more blurred motion field. +@param iterations number of iterations the algorithm does at each pyramid level. +@param poly_n size of the pixel neighborhood used to find polynomial expansion in each pixel; +larger values mean that the image will be approximated with smoother surfaces, yielding more +robust algorithm and more blurred motion field, typically poly_n =5 or 7. +@param poly_sigma standard deviation of the Gaussian that is used to smooth derivatives used as a +basis for the polynomial expansion; for poly_n=5, you can set poly_sigma=1.1, for poly_n=7, a +good value would be poly_sigma=1.5. +@param flags operation flags that can be a combination of the following: + - **OPTFLOW_USE_INITIAL_FLOW** uses the input flow as an initial flow approximation. + - **OPTFLOW_FARNEBACK_GAUSSIAN** uses the Gaussian \f$\texttt{winsize}\times\texttt{winsize}\f$ + filter instead of a box filter of the same size for optical flow estimation; usually, this + option gives z more accurate flow than with a box filter, at the cost of lower speed; + normally, winsize for a Gaussian window should be set to a larger value to achieve the same + level of robustness. + +The function finds an optical flow for each prev pixel using the @cite Farneback2003 algorithm so that + +\f[\texttt{prev} (y,x) \sim \texttt{next} ( y + \texttt{flow} (y,x)[1], x + \texttt{flow} (y,x)[0])\f] + +@note + +- An example using the optical flow algorithm described by Gunnar Farneback can be found at + opencv_source_code/samples/cpp/fback.cpp +- (Python) An example using the optical flow algorithm described by Gunnar Farneback can be + found at opencv_source_code/samples/python/opt_flow.py + */ +CV_EXPORTS_W void calcOpticalFlowFarneback( InputArray prev, InputArray next, InputOutputArray flow, + double pyr_scale, int levels, int winsize, + int iterations, int poly_n, double poly_sigma, + int flags ); + +/** @brief Computes an optimal affine transformation between two 2D point sets. + +@param src First input 2D point set stored in std::vector or Mat, or an image stored in Mat. +@param dst Second input 2D point set of the same size and the same type as A, or another image. +@param fullAffine If true, the function finds an optimal affine transformation with no additional +restrictions (6 degrees of freedom). Otherwise, the class of transformations to choose from is +limited to combinations of translation, rotation, and uniform scaling (4 degrees of freedom). + +The function finds an optimal affine transform *[A|b]* (a 2 x 3 floating-point matrix) that +approximates best the affine transformation between: + +* Two point sets +* Two raster images. In this case, the function first finds some features in the src image and + finds the corresponding features in dst image. After that, the problem is reduced to the first + case. +In case of point sets, the problem is formulated as follows: you need to find a 2x2 matrix *A* and +2x1 vector *b* so that: + +\f[[A^*|b^*] = arg \min _{[A|b]} \sum _i \| \texttt{dst}[i] - A { \texttt{src}[i]}^T - b \| ^2\f] +where src[i] and dst[i] are the i-th points in src and dst, respectively +\f$[A|b]\f$ can be either arbitrary (when fullAffine=true ) or have a form of +\f[\begin{bmatrix} a_{11} & a_{12} & b_1 \\ -a_{12} & a_{11} & b_2 \end{bmatrix}\f] +when fullAffine=false. + +@deprecated Use cv::estimateAffine2D, cv::estimateAffinePartial2D instead. If you are using this function +with images, extract points using cv::calcOpticalFlowPyrLK and then use the estimation functions. + +@sa +estimateAffine2D, estimateAffinePartial2D, getAffineTransform, getPerspectiveTransform, findHomography + */ +CV_DEPRECATED CV_EXPORTS Mat estimateRigidTransform( InputArray src, InputArray dst, bool fullAffine ); + +enum +{ + MOTION_TRANSLATION = 0, + MOTION_EUCLIDEAN = 1, + MOTION_AFFINE = 2, + MOTION_HOMOGRAPHY = 3 +}; + +/** @brief Computes the Enhanced Correlation Coefficient value between two images @cite EP08 . + +@param templateImage single-channel template image; CV_8U or CV_32F array. +@param inputImage single-channel input image to be warped to provide an image similar to + templateImage, same type as templateImage. +@param inputMask An optional mask to indicate valid values of inputImage. + +@sa +findTransformECC + */ + +CV_EXPORTS_W double computeECC(InputArray templateImage, InputArray inputImage, InputArray inputMask = noArray()); + +/** @example samples/cpp/image_alignment.cpp +An example using the image alignment ECC algorithm +*/ + +/** @brief Finds the geometric transform (warp) between two images in terms of the ECC criterion @cite EP08 . + +@param templateImage single-channel template image; CV_8U or CV_32F array. +@param inputImage single-channel input image which should be warped with the final warpMatrix in +order to provide an image similar to templateImage, same type as templateImage. +@param warpMatrix floating-point \f$2\times 3\f$ or \f$3\times 3\f$ mapping matrix (warp). +@param motionType parameter, specifying the type of motion: + - **MOTION_TRANSLATION** sets a translational motion model; warpMatrix is \f$2\times 3\f$ with + the first \f$2\times 2\f$ part being the unity matrix and the rest two parameters being + estimated. + - **MOTION_EUCLIDEAN** sets a Euclidean (rigid) transformation as motion model; three + parameters are estimated; warpMatrix is \f$2\times 3\f$. + - **MOTION_AFFINE** sets an affine motion model (DEFAULT); six parameters are estimated; + warpMatrix is \f$2\times 3\f$. + - **MOTION_HOMOGRAPHY** sets a homography as a motion model; eight parameters are + estimated;\`warpMatrix\` is \f$3\times 3\f$. +@param criteria parameter, specifying the termination criteria of the ECC algorithm; +criteria.epsilon defines the threshold of the increment in the correlation coefficient between two +iterations (a negative criteria.epsilon makes criteria.maxcount the only termination criterion). +Default values are shown in the declaration above. +@param inputMask An optional mask to indicate valid values of inputImage. +@param gaussFiltSize An optional value indicating size of gaussian blur filter; (DEFAULT: 5) + +The function estimates the optimum transformation (warpMatrix) with respect to ECC criterion +(@cite EP08), that is + +\f[\texttt{warpMatrix} = \arg\max_{W} \texttt{ECC}(\texttt{templateImage}(x,y),\texttt{inputImage}(x',y'))\f] + +where + +\f[\begin{bmatrix} x' \\ y' \end{bmatrix} = W \cdot \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}\f] + +(the equation holds with homogeneous coordinates for homography). It returns the final enhanced +correlation coefficient, that is the correlation coefficient between the template image and the +final warped input image. When a \f$3\times 3\f$ matrix is given with motionType =0, 1 or 2, the third +row is ignored. + +Unlike findHomography and estimateRigidTransform, the function findTransformECC implements an +area-based alignment that builds on intensity similarities. In essence, the function updates the +initial transformation that roughly aligns the images. If this information is missing, the identity +warp (unity matrix) is used as an initialization. Note that if images undergo strong +displacements/rotations, an initial transformation that roughly aligns the images is necessary +(e.g., a simple euclidean/similarity transform that allows for the images showing the same image +content approximately). Use inverse warping in the second image to take an image close to the first +one, i.e. use the flag WARP_INVERSE_MAP with warpAffine or warpPerspective. See also the OpenCV +sample image_alignment.cpp that demonstrates the use of the function. Note that the function throws +an exception if algorithm does not converges. + +@sa +computeECC, estimateAffine2D, estimateAffinePartial2D, findHomography + */ +CV_EXPORTS_W double findTransformECC( InputArray templateImage, InputArray inputImage, + InputOutputArray warpMatrix, int motionType, + TermCriteria criteria, + InputArray inputMask, int gaussFiltSize); + +/** @overload */ +CV_EXPORTS_W +double findTransformECC(InputArray templateImage, InputArray inputImage, + InputOutputArray warpMatrix, int motionType = MOTION_AFFINE, + TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 50, 0.001), + InputArray inputMask = noArray()); + +/** @example samples/cpp/kalman.cpp +An example using the standard Kalman filter +*/ + +/** @brief Kalman filter class. + +The class implements a standard Kalman filter , +@cite Welch95 . However, you can modify transitionMatrix, controlMatrix, and measurementMatrix to get +an extended Kalman filter functionality. +@note In C API when CvKalman\* kalmanFilter structure is not needed anymore, it should be released +with cvReleaseKalman(&kalmanFilter) + */ +class CV_EXPORTS_W KalmanFilter +{ +public: + CV_WRAP KalmanFilter(); + /** @overload + @param dynamParams Dimensionality of the state. + @param measureParams Dimensionality of the measurement. + @param controlParams Dimensionality of the control vector. + @param type Type of the created matrices that should be CV_32F or CV_64F. + */ + CV_WRAP KalmanFilter( int dynamParams, int measureParams, int controlParams = 0, int type = CV_32F ); + + /** @brief Re-initializes Kalman filter. The previous content is destroyed. + + @param dynamParams Dimensionality of the state. + @param measureParams Dimensionality of the measurement. + @param controlParams Dimensionality of the control vector. + @param type Type of the created matrices that should be CV_32F or CV_64F. + */ + void init( int dynamParams, int measureParams, int controlParams = 0, int type = CV_32F ); + + /** @brief Computes a predicted state. + + @param control The optional input control + */ + CV_WRAP const Mat& predict( const Mat& control = Mat() ); + + /** @brief Updates the predicted state from the measurement. + + @param measurement The measured system parameters + */ + CV_WRAP const Mat& correct( const Mat& measurement ); + + CV_PROP_RW Mat statePre; //!< predicted state (x'(k)): x(k)=A*x(k-1)+B*u(k) + CV_PROP_RW Mat statePost; //!< corrected state (x(k)): x(k)=x'(k)+K(k)*(z(k)-H*x'(k)) + CV_PROP_RW Mat transitionMatrix; //!< state transition matrix (A) + CV_PROP_RW Mat controlMatrix; //!< control matrix (B) (not used if there is no control) + CV_PROP_RW Mat measurementMatrix; //!< measurement matrix (H) + CV_PROP_RW Mat processNoiseCov; //!< process noise covariance matrix (Q) + CV_PROP_RW Mat measurementNoiseCov;//!< measurement noise covariance matrix (R) + CV_PROP_RW Mat errorCovPre; //!< priori error estimate covariance matrix (P'(k)): P'(k)=A*P(k-1)*At + Q)*/ + CV_PROP_RW Mat gain; //!< Kalman gain matrix (K(k)): K(k)=P'(k)*Ht*inv(H*P'(k)*Ht+R) + CV_PROP_RW Mat errorCovPost; //!< posteriori error estimate covariance matrix (P(k)): P(k)=(I-K(k)*H)*P'(k) + + // temporary matrices + Mat temp1; + Mat temp2; + Mat temp3; + Mat temp4; + Mat temp5; +}; + + +/** @brief Read a .flo file + + @param path Path to the file to be loaded + + The function readOpticalFlow loads a flow field from a file and returns it as a single matrix. + Resulting Mat has a type CV_32FC2 - floating-point, 2-channel. First channel corresponds to the + flow in the horizontal direction (u), second - vertical (v). + */ +CV_EXPORTS_W Mat readOpticalFlow( const String& path ); +/** @brief Write a .flo to disk + + @param path Path to the file to be written + @param flow Flow field to be stored + + The function stores a flow field in a file, returns true on success, false otherwise. + The flow field must be a 2-channel, floating-point matrix (CV_32FC2). First channel corresponds + to the flow in the horizontal direction (u), second - vertical (v). + */ +CV_EXPORTS_W bool writeOpticalFlow( const String& path, InputArray flow ); + +/** + Base class for dense optical flow algorithms +*/ +class CV_EXPORTS_W DenseOpticalFlow : public Algorithm +{ +public: + /** @brief Calculates an optical flow. + + @param I0 first 8-bit single-channel input image. + @param I1 second input image of the same size and the same type as prev. + @param flow computed flow image that has the same size as prev and type CV_32FC2. + */ + CV_WRAP virtual void calc( InputArray I0, InputArray I1, InputOutputArray flow ) = 0; + /** @brief Releases all inner buffers. + */ + CV_WRAP virtual void collectGarbage() = 0; +}; + +/** @brief Base interface for sparse optical flow algorithms. + */ +class CV_EXPORTS_W SparseOpticalFlow : public Algorithm +{ +public: + /** @brief Calculates a sparse optical flow. + + @param prevImg First input image. + @param nextImg Second input image of the same size and the same type as prevImg. + @param prevPts Vector of 2D points for which the flow needs to be found. + @param nextPts Output vector of 2D points containing the calculated new positions of input features in the second image. + @param status Output status vector. Each element of the vector is set to 1 if the + flow for the corresponding features has been found. Otherwise, it is set to 0. + @param err Optional output vector that contains error response for each point (inverse confidence). + */ + CV_WRAP virtual void calc(InputArray prevImg, InputArray nextImg, + InputArray prevPts, InputOutputArray nextPts, + OutputArray status, + OutputArray err = cv::noArray()) = 0; +}; + + +/** @brief Class computing a dense optical flow using the Gunnar Farneback's algorithm. + */ +class CV_EXPORTS_W FarnebackOpticalFlow : public DenseOpticalFlow +{ +public: + CV_WRAP virtual int getNumLevels() const = 0; + CV_WRAP virtual void setNumLevels(int numLevels) = 0; + + CV_WRAP virtual double getPyrScale() const = 0; + CV_WRAP virtual void setPyrScale(double pyrScale) = 0; + + CV_WRAP virtual bool getFastPyramids() const = 0; + CV_WRAP virtual void setFastPyramids(bool fastPyramids) = 0; + + CV_WRAP virtual int getWinSize() const = 0; + CV_WRAP virtual void setWinSize(int winSize) = 0; + + CV_WRAP virtual int getNumIters() const = 0; + CV_WRAP virtual void setNumIters(int numIters) = 0; + + CV_WRAP virtual int getPolyN() const = 0; + CV_WRAP virtual void setPolyN(int polyN) = 0; + + CV_WRAP virtual double getPolySigma() const = 0; + CV_WRAP virtual void setPolySigma(double polySigma) = 0; + + CV_WRAP virtual int getFlags() const = 0; + CV_WRAP virtual void setFlags(int flags) = 0; + + CV_WRAP static Ptr create( + int numLevels = 5, + double pyrScale = 0.5, + bool fastPyramids = false, + int winSize = 13, + int numIters = 10, + int polyN = 5, + double polySigma = 1.1, + int flags = 0); +}; + +/** @brief Variational optical flow refinement + +This class implements variational refinement of the input flow field, i.e. +it uses input flow to initialize the minimization of the following functional: +\f$E(U) = \int_{\Omega} \delta \Psi(E_I) + \gamma \Psi(E_G) + \alpha \Psi(E_S) \f$, +where \f$E_I,E_G,E_S\f$ are color constancy, gradient constancy and smoothness terms +respectively. \f$\Psi(s^2)=\sqrt{s^2+\epsilon^2}\f$ is a robust penalizer to limit the +influence of outliers. A complete formulation and a description of the minimization +procedure can be found in @cite Brox2004 +*/ +class CV_EXPORTS_W VariationalRefinement : public DenseOpticalFlow +{ +public: + /** @brief @ref calc function overload to handle separate horizontal (u) and vertical (v) flow components + (to avoid extra splits/merges) */ + CV_WRAP virtual void calcUV(InputArray I0, InputArray I1, InputOutputArray flow_u, InputOutputArray flow_v) = 0; + + /** @brief Number of outer (fixed-point) iterations in the minimization procedure. + @see setFixedPointIterations */ + CV_WRAP virtual int getFixedPointIterations() const = 0; + /** @copybrief getFixedPointIterations @see getFixedPointIterations */ + CV_WRAP virtual void setFixedPointIterations(int val) = 0; + + /** @brief Number of inner successive over-relaxation (SOR) iterations + in the minimization procedure to solve the respective linear system. + @see setSorIterations */ + CV_WRAP virtual int getSorIterations() const = 0; + /** @copybrief getSorIterations @see getSorIterations */ + CV_WRAP virtual void setSorIterations(int val) = 0; + + /** @brief Relaxation factor in SOR + @see setOmega */ + CV_WRAP virtual float getOmega() const = 0; + /** @copybrief getOmega @see getOmega */ + CV_WRAP virtual void setOmega(float val) = 0; + + /** @brief Weight of the smoothness term + @see setAlpha */ + CV_WRAP virtual float getAlpha() const = 0; + /** @copybrief getAlpha @see getAlpha */ + CV_WRAP virtual void setAlpha(float val) = 0; + + /** @brief Weight of the color constancy term + @see setDelta */ + CV_WRAP virtual float getDelta() const = 0; + /** @copybrief getDelta @see getDelta */ + CV_WRAP virtual void setDelta(float val) = 0; + + /** @brief Weight of the gradient constancy term + @see setGamma */ + CV_WRAP virtual float getGamma() const = 0; + /** @copybrief getGamma @see getGamma */ + CV_WRAP virtual void setGamma(float val) = 0; + + /** @brief Creates an instance of VariationalRefinement + */ + CV_WRAP static Ptr create(); +}; + +/** @brief DIS optical flow algorithm. + +This class implements the Dense Inverse Search (DIS) optical flow algorithm. More +details about the algorithm can be found at @cite Kroeger2016 . Includes three presets with preselected +parameters to provide reasonable trade-off between speed and quality. However, even the slowest preset is +still relatively fast, use DeepFlow if you need better quality and don't care about speed. + +This implementation includes several additional features compared to the algorithm described in the paper, +including spatial propagation of flow vectors (@ref getUseSpatialPropagation), as well as an option to +utilize an initial flow approximation passed to @ref calc (which is, essentially, temporal propagation, +if the previous frame's flow field is passed). +*/ +class CV_EXPORTS_W DISOpticalFlow : public DenseOpticalFlow +{ +public: + enum + { + PRESET_ULTRAFAST = 0, + PRESET_FAST = 1, + PRESET_MEDIUM = 2 + }; + + /** @brief Finest level of the Gaussian pyramid on which the flow is computed (zero level + corresponds to the original image resolution). The final flow is obtained by bilinear upscaling. + @see setFinestScale */ + CV_WRAP virtual int getFinestScale() const = 0; + /** @copybrief getFinestScale @see getFinestScale */ + CV_WRAP virtual void setFinestScale(int val) = 0; + + /** @brief Size of an image patch for matching (in pixels). Normally, default 8x8 patches work well + enough in most cases. + @see setPatchSize */ + CV_WRAP virtual int getPatchSize() const = 0; + /** @copybrief getPatchSize @see getPatchSize */ + CV_WRAP virtual void setPatchSize(int val) = 0; + + /** @brief Stride between neighbor patches. Must be less than patch size. Lower values correspond + to higher flow quality. + @see setPatchStride */ + CV_WRAP virtual int getPatchStride() const = 0; + /** @copybrief getPatchStride @see getPatchStride */ + CV_WRAP virtual void setPatchStride(int val) = 0; + + /** @brief Maximum number of gradient descent iterations in the patch inverse search stage. Higher values + may improve quality in some cases. + @see setGradientDescentIterations */ + CV_WRAP virtual int getGradientDescentIterations() const = 0; + /** @copybrief getGradientDescentIterations @see getGradientDescentIterations */ + CV_WRAP virtual void setGradientDescentIterations(int val) = 0; + + /** @brief Number of fixed point iterations of variational refinement per scale. Set to zero to + disable variational refinement completely. Higher values will typically result in more smooth and + high-quality flow. + @see setGradientDescentIterations */ + CV_WRAP virtual int getVariationalRefinementIterations() const = 0; + /** @copybrief getGradientDescentIterations @see getGradientDescentIterations */ + CV_WRAP virtual void setVariationalRefinementIterations(int val) = 0; + + /** @brief Weight of the smoothness term + @see setVariationalRefinementAlpha */ + CV_WRAP virtual float getVariationalRefinementAlpha() const = 0; + /** @copybrief getVariationalRefinementAlpha @see getVariationalRefinementAlpha */ + CV_WRAP virtual void setVariationalRefinementAlpha(float val) = 0; + + /** @brief Weight of the color constancy term + @see setVariationalRefinementDelta */ + CV_WRAP virtual float getVariationalRefinementDelta() const = 0; + /** @copybrief getVariationalRefinementDelta @see getVariationalRefinementDelta */ + CV_WRAP virtual void setVariationalRefinementDelta(float val) = 0; + + /** @brief Weight of the gradient constancy term + @see setVariationalRefinementGamma */ + CV_WRAP virtual float getVariationalRefinementGamma() const = 0; + /** @copybrief getVariationalRefinementGamma @see getVariationalRefinementGamma */ + CV_WRAP virtual void setVariationalRefinementGamma(float val) = 0; + + + /** @brief Whether to use mean-normalization of patches when computing patch distance. It is turned on + by default as it typically provides a noticeable quality boost because of increased robustness to + illumination variations. Turn it off if you are certain that your sequence doesn't contain any changes + in illumination. + @see setUseMeanNormalization */ + CV_WRAP virtual bool getUseMeanNormalization() const = 0; + /** @copybrief getUseMeanNormalization @see getUseMeanNormalization */ + CV_WRAP virtual void setUseMeanNormalization(bool val) = 0; + + /** @brief Whether to use spatial propagation of good optical flow vectors. This option is turned on by + default, as it tends to work better on average and can sometimes help recover from major errors + introduced by the coarse-to-fine scheme employed by the DIS optical flow algorithm. Turning this + option off can make the output flow field a bit smoother, however. + @see setUseSpatialPropagation */ + CV_WRAP virtual bool getUseSpatialPropagation() const = 0; + /** @copybrief getUseSpatialPropagation @see getUseSpatialPropagation */ + CV_WRAP virtual void setUseSpatialPropagation(bool val) = 0; + + /** @brief Creates an instance of DISOpticalFlow + + @param preset one of PRESET_ULTRAFAST, PRESET_FAST and PRESET_MEDIUM + */ + CV_WRAP static Ptr create(int preset = DISOpticalFlow::PRESET_FAST); +}; + +/** @brief Class used for calculating a sparse optical flow. + +The class can calculate an optical flow for a sparse feature set using the +iterative Lucas-Kanade method with pyramids. + +@sa calcOpticalFlowPyrLK + +*/ +class CV_EXPORTS_W SparsePyrLKOpticalFlow : public SparseOpticalFlow +{ +public: + CV_WRAP virtual Size getWinSize() const = 0; + CV_WRAP virtual void setWinSize(Size winSize) = 0; + + CV_WRAP virtual int getMaxLevel() const = 0; + CV_WRAP virtual void setMaxLevel(int maxLevel) = 0; + + CV_WRAP virtual TermCriteria getTermCriteria() const = 0; + CV_WRAP virtual void setTermCriteria(TermCriteria& crit) = 0; + + CV_WRAP virtual int getFlags() const = 0; + CV_WRAP virtual void setFlags(int flags) = 0; + + CV_WRAP virtual double getMinEigThreshold() const = 0; + CV_WRAP virtual void setMinEigThreshold(double minEigThreshold) = 0; + + CV_WRAP static Ptr create( + Size winSize = Size(21, 21), + int maxLevel = 3, TermCriteria crit = + TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01), + int flags = 0, + double minEigThreshold = 1e-4); +}; + + + + +/** @brief Base abstract class for the long-term tracker + */ +class CV_EXPORTS_W Tracker +{ +protected: + Tracker(); +public: + virtual ~Tracker(); + + /** @brief Initialize the tracker with a known bounding box that surrounded the target + @param image The initial frame + @param boundingBox The initial bounding box + */ + CV_WRAP virtual + void init(InputArray image, const Rect& boundingBox) = 0; + + /** @brief Update the tracker, find the new most likely bounding box for the target + @param image The current frame + @param boundingBox The bounding box that represent the new target location, if true was returned, not + modified otherwise + + @return True means that target was located and false means that tracker cannot locate target in + current frame. Note, that latter *does not* imply that tracker has failed, maybe target is indeed + missing from the frame (say, out of sight) + */ + CV_WRAP virtual + bool update(InputArray image, CV_OUT Rect& boundingBox) = 0; +}; + + + +/** @brief The MIL algorithm trains a classifier in an online manner to separate the object from the +background. + +Multiple Instance Learning avoids the drift problem for a robust tracking. The implementation is +based on @cite MIL . + +Original code can be found here + */ +class CV_EXPORTS_W TrackerMIL : public Tracker +{ +protected: + TrackerMIL(); // use ::create() +public: + virtual ~TrackerMIL() CV_OVERRIDE; + + struct CV_EXPORTS_W_SIMPLE Params + { + CV_WRAP Params(); + //parameters for sampler + CV_PROP_RW float samplerInitInRadius; //!< radius for gathering positive instances during init + CV_PROP_RW int samplerInitMaxNegNum; //!< # negative samples to use during init + CV_PROP_RW float samplerSearchWinSize; //!< size of search window + CV_PROP_RW float samplerTrackInRadius; //!< radius for gathering positive instances during tracking + CV_PROP_RW int samplerTrackMaxPosNum; //!< # positive samples to use during tracking + CV_PROP_RW int samplerTrackMaxNegNum; //!< # negative samples to use during tracking + CV_PROP_RW int featureSetNumFeatures; //!< # features + }; + + /** @brief Create MIL tracker instance + * @param parameters MIL parameters TrackerMIL::Params + */ + static CV_WRAP + Ptr create(const TrackerMIL::Params ¶meters = TrackerMIL::Params()); + + //void init(InputArray image, const Rect& boundingBox) CV_OVERRIDE; + //bool update(InputArray image, CV_OUT Rect& boundingBox) CV_OVERRIDE; +}; + + + +/** @brief the GOTURN (Generic Object Tracking Using Regression Networks) tracker + * + * GOTURN (@cite GOTURN) is kind of trackers based on Convolutional Neural Networks (CNN). While taking all advantages of CNN trackers, + * GOTURN is much faster due to offline training without online fine-tuning nature. + * GOTURN tracker addresses the problem of single target tracking: given a bounding box label of an object in the first frame of the video, + * we track that object through the rest of the video. NOTE: Current method of GOTURN does not handle occlusions; however, it is fairly + * robust to viewpoint changes, lighting changes, and deformations. + * Inputs of GOTURN are two RGB patches representing Target and Search patches resized to 227x227. + * Outputs of GOTURN are predicted bounding box coordinates, relative to Search patch coordinate system, in format X1,Y1,X2,Y2. + * Original paper is here: + * As long as original authors implementation: + * Implementation of training algorithm is placed in separately here due to 3d-party dependencies: + * + * GOTURN architecture goturn.prototxt and trained model goturn.caffemodel are accessible on opencv_extra GitHub repository. + */ +class CV_EXPORTS_W TrackerGOTURN : public Tracker +{ +protected: + TrackerGOTURN(); // use ::create() +public: + virtual ~TrackerGOTURN() CV_OVERRIDE; + + struct CV_EXPORTS_W_SIMPLE Params + { + CV_WRAP Params(); + CV_PROP_RW std::string modelTxt; + CV_PROP_RW std::string modelBin; + }; + + /** @brief Constructor + @param parameters GOTURN parameters TrackerGOTURN::Params + */ + static CV_WRAP + Ptr create(const TrackerGOTURN::Params& parameters = TrackerGOTURN::Params()); + + //void init(InputArray image, const Rect& boundingBox) CV_OVERRIDE; + //bool update(InputArray image, CV_OUT Rect& boundingBox) CV_OVERRIDE; +}; + +class CV_EXPORTS_W TrackerDaSiamRPN : public Tracker +{ +protected: + TrackerDaSiamRPN(); // use ::create() +public: + virtual ~TrackerDaSiamRPN() CV_OVERRIDE; + + struct CV_EXPORTS_W_SIMPLE Params + { + CV_WRAP Params(); + CV_PROP_RW std::string model; + CV_PROP_RW std::string kernel_cls1; + CV_PROP_RW std::string kernel_r1; + CV_PROP_RW int backend; + CV_PROP_RW int target; + }; + + /** @brief Constructor + @param parameters DaSiamRPN parameters TrackerDaSiamRPN::Params + */ + static CV_WRAP + Ptr create(const TrackerDaSiamRPN::Params& parameters = TrackerDaSiamRPN::Params()); + + /** @brief Return tracking score + */ + CV_WRAP virtual float getTrackingScore() = 0; + + //void init(InputArray image, const Rect& boundingBox) CV_OVERRIDE; + //bool update(InputArray image, CV_OUT Rect& boundingBox) CV_OVERRIDE; +}; + + +//! @} video_track + +} // cv + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/opencv2/video/video.hpp b/duix-sdk/src/main/cpp/third/arm/include/opencv2/video/video.hpp new file mode 100644 index 0000000..8267b85 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/opencv2/video/video.hpp @@ -0,0 +1,48 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's 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. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 Intel Corporation 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. +// +//M*/ + +#ifdef __OPENCV_BUILD +#error this is a compatibility header which should not be used inside the OpenCV library +#endif + +#include "opencv2/video.hpp" diff --git a/duix-sdk/src/main/cpp/third/arm/include/rknn_api.h b/duix-sdk/src/main/cpp/third/arm/include/rknn_api.h new file mode 100644 index 0000000..8007931 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/rknn_api.h @@ -0,0 +1,697 @@ +/**************************************************************************** +* +* Copyright (c) 2017 - 2022 by Rockchip Corp. All rights reserved. +* +* The material in this file is confidential and contains trade secrets +* of Rockchip Corporation. This is proprietary information owned by +* Rockchip Corporation. No part of this work may be disclosed, +* reproduced, copied, transmitted, or used in any way for any purpose, +* without the express written permission of Rockchip Corporation. +* +*****************************************************************************/ + + +#ifndef _RKNN_API_H +#define _RKNN_API_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* + Definition of extended flag for rknn_init. +*/ +/* set high priority context. */ +#define RKNN_FLAG_PRIOR_HIGH 0x00000000 + +/* set medium priority context */ +#define RKNN_FLAG_PRIOR_MEDIUM 0x00000001 + +/* set low priority context. */ +#define RKNN_FLAG_PRIOR_LOW 0x00000002 + +/* asynchronous mode. + when enable, rknn_outputs_get will not block for too long because it directly retrieves the result of + the previous frame which can increase the frame rate on single-threaded mode, but at the cost of + rknn_outputs_get not retrieves the result of the current frame. + in multi-threaded mode you do not need to turn this mode on. */ +#define RKNN_FLAG_ASYNC_MASK 0x00000004 + +/* collect performance mode. + when enable, you can get detailed performance reports via rknn_query(ctx, RKNN_QUERY_PERF_DETAIL, ...), + but it will reduce the frame rate. */ +#define RKNN_FLAG_COLLECT_PERF_MASK 0x00000008 + +/* allocate all memory in outside, includes weight/internal/inputs/outputs */ +#define RKNN_FLAG_MEM_ALLOC_OUTSIDE 0x00000010 + +/* weight sharing with the same network structure */ +#define RKNN_FLAG_SHARE_WEIGHT_MEM 0x00000020 + +/* send fence fd from outside */ +#define RKNN_FLAG_FENCE_IN_OUTSIDE 0x00000040 + +/* get fence fd from inside */ +#define RKNN_FLAG_FENCE_OUT_OUTSIDE 0x00000080 + +/* dummy init flag: could only get total_weight_size and total_internal_size by rknn_query*/ +#define RKNN_FLAG_COLLECT_MODEL_INFO_ONLY 0x00000100 + +/* + Error code returned by the RKNN API. +*/ +#define RKNN_SUCC 0 /* execute succeed. */ +#define RKNN_ERR_FAIL -1 /* execute failed. */ +#define RKNN_ERR_TIMEOUT -2 /* execute timeout. */ +#define RKNN_ERR_DEVICE_UNAVAILABLE -3 /* device is unavailable. */ +#define RKNN_ERR_MALLOC_FAIL -4 /* memory malloc fail. */ +#define RKNN_ERR_PARAM_INVALID -5 /* parameter is invalid. */ +#define RKNN_ERR_MODEL_INVALID -6 /* model is invalid. */ +#define RKNN_ERR_CTX_INVALID -7 /* context is invalid. */ +#define RKNN_ERR_INPUT_INVALID -8 /* input is invalid. */ +#define RKNN_ERR_OUTPUT_INVALID -9 /* output is invalid. */ +#define RKNN_ERR_DEVICE_UNMATCH -10 /* the device is unmatch, please update rknn sdk + and npu driver/firmware. */ +#define RKNN_ERR_INCOMPATILE_PRE_COMPILE_MODEL -11 /* This RKNN model use pre_compile mode, but not compatible with current driver. */ +#define RKNN_ERR_INCOMPATILE_OPTIMIZATION_LEVEL_VERSION -12 /* This RKNN model set optimization level, but not compatible with current driver. */ +#define RKNN_ERR_TARGET_PLATFORM_UNMATCH -13 /* This RKNN model set target platform, but not compatible with current platform. */ + +/* + Definition for tensor +*/ +#define RKNN_MAX_DIMS 16 /* maximum dimension of tensor. */ +#define RKNN_MAX_NUM_CHANNEL 15 /* maximum channel number of input tensor. */ +#define RKNN_MAX_NAME_LEN 256 /* maximum name lenth of tensor. */ +#define RKNN_MAX_DYNAMIC_SHAPE_NUM 512 /* maximum number of dynamic shape for each input. */ + +#ifdef __arm__ +typedef uint32_t rknn_context; +#else +typedef uint64_t rknn_context; +#endif + + +/* + The query command for rknn_query +*/ +typedef enum _rknn_query_cmd { + RKNN_QUERY_IN_OUT_NUM = 0, /* query the number of input & output tensor. */ + RKNN_QUERY_INPUT_ATTR = 1, /* query the attribute of input tensor. */ + RKNN_QUERY_OUTPUT_ATTR = 2, /* query the attribute of output tensor. */ + RKNN_QUERY_PERF_DETAIL = 3, /* query the detail performance, need set + RKNN_FLAG_COLLECT_PERF_MASK when call rknn_init, + this query needs to be valid after rknn_outputs_get. */ + RKNN_QUERY_PERF_RUN = 4, /* query the time of run, + this query needs to be valid after rknn_outputs_get. */ + RKNN_QUERY_SDK_VERSION = 5, /* query the sdk & driver version */ + + RKNN_QUERY_MEM_SIZE = 6, /* query the weight & internal memory size */ + RKNN_QUERY_CUSTOM_STRING = 7, /* query the custom string */ + + RKNN_QUERY_NATIVE_INPUT_ATTR = 8, /* query the attribute of native input tensor. */ + RKNN_QUERY_NATIVE_OUTPUT_ATTR = 9, /* query the attribute of native output tensor. */ + + RKNN_QUERY_NATIVE_NC1HWC2_INPUT_ATTR = 8, /* query the attribute of native input tensor. */ + RKNN_QUERY_NATIVE_NC1HWC2_OUTPUT_ATTR = 9, /* query the attribute of native output tensor. */ + + RKNN_QUERY_NATIVE_NHWC_INPUT_ATTR = 10, /* query the attribute of native input tensor. */ + RKNN_QUERY_NATIVE_NHWC_OUTPUT_ATTR = 11, /* query the attribute of native output tensor. */ + + RKNN_QUERY_DEVICE_MEM_INFO = 12, /* query the attribute of rknn memory information. */ + + RKNN_QUERY_INPUT_DYNAMIC_RANGE = 13, /* query the dynamic shape range of rknn input tensor. */ + RKNN_QUERY_CURRENT_INPUT_ATTR = 14, /* query the current shape of rknn input tensor, only valid for dynamic rknn model*/ + RKNN_QUERY_CURRENT_OUTPUT_ATTR = 15, /* query the current shape of rknn output tensor, only valid for dynamic rknn model*/ + + RKNN_QUERY_CMD_MAX +} rknn_query_cmd; + +/* + the tensor data type. +*/ +typedef enum _rknn_tensor_type { + RKNN_TENSOR_FLOAT32 = 0, /* data type is float32. */ + RKNN_TENSOR_FLOAT16, /* data type is float16. */ + RKNN_TENSOR_INT8, /* data type is int8. */ + RKNN_TENSOR_UINT8, /* data type is uint8. */ + RKNN_TENSOR_INT16, /* data type is int16. */ + RKNN_TENSOR_UINT16, /* data type is uint16. */ + RKNN_TENSOR_INT32, /* data type is int32. */ + RKNN_TENSOR_UINT32, /* data type is uint32. */ + RKNN_TENSOR_INT64, /* data type is int64. */ + RKNN_TENSOR_BOOL, + + RKNN_TENSOR_TYPE_MAX +} rknn_tensor_type; + +inline static const char* get_type_string(rknn_tensor_type type) +{ + switch(type) { + case RKNN_TENSOR_FLOAT32: return "FP32"; + case RKNN_TENSOR_FLOAT16: return "FP16"; + case RKNN_TENSOR_INT8: return "INT8"; + case RKNN_TENSOR_UINT8: return "UINT8"; + case RKNN_TENSOR_INT16: return "INT16"; + case RKNN_TENSOR_UINT16: return "UINT16"; + case RKNN_TENSOR_INT32: return "INT32"; + case RKNN_TENSOR_UINT32: return "UINT32"; + case RKNN_TENSOR_INT64: return "INT64"; + case RKNN_TENSOR_BOOL: return "BOOL"; + default: return "UNKNOW"; + } +} + +/* + the quantitative type. +*/ +typedef enum _rknn_tensor_qnt_type { + RKNN_TENSOR_QNT_NONE = 0, /* none. */ + RKNN_TENSOR_QNT_DFP, /* dynamic fixed point. */ + RKNN_TENSOR_QNT_AFFINE_ASYMMETRIC, /* asymmetric affine. */ + + RKNN_TENSOR_QNT_MAX +} rknn_tensor_qnt_type; + +inline static const char* get_qnt_type_string(rknn_tensor_qnt_type type) +{ + switch(type) { + case RKNN_TENSOR_QNT_NONE: return "NONE"; + case RKNN_TENSOR_QNT_DFP: return "DFP"; + case RKNN_TENSOR_QNT_AFFINE_ASYMMETRIC: return "AFFINE"; + default: return "UNKNOW"; + } +} + +/* + the tensor data format. +*/ +typedef enum _rknn_tensor_format { + RKNN_TENSOR_NCHW = 0, /* data format is NCHW. */ + RKNN_TENSOR_NHWC, /* data format is NHWC. */ + RKNN_TENSOR_NC1HWC2, /* data format is NC1HWC2. */ + RKNN_TENSOR_UNDEFINED, + + RKNN_TENSOR_FORMAT_MAX +} rknn_tensor_format; + +/* + the mode of running on target NPU core. +*/ +typedef enum _rknn_core_mask { + RKNN_NPU_CORE_AUTO = 0, /* default, run on NPU core randomly. */ + RKNN_NPU_CORE_0 = 1, /* run on NPU core 0. */ + RKNN_NPU_CORE_1 = 2, /* run on NPU core 1. */ + RKNN_NPU_CORE_2 = 4, /* run on NPU core 2. */ + RKNN_NPU_CORE_0_1 = RKNN_NPU_CORE_0 | RKNN_NPU_CORE_1, /* run on NPU core 1 and core 2. */ + RKNN_NPU_CORE_0_1_2 = RKNN_NPU_CORE_0_1 | RKNN_NPU_CORE_2, /* run on NPU core 1 and core 2 and core 3. */ + + RKNN_NPU_CORE_UNDEFINED, +} rknn_core_mask; + +inline static const char* get_format_string(rknn_tensor_format fmt) +{ + switch(fmt) { + case RKNN_TENSOR_NCHW: return "NCHW"; + case RKNN_TENSOR_NHWC: return "NHWC"; + case RKNN_TENSOR_NC1HWC2: return "NC1HWC2"; + case RKNN_TENSOR_UNDEFINED: return "UNDEFINED"; + default: return "UNKNOW"; + } +} + +/* + the information for RKNN_QUERY_IN_OUT_NUM. +*/ +typedef struct _rknn_input_output_num { + uint32_t n_input; /* the number of input. */ + uint32_t n_output; /* the number of output. */ +} rknn_input_output_num; + +/* + the information for RKNN_QUERY_INPUT_ATTR / RKNN_QUERY_OUTPUT_ATTR. +*/ +typedef struct _rknn_tensor_attr { + uint32_t index; /* input parameter, the index of input/output tensor, + need set before call rknn_query. */ + + uint32_t n_dims; /* the number of dimensions. */ + uint32_t dims[RKNN_MAX_DIMS]; /* the dimensions array. */ + char name[RKNN_MAX_NAME_LEN]; /* the name of tensor. */ + + uint32_t n_elems; /* the number of elements. */ + uint32_t size; /* the bytes size of tensor. */ + + rknn_tensor_format fmt; /* the data format of tensor. */ + rknn_tensor_type type; /* the data type of tensor. */ + rknn_tensor_qnt_type qnt_type; /* the quantitative type of tensor. */ + int8_t fl; /* fractional length for RKNN_TENSOR_QNT_DFP. */ + int32_t zp; /* zero point for RKNN_TENSOR_QNT_AFFINE_ASYMMETRIC. */ + float scale; /* scale for RKNN_TENSOR_QNT_AFFINE_ASYMMETRIC. */ + + uint32_t w_stride; /* the stride of tensor along the width dimention of input, + Note: it is read-only, 0 means equal to width. */ + uint32_t size_with_stride; /* the bytes size of tensor with stride. */ + + uint8_t pass_through; /* pass through mode, for rknn_set_io_mem interface. + if TRUE, the buf data is passed directly to the input node of the rknn model + without any conversion. the following variables do not need to be set. + if FALSE, the buf data is converted into an input consistent with the model + according to the following type and fmt. so the following variables + need to be set.*/ + uint32_t h_stride; /* the stride along the height dimention of input, + Note: it is write-only, if it was set to 0, h_stride = height. */ +} rknn_tensor_attr; + +typedef struct _rknn_input_range { + uint32_t index; /* input parameter, the index of input/output tensor, + need set before call rknn_query. */ + uint32_t shape_number; /* the number of shape. */ + rknn_tensor_format fmt; /* the data format of tensor. */ + char name[RKNN_MAX_NAME_LEN]; /* the name of tensor. */ + uint32_t dyn_range[RKNN_MAX_DYNAMIC_SHAPE_NUM][RKNN_MAX_DIMS]; /* the dynamic input dimensions range. */ + uint32_t n_dims; /* the number of dimensions. */ + +} rknn_input_range; + +/* + the information for RKNN_QUERY_PERF_DETAIL. +*/ +typedef struct _rknn_perf_detail { + char* perf_data; /* the string pointer of perf detail. don't need free it by user. */ + uint64_t data_len; /* the string length. */ +} rknn_perf_detail; + +/* + the information for RKNN_QUERY_PERF_RUN. +*/ +typedef struct _rknn_perf_run { + int64_t run_duration; /* real inference time (us) */ +} rknn_perf_run; + +/* + the information for RKNN_QUERY_SDK_VERSION. +*/ +typedef struct _rknn_sdk_version { + char api_version[256]; /* the version of rknn api. */ + char drv_version[256]; /* the version of rknn driver. */ +} rknn_sdk_version; + +/* + the information for RKNN_QUERY_MEM_SIZE. +*/ +typedef struct _rknn_mem_size { + uint32_t total_weight_size; /* the weight memory size */ + uint32_t total_internal_size; /* the internal memory size, exclude inputs/outputs */ + uint64_t total_dma_allocated_size; /* total dma memory allocated size */ + uint32_t total_sram_size; /* total system sram size reserved for rknn */ + uint32_t free_sram_size; /* free system sram size reserved for rknn */ + uint32_t reserved[10]; /* reserved */ +} rknn_mem_size; + +/* + the information for RKNN_QUERY_CUSTOM_STRING. +*/ +typedef struct _rknn_custom_string { + char string[1024]; /* the string of custom, lengths max to 1024 bytes */ +} rknn_custom_string; + +/* + The flags of rknn_tensor_mem. +*/ +typedef enum _rknn_tensor_mem_flags { + RKNN_TENSOR_MEMORY_FLAGS_ALLOC_INSIDE = 1, /*Used to mark in rknn_destroy_mem() whether it is necessary to release the "mem" pointer itself. + If the flag RKNN_TENSOR_MEMORY_FLAGS_ALLOC_INSIDE is set, rknn_destroy_mem() will call free(mem).*/ + RKNN_TENSOR_MEMORY_FLAGS_FROM_FD = 2, /*Used to mark in rknn_create_mem_from_fd() whether it is necessary to release the "mem" pointer itself. + If the flag RKNN_TENSOR_MEMORY_FLAGS_FROM_FD is set, rknn_destroy_mem() will call free(mem).*/ + RKNN_TENSOR_MEMORY_FLAGS_FROM_PHYS = 3, /*Used to mark in rknn_create_mem_from_phys() whether it is necessary to release the "mem" pointer itself. + If the flag RKNN_TENSOR_MEMORY_FLAGS_FROM_PHYS is set, rknn_destroy_mem() will call free(mem).*/ + RKNN_TENSOR_MEMORY_FLAGS_UNKNOWN +} rknn_tensor_mem_flags; + +/* + the memory information of tensor. +*/ +typedef struct _rknn_tensor_memory { + void* virt_addr; /* the virtual address of tensor buffer. */ + uint64_t phys_addr; /* the physical address of tensor buffer. */ + int32_t fd; /* the fd of tensor buffer. */ + int32_t offset; /* indicates the offset of the memory. */ + uint32_t size; /* the size of tensor buffer. */ + uint32_t flags; /* the flags of tensor buffer, reserved */ + void * priv_data; /* the private data of tensor buffer. */ +} rknn_tensor_mem; + +/* + the input information for rknn_input_set. +*/ +typedef struct _rknn_input { + uint32_t index; /* the input index. */ + void* buf; /* the input buf for index. */ + uint32_t size; /* the size of input buf. */ + uint8_t pass_through; /* pass through mode. + if TRUE, the buf data is passed directly to the input node of the rknn model + without any conversion. the following variables do not need to be set. + if FALSE, the buf data is converted into an input consistent with the model + according to the following type and fmt. so the following variables + need to be set.*/ + rknn_tensor_type type; /* the data type of input buf. */ + rknn_tensor_format fmt; /* the data format of input buf. + currently the internal input format of NPU is NCHW by default. + so entering NCHW data can avoid the format conversion in the driver. */ +} rknn_input; + +/* + the output information for rknn_outputs_get. +*/ +typedef struct _rknn_output { + uint8_t want_float; /* want transfer output data to float */ + uint8_t is_prealloc; /* whether buf is pre-allocated. + if TRUE, the following variables need to be set. + if FALSE, the following variables do not need to be set. */ + uint32_t index; /* the output index. */ + void* buf; /* the output buf for index. + when is_prealloc = FALSE and rknn_outputs_release called, + this buf pointer will be free and don't use it anymore. */ + uint32_t size; /* the size of output buf. */ +} rknn_output; + +/* + the extend information for rknn_init. +*/ +typedef struct _rknn_init_extend { + rknn_context ctx; /* rknn context */ + int32_t real_model_offset; /* real rknn model file offset, only valid when init context with rknn file path */ + uint32_t real_model_size; /* real rknn model file size, only valid when init context with rknn file path */ + uint8_t reserved[120]; /* reserved */ +} rknn_init_extend; + +/* + the extend information for rknn_run. +*/ +typedef struct _rknn_run_extend { + uint64_t frame_id; /* output parameter, indicate current frame id of run. */ + int32_t non_block; /* block flag of run, 0 is block else 1 is non block */ + int32_t timeout_ms; /* timeout for block mode, in milliseconds */ + int32_t fence_fd; /* fence fd from other unit */ +} rknn_run_extend; + +/* + the extend information for rknn_outputs_get. +*/ +typedef struct _rknn_output_extend { + uint64_t frame_id; /* output parameter, indicate the frame id of outputs, corresponds to + struct rknn_run_extend.frame_id.*/ +} rknn_output_extend; + + +/* rknn_init + + initial the context and load the rknn model. + + input: + rknn_context* context the pointer of context handle. + void* model if size > 0, pointer to the rknn model, if size = 0, filepath to the rknn model. + uint32_t size the size of rknn model. + uint32_t flag extend flag, see the define of RKNN_FLAG_XXX_XXX. + rknn_init_extend* extend the extend information of init. + return: + int error code. +*/ +int rknn_init(rknn_context* context, void* model, uint32_t size, uint32_t flag, rknn_init_extend* extend); + +/* rknn_dup_context + + initial the context and load the rknn model. + + input: + rknn_context* context_in the pointer of context in handle. + rknn_context* context_out the pointer of context out handle. + return: + int error code. +*/ +int rknn_dup_context(rknn_context* context_in, rknn_context* context_out); + +/* rknn_destroy + + unload the rknn model and destroy the context. + + input: + rknn_context context the handle of context. + return: + int error code. +*/ +int rknn_destroy(rknn_context context); + + +/* rknn_query + + query the information about model or others. see rknn_query_cmd. + + input: + rknn_context context the handle of context. + rknn_query_cmd cmd the command of query. + void* info the buffer point of information. + uint32_t size the size of information. + return: + int error code. +*/ +int rknn_query(rknn_context context, rknn_query_cmd cmd, void* info, uint32_t size); + + +/* rknn_inputs_set + + set inputs information by input index of rknn model. + inputs information see rknn_input. + + input: + rknn_context context the handle of context. + uint32_t n_inputs the number of inputs. + rknn_input inputs[] the arrays of inputs information, see rknn_input. + return: + int error code +*/ +int rknn_inputs_set(rknn_context context, uint32_t n_inputs, rknn_input inputs[]); + +/* + rknn_set_batch_core_num + + set rknn batch core_num. + + input: + rknn_context context the handle of context. + int core_num the core number. + return: + int error code. + +*/ +int rknn_set_batch_core_num(rknn_context context, int core_num); + +/* rknn_set_core_mask + + set rknn core mask.(only supported on RK3588 now) + + RKNN_NPU_CORE_AUTO: auto mode, default value + RKNN_NPU_CORE_0: core 0 mode + RKNN_NPU_CORE_1: core 1 mode + RKNN_NPU_CORE_2: core 2 mode + RKNN_NPU_CORE_0_1: combine core 0/1 mode + RKNN_NPU_CORE_0_1_2: combine core 0/1/2 mode + + input: + rknn_context context the handle of context. + rknn_core_mask core_mask the core mask. + return: + int error code. +*/ +int rknn_set_core_mask(rknn_context context, rknn_core_mask core_mask); + +/* rknn_run + + run the model to execute inference. + + input: + rknn_context context the handle of context. + rknn_run_extend* extend the extend information of run. + return: + int error code. +*/ +int rknn_run(rknn_context context, rknn_run_extend* extend); + + +/* rknn_wait + + wait the model after execute inference. + + input: + rknn_context context the handle of context. + rknn_run_extend* extend the extend information of run. + return: + int error code. +*/ +int rknn_wait(rknn_context context, rknn_run_extend* extend); + + +/* rknn_outputs_get + + wait the inference to finish and get the outputs. + this function will block until inference finish. + the results will set to outputs[]. + + input: + rknn_context context the handle of context. + uint32_t n_outputs the number of outputs. + rknn_output outputs[] the arrays of output, see rknn_output. + rknn_output_extend* the extend information of output. + return: + int error code. +*/ +int rknn_outputs_get(rknn_context context, uint32_t n_outputs, rknn_output outputs[], rknn_output_extend* extend); + + +/* rknn_outputs_release + + release the outputs that get by rknn_outputs_get. + after called, the rknn_output[x].buf get from rknn_outputs_get will + also be free when rknn_output[x].is_prealloc = FALSE. + + input: + rknn_context context the handle of context. + uint32_t n_ouputs the number of outputs. + rknn_output outputs[] the arrays of output. + return: + int error code +*/ +int rknn_outputs_release(rknn_context context, uint32_t n_ouputs, rknn_output outputs[]); + + +/* new api for zero copy */ + +/* rknn_create_mem_from_phys (memory allocated outside) + + initialize tensor memory from physical address. + + input: + rknn_context ctx the handle of context. + uint64_t phys_addr physical address. + void *virt_addr virtual address. + uint32_t size the size of tensor buffer. + return: + rknn_tensor_mem the pointer of tensor memory information. +*/ +rknn_tensor_mem* rknn_create_mem_from_phys(rknn_context ctx, uint64_t phys_addr, void *virt_addr, uint32_t size); + + +/* rknn_create_mem_from_fd (memory allocated outside) + + initialize tensor memory from file description. + + input: + rknn_context ctx the handle of context. + int32_t fd file description. + void *virt_addr virtual address. + uint32_t size the size of tensor buffer. + int32_t offset indicates the offset of the memory (virt_addr without offset). + return: + rknn_tensor_mem the pointer of tensor memory information. +*/ +rknn_tensor_mem* rknn_create_mem_from_fd(rknn_context ctx, int32_t fd, void *virt_addr, uint32_t size, int32_t offset); + + +/* rknn_create_mem_from_mb_blk (memory allocated outside) + + create tensor memory from mb_blk. + + input: + rknn_context ctx the handle of context. + void *mb_blk mb_blk allocate from system api. + int32_t offset indicates the offset of the memory. + return: + rknn_tensor_mem the pointer of tensor memory information. +*/ +rknn_tensor_mem* rknn_create_mem_from_mb_blk(rknn_context ctx, void *mb_blk, int32_t offset); + + +/* rknn_create_mem (memory allocated inside) + + create tensor memory. + + input: + rknn_context ctx the handle of context. + uint32_t size the size of tensor buffer. + return: + rknn_tensor_mem the pointer of tensor memory information. +*/ +rknn_tensor_mem* rknn_create_mem(rknn_context ctx, uint32_t size); + + +/* rknn_destroy_mem (support allocate inside and outside) + + destroy tensor memory. + + input: + rknn_context ctx the handle of context. + rknn_tensor_mem *mem the pointer of tensor memory information. + return: + int error code +*/ +int rknn_destroy_mem(rknn_context ctx, rknn_tensor_mem *mem); + + +/* rknn_set_weight_mem + + set the weight memory. + + input: + rknn_context ctx the handle of context. + rknn_tensor_mem *mem the array of tensor memory information + return: + int error code. +*/ +int rknn_set_weight_mem(rknn_context ctx, rknn_tensor_mem *mem); + + +/* rknn_set_internal_mem + + set the internal memory. + + input: + rknn_context ctx the handle of context. + rknn_tensor_mem *mem the array of tensor memory information + return: + int error code. +*/ +int rknn_set_internal_mem(rknn_context ctx, rknn_tensor_mem *mem); + + +/* rknn_set_io_mem + + set the input and output tensors buffer. + + input: + rknn_context ctx the handle of context. + rknn_tensor_mem *mem the array of tensor memory information. + rknn_tensor_attr *attr the attribute of input or output tensor buffer. + return: + int error code. +*/ +int rknn_set_io_mem(rknn_context ctx, rknn_tensor_mem *mem, rknn_tensor_attr *attr); + +/* rknn_set_input_shape + + set the input tensor shape (only valid for dynamic shape rknn model). + + input: + rknn_context ctx the handle of context. + rknn_tensor_attr *attr the attribute of input or output tensor buffer. + return: + int error code. +*/ +int rknn_set_input_shape(rknn_context ctx, rknn_tensor_attr* attr); + +#ifdef __cplusplus +} //extern "C" +#endif + +#endif //_RKNN_API_H diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/bmp.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/bmp.h new file mode 100644 index 0000000..0d1e4dc --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/bmp.h @@ -0,0 +1,46 @@ +/* + * Copyright (C)2011 D. R. Commander. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted 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 libjpeg-turbo Project nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 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 HOLDERS 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. + */ + +#ifndef __BMP_H__ +#define __BMP_H__ + +#include "./turbojpeg.h" + +int loadbmp(char *filename, unsigned char **buf, int *w, int *h, int pf, + int bottomup); + +int savebmp(char *filename, unsigned char *buf, int w, int h, int pf, + int bottomup); + +const char *bmpgeterr(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/cderror.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/cderror.h new file mode 100644 index 0000000..e19c475 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/cderror.h @@ -0,0 +1,134 @@ +/* + * cderror.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * Modified 2009 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the error and message codes for the cjpeg/djpeg + * applications. These strings are not needed as part of the JPEG library + * proper. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef CDERROR_H +#define CDERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code,string) +#endif /* CDERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code,string) code , + +#endif /* JMAKE_ENUM_LIST */ + +JMESSAGE(JMSG_FIRSTADDONCODE=1000, NULL) /* Must be first entry! */ + +#ifdef BMP_SUPPORTED +JMESSAGE(JERR_BMP_BADCMAP, "Unsupported BMP colormap format") +JMESSAGE(JERR_BMP_BADDEPTH, "Only 8- and 24-bit BMP files are supported") +JMESSAGE(JERR_BMP_BADHEADER, "Invalid BMP file: bad header length") +JMESSAGE(JERR_BMP_BADPLANES, "Invalid BMP file: biPlanes not equal to 1") +JMESSAGE(JERR_BMP_COLORSPACE, "BMP output must be grayscale or RGB") +JMESSAGE(JERR_BMP_COMPRESSED, "Sorry, compressed BMPs not yet supported") +JMESSAGE(JERR_BMP_EMPTY, "Empty BMP image") +JMESSAGE(JERR_BMP_NOT, "Not a BMP file - does not start with BM") +JMESSAGE(JTRC_BMP, "%ux%u 24-bit BMP image") +JMESSAGE(JTRC_BMP_MAPPED, "%ux%u 8-bit colormapped BMP image") +JMESSAGE(JTRC_BMP_OS2, "%ux%u 24-bit OS2 BMP image") +JMESSAGE(JTRC_BMP_OS2_MAPPED, "%ux%u 8-bit colormapped OS2 BMP image") +#endif /* BMP_SUPPORTED */ + +#ifdef GIF_SUPPORTED +JMESSAGE(JERR_GIF_BUG, "GIF output got confused") +JMESSAGE(JERR_GIF_CODESIZE, "Bogus GIF codesize %d") +JMESSAGE(JERR_GIF_COLORSPACE, "GIF output must be grayscale or RGB") +JMESSAGE(JERR_GIF_IMAGENOTFOUND, "Too few images in GIF file") +JMESSAGE(JERR_GIF_NOT, "Not a GIF file") +JMESSAGE(JTRC_GIF, "%ux%ux%d GIF image") +JMESSAGE(JTRC_GIF_BADVERSION, + "Warning: unexpected GIF version number '%c%c%c'") +JMESSAGE(JTRC_GIF_EXTENSION, "Ignoring GIF extension block of type 0x%02x") +JMESSAGE(JTRC_GIF_NONSQUARE, "Caution: nonsquare pixels in input") +JMESSAGE(JWRN_GIF_BADDATA, "Corrupt data in GIF file") +JMESSAGE(JWRN_GIF_CHAR, "Bogus char 0x%02x in GIF file, ignoring") +JMESSAGE(JWRN_GIF_ENDCODE, "Premature end of GIF image") +JMESSAGE(JWRN_GIF_NOMOREDATA, "Ran out of GIF bits") +#endif /* GIF_SUPPORTED */ + +#ifdef PPM_SUPPORTED +JMESSAGE(JERR_PPM_COLORSPACE, "PPM output must be grayscale or RGB") +JMESSAGE(JERR_PPM_NONNUMERIC, "Nonnumeric data in PPM file") +JMESSAGE(JERR_PPM_NOT, "Not a PPM/PGM file") +JMESSAGE(JTRC_PGM, "%ux%u PGM image") +JMESSAGE(JTRC_PGM_TEXT, "%ux%u text PGM image") +JMESSAGE(JTRC_PPM, "%ux%u PPM image") +JMESSAGE(JTRC_PPM_TEXT, "%ux%u text PPM image") +#endif /* PPM_SUPPORTED */ + +#ifdef RLE_SUPPORTED +JMESSAGE(JERR_RLE_BADERROR, "Bogus error code from RLE library") +JMESSAGE(JERR_RLE_COLORSPACE, "RLE output must be grayscale or RGB") +JMESSAGE(JERR_RLE_DIMENSIONS, "Image dimensions (%ux%u) too large for RLE") +JMESSAGE(JERR_RLE_EMPTY, "Empty RLE file") +JMESSAGE(JERR_RLE_EOF, "Premature EOF in RLE header") +JMESSAGE(JERR_RLE_MEM, "Insufficient memory for RLE header") +JMESSAGE(JERR_RLE_NOT, "Not an RLE file") +JMESSAGE(JERR_RLE_TOOMANYCHANNELS, "Cannot handle %d output channels for RLE") +JMESSAGE(JERR_RLE_UNSUPPORTED, "Cannot handle this RLE setup") +JMESSAGE(JTRC_RLE, "%ux%u full-color RLE file") +JMESSAGE(JTRC_RLE_FULLMAP, "%ux%u full-color RLE file with map of length %d") +JMESSAGE(JTRC_RLE_GRAY, "%ux%u grayscale RLE file") +JMESSAGE(JTRC_RLE_MAPGRAY, "%ux%u grayscale RLE file with map of length %d") +JMESSAGE(JTRC_RLE_MAPPED, "%ux%u colormapped RLE file with map of length %d") +#endif /* RLE_SUPPORTED */ + +#ifdef TARGA_SUPPORTED +JMESSAGE(JERR_TGA_BADCMAP, "Unsupported Targa colormap format") +JMESSAGE(JERR_TGA_BADPARMS, "Invalid or unsupported Targa file") +JMESSAGE(JERR_TGA_COLORSPACE, "Targa output must be grayscale or RGB") +JMESSAGE(JTRC_TGA, "%ux%u RGB Targa image") +JMESSAGE(JTRC_TGA_GRAY, "%ux%u grayscale Targa image") +JMESSAGE(JTRC_TGA_MAPPED, "%ux%u colormapped Targa image") +#else +JMESSAGE(JERR_TGA_NOTCOMP, "Targa support was not compiled") +#endif /* TARGA_SUPPORTED */ + +JMESSAGE(JERR_BAD_CMAP_FILE, + "Color map file is invalid or of unsupported format") +JMESSAGE(JERR_TOO_MANY_COLORS, + "Output file format cannot handle %d colormap entries") +JMESSAGE(JERR_UNGETC_FAILED, "ungetc failed") +#ifdef TARGA_SUPPORTED +JMESSAGE(JERR_UNKNOWN_FORMAT, + "Unrecognized input file format --- perhaps you need -targa") +#else +JMESSAGE(JERR_UNKNOWN_FORMAT, "Unrecognized input file format") +#endif +JMESSAGE(JERR_UNSUPPORTED_FORMAT, "Unsupported output file format") + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTADDONCODE +} ADDON_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/cdjpeg.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/cdjpeg.h new file mode 100644 index 0000000..ed024ac --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/cdjpeg.h @@ -0,0 +1,187 @@ +/* + * cdjpeg.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains common declarations for the sample applications + * cjpeg and djpeg. It is NOT used by the core JPEG library. + */ + +#define JPEG_CJPEG_DJPEG /* define proper options in jconfig.h */ +#define JPEG_INTERNAL_OPTIONS /* cjpeg.c,djpeg.c need to see xxx_SUPPORTED */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" /* get library error codes too */ +#include "cderror.h" /* get application-specific error codes */ + + +/* + * Object interface for cjpeg's source file decoding modules + */ + +typedef struct cjpeg_source_struct * cjpeg_source_ptr; + +struct cjpeg_source_struct { + JMETHOD(void, start_input, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); + JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); + JMETHOD(void, finish_input, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); + + FILE *input_file; + + JSAMPARRAY buffer; + JDIMENSION buffer_height; +}; + + +/* + * Object interface for djpeg's output file encoding modules + */ + +typedef struct djpeg_dest_struct * djpeg_dest_ptr; + +struct djpeg_dest_struct { + /* start_output is called after jpeg_start_decompress finishes. + * The color map will be ready at this time, if one is needed. + */ + JMETHOD(void, start_output, (j_decompress_ptr cinfo, + djpeg_dest_ptr dinfo)); + /* Emit the specified number of pixel rows from the buffer. */ + JMETHOD(void, put_pixel_rows, (j_decompress_ptr cinfo, + djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied)); + /* Finish up at the end of the image. */ + JMETHOD(void, finish_output, (j_decompress_ptr cinfo, + djpeg_dest_ptr dinfo)); + + /* Target file spec; filled in by djpeg.c after object is created. */ + FILE * output_file; + + /* Output pixel-row buffer. Created by module init or start_output. + * Width is cinfo->output_width * cinfo->output_components; + * height is buffer_height. + */ + JSAMPARRAY buffer; + JDIMENSION buffer_height; +}; + + +/* + * cjpeg/djpeg may need to perform extra passes to convert to or from + * the source/destination file format. The JPEG library does not know + * about these passes, but we'd like them to be counted by the progress + * monitor. We use an expanded progress monitor object to hold the + * additional pass count. + */ + +struct cdjpeg_progress_mgr { + struct jpeg_progress_mgr pub; /* fields known to JPEG library */ + int completed_extra_passes; /* extra passes completed */ + int total_extra_passes; /* total extra */ + /* last printed percentage stored here to avoid multiple printouts */ + int percent_done; +}; + +typedef struct cdjpeg_progress_mgr * cd_progress_ptr; + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jinit_read_bmp jIRdBMP +#define jinit_write_bmp jIWrBMP +#define jinit_read_gif jIRdGIF +#define jinit_write_gif jIWrGIF +#define jinit_read_ppm jIRdPPM +#define jinit_write_ppm jIWrPPM +#define jinit_read_rle jIRdRLE +#define jinit_write_rle jIWrRLE +#define jinit_read_targa jIRdTarga +#define jinit_write_targa jIWrTarga +#define read_quant_tables RdQTables +#define read_scan_script RdScnScript +#define set_quality_ratings SetQRates +#define set_quant_slots SetQSlots +#define set_sample_factors SetSFacts +#define read_color_map RdCMap +#define enable_signal_catcher EnSigCatcher +#define start_progress_monitor StProgMon +#define end_progress_monitor EnProgMon +#define read_stdin RdStdin +#define write_stdout WrStdout +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Module selection routines for I/O modules. */ + +EXTERN(cjpeg_source_ptr) jinit_read_bmp JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_bmp JPP((j_decompress_ptr cinfo, + boolean is_os2)); +EXTERN(cjpeg_source_ptr) jinit_read_gif JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_gif JPP((j_decompress_ptr cinfo)); +EXTERN(cjpeg_source_ptr) jinit_read_ppm JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_ppm JPP((j_decompress_ptr cinfo)); +EXTERN(cjpeg_source_ptr) jinit_read_rle JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_rle JPP((j_decompress_ptr cinfo)); +EXTERN(cjpeg_source_ptr) jinit_read_targa JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_targa JPP((j_decompress_ptr cinfo)); + +/* cjpeg support routines (in rdswitch.c) */ + +EXTERN(boolean) read_quant_tables JPP((j_compress_ptr cinfo, char * filename, + boolean force_baseline)); +EXTERN(boolean) read_scan_script JPP((j_compress_ptr cinfo, char * filename)); +EXTERN(boolean) set_quality_ratings JPP((j_compress_ptr cinfo, char *arg, + boolean force_baseline)); +EXTERN(boolean) set_quant_slots JPP((j_compress_ptr cinfo, char *arg)); +EXTERN(boolean) set_sample_factors JPP((j_compress_ptr cinfo, char *arg)); + +/* djpeg support routines (in rdcolmap.c) */ + +EXTERN(void) read_color_map JPP((j_decompress_ptr cinfo, FILE * infile)); + +/* common support routines (in cdjpeg.c) */ + +EXTERN(void) enable_signal_catcher JPP((j_common_ptr cinfo)); +EXTERN(void) start_progress_monitor JPP((j_common_ptr cinfo, + cd_progress_ptr progress)); +EXTERN(void) end_progress_monitor JPP((j_common_ptr cinfo)); +EXTERN(boolean) keymatch JPP((char * arg, const char * keyword, int minchars)); +EXTERN(FILE *) read_stdin JPP((void)); +EXTERN(FILE *) write_stdout JPP((void)); + +/* miscellaneous useful macros */ + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#define WRITE_BINARY "w" +#else +#ifdef VMS /* VMS is very nonstandard */ +#define READ_BINARY "rb", "ctx=stm" +#define WRITE_BINARY "wb", "ctx=stm" +#else /* standard ANSI-compliant case */ +#define READ_BINARY "rb" +#define WRITE_BINARY "wb" +#endif +#endif + +#ifndef EXIT_FAILURE /* define exit() codes if not provided */ +#define EXIT_FAILURE 1 +#endif +#ifndef EXIT_SUCCESS +#ifdef VMS +#define EXIT_SUCCESS 1 /* VMS is very nonstandard */ +#else +#define EXIT_SUCCESS 0 +#endif +#endif +#ifndef EXIT_WARNING +#ifdef VMS +#define EXIT_WARNING 1 /* VMS is very nonstandard */ +#else +#define EXIT_WARNING 2 +#endif +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/config.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/config.h new file mode 100644 index 0000000..6e38c88 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/config.h @@ -0,0 +1,131 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Build number */ +#define BUILD "20110829" + +/* Support arithmetic encoding */ +#define C_ARITH_CODING_SUPPORTED 1 + +/* Support arithmetic decoding */ +#define D_ARITH_CODING_SUPPORTED 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_JNI_H */ + +/* Define to 1 if you have the `memcpy' function. */ +#define HAVE_MEMCPY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define if your compiler supports prototypes */ +#define HAVE_PROTOTYPES 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if the system has the type `unsigned char'. */ +#define HAVE_UNSIGNED_CHAR 1 + +/* Define to 1 if the system has the type `unsigned short'. */ +#define HAVE_UNSIGNED_SHORT 1 + +/* Compiler does not support pointers to undefined structures. */ +/* #undef INCOMPLETE_TYPES_BROKEN */ + +/* libjpeg API version */ +#define JPEG_LIB_VERSION 62 + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define if you have BSD-like bzero and bcopy */ +/* #undef NEED_BSD_STRINGS */ + +/* Define if you need short function names */ +/* #undef NEED_SHORT_EXTERNAL_NAMES */ + +/* Define if you have sys/types.h */ +#define NEED_SYS_TYPES_H 1 + +/* Name of package */ +#define PACKAGE "libjpeg-turbo" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libjpeg-turbo" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libjpeg-turbo 1.1.90" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libjpeg-turbo" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.1.90" + +/* Define if shift is unsigned */ +/* #undef RIGHT_SHIFT_IS_UNSIGNED */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "1.1.90" + +/* Use accelerated SIMD routines. */ +#define WITH_SIMD 1 + +/* Define to 1 if type `char' is unsigned and you are not using gcc. */ +#ifndef __CHAR_UNSIGNED__ +/* # undef __CHAR_UNSIGNED__ */ +#endif + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/cpu-features.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/cpu-features.h new file mode 100644 index 0000000..39c1db3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/cpu-features.h @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted 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. + * + * 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 OWNER 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. + */ +#ifndef _ARM_MACHINE_CPU_FEATURES_H +#define _ARM_MACHINE_CPU_FEATURES_H + +/* The purpose of this file is to define several macros corresponding + * to CPU features that may or may not be available at build time on + * on the target CPU. + * + * This is done to abstract us from the various ARM Architecture + * quirks and alphabet soup. + * + * IMPORTANT: We have no intention to support anything below an ARMv4T ! + */ + +/* __ARM_ARCH__ is a number corresponding to the ARM revision + * we're going to support + * + * it looks like our toolchain doesn't define __ARM_ARCH__ + * so try to guess it. + * + * + * + */ +#ifndef __ARM_ARCH__ + +# if defined __ARM_ARCH_7__ || defined __ARM_ARCH_7A__ || \ + defined __ARM_ARCH_7R__ || defined __ARM_ARCH_7M__ + +# define __ARM_ARCH__ 7 + +# elif defined __ARM_ARCH_6__ || defined __ARM_ARCH_6J__ || \ + defined __ARM_ARCH_6K__ || defined __ARM_ARCH_6Z__ || \ + defined __ARM_ARCH_6KZ__ || defined __ARM_ARCH_6T2__ +# +# define __ARM_ARCH__ 6 +# +# elif defined __ARM_ARCH_5__ || defined __ARM_ARCH_5T__ || \ + defined __ARM_ARCH_5TE__ || defined __ARM_ARCH_5TEJ__ +# +# define __ARM_ARCH__ 5 +# +# elif defined __ARM_ARCH_4T__ +# +# define __ARM_ARCH__ 4 +# +# elif defined __ARM_ARCH_4__ +# error ARMv4 is not supported, please use ARMv4T at a minimum +# else +# error Unknown or unsupported ARM architecture +# endif +#endif + +/* experimental feature used to check that our ARMv4 workarounds + * work correctly without a real ARMv4 machine */ +#ifdef BIONIC_EXPERIMENTAL_FORCE_ARMV4 +# undef __ARM_ARCH__ +# define __ARM_ARCH__ 4 +#endif + +/* define __ARM_HAVE_5TE if we have the ARMv5TE instructions */ +#if __ARM_ARCH__ > 5 +# define __ARM_HAVE_5TE 1 +#elif __ARM_ARCH__ == 5 +# if defined __ARM_ARCH_5TE__ || defined __ARM_ARCH_5TEJ__ +# define __ARM_HAVE_5TE 1 +# endif +#endif + +/* instructions introduced in ARMv5 */ +#if __ARM_ARCH__ >= 5 +# define __ARM_HAVE_BLX 1 +# define __ARM_HAVE_CLZ 1 +# define __ARM_HAVE_LDC2 1 +# define __ARM_HAVE_MCR2 1 +# define __ARM_HAVE_MRC2 1 +# define __ARM_HAVE_STC2 1 +#endif + +/* ARMv5TE introduces a few instructions */ +#if __ARM_HAVE_5TE +# define __ARM_HAVE_PLD 1 +# define __ARM_HAVE_MCRR 1 +# define __ARM_HAVE_MRRC 1 +#endif + +/* define __ARM_HAVE_HALFWORD_MULTIPLY when half-word multiply instructions + * this means variants of: smul, smulw, smla, smlaw, smlal + */ +#if __ARM_HAVE_5TE +# define __ARM_HAVE_HALFWORD_MULTIPLY 1 +#endif + +/* define __ARM_HAVE_PAIR_LOAD_STORE when 64-bit memory loads and stored + * into/from a pair of 32-bit registers is supported throuhg 'ldrd' and 'strd' + */ +#if __ARM_HAVE_5TE +# define __ARM_HAVE_PAIR_LOAD_STORE 1 +#endif + +/* define __ARM_HAVE_SATURATED_ARITHMETIC is you have the saturated integer + * arithmetic instructions: qdd, qdadd, qsub, qdsub + */ +#if __ARM_HAVE_5TE +# define __ARM_HAVE_SATURATED_ARITHMETIC 1 +#endif + +/* define __ARM_HAVE_PC_INTERWORK when a direct assignment to the + * pc register will switch into thumb/ARM mode depending on bit 0 + * of the new instruction address. Before ARMv5, this was not the + * case, and you have to write: + * + * mov r0, [] + * bx r0 + * + * instead of: + * + * ldr pc, [] + * + * note that this affects any instruction that explicitly changes the + * value of the pc register, including ldm { ...,pc } or 'add pc, #offset' + */ +#if __ARM_ARCH__ >= 5 +# define __ARM_HAVE_PC_INTERWORK +#endif + +/* define __ARM_HAVE_LDREX_STREX for ARMv6 and ARMv7 architecture to be + * used in replacement of deprecated swp instruction + */ +#if __ARM_ARCH__ >= 6 +# define __ARM_HAVE_LDREX_STREX +#endif + +/* define __ARM_HAVE_DMB for ARMv7 architecture + */ +#if __ARM_ARCH__ >= 7 +# define __ARM_HAVE_DMB +#endif + +/* define __ARM_HAVE_LDREXD for ARMv7 architecture + * (also present in ARMv6K, but not implemented in ARMv7-M, neither of which + * we care about) + */ +#if __ARM_ARCH__ >= 7 +# define __ARM_HAVE_LDREXD +#endif + +/* define _ARM_HAVE_VFP if we have VFPv3 + */ +#if __ARM_ARCH__ >= 7 && defined __VFP_FP__ +# define __ARM_HAVE_VFP +#endif + +/* define _ARM_HAVE_NEON for ARMv7 architecture if we support the + * Neon SIMD instruction set extensions. This also implies + * that VFPv3-D32 is supported. + */ +#if __ARM_ARCH__ >= 7 && defined __ARM_NEON__ +# define __ARM_HAVE_NEON +#endif + +/* Assembly-only macros */ + +/* define a handy PLD(address) macro since the cache preload + * is an optional opcode + */ +#if __ARM_HAVE_PLD +# define PLD(reg,offset) pld [reg, offset] +#else +# define PLD(reg,offset) /* nothing */ +#endif + +#endif /* _ARM_MACHINE_CPU_FEATURES_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jchuff.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jchuff.h new file mode 100644 index 0000000..a9599fc --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jchuff.h @@ -0,0 +1,47 @@ +/* + * jchuff.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for Huffman entropy encoding routines + * that are shared between the sequential encoder (jchuff.c) and the + * progressive encoder (jcphuff.c). No other modules need to see these. + */ + +/* The legal range of a DCT coefficient is + * -1024 .. +1023 for 8-bit data; + * -16384 .. +16383 for 12-bit data. + * Hence the magnitude should always fit in 10 or 14 bits respectively. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MAX_COEF_BITS 10 +#else +#define MAX_COEF_BITS 14 +#endif + +/* Derived data constructed for each Huffman table */ + +typedef struct { + unsigned int ehufco[256]; /* code for each symbol */ + char ehufsi[256]; /* length of code for each symbol */ + /* If no code has been allocated for a symbol S, ehufsi[S] contains 0 */ +} c_derived_tbl; + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_make_c_derived_tbl jMkCDerived +#define jpeg_gen_optimal_table jGenOptTbl +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Expand a Huffman table definition into the derived format */ +EXTERN(void) jpeg_make_c_derived_tbl + JPP((j_compress_ptr cinfo, boolean isDC, int tblno, + c_derived_tbl ** pdtbl)); + +/* Generate an optimal table definition given the specified counts */ +EXTERN(void) jpeg_gen_optimal_table + JPP((j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[])); diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jconfig.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jconfig.h new file mode 100644 index 0000000..3f12221 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jconfig.h @@ -0,0 +1,62 @@ +/* jconfig.h. Generated from jconfig.h.in by configure. */ +/* Version ID for the JPEG library. + * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60". + */ +#define JPEG_LIB_VERSION 62 + +/* Support arithmetic encoding */ +#define C_ARITH_CODING_SUPPORTED 1 + +/* Support arithmetic decoding */ +#define D_ARITH_CODING_SUPPORTED 1 + +/* Define if your compiler supports prototypes */ +#define HAVE_PROTOTYPES 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if the system has the type `unsigned char'. */ +#define HAVE_UNSIGNED_CHAR 1 + +/* Define to 1 if the system has the type `unsigned short'. */ +#define HAVE_UNSIGNED_SHORT 1 + +/* Define if you want use complete types */ +/* #undef INCOMPLETE_TYPES_BROKEN */ + +/* Define if you have BSD-like bzero and bcopy */ +/* #undef NEED_BSD_STRINGS */ + +/* Define if you need short function names */ +/* #undef NEED_SHORT_EXTERNAL_NAMES */ + +/* Define if you have sys/types.h */ +#define NEED_SYS_TYPES_H 1 + +/* Define if shift is unsigned */ +/* #undef RIGHT_SHIFT_IS_UNSIGNED */ + +/* Use accelerated SIMD routines. */ +#define WITH_SIMD 1 + +/* Define to 1 if type `char' is unsigned and you are not using gcc. */ +#ifndef __CHAR_UNSIGNED__ +/* # undef __CHAR_UNSIGNED__ */ +#endif + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jdct.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jdct.h new file mode 100644 index 0000000..7b49a97 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jdct.h @@ -0,0 +1,184 @@ +/* + * jdct.h + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file contains common declarations for the forward and + * inverse DCT modules. These declarations are private to the DCT managers + * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms. + * The individual DCT algorithms are kept in separate files to ease + * machine-dependent tuning (e.g., assembly coding). + */ + + +/* + * A forward DCT routine is given a pointer to a work area of type DCTELEM[]; + * the DCT is to be performed in-place in that buffer. Type DCTELEM is int + * for 8-bit samples, INT32 for 12-bit samples. (NOTE: Floating-point DCT + * implementations use an array of type FAST_FLOAT, instead.) + * The DCT inputs are expected to be signed (range +-CENTERJSAMPLE). + * The DCT outputs are returned scaled up by a factor of 8; they therefore + * have a range of +-8K for 8-bit data, +-128K for 12-bit data. This + * convention improves accuracy in integer implementations and saves some + * work in floating-point ones. + * Quantization of the output coefficients is done by jcdctmgr.c. This + * step requires an unsigned type and also one with twice the bits. + */ + +#if BITS_IN_JSAMPLE == 8 +#ifndef WITH_SIMD +typedef int DCTELEM; /* 16 or 32 bits is fine */ +typedef unsigned int UDCTELEM; +typedef unsigned long long UDCTELEM2; +#else +typedef short DCTELEM; /* prefer 16 bit with SIMD for parellelism */ +typedef unsigned short UDCTELEM; +typedef unsigned int UDCTELEM2; +#endif +#else +typedef INT32 DCTELEM; /* must have 32 bits */ +typedef UINT32 UDCTELEM; +typedef unsigned long long UDCTELEM2; +#endif + + +/* + * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer + * to an output sample array. The routine must dequantize the input data as + * well as perform the IDCT; for dequantization, it uses the multiplier table + * pointed to by compptr->dct_table. The output data is to be placed into the + * sample array starting at a specified column. (Any row offset needed will + * be applied to the array pointer before it is passed to the IDCT code.) + * Note that the number of samples emitted by the IDCT routine is + * DCT_scaled_size * DCT_scaled_size. + */ + +/* typedef inverse_DCT_method_ptr is declared in jpegint.h */ + +/* + * Each IDCT routine has its own ideas about the best dct_table element type. + */ + +typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */ +#if BITS_IN_JSAMPLE == 8 +typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */ +#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */ +#else +typedef INT32 IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */ +#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */ +#endif +typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */ + + +/* + * Each IDCT routine is responsible for range-limiting its results and + * converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could + * be quite far out of range if the input data is corrupt, so a bulletproof + * range-limiting step is required. We use a mask-and-table-lookup method + * to do the combined operations quickly. See the comments with + * prepare_range_limit_table (in jdmaster.c) for more info. + */ + +#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit + CENTERJSAMPLE) + +#define RANGE_MASK (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_fdct_islow jFDislow +#define jpeg_fdct_ifast jFDifast +#define jpeg_fdct_float jFDfloat +#define jpeg_idct_islow jRDislow +#define jpeg_idct_ifast jRDifast +#define jpeg_idct_float jRDfloat +#define jpeg_idct_4x4 jRD4x4 +#define jpeg_idct_2x2 jRD2x2 +#define jpeg_idct_1x1 jRD1x1 +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Extern declarations for the forward and inverse DCT routines. */ + +EXTERN(void) jpeg_fdct_islow JPP((DCTELEM * data)); +EXTERN(void) jpeg_fdct_ifast JPP((DCTELEM * data)); +EXTERN(void) jpeg_fdct_float JPP((FAST_FLOAT * data)); + +EXTERN(void) jpeg_idct_islow + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_ifast + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_float + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_4x4 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_2x2 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_1x1 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); + + +/* + * Macros for handling fixed-point arithmetic; these are used by many + * but not all of the DCT/IDCT modules. + * + * All values are expected to be of type INT32. + * Fractional constants are scaled left by CONST_BITS bits. + * CONST_BITS is defined within each module using these macros, + * and may differ from one module to the next. + */ + +#define ONE ((INT32) 1) +#define CONST_SCALE (ONE << CONST_BITS) + +/* Convert a positive real constant to an integer scaled by CONST_SCALE. + * Caution: some C compilers fail to reduce "FIX(constant)" at compile time, + * thus causing a lot of useless floating-point operations at run time. + */ + +#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5)) + +/* Descale and correctly round an INT32 value that's scaled by N bits. + * We assume RIGHT_SHIFT rounds towards minus infinity, so adding + * the fudge factor is correct for either sign of X. + */ + +#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n) + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * This macro is used only when the two inputs will actually be no more than + * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a + * full 32x32 multiply. This provides a useful speedup on many machines. + * Unfortunately there is no way to specify a 16x16->32 multiply portably + * in C, but some C compilers will do the right thing if you provide the + * correct combination of casts. + */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const))) +#endif +#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */ +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT32) (const))) +#endif + +#ifndef MULTIPLY16C16 /* default definition */ +#define MULTIPLY16C16(var,const) ((var) * (const)) +#endif + +/* Same except both inputs are variables. */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16V16(var1,var2) (((INT16) (var1)) * ((INT16) (var2))) +#endif + +#ifndef MULTIPLY16V16 /* default definition */ +#define MULTIPLY16V16(var1,var2) ((var1) * (var2)) +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jdhuff.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jdhuff.h new file mode 100644 index 0000000..47665a9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jdhuff.h @@ -0,0 +1,235 @@ +/* + * jdhuff.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Copyright (C) 2010-2011, D. R. Commander. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for Huffman entropy decoding routines + * that are shared between the sequential decoder (jdhuff.c) and the + * progressive decoder (jdphuff.c). No other modules need to see these. + */ + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_make_d_derived_tbl jMkDDerived +#define jpeg_fill_bit_buffer jFilBitBuf +#define jpeg_huff_decode jHufDecode +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Derived data constructed for each Huffman table */ + +#define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */ + +typedef struct { + /* Basic tables: (element [0] of each array is unused) */ + INT32 maxcode[18]; /* largest code of length k (-1 if none) */ + /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */ + INT32 valoffset[18]; /* huffval[] offset for codes of length k */ + /* valoffset[k] = huffval[] index of 1st symbol of code length k, less + * the smallest code of length k; so given a code of length k, the + * corresponding symbol is huffval[code + valoffset[k]] + */ + + /* Link to public Huffman table (needed only in jpeg_huff_decode) */ + JHUFF_TBL *pub; + + /* Lookahead table: indexed by the next HUFF_LOOKAHEAD bits of + * the input data stream. If the next Huffman code is no more + * than HUFF_LOOKAHEAD bits long, we can obtain its length and + * the corresponding symbol directly from this tables. + * + * The lower 8 bits of each table entry contain the number of + * bits in the corresponding Huffman code, or HUFF_LOOKAHEAD + 1 + * if too long. The next 8 bits of each entry contain the + * symbol. + */ + int lookup[1< 32 bits on your machine, and shifting/masking longs is + * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE + * appropriately should be a win. Unfortunately we can't define the size + * with something like #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8) + * because not all machines measure sizeof in 8-bit bytes. + */ + +typedef struct { /* Bitreading state saved across MCUs */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ +} bitread_perm_state; + +typedef struct { /* Bitreading working state within an MCU */ + /* Current data source location */ + /* We need a copy, rather than munging the original, in case of suspension */ + const JOCTET * next_input_byte; /* => next byte to read from source */ + size_t bytes_in_buffer; /* # of bytes remaining in source buffer */ + /* Bit input buffer --- note these values are kept in register variables, + * not in this struct, inside the inner loops. + */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ + /* Pointer needed by jpeg_fill_bit_buffer. */ + j_decompress_ptr cinfo; /* back link to decompress master record */ +} bitread_working_state; + +/* Macros to declare and load/writeFileAsync bitread local variables. */ +#define BITREAD_STATE_VARS \ + register bit_buf_type get_buffer; \ + register int bits_left; \ + bitread_working_state br_state + +#define BITREAD_LOAD_STATE(cinfop,permstate) \ + br_state.cinfo = cinfop; \ + br_state.next_input_byte = cinfop->src->next_input_byte; \ + br_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \ + get_buffer = permstate.get_buffer; \ + bits_left = permstate.bits_left; + +#define BITREAD_SAVE_STATE(cinfop,permstate) \ + cinfop->src->next_input_byte = br_state.next_input_byte; \ + cinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \ + permstate.get_buffer = get_buffer; \ + permstate.bits_left = bits_left + +/* + * These macros provide the in-line portion of bit fetching. + * Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer + * before using GET_BITS, PEEK_BITS, or DROP_BITS. + * The variables get_buffer and bits_left are assumed to be locals, + * but the state struct might not be (jpeg_huff_decode needs this). + * CHECK_BIT_BUFFER(state,n,action); + * Ensure there are N bits in get_buffer; if suspend, take action. + * val = GET_BITS(n); + * Fetch next N bits. + * val = PEEK_BITS(n); + * Fetch next N bits without removing them from the buffer. + * DROP_BITS(n); + * Discard next N bits. + * The value N should be a simple variable, not an expression, because it + * is evaluated multiple times. + */ + +#define CHECK_BIT_BUFFER(state,nbits,action) \ + { if (bits_left < (nbits)) { \ + if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) \ + { action; } \ + get_buffer = (state).get_buffer; bits_left = (state).bits_left; } } + +#define GET_BITS(nbits) \ + (((int) (get_buffer >> (bits_left -= (nbits)))) & ((1<<(nbits))-1)) + +#define PEEK_BITS(nbits) \ + (((int) (get_buffer >> (bits_left - (nbits)))) & ((1<<(nbits))-1)) + +#define DROP_BITS(nbits) \ + (bits_left -= (nbits)) + +/* Load up the bit buffer to a depth of at least nbits */ +EXTERN(boolean) jpeg_fill_bit_buffer + JPP((bitread_working_state * state, register bit_buf_type get_buffer, + register int bits_left, int nbits)); + + +/* + * Code for extracting next Huffman-coded symbol from input bit stream. + * Again, this is time-critical and we make the main paths be macros. + * + * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits + * without looping. Usually, more than 95% of the Huffman codes will be 8 + * or fewer bits long. The few overlength codes are handled with a loop, + * which need not be inline code. + * + * Notes about the HUFF_DECODE macro: + * 1. Near the end of the data segment, we may fail to get enough bits + * for a lookahead. In that case, we do it the hard way. + * 2. If the lookahead table contains no entry, the next code must be + * more than HUFF_LOOKAHEAD bits long. + * 3. jpeg_huff_decode returns -1 if forced to suspend. + */ + +#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \ +{ register int nb, look; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + nb = 1; goto slowlabel; \ + } \ + } \ + look = PEEK_BITS(HUFF_LOOKAHEAD); \ + if ((nb = (htbl->lookup[look] >> HUFF_LOOKAHEAD)) <= HUFF_LOOKAHEAD) { \ + DROP_BITS(nb); \ + result = htbl->lookup[look] & ((1 << HUFF_LOOKAHEAD) - 1); \ + } else { \ +slowlabel: \ + if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \ + { failaction; } \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + } \ +} + +#define HUFF_DECODE_FAST(s,nb,htbl) \ + FILL_BIT_BUFFER_FAST; \ + s = PEEK_BITS(HUFF_LOOKAHEAD); \ + s = htbl->lookup[s]; \ + nb = s >> HUFF_LOOKAHEAD; \ + /* Pre-execute the common case of nb <= HUFF_LOOKAHEAD */ \ + DROP_BITS(nb); \ + s = s & ((1 << HUFF_LOOKAHEAD) - 1); \ + if (nb > HUFF_LOOKAHEAD) { \ + /* Equivalent of jpeg_huff_decode() */ \ + /* Don't use GET_BITS() here because we don't want to modify bits_left */ \ + s = (get_buffer >> bits_left) & ((1 << (nb)) - 1); \ + while (s > htbl->maxcode[nb]) { \ + s <<= 1; \ + s |= GET_BITS(1); \ + nb++; \ + } \ + s = htbl->pub->huffval[ (int) (s + htbl->valoffset[nb]) & 0xFF ]; \ + } + +/* Out-of-line case for Huffman code fetching */ +EXTERN(int) jpeg_huff_decode + JPP((bitread_working_state * state, register bit_buf_type get_buffer, + register int bits_left, d_derived_tbl * htbl, int min_bits)); diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jerror.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jerror.h new file mode 100644 index 0000000..275086e --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jerror.h @@ -0,0 +1,314 @@ +/* + * jerror.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * Modified 1997-2009 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the error and message codes for the JPEG library. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + * A set of error-reporting macros are defined too. Some applications using + * the JPEG library may wish to include this file to get the error codes + * and/or the macros. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef JERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code,string) +#endif /* JERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code,string) code , + +#endif /* JMAKE_ENUM_LIST */ + +JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */ + +/* For maintenance convenience, list is alphabetical by message code name */ +#if JPEG_LIB_VERSION < 70 +JMESSAGE(JERR_ARITH_NOTIMPL, + "Sorry, arithmetic coding is not implemented") +#endif +JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix") +JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") +JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") +JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") +#if JPEG_LIB_VERSION >= 70 +JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request") +#endif +JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range") +JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported") +#if JPEG_LIB_VERSION >= 70 +JMESSAGE(JERR_BAD_DROP_SAMPLING, + "Component index %d: mismatching sampling ratio %d:%d, %d:%d, %c") +#endif +JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition") +JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace") +JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace") +JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length") +JMESSAGE(JERR_BAD_LIB_VERSION, + "Wrong JPEG library version: library is %d, caller expects %d") +JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan") +JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d") +JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d") +JMESSAGE(JERR_BAD_PROGRESSION, + "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d") +JMESSAGE(JERR_BAD_PROG_SCRIPT, + "Invalid progressive parameters at scan script entry %d") +JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors") +JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d") +JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d") +JMESSAGE(JERR_BAD_STRUCT_SIZE, + "JPEG parameter struct mismatch: library thinks size is %u, caller expects %u") +JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access") +JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small") +JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here") +JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet") +JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d") +JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request") +JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d") +JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x") +JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d") +JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d") +JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)") +JMESSAGE(JERR_EMS_READ, "Read from EMS failed") +JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed") +JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan") +JMESSAGE(JERR_FILE_READ, "Input file read error") +JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?") +JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet") +JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow") +JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry") +JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels") +JMESSAGE(JERR_INPUT_EMPTY, "Empty input file") +JMESSAGE(JERR_INPUT_EOF, "Premature end of input file") +JMESSAGE(JERR_MISMATCHED_QUANT_TABLE, + "Cannot transcode due to multiple use of quantization table %d") +JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data") +JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change") +JMESSAGE(JERR_NOTIMPL, "Not implemented yet") +JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time") +#if JPEG_LIB_VERSION >= 70 +JMESSAGE(JERR_NO_ARITH_TABLE, "Arithmetic table 0x%02x was not defined") +#endif +JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported") +JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined") +JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image") +JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined") +JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x") +JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)") +JMESSAGE(JERR_QUANT_COMPONENTS, + "Cannot quantize more than %d color components") +JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors") +JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors") +JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers") +JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker") +JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x") +JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers") +JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF") +JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s") +JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file") +JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file") +JMESSAGE(JERR_TFILE_WRITE, + "Write failed on temporary file --- out of disk space?") +JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines") +JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x") +JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up") +JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation") +JMESSAGE(JERR_XMS_READ, "Read from XMS failed") +JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed") +JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT) +JMESSAGE(JMSG_VERSION, JVERSION) +JMESSAGE(JTRC_16BIT_TABLES, + "Caution: quantization tables are too coarse for baseline JPEG") +JMESSAGE(JTRC_ADOBE, + "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d") +JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u") +JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u") +JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x") +JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x") +JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d") +JMESSAGE(JTRC_DRI, "Define Restart Interval %u") +JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u") +JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u") +JMESSAGE(JTRC_EOI, "End Of Image") +JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d") +JMESSAGE(JTRC_JFIF, "JFIF APP0 marker: version %d.%02d, density %dx%d %d") +JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE, + "Warning: thumbnail image size does not match data length %u") +JMESSAGE(JTRC_JFIF_EXTENSION, + "JFIF extension marker: type 0x%02x, length %u") +JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image") +JMESSAGE(JTRC_MISC_MARKER, "Miscellaneous marker 0x%02x, length %u") +JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x") +JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u") +JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors") +JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors") +JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization") +JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d") +JMESSAGE(JTRC_RST, "RST%d") +JMESSAGE(JTRC_SMOOTH_NOTIMPL, + "Smoothing not supported with nonstandard sampling ratios") +JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d") +JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d") +JMESSAGE(JTRC_SOI, "Start of Image") +JMESSAGE(JTRC_SOS, "Start Of Scan: %d components") +JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d") +JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d") +JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s") +JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s") +JMESSAGE(JTRC_THUMB_JPEG, + "JFIF extension marker: JPEG-compressed thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_PALETTE, + "JFIF extension marker: palette thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_RGB, + "JFIF extension marker: RGB thumbnail image, length %u") +JMESSAGE(JTRC_UNKNOWN_IDS, + "Unrecognized component IDs %d %d %d, assuming YCbCr") +JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u") +JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u") +JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d") +#if JPEG_LIB_VERSION >= 70 +JMESSAGE(JWRN_ARITH_BAD_CODE, "Corrupt JPEG data: bad arithmetic code") +#endif +JMESSAGE(JWRN_BOGUS_PROGRESSION, + "Inconsistent progression sequence for component %d coefficient %d") +JMESSAGE(JWRN_EXTRANEOUS_DATA, + "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x") +JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment") +JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code") +JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d") +JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file") +JMESSAGE(JWRN_MUST_RESYNC, + "Corrupt JPEG data: found marker 0x%02x instead of RST%d") +JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG") +JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines") +#if JPEG_LIB_VERSION < 70 +JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request") +#if defined(C_ARITH_CODING_SUPPORTED) || defined(D_ARITH_CODING_SUPPORTED) +JMESSAGE(JERR_NO_ARITH_TABLE, "Arithmetic table 0x%02x was not defined") +JMESSAGE(JWRN_ARITH_BAD_CODE, "Corrupt JPEG data: bad arithmetic code") +#endif +#endif + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTMSGCODE +} J_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE + + +#ifndef JERROR_H +#define JERROR_H + +/* Macros to simplify using the error and trace message stuff */ +/* The first parameter is either type of cinfo pointer */ + +/* Fatal errors (print message and exit) */ +#define ERREXIT(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT3(cinfo,code,p1,p2,p3) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (cinfo)->err->msg_parm.i[3] = (p4), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXITS(cinfo,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) + +#define MAKESTMT(stuff) do { stuff } while (0) + +/* Nonfatal errors (we can keep going, but the data is probably corrupt) */ +#define WARNMS(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) + +/* Informational/debugging messages */ +#define TRACEMS(cinfo,lvl,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS1(cinfo,lvl,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS2(cinfo,lvl,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS5(cinfo,lvl,code,p1,p2,p3,p4,p5) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMSS(cinfo,lvl,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) + +#endif /* JERROR_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jinclude.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jinclude.h new file mode 100644 index 0000000..0a4f151 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jinclude.h @@ -0,0 +1,91 @@ +/* + * jinclude.h + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file exists to provide a single place to fix any problems with + * including the wrong system include files. (Common problems are taken + * care of by the standard jconfig symbols, but on really weird systems + * you may have to edit this file.) + * + * NOTE: this file is NOT intended to be included by applications using the + * JPEG library. Most applications need only include jpeglib.h. + */ + + +/* Include auto-config file to find out which system include files we need. */ + +#include "jconfig.h" /* auto configuration options */ +#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ + +/* + * We need the NULL macro and size_t typedef. + * On an ANSI-conforming system it is sufficient to include . + * Otherwise, we get them from or ; we may have to + * pull in as well. + * Note that the core JPEG library does not require ; + * only the default error handler and data source/destination modules do. + * But we must pull it in because of the references to FILE in jpeglib.h. + * You can remove those references if you want to compile without . + */ + +#ifdef HAVE_STDDEF_H +#include +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef NEED_SYS_TYPES_H +#include +#endif + +#include + +/* + * We need memory copying and zeroing functions, plus strncpy(). + * ANSI and System V implementations declare these in . + * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). + * Some systems may declare memset and memcpy in . + * + * NOTE: we assume the size parameters to these functions are of type size_t. + * Change the casts in these macros if not! + */ + +#ifdef NEED_BSD_STRINGS + +#include +#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size)) +#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size)) + +#else /* not BSD, assume ANSI/SysV string lib */ + +#include +#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size)) +#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size)) + +#endif + +/* + * In ANSI C, and indeed any rational implementation, size_t is also the + * type returned by sizeof(). However, it seems there are some irrational + * implementations out there, in which sizeof() returns an int even though + * size_t is defined as long or unsigned long. To ensure consistent results + * we always use this SIZEOF() macro in place of using sizeof() directly. + */ + +#define SIZEOF(object) ((size_t) sizeof(object)) + +/* + * The modules that use fread() and fwrite() always invoke them through + * these macros. On some systems you may need to twiddle the argument casts. + * CAUTION: argument order is different from underlying functions! + */ + +#define JFREAD(file,buf,sizeofbuf) \ + ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFWRITE(file,buf,sizeofbuf) \ + ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jmemsys.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jmemsys.h new file mode 100644 index 0000000..b190945 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jmemsys.h @@ -0,0 +1,198 @@ +/* + * jmemsys.h + * + * Copyright (C) 1992-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file defines the interface between the system-independent + * and system-dependent portions of the JPEG memory manager. No other + * modules need include it. (The system-independent portion is jmemmgr.c; + * there are several different versions of the system-dependent portion.) + * + * This file works as-is for the system-dependent memory managers supplied + * in the IJG distribution. You may need to modify it if you write a + * custom memory manager. If system-dependent changes are needed in + * this file, the best method is to #ifdef them based on a configuration + * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR + * and USE_MAC_MEMMGR. + */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_get_small jGetSmall +#define jpeg_free_small jFreeSmall +#define jpeg_get_large jGetLarge +#define jpeg_free_large jFreeLarge +#define jpeg_mem_available jMemAvail +#define jpeg_open_backing_store jOpenBackStore +#define jpeg_mem_init jMemInit +#define jpeg_mem_term jMemTerm +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* + * These two functions are used to allocate and release small chunks of + * memory. (Typically the total amount requested through jpeg_get_small is + * no more than 20K or so; this will be requested in chunks of a few K each.) + * Behavior should be the same as for the standard library functions malloc + * and free; in particular, jpeg_get_small must return NULL on failure. + * On most systems, these ARE malloc and free. jpeg_free_small is passed the + * size of the object being freed, just in case it's needed. + * On an 80x86 machine using small-data memory model, these manage near heap. + */ + +EXTERN(void *) jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject)); +EXTERN(void) jpeg_free_small JPP((j_common_ptr cinfo, void * object, + size_t sizeofobject)); + +/* + * These two functions are used to allocate and release large chunks of + * memory (up to the total free space designated by jpeg_mem_available). + * The interface is the same as above, except that on an 80x86 machine, + * far pointers are used. On most other machines these are identical to + * the jpeg_get/free_small routines; but we keep them separate anyway, + * in case a different allocation strategy is desirable for large chunks. + */ + +EXTERN(void FAR *) jpeg_get_large JPP((j_common_ptr cinfo, + size_t sizeofobject)); +EXTERN(void) jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object, + size_t sizeofobject)); + +/* + * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may + * be requested in a single call to jpeg_get_large (and jpeg_get_small for that + * matter, but that case should never come into play). This macro is needed + * to model the 64Kb-segment-size limit of far addressing on 80x86 machines. + * On those machines, we expect that jconfig.h will provide a proper value. + * On machines with 32-bit flat address spaces, any large constant may be used. + * + * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type + * size_t and will be a multiple of sizeof(align_type). + */ + +#ifndef MAX_ALLOC_CHUNK /* may be overridden in jconfig.h */ +#define MAX_ALLOC_CHUNK 1000000000L +#endif + +/* + * This routine computes the total space still available for allocation by + * jpeg_get_large. If more space than this is needed, backing store will be + * used. NOTE: any memory already allocated must not be counted. + * + * There is a minimum space requirement, corresponding to the minimum + * feasible buffer sizes; jmemmgr.c will request that much space even if + * jpeg_mem_available returns zero. The maximum space needed, enough to hold + * all working storage in memory, is also passed in case it is useful. + * Finally, the total space already allocated is passed. If no better + * method is available, cinfo->mem->max_memory_to_use - already_allocated + * is often a suitable calculation. + * + * It is OK for jpeg_mem_available to underestimate the space available + * (that'll just lead to more backing-store access than is really necessary). + * However, an overestimate will lead to failure. Hence it's wise to subtract + * a slop factor from the true available space. 5% should be enough. + * + * On machines with lots of virtual memory, any large constant may be returned. + * Conversely, zero may be returned to always use the minimum amount of memory. + */ + +EXTERN(size_t) jpeg_mem_available JPP((j_common_ptr cinfo, + size_t min_bytes_needed, + size_t max_bytes_needed, + size_t already_allocated)); + + +/* + * This structure holds whatever state is needed to access a single + * backing-store object. The read/write/close method pointers are called + * by jmemmgr.c to manipulate the backing-store object; all other fields + * are private to the system-dependent backing store routines. + */ + +#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */ + + +#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */ + +typedef unsigned short XMSH; /* type of extended-memory handles */ +typedef unsigned short EMSH; /* type of expanded-memory handles */ + +typedef union { + short file_handle; /* DOS file handle if it's a temp file */ + XMSH xms_handle; /* handle if it's a chunk of XMS */ + EMSH ems_handle; /* handle if it's a chunk of EMS */ +} handle_union; + +#endif /* USE_MSDOS_MEMMGR */ + +#ifdef USE_MAC_MEMMGR /* Mac-specific junk */ +#include +#endif /* USE_MAC_MEMMGR */ + + +typedef struct backing_store_struct * backing_store_ptr; + +typedef struct backing_store_struct { + /* Methods for reading/writing/closing this backing-store object */ + JMETHOD(void, read_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, write_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, close_backing_store, (j_common_ptr cinfo, + backing_store_ptr info)); + + /* Private fields for system-dependent backing-store management */ +#ifdef USE_MSDOS_MEMMGR + /* For the MS-DOS manager (jmemdos.c), we need: */ + handle_union handle; /* reference to backing-store storage object */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else +#ifdef USE_MAC_MEMMGR + /* For the Mac manager (jmemmac.c), we need: */ + short temp_file; /* file reference number to temp file */ + FSSpec tempSpec; /* the FSSpec for the temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else + /* For a typical implementation with temp files, we need: */ + FILE * temp_file; /* stdio reference to temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */ +#endif +#endif +} backing_store_info; + + +/* + * Initial opening of a backing-store object. This must fill in the + * read/write/close pointers in the object. The read/write routines + * may take an error exit if the specified maximum file size is exceeded. + * (If jpeg_mem_available always returns a large value, this routine can + * just take an error exit.) + */ + +EXTERN(void) jpeg_open_backing_store JPP((j_common_ptr cinfo, + backing_store_ptr info, + long total_bytes_needed)); + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. jpeg_mem_init will be called before anything is + * allocated (and, therefore, nothing in cinfo is of use except the error + * manager pointer). It should return a suitable default value for + * max_memory_to_use; this may subsequently be overridden by the surrounding + * application. (Note that max_memory_to_use is only important if + * jpeg_mem_available chooses to consult it ... no one else will.) + * jpeg_mem_term may assume that all requested memory has been freed and that + * all opened backing-store objects have been closed. + */ + +EXTERN(long) jpeg_mem_init JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_mem_term JPP((j_common_ptr cinfo)); diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jmorecfg.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jmorecfg.h new file mode 100644 index 0000000..f762ae7 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jmorecfg.h @@ -0,0 +1,446 @@ +/* + * jmorecfg.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Copyright (C) 2009, 2011, D. R. Commander. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains additional configuration options that customize the + * JPEG software for special applications or support machine-dependent + * optimizations. Most users will not need to touch this file. + */ + +/* + * When we're building for android, turn on ANDROID_RGB by default. + * This is needed for components like skia which make use of the + * new encodings defined behind ANDROID_RBG. It's not a reasonable + * config to have ANDROID_RBG off. + */ +#ifdef ANDROID +#ifndef ANDROID_RGB +#define ANDROID_RGB +#endif +#endif + +/* + * Define BITS_IN_JSAMPLE as either + * 8 for 8-bit sample values (the usual setting) + * 12 for 12-bit sample values + * Only 8 and 12 are legal data precisions for lossy JPEG according to the + * JPEG standard, and the IJG code does not support anything else! + * We do not support run-time selection of data precision, sorry. + */ + +#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ + + +/* + * Maximum number of components (color channels) allowed in JPEG image. + * To meet the letter of the JPEG spec, set this to 255. However, darn + * few applications need more than 4 channels (maybe 5 for CMYK + alpha + * mask). We recommend 10 as a reasonable compromise; use 4 if you are + * really short on memory. (Each allowed component costs a hundred or so + * bytes of storage, whether actually used in an image or not.) + */ + +#define MAX_COMPONENTS 10 /* maximum number of image components */ + + +/* + * Basic data types. + * You may need to change these if you have a machine with unusual data + * type sizes; for example, "char" not 8 bits, "short" not 16 bits, + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + * but it had better be at least 16. + */ + +/* Representation of a single sample (pixel element value). + * We frequently allocate large arrays of these, so it's important to keep + * them small. But if you have memory to burn and access to char or short + * arrays is very slow on your hardware, you might want to change these. + */ + +#if BITS_IN_JSAMPLE == 8 +/* JSAMPLE should be the smallest type that will hold the values 0..255. + * You can use a signed char by having GETJSAMPLE mask it with 0xFF. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JSAMPLE; +#ifdef __CHAR_UNSIGNED__ +#define GETJSAMPLE(value) ((int) (value)) +#else +#define GETJSAMPLE(value) ((int) (value) & 0xFF) +#endif /* __CHAR_UNSIGNED__ */ + +#endif /* HAVE_UNSIGNED_CHAR */ + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 + +#endif /* BITS_IN_JSAMPLE == 8 */ + + +#if BITS_IN_JSAMPLE == 12 +/* JSAMPLE should be the smallest type that will hold the values 0..4095. + * On nearly all machines "short" will do nicely. + */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#define MAXJSAMPLE 4095 +#define CENTERJSAMPLE 2048 + +#endif /* BITS_IN_JSAMPLE == 12 */ + + +/* Representation of a DCT frequency coefficient. + * This should be a signed value of at least 16 bits; "short" is usually OK. + * Again, we allocate large arrays of these, but you can change to int + * if you have memory to burn and "short" is really slow. + */ + +typedef short JCOEF; + + +/* Compressed datastreams are represented as arrays of JOCTET. + * These must be EXACTLY 8 bits wide, at least once they are written to + * external storage. Note that when using the stdio data source/destination + * managers, this is also the data type passed to fread/fwrite. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JOCTET; +#define GETJOCTET(value) (value) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JOCTET; +#ifdef __CHAR_UNSIGNED__ +#define GETJOCTET(value) (value) +#else +#define GETJOCTET(value) ((value) & 0xFF) +#endif /* __CHAR_UNSIGNED__ */ + +#endif /* HAVE_UNSIGNED_CHAR */ + + +/* These typedefs are used for various table entries and so forth. + * They must be at least as wide as specified; but making them too big + * won't cost a huge amount of memory, so we don't provide special + * extraction code like we did for JSAMPLE. (In other words, these + * typedefs live at a different point on the speed/space tradeoff curve.) + */ + +/* UINT8 must hold at least the values 0..255. */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char UINT8; +#else /* not HAVE_UNSIGNED_CHAR */ +#ifdef __CHAR_UNSIGNED__ +typedef char UINT8; +#else /* not __CHAR_UNSIGNED__ */ +typedef short UINT8; +#endif /* __CHAR_UNSIGNED__ */ +#endif /* HAVE_UNSIGNED_CHAR */ + +/* UINT16 must hold at least the values 0..65535. */ + +#ifdef HAVE_UNSIGNED_SHORT +typedef unsigned short UINT16; +#else /* not HAVE_UNSIGNED_SHORT */ +typedef unsigned int UINT16; +#endif /* HAVE_UNSIGNED_SHORT */ + +/* INT16 must hold at least the values -32768..32767. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ +typedef short INT16; +#endif + +/* INT32 must hold at least signed 32-bit values. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ +typedef long INT32; +#endif + +/* Datatype used for image dimensions. The JPEG standard only supports + * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore + * "unsigned int" is sufficient on all machines. However, if you need to + * handle larger images and you don't mind deviating from the spec, you + * can change this datatype. + */ + +typedef unsigned int JDIMENSION; + +#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ + + +/* These macros are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions; + * in particular, you'll need to do that to make the library a Windows DLL. + * Another application is to make all functions global for use with debuggers + * or code profilers that require it. + */ + +/* a function called through method pointers: */ +#define METHODDEF(type) static type +/* a function used only in its module: */ +#define LOCAL(type) static type +/* a function referenced thru EXTERNs: */ +#define GLOBAL(type) type +/* a reference to a GLOBAL function: */ +#define EXTERN(type) extern type + + +/* This macro is used to declare a "method", that is, a function pointer. + * We want to supply prototype parameters if the compiler can cope. + * Note that the arglist parameter must be parenthesized! + * Again, you can customize this if you need special linkage keywords. + */ + +#ifdef HAVE_PROTOTYPES +#define JMETHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define JMETHOD(type,methodname,arglist) type (*methodname) () +#endif + + +/* Here is the pseudo-keyword for declaring pointers that must be "far" + * on 80x86 machines. Most of the specialized coding for 80x86 is handled + * by just saying "FAR *" where such a pointer is needed. In a few places + * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. + */ + +#ifdef NEED_FAR_POINTERS +#define FAR far +#else +#define FAR +#endif + + +/* + * On a few systems, type boolean and/or its values FALSE, TRUE may appear + * in standard header files. Or you may have conflicts with application- + * specific header files that you want to include together with these files. + * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. + */ + +#ifndef HAVE_BOOLEAN +typedef int boolean; +#endif +#ifndef FALSE /* in case these macros already exist */ +#define FALSE 0 /* values of boolean */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif + + +/* + * The remaining options affect code selection within the JPEG library, + * but they don't need to be visible to most applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. + */ + +#ifdef JPEG_INTERNALS +#define JPEG_INTERNAL_OPTIONS +#endif + +#ifdef JPEG_INTERNAL_OPTIONS + + +/* + * These defines indicate whether to include various optional functions. + * Undefining some of these symbols will produce a smaller but less capable + * library. Note that you can leave certain source files out of the + * compilation/linking process if you've #undef'd the corresponding symbols. + * (You may HAVE to do that if your compiler doesn't like null source files.) + */ + +/* Capability options common to encoder and decoder: */ + +#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ +#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ +#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ + +/* Encoder capability options: */ + +#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ +/* Note: if you selected 12-bit data precision, it is dangerous to turn off + * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit + * precision, so jchuff.c normally uses entropy optimization to compute + * usable tables for higher precision. If you don't want to do optimization, + * you'll have to supply different default Huffman tables. + * The exact same statements apply for progressive JPEG: the default tables + * don't work for progressive mode. (This may get fixed, however.) + */ +#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ + +/* Decoder capability options: */ + +#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ +#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ +#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ +#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ +#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ +#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ +#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ + +/* more capability options later, no doubt */ + + +/* + * Ordering of RGB data in scanlines passed to or from the application. + * If your application wants to deal with data in the order B,G,R, just + * change these macros. You can also deal with formats such as R,G,B,X + * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing + * the offsets will also change the order in which colormap data is organized. + * RESTRICTIONS: + * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. + * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not + * useful if you are using JPEG color spaces other than YCbCr or grayscale. + * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE + * is not 3 (they don't understand about dummy color components!). So you + * can't use color quantization if you change that value. + */ + +#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ +#define RGB_GREEN 1 /* Offset of Green */ +#define RGB_BLUE 2 /* Offset of Blue */ +#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ + +#ifdef ANDROID_RGB +#define RGB_ALPHA 3 /* Offset of Alpha */ +#endif + +#define JPEG_NUMCS 16 + +#define EXT_RGB_RED 0 +#define EXT_RGB_GREEN 1 +#define EXT_RGB_BLUE 2 +#define EXT_RGB_PIXELSIZE 3 + +#define EXT_RGBX_RED 0 +#define EXT_RGBX_GREEN 1 +#define EXT_RGBX_BLUE 2 +#define EXT_RGBX_PIXELSIZE 4 + +#define EXT_BGR_RED 2 +#define EXT_BGR_GREEN 1 +#define EXT_BGR_BLUE 0 +#define EXT_BGR_PIXELSIZE 3 + +#define EXT_BGRX_RED 2 +#define EXT_BGRX_GREEN 1 +#define EXT_BGRX_BLUE 0 +#define EXT_BGRX_PIXELSIZE 4 + +#define EXT_XBGR_RED 3 +#define EXT_XBGR_GREEN 2 +#define EXT_XBGR_BLUE 1 +#define EXT_XBGR_PIXELSIZE 4 + +#define EXT_XRGB_RED 1 +#define EXT_XRGB_GREEN 2 +#define EXT_XRGB_BLUE 3 +#define EXT_XRGB_PIXELSIZE 4 + +#ifdef ANDROID_RGB +#define RGB_ALPHA 3 /* Offset of Alpha */ +#endif + +static const int rgb_red[JPEG_NUMCS] = { + -1, -1, RGB_RED, -1, -1, -1, EXT_RGB_RED, EXT_RGBX_RED, + EXT_BGR_RED, EXT_BGRX_RED, EXT_XBGR_RED, EXT_XRGB_RED, + EXT_RGBX_RED, EXT_BGRX_RED, EXT_XBGR_RED, EXT_XRGB_RED +}; + +static const int rgb_green[JPEG_NUMCS] = { + -1, -1, RGB_GREEN, -1, -1, -1, EXT_RGB_GREEN, EXT_RGBX_GREEN, + EXT_BGR_GREEN, EXT_BGRX_GREEN, EXT_XBGR_GREEN, EXT_XRGB_GREEN, + EXT_RGBX_GREEN, EXT_BGRX_GREEN, EXT_XBGR_GREEN, EXT_XRGB_GREEN +}; + +static const int rgb_blue[JPEG_NUMCS] = { + -1, -1, RGB_BLUE, -1, -1, -1, EXT_RGB_BLUE, EXT_RGBX_BLUE, + EXT_BGR_BLUE, EXT_BGRX_BLUE, EXT_XBGR_BLUE, EXT_XRGB_BLUE, + EXT_RGBX_BLUE, EXT_BGRX_BLUE, EXT_XBGR_BLUE, EXT_XRGB_BLUE +}; + +static const int rgb_pixelsize[JPEG_NUMCS] = { + -1, -1, RGB_PIXELSIZE, -1, -1, -1, EXT_RGB_PIXELSIZE, EXT_RGBX_PIXELSIZE, + EXT_BGR_PIXELSIZE, EXT_BGRX_PIXELSIZE, EXT_XBGR_PIXELSIZE, EXT_XRGB_PIXELSIZE, + EXT_RGBX_PIXELSIZE, EXT_BGRX_PIXELSIZE, EXT_XBGR_PIXELSIZE, EXT_XRGB_PIXELSIZE +}; + + +/* + * Define ANDROID_RGB to enable specific optimizations for Android + * JCS_RGBA_8888 support + * JCS_RGB_565 support + * + */ + +#ifdef ANDROID_RGB +#define PACK_SHORT_565(r,g,b) ((((r)<<8)&0xf800)|(((g)<<3)&0x7E0)|((b)>>3)) +#define PACK_TWO_PIXELS(l,r) ((r<<16) | l) +#define PACK_NEED_ALIGNMENT(ptr) (((int)(ptr))&3) +#define WRITE_TWO_PIXELS(addr, pixels) do { \ + ((INT16*)(addr))[0] = (pixels); \ + ((INT16*)(addr))[1] = (pixels)>>16; \ + } while(0) +#define WRITE_TWO_ALIGNED_PIXELS(addr, pixels) ((*(INT32*)(addr)) = pixels) +#define DITHER_565_R(r, dither) ((r) + ((dither)&0xFF)) +#define DITHER_565_G(g, dither) ((g) + (((dither)&0xFF)>>1)) +#define DITHER_565_B(b, dither) ((b) + ((dither)&0xFF)) +#endif + + +/* Definitions for speed-related optimizations. */ + +/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying + * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER + * as short on such a machine. MULTIPLIER must be at least 16 bits wide. + */ + +#ifndef MULTIPLIER +#ifndef WITH_SIMD +#define MULTIPLIER int /* type for fastest integer multiply */ +#else +#define MULTIPLIER short /* prefer 16-bit with SIMD for parellelism */ +#endif +#endif + + +/* FAST_FLOAT should be either float or double, whichever is done faster + * by your compiler. (Note that this type is only used in the floating point + * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) + * Typically, float is faster in ANSI C compilers, while double is faster in + * pre-ANSI compilers (because they insist on converting to double anyway). + * The code below therefore chooses float if we have ANSI-style prototypes. + */ + +#ifndef FAST_FLOAT +#ifdef HAVE_PROTOTYPES +#define FAST_FLOAT float +#else +#define FAST_FLOAT double +#endif +#endif + +#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jpegcomp.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jpegcomp.h new file mode 100644 index 0000000..1b9e0a4 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jpegcomp.h @@ -0,0 +1,26 @@ +/* + * jpegcomp.h + * + * Copyright (C) 2010, D. R. Commander + * For conditions of distribution and use, see the accompanying README file. + * + * JPEG compatibility macros + * These declarations are considered internal to the JPEG library; most + * applications using the library shouldn't need to include this file. + */ + +#if JPEG_LIB_VERSION >= 70 +#define _DCT_scaled_size DCT_h_scaled_size +#define _min_DCT_scaled_size min_DCT_h_scaled_size +#define _min_DCT_h_scaled_size min_DCT_h_scaled_size +#define _min_DCT_v_scaled_size min_DCT_v_scaled_size +#define _jpeg_width jpeg_width +#define _jpeg_height jpeg_height +#else +#define _DCT_scaled_size DCT_scaled_size +#define _min_DCT_scaled_size min_DCT_scaled_size +#define _min_DCT_h_scaled_size min_DCT_scaled_size +#define _min_DCT_v_scaled_size min_DCT_scaled_size +#define _jpeg_width image_width +#define _jpeg_height image_height +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jpegint.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jpegint.h new file mode 100644 index 0000000..a849a47 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jpegint.h @@ -0,0 +1,460 @@ +/* + * jpegint.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 1997-2009 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides common declarations for the various JPEG modules. + * These declarations are considered internal to the JPEG library; most + * applications using the library shouldn't need to include this file. + */ + + +/* Declarations for both compression & decompression */ + +typedef enum { /* Operating modes for buffer controllers */ + JBUF_PASS_THRU, /* Plain stripwise operation */ + /* Remaining modes require a full-image buffer to have been created */ + JBUF_SAVE_SOURCE, /* Run source subobject only, writeFileAsync output */ + JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ + JBUF_SAVE_AND_PASS /* Run both subobjects, writeFileAsync output */ +} J_BUF_MODE; + +/* Values of global_state field (jdapi.c has some dependencies on ordering!) */ +#define CSTATE_START 100 /* after create_compress */ +#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */ +#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */ +#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */ +#define DSTATE_START 200 /* after create_decompress */ +#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ +#define DSTATE_READY 202 /* found SOS, ready for start_decompress */ +#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/ +#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */ +#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */ +#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */ +#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */ +#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */ +#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */ +#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ + + +/* Declarations for compression modules */ + +/* Master control module */ +struct jpeg_comp_master { + JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo)); + JMETHOD(void, pass_startup, (j_compress_ptr cinfo)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean call_pass_startup; /* True if pass_startup must be called */ + boolean is_last_pass; /* True during last pass */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_c_main_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail)); +}; + +/* Compression preprocessing (downsampling input buffer control) */ +struct jpeg_c_prep_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, pre_process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, + JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail)); +}; + +/* Coefficient buffer control */ +struct jpeg_c_coef_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(boolean, compress_data, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf)); +}; + +/* Colorspace conversion */ +struct jpeg_color_converter { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, color_convert, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +}; + +/* Downsampling */ +struct jpeg_downsampler { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, downsample, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + JSAMPIMAGE output_buf, + JDIMENSION out_row_group_index)); + + boolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Forward DCT (also controls coefficient quantization) */ +struct jpeg_forward_dct { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + /* perhaps this should be an array??? */ + JMETHOD(void, forward_DCT, (j_compress_ptr cinfo, + jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks)); +}; + +/* Entropy encoding */ +struct jpeg_entropy_encoder { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics)); + JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); +}; + +/* Marker writing */ +struct jpeg_marker_writer { + JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_frame_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_scan_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo)); + JMETHOD(void, write_tables_only, (j_compress_ptr cinfo)); + /* These routines are exported to allow insertion of extra markers */ + /* Probably only COM and APPn markers should be written this way */ + JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker, + unsigned int datalen)); + JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val)); +}; + + +/* Declarations for decompression modules */ + +/* Master control module */ +struct jpeg_decomp_master { + JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ +}; + +/* Input control module */ +struct jpeg_input_controller { + JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); + JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean has_multiple_scans; /* True if file has multiple scans */ + boolean eoi_reached; /* True when EOI has been consumed */ + +#ifdef ANDROID + JMETHOD(int, consume_input_build_huffman_index, (j_decompress_ptr cinfo, + huffman_index *index, int scan_count)); + JMETHOD(int, consume_markers, (j_decompress_ptr cinfo, + huffman_index *index, int scan_count)); +#endif +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_d_main_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Coefficient buffer control */ +struct jpeg_d_coef_controller { + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); + JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, + JSAMPIMAGE output_buf)); + + /* Pointer to array of coefficient virtual arrays, or NULL if none */ + jvirt_barray_ptr *coef_arrays; + +#ifdef ANDROID + JMETHOD(int, consume_data_build_huffman_index, (j_decompress_ptr cinfo, + huffman_index* index, int scan_count)); + + /* column number of the first and last tile, respectively */ + int column_left_boundary; + int column_right_boundary; + + /* column number of the first and last MCU, respectively */ + int MCU_column_left_boundary; + int MCU_column_right_boundary; + + /* the number of MCU columns to skip from the indexed MCU, iM, + * to the requested MCU boundary, rM, where iM is the MCU that we sample + * into our index and is the nearest one to the left of rM. + */ + int MCU_columns_to_skip; + +#endif +}; + +/* Decompression postprocessing (color quantization buffer control) */ +struct jpeg_d_post_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, post_process_data, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Marker reading & parsing */ +struct jpeg_marker_reader { + JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo)); + /* Read markers until SOS or EOI. + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + */ + JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); + /* Read a restart marker --- exported for use by entropy decoder only */ + jpeg_marker_parser_method read_restart_marker; + + /* State of marker reader --- nominally internal, but applications + * supplying COM or APPn handlers might like to know the state. + */ + boolean saw_SOI; /* found SOI? */ + boolean saw_SOF; /* found SOF? */ + int next_restart_num; /* next restart number expected (0-7) */ + unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ + +#ifdef ANDROID + JMETHOD(void, get_sos_marker_position, (j_decompress_ptr cinfo, + huffman_index *index)); + + int current_sos_marker_position; +#endif +}; + +/* Entropy decoding */ +struct jpeg_entropy_decoder { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); + + /* This is here to share code between baseline and progressive decoders; */ + /* other modules probably should not use it */ + boolean insufficient_data; /* set TRUE after emitting warning */ + +#ifdef ANDROID + JMETHOD(boolean, decode_mcu_discard_coef, (j_decompress_ptr cinfo)); + JMETHOD(void, configure_huffman_decoder, (j_decompress_ptr cinfo, + huffman_offset_data offset)); + JMETHOD(void, get_huffman_decoder_configuration, (j_decompress_ptr cinfo, + huffman_offset_data *offset)); + + huffman_index *index; +#endif +}; + +/* Inverse DCT (also performs dequantization) */ +typedef JMETHOD(void, inverse_DCT_method_ptr, + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col)); + +struct jpeg_inverse_dct { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + /* It is useful to allow each component to have a separate IDCT method. */ + inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS]; +}; + +/* Upsampling (note that upsampler must also call color converter) */ +struct jpeg_upsampler { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, upsample, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); + + boolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Colorspace conversion */ +struct jpeg_color_deconverter { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, color_convert, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +}; + +/* Color quantization or color precision reduction */ +struct jpeg_color_quantizer { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan)); + JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, + int num_rows)); + JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); +}; + + +/* Miscellaneous useful macros */ + +#undef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#undef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + + +/* We assume that right shift corresponds to signed division by 2 with + * rounding towards minus infinity. This is correct for typical "arithmetic + * shift" instructions that shift in copies of the sign bit. But some + * C compilers implement >> with an unsigned shift. For these machines you + * must define RIGHT_SHIFT_IS_UNSIGNED. + * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. + * It is only applied with constant shift counts. SHIFT_TEMPS must be + * included in the variables of any routine using RIGHT_SHIFT. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define SHIFT_TEMPS INT32 shift_temp; +#define RIGHT_SHIFT(x,shft) \ + ((shift_temp = (x)) < 0 ? \ + (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ + (shift_temp >> (shft))) +#else +#define SHIFT_TEMPS +#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jinit_compress_master jICompress +#define jinit_c_master_control jICMaster +#define jinit_c_main_controller jICMainC +#define jinit_c_prep_controller jICPrepC +#define jinit_c_coef_controller jICCoefC +#define jinit_color_converter jICColor +#define jinit_downsampler jIDownsampler +#define jinit_forward_dct jIFDCT +#define jinit_huff_encoder jIHEncoder +#define jinit_phuff_encoder jIPHEncoder +#define jinit_arith_encoder jIAEncoder +#define jinit_marker_writer jIMWriter +#define jinit_master_decompress jIDMaster +#define jinit_d_main_controller jIDMainC +#define jinit_d_coef_controller jIDCoefC +#define jinit_d_post_controller jIDPostC +#define jinit_input_controller jIInCtlr +#define jinit_marker_reader jIMReader +#define jinit_huff_decoder jIHDecoder +#define jinit_phuff_decoder jIPHDecoder +#define jinit_arith_decoder jIADecoder +#define jinit_inverse_dct jIIDCT +#define jinit_upsampler jIUpsampler +#define jinit_color_deconverter jIDColor +#define jinit_1pass_quantizer jI1Quant +#define jinit_2pass_quantizer jI2Quant +#define jinit_merged_upsampler jIMUpsampler +#define jinit_memory_mgr jIMemMgr +#define jdiv_round_up jDivRound +#define jround_up jRound +#define jcopy_sample_rows jCopySamples +#define jcopy_block_row jCopyBlocks +#define jzero_far jZeroFar +#define jpeg_zigzag_order jZIGTable +#define jpeg_natural_order jZAGTable +#define jpeg_aritab jAriTab +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Compression module initialization routines */ +EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo, + boolean transcode_only)); +EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_phuff_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_arith_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo)); +/* Decompression module initialization routines */ +EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_phuff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_arith_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); + +#ifdef ANDROID +EXTERN(void) jinit_huff_decoder_no_data JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_decompress_per_scan_setup (j_decompress_ptr cinfo); +#endif + +/* Memory manager initialization */ +EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo)); + +/* Utility routines in jutils.c */ +EXTERN(long) jdiv_round_up JPP((long a, long b)); +EXTERN(long) jround_up JPP((long a, long b)); +EXTERN(long) jmin JPP((long a, long b)); +EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, JDIMENSION num_cols)); +EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, + JDIMENSION num_blocks)); +EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero)); +EXTERN(void) jset_input_stream_position JPP((j_decompress_ptr cinfo, + int offset)); +EXTERN(void) jset_input_stream_position_bit JPP((j_decompress_ptr cinfo, + int byte_offset, int bit_left, INT32 buf)); + +EXTERN(int) jget_input_stream_position JPP((j_decompress_ptr cinfo)); + +/* Constant tables in jutils.c */ +#if 0 /* This table is not actually needed in v6a */ +extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ +#endif +extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ + +/* Arithmetic coding probability estimation tables in jaricom.c */ +extern const INT32 jpeg_aritab[]; + +/* Suppress undefined-structure complaints if necessary. */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +#endif +#endif /* INCOMPLETE_TYPES_BROKEN */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jpeglib.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jpeglib.h new file mode 100644 index 0000000..3811d7d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jpeglib.h @@ -0,0 +1,1611 @@ +/* + * jpeglib.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * Modified 2002-2009 by Guido Vollbeding. + * Copyright (C) 2009-2011, D. R. Commander. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the application interface for the JPEG library. + * Most applications using the library need only include this file, + * and perhaps jerror.h if they want to know the exact error codes. + */ + +#ifndef JPEGLIB_H +#define JPEGLIB_H + + +#include "stdio.h" + +/* + * First we include the configuration files that record how this + * installation of the JPEG library is set up. jconfig.h can be + * generated automatically for many systems. jmorecfg.h contains + * manual configuration options that most people need not worry about. + */ + +#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ + +#include "jconfig.h" /* widely used configuration options */ + +#endif + +#include "jmorecfg.h" /* seldom changed options */ + +#ifndef ANDROID +#ifdef __cplusplus +#ifndef DONT_USE_EXTERN_C +extern "C" { +#endif +#endif +#endif + + +/* Various constants determining the sizes of things. + * All of these are specified by the JPEG standard, so don't change them + * if you want to be compatible. + */ + +#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ +#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; + * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. + * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU + * to handle it. We even let you do this from the jconfig.h file. However, + * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe + * sometimes emits noncompliant files doesn't mean you should too. + */ +#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ +#ifndef D_MAX_BLOCKS_IN_MCU +#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ +#endif + + +/* Data structures for images (arrays of samples and of DCT coefficients). + * On 80x86 machines, the image arrays are too big for near pointers, + * but the pointer arrays can fit in near memory. + */ + +typedef JSAMPLE FAR *JSAMPROW; +/* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; +/* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; +/* a 3-D sample array: top index is color */ + +typedef JCOEF JBLOCK[DCTSIZE2]; +/* one block of coefficients */ +typedef JBLOCK FAR *JBLOCKROW; +/* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; +/* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; +/* a 3-D array of coefficient blocks */ + +typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ + + +/* Types for JPEG compression parameters and working tables. */ + + +/* DCT coefficient quantization tables. */ + +typedef struct { + /* This array gives the coefficient quantizers in natural array order + * (not the zigzag order in which they are stored in a JPEG DQT marker). + * CAUTION: IJG versions prior to v6a kept this array in zigzag order. + */ + UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JQUANT_TBL; + + +/* Huffman coding tables. */ + +typedef struct { + /* These two fields directly represent the contents of a JPEG DHT marker */ + UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + UINT8 huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JHUFF_TBL; + + +/* Basic info about one component (color channel). */ + +typedef struct { + /* These values are fixed over the whole image. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOF marker. */ + int component_id; + /* identifier for this component (0..255) */ + int component_index; + /* its index in SOF or cinfo->comp_info[] */ + int h_samp_factor; + /* horizontal sampling factor (1..4) */ + int v_samp_factor; + /* vertical sampling factor (1..4) */ + int quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOS marker. */ + /* The decompressor output side may not use these variables. */ + int dc_tbl_no; + /* DC entropy table selector (0..3) */ + int ac_tbl_no; /* AC entropy table selector (0..3) */ + + /* Remaining fields should be treated as private by applications. */ + + /* These values are computed during compression or decompression startup: */ + /* Component's size in DCT blocks. + * Any dummy blocks added to complete an MCU are not counted; therefore + * these values do not depend on whether a scan is interleaved or not. + */ + JDIMENSION width_in_blocks; + JDIMENSION height_in_blocks; + /* Size of a DCT block in samples. Always DCTSIZE for compression. + * For decompression this is the size of the output from one DCT block, + * reflecting any scaling we choose to apply during the IDCT step. + * Values of 1,2,4,8 are likely to be supported. Note that different + * components may receive different IDCT scalings. + */ +#if JPEG_LIB_VERSION >= 70 + int DCT_h_scaled_size; + int DCT_v_scaled_size; +#else + int DCT_scaled_size; +#endif + /* The downsampled dimensions are the component's actual, unpadded number + * of samples at the main buffer (preprocessing/compression interface), thus + * downsampled_width = ceil(image_width * Hi/Hmax) + * and similarly for height. For decompression, IDCT scaling is included, so + * downsampled_width = ceil(image_width * Hi/Hmax * DCT_[h_]scaled_size/DCTSIZE) + */ + JDIMENSION downsampled_width; + /* actual width in samples */ + JDIMENSION downsampled_height; /* actual height in samples */ + /* This flag is used only for decompression. In cases where some of the + * components will be ignored (eg grayscale output from YCbCr image), + * we can skip most computations for the unused components. + */ + boolean component_needed; /* do we need the value of this component? */ + + /* These values are computed before starting a scan of the component. */ + /* The decompressor output side may not use these variables. */ + int MCU_width; + /* number of blocks per MCU, horizontally */ + int MCU_height; + /* number of blocks per MCU, vertically */ + int MCU_blocks; + /* MCU_width * MCU_height */ + int MCU_sample_width; + /* MCU width in samples, MCU_width*DCT_[h_]scaled_size */ + int last_col_width; + /* # of non-dummy blocks across in last MCU */ + int last_row_height; /* # of non-dummy blocks down in last MCU */ + + /* Saved quantization table for component; NULL if none yet saved. + * See jdinput.c comments about the need for this information. + * This field is currently used only for decompression. + */ + JQUANT_TBL *quant_table; + + /* Private per-component storage for DCT or IDCT subsystem. */ + void *dct_table; +} jpeg_component_info; + + +/* The script for encoding a multiple-scan file is an array of these: */ + +typedef struct { + int comps_in_scan; + /* number of components encoded in this scan */ + int component_index[MAX_COMPS_IN_SCAN]; + /* their SOF/comp_info[] indexes */ + int Ss, Se; + /* progressive JPEG spectral selection parms */ + int Ah, Al; /* progressive JPEG successive approx. parms */ +} jpeg_scan_info; + +/* The decompressor can writeFileAsync APPn and COM markers in a list of these: */ + +typedef struct jpeg_marker_struct FAR *jpeg_saved_marker_ptr; + +struct jpeg_marker_struct { + jpeg_saved_marker_ptr next; + /* next in list, or NULL */ + UINT8 marker; + /* marker code: JPEG_COM, or JPEG_APP0+n */ + unsigned int original_length; + /* # bytes of data in the file */ + unsigned int data_length; + /* # bytes of data saved at data[] */ + JOCTET FAR *data; /* the data contained in the marker */ + /* the marker length word is not counted in data_length or original_length */ +}; + +/* Known color spaces. */ + +#define JCS_EXTENSIONS 1 +#define JCS_ALPHA_EXTENSIONS 1 + +typedef enum { + JCS_UNKNOWN, /* error/unspecified */ + JCS_GRAYSCALE, /* monochrome */ + JCS_RGB, /* red/green/blue as specified by the RGB_RED, RGB_GREEN, + RGB_BLUE, and RGB_PIXELSIZE macros */ + JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ + JCS_CMYK, /* C/M/Y/K */ + JCS_YCCK, /* Y/Cb/Cr/K */ + JCS_EXT_RGB, /* red/green/blue */ + JCS_EXT_RGBX, /* red/green/blue/x */ + JCS_EXT_BGR, /* blue/green/red */ + JCS_EXT_BGRX, /* blue/green/red/x */ + JCS_EXT_XBGR, /* x/blue/green/red */ + JCS_EXT_XRGB, /* x/red/green/blue */ + /* When out_color_space it set to JCS_EXT_RGBX, JCS_EXT_BGRX, + JCS_EXT_XBGR, or JCS_EXT_XRGB during decompression, the X byte is + undefined, and in order to ensure the best performance, + libjpeg-turbo can set that byte to whatever value it wishes. Use + the following colorspace constants to ensure that the X byte is set + to 0xFF, so that it can be interpreted as an opaque alpha + channel. */ + JCS_EXT_RGBA, /* red/green/blue/alpha */ + JCS_EXT_BGRA, /* blue/green/red/alpha */ + JCS_EXT_ABGR, /* alpha/blue/green/red */ + JCS_EXT_ARGB, /* alpha/red/green/blue */ +#ifdef ANDROID_RGB + JCS_RGBA_8888, /* red/green/blue/alpha */ + JCS_RGB_565 /* red/green/blue in 565 format */ +#endif +} J_COLOR_SPACE; + +/* DCT/IDCT algorithm options. */ + +typedef enum { + JDCT_ISLOW, /* slow but accurate integer algorithm */ + JDCT_IFAST, /* faster, less accurate integer method */ + JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ +} J_DCT_METHOD; + +#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ +#define JDCT_DEFAULT JDCT_ISLOW +#endif +#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ +#define JDCT_FASTEST JDCT_IFAST +#endif + +/* Dithering options for decompression. */ + +typedef enum { + JDITHER_NONE, /* no dithering */ + JDITHER_ORDERED, /* simple ordered dither */ + JDITHER_FS /* Floyd-Steinberg error diffusion dither */ +} J_DITHER_MODE; + + +/* Common fields between JPEG compression and decompression master structs. */ + +#define jpeg_common_fields \ + struct jpeg_error_mgr * err; /* Error handler module */\ + struct jpeg_memory_mgr * mem; /* Memory manager module */\ + struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ + void * client_data; /* Available for use by application */\ + boolean is_decompressor; /* So common code can tell which is which */\ + int global_state /* For checking call sequence validity */ + +/* Routines that are to be used by both halves of the library are declared + * to receive a pointer to this structure. There are no actual instances of + * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. + */ +struct jpeg_common_struct { + jpeg_common_fields; /* Fields common to both master struct types */ + /* Additional fields follow in an actual jpeg_compress_struct or + * jpeg_decompress_struct. All three structs must agree on these + * initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct jpeg_common_struct *j_common_ptr; +typedef struct jpeg_compress_struct *j_compress_ptr; +typedef struct jpeg_decompress_struct *j_decompress_ptr; + + +/* Master record for a compression instance */ + +struct jpeg_compress_struct { + jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ + + /* Destination for compressed data */ + struct jpeg_destination_mgr *dest; + + /* Description of source image --- these fields must be filled in by + * outer application before starting compression. in_color_space must + * be correct before you can even call jpeg_set_defaults(). + */ + + JDIMENSION image_width; + /* input image width */ + JDIMENSION image_height; + /* input image height */ + int input_components; + /* # of color components in input image */ + J_COLOR_SPACE in_color_space; + /* colorspace of input image */ + + double input_gamma; /* image gamma of input image */ + + /* Compression parameters --- these fields must be set before calling + * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to + * initialize everything to reasonable defaults, then changing anything + * the application specifically wants to change. That way you won't get + * burnt when new parameters are added. Also note that there are several + * helper routines to simplify changing parameters. + */ + +#if JPEG_LIB_VERSION >= 70 + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + JDIMENSION jpeg_width; /* scaled JPEG image width */ + JDIMENSION jpeg_height; /* scaled JPEG image height */ + /* Dimensions of actual JPEG image that will be written to file, + * derived from input dimensions by scaling factors above. + * These fields are computed by jpeg_start_compress(). + * You can also use jpeg_calc_jpeg_dimensions() to determine these values + * in advance of calling jpeg_start_compress(). + */ +#endif + + int data_precision; + /* bits of precision in image data */ + + int num_components; + /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; + /* colorspace of JPEG image */ + + jpeg_component_info *comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + JQUANT_TBL *quant_tbl_ptrs[NUM_QUANT_TBLS]; +#if JPEG_LIB_VERSION >= 70 + int q_scale_factor[NUM_QUANT_TBLS]; +#endif + /* ptrs to coefficient quantization tables, or NULL if not defined, + * and corresponding scale factors (percentage, initialized 100). + */ + + JHUFF_TBL *dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL *ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; + /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; + /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; + /* Kx values for AC arith-coding tables */ + + int num_scans; + /* # of entries in scan_info array */ + const jpeg_scan_info *scan_info; /* script for multi-scan file, or NULL */ + /* The default value of scan_info is NULL, which causes a single-scan + * sequential JPEG file to be emitted. To create a multi-scan file, + * set num_scans and scan_info to point to an array of scan definitions. + */ + + boolean raw_data_in; + /* TRUE=caller supplies downsampled data */ + boolean arith_code; + /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean optimize_coding; + /* TRUE=optimize entropy encoding parms */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ +#if JPEG_LIB_VERSION >= 70 + boolean do_fancy_downsampling; /* TRUE=apply fancy downsampling */ +#endif + int smoothing_factor; + /* 1..100, or 0 for no input smoothing */ + J_DCT_METHOD dct_method; /* DCT algorithm selector */ + + /* The restart interval can be specified in absolute MCUs by setting + * restart_interval, or in MCU rows by setting restart_in_rows + * (in which case the correct restart_interval will be figured + * for each scan). + */ + unsigned int restart_interval; + /* MCUs per restart, or 0 for no restart */ + int restart_in_rows; /* if > 0, MCU rows per restart interval */ + + /* Parameters controlling emission of special markers. */ + + boolean write_JFIF_header; + /* should a JFIF marker be written? */ + UINT8 JFIF_major_version; + /* What to write for the JFIF version number */ + UINT8 JFIF_minor_version; + /* These three values are not used by the JPEG code, merely copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + UINT8 density_unit; + /* JFIF code for pixel size units */ + UINT16 X_density; + /* Horizontal pixel density */ + UINT16 Y_density; + /* Vertical pixel density */ + boolean write_Adobe_marker; /* should an Adobe marker be written? */ + + /* State variable: index of next scanline to be written to + * jpeg_write_scanlines(). Application may use this to control its + * processing loop, e.g., "while (next_scanline < image_height)". + */ + + JDIMENSION next_scanline; /* 0 .. image_height-1 */ + + /* Remaining fields are known throughout compressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during compression startup + */ + boolean progressive_mode; + /* TRUE if scan script uses progressive mode */ + int max_h_samp_factor; + /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + +#if JPEG_LIB_VERSION >= 70 + int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */ + int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */ +#endif + + JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ + /* The coefficient controller receives data in units of MCU rows as defined + * for fully interleaved scans (whether the JPEG file is interleaved or not). + * There are v_samp_factor * DCTSIZE sample rows of each component in an + * "iMCU" (interleaved MCU) row. + */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + */ + int comps_in_scan; + /* # of JPEG components in this scan */ + jpeg_component_info *cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; + /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; + /* # of MCU rows in the image */ + + int blocks_in_MCU; + /* # of DCT blocks per MCU */ + int MCU_membership[C_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + +#if JPEG_LIB_VERSION >= 80 + int block_size; /* the basic DCT block size: 1..16 */ + const int * natural_order; /* natural-order position array */ + int lim_Se; /* min( Se, DCTSIZE2-1 ) */ +#endif + + /* + * Links to compression subobjects (methods and private variables of modules) + */ + struct jpeg_comp_master *master; + struct jpeg_c_main_controller *main; + struct jpeg_c_prep_controller *prep; + struct jpeg_c_coef_controller *coef; + struct jpeg_marker_writer *marker; + struct jpeg_color_converter *cconvert; + struct jpeg_downsampler *downsample; + struct jpeg_forward_dct *fdct; + struct jpeg_entropy_encoder *entropy; + jpeg_scan_info *script_space; + /* workspace for jpeg_simple_progression */ + int script_space_size; +}; + + +/* Master record for a decompression instance */ + +struct jpeg_decompress_struct { + jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ + + /* Source of compressed data */ + struct jpeg_source_mgr *src; + + /* Basic description of image --- filled in by jpeg_read_header(). */ + /* Application may inspect these values to decide how to process image. */ + + JDIMENSION original_image_width; + /* nominal image width (from SOF marker) */ + JDIMENSION image_width; + /* nominal image width (from SOF marker) */ + JDIMENSION image_height; + /* nominal image height */ + int num_components; + /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + /* Decompression processing parameters --- these fields must be set before + * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes + * them to default values. + */ + + J_COLOR_SPACE out_color_space; + /* colorspace for output */ + + unsigned int scale_num, scale_denom; + /* fraction by which to scale image */ + + double output_gamma; + /* image gamma wanted in output */ + + boolean buffered_image; + /* TRUE=multiple output passes */ + boolean raw_data_out; + /* TRUE=downsampled data wanted */ + + J_DCT_METHOD dct_method; + /* IDCT algorithm selector */ + boolean do_fancy_upsampling; + /* TRUE=apply fancy upsampling */ + boolean do_block_smoothing; + /* TRUE=apply interblock smoothing */ + + boolean quantize_colors; /* TRUE=colormapped output wanted */ + /* the following are ignored if not quantize_colors: */ + J_DITHER_MODE dither_mode; + /* type of color dithering to use */ + boolean two_pass_quantize; + /* TRUE=use two-pass color quantization */ + int desired_number_of_colors; /* max # colors to use in created colormap */ + /* these are significant only in buffered-image mode: */ + boolean enable_1pass_quant; + /* enable future use of 1-pass quantizer */ + boolean enable_external_quant; + /* enable future use of external colormap */ + boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ + + /* Description of actual output image that will be returned to application. + * These fields are computed by jpeg_start_decompress(). + * You can also use jpeg_calc_output_dimensions() to determine these values + * in advance of calling jpeg_start_decompress(). + */ + + JDIMENSION output_width; + /* scaled image width */ + JDIMENSION output_height; + /* scaled image height */ + int out_color_components; + /* # of color components in out_color_space */ + int output_components; /* # of color components returned */ + /* output_components is 1 (a colormap index) when quantizing colors; + * otherwise it equals out_color_components. + */ + int rec_outbuf_height; /* min recommended height of scanline buffer */ + /* If the buffer passed to jpeg_read_scanlines() is less than this many rows + * high, space and time will be wasted due to unnecessary data copying. + * Usually rec_outbuf_height will be 1 or 2, at most 4. + */ + + /* When quantizing colors, the output colormap is described by these fields. + * The application can supply a colormap by setting colormap non-NULL before + * calling jpeg_start_decompress; otherwise a colormap is created during + * jpeg_start_decompress or jpeg_start_output. + * The map has out_color_components rows and actual_number_of_colors columns. + */ + int actual_number_of_colors; + /* number of entries in use */ + JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ + + /* State variables: these variables indicate the progress of decompression. + * The application may examine these but must not modify them. + */ + + /* Row index of next scanline to be read from jpeg_read_scanlines(). + * Application may use this to control its processing loop, e.g., + * "while (output_scanline < output_height)". + */ + JDIMENSION output_scanline; /* 0 .. output_height-1 */ + + /* Current input scan number and number of iMCU rows completed in scan. + * These indicate the progress of the decompressor input side. + */ + int input_scan_number; + /* Number of SOS markers seen so far */ + JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ + + /* The "output scan number" is the notional scan being displayed by the + * output side. The decompressor will not allow output scan/row number + * to get ahead of input scan/row, but it can fall arbitrarily far behind. + */ + int output_scan_number; + /* Nominal scan number being displayed */ + JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ + + /* Current progression status. coef_bits[c][i] indicates the precision + * with which component c's DCT coefficient i (in zigzag order) is known. + * It is -1 when no data has yet been received, otherwise it is the point + * transform (shift) value for the most recent scan of the coefficient + * (thus, 0 at completion of the progression). + * This pointer is NULL when reading a non-progressive file. + */ + int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ + + /* Internal JPEG parameters --- the application usually need not look at + * these fields. Note that the decompressor output side may not use + * any parameters that can change between scans. + */ + + /* Quantization and Huffman tables are carried forward across input + * datastreams when processing abbreviated JPEG datastreams. + */ + + JQUANT_TBL *quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL *dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL *ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + /* These parameters are never carried across datastreams, since they + * are given in SOF/SOS markers or defined to be reset by SOI. + */ + + int data_precision; + /* bits of precision in image data */ + + jpeg_component_info *comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + +#if JPEG_LIB_VERSION >= 80 + boolean is_baseline; /* TRUE if Baseline SOF0 encountered */ +#endif +#ifdef ANDROID + boolean tile_decode; /* TRUE if using tile based decoding */ +#endif + boolean progressive_mode; + /* TRUE if SOFn specifies progressive mode */ + boolean arith_code; + /* TRUE=arithmetic coding, FALSE=Huffman */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; + /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; + /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; + /* Kx values for AC arith-coding tables */ + + unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ + + /* These fields record data obtained from optional markers recognized by + * the JPEG library. + */ + boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ + /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ + UINT8 JFIF_major_version; + /* JFIF version number */ + UINT8 JFIF_minor_version; + UINT8 density_unit; + /* JFIF code for pixel size units */ + UINT16 X_density; + /* Horizontal pixel density */ + UINT16 Y_density; + /* Vertical pixel density */ + boolean saw_Adobe_marker; + /* TRUE iff an Adobe APP14 marker was found */ + UINT8 Adobe_transform; + /* Color transform code from Adobe marker */ + + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + /* Aside from the specific data retained from APPn markers known to the + * library, the uninterpreted contents of any or all APPn and COM markers + * can be saved in a list for examination by the application. + */ + jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ + + /* Remaining fields are known throughout decompressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during decompression startup + */ + int max_h_samp_factor; + /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + +#if JPEG_LIB_VERSION >= 70 + int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */ + int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */ +#else + int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */ +#endif + + JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ + /* The coefficient controller's input and output progress is measured in + * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows + * in fully interleaved JPEG scans, but are used whether the scan is + * interleaved or not. We define an iMCU row as v_samp_factor DCT block + * rows of each component. Therefore, the IDCT output contains + * v_samp_factor*DCT_[v_]scaled_size sample rows of a component per iMCU row. + */ + + JSAMPLE *sample_range_limit; /* table for fast range-limiting */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + * Note that the decompressor output side must not use these fields. + */ + int comps_in_scan; + /* # of JPEG components in this scan */ + jpeg_component_info *cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; + /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; + /* # of MCU rows in the image */ + + int blocks_in_MCU; + /* # of DCT blocks per MCU */ + int MCU_membership[D_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + +#if JPEG_LIB_VERSION >= 80 + /* These fields are derived from Se of first SOS marker. + */ + int block_size; /* the basic DCT block size: 1..16 */ + const int * natural_order; /* natural-order position array for entropy decode */ + int lim_Se; /* min( Se, DCTSIZE2-1 ) for entropy decode */ +#endif + + /* This field is shared between entropy decoder and marker parser. + * It is either zero or the code of a JPEG marker that has been + * read from the data source, but has not yet been processed. + */ + int unread_marker; + + /* + * Links to decompression subobjects (methods, private variables of modules) + */ + struct jpeg_decomp_master *master; + struct jpeg_d_main_controller *main; + struct jpeg_d_coef_controller *coef; + struct jpeg_d_post_controller *post; + struct jpeg_input_controller *inputctl; + struct jpeg_marker_reader *marker; + struct jpeg_entropy_decoder *entropy; + struct jpeg_inverse_dct *idct; + struct jpeg_upsampler *upsample; + struct jpeg_color_deconverter *cconvert; + struct jpeg_color_quantizer *cquantize; +}; + + +typedef struct { + + // |--- byte_offset ---|- bit_left -| + // \------ 27 -------/ \---- 5 ----/ + unsigned int bitstream_offset; + short prev_dc[3]; + + // remaining EOBs in EOBRUN + unsigned short EOBRUN; + + // writeFileAsync the decoder current bit buffer, entropy->bitstate.get_buffer. + INT32 get_buffer; + + // writeFileAsync the restart info. + unsigned short restarts_to_go; + unsigned char next_restart_num; +} huffman_offset_data; + +typedef struct { + + // The header starting position of this scan + unsigned int bitstream_offset; + + // Number of components in this scan + int comps_in_scan; + + // Number of MCUs in each row + int MCUs_per_row; + int MCU_rows_per_iMCU_row; + + // The last MCU position and its dc value in this scan + huffman_offset_data prev_MCU_offset; + + huffman_offset_data **offset; +} huffman_scan_header; + +#define DEFAULT_MCU_SAMPLE_SIZE 16 + +typedef struct { + + // The number of MCUs that we sample each time as an index point + int MCU_sample_size; + + // Number of scan in this image + int scan_count; + + // Number of iMCUs rows in this image + int total_iMCU_rows; + + // Memory used by scan struct + size_t mem_used; + huffman_scan_header *scan; +} huffman_index; + + +/* "Object" declarations for JPEG modules that may be supplied or called + * directly by the surrounding application. + * As with all objects in the JPEG library, these structs only define the + * publicly visible methods and state variables of a module. Additional + * private fields may exist after the public ones. + */ + + +/* Error handler object */ + +struct jpeg_error_mgr { + /* Error exit handler: does not return to caller */ + JMETHOD(void, error_exit, (j_common_ptr + cinfo)); + /* Conditionally emit a trace or warning message */ + JMETHOD(void, emit_message, (j_common_ptr + cinfo, + int msg_level)); + /* Routine that actually outputs a trace or error message */ + JMETHOD(void, output_message, (j_common_ptr + cinfo)); + /* Format a message string for the most recent JPEG error or message */ + JMETHOD(void, format_message, (j_common_ptr + cinfo, + char *buffer)); + +#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ + /* Reset error state variables at start of a new image */ + JMETHOD(void, reset_error_mgr, (j_common_ptr + cinfo)); + + /* The message ID code and any parameters are saved here. + * A message can have one string parameter or up to 8 int parameters. + */ + int msg_code; +#define JMSG_STR_PARM_MAX 80 + union { + int i[8]; + char s[JMSG_STR_PARM_MAX]; + } msg_parm; + + /* Standard state variables for error facility */ + + int trace_level; /* max msg_level that will be displayed */ + + /* For recoverable corrupt-data errors, we emit a warning message, + * but keep going unless emit_message chooses to abort. emit_message + * should count warnings in num_warnings. The surrounding application + * can check for bad data by seeing if num_warnings is nonzero at the + * end of processing. + */ + long num_warnings; /* number of corrupt-data warnings */ + + /* These fields point to the table(s) of error message strings. + * An application can change the table pointer to switch to a different + * message list (typically, to change the language in which errors are + * reported). Some applications may wish to add additional error codes + * that will be handled by the JPEG library error mechanism; the second + * table pointer is used for this purpose. + * + * First table includes all errors generated by JPEG library itself. + * Error code 0 is reserved for a "no such error string" message. + */ + const char *const *jpeg_message_table; + /* Library errors */ + int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ + /* Second table can be added by application (see cjpeg/djpeg for example). + * It contains strings numbered first_addon_message..last_addon_message. + */ + const char *const *addon_message_table; + /* Non-library errors */ + int first_addon_message; + /* code for first string in addon table */ + int last_addon_message; /* code for last string in addon table */ +}; + + +/* Progress monitor object */ + +struct jpeg_progress_mgr { + JMETHOD(void, progress_monitor, (j_common_ptr + cinfo)); + + long pass_counter; + /* work units completed in this pass */ + long pass_limit; + /* total number of work units in this pass */ + int completed_passes; + /* passes completed so far */ + int total_passes; /* total number of passes expected */ +}; + + +/* Data destination object for compression */ + +struct jpeg_destination_mgr { + JOCTET *next_output_byte; + /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + + JMETHOD(void, init_destination, (j_compress_ptr + cinfo)); + + JMETHOD(boolean, empty_output_buffer, (j_compress_ptr + cinfo)); + + JMETHOD(void, term_destination, (j_compress_ptr + cinfo)); +}; + + +/* Data source object for decompression */ + +struct jpeg_source_mgr { + const JOCTET *next_input_byte; + /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ +#ifdef ANDROID + const JOCTET *start_input_byte; + /* => first byte to read from input */ + size_t current_offset; /* current readed input offset */ +#endif + + JMETHOD(void, init_source, (j_decompress_ptr + cinfo)); + + JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr + cinfo)); + + JMETHOD(void, skip_input_data, (j_decompress_ptr + cinfo, + long num_bytes)); + + JMETHOD(boolean, resync_to_restart, (j_decompress_ptr + cinfo, + int desired)); + + JMETHOD(void, term_source, (j_decompress_ptr + cinfo)); + +#ifdef ANDROID + + JMETHOD(boolean, seek_input_data, (j_decompress_ptr + cinfo, + long byte_offset)); + +#endif +}; + + +/* Memory manager object. + * Allocates "small" objects (a few K total), "large" objects (tens of K), + * and "really big" objects (virtual arrays with backing store if needed). + * The memory manager does not allow individual objects to be freed; rather, + * each created object is assigned to a pool, and whole pools can be freed + * at once. This is faster and more convenient than remembering exactly what + * to free, especially where malloc()/free() are not too speedy. + * NB: alloc routines never return NULL. They exit to error_exit if not + * successful. + */ + +#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ +#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ +#define JPOOL_NUMPOOLS 2 + +typedef struct jvirt_sarray_control *jvirt_sarray_ptr; +typedef struct jvirt_barray_control *jvirt_barray_ptr; + + +struct jpeg_memory_mgr { + /* Method pointers */ + JMETHOD(void *, alloc_small, (j_common_ptr + cinfo, + int pool_id, + size_t sizeofobject)); + + JMETHOD(void FAR + *, alloc_large, (j_common_ptr + cinfo, + int pool_id, + size_t sizeofobject)); + + JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr + cinfo, + int pool_id, + JDIMENSION samplesperrow, + JDIMENSION numrows)); + + JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr + cinfo, + int pool_id, + JDIMENSION blocksperrow, + JDIMENSION numrows)); + + JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr + cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION samplesperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + + JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr + cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION blocksperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + + JMETHOD(void, realize_virt_arrays, (j_common_ptr + cinfo)); + + JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr + cinfo, + jvirt_sarray_ptr + ptr, + JDIMENSION + start_row, + JDIMENSION + num_rows, + boolean + writable)); + + JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr + cinfo, + jvirt_barray_ptr + ptr, + JDIMENSION + start_row, + JDIMENSION + num_rows, + boolean + writable)); + + JMETHOD(void, free_pool, (j_common_ptr + cinfo, + int pool_id)); + + JMETHOD(void, self_destruct, (j_common_ptr + cinfo)); + + /* Limit on memory allocation for this JPEG object. (Note that this is + * merely advisory, not a guaranteed maximum; it only affects the space + * used for virtual-array buffers.) May be changed by outer application + * after creating the JPEG object. + */ + long max_memory_to_use; + + /* Maximum allocation request accepted by alloc_large. */ + long max_alloc_chunk; +}; + + +/* Routine signature for application-supplied marker processing methods. + * Need not pass marker code since it is stored in cinfo->unread_marker. + */ +typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr + cinfo)); + + +/* Declarations for routines called by application. + * The JPP macro hides prototype parameters from compilers that can't cope. + * Note JPP requires double parentheses. + */ + +#ifdef HAVE_PROTOTYPES +#define JPP(arglist) arglist +#else +#define JPP(arglist) () +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. + * We shorten external names to be unique in the first six letters, which + * is good enough for all known systems. + * (If your compiler itself needs names to be unique in less than 15 + * characters, you are out of luck. Get a better compiler.) + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_error jStdError +#define jpeg_CreateCompress jCreaCompress +#define jpeg_CreateDecompress jCreaDecompress +#define jpeg_destroy_compress jDestCompress +#define jpeg_destroy_decompress jDestDecompress +#define jpeg_stdio_dest jStdDest +#define jpeg_stdio_src jStdSrc +#if JPEG_LIB_VERSION >= 80 +#define jpeg_mem_dest jMemDest +#define jpeg_mem_src jMemSrc +#endif +#define jpeg_set_defaults jSetDefaults +#define jpeg_set_colorspace jSetColorspace +#define jpeg_default_colorspace jDefColorspace +#define jpeg_set_quality jSetQuality +#define jpeg_set_linear_quality jSetLQuality +#if JPEG_LIB_VERSION >= 70 +#define jpeg_default_qtables jDefQTables +#endif +#define jpeg_add_quant_table jAddQuantTable +#define jpeg_quality_scaling jQualityScaling +#define jpeg_simple_progression jSimProgress +#define jpeg_suppress_tables jSuppressTables +#define jpeg_alloc_quant_table jAlcQTable +#define jpeg_alloc_huff_table jAlcHTable +#define jpeg_start_compress jStrtCompress +#define jpeg_write_scanlines jWrtScanlines +#define jpeg_finish_compress jFinCompress +#if JPEG_LIB_VERSION >= 70 +#define jpeg_calc_jpeg_dimensions jCjpegDimensions +#endif +#define jpeg_write_raw_data jWrtRawData +#define jpeg_write_marker jWrtMarker +#define jpeg_write_m_header jWrtMHeader +#define jpeg_write_m_byte jWrtMByte +#define jpeg_write_tables jWrtTables +#define jpeg_read_header jReadHeader +#define jpeg_start_decompress jStrtDecompress +#define jpeg_read_scanlines jReadScanlines +#define jpeg_finish_decompress jFinDecompress +#define jpeg_read_raw_data jReadRawData +#define jpeg_has_multiple_scans jHasMultScn +#define jpeg_start_output jStrtOutput +#define jpeg_finish_output jFinOutput +#define jpeg_input_complete jInComplete +#define jpeg_new_colormap jNewCMap +#define jpeg_consume_input jConsumeInput +#if JPEG_LIB_VERSION >= 80 +#define jpeg_core_output_dimensions jCoreDimensions +#endif +#define jpeg_calc_output_dimensions jCalcDimensions +#define jpeg_save_markers jSaveMarkers +#define jpeg_set_marker_processor jSetMarker +#define jpeg_read_coefficients jReadCoefs +#define jpeg_write_coefficients jWrtCoefs +#define jpeg_copy_critical_parameters jCopyCrit +#define jpeg_abort_compress jAbrtCompress +#define jpeg_abort_decompress jAbrtDecompress +#define jpeg_abort jAbort +#define jpeg_destroy jDestroy +#define jpeg_resync_to_restart jResyncRestart +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Default error-management setup */ +EXTERN(struct jpeg_error_mgr *)jpeg_std_error + JPP((struct jpeg_error_mgr * err)); + +/* Initialization of JPEG compression objects. + * jpeg_create_compress() and jpeg_create_decompress() are the exported + * names that applications should call. These expand to calls on + * jpeg_CreateCompress and jpeg_CreateDecompress with additional information + * passed for version mismatch checking. + * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. + */ +#define jpeg_create_compress(cinfo) \ + jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_compress_struct)) +#define jpeg_create_decompress(cinfo) \ + jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_decompress_struct)) + +EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr + cinfo, + int version, size_t + structsize)); + +EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr + cinfo, + int version, size_t + structsize)); +/* Destruction of JPEG compression objects */ +EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr + cinfo)); + +EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr + cinfo)); + +/* Standard data source and destination managers: stdio streams. */ +/* Caller is responsible for opening the file before and closing after. */ +EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr + cinfo, FILE * outfile)); + +EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr + cinfo, FILE * infile)); + +#if JPEG_LIB_VERSION >= 80 +/* Data source and destination managers: memory buffers. */ +EXTERN(void) jpeg_mem_dest JPP((j_compress_ptr cinfo, + unsigned char ** outbuffer, + unsigned long * outsize)); +EXTERN(void) jpeg_mem_src JPP((j_decompress_ptr cinfo, + unsigned char * inbuffer, + unsigned long insize)); +#endif + +/* Default parameter setup for compression */ +EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr + cinfo)); +/* Compression parameter setup aids */ +EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr + cinfo, + J_COLOR_SPACE + colorspace)); + +EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr + cinfo)); + +EXTERN(void) jpeg_set_quality JPP((j_compress_ptr + cinfo, + int quality, + boolean force_baseline)); + +EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr + cinfo, + int scale_factor, + boolean force_baseline)); + +#if JPEG_LIB_VERSION >= 70 +EXTERN(void) jpeg_default_qtables JPP((j_compress_ptr cinfo, + boolean force_baseline)); +#endif + +EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr + cinfo, + int which_tbl, + const unsigned int *basic_table, + int scale_factor, + boolean force_baseline)); + +EXTERN(int) jpeg_quality_scaling JPP((int quality)); + +EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr + cinfo)); + +EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr + cinfo, + boolean + suppress)); + +EXTERN(JQUANT_TBL *)jpeg_alloc_quant_table JPP((j_common_ptr + cinfo)); + +EXTERN(JHUFF_TBL *)jpeg_alloc_huff_table JPP((j_common_ptr + cinfo)); + +/* Main entry points for compression */ +EXTERN(void) jpeg_start_compress JPP((j_compress_ptr + cinfo, + boolean + write_all_tables)); + +EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr + cinfo, + JSAMPARRAY + scanlines, + JDIMENSION + num_lines)); + +EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr + cinfo)); + +#if JPEG_LIB_VERSION >= 70 +/* Precalculate JPEG dimensions for current compression parameters. */ +EXTERN(void) jpeg_calc_jpeg_dimensions JPP((j_compress_ptr cinfo)); +#endif + +/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr + cinfo, + JSAMPIMAGE + data, + JDIMENSION + num_lines)); + +/* Write a special marker. See libjpeg.txt concerning safe usage. */ +EXTERN(void) jpeg_write_marker + JPP((j_compress_ptr + cinfo, + int marker, + const JOCTET *dataptr, + unsigned int datalen)); +/* Same, but piecemeal. */ +EXTERN(void) jpeg_write_m_header + JPP((j_compress_ptr + cinfo, + int marker, + unsigned int datalen)); + +EXTERN(void) jpeg_write_m_byte + JPP((j_compress_ptr + cinfo, + int val)); + +/* Alternate compression function: just write an abbreviated table file */ +EXTERN(void) jpeg_write_tables JPP((j_compress_ptr + cinfo)); + +/* Decompression startup: read start of JPEG datastream to see what's there */ +EXTERN(int) jpeg_read_header JPP((j_decompress_ptr + cinfo, + boolean + require_image)); +/* Return value is one of: */ +#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ +#define JPEG_HEADER_OK 1 /* Found valid image datastream */ +#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ +/* If you pass require_image = TRUE (normal case), you need not check for + * a TABLES_ONLY return code; an abbreviated file will cause an error exit. + * JPEG_SUSPENDED is only possible if you use a data source module that can + * give a suspension return (the stdio source module doesn't). + */ + +/* Main entry points for decompression */ +EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr + cinfo)); + +#ifdef ANDROID + +EXTERN(boolean) jpeg_start_tile_decompress JPP((j_decompress_ptr + cinfo)); + +#endif + +EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr + cinfo, + JSAMPARRAY + scanlines, + JDIMENSION + max_lines)); + +EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr + cinfo)); + +/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr + cinfo, + JSAMPIMAGE + data, + JDIMENSION + max_lines)); + +#ifdef ANDROID + +EXTERN(JDIMENSION) jpeg_read_scanlines_from JPP((j_decompress_ptr + cinfo, + JSAMPARRAY + scanlines, + int line_offset, + JDIMENSION max_lines)); + +EXTERN(JDIMENSION) jpeg_read_tile_scanline JPP((j_decompress_ptr + cinfo, + huffman_index * index, + JSAMPARRAY + scanlines)); + +EXTERN(void) jpeg_init_read_tile_scanline JPP((j_decompress_ptr + cinfo, + huffman_index * index, + int *start_x, + int *start_y, + int *width, + int *height)); + +#endif + +/* Additional entry points for buffered-image mode. */ +EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr + cinfo)); + +EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr + cinfo, + int scan_number)); + +EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr + cinfo)); + +EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr + cinfo)); + +EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr + cinfo)); + +EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr + cinfo)); +/* Return value is one of: */ +/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ +#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ +#define JPEG_REACHED_EOI 2 /* Reached end of image */ +#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ +#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ + +/* Precalculate output dimensions for current decompression parameters. */ +#if JPEG_LIB_VERSION >= 80 +EXTERN(void) jpeg_core_output_dimensions JPP((j_decompress_ptr cinfo)); +#endif + +EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr + cinfo)); + +/* Control saving of COM and APPn markers into marker_list. */ +EXTERN(void) jpeg_save_markers + JPP((j_decompress_ptr + cinfo, + int marker_code, + unsigned int length_limit)); + +/* Install a special processing method for COM or APPn markers. */ +EXTERN(void) jpeg_set_marker_processor + JPP((j_decompress_ptr + cinfo, + int marker_code, + jpeg_marker_parser_method routine)); + +/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ +EXTERN(jvirt_barray_ptr *)jpeg_read_coefficients JPP((j_decompress_ptr + cinfo)); + +EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr + cinfo, + jvirt_barray_ptr * coef_arrays)); + +EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr + srcinfo, + j_compress_ptr + dstinfo)); + +/* If you choose to abort compression or decompression before completing + * jpeg_finish_(de)compress, then you need to clean up to release memory, + * temporary files, etc. You can just call jpeg_destroy_(de)compress + * if you're done with the JPEG object, but if you want to clean it up and + * reuse it, call this: + */ +EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr + cinfo)); + +EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr + cinfo)); + +/* Generic versions of jpeg_abort and jpeg_destroy that work on either + * flavor of JPEG object. These may be more convenient in some places. + */ +EXTERN(void) jpeg_abort JPP((j_common_ptr + cinfo)); + +EXTERN(void) jpeg_destroy JPP((j_common_ptr + cinfo)); + +/* Default restart-marker-resync procedure for use by data source modules */ +EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr + cinfo, + int desired)); + +#ifdef ANDROID + +EXTERN(boolean) jpeg_build_huffman_index + JPP((j_decompress_ptr + cinfo, huffman_index * index)); + +EXTERN(void) jpeg_configure_huffman_decoder(j_decompress_ptr cinfo, + huffman_offset_data offset); + +EXTERN(void) jpeg_get_huffman_decoder_configuration(j_decompress_ptr cinfo, + huffman_offset_data *offset); + +EXTERN(void) jpeg_create_huffman_index(j_decompress_ptr cinfo, + huffman_index *index); + +EXTERN(void) jpeg_configure_huffman_index_scan(j_decompress_ptr cinfo, + huffman_index *index, int scan_no, int offset); + +EXTERN(void) jpeg_destroy_huffman_index(huffman_index *index); + +#endif + +/* These marker codes are exported since applications and data source modules + * are likely to want to use them. + */ + +#define JPEG_RST0 0xD0 /* RST0 marker code */ +#define JPEG_EOI 0xD9 /* EOI marker code */ +#define JPEG_APP0 0xE0 /* APP0 marker code */ +#define JPEG_COM 0xFE /* COM marker code */ + + +/* If we have a brain-damaged compiler that emits warnings (or worse, errors) + * for structure definitions that are never filled in, keep it quiet by + * supplying dummy definitions for the various substructures. + */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +struct jpeg_comp_master { long dummy; }; +struct jpeg_c_main_controller { long dummy; }; +struct jpeg_c_prep_controller { long dummy; }; +struct jpeg_c_coef_controller { long dummy; }; +struct jpeg_marker_writer { long dummy; }; +struct jpeg_color_converter { long dummy; }; +struct jpeg_downsampler { long dummy; }; +struct jpeg_forward_dct { long dummy; }; +struct jpeg_entropy_encoder { long dummy; }; +struct jpeg_decomp_master { long dummy; }; +struct jpeg_d_main_controller { long dummy; }; +struct jpeg_d_coef_controller { long dummy; }; +struct jpeg_d_post_controller { long dummy; }; +struct jpeg_input_controller { long dummy; }; +struct jpeg_marker_reader { long dummy; }; +struct jpeg_entropy_decoder { long dummy; }; +struct jpeg_inverse_dct { long dummy; }; +struct jpeg_upsampler { long dummy; }; +struct jpeg_color_deconverter { long dummy; }; +struct jpeg_color_quantizer { long dummy; }; +#endif /* JPEG_INTERNALS */ +#endif /* INCOMPLETE_TYPES_BROKEN */ + + +/* + * The JPEG library modules define JPEG_INTERNALS before including this file. + * The internal structure declarations are read only when that is true. + * Applications using the library should not include jpegint.h, but may wish + * to include jerror.h. + */ + +#ifdef JPEG_INTERNALS +#include "jpegint.h" /* fetch private declarations */ +#include "jerror.h" /* fetch error codes too */ +#endif + +#ifndef ANDROID +#ifdef __cplusplus +#ifndef DONT_USE_EXTERN_C +} +#endif +#endif +#endif + +#endif /* JPEGLIB_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jsimd.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jsimd.h new file mode 100644 index 0000000..6ee99cc --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jsimd.h @@ -0,0 +1,666 @@ +/* + * simd/jsimd.h + * + * Copyright 2009 Pierre Ossman for Cendio AB + * Copyright 2011 D. R. Commander + * + * Based on the x86 SIMD extension for IJG JPEG library, + * Copyright (C) 1999-2006, MIYASAKA Masaru. + * For conditions of distribution and use, see copyright notice in jsimdext.inc + * + */ + +/* Bitmask for supported acceleration methods */ + +#define JSIMD_NONE 0x00 +#define JSIMD_MMX 0x01 +#define JSIMD_3DNOW 0x02 +#define JSIMD_SSE 0x04 +#define JSIMD_SSE2 0x08 +#define JSIMD_ARM_NEON 0x10 + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_simd_cpu_support jSiCpuSupport +#define jsimd_rgb_ycc_convert_mmx jSRGBYCCM +#define jsimd_extrgb_ycc_convert_mmx jSEXTRGBYCCM +#define jsimd_extrgbx_ycc_convert_mmx jSEXTRGBXYCCM +#define jsimd_extbgr_ycc_convert_mmx jSEXTBGRYCCM +#define jsimd_extbgrx_ycc_convert_mmx jSEXTBGRXYCCM +#define jsimd_extxbgr_ycc_convert_mmx jSEXTXBGRYCCM +#define jsimd_extxrgb_ycc_convert_mmx jSEXTXRGBYCCM +#define jsimd_rgb_gray_convert_mmx jSRGBGRYM +#define jsimd_extrgb_gray_convert_mmx jSEXTRGBGRYM +#define jsimd_extrgbx_gray_convert_mmx jSEXTRGBXGRYM +#define jsimd_extbgr_gray_convert_mmx jSEXTBGRGRYM +#define jsimd_extbgrx_gray_convert_mmx jSEXTBGRXGRYM +#define jsimd_extxbgr_gray_convert_mmx jSEXTXBGRGRYM +#define jsimd_extxrgb_gray_convert_mmx jSEXTXRGBGRYM +#define jsimd_ycc_rgb_convert_mmx jSYCCRGBM +#define jsimd_ycc_extrgb_convert_mmx jSYCCEXTRGBM +#define jsimd_ycc_extrgbx_convert_mmx jSYCCEXTRGBXM +#define jsimd_ycc_extbgr_convert_mmx jSYCCEXTBGRM +#define jsimd_ycc_extbgrx_convert_mmx jSYCCEXTBGRXM +#define jsimd_ycc_extxbgr_convert_mmx jSYCCEXTXBGRM +#define jsimd_ycc_extxrgb_convert_mmx jSYCCEXTXRGBM +#define jconst_rgb_ycc_convert_sse2 jSCRGBYCCS2 +#define jsimd_rgb_ycc_convert_sse2 jSRGBYCCS2 +#define jsimd_extrgb_ycc_convert_sse2 jSEXTRGBYCCS2 +#define jsimd_extrgbx_ycc_convert_sse2 jSEXTRGBXYCCS2 +#define jsimd_extbgr_ycc_convert_sse2 jSEXTBGRYCCS2 +#define jsimd_extbgrx_ycc_convert_sse2 jSEXTBGRXYCCS2 +#define jsimd_extxbgr_ycc_convert_sse2 jSEXTXBGRYCCS2 +#define jsimd_extxrgb_ycc_convert_sse2 jSEXTXRGBYCCS2 +#define jconst_rgb_gray_convert_sse2 jSCRGBGRYS2 +#define jsimd_rgb_gray_convert_sse2 jSRGBGRYS2 +#define jsimd_extrgb_gray_convert_sse2 jSEXTRGBGRYS2 +#define jsimd_extrgbx_gray_convert_sse2 jSEXTRGBXGRYS2 +#define jsimd_extbgr_gray_convert_sse2 jSEXTBGRGRYS2 +#define jsimd_extbgrx_gray_convert_sse2 jSEXTBGRXGRYS2 +#define jsimd_extxbgr_gray_convert_sse2 jSEXTXBGRGRYS2 +#define jsimd_extxrgb_gray_convert_sse2 jSEXTXRGBGRYS2 +#define jconst_ycc_rgb_convert_sse2 jSCYCCRGBS2 +#define jsimd_ycc_rgb_convert_sse2 jSYCCRGBS2 +#define jsimd_ycc_extrgb_convert_sse2 jSYCCEXTRGBS2 +#define jsimd_ycc_extrgbx_convert_sse2 jSYCCEXTRGBXS2 +#define jsimd_ycc_extbgr_convert_sse2 jSYCCEXTBGRS2 +#define jsimd_ycc_extbgrx_convert_sse2 jSYCCEXTBGRXS2 +#define jsimd_ycc_extxbgr_convert_sse2 jSYCCEXTXBGRS2 +#define jsimd_ycc_extxrgb_convert_sse2 jSYCCEXTXRGBS2 +#define jsimd_h2v2_downsample_mmx jSDnH2V2M +#define jsimd_h2v1_downsample_mmx jSDnH2V1M +#define jsimd_h2v2_downsample_sse2 jSDnH2V2S2 +#define jsimd_h2v1_downsample_sse2 jSDnH2V1S2 +#define jsimd_h2v2_upsample_mmx jSUpH2V2M +#define jsimd_h2v1_upsample_mmx jSUpH2V1M +#define jsimd_h2v2_fancy_upsample_mmx jSFUpH2V2M +#define jsimd_h2v1_fancy_upsample_mmx jSFUpH2V1M +#define jsimd_h2v2_merged_upsample_mmx jSMUpH2V2M +#define jsimd_h2v2_extrgb_merged_upsample_mmx jSMUpH2V2EXTRGBM +#define jsimd_h2v2_extrgbx_merged_upsample_mmx jSMUpH2V2EXTRGBXM +#define jsimd_h2v2_extbgr_merged_upsample_mmx jSMUpH2V2EXTBGRM +#define jsimd_h2v2_extbgrx_merged_upsample_mmx jSMUpH2V2EXTBGRXM +#define jsimd_h2v2_extxbgr_merged_upsample_mmx jSMUpH2V2EXTXBGRM +#define jsimd_h2v2_extxrgb_merged_upsample_mmx jSMUpH2V2EXTXRGBM +#define jsimd_h2v1_merged_upsample_mmx jSMUpH2V1M +#define jsimd_h2v1_extrgb_merged_upsample_mmx jSMUpH2V1EXTRGBM +#define jsimd_h2v1_extrgbx_merged_upsample_mmx jSMUpH2V1EXTRGBXM +#define jsimd_h2v1_extbgr_merged_upsample_mmx jSMUpH2V1EXTBGRM +#define jsimd_h2v1_extbgrx_merged_upsample_mmx jSMUpH2V1EXTBGRXM +#define jsimd_h2v1_extxbgr_merged_upsample_mmx jSMUpH2V1EXTXBGRM +#define jsimd_h2v1_extxrgb_merged_upsample_mmx jSMUpH2V1EXTXRGBM +#define jsimd_h2v2_upsample_sse2 jSUpH2V2S2 +#define jsimd_h2v1_upsample_sse2 jSUpH2V1S2 +#define jconst_fancy_upsample_sse2 jSCFUpS2 +#define jsimd_h2v2_fancy_upsample_sse2 jSFUpH2V2S2 +#define jsimd_h2v1_fancy_upsample_sse2 jSFUpH2V1S2 +#define jconst_merged_upsample_sse2 jSCMUpS2 +#define jsimd_h2v2_merged_upsample_sse2 jSMUpH2V2S2 +#define jsimd_h2v2_extrgb_merged_upsample_sse2 jSMUpH2V2EXTRGBS2 +#define jsimd_h2v2_extrgbx_merged_upsample_sse2 jSMUpH2V2EXTRGBXS2 +#define jsimd_h2v2_extbgr_merged_upsample_sse2 jSMUpH2V2EXTBGRS2 +#define jsimd_h2v2_extbgrx_merged_upsample_sse2 jSMUpH2V2EXTBGRXS2 +#define jsimd_h2v2_extxbgr_merged_upsample_sse2 jSMUpH2V2EXTXBGRS2 +#define jsimd_h2v2_extxrgb_merged_upsample_sse2 jSMUpH2V2EXTXRGBS2 +#define jsimd_h2v1_merged_upsample_sse2 jSMUpH2V1S2 +#define jsimd_h2v1_extrgb_merged_upsample_sse2 jSMUpH2V1EXTRGBS2 +#define jsimd_h2v1_extrgbx_merged_upsample_sse2 jSMUpH2V1EXTRGBXS2 +#define jsimd_h2v1_extbgr_merged_upsample_sse2 jSMUpH2V1EXTBGRS2 +#define jsimd_h2v1_extbgrx_merged_upsample_sse2 jSMUpH2V1EXTBGRXS2 +#define jsimd_h2v1_extxbgr_merged_upsample_sse2 jSMUpH2V1EXTXBGRS2 +#define jsimd_h2v1_extxrgb_merged_upsample_sse2 jSMUpH2V1EXTXRGBS2 +#define jsimd_convsamp_mmx jSConvM +#define jsimd_convsamp_sse2 jSConvS2 +#define jsimd_convsamp_float_3dnow jSConvF3D +#define jsimd_convsamp_float_sse jSConvFS +#define jsimd_convsamp_float_sse2 jSConvFS2 +#define jsimd_fdct_islow_mmx jSFDMIS +#define jsimd_fdct_ifast_mmx jSFDMIF +#define jconst_fdct_islow_sse2 jSCFDS2IS +#define jsimd_fdct_islow_sse2 jSFDS2IS +#define jconst_fdct_ifast_sse2 jSCFDS2IF +#define jsimd_fdct_ifast_sse2 jSFDS2IF +#define jsimd_fdct_float_3dnow jSFD3DF +#define jconst_fdct_float_sse jSCFDSF +#define jsimd_fdct_float_sse jSFDSF +#define jsimd_quantize_mmx jSQuantM +#define jsimd_quantize_sse2 jSQuantS2 +#define jsimd_quantize_float_3dnow jSQuantF3D +#define jsimd_quantize_float_sse jSQuantFS +#define jsimd_quantize_float_sse2 jSQuantFS2 +#define jsimd_idct_2x2_mmx jSIDM22 +#define jsimd_idct_4x4_mmx jSIDM44 +#define jconst_idct_red_sse2 jSCIDS2R +#define jsimd_idct_2x2_sse2 jSIDS222 +#define jsimd_idct_4x4_sse2 jSIDS244 +#define jsimd_idct_islow_mmx jSIDMIS +#define jsimd_idct_ifast_mmx jSIDMIF +#define jconst_idct_islow_sse2 jSCIDS2IS +#define jsimd_idct_islow_sse2 jSIDS2IS +#define jconst_idct_ifast_sse2 jSCIDS2IF +#define jsimd_idct_ifast_sse2 jSIDS2IF +#define jsimd_idct_float_3dnow jSID3DF +#define jconst_fdct_float_sse jSCIDSF +#define jsimd_idct_float_sse jSIDSF +#define jconst_fdct_float_sse2 jSCIDS2F +#define jsimd_idct_float_sse2 jSIDS2F +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* SIMD Ext: retrieve SIMD/CPU information */ +EXTERN(unsigned int) jpeg_simd_cpu_support JPP((void)); + +/* SIMD Color Space Conversion */ +EXTERN(void) jsimd_rgb_ycc_convert_mmx + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extrgb_ycc_convert_mmx + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extrgbx_ycc_convert_mmx + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extbgr_ycc_convert_mmx + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extbgrx_ycc_convert_mmx + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extxbgr_ycc_convert_mmx + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extxrgb_ycc_convert_mmx + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); + +EXTERN(void) jsimd_rgb_gray_convert_mmx + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extrgb_gray_convert_mmx + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extrgbx_gray_convert_mmx + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extbgr_gray_convert_mmx + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extbgrx_gray_convert_mmx + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extxbgr_gray_convert_mmx + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extxrgb_gray_convert_mmx + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); + +EXTERN(void) jsimd_ycc_rgb_convert_mmx + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +EXTERN(void) jsimd_ycc_extrgb_convert_mmx + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +EXTERN(void) jsimd_ycc_extrgbx_convert_mmx + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +EXTERN(void) jsimd_ycc_extbgr_convert_mmx + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +EXTERN(void) jsimd_ycc_extbgrx_convert_mmx + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +EXTERN(void) jsimd_ycc_extxbgr_convert_mmx + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +EXTERN(void) jsimd_ycc_extxrgb_convert_mmx + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); + +extern const int jconst_rgb_ycc_convert_sse2[]; +EXTERN(void) jsimd_rgb_ycc_convert_sse2 + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extrgb_ycc_convert_sse2 + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extrgbx_ycc_convert_sse2 + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extbgr_ycc_convert_sse2 + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extbgrx_ycc_convert_sse2 + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extxbgr_ycc_convert_sse2 + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extxrgb_ycc_convert_sse2 + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); + +extern const int jconst_rgb_gray_convert_sse2[]; +EXTERN(void) jsimd_rgb_gray_convert_sse2 + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extrgb_gray_convert_sse2 + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extrgbx_gray_convert_sse2 + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extbgr_gray_convert_sse2 + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extbgrx_gray_convert_sse2 + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extxbgr_gray_convert_sse2 + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extxrgb_gray_convert_sse2 + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); + +extern const int jconst_ycc_rgb_convert_sse2[]; +EXTERN(void) jsimd_ycc_rgb_convert_sse2 + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +EXTERN(void) jsimd_ycc_extrgb_convert_sse2 + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +EXTERN(void) jsimd_ycc_extrgbx_convert_sse2 + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +EXTERN(void) jsimd_ycc_extbgr_convert_sse2 + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +EXTERN(void) jsimd_ycc_extbgrx_convert_sse2 + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +EXTERN(void) jsimd_ycc_extxbgr_convert_sse2 + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +EXTERN(void) jsimd_ycc_extxrgb_convert_sse2 + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); + +EXTERN(void) jsimd_rgb_ycc_convert_neon + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extrgb_ycc_convert_neon + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extrgbx_ycc_convert_neon + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extbgr_ycc_convert_neon + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extbgrx_ycc_convert_neon + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extxbgr_ycc_convert_neon + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +EXTERN(void) jsimd_extxrgb_ycc_convert_neon + JPP((JDIMENSION img_width, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); + +EXTERN(void) jsimd_ycc_rgb_convert_neon + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +EXTERN(void) jsimd_ycc_extrgb_convert_neon + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +EXTERN(void) jsimd_ycc_extrgbx_convert_neon + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +EXTERN(void) jsimd_ycc_extbgr_convert_neon + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +EXTERN(void) jsimd_ycc_extbgrx_convert_neon + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +EXTERN(void) jsimd_ycc_extxbgr_convert_neon + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +EXTERN(void) jsimd_ycc_extxrgb_convert_neon + JPP((JDIMENSION out_width, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); + +/* SIMD Downsample */ +EXTERN(void) jsimd_h2v2_downsample_mmx + JPP((JDIMENSION image_width, int max_v_samp_factor, + JDIMENSION v_samp_factor, JDIMENSION width_blocks, + JSAMPARRAY input_data, JSAMPARRAY output_data)); +EXTERN(void) jsimd_h2v1_downsample_mmx + JPP((JDIMENSION image_width, int max_v_samp_factor, + JDIMENSION v_samp_factor, JDIMENSION width_blocks, + JSAMPARRAY input_data, JSAMPARRAY output_data)); + +EXTERN(void) jsimd_h2v2_downsample_sse2 + JPP((JDIMENSION image_width, int max_v_samp_factor, + JDIMENSION v_samp_factor, JDIMENSION width_blocks, + JSAMPARRAY input_data, JSAMPARRAY output_data)); +EXTERN(void) jsimd_h2v1_downsample_sse2 + JPP((JDIMENSION image_width, int max_v_samp_factor, + JDIMENSION v_samp_factor, JDIMENSION width_blocks, + JSAMPARRAY input_data, JSAMPARRAY output_data)); + +/* SIMD Upsample */ +EXTERN(void) jsimd_h2v2_upsample_mmx + JPP((int max_v_samp_factor, JDIMENSION output_width, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)); +EXTERN(void) jsimd_h2v1_upsample_mmx + JPP((int max_v_samp_factor, JDIMENSION output_width, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)); + +EXTERN(void) jsimd_h2v2_fancy_upsample_mmx + JPP((int max_v_samp_factor, JDIMENSION downsampled_width, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)); +EXTERN(void) jsimd_h2v1_fancy_upsample_mmx + JPP((int max_v_samp_factor, JDIMENSION downsampled_width, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)); + +EXTERN(void) jsimd_h2v2_merged_upsample_mmx + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v2_extrgb_merged_upsample_mmx + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v2_extrgbx_merged_upsample_mmx + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v2_extbgr_merged_upsample_mmx + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v2_extbgrx_merged_upsample_mmx + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v2_extxbgr_merged_upsample_mmx + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v2_extxrgb_merged_upsample_mmx + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v1_merged_upsample_mmx + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v1_extrgb_merged_upsample_mmx + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v1_extrgbx_merged_upsample_mmx + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v1_extbgr_merged_upsample_mmx + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v1_extbgrx_merged_upsample_mmx + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v1_extxbgr_merged_upsample_mmx + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v1_extxrgb_merged_upsample_mmx + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); + +EXTERN(void) jsimd_h2v2_upsample_sse2 + JPP((int max_v_samp_factor, JDIMENSION output_width, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)); +EXTERN(void) jsimd_h2v1_upsample_sse2 + JPP((int max_v_samp_factor, JDIMENSION output_width, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)); + +extern const int jconst_fancy_upsample_sse2[]; +EXTERN(void) jsimd_h2v2_fancy_upsample_sse2 + JPP((int max_v_samp_factor, JDIMENSION downsampled_width, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)); +EXTERN(void) jsimd_h2v1_fancy_upsample_sse2 + JPP((int max_v_samp_factor, JDIMENSION downsampled_width, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)); + +extern const int jconst_merged_upsample_sse2[]; +EXTERN(void) jsimd_h2v2_merged_upsample_sse2 + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v2_extrgb_merged_upsample_sse2 + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v2_extrgbx_merged_upsample_sse2 + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v2_extbgr_merged_upsample_sse2 + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v2_extbgrx_merged_upsample_sse2 + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v2_extxbgr_merged_upsample_sse2 + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v2_extxrgb_merged_upsample_sse2 + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v1_merged_upsample_sse2 + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v1_extrgb_merged_upsample_sse2 + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v1_extrgbx_merged_upsample_sse2 + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v1_extbgr_merged_upsample_sse2 + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v1_extbgrx_merged_upsample_sse2 + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v1_extxbgr_merged_upsample_sse2 + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); +EXTERN(void) jsimd_h2v1_extxrgb_merged_upsample_sse2 + JPP((JDIMENSION output_width, JSAMPIMAGE input_buf, + JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)); + +/* SIMD Sample Conversion */ +EXTERN(void) jsimd_convsamp_mmx JPP((JSAMPARRAY sample_data, + JDIMENSION start_col, + DCTELEM * workspace)); + +EXTERN(void) jsimd_convsamp_sse2 JPP((JSAMPARRAY sample_data, + JDIMENSION start_col, + DCTELEM * workspace)); + +EXTERN(void) jsimd_convsamp_neon JPP((JSAMPARRAY sample_data, + JDIMENSION start_col, + DCTELEM * workspace)); + +EXTERN(void) jsimd_convsamp_float_3dnow JPP((JSAMPARRAY sample_data, + JDIMENSION start_col, + FAST_FLOAT * workspace)); + +EXTERN(void) jsimd_convsamp_float_sse JPP((JSAMPARRAY sample_data, + JDIMENSION start_col, + FAST_FLOAT * workspace)); + +EXTERN(void) jsimd_convsamp_float_sse2 JPP((JSAMPARRAY sample_data, + JDIMENSION start_col, + FAST_FLOAT * workspace)); + +/* SIMD Forward DCT */ +EXTERN(void) jsimd_fdct_islow_mmx JPP((DCTELEM * data)); +EXTERN(void) jsimd_fdct_ifast_mmx JPP((DCTELEM * data)); + +extern const int jconst_fdct_ifast_sse2[]; +EXTERN(void) jsimd_fdct_islow_sse2 JPP((DCTELEM * data)); +extern const int jconst_fdct_islow_sse2[]; +EXTERN(void) jsimd_fdct_ifast_sse2 JPP((DCTELEM * data)); + +EXTERN(void) jsimd_fdct_ifast_neon JPP((DCTELEM * data)); + +EXTERN(void) jsimd_fdct_float_3dnow JPP((FAST_FLOAT * data)); + +extern const int jconst_fdct_float_sse[]; +EXTERN(void) jsimd_fdct_float_sse JPP((FAST_FLOAT * data)); + +/* SIMD Quantization */ +EXTERN(void) jsimd_quantize_mmx JPP((JCOEFPTR coef_block, + DCTELEM * divisors, + DCTELEM * workspace)); + +EXTERN(void) jsimd_quantize_sse2 JPP((JCOEFPTR coef_block, + DCTELEM * divisors, + DCTELEM * workspace)); + +EXTERN(void) jsimd_quantize_neon JPP((JCOEFPTR coef_block, + DCTELEM * divisors, + DCTELEM * workspace)); + +EXTERN(void) jsimd_quantize_float_3dnow JPP((JCOEFPTR coef_block, + FAST_FLOAT * divisors, + FAST_FLOAT * workspace)); + +EXTERN(void) jsimd_quantize_float_sse JPP((JCOEFPTR coef_block, + FAST_FLOAT * divisors, + FAST_FLOAT * workspace)); + +EXTERN(void) jsimd_quantize_float_sse2 JPP((JCOEFPTR coef_block, + FAST_FLOAT * divisors, + FAST_FLOAT * workspace)); + +/* SIMD Reduced Inverse DCT */ +EXTERN(void) jsimd_idct_2x2_mmx JPP((void * dct_table, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, + JDIMENSION output_col)); +EXTERN(void) jsimd_idct_4x4_mmx JPP((void * dct_table, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, + JDIMENSION output_col)); + +extern const int jconst_idct_red_sse2[]; +EXTERN(void) jsimd_idct_2x2_sse2 JPP((void * dct_table, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, + JDIMENSION output_col)); +EXTERN(void) jsimd_idct_4x4_sse2 JPP((void * dct_table, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, + JDIMENSION output_col)); + +EXTERN(void) jsimd_idct_2x2_neon JPP((void * dct_table, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, + JDIMENSION output_col)); +EXTERN(void) jsimd_idct_4x4_neon JPP((void * dct_table, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, + JDIMENSION output_col)); + +/* SIMD Inverse DCT */ +EXTERN(void) jsimd_idct_islow_mmx JPP((void * dct_table, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, + JDIMENSION output_col)); +EXTERN(void) jsimd_idct_ifast_mmx JPP((void * dct_table, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, + JDIMENSION output_col)); + +extern const int jconst_idct_islow_sse2[]; +EXTERN(void) jsimd_idct_islow_sse2 JPP((void * dct_table, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, + JDIMENSION output_col)); +extern const int jconst_idct_ifast_sse2[]; +EXTERN(void) jsimd_idct_ifast_sse2 JPP((void * dct_table, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, + JDIMENSION output_col)); + +EXTERN(void) jsimd_idct_islow_neon JPP((void * dct_table, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, + JDIMENSION output_col)); +EXTERN(void) jsimd_idct_ifast_neon JPP((void * dct_table, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, + JDIMENSION output_col)); + +EXTERN(void) jsimd_idct_float_3dnow JPP((void * dct_table, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, + JDIMENSION output_col)); + +extern const int jconst_idct_float_sse[]; +EXTERN(void) jsimd_idct_float_sse JPP((void * dct_table, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, + JDIMENSION output_col)); + +extern const int jconst_idct_float_sse2[]; +EXTERN(void) jsimd_idct_float_sse2 JPP((void * dct_table, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, + JDIMENSION output_col)); + diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jsimdcfg.inc.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jsimdcfg.inc.h new file mode 100644 index 0000000..0dacd06 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jsimdcfg.inc.h @@ -0,0 +1,199 @@ +// This file generates the include file for the assembly +// implementations by abusing the C preprocessor. +// +// Note: Some things are manually defined as they need to +// be mapped to NASM types. + +; +; Automatically generated include file from jsimdcfg.inc.h +; + +#define JPEG_INTERNALS + +#include "../jpeglib.h" +#include "../jconfig.h" +#include "../jmorecfg.h" +#include "jsimd.h" + +#define define(var) %define _cpp_protection_##var +#define definev(var) %define _cpp_protection_##var var + +; +; -- jpeglib.h +; + +definev(DCTSIZE) +definev(DCTSIZE2) + +; +; -- jmorecfg.h +; + +definev(RGB_RED) +definev(RGB_GREEN) +definev(RGB_BLUE) +definev(RGB_PIXELSIZE) + +definev(EXT_RGB_RED) +definev(EXT_RGB_GREEN) +definev(EXT_RGB_BLUE) +definev(EXT_RGB_PIXELSIZE) + +definev(EXT_RGBX_RED) +definev(EXT_RGBX_GREEN) +definev(EXT_RGBX_BLUE) +definev(EXT_RGBX_PIXELSIZE) + +definev(EXT_BGR_RED) +definev(EXT_BGR_GREEN) +definev(EXT_BGR_BLUE) +definev(EXT_BGR_PIXELSIZE) + +definev(EXT_BGRX_RED) +definev(EXT_BGRX_GREEN) +definev(EXT_BGRX_BLUE) +definev(EXT_BGRX_PIXELSIZE) + +definev(EXT_XBGR_RED) +definev(EXT_XBGR_GREEN) +definev(EXT_XBGR_BLUE) +definev(EXT_XBGR_PIXELSIZE) + +definev(EXT_XRGB_RED) +definev(EXT_XRGB_GREEN) +definev(EXT_XRGB_BLUE) +definev(EXT_XRGB_PIXELSIZE) + +%define RGBX_FILLER_0XFF 1 + +; Representation of a single sample (pixel element value). +; On this SIMD implementation, this must be 'unsigned char'. +; + +%define JSAMPLE byte ; unsigned char +%define SIZEOF_JSAMPLE SIZEOF_BYTE ; sizeof(JSAMPLE) + +definev(CENTERJSAMPLE) + +; Representation of a DCT frequency coefficient. +; On this SIMD implementation, this must be 'short'. +; +%define JCOEF word ; short +%define SIZEOF_JCOEF SIZEOF_WORD ; sizeof(JCOEF) + +; Datatype used for image dimensions. +; On this SIMD implementation, this must be 'unsigned int'. +; +%define JDIMENSION dword ; unsigned int +%define SIZEOF_JDIMENSION SIZEOF_DWORD ; sizeof(JDIMENSION) + +%define JSAMPROW POINTER ; JSAMPLE FAR * (jpeglib.h) +%define JSAMPARRAY POINTER ; JSAMPROW * (jpeglib.h) +%define JSAMPIMAGE POINTER ; JSAMPARRAY * (jpeglib.h) +%define JCOEFPTR POINTER ; JCOEF FAR * (jpeglib.h) +%define SIZEOF_JSAMPROW SIZEOF_POINTER ; sizeof(JSAMPROW) +%define SIZEOF_JSAMPARRAY SIZEOF_POINTER ; sizeof(JSAMPARRAY) +%define SIZEOF_JSAMPIMAGE SIZEOF_POINTER ; sizeof(JSAMPIMAGE) +%define SIZEOF_JCOEFPTR SIZEOF_POINTER ; sizeof(JCOEFPTR) + +; +; -- jdct.h +; + +; A forward DCT routine is given a pointer to a work area of type DCTELEM[]; +; the DCT is to be performed in-place in that buffer. +; To maximize parallelism, Type DCTELEM is changed to short (originally, int). +; +%define DCTELEM word ; short +%define SIZEOF_DCTELEM SIZEOF_WORD ; sizeof(DCTELEM) + +%define FAST_FLOAT FP32 ; float +%define SIZEOF_FAST_FLOAT SIZEOF_FP32 ; sizeof(FAST_FLOAT) + +; To maximize parallelism, Type MULTIPLIER is changed to short. +; +%define ISLOW_MULT_TYPE word ; must be short +%define SIZEOF_ISLOW_MULT_TYPE SIZEOF_WORD ; sizeof(ISLOW_MULT_TYPE) + +%define IFAST_MULT_TYPE word ; must be short +%define SIZEOF_IFAST_MULT_TYPE SIZEOF_WORD ; sizeof(IFAST_MULT_TYPE) +%define IFAST_SCALE_BITS 2 ; fractional bits in scale factors + +%define FLOAT_MULT_TYPE FP32 ; must be float +%define SIZEOF_FLOAT_MULT_TYPE SIZEOF_FP32 ; sizeof(FLOAT_MULT_TYPE) + +; +; -- jsimd.h +; + +definev(JSIMD_NONE) +definev(JSIMD_MMX) +definev(JSIMD_3DNOW) +definev(JSIMD_SSE) +definev(JSIMD_SSE2) + +; Short forms of external names for systems with brain-damaged linkers. +; +#ifdef NEED_SHORT_EXTERNAL_NAMES +definev(jpeg_simd_cpu_support) +definev(jsimd_rgb_ycc_convert_mmx) +definev(jsimd_ycc_rgb_convert_mmx) +definev(jconst_rgb_ycc_convert_sse2) +definev(jsimd_rgb_ycc_convert_sse2) +definev(jconst_ycc_rgb_convert_sse2) +definev(jsimd_ycc_rgb_convert_sse2) +definev(jsimd_h2v2_downsample_mmx) +definev(jsimd_h2v1_downsample_mmx) +definev(jsimd_h2v2_downsample_sse2) +definev(jsimd_h2v1_downsample_sse2) +definev(jsimd_h2v2_upsample_mmx) +definev(jsimd_h2v1_upsample_mmx) +definev(jsimd_h2v1_fancy_upsample_mmx) +definev(jsimd_h2v2_fancy_upsample_mmx) +definev(jsimd_h2v1_merged_upsample_mmx) +definev(jsimd_h2v2_merged_upsample_mmx) +definev(jsimd_h2v2_upsample_sse2) +definev(jsimd_h2v1_upsample_sse2) +definev(jconst_fancy_upsample_sse2) +definev(jsimd_h2v1_fancy_upsample_sse2) +definev(jsimd_h2v2_fancy_upsample_sse2) +definev(jconst_merged_upsample_sse2) +definev(jsimd_h2v1_merged_upsample_sse2) +definev(jsimd_h2v2_merged_upsample_sse2) +definev(jsimd_convsamp_mmx) +definev(jsimd_convsamp_sse2) +definev(jsimd_convsamp_float_3dnow) +definev(jsimd_convsamp_float_sse) +definev(jsimd_convsamp_float_sse2) +definev(jsimd_fdct_islow_mmx) +definev(jsimd_fdct_ifast_mmx) +definev(jconst_fdct_islow_sse2) +definev(jsimd_fdct_islow_sse2) +definev(jconst_fdct_ifast_sse2) +definev(jsimd_fdct_ifast_sse2) +definev(jsimd_fdct_float_3dnow) +definev(jconst_fdct_float_sse) +definev(jsimd_fdct_float_sse) +definev(jsimd_quantize_mmx) +definev(jsimd_quantize_sse2) +definev(jsimd_quantize_float_3dnow) +definev(jsimd_quantize_float_sse) +definev(jsimd_quantize_float_sse2) +definev(jsimd_idct_2x2_mmx) +definev(jsimd_idct_4x4_mmx) +definev(jconst_idct_red_sse2) +definev(jsimd_idct_2x2_sse2) +definev(jsimd_idct_4x4_sse2) +definev(jsimd_idct_islow_mmx) +definev(jsimd_idct_ifast_mmx) +definev(jconst_idct_islow_sse2) +definev(jsimd_idct_islow_sse2) +definev(jconst_idct_ifast_sse2) +definev(jsimd_idct_ifast_sse2) +definev(jsimd_idct_float_3dnow) +definev(jconst_idct_float_sse) +definev(jsimd_idct_float_sse) +definev(jconst_idct_float_sse2) +definev(jsimd_idct_float_sse2) +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jsimddct.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jsimddct.h new file mode 100644 index 0000000..a1c7440 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jsimddct.h @@ -0,0 +1,102 @@ +/* + * jsimddct.h + * + * Copyright 2009 Pierre Ossman for Cendio AB + * + * Based on the x86 SIMD extension for IJG JPEG library, + * Copyright (C) 1999-2006, MIYASAKA Masaru. + * For conditions of distribution and use, see copyright notice in jsimdext.inc + * + */ + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jsimd_can_convsamp jSCanConv +#define jsimd_can_convsamp_float jSCanConvF +#define jsimd_convsamp jSConv +#define jsimd_convsamp_float jSConvF +#define jsimd_can_fdct_islow jSCanFDCTIS +#define jsimd_can_fdct_ifast jSCanFDCTIF +#define jsimd_can_fdct_float jSCanFDCTFl +#define jsimd_fdct_islow jSFDCTIS +#define jsimd_fdct_ifast jSFDCTIF +#define jsimd_fdct_float jSFDCTFl +#define jsimd_can_quantize jSCanQuant +#define jsimd_can_quantize_float jSCanQuantF +#define jsimd_quantize jSQuant +#define jsimd_quantize_float jSQuantF +#define jsimd_can_idct_2x2 jSCanIDCT22 +#define jsimd_can_idct_4x4 jSCanIDCT44 +#define jsimd_idct_2x2 jSIDCT22 +#define jsimd_idct_4x4 jSIDCT44 +#define jsimd_can_idct_islow jSCanIDCTIS +#define jsimd_can_idct_ifast jSCanIDCTIF +#define jsimd_can_idct_float jSCanIDCTFl +#define jsimd_idct_islow jSIDCTIS +#define jsimd_idct_ifast jSIDCTIF +#define jsimd_idct_float jSIDCTFl +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +EXTERN(int) jsimd_can_convsamp JPP((void)); +EXTERN(int) jsimd_can_convsamp_float JPP((void)); + +EXTERN(void) jsimd_convsamp JPP((JSAMPARRAY sample_data, + JDIMENSION start_col, + DCTELEM * workspace)); +EXTERN(void) jsimd_convsamp_float JPP((JSAMPARRAY sample_data, + JDIMENSION start_col, + FAST_FLOAT * workspace)); + +EXTERN(int) jsimd_can_fdct_islow JPP((void)); +EXTERN(int) jsimd_can_fdct_ifast JPP((void)); +EXTERN(int) jsimd_can_fdct_float JPP((void)); + +EXTERN(void) jsimd_fdct_islow JPP((DCTELEM * data)); +EXTERN(void) jsimd_fdct_ifast JPP((DCTELEM * data)); +EXTERN(void) jsimd_fdct_float JPP((FAST_FLOAT * data)); + +EXTERN(int) jsimd_can_quantize JPP((void)); +EXTERN(int) jsimd_can_quantize_float JPP((void)); + +EXTERN(void) jsimd_quantize JPP((JCOEFPTR coef_block, + DCTELEM * divisors, + DCTELEM * workspace)); +EXTERN(void) jsimd_quantize_float JPP((JCOEFPTR coef_block, + FAST_FLOAT * divisors, + FAST_FLOAT * workspace)); + +EXTERN(int) jsimd_can_idct_2x2 JPP((void)); +EXTERN(int) jsimd_can_idct_4x4 JPP((void)); + +EXTERN(void) jsimd_idct_2x2 JPP((j_decompress_ptr cinfo, + jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, + JDIMENSION output_col)); +EXTERN(void) jsimd_idct_4x4 JPP((j_decompress_ptr cinfo, + jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, + JDIMENSION output_col)); + +EXTERN(int) jsimd_can_idct_islow JPP((void)); +EXTERN(int) jsimd_can_idct_ifast JPP((void)); +EXTERN(int) jsimd_can_idct_float JPP((void)); + +EXTERN(void) jsimd_idct_islow JPP((j_decompress_ptr cinfo, + jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, + JDIMENSION output_col)); +EXTERN(void) jsimd_idct_ifast JPP((j_decompress_ptr cinfo, + jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, + JDIMENSION output_col)); +EXTERN(void) jsimd_idct_float JPP((j_decompress_ptr cinfo, + jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, + JDIMENSION output_col)); + diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jversion.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jversion.h new file mode 100644 index 0000000..a045405 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/jversion.h @@ -0,0 +1,36 @@ +/* + * jversion.h + * + * Copyright (C) 1991-2010, Thomas G. Lane, Guido Vollbeding. + * Copyright (C) 2010, D. R. Commander. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains software version identification. + */ + + +#if JPEG_LIB_VERSION >= 80 + +#define JVERSION "8b 16-May-2010" + +#define JCOPYRIGHT "Copyright (C) 2010, Thomas G. Lane, Guido Vollbeding" + +#elif JPEG_LIB_VERSION >= 70 + +#define JVERSION "7 27-Jun-2009" + +#define JCOPYRIGHT "Copyright (C) 2009, Thomas G. Lane, Guido Vollbeding" + +#else + +#define JVERSION "6b 27-Mar-1998" + +#define JCOPYRIGHT "Copyright (C) 1998, Thomas G. Lane" + +#endif + +#define LJTCOPYRIGHT "Copyright (C) 1999-2006 MIYASAKA Masaru\n" \ + "Copyright (C) 2009 Pierre Ossman for Cendio AB\n" \ + "Copyright (C) 2009-2011 D. R. Commander\n" \ + "Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies)" diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/platform.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/platform.h new file mode 100644 index 0000000..f7f28af --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/platform.h @@ -0,0 +1,11 @@ +#ifndef __JKUTILS_H__ +#define __JKUTILS_H__ + +#include +#include +#include +#include + +typedef struct { unsigned char *bytes; } Allocation; + +#endif \ No newline at end of file diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/tjutil.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/tjutil.h new file mode 100644 index 0000000..bdad348 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/tjutil.h @@ -0,0 +1,47 @@ +/* + * Copyright (C)2011 D. R. Commander. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted 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 libjpeg-turbo Project nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 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 HOLDERS 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. + */ + +#ifdef _WIN32 + #ifndef __MINGW32__ + #include + #define snprintf(str, n, format, ...) \ + _snprintf_s(str, n, _TRUNCATE, format, __VA_ARGS__) + #endif + #define strcasecmp stricmp + #define strncasecmp strnicmp +#endif + +#ifndef min + #define min(a,b) ((a)<(b)?(a):(b)) +#endif + +#ifndef max + #define max(a,b) ((a)>(b)?(a):(b)) +#endif + +extern double gettime(void); diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/transupp.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/transupp.h new file mode 100644 index 0000000..57633ab --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/transupp.h @@ -0,0 +1,217 @@ +/* + * transupp.h + * + * Copyright (C) 1997-2009, Thomas G. Lane, Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for image transformation routines and + * other utility code used by the jpegtran sample application. These are + * NOT part of the core JPEG library. But we keep these routines separate + * from jpegtran.c to ease the task of maintaining jpegtran-like programs + * that have other user interfaces. + * + * NOTE: all the routines declared here have very specific requirements + * about when they are to be executed during the reading and writing of the + * source and destination files. See the comments in transupp.c, or see + * jpegtran.c for an example of correct usage. + */ + +/* If you happen not to want the image transform support, disable it here */ +#ifndef TRANSFORMS_SUPPORTED +#define TRANSFORMS_SUPPORTED 1 /* 0 disables transform code */ +#endif + +/* + * Although rotating and flipping data expressed as DCT coefficients is not + * hard, there is an asymmetry in the JPEG format specification for images + * whose dimensions aren't multiples of the iMCU size. The right and bottom + * image edges are padded out to the next iMCU boundary with junk data; but + * no padding is possible at the top and left edges. If we were to flip + * the whole image including the pad data, then pad garbage would become + * visible at the top and/or left, and real pixels would disappear into the + * pad margins --- perhaps permanently, since encoders & decoders may not + * bother to preserve DCT blocks that appear to be completely outside the + * nominal image area. So, we have to exclude any partial iMCUs from the + * basic transformation. + * + * Transpose is the only transformation that can handle partial iMCUs at the + * right and bottom edges completely cleanly. flip_h can flip partial iMCUs + * at the bottom, but leaves any partial iMCUs at the right edge untouched. + * Similarly flip_v leaves any partial iMCUs at the bottom edge untouched. + * The other transforms are defined as combinations of these basic transforms + * and process edge blocks in a way that preserves the equivalence. + * + * The "trim" option causes untransformable partial iMCUs to be dropped; + * this is not strictly lossless, but it usually gives the best-looking + * result for odd-size images. Note that when this option is active, + * the expected mathematical equivalences between the transforms may not hold. + * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim + * followed by -rot 180 -trim trims both edges.) + * + * We also offer a lossless-crop option, which discards data outside a given + * image region but losslessly preserves what is inside. Like the setRotation and + * flip transforms, lossless crop is restricted by the JPEG format: the upper + * left corner of the selected region must fall on an iMCU boundary. If this + * does not hold for the given crop parameters, we silently move the upper left + * corner up and/or left to make it so, simultaneously increasing the region + * dimensions to keep the lower right crop corner unchanged. (Thus, the + * output image covers at least the requested region, but may cover more.) + * + * We also provide a lossless-resize option, which is kind of a lossless-crop + * operation in the DCT coefficient block domain - it discards higher-order + * coefficients and losslessly preserves lower-order coefficients of a + * sub-block. + * + * Rotate/flip transform, resize, and crop can be requested together in a + * single invocation. The crop is applied last --- that is, the crop region + * is specified in terms of the destination image after transform/resize. + * + * We also offer a "force to grayscale" option, which simply discards the + * chrominance channels of a YCbCr image. This is lossless in the sense that + * the luminance channel is preserved exactly. It's not the same kind of + * thing as the setRotation/flip transformations, but it's convenient to handle it + * as part of this package, mainly because the transformation routines have to + * be aware of the option to know how many components to work on. + */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jtransform_parse_crop_spec jTrParCrop +#define jtransform_request_workspace jTrRequest +#define jtransform_adjust_parameters jTrAdjust +#define jtransform_execute_transform jTrExec +#define jtransform_perfect_transform jTrPerfect +#define jcopy_markers_setup jCMrkSetup +#define jcopy_markers_execute jCMrkExec +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* + * Codes for supported types of image transformations. + */ + +typedef enum { + JXFORM_NONE, /* no transformation */ + JXFORM_FLIP_H, /* horizontal flip */ + JXFORM_FLIP_V, /* vertical flip */ + JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */ + JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */ + JXFORM_ROT_90, /* 90-degree clockwise rotation */ + JXFORM_ROT_180, /* 180-degree rotation */ + JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */ +} JXFORM_CODE; + +/* + * Codes for crop parameters, which can individually be unspecified, + * positive, or negative. (Negative width or height makes no sense, though.) + */ + +typedef enum { + JCROP_UNSET, + JCROP_POS, + JCROP_NEG +} JCROP_CODE; + +/* + * Transform parameters struct. + * NB: application must not change any elements of this struct after + * calling jtransform_request_workspace. + */ + +typedef struct { + /* Options: set by caller */ + JXFORM_CODE transform; /* image transform operator */ + boolean perfect; /* if TRUE, fail if partial MCUs are requested */ + boolean trim; /* if TRUE, trim partial MCUs as needed */ + boolean force_grayscale; /* if TRUE, convert color image to grayscale */ + boolean crop; /* if TRUE, crop source image */ + boolean slow_hflip; /* For best performance, the JXFORM_FLIP_H transform + normally modifies the source coefficients in place. + Setting this to TRUE will instead use a slower, + double-buffered algorithm, which leaves the source + coefficients in tact (necessary if other transformed + images must be generated from the same set of + coefficients. */ + + /* Crop parameters: application need not set these unless crop is TRUE. + * These can be filled in by jtransform_parse_crop_spec(). + */ + JDIMENSION crop_width; /* Width of selected region */ + JCROP_CODE crop_width_set; + JDIMENSION crop_height; /* Height of selected region */ + JCROP_CODE crop_height_set; + JDIMENSION crop_xoffset; /* X offset of selected region */ + JCROP_CODE crop_xoffset_set; /* (negative measures from right edge) */ + JDIMENSION crop_yoffset; /* Y offset of selected region */ + JCROP_CODE crop_yoffset_set; /* (negative measures from bottom edge) */ + + /* Internal workspace: caller should not touch these */ + int num_components; /* # of components in workspace */ + jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */ + JDIMENSION output_width; /* cropped destination dimensions */ + JDIMENSION output_height; + JDIMENSION x_crop_offset; /* destination crop offsets measured in iMCUs */ + JDIMENSION y_crop_offset; + int iMCU_sample_width; /* destination iMCU size */ + int iMCU_sample_height; +} jpeg_transform_info; + + +#if TRANSFORMS_SUPPORTED + +/* Parse a crop specification (written in X11 geometry style) */ +EXTERN(boolean) jtransform_parse_crop_spec + JPP((jpeg_transform_info *info, const char *spec)); +/* Request any required workspace */ +EXTERN(boolean) jtransform_request_workspace + JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info)); +/* Adjust output image parameters */ +EXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info)); +/* Execute the actual transformation, if any */ +EXTERN(void) jtransform_execute_transform + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info)); +/* Determine whether lossless transformation is perfectly + * possible for a specified image and transformation. + */ +EXTERN(boolean) jtransform_perfect_transform + JPP((JDIMENSION image_width, JDIMENSION image_height, + int MCU_width, int MCU_height, + JXFORM_CODE transform)); + +/* jtransform_execute_transform used to be called + * jtransform_execute_transformation, but some compilers complain about + * routine names that long. This macro is here to avoid breaking any + * old source code that uses the original name... + */ +#define jtransform_execute_transformation jtransform_execute_transform + +#endif /* TRANSFORMS_SUPPORTED */ + + +/* + * Support for copying optional markers from source to destination file. + */ + +typedef enum { + JCOPYOPT_NONE, /* copy no optional markers */ + JCOPYOPT_COMMENTS, /* copy only comment (COM) markers */ + JCOPYOPT_ALL /* copy all optional markers */ +} JCOPY_OPTION; + +#define JCOPYOPT_DEFAULT JCOPYOPT_COMMENTS /* recommended default */ + +/* Setup decompression object to writeFileAsync desired markers in memory */ +EXTERN(void) jcopy_markers_setup + JPP((j_decompress_ptr srcinfo, JCOPY_OPTION option)); +/* Copy markers saved in the given source object to the destination object */ +EXTERN(void) jcopy_markers_execute + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JCOPY_OPTION option)); diff --git a/duix-sdk/src/main/cpp/third/arm/include/tjpeg/turbojpeg.h b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/turbojpeg.h new file mode 100644 index 0000000..343788a --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/tjpeg/turbojpeg.h @@ -0,0 +1,897 @@ +/* + * Copyright (C)2009-2011 D. R. Commander. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted 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 libjpeg-turbo Project nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 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 HOLDERS 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. + */ + +#ifndef __TURBOJPEG_H__ +#define __TURBOJPEG_H__ + +#if defined(_WIN32) && defined(DLLDEFINE) +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif +#define DLLCALL + + +/** + * @addtogroup TurboJPEG + * TurboJPEG API. This API provides an interface for generating, decoding, and + * transforming planar YUV and JPEG images in memory. + * + * @{ + */ + + +/** + * The number of chrominance subsampling options + */ +#define TJ_NUMSAMP 5 + +/** + * Chrominance subsampling options. + * When an image is converted from the RGB to the YCbCr colorspace as part of + * the JPEG compression process, some of the Cb and Cr (chrominance) components + * can be discarded or averaged together to produce a smaller image with little + * perceptible loss of image clarity (the human eye is more sensitive to small + * changes in brightness than small changes in color.) This is called + * "chrominance subsampling". + */ +enum TJSAMP +{ + /** + * 4:4:4 chrominance subsampling (no chrominance subsampling). The JPEG or + * YUV image will contain one chrominance component for every pixel in the + * source image. + */ + TJSAMP_444=0, + /** + * 4:2:2 chrominance subsampling. The JPEG or YUV image will contain one + * chrominance component for every 2x1 block of pixels in the source image. + */ + TJSAMP_422, + /** + * 4:2:0 chrominance subsampling. The JPEG or YUV image will contain one + * chrominance component for every 2x2 block of pixels in the source image. + */ + TJSAMP_420, + /** + * Grayscale. The JPEG or YUV image will contain no chrominance components. + */ + TJSAMP_GRAY, + /** + * 4:4:0 chrominance subsampling. The JPEG or YUV image will contain one + * chrominance component for every 1x2 block of pixels in the source image. + */ + TJSAMP_440 +}; + +/** + * MCU block width (in pixels) for a given level of chrominance subsampling. + * MCU block sizes: + * - 8x8 for no subsampling or grayscale + * - 16x8 for 4:2:2 + * - 8x16 for 4:4:0 + * - 16x16 for 4:2:0 + */ +static const int tjMCUWidth[TJ_NUMSAMP] = {8, 16, 16, 8, 8}; + +/** + * MCU block height (in pixels) for a given level of chrominance subsampling. + * MCU block sizes: + * - 8x8 for no subsampling or grayscale + * - 16x8 for 4:2:2 + * - 8x16 for 4:4:0 + * - 16x16 for 4:2:0 + */ +static const int tjMCUHeight[TJ_NUMSAMP] = {8, 8, 16, 8, 16}; + + +/** + * The number of pixel formats + */ +#define TJ_NUMPF 11 + +/** + * Pixel formats + */ +enum TJPF +{ + /** + * RGB pixel format. The red, green, and blue components in the image are + * stored in 3-byte pixels in the order R, G, B from lowest to highest byte + * address within each pixel. + */ + TJPF_RGB=0, + /** + * BGR pixel format. The red, green, and blue components in the image are + * stored in 3-byte pixels in the order B, G, R from lowest to highest byte + * address within each pixel. + */ + TJPF_BGR, + /** + * RGBX pixel format. The red, green, and blue components in the image are + * stored in 4-byte pixels in the order R, G, B from lowest to highest byte + * address within each pixel. The X component is ignored when compressing + * and undefined when decompressing. + */ + TJPF_RGBX, + /** + * BGRX pixel format. The red, green, and blue components in the image are + * stored in 4-byte pixels in the order B, G, R from lowest to highest byte + * address within each pixel. The X component is ignored when compressing + * and undefined when decompressing. + */ + TJPF_BGRX, + /** + * XBGR pixel format. The red, green, and blue components in the image are + * stored in 4-byte pixels in the order R, G, B from highest to lowest byte + * address within each pixel. The X component is ignored when compressing + * and undefined when decompressing. + */ + TJPF_XBGR, + /** + * XRGB pixel format. The red, green, and blue components in the image are + * stored in 4-byte pixels in the order B, G, R from highest to lowest byte + * address within each pixel. The X component is ignored when compressing + * and undefined when decompressing. + */ + TJPF_XRGB, + /** + * Grayscale pixel format. Each 1-byte pixel represents a luminance + * (brightness) level from 0 to 255. + */ + TJPF_GRAY, + /** + * RGBA pixel format. This is the same as @ref TJPF_RGBX, except that when + * decompressing, the X component is guaranteed to be 0xFF, which can be + * interpreted as an opaque alpha channel. + */ + TJPF_RGBA, + /** + * BGRA pixel format. This is the same as @ref TJPF_BGRX, except that when + * decompressing, the X component is guaranteed to be 0xFF, which can be + * interpreted as an opaque alpha channel. + */ + TJPF_BGRA, + /** + * ABGR pixel format. This is the same as @ref TJPF_XBGR, except that when + * decompressing, the X component is guaranteed to be 0xFF, which can be + * interpreted as an opaque alpha channel. + */ + TJPF_ABGR, + /** + * ARGB pixel format. This is the same as @ref TJPF_XRGB, except that when + * decompressing, the X component is guaranteed to be 0xFF, which can be + * interpreted as an opaque alpha channel. + */ + TJPF_ARGB +}; + +/** + * Red offset (in bytes) for a given pixel format. This specifies the number + * of bytes that the red component is offset from the start of the pixel. For + * instance, if a pixel of format TJ_BGRX is stored in char pixel[], + * then the red component will be pixel[tjRedOffset[TJ_BGRX]]. + */ +static const int tjRedOffset[TJ_NUMPF] = {0, 2, 0, 2, 3, 1, 0, 0, 2, 3, 1}; +/** + * Green offset (in bytes) for a given pixel format. This specifies the number + * of bytes that the green component is offset from the start of the pixel. + * For instance, if a pixel of format TJ_BGRX is stored in + * char pixel[], then the green component will be + * pixel[tjGreenOffset[TJ_BGRX]]. + */ +static const int tjGreenOffset[TJ_NUMPF] = {1, 1, 1, 1, 2, 2, 0, 1, 1, 2, 2}; +/** + * Blue offset (in bytes) for a given pixel format. This specifies the number + * of bytes that the Blue component is offset from the start of the pixel. For + * instance, if a pixel of format TJ_BGRX is stored in char pixel[], + * then the blue component will be pixel[tjBlueOffset[TJ_BGRX]]. + */ +static const int tjBlueOffset[TJ_NUMPF] = {2, 0, 2, 0, 1, 3, 0, 2, 0, 1, 3}; + +/** + * Pixel size (in bytes) for a given pixel format. + */ +static const int tjPixelSize[TJ_NUMPF] = {3, 3, 4, 4, 4, 4, 1, 4, 4, 4, 4}; + + +/** + * The uncompressed source/destination image is stored in bottom-up (Windows, + * OpenGL) order, not top-down (X11) order. + */ +#define TJFLAG_BOTTOMUP 2 +/** + * Turn off CPU auto-detection and force TurboJPEG to use MMX code (IPP and + * 32-bit libjpeg-turbo versions only.) + */ +#define TJFLAG_FORCEMMX 8 +/** + * Turn off CPU auto-detection and force TurboJPEG to use SSE code (32-bit IPP + * and 32-bit libjpeg-turbo versions only) + */ +#define TJFLAG_FORCESSE 16 +/** + * Turn off CPU auto-detection and force TurboJPEG to use SSE2 code (32-bit IPP + * and 32-bit libjpeg-turbo versions only) + */ +#define TJFLAG_FORCESSE2 32 +/** + * Turn off CPU auto-detection and force TurboJPEG to use SSE3 code (64-bit IPP + * version only) + */ +#define TJFLAG_FORCESSE3 128 +/** + * Use fast, inaccurate chrominance upsampling routines in the JPEG + * decompressor (libjpeg and libjpeg-turbo versions only) + */ +#define TJFLAG_FASTUPSAMPLE 256 +/** + * Disable buffer (re)allocation. If passed to #tjCompress2() or + * #tjTransform(), this flag will cause those functions to generate an error if + * the JPEG image buffer is invalid or too small rather than attempting to + * allocate or reallocate that buffer. This reproduces the behavior of earlier + * versions of TurboJPEG. + */ +#define TJFLAG_NOREALLOC 1024 + + +/** + * Number of transform operations + */ +#define TJ_NUMXOP 8 + +/** + * Transform operations for #tjTransform() + */ +enum TJXOP +{ + /** + * Do not transform the position of the image pixels + */ + TJXOP_NONE=0, + /** + * Flip (mirror) image horizontally. This transform is imperfect if there + * are any partial MCU blocks on the right edge (see #TJXOPT_PERFECT.) + */ + TJXOP_HFLIP, + /** + * Flip (mirror) image vertically. This transform is imperfect if there are + * any partial MCU blocks on the bottom edge (see #TJXOPT_PERFECT.) + */ + TJXOP_VFLIP, + /** + * Transpose image (flip/mirror along upper left to lower right axis.) This + * transform is always perfect. + */ + TJXOP_TRANSPOSE, + /** + * Transverse transpose image (flip/mirror along upper right to lower left + * axis.) This transform is imperfect if there are any partial MCU blocks in + * the image (see #TJXOPT_PERFECT.) + */ + TJXOP_TRANSVERSE, + /** + * Rotate image clockwise by 90 degrees. This transform is imperfect if + * there are any partial MCU blocks on the bottom edge (see + * #TJXOPT_PERFECT.) + */ + TJXOP_ROT90, + /** + * Rotate image 180 degrees. This transform is imperfect if there are any + * partial MCU blocks in the image (see #TJXOPT_PERFECT.) + */ + TJXOP_ROT180, + /** + * Rotate image counter-clockwise by 90 degrees. This transform is imperfect + * if there are any partial MCU blocks on the right edge (see + * #TJXOPT_PERFECT.) + */ + TJXOP_ROT270 +}; + + +/** + * This option will cause #tjTransform() to return an error if the transform is + * not perfect. Lossless transforms operate on MCU blocks, whose size depends + * on the level of chrominance subsampling used (see #tjMCUWidth + * and #tjMCUHeight.) If the image's width or height is not evenly divisible + * by the MCU block size, then there will be partial MCU blocks on the right + * and/or bottom edges. It is not possible to move these partial MCU blocks to + * the top or left of the image, so any transform that would require that is + * "imperfect." If this option is not specified, then any partial MCU blocks + * that cannot be transformed will be left in place, which will create + * odd-looking strips on the right or bottom edge of the image. + */ +#define TJXOPT_PERFECT 1 +/** + * This option will cause #tjTransform() to discard any partial MCU blocks that + * cannot be transformed. + */ +#define TJXOPT_TRIM 2 +/** + * This option will enable lossless cropping. See #tjTransform() for more + * information. + */ +#define TJXOPT_CROP 4 +/** + * This option will discard the color data in the input image and produce + * a grayscale output image. + */ +#define TJXOPT_GRAY 8 +/** + * This option will prevent #tjTransform() from outputting a JPEG image for + * this particular transform (this can be used in conjunction with a custom + * filter to capture the transformed DCT coefficients without transcoding + * them.) + */ +#define TJXOPT_NOOUTPUT 16 + + +/** + * Scaling factor + */ +typedef struct +{ + /** + * Numerator + */ + int num; + /** + * Denominator + */ + int denom; +} tjscalingfactor; + +/** + * Cropping region + */ +typedef struct +{ + /** + * The left boundary of the cropping region. This must be evenly divisible + * by the MCU block width (see #tjMCUWidth.) + */ + int x; + /** + * The upper boundary of the cropping region. This must be evenly divisible + * by the MCU block height (see #tjMCUHeight.) + */ + int y; + /** + * The width of the cropping region. Setting this to 0 is the equivalent of + * setting it to the width of the source JPEG image - x. + */ + int w; + /** + * The height of the cropping region. Setting this to 0 is the equivalent of + * setting it to the height of the source JPEG image - y. + */ + int h; +} tjregion; + +/** + * Lossless transform + */ +typedef struct tjtransform +{ + /** + * Cropping region + */ + tjregion r; + /** + * One of the @ref TJXOP "transform operations" + */ + int op; + /** + * The bitwise OR of one of more of the @ref TJXOPT_CROP "transform options" + */ + int options; + /** + * Arbitrary data that can be accessed within the body of the callback + * function + */ + void *data; + /** + * A callback function that can be used to modify the DCT coefficients + * after they are losslessly transformed but before they are transcoded to a + * new JPEG file. This allows for custom filters or other transformations to + * be applied in the frequency domain. + * + * @param coeffs pointer to an array of transformed DCT coefficients. (NOTE: + * this pointer is not guaranteed to be valid once the callback + * returns, so applications wishing to hand off the DCT coefficients + * to another function or library should make a copy of them within + * the body of the callback.) + * @param arrayRegion #tjregion structure containing the width and height of + * the array pointed to by coeffs as well as its offset + * relative to the component plane. TurboJPEG implementations may + * choose to split each component plane into multiple DCT coefficient + * arrays and call the callback function once for each array. + * @param planeRegion #tjregion structure containing the width and height of + * the component plane to which coeffs belongs + * @param componentID ID number of the component plane to which + * coeffs belongs (Y, Cb, and Cr have, respectively, ID's of + * 0, 1, and 2 in typical JPEG images.) + * @param transformID ID number of the transformed image to which + * coeffs belongs. This is the same as the index of the + * transform in the transforms array that was passed to + * #tjTransform(). + * @param transform a pointer to a #tjtransform structure that specifies the + * parameters and/or cropping region for this transform + * + * @return 0 if the callback was successful, or -1 if an error occurred. + */ + int (*customFilter)(short *coeffs, tjregion arrayRegion, + tjregion planeRegion, int componentIndex, int transformIndex, + struct tjtransform *transform); +} tjtransform; + +/** + * TurboJPEG instance handle + */ +typedef void* tjhandle; + + +/** + * Pad the given width to the nearest 32-bit boundary + */ +#define TJPAD(width) (((width)+3)&(~3)) + +/** + * Compute the scaled value of dimension using the given scaling + * factor. This macro performs the integer equivalent of ceil(dimension * + * scalingFactor). + */ +#define TJSCALED(dimension, scalingFactor) ((dimension * scalingFactor.num \ + + scalingFactor.denom - 1) / scalingFactor.denom) + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Create a TurboJPEG compressor instance. + * + * @return a handle to the newly-created instance, or NULL if an error + * occurred (see #tjGetErrorStr().) + */ +DLLEXPORT tjhandle DLLCALL tjInitCompress(void); + + +/** + * Compress an RGB or grayscale image into a JPEG image. + * + * @param handle a handle to a TurboJPEG compressor or transformer instance + * @param srcBuf pointer to an image buffer containing RGB or grayscale pixels + * to be compressed + * @param width width (in pixels) of the source image + * @param pitch bytes per line of the source image. Normally, this should be + * width * #tjPixelSize[pixelFormat] if the image is unpadded, + * or #TJPAD(width * #tjPixelSize[pixelFormat]) if each line of + * the image is padded to the nearest 32-bit boundary, as is the case + * for Windows bitmaps. You can also be clever and use this parameter + * to skip lines, etc. Setting this parameter to 0 is the equivalent of + * setting it to width * #tjPixelSize[pixelFormat]. + * @param height height (in pixels) of the source image + * @param pixelFormat pixel format of the source image (see @ref TJPF + * "Pixel formats".) + * @param jpegBuf address of a pointer to an image buffer that will receive the + * JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer + * to accommodate the size of the JPEG image. Thus, you can choose to: + * -# pre-allocate the JPEG buffer with an arbitrary size using + * #tjAlloc() and let TurboJPEG grow the buffer as needed, + * -# set *jpegBuf to NULL to tell TurboJPEG to allocate the + * buffer for you, or + * -# pre-allocate the buffer to a "worst case" size determined by + * calling #tjBufSize(). This should ensure that the buffer never has + * to be re-allocated (setting #TJFLAG_NOREALLOC guarantees this.) + * . + * If you choose option 1, *jpegSize should be set to the + * size of your pre-allocated buffer. In any case, unless you have + * set #TJFLAG_NOREALLOC, you should always check *jpegBuf upon + * return from this function, as it may have changed. + * @param jpegSize pointer to an unsigned long variable that holds the size of + * the JPEG image buffer. If *jpegBuf points to a + * pre-allocated buffer, then *jpegSize should be set to the + * size of the buffer. Upon return, *jpegSize will contain the + * size of the JPEG image (in bytes.) + * @param jpegSubsamp the level of chrominance subsampling to be used when + * generating the JPEG image (see @ref TJSAMP + * "Chrominance subsampling options".) + * @param jpegQual the image quality of the generated JPEG image (1 = worst, + 100 = best) + * @param flags the bitwise OR of one or more of the @ref TJFLAG_BOTTOMUP + * "flags". + * + * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().) +*/ +DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf, + int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf, + unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags); + + +/** + * The maximum size of the buffer (in bytes) required to hold a JPEG image with + * the given parameters. The number of bytes returned by this function is + * larger than the size of the uncompressed source image. The reason for this + * is that the JPEG format uses 16-bit coefficients, and it is thus possible + * for a very high-quality JPEG image with very high frequency content to + * expand rather than compress when converted to the JPEG format. Such images + * represent a very rare corner case, but since there is no way to predict the + * size of a JPEG image prior to compression, the corner case has to be + * handled. + * + * @param width width of the image (in pixels) + * @param height height of the image (in pixels) + * @param jpegSubsamp the level of chrominance subsampling to be used when + * generating the JPEG image (see @ref TJSAMP + * "Chrominance subsampling options".) + * + * @return the maximum size of the buffer (in bytes) required to hold the + * image, or -1 if the arguments are out of bounds. + */ +DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height, + int jpegSubsamp); + + +/** + * The size of the buffer (in bytes) required to hold a YUV planar image with + * the given parameters. + * + * @param width width of the image (in pixels) + * @param height height of the image (in pixels) + * @param subsamp level of chrominance subsampling in the image (see + * @ref TJSAMP "Chrominance subsampling options".) + * + * @return the size of the buffer (in bytes) required to hold the image, or + * -1 if the arguments are out of bounds. + */ +DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height, + int subsamp); + + +/** + * Encode an RGB or grayscale image into a YUV planar image. This function + * uses the accelerated color conversion routines in TurboJPEG's underlying + * codec to produce a planar YUV image that is suitable for X Video. + * Specifically, if the chrominance components are subsampled along the + * horizontal dimension, then the width of the luminance plane is padded to 2 + * in the output image (same goes for the height of the luminance plane, if the + * chrominance components are subsampled along the vertical dimension.) Also, + * each line of each plane in the output image is padded to 4 bytes. Although + * this will work with any subsampling option, it is really only useful in + * combination with TJ_420, which produces an image compatible with the I420 + * (AKA "YUV420P") format. + * + * @param handle a handle to a TurboJPEG compressor or transformer instance + * @param srcBuf pointer to an image buffer containing RGB or grayscale pixels + * to be encoded + * @param width width (in pixels) of the source image + * @param pitch bytes per line of the source image. Normally, this should be + * width * #tjPixelSize[pixelFormat] if the image is unpadded, + * or #TJPAD(width * #tjPixelSize[pixelFormat]) if each line of + * the image is padded to the nearest 32-bit boundary, as is the case + * for Windows bitmaps. You can also be clever and use this parameter + * to skip lines, etc. Setting this parameter to 0 is the equivalent of + * setting it to width * #tjPixelSize[pixelFormat]. + * @param height height (in pixels) of the source image + * @param pixelFormat pixel format of the source image (see @ref TJPF + * "Pixel formats".) + * @param dstBuf pointer to an image buffer that will receive the YUV image. + * Use #tjBufSizeYUV() to determine the appropriate size for this buffer + * based on the image width, height, and level of chrominance + * subsampling. + * @param subsamp the level of chrominance subsampling to be used when + * generating the YUV image (see @ref TJSAMP + * "Chrominance subsampling options".) + * @param flags the bitwise OR of one or more of the @ref TJFLAG_BOTTOMUP + * "flags". + * + * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().) +*/ +DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, + unsigned char *srcBuf, int width, int pitch, int height, int pixelFormat, + unsigned char *dstBuf, int subsamp, int flags); + + +/** + * Create a TurboJPEG decompressor instance. + * + * @return a handle to the newly-created instance, or NULL if an error + * occurred (see #tjGetErrorStr().) +*/ +DLLEXPORT tjhandle DLLCALL tjInitDecompress(void); + + +/** + * Retrieve information about a JPEG image without decompressing it. + * + * @param handle a handle to a TurboJPEG decompressor or transformer instance + * @param jpegBuf pointer to a buffer containing a JPEG image + * @param jpegSize size of the JPEG image (in bytes) + * @param width pointer to an integer variable that will receive the width (in + * pixels) of the JPEG image + * @param height pointer to an integer variable that will receive the height + * (in pixels) of the JPEG image + * @param jpegSubsamp pointer to an integer variable that will receive the + * level of chrominance subsampling used when compressing the JPEG image + * (see @ref TJSAMP "Chrominance subsampling options".) + * + * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().) +*/ +DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle, + unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height, + int *jpegSubsamp); + + +/** + * Returns a list of fractional scaling factors that the JPEG decompressor in + * this implementation of TurboJPEG supports. + * + * @param numscalingfactors pointer to an integer variable that will receive + * the number of elements in the list + * + * @return a pointer to a list of fractional scaling factors, or NULL if an + * error is encountered (see #tjGetErrorStr().) +*/ +DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors); + + +/** + * Decompress a JPEG image to an RGB or grayscale image. + * + * @param handle a handle to a TurboJPEG decompressor or transformer instance + * @param jpegBuf pointer to a buffer containing the JPEG image to decompress + * @param jpegSize size of the JPEG image (in bytes) + * @param dstBuf pointer to an image buffer that will receive the decompressed + * image. This buffer should normally be pitch * scaledHeight + * bytes in size, where scaledHeight can be determined by + * calling #TJSCALED() with the JPEG image height and one of the scaling + * factors returned by #tjGetScalingFactors(). The dstBuf pointer may + * also be used to decompress into a specific region of a larger buffer. + * @param width desired width (in pixels) of the destination image. If this is + * smaller than the width of the JPEG image being decompressed, then + * TurboJPEG will use scaling in the JPEG decompressor to generate the + * largest possible image that will fit within the desired width. If + * width is set to 0, then only the height will be considered when + * determining the scaled image size. + * @param pitch bytes per line of the destination image. Normally, this is + * scaledWidth * #tjPixelSize[pixelFormat] if the decompressed + * image is unpadded, else #TJPAD(scaledWidth * + * #tjPixelSize[pixelFormat]) if each line of the decompressed + * image is padded to the nearest 32-bit boundary, as is the case for + * Windows bitmaps. (NOTE: scaledWidth can be determined by + * calling #TJSCALED() with the JPEG image width and one of the scaling + * factors returned by #tjGetScalingFactors().) You can also be clever + * and use the pitch parameter to skip lines, etc. Setting this + * parameter to 0 is the equivalent of setting it to scaledWidth + * * #tjPixelSize[pixelFormat]. + * @param height desired height (in pixels) of the destination image. If this + * is smaller than the height of the JPEG image being decompressed, then + * TurboJPEG will use scaling in the JPEG decompressor to generate the + * largest possible image that will fit within the desired height. If + * height is set to 0, then only the width will be considered when + * determining the scaled image size. + * @param pixelFormat pixel format of the destination image (see @ref + * TJPF "Pixel formats".) + * @param flags the bitwise OR of one or more of the @ref TJFLAG_BOTTOMUP + * "flags". + * + * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().) + */ +DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, + unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf, + int width, int pitch, int height, int pixelFormat, int flags); + + +/** + * Decompress a JPEG image to a YUV planar image. This function performs JPEG + * decompression but leaves out the color conversion step, so a planar YUV + * image is generated instead of an RGB image. The padding of the planes in + * this image is the same as the images generated by #tjEncodeYUV2(). Note + * that, if the width or height of the image is not an even multiple of the MCU + * block size (see #tjMCUWidth and #tjMCUHeight), then an intermediate buffer + * copy will be performed within TurboJPEG. + * + * @param handle a handle to a TurboJPEG decompressor or transformer instance + * @param jpegBuf pointer to a buffer containing the JPEG image to decompress + * @param jpegSize size of the JPEG image (in bytes) + * @param dstBuf pointer to an image buffer that will receive the YUV image. + * Use #tjBufSizeYUV to determine the appropriate size for this buffer + * based on the image width, height, and level of subsampling. + * @param flags the bitwise OR of one or more of the @ref TJFLAG_BOTTOMUP + * "flags". + * + * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().) + */ +DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle, + unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf, + int flags); + + +/** + * Create a new TurboJPEG transformer instance. + * + * @return a handle to the newly-created instance, or NULL if an error + * occurred (see #tjGetErrorStr().) + */ +DLLEXPORT tjhandle DLLCALL tjInitTransform(void); + + +/** + * Losslessly transform a JPEG image into another JPEG image. Lossless + * transforms work by moving the raw coefficients from one JPEG image structure + * to another without altering the values of the coefficients. While this is + * typically faster than decompressing the image, transforming it, and + * re-compressing it, lossless transforms are not free. Each lossless + * transform requires reading and Huffman decoding all of the coefficients in + * the source image, regardless of the size of the destination image. Thus, + * this function provides a means of generating multiple transformed images + * from the same source or of applying multiple transformations simultaneously, + * in order to eliminate the need to read the source coefficients multiple + * times. + * + * @param handle a handle to a TurboJPEG transformer instance + * @param jpegBuf pointer to a buffer containing the JPEG image to transform + * @param jpegSize size of the JPEG image (in bytes) + * @param n the number of transformed JPEG images to generate + * @param dstBufs pointer to an array of n image buffers. dstBufs[i] + * will receive a JPEG image that has been transformed using the + * parameters in transforms[i]. TurboJPEG has the ability to + * reallocate the JPEG buffer to accommodate the size of the JPEG image. + * Thus, you can choose to: + * -# pre-allocate the JPEG buffer with an arbitrary size using + * #tjAlloc() and let TurboJPEG grow the buffer as needed, + * -# set dstBufs[i] to NULL to tell TurboJPEG to allocate the + * buffer for you, or + * -# pre-allocate the buffer to a "worst case" size determined by + * calling #tjBufSize() with the cropped width and height. This should + * ensure that the buffer never has to be re-allocated (setting + * #TJFLAG_NOREALLOC guarantees this.) + * . + * If you choose option 1, dstSizes[i] should be set to + * the size of your pre-allocated buffer. In any case, unless you have + * set #TJFLAG_NOREALLOC, you should always check dstBufs[i] + * upon return from this function, as it may have changed. + * @param dstSizes pointer to an array of n unsigned long variables that will + * receive the actual sizes (in bytes) of each transformed JPEG image. + * If dstBufs[i] points to a pre-allocated buffer, then + * dstSizes[i] should be set to the size of the buffer. Upon + * return, dstSizes[i] will contain the size of the JPEG image + * (in bytes.) + * @param transforms pointer to an array of n tjtransform structures, each of + * which specifies the transform parameters and/or cropping region for + * the corresponding transformed output image. + * @param flags the bitwise OR of one or more of the @ref TJFLAG_BOTTOMUP + * "flags". + * + * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().) + */ +DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf, + unsigned long jpegSize, int n, unsigned char **dstBufs, + unsigned long *dstSizes, tjtransform *transforms, int flags); + + +/** + * Destroy a TurboJPEG compressor, decompressor, or transformer instance. + * + * @param handle a handle to a TurboJPEG compressor, decompressor or + * transformer instance + * + * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().) + */ +DLLEXPORT int DLLCALL tjDestroy(tjhandle handle); + + +/** + * Allocate an image buffer for use with TurboJPEG. You should always use + * this function to allocate the JPEG destination buffer(s) for #tjCompress2() + * and #tjTransform() unless you are disabling automatic buffer + * (re)allocation (by setting #TJFLAG_NOREALLOC.) + * + * @param bytes the number of bytes to allocate + * + * @return a pointer to a newly-allocated buffer with the specified number of + * bytes + * + * @sa tjFree() + */ +DLLEXPORT unsigned char* DLLCALL tjAlloc(int bytes); + + +/** + * Free an image buffer previously allocated by TurboJPEG. You should always + * use this function to free JPEG destination buffer(s) that were automatically + * (re)allocated by #tjCompress2() or #tjTransform() or that were manually + * allocated using #tjAlloc(). + * + * @param buffer address of the buffer to free + * + * @sa tjAlloc() + */ +DLLEXPORT void DLLCALL tjFree(unsigned char *buffer); + + +/** + * Returns a descriptive error message explaining why the last command failed. + * + * @return a descriptive error message explaining why the last command failed. + */ +DLLEXPORT char* DLLCALL tjGetErrorStr(void); + + +/* Backward compatibility functions and macros (nothing to see here) */ +#define NUMSUBOPT TJ_NUMSAMP +#define TJ_444 TJSAMP_444 +#define TJ_422 TJSAMP_422 +#define TJ_420 TJSAMP_420 +#define TJ_411 TJSAMP_420 +#define TJ_GRAYSCALE TJSAMP_GRAY + +#define TJ_BGR 1 +#define TJ_BOTTOMUP TJFLAG_BOTTOMUP +#define TJ_FORCEMMX TJFLAG_FORCEMMX +#define TJ_FORCESSE TJFLAG_FORCESSE +#define TJ_FORCESSE2 TJFLAG_FORCESSE2 +#define TJ_ALPHAFIRST 64 +#define TJ_FORCESSE3 TJFLAG_FORCESSE3 +#define TJ_FASTUPSAMPLE TJFLAG_FASTUPSAMPLE +#define TJ_YUV 512 + +DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height); + +DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height, + int jpegSubsamp); + +DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf, + int width, int pitch, int height, int pixelSize, unsigned char *dstBuf, + unsigned long *compressedSize, int jpegSubsamp, int jpegQual, int flags); + +DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, + unsigned char *srcBuf, int width, int pitch, int height, int pixelSize, + unsigned char *dstBuf, int subsamp, int flags); + +DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle, + unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height); + +DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, + unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf, + int width, int pitch, int height, int pixelSize, int flags); + + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/turbojpeg/jconfig.h b/duix-sdk/src/main/cpp/third/arm/include/turbojpeg/jconfig.h new file mode 100644 index 0000000..1c68fee --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/turbojpeg/jconfig.h @@ -0,0 +1,60 @@ +/* Version ID for the JPEG library. + * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60". + */ +#define JPEG_LIB_VERSION 62 + +/* libjpeg-turbo version */ +#define LIBJPEG_TURBO_VERSION 3.0.1 + +/* libjpeg-turbo version in integer form */ +#define LIBJPEG_TURBO_VERSION_NUMBER 3000001 + +/* Support arithmetic encoding when using 8-bit samples */ +#define C_ARITH_CODING_SUPPORTED 1 + +/* Support arithmetic decoding when using 8-bit samples */ +#define D_ARITH_CODING_SUPPORTED 1 + +/* Support in-memory source/destination managers */ +#define MEM_SRCDST_SUPPORTED 1 + +/* Use accelerated SIMD routines when using 8-bit samples */ +#define WITH_SIMD 1 + +/* This version of libjpeg-turbo supports run-time selection of data precision, + * so BITS_IN_JSAMPLE is no longer used to specify the data precision at build + * time. However, some downstream software expects the macro to be defined. + * Since 12-bit data precision is an opt-in feature that requires explicitly + * calling 12-bit-specific libjpeg API functions and using 12-bit-specific data + * types, the unmodified portion of the libjpeg API still behaves as if it were + * built for 8-bit precision, and JSAMPLE is still literally an 8-bit data + * type. Thus, it is correct to define BITS_IN_JSAMPLE to 8 here. + */ +#ifndef BITS_IN_JSAMPLE +#define BITS_IN_JSAMPLE 8 +#endif + +#ifdef _WIN32 + +#undef RIGHT_SHIFT_IS_UNSIGNED + +/* Define "boolean" as unsigned char, not int, per Windows custom */ +#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */ +typedef unsigned char boolean; +#endif +#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */ + +/* Define "INT32" as int, not long, per Windows custom */ +#if !(defined(_BASETSD_H_) || defined(_BASETSD_H)) /* don't conflict if basetsd.h already read */ +typedef short INT16; +typedef signed int INT32; +#endif +#define XMD_H /* prevent jmorecfg.h from redefining it */ + +#else + +/* Define if your (broken) compiler shifts signed values as if they were + unsigned. */ +/* #undef RIGHT_SHIFT_IS_UNSIGNED */ + +#endif diff --git a/duix-sdk/src/main/cpp/third/arm/include/turbojpeg/jerror.h b/duix-sdk/src/main/cpp/third/arm/include/turbojpeg/jerror.h new file mode 100644 index 0000000..39362fd --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/turbojpeg/jerror.h @@ -0,0 +1,336 @@ +/* + * jerror.h + * + * This file was part of the Independent JPEG Group's software: + * Copyright (C) 1994-1997, Thomas G. Lane. + * Modified 1997-2009 by Guido Vollbeding. + * Lossless JPEG Modifications: + * Copyright (C) 1999, Ken Murchison. + * libjpeg-turbo Modifications: + * Copyright (C) 2014, 2017, 2021-2022, D. R. Commander. + * For conditions of distribution and use, see the accompanying README.ijg + * file. + * + * This file defines the error and message codes for the JPEG library. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + * A set of error-reporting macros are defined too. Some applications using + * the JPEG library may wish to include this file to get the error codes + * and/or the macros. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef JERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code, string) +#endif /* JERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code, string) code, + +#endif /* JMAKE_ENUM_LIST */ + +JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */ + +/* For maintenance convenience, list is alphabetical by message code name */ +#if JPEG_LIB_VERSION < 70 +JMESSAGE(JERR_ARITH_NOTIMPL, "Sorry, arithmetic coding is not implemented") +#endif +JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix") +JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") +JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") +JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") +#if JPEG_LIB_VERSION >= 70 +JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request") +#endif +JMESSAGE(JERR_BAD_DCT_COEF, + "DCT coefficient (lossy) or spatial difference (lossless) out of range") +JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported") +#if JPEG_LIB_VERSION >= 70 +JMESSAGE(JERR_BAD_DROP_SAMPLING, + "Component index %d: mismatching sampling ratio %d:%d, %d:%d, %c") +#endif +JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition") +JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace") +JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace") +JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length") +JMESSAGE(JERR_BAD_LIB_VERSION, + "Wrong JPEG library version: library is %d, caller expects %d") +JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan") +JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d") +JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d") +JMESSAGE(JERR_BAD_PROGRESSION, + "Invalid progressive/lossless parameters Ss=%d Se=%d Ah=%d Al=%d") +JMESSAGE(JERR_BAD_PROG_SCRIPT, + "Invalid progressive/lossless parameters at scan script entry %d") +JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors") +JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d") +JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d") +JMESSAGE(JERR_BAD_STRUCT_SIZE, + "JPEG parameter struct mismatch: library thinks size is %u, caller expects %u") +JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access") +JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small") +JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here") +JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet") +JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d") +JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request") +JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d") +JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x") +JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d") +JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d") +JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)") +JMESSAGE(JERR_EMS_READ, "Read from EMS failed") +JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed") +JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan") +JMESSAGE(JERR_FILE_READ, "Input file read error") +JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?") +JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet") +JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow") +JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry") +JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels") +JMESSAGE(JERR_INPUT_EMPTY, "Empty input file") +JMESSAGE(JERR_INPUT_EOF, "Premature end of input file") +JMESSAGE(JERR_MISMATCHED_QUANT_TABLE, + "Cannot transcode due to multiple use of quantization table %d") +JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data") +JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change") +JMESSAGE(JERR_NOTIMPL, "Requested features are incompatible") +JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time") +#if JPEG_LIB_VERSION >= 70 +JMESSAGE(JERR_NO_ARITH_TABLE, "Arithmetic table 0x%02x was not defined") +#endif +JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported") +JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined") +JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image") +JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined") +JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x") +JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)") +JMESSAGE(JERR_QUANT_COMPONENTS, + "Cannot quantize more than %d color components") +JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors") +JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors") +JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers") +JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker") +JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x") +JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers") +JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF") +JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s") +JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file") +JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file") +JMESSAGE(JERR_TFILE_WRITE, + "Write failed on temporary file --- out of disk space?") +JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines") +JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x") +JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up") +JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation") +JMESSAGE(JERR_XMS_READ, "Read from XMS failed") +JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed") +JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT_SHORT) +JMESSAGE(JMSG_VERSION, JVERSION) +JMESSAGE(JTRC_16BIT_TABLES, + "Caution: quantization tables are too coarse for baseline JPEG") +JMESSAGE(JTRC_ADOBE, + "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d") +JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u") +JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u") +JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x") +JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x") +JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d") +JMESSAGE(JTRC_DRI, "Define Restart Interval %u") +JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u") +JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u") +JMESSAGE(JTRC_EOI, "End Of Image") +JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d") +JMESSAGE(JTRC_JFIF, "JFIF APP0 marker: version %d.%02d, density %dx%d %d") +JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE, + "Warning: thumbnail image size does not match data length %u") +JMESSAGE(JTRC_JFIF_EXTENSION, "JFIF extension marker: type 0x%02x, length %u") +JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image") +JMESSAGE(JTRC_MISC_MARKER, "Miscellaneous marker 0x%02x, length %u") +JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x") +JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u") +JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors") +JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors") +JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization") +JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d") +JMESSAGE(JTRC_RST, "RST%d") +JMESSAGE(JTRC_SMOOTH_NOTIMPL, + "Smoothing not supported with nonstandard sampling ratios") +JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d") +JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d") +JMESSAGE(JTRC_SOI, "Start of Image") +JMESSAGE(JTRC_SOS, "Start Of Scan: %d components") +JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d") +JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d") +JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s") +JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s") +JMESSAGE(JTRC_THUMB_JPEG, + "JFIF extension marker: JPEG-compressed thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_PALETTE, + "JFIF extension marker: palette thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_RGB, + "JFIF extension marker: RGB thumbnail image, length %u") +JMESSAGE(JTRC_UNKNOWN_IDS, + "Unrecognized component IDs %d %d %d, assuming YCbCr (lossy) or RGB (lossless)") +JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u") +JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u") +JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d") +#if JPEG_LIB_VERSION >= 70 +JMESSAGE(JWRN_ARITH_BAD_CODE, "Corrupt JPEG data: bad arithmetic code") +#endif +JMESSAGE(JWRN_BOGUS_PROGRESSION, + "Inconsistent progression sequence for component %d coefficient %d") +JMESSAGE(JWRN_EXTRANEOUS_DATA, + "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x") +JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment") +JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code") +JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d") +JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file") +JMESSAGE(JWRN_MUST_RESYNC, + "Corrupt JPEG data: found marker 0x%02x instead of RST%d") +JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG") +JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines") +#if JPEG_LIB_VERSION < 70 +JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request") +#if defined(C_ARITH_CODING_SUPPORTED) || defined(D_ARITH_CODING_SUPPORTED) +JMESSAGE(JERR_NO_ARITH_TABLE, "Arithmetic table 0x%02x was not defined") +JMESSAGE(JWRN_ARITH_BAD_CODE, "Corrupt JPEG data: bad arithmetic code") +#endif +#endif +JMESSAGE(JWRN_BOGUS_ICC, "Corrupt JPEG data: bad ICC marker") +#if JPEG_LIB_VERSION < 70 +JMESSAGE(JERR_BAD_DROP_SAMPLING, + "Component index %d: mismatching sampling ratio %d:%d, %d:%d, %c") +#endif +JMESSAGE(JERR_BAD_RESTART, + "Invalid restart interval %d; must be an integer multiple of the number of MCUs in an MCU row (%d)") + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTMSGCODE +} J_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE + + +#ifndef JERROR_H +#define JERROR_H + +/* Macros to simplify using the error and trace message stuff */ +/* The first parameter is either type of cinfo pointer */ + +/* Fatal errors (print message and exit) */ +#define ERREXIT(cinfo, code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->error_exit) ((j_common_ptr)(cinfo))) +#define ERREXIT1(cinfo, code, p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->error_exit) ((j_common_ptr)(cinfo))) +#define ERREXIT2(cinfo, code, p1, p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->error_exit) ((j_common_ptr)(cinfo))) +#define ERREXIT3(cinfo, code, p1, p2, p3) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (*(cinfo)->err->error_exit) ((j_common_ptr)(cinfo))) +#define ERREXIT4(cinfo, code, p1, p2, p3, p4) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (cinfo)->err->msg_parm.i[3] = (p4), \ + (*(cinfo)->err->error_exit) ((j_common_ptr)(cinfo))) +#define ERREXIT6(cinfo, code, p1, p2, p3, p4, p5, p6) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (cinfo)->err->msg_parm.i[3] = (p4), \ + (cinfo)->err->msg_parm.i[4] = (p5), \ + (cinfo)->err->msg_parm.i[5] = (p6), \ + (*(cinfo)->err->error_exit) ((j_common_ptr)(cinfo))) +#define ERREXITS(cinfo, code, str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (cinfo)->err->msg_parm.s[JMSG_STR_PARM_MAX - 1] = '\0', \ + (*(cinfo)->err->error_exit) ((j_common_ptr)(cinfo))) + +#define MAKESTMT(stuff) do { stuff } while (0) + +/* Nonfatal errors (we can keep going, but the data is probably corrupt) */ +#define WARNMS(cinfo, code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr)(cinfo), -1)) +#define WARNMS1(cinfo, code, p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr)(cinfo), -1)) +#define WARNMS2(cinfo, code, p1, p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr)(cinfo), -1)) + +/* Informational/debugging messages */ +#define TRACEMS(cinfo, lvl, code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr)(cinfo), (lvl))) +#define TRACEMS1(cinfo, lvl, code, p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr)(cinfo), (lvl))) +#define TRACEMS2(cinfo, lvl, code, p1, p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr)(cinfo), (lvl))) +#define TRACEMS3(cinfo, lvl, code, p1, p2, p3) \ + MAKESTMT(int *_mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr)(cinfo), (lvl)); ) +#define TRACEMS4(cinfo, lvl, code, p1, p2, p3, p4) \ + MAKESTMT(int *_mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr)(cinfo), (lvl)); ) +#define TRACEMS5(cinfo, lvl, code, p1, p2, p3, p4, p5) \ + MAKESTMT(int *_mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr)(cinfo), (lvl)); ) +#define TRACEMS8(cinfo, lvl, code, p1, p2, p3, p4, p5, p6, p7, p8) \ + MAKESTMT(int *_mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr)(cinfo), (lvl)); ) +#define TRACEMSS(cinfo, lvl, code, str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (cinfo)->err->msg_parm.s[JMSG_STR_PARM_MAX - 1] = '\0', \ + (*(cinfo)->err->emit_message) ((j_common_ptr)(cinfo), (lvl))) + +#endif /* JERROR_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/turbojpeg/jmorecfg.h b/duix-sdk/src/main/cpp/third/arm/include/turbojpeg/jmorecfg.h new file mode 100644 index 0000000..89c7842 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/turbojpeg/jmorecfg.h @@ -0,0 +1,385 @@ +/* + * jmorecfg.h + * + * This file was part of the Independent JPEG Group's software: + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 1997-2009 by Guido Vollbeding. + * Lossless JPEG Modifications: + * Copyright (C) 1999, Ken Murchison. + * libjpeg-turbo Modifications: + * Copyright (C) 2009, 2011, 2014-2015, 2018, 2020, 2022, D. R. Commander. + * For conditions of distribution and use, see the accompanying README.ijg + * file. + * + * This file contains additional configuration options that customize the + * JPEG software for special applications or support machine-dependent + * optimizations. Most users will not need to touch this file. + */ + + +/* + * Maximum number of components (color channels) allowed in JPEG image. + * To meet the letter of Rec. ITU-T T.81 | ISO/IEC 10918-1, set this to 255. + * However, darn few applications need more than 4 channels (maybe 5 for CMYK + + * alpha mask). We recommend 10 as a reasonable compromise; use 4 if you are + * really short on memory. (Each allowed component costs a hundred or so + * bytes of storage, whether actually used in an image or not.) + */ + +#define MAX_COMPONENTS 10 /* maximum number of image components */ + + +/* + * Basic data types. + * You may need to change these if you have a machine with unusual data + * type sizes; for example, "char" not 8 bits, "short" not 16 bits, + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + * but it had better be at least 16. + */ + +/* Representation of a single sample (pixel element value). + * We frequently allocate large arrays of these, so it's important to keep + * them small. But if you have memory to burn and access to char or short + * arrays is very slow on your hardware, you might want to change these. + */ + +/* JSAMPLE should be the smallest type that will hold the values 0..255. */ + +typedef unsigned char JSAMPLE; +#define GETJSAMPLE(value) ((int)(value)) + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 + + +/* J12SAMPLE should be the smallest type that will hold the values 0..4095. */ + +typedef short J12SAMPLE; + +#define MAXJ12SAMPLE 4095 +#define CENTERJ12SAMPLE 2048 + + +/* J16SAMPLE should be the smallest type that will hold the values 0..65535. */ + +typedef unsigned short J16SAMPLE; + +#define MAXJ16SAMPLE 65535 +#define CENTERJ16SAMPLE 32768 + + +/* Representation of a DCT frequency coefficient. + * This should be a signed value of at least 16 bits; "short" is usually OK. + * Again, we allocate large arrays of these, but you can change to int + * if you have memory to burn and "short" is really slow. + */ + +typedef short JCOEF; + + +/* Compressed datastreams are represented as arrays of JOCTET. + * These must be EXACTLY 8 bits wide, at least once they are written to + * external storage. Note that when using the stdio data source/destination + * managers, this is also the data type passed to fread/fwrite. + */ + +typedef unsigned char JOCTET; +#define GETJOCTET(value) (value) + + +/* These typedefs are used for various table entries and so forth. + * They must be at least as wide as specified; but making them too big + * won't cost a huge amount of memory, so we don't provide special + * extraction code like we did for JSAMPLE. (In other words, these + * typedefs live at a different point on the speed/space tradeoff curve.) + */ + +/* UINT8 must hold at least the values 0..255. */ + +typedef unsigned char UINT8; + +/* UINT16 must hold at least the values 0..65535. */ + +typedef unsigned short UINT16; + +/* INT16 must hold at least the values -32768..32767. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ +typedef short INT16; +#endif + +/* INT32 must hold at least signed 32-bit values. + * + * NOTE: The INT32 typedef dates back to libjpeg v5 (1994.) Integers were + * sometimes 16-bit back then (MS-DOS), which is why INT32 is typedef'd to + * long. It also wasn't common (or at least as common) in 1994 for INT32 to be + * defined by platform headers. Since then, however, INT32 is defined in + * several other common places: + * + * Xmd.h (X11 header) typedefs INT32 to int on 64-bit platforms and long on + * 32-bit platforms (i.e always a 32-bit signed type.) + * + * basetsd.h (Win32 header) typedefs INT32 to int (always a 32-bit signed type + * on modern platforms.) + * + * qglobal.h (Qt header) typedefs INT32 to int (always a 32-bit signed type on + * modern platforms.) + * + * This is a recipe for conflict, since "long" and "int" aren't always + * compatible types. Since the definition of INT32 has technically been part + * of the libjpeg API for more than 20 years, we can't remove it, but we do not + * use it internally any longer. We instead define a separate type (JLONG) + * for internal use, which ensures that internal behavior will always be the + * same regardless of any external headers that may be included. + */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ +#ifndef _BASETSD_H_ /* Microsoft defines it in basetsd.h */ +#ifndef _BASETSD_H /* MinGW is slightly different */ +#ifndef QGLOBAL_H /* Qt defines it in qglobal.h */ +typedef long INT32; +#endif +#endif +#endif +#endif + +/* Datatype used for image dimensions. The JPEG standard only supports + * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore + * "unsigned int" is sufficient on all machines. However, if you need to + * handle larger images and you don't mind deviating from the spec, you + * can change this datatype. (Note that changing this datatype will + * potentially require modifying the SIMD code. The x86-64 SIMD extensions, + * in particular, assume a 32-bit JDIMENSION.) + */ + +typedef unsigned int JDIMENSION; + +#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ + + +/* These macros are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions; + * in particular, you'll need to do that to make the library a Windows DLL. + * Another application is to make all functions global for use with debuggers + * or code profilers that require it. + */ + +/* a function called through method pointers: */ +#define METHODDEF(type) static type +/* a function used only in its module: */ +#define LOCAL(type) static type +/* a function referenced thru EXTERNs: */ +#define GLOBAL(type) type +/* a reference to a GLOBAL function: */ +#define EXTERN(type) extern type + + +/* Originally, this macro was used as a way of defining function prototypes + * for both modern compilers as well as older compilers that did not support + * prototype parameters. libjpeg-turbo has never supported these older, + * non-ANSI compilers, but the macro is still included because there is some + * software out there that uses it. + */ + +#define JMETHOD(type, methodname, arglist) type (*methodname) arglist + + +/* libjpeg-turbo no longer supports platforms that have far symbols (MS-DOS), + * but again, some software relies on this macro. + */ + +#undef FAR +#define FAR + + +/* + * On a few systems, type boolean and/or its values FALSE, TRUE may appear + * in standard header files. Or you may have conflicts with application- + * specific header files that you want to include together with these files. + * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. + */ + +#ifndef HAVE_BOOLEAN +typedef int boolean; +#endif +#ifndef FALSE /* in case these macros already exist */ +#define FALSE 0 /* values of boolean */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif + + +/* + * The remaining options affect code selection within the JPEG library, + * but they don't need to be visible to most applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. + */ + +#ifdef JPEG_INTERNALS +#define JPEG_INTERNAL_OPTIONS +#endif + +#ifdef JPEG_INTERNAL_OPTIONS + + +/* + * These defines indicate whether to include various optional functions. + * Undefining some of these symbols will produce a smaller but less capable + * library. Note that you can leave certain source files out of the + * compilation/linking process if you've #undef'd the corresponding symbols. + * (You may HAVE to do that if your compiler doesn't like null source files.) + */ + +/* Capability options common to encoder and decoder: */ + +#define DCT_ISLOW_SUPPORTED /* accurate integer method */ +#define DCT_IFAST_SUPPORTED /* less accurate int method [legacy feature] */ +#define DCT_FLOAT_SUPPORTED /* floating-point method [legacy feature] */ + +/* Encoder capability options: */ + +#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define C_LOSSLESS_SUPPORTED /* Lossless JPEG? */ +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ +/* Note: if you selected 12-bit data precision, it is dangerous to turn off + * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit + * precision, so jchuff.c normally uses entropy optimization to compute + * usable tables for higher precision. If you don't want to do optimization, + * you'll have to supply different default Huffman tables. + * The exact same statements apply for progressive and lossless JPEG: + * the default tables don't work for progressive mode or lossless mode. + * (This may get fixed, however.) + */ +#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ + +/* Decoder capability options: */ + +#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define D_LOSSLESS_SUPPORTED /* Lossless JPEG? */ +#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ +#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ +#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ +#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ +#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ +#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ +#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ + +/* more capability options later, no doubt */ + + +/* + * The RGB_RED, RGB_GREEN, RGB_BLUE, and RGB_PIXELSIZE macros are a vestigial + * feature of libjpeg. The idea was that, if an application developer needed + * to compress from/decompress to a BGR/BGRX/RGBX/XBGR/XRGB buffer, they could + * change these macros, rebuild libjpeg, and link their application statically + * with it. In reality, few people ever did this, because there were some + * severe restrictions involved (cjpeg and djpeg no longer worked properly, + * compressing/decompressing RGB JPEGs no longer worked properly, and the color + * quantizer wouldn't work with pixel sizes other than 3.) Furthermore, since + * all of the O/S-supplied versions of libjpeg were built with the default + * values of RGB_RED, RGB_GREEN, RGB_BLUE, and RGB_PIXELSIZE, many applications + * have come to regard these values as immutable. + * + * The libjpeg-turbo colorspace extensions provide a much cleaner way of + * compressing from/decompressing to buffers with arbitrary component orders + * and pixel sizes. Thus, we do not support changing the values of RGB_RED, + * RGB_GREEN, RGB_BLUE, or RGB_PIXELSIZE. In addition to the restrictions + * listed above, changing these values will also break the SIMD extensions and + * the regression tests. + */ + +#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ +#define RGB_GREEN 1 /* Offset of Green */ +#define RGB_BLUE 2 /* Offset of Blue */ +#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ + +#define JPEG_NUMCS 17 + +#define EXT_RGB_RED 0 +#define EXT_RGB_GREEN 1 +#define EXT_RGB_BLUE 2 +#define EXT_RGB_PIXELSIZE 3 + +#define EXT_RGBX_RED 0 +#define EXT_RGBX_GREEN 1 +#define EXT_RGBX_BLUE 2 +#define EXT_RGBX_PIXELSIZE 4 + +#define EXT_BGR_RED 2 +#define EXT_BGR_GREEN 1 +#define EXT_BGR_BLUE 0 +#define EXT_BGR_PIXELSIZE 3 + +#define EXT_BGRX_RED 2 +#define EXT_BGRX_GREEN 1 +#define EXT_BGRX_BLUE 0 +#define EXT_BGRX_PIXELSIZE 4 + +#define EXT_XBGR_RED 3 +#define EXT_XBGR_GREEN 2 +#define EXT_XBGR_BLUE 1 +#define EXT_XBGR_PIXELSIZE 4 + +#define EXT_XRGB_RED 1 +#define EXT_XRGB_GREEN 2 +#define EXT_XRGB_BLUE 3 +#define EXT_XRGB_PIXELSIZE 4 + +static const int rgb_red[JPEG_NUMCS] = { + -1, -1, RGB_RED, -1, -1, -1, EXT_RGB_RED, EXT_RGBX_RED, + EXT_BGR_RED, EXT_BGRX_RED, EXT_XBGR_RED, EXT_XRGB_RED, + EXT_RGBX_RED, EXT_BGRX_RED, EXT_XBGR_RED, EXT_XRGB_RED, + -1 +}; + +static const int rgb_green[JPEG_NUMCS] = { + -1, -1, RGB_GREEN, -1, -1, -1, EXT_RGB_GREEN, EXT_RGBX_GREEN, + EXT_BGR_GREEN, EXT_BGRX_GREEN, EXT_XBGR_GREEN, EXT_XRGB_GREEN, + EXT_RGBX_GREEN, EXT_BGRX_GREEN, EXT_XBGR_GREEN, EXT_XRGB_GREEN, + -1 +}; + +static const int rgb_blue[JPEG_NUMCS] = { + -1, -1, RGB_BLUE, -1, -1, -1, EXT_RGB_BLUE, EXT_RGBX_BLUE, + EXT_BGR_BLUE, EXT_BGRX_BLUE, EXT_XBGR_BLUE, EXT_XRGB_BLUE, + EXT_RGBX_BLUE, EXT_BGRX_BLUE, EXT_XBGR_BLUE, EXT_XRGB_BLUE, + -1 +}; + +static const int rgb_pixelsize[JPEG_NUMCS] = { + -1, -1, RGB_PIXELSIZE, -1, -1, -1, EXT_RGB_PIXELSIZE, EXT_RGBX_PIXELSIZE, + EXT_BGR_PIXELSIZE, EXT_BGRX_PIXELSIZE, EXT_XBGR_PIXELSIZE, EXT_XRGB_PIXELSIZE, + EXT_RGBX_PIXELSIZE, EXT_BGRX_PIXELSIZE, EXT_XBGR_PIXELSIZE, EXT_XRGB_PIXELSIZE, + -1 +}; + +/* Definitions for speed-related optimizations. */ + +/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying + * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER + * as short on such a machine. MULTIPLIER must be at least 16 bits wide. + */ + +#ifndef MULTIPLIER +#ifndef WITH_SIMD +#define MULTIPLIER int /* type for fastest integer multiply */ +#else +#define MULTIPLIER short /* prefer 16-bit with SIMD for parellelism */ +#endif +#endif + + +/* FAST_FLOAT should be either float or double, whichever is done faster + * by your compiler. (Note that this type is only used in the floating point + * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) + */ + +#ifndef FAST_FLOAT +#define FAST_FLOAT float +#endif + +#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/turbojpeg/jpeglib.h b/duix-sdk/src/main/cpp/third/arm/include/turbojpeg/jpeglib.h new file mode 100644 index 0000000..a59e98c --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/turbojpeg/jpeglib.h @@ -0,0 +1,1209 @@ +/* + * jpeglib.h + * + * This file was part of the Independent JPEG Group's software: + * Copyright (C) 1991-1998, Thomas G. Lane. + * Modified 2002-2009 by Guido Vollbeding. + * Lossless JPEG Modifications: + * Copyright (C) 1999, Ken Murchison. + * libjpeg-turbo Modifications: + * Copyright (C) 2009-2011, 2013-2014, 2016-2017, 2020, 2022-2023, + D. R. Commander. + * Copyright (C) 2015, Google, Inc. + * For conditions of distribution and use, see the accompanying README.ijg + * file. + * + * This file defines the application interface for the JPEG library. + * Most applications using the library need only include this file, + * and perhaps jerror.h if they want to know the exact error codes. + */ + +#ifndef JPEGLIB_H +#define JPEGLIB_H + +/* + * First we include the configuration files that record how this + * installation of the JPEG library is set up. jconfig.h can be + * generated automatically for many systems. jmorecfg.h contains + * manual configuration options that most people need not worry about. + */ + +#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ +#include "jconfig.h" /* widely used configuration options */ +#endif +#include "jmorecfg.h" /* seldom changed options */ + + +#ifdef __cplusplus +#ifndef DONT_USE_EXTERN_C +extern "C" { +#endif +#endif + + +/* Various constants determining the sizes of things. + * All of these are specified by the JPEG standard, so don't change them + * if you want to be compatible. + */ + +/* NOTE: In lossless mode, an MCU contains one or more samples rather than one + * or more 8x8 DCT blocks, so the term "data unit" is used to generically + * describe a sample in lossless mode or an 8x8 DCT block in lossy mode. To + * preserve backward API/ABI compatibility, the field and macro names retain + * the "block" terminology. + */ + +#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ +#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; + * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. + * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU + * to handle it. We even let you do this from the jconfig.h file. However, + * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe + * sometimes emits noncompliant files doesn't mean you should too. + */ +#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on data units/MCU */ +#ifndef D_MAX_BLOCKS_IN_MCU +#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on data units/MCU */ +#endif + + +/* Data structures for images (arrays of samples and of DCT coefficients). + */ + +typedef JSAMPLE *JSAMPROW; /* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + +typedef J12SAMPLE *J12SAMPROW; /* ptr to one image row of 12-bit pixel + samples. */ +typedef J12SAMPROW *J12SAMPARRAY; /* ptr to some 12-bit sample rows (a 2-D + 12-bit sample array) */ +typedef J12SAMPARRAY *J12SAMPIMAGE; /* a 3-D 12-bit sample array: top index is + color */ + +typedef J16SAMPLE *J16SAMPROW; /* ptr to one image row of 16-bit pixel + samples. */ +typedef J16SAMPROW *J16SAMPARRAY; /* ptr to some 16-bit sample rows (a 2-D + 16-bit sample array) */ +typedef J16SAMPARRAY *J16SAMPIMAGE; /* a 3-D 16-bit sample array: top index is + color */ + +typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ +typedef JBLOCK *JBLOCKROW; /* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ + +typedef JCOEF *JCOEFPTR; /* useful in a couple of places */ + + +/* Types for JPEG compression parameters and working tables. */ + + +/* DCT coefficient quantization tables. */ + +typedef struct { + /* This array gives the coefficient quantizers in natural array order + * (not the zigzag order in which they are stored in a JPEG DQT marker). + * CAUTION: IJG versions prior to v6a kept this array in zigzag order. + */ + UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JQUANT_TBL; + + +/* Huffman coding tables. */ + +typedef struct { + /* These two fields directly represent the contents of a JPEG DHT marker */ + UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + UINT8 huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JHUFF_TBL; + + +/* Basic info about one component (color channel). */ + +typedef struct { + /* These values are fixed over the whole image. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOF marker. */ + int component_id; /* identifier for this component (0..255) */ + int component_index; /* its index in SOF or cinfo->comp_info[] */ + int h_samp_factor; /* horizontal sampling factor (1..4) */ + int v_samp_factor; /* vertical sampling factor (1..4) */ + int quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOS marker. */ + /* The decompressor output side may not use these variables. */ + int dc_tbl_no; /* DC entropy table selector (0..3) */ + int ac_tbl_no; /* AC entropy table selector (0..3) */ + + /* Remaining fields should be treated as private by applications. */ + + /* These values are computed during compression or decompression startup: */ + /* Component's size in data units. + * In lossy mode, any dummy blocks added to complete an MCU are not counted; + * therefore these values do not depend on whether a scan is interleaved or + * not. In lossless mode, these are always equal to the image width and + * height. + */ + JDIMENSION width_in_blocks; + JDIMENSION height_in_blocks; + /* Size of a data unit in samples. Always DCTSIZE for lossy compression. + * For lossy decompression this is the size of the output from one DCT block, + * reflecting any scaling we choose to apply during the IDCT step. + * Values from 1 to 16 are supported. Note that different components may + * receive different IDCT scalings. In lossless mode, this is always equal + * to 1. + */ +#if JPEG_LIB_VERSION >= 70 + int DCT_h_scaled_size; + int DCT_v_scaled_size; +#else + int DCT_scaled_size; +#endif + /* The downsampled dimensions are the component's actual, unpadded number + * of samples at the main buffer (preprocessing/compression interface), thus + * downsampled_width = ceil(image_width * Hi/Hmax) + * and similarly for height. For lossy decompression, IDCT scaling is + * included, so + * downsampled_width = ceil(image_width * Hi/Hmax * DCT_[h_]scaled_size/DCTSIZE) + * In lossless mode, these are always equal to the image width and height. + */ + JDIMENSION downsampled_width; /* actual width in samples */ + JDIMENSION downsampled_height; /* actual height in samples */ + /* This flag is used only for decompression. In cases where some of the + * components will be ignored (eg grayscale output from YCbCr image), + * we can skip most computations for the unused components. + */ + boolean component_needed; /* do we need the value of this component? */ + + /* These values are computed before starting a scan of the component. */ + /* The decompressor output side may not use these variables. */ + int MCU_width; /* number of data units per MCU, horizontally */ + int MCU_height; /* number of data units per MCU, vertically */ + int MCU_blocks; /* MCU_width * MCU_height */ + int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_[h_]scaled_size */ + int last_col_width; /* # of non-dummy data units across in last MCU */ + int last_row_height; /* # of non-dummy data units down in last MCU */ + + /* Saved quantization table for component; NULL if none yet saved. + * See jdinput.c comments about the need for this information. + * This field is currently used only for decompression. + */ + JQUANT_TBL *quant_table; + + /* Private per-component storage for DCT or IDCT subsystem. */ + void *dct_table; +} jpeg_component_info; + + +/* The script for encoding a multiple-scan file is an array of these: */ + +typedef struct { + int comps_in_scan; /* number of components encoded in this scan */ + int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ + int Ss, Se; /* progressive JPEG spectral selection parms + (Ss is the predictor selection value in + lossless mode) */ + int Ah, Al; /* progressive JPEG successive approx. parms + (Al is the point transform value in lossless + mode) */ +} jpeg_scan_info; + +/* The decompressor can save APPn and COM markers in a list of these: */ + +typedef struct jpeg_marker_struct *jpeg_saved_marker_ptr; + +struct jpeg_marker_struct { + jpeg_saved_marker_ptr next; /* next in list, or NULL */ + UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ + unsigned int original_length; /* # bytes of data in the file */ + unsigned int data_length; /* # bytes of data saved at data[] */ + JOCTET *data; /* the data contained in the marker */ + /* the marker length word is not counted in data_length or original_length */ +}; + +/* Known color spaces. */ + +#define JCS_EXTENSIONS 1 +#define JCS_ALPHA_EXTENSIONS 1 + +typedef enum { + JCS_UNKNOWN, /* error/unspecified */ + JCS_GRAYSCALE, /* monochrome */ + JCS_RGB, /* red/green/blue as specified by the RGB_RED, + RGB_GREEN, RGB_BLUE, and RGB_PIXELSIZE macros */ + JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ + JCS_CMYK, /* C/M/Y/K */ + JCS_YCCK, /* Y/Cb/Cr/K */ + JCS_EXT_RGB, /* red/green/blue */ + JCS_EXT_RGBX, /* red/green/blue/x */ + JCS_EXT_BGR, /* blue/green/red */ + JCS_EXT_BGRX, /* blue/green/red/x */ + JCS_EXT_XBGR, /* x/blue/green/red */ + JCS_EXT_XRGB, /* x/red/green/blue */ + /* When out_color_space it set to JCS_EXT_RGBX, JCS_EXT_BGRX, JCS_EXT_XBGR, + or JCS_EXT_XRGB during decompression, the X byte is undefined, and in + order to ensure the best performance, libjpeg-turbo can set that byte to + whatever value it wishes. Use the following colorspace constants to + ensure that the X byte is set to 0xFF, so that it can be interpreted as an + opaque alpha channel. */ + JCS_EXT_RGBA, /* red/green/blue/alpha */ + JCS_EXT_BGRA, /* blue/green/red/alpha */ + JCS_EXT_ABGR, /* alpha/blue/green/red */ + JCS_EXT_ARGB, /* alpha/red/green/blue */ + JCS_RGB565 /* 5-bit red/6-bit green/5-bit blue + [decompression only] */ +} J_COLOR_SPACE; + +/* DCT/IDCT algorithm options. */ + +typedef enum { + JDCT_ISLOW, /* accurate integer method */ + JDCT_IFAST, /* less accurate integer method [legacy feature] */ + JDCT_FLOAT /* floating-point method [legacy feature] */ +} J_DCT_METHOD; + +#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ +#define JDCT_DEFAULT JDCT_ISLOW +#endif +#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ +#define JDCT_FASTEST JDCT_IFAST +#endif + +/* Dithering options for decompression. */ + +typedef enum { + JDITHER_NONE, /* no dithering */ + JDITHER_ORDERED, /* simple ordered dither */ + JDITHER_FS /* Floyd-Steinberg error diffusion dither */ +} J_DITHER_MODE; + + +/* Common fields between JPEG compression and decompression master structs. */ + +#define jpeg_common_fields \ + struct jpeg_error_mgr *err; /* Error handler module */ \ + struct jpeg_memory_mgr *mem; /* Memory manager module */ \ + struct jpeg_progress_mgr *progress; /* Progress monitor, or NULL if none */ \ + void *client_data; /* Available for use by application */ \ + boolean is_decompressor; /* So common code can tell which is which */ \ + int global_state /* For checking call sequence validity */ + +/* Routines that are to be used by both halves of the library are declared + * to receive a pointer to this structure. There are no actual instances of + * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. + */ +struct jpeg_common_struct { + jpeg_common_fields; /* Fields common to both master struct types */ + /* Additional fields follow in an actual jpeg_compress_struct or + * jpeg_decompress_struct. All three structs must agree on these + * initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct jpeg_common_struct *j_common_ptr; +typedef struct jpeg_compress_struct *j_compress_ptr; +typedef struct jpeg_decompress_struct *j_decompress_ptr; + + +/* Master record for a compression instance */ + +struct jpeg_compress_struct { + jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ + + /* Destination for compressed data */ + struct jpeg_destination_mgr *dest; + + /* Description of source image --- these fields must be filled in by + * outer application before starting compression. in_color_space must + * be correct before you can even call jpeg_set_defaults(). + */ + + JDIMENSION image_width; /* input image width */ + JDIMENSION image_height; /* input image height */ + int input_components; /* # of color components in input image */ + J_COLOR_SPACE in_color_space; /* colorspace of input image */ + + double input_gamma; /* image gamma of input image */ + + /* Compression parameters --- these fields must be set before calling + * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to + * initialize everything to reasonable defaults, then changing anything + * the application specifically wants to change. That way you won't get + * burnt when new parameters are added. Also note that there are several + * helper routines to simplify changing parameters. + */ + +#if JPEG_LIB_VERSION >= 70 + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + JDIMENSION jpeg_width; /* scaled JPEG image width */ + JDIMENSION jpeg_height; /* scaled JPEG image height */ + /* Dimensions of actual JPEG image that will be written to file, + * derived from input dimensions by scaling factors above. + * These fields are computed by jpeg_start_compress(). + * You can also use jpeg_calc_jpeg_dimensions() to determine these values + * in advance of calling jpeg_start_compress(). + */ +#endif + + int data_precision; /* bits of precision in image data */ + + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + jpeg_component_info *comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + JQUANT_TBL *quant_tbl_ptrs[NUM_QUANT_TBLS]; +#if JPEG_LIB_VERSION >= 70 + int q_scale_factor[NUM_QUANT_TBLS]; +#endif + /* ptrs to coefficient quantization tables, or NULL if not defined, + * and corresponding scale factors (percentage, initialized 100). + */ + + JHUFF_TBL *dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL *ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + int num_scans; /* # of entries in scan_info array */ + const jpeg_scan_info *scan_info; /* script for multi-scan file, or NULL */ + /* The default value of scan_info is NULL, which causes a single-scan + * sequential JPEG file to be emitted. To create a multi-scan file, + * set num_scans and scan_info to point to an array of scan definitions. + */ + + boolean raw_data_in; /* TRUE=caller supplies downsampled data */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ +#if JPEG_LIB_VERSION >= 70 + boolean do_fancy_downsampling; /* TRUE=apply fancy downsampling */ +#endif + int smoothing_factor; /* 1..100, or 0 for no input smoothing */ + J_DCT_METHOD dct_method; /* DCT algorithm selector */ + + /* The restart interval can be specified in absolute MCUs by setting + * restart_interval, or in MCU rows by setting restart_in_rows + * (in which case the correct restart_interval will be figured + * for each scan). + */ + unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ + int restart_in_rows; /* if > 0, MCU rows per restart interval */ + + /* Parameters controlling emission of special markers. */ + + boolean write_JFIF_header; /* should a JFIF marker be written? */ + UINT8 JFIF_major_version; /* What to write for the JFIF version number */ + UINT8 JFIF_minor_version; + /* These three values are not used by the JPEG code, merely copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean write_Adobe_marker; /* should an Adobe marker be written? */ + + /* State variable: index of next scanline to be written to + * jpeg_write_scanlines(). Application may use this to control its + * processing loop, e.g., "while (next_scanline < image_height)". + */ + + JDIMENSION next_scanline; /* 0 .. image_height-1 */ + + /* Remaining fields are known throughout compressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during compression startup + */ + boolean progressive_mode; /* TRUE if scan script uses progressive mode */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + +#if JPEG_LIB_VERSION >= 70 + int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */ + int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */ +#endif + + JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coefficient or + difference controller */ + /* The coefficient or difference controller receives data in units of MCU + * rows as defined for fully interleaved scans (whether the JPEG file is + * interleaved or not). In lossy mode, there are v_samp_factor * DCTSIZE + * sample rows of each component in an "iMCU" (interleaved MCU) row. In + * lossless mode, total_iMCU_rows is always equal to the image height. + */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info *cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of data units per MCU */ + int MCU_membership[C_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th data unit in an MCU */ + + int Ss, Se, Ah, Al; /* progressive/lossless JPEG parameters for + scan */ + +#if JPEG_LIB_VERSION >= 80 + int block_size; /* the basic DCT block size: 1..16 */ + const int *natural_order; /* natural-order position array */ + int lim_Se; /* min( Se, DCTSIZE2-1 ) */ +#endif + + /* + * Links to compression subobjects (methods and private variables of modules) + */ + struct jpeg_comp_master *master; + struct jpeg_c_main_controller *main; + struct jpeg_c_prep_controller *prep; + struct jpeg_c_coef_controller *coef; + struct jpeg_marker_writer *marker; + struct jpeg_color_converter *cconvert; + struct jpeg_downsampler *downsample; + struct jpeg_forward_dct *fdct; + struct jpeg_entropy_encoder *entropy; + jpeg_scan_info *script_space; /* workspace for jpeg_simple_progression */ + int script_space_size; +}; + + +/* Master record for a decompression instance */ + +struct jpeg_decompress_struct { + jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ + + /* Source of compressed data */ + struct jpeg_source_mgr *src; + + /* Basic description of image --- filled in by jpeg_read_header(). */ + /* Application may inspect these values to decide how to process image. */ + + JDIMENSION image_width; /* nominal image width (from SOF marker) */ + JDIMENSION image_height; /* nominal image height */ + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + /* Decompression processing parameters --- these fields must be set before + * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes + * them to default values. + */ + + J_COLOR_SPACE out_color_space; /* colorspace for output */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + double output_gamma; /* image gamma wanted in output */ + + boolean buffered_image; /* TRUE=multiple output passes */ + boolean raw_data_out; /* TRUE=downsampled data wanted */ + + J_DCT_METHOD dct_method; /* IDCT algorithm selector */ + boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ + boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ + + boolean quantize_colors; /* TRUE=colormapped output wanted */ + /* the following are ignored if not quantize_colors: */ + J_DITHER_MODE dither_mode; /* type of color dithering to use */ + boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ + int desired_number_of_colors; /* max # colors to use in created colormap */ + /* these are significant only in buffered-image mode: */ + boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ + boolean enable_external_quant;/* enable future use of external colormap */ + boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ + + /* Description of actual output image that will be returned to application. + * These fields are computed by jpeg_start_decompress(). + * You can also use jpeg_calc_output_dimensions() to determine these values + * in advance of calling jpeg_start_decompress(). + */ + + JDIMENSION output_width; /* scaled image width */ + JDIMENSION output_height; /* scaled image height */ + int out_color_components; /* # of color components in out_color_space */ + int output_components; /* # of color components returned */ + /* output_components is 1 (a colormap index) when quantizing colors; + * otherwise it equals out_color_components. + */ + int rec_outbuf_height; /* min recommended height of scanline buffer */ + /* If the buffer passed to jpeg_read_scanlines() is less than this many rows + * high, space and time will be wasted due to unnecessary data copying. + * Usually rec_outbuf_height will be 1 or 2, at most 4. + */ + + /* When quantizing colors, the output colormap is described by these fields. + * The application can supply a colormap by setting colormap non-NULL before + * calling jpeg_start_decompress; otherwise a colormap is created during + * jpeg_start_decompress or jpeg_start_output. + * The map has out_color_components rows and actual_number_of_colors columns. + */ + int actual_number_of_colors; /* number of entries in use */ + JSAMPARRAY colormap; /* The color map as a 2-D pixel array + If data_precision is 12 or 16, then this is + actually a J12SAMPARRAY or a J16SAMPARRAY, + so callers must type-cast it in order to + read/write 12-bit or 16-bit samples from/to + the array. */ + + /* State variables: these variables indicate the progress of decompression. + * The application may examine these but must not modify them. + */ + + /* Row index of next scanline to be read from jpeg_read_scanlines(). + * Application may use this to control its processing loop, e.g., + * "while (output_scanline < output_height)". + */ + JDIMENSION output_scanline; /* 0 .. output_height-1 */ + + /* Current input scan number and number of iMCU rows completed in scan. + * These indicate the progress of the decompressor input side. + */ + int input_scan_number; /* Number of SOS markers seen so far */ + JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ + + /* The "output scan number" is the notional scan being displayed by the + * output side. The decompressor will not allow output scan/row number + * to get ahead of input scan/row, but it can fall arbitrarily far behind. + */ + int output_scan_number; /* Nominal scan number being displayed */ + JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ + + /* Current progression status. coef_bits[c][i] indicates the precision + * with which component c's DCT coefficient i (in zigzag order) is known. + * It is -1 when no data has yet been received, otherwise it is the point + * transform (shift) value for the most recent scan of the coefficient + * (thus, 0 at completion of the progression). + * This pointer is NULL when reading a non-progressive file. + */ + int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ + + /* Internal JPEG parameters --- the application usually need not look at + * these fields. Note that the decompressor output side may not use + * any parameters that can change between scans. + */ + + /* Quantization and Huffman tables are carried forward across input + * datastreams when processing abbreviated JPEG datastreams. + */ + + JQUANT_TBL *quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL *dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL *ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + /* These parameters are never carried across datastreams, since they + * are given in SOF/SOS markers or defined to be reset by SOI. + */ + + int data_precision; /* bits of precision in image data */ + + jpeg_component_info *comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + +#if JPEG_LIB_VERSION >= 80 + boolean is_baseline; /* TRUE if Baseline SOF0 encountered */ +#endif + boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ + + /* These fields record data obtained from optional markers recognized by + * the JPEG library. + */ + boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ + /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ + UINT8 JFIF_major_version; /* JFIF version number */ + UINT8 JFIF_minor_version; + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ + UINT8 Adobe_transform; /* Color transform code from Adobe marker */ + + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + /* Aside from the specific data retained from APPn markers known to the + * library, the uninterpreted contents of any or all APPn and COM markers + * can be saved in a list for examination by the application. + */ + jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ + + /* Remaining fields are known throughout decompressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during decompression startup + */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + +#if JPEG_LIB_VERSION >= 70 + int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */ + int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */ +#else + int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */ +#endif + + JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ + /* The coefficient or difference controller's input and output progress is + * measured in units of "iMCU" (interleaved MCU) rows. These are the same as + * MCU rows in fully interleaved JPEG scans, but are used whether the scan is + * interleaved or not. In lossy mode, we define an iMCU row as v_samp_factor + * DCT block rows of each component. Therefore, the IDCT output contains + * v_samp_factor*DCT_[v_]scaled_size sample rows of a component per iMCU row. + * In lossless mode, total_iMCU_rows is always equal to the image height. + */ + + JSAMPLE *sample_range_limit; /* table for fast range-limiting + If data_precision is 12 or 16, then this is + actually a J12SAMPLE pointer or a J16SAMPLE + pointer, so callers must type-cast it in + order to read 12-bit or 16-bit samples from + the array. */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + * Note that the decompressor output side must not use these fields. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info *cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of data units per MCU */ + int MCU_membership[D_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th data unit in an MCU */ + + int Ss, Se, Ah, Al; /* progressive/lossless JPEG parameters for + scan */ + +#if JPEG_LIB_VERSION >= 80 + /* These fields are derived from Se of first SOS marker. + */ + int block_size; /* the basic DCT block size: 1..16 */ + const int *natural_order; /* natural-order position array for entropy decode */ + int lim_Se; /* min( Se, DCTSIZE2-1 ) for entropy decode */ +#endif + + /* This field is shared between entropy decoder and marker parser. + * It is either zero or the code of a JPEG marker that has been + * read from the data source, but has not yet been processed. + */ + int unread_marker; + + /* + * Links to decompression subobjects (methods, private variables of modules) + */ + struct jpeg_decomp_master *master; + struct jpeg_d_main_controller *main; + struct jpeg_d_coef_controller *coef; + struct jpeg_d_post_controller *post; + struct jpeg_input_controller *inputctl; + struct jpeg_marker_reader *marker; + struct jpeg_entropy_decoder *entropy; + struct jpeg_inverse_dct *idct; + struct jpeg_upsampler *upsample; + struct jpeg_color_deconverter *cconvert; + struct jpeg_color_quantizer *cquantize; +}; + + +/* "Object" declarations for JPEG modules that may be supplied or called + * directly by the surrounding application. + * As with all objects in the JPEG library, these structs only define the + * publicly visible methods and state variables of a module. Additional + * private fields may exist after the public ones. + */ + + +/* Error handler object */ + +struct jpeg_error_mgr { + /* Error exit handler: does not return to caller */ + void (*error_exit) (j_common_ptr cinfo); + /* Conditionally emit a trace or warning message */ + void (*emit_message) (j_common_ptr cinfo, int msg_level); + /* Routine that actually outputs a trace or error message */ + void (*output_message) (j_common_ptr cinfo); + /* Format a message string for the most recent JPEG error or message */ + void (*format_message) (j_common_ptr cinfo, char *buffer); +#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ + /* Reset error state variables at start of a new image */ + void (*reset_error_mgr) (j_common_ptr cinfo); + + /* The message ID code and any parameters are saved here. + * A message can have one string parameter or up to 8 int parameters. + */ + int msg_code; +#define JMSG_STR_PARM_MAX 80 + union { + int i[8]; + char s[JMSG_STR_PARM_MAX]; + } msg_parm; + + /* Standard state variables for error facility */ + + int trace_level; /* max msg_level that will be displayed */ + + /* For recoverable corrupt-data errors, we emit a warning message, + * but keep going unless emit_message chooses to abort. emit_message + * should count warnings in num_warnings. The surrounding application + * can check for bad data by seeing if num_warnings is nonzero at the + * end of processing. + */ + long num_warnings; /* number of corrupt-data warnings */ + + /* These fields point to the table(s) of error message strings. + * An application can change the table pointer to switch to a different + * message list (typically, to change the language in which errors are + * reported). Some applications may wish to add additional error codes + * that will be handled by the JPEG library error mechanism; the second + * table pointer is used for this purpose. + * + * First table includes all errors generated by JPEG library itself. + * Error code 0 is reserved for a "no such error string" message. + */ + const char * const *jpeg_message_table; /* Library errors */ + int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ + /* Second table can be added by application (see cjpeg/djpeg for example). + * It contains strings numbered first_addon_message..last_addon_message. + */ + const char * const *addon_message_table; /* Non-library errors */ + int first_addon_message; /* code for first string in addon table */ + int last_addon_message; /* code for last string in addon table */ +}; + + +/* Progress monitor object */ + +struct jpeg_progress_mgr { + void (*progress_monitor) (j_common_ptr cinfo); + + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +}; + + +/* Data destination object for compression */ + +struct jpeg_destination_mgr { + JOCTET *next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + + void (*init_destination) (j_compress_ptr cinfo); + boolean (*empty_output_buffer) (j_compress_ptr cinfo); + void (*term_destination) (j_compress_ptr cinfo); +}; + + +/* Data source object for decompression */ + +struct jpeg_source_mgr { + const JOCTET *next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + + void (*init_source) (j_decompress_ptr cinfo); + boolean (*fill_input_buffer) (j_decompress_ptr cinfo); + void (*skip_input_data) (j_decompress_ptr cinfo, long num_bytes); + boolean (*resync_to_restart) (j_decompress_ptr cinfo, int desired); + void (*term_source) (j_decompress_ptr cinfo); +}; + + +/* Memory manager object. + * Allocates "small" objects (a few K total), "large" objects (tens of K), + * and "really big" objects (virtual arrays with backing store if needed). + * The memory manager does not allow individual objects to be freed; rather, + * each created object is assigned to a pool, and whole pools can be freed + * at once. This is faster and more convenient than remembering exactly what + * to free, especially where malloc()/free() are not too speedy. + * NB: alloc routines never return NULL. They exit to error_exit if not + * successful. + */ + +#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ +#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ +#define JPOOL_NUMPOOLS 2 + +typedef struct jvirt_sarray_control *jvirt_sarray_ptr; +typedef struct jvirt_barray_control *jvirt_barray_ptr; + + +struct jpeg_memory_mgr { + /* Method pointers */ + void *(*alloc_small) (j_common_ptr cinfo, int pool_id, size_t sizeofobject); + void *(*alloc_large) (j_common_ptr cinfo, int pool_id, + size_t sizeofobject); + /* If cinfo->data_precision is 12 or 16, then this method and the + * access_virt_sarray method actually return a J12SAMPARRAY or a + * J16SAMPARRAY, so callers must type-cast the return value in order to + * read/write 12-bit or 16-bit samples from/to the array. + */ + JSAMPARRAY (*alloc_sarray) (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, JDIMENSION numrows); + JBLOCKARRAY (*alloc_barray) (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, JDIMENSION numrows); + jvirt_sarray_ptr (*request_virt_sarray) (j_common_ptr cinfo, int pool_id, + boolean pre_zero, + JDIMENSION samplesperrow, + JDIMENSION numrows, + JDIMENSION maxaccess); + jvirt_barray_ptr (*request_virt_barray) (j_common_ptr cinfo, int pool_id, + boolean pre_zero, + JDIMENSION blocksperrow, + JDIMENSION numrows, + JDIMENSION maxaccess); + void (*realize_virt_arrays) (j_common_ptr cinfo); + JSAMPARRAY (*access_virt_sarray) (j_common_ptr cinfo, jvirt_sarray_ptr ptr, + JDIMENSION start_row, JDIMENSION num_rows, + boolean writable); + JBLOCKARRAY (*access_virt_barray) (j_common_ptr cinfo, jvirt_barray_ptr ptr, + JDIMENSION start_row, JDIMENSION num_rows, + boolean writable); + void (*free_pool) (j_common_ptr cinfo, int pool_id); + void (*self_destruct) (j_common_ptr cinfo); + + /* Limit on memory allocation for this JPEG object. (Note that this is + * merely advisory, not a guaranteed maximum; it only affects the space + * used for virtual-array buffers.) May be changed by outer application + * after creating the JPEG object. + */ + long max_memory_to_use; + + /* Maximum allocation request accepted by alloc_large. */ + long max_alloc_chunk; +}; + + +/* Routine signature for application-supplied marker processing methods. + * Need not pass marker code since it is stored in cinfo->unread_marker. + */ +typedef boolean (*jpeg_marker_parser_method) (j_decompress_ptr cinfo); + + +/* Originally, this macro was used as a way of defining function prototypes + * for both modern compilers as well as older compilers that did not support + * prototype parameters. libjpeg-turbo has never supported these older, + * non-ANSI compilers, but the macro is still included because there is some + * software out there that uses it. + */ + +#define JPP(arglist) arglist + + +/* Default error-management setup */ +EXTERN(struct jpeg_error_mgr *) jpeg_std_error(struct jpeg_error_mgr *err); + +/* Initialization of JPEG compression objects. + * jpeg_create_compress() and jpeg_create_decompress() are the exported + * names that applications should call. These expand to calls on + * jpeg_CreateCompress and jpeg_CreateDecompress with additional information + * passed for version mismatch checking. + * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. + */ +#define jpeg_create_compress(cinfo) \ + jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ + (size_t)sizeof(struct jpeg_compress_struct)) +#define jpeg_create_decompress(cinfo) \ + jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ + (size_t)sizeof(struct jpeg_decompress_struct)) +EXTERN(void) jpeg_CreateCompress(j_compress_ptr cinfo, int version, + size_t structsize); +EXTERN(void) jpeg_CreateDecompress(j_decompress_ptr cinfo, int version, + size_t structsize); +/* Destruction of JPEG compression objects */ +EXTERN(void) jpeg_destroy_compress(j_compress_ptr cinfo); +EXTERN(void) jpeg_destroy_decompress(j_decompress_ptr cinfo); + +/* Standard data source and destination managers: stdio streams. */ +/* Caller is responsible for opening the file before and closing after. */ +EXTERN(void) jpeg_stdio_dest(j_compress_ptr cinfo, FILE *outfile); +EXTERN(void) jpeg_stdio_src(j_decompress_ptr cinfo, FILE *infile); + +/* Data source and destination managers: memory buffers. */ +EXTERN(void) jpeg_mem_dest(j_compress_ptr cinfo, unsigned char **outbuffer, + unsigned long *outsize); +EXTERN(void) jpeg_mem_src(j_decompress_ptr cinfo, + const unsigned char *inbuffer, unsigned long insize); + +/* Default parameter setup for compression */ +EXTERN(void) jpeg_set_defaults(j_compress_ptr cinfo); +/* Compression parameter setup aids */ +EXTERN(void) jpeg_set_colorspace(j_compress_ptr cinfo, + J_COLOR_SPACE colorspace); +EXTERN(void) jpeg_default_colorspace(j_compress_ptr cinfo); +EXTERN(void) jpeg_set_quality(j_compress_ptr cinfo, int quality, + boolean force_baseline); +EXTERN(void) jpeg_set_linear_quality(j_compress_ptr cinfo, int scale_factor, + boolean force_baseline); +#if JPEG_LIB_VERSION >= 70 +EXTERN(void) jpeg_default_qtables(j_compress_ptr cinfo, + boolean force_baseline); +#endif +EXTERN(void) jpeg_add_quant_table(j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, boolean force_baseline); +EXTERN(int) jpeg_quality_scaling(int quality); +EXTERN(void) jpeg_enable_lossless(j_compress_ptr cinfo, + int predictor_selection_value, + int point_transform); +EXTERN(void) jpeg_simple_progression(j_compress_ptr cinfo); +EXTERN(void) jpeg_suppress_tables(j_compress_ptr cinfo, boolean suppress); +EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table(j_common_ptr cinfo); +EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table(j_common_ptr cinfo); + +/* Main entry points for compression */ +EXTERN(void) jpeg_start_compress(j_compress_ptr cinfo, + boolean write_all_tables); +EXTERN(JDIMENSION) jpeg_write_scanlines(j_compress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION num_lines); +EXTERN(JDIMENSION) jpeg12_write_scanlines(j_compress_ptr cinfo, + J12SAMPARRAY scanlines, + JDIMENSION num_lines); +EXTERN(JDIMENSION) jpeg16_write_scanlines(j_compress_ptr cinfo, + J16SAMPARRAY scanlines, + JDIMENSION num_lines); +EXTERN(void) jpeg_finish_compress(j_compress_ptr cinfo); + +#if JPEG_LIB_VERSION >= 70 +/* Precalculate JPEG dimensions for current compression parameters. */ +EXTERN(void) jpeg_calc_jpeg_dimensions(j_compress_ptr cinfo); +#endif + +/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_write_raw_data(j_compress_ptr cinfo, JSAMPIMAGE data, + JDIMENSION num_lines); +EXTERN(JDIMENSION) jpeg12_write_raw_data(j_compress_ptr cinfo, + J12SAMPIMAGE data, + JDIMENSION num_lines); + +/* Write a special marker. See libjpeg.txt concerning safe usage. */ +EXTERN(void) jpeg_write_marker(j_compress_ptr cinfo, int marker, + const JOCTET *dataptr, unsigned int datalen); +/* Same, but piecemeal. */ +EXTERN(void) jpeg_write_m_header(j_compress_ptr cinfo, int marker, + unsigned int datalen); +EXTERN(void) jpeg_write_m_byte(j_compress_ptr cinfo, int val); + +/* Alternate compression function: just write an abbreviated table file */ +EXTERN(void) jpeg_write_tables(j_compress_ptr cinfo); + +/* Write ICC profile. See libjpeg.txt for usage information. */ +EXTERN(void) jpeg_write_icc_profile(j_compress_ptr cinfo, + const JOCTET *icc_data_ptr, + unsigned int icc_data_len); + + +/* Decompression startup: read start of JPEG datastream to see what's there */ +EXTERN(int) jpeg_read_header(j_decompress_ptr cinfo, boolean require_image); +/* Return value is one of: */ +#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ +#define JPEG_HEADER_OK 1 /* Found valid image datastream */ +#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ +/* If you pass require_image = TRUE (normal case), you need not check for + * a TABLES_ONLY return code; an abbreviated file will cause an error exit. + * JPEG_SUSPENDED is only possible if you use a data source module that can + * give a suspension return (the stdio source module doesn't). + */ + +/* Main entry points for decompression */ +EXTERN(boolean) jpeg_start_decompress(j_decompress_ptr cinfo); +EXTERN(JDIMENSION) jpeg_read_scanlines(j_decompress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION max_lines); +EXTERN(JDIMENSION) jpeg12_read_scanlines(j_decompress_ptr cinfo, + J12SAMPARRAY scanlines, + JDIMENSION max_lines); +EXTERN(JDIMENSION) jpeg16_read_scanlines(j_decompress_ptr cinfo, + J16SAMPARRAY scanlines, + JDIMENSION max_lines); +EXTERN(JDIMENSION) jpeg_skip_scanlines(j_decompress_ptr cinfo, + JDIMENSION num_lines); +EXTERN(JDIMENSION) jpeg12_skip_scanlines(j_decompress_ptr cinfo, + JDIMENSION num_lines); +EXTERN(void) jpeg_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset, + JDIMENSION *width); +EXTERN(void) jpeg12_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset, + JDIMENSION *width); +EXTERN(boolean) jpeg_finish_decompress(j_decompress_ptr cinfo); + +/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_read_raw_data(j_decompress_ptr cinfo, JSAMPIMAGE data, + JDIMENSION max_lines); +EXTERN(JDIMENSION) jpeg12_read_raw_data(j_decompress_ptr cinfo, + J12SAMPIMAGE data, + JDIMENSION max_lines); + +/* Additional entry points for buffered-image mode. */ +EXTERN(boolean) jpeg_has_multiple_scans(j_decompress_ptr cinfo); +EXTERN(boolean) jpeg_start_output(j_decompress_ptr cinfo, int scan_number); +EXTERN(boolean) jpeg_finish_output(j_decompress_ptr cinfo); +EXTERN(boolean) jpeg_input_complete(j_decompress_ptr cinfo); +EXTERN(void) jpeg_new_colormap(j_decompress_ptr cinfo); +EXTERN(int) jpeg_consume_input(j_decompress_ptr cinfo); +/* Return value is one of: */ +/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ +#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ +#define JPEG_REACHED_EOI 2 /* Reached end of image */ +#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ +#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ + +/* Precalculate output dimensions for current decompression parameters. */ +#if JPEG_LIB_VERSION >= 80 +EXTERN(void) jpeg_core_output_dimensions(j_decompress_ptr cinfo); +#endif +EXTERN(void) jpeg_calc_output_dimensions(j_decompress_ptr cinfo); + +/* Control saving of COM and APPn markers into marker_list. */ +EXTERN(void) jpeg_save_markers(j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit); + +/* Install a special processing method for COM or APPn markers. */ +EXTERN(void) jpeg_set_marker_processor(j_decompress_ptr cinfo, + int marker_code, + jpeg_marker_parser_method routine); + +/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ +EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients(j_decompress_ptr cinfo); +EXTERN(void) jpeg_write_coefficients(j_compress_ptr cinfo, + jvirt_barray_ptr *coef_arrays); +EXTERN(void) jpeg_copy_critical_parameters(j_decompress_ptr srcinfo, + j_compress_ptr dstinfo); + +/* If you choose to abort compression or decompression before completing + * jpeg_finish_(de)compress, then you need to clean up to release memory, + * temporary files, etc. You can just call jpeg_destroy_(de)compress + * if you're done with the JPEG object, but if you want to clean it up and + * reuse it, call this: + */ +EXTERN(void) jpeg_abort_compress(j_compress_ptr cinfo); +EXTERN(void) jpeg_abort_decompress(j_decompress_ptr cinfo); + +/* Generic versions of jpeg_abort and jpeg_destroy that work on either + * flavor of JPEG object. These may be more convenient in some places. + */ +EXTERN(void) jpeg_abort(j_common_ptr cinfo); +EXTERN(void) jpeg_destroy(j_common_ptr cinfo); + +/* Default restart-marker-resync procedure for use by data source modules */ +EXTERN(boolean) jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired); + +/* Read ICC profile. See libjpeg.txt for usage information. */ +EXTERN(boolean) jpeg_read_icc_profile(j_decompress_ptr cinfo, + JOCTET **icc_data_ptr, + unsigned int *icc_data_len); + + +/* These marker codes are exported since applications and data source modules + * are likely to want to use them. + */ + +#define JPEG_RST0 0xD0 /* RST0 marker code */ +#define JPEG_EOI 0xD9 /* EOI marker code */ +#define JPEG_APP0 0xE0 /* APP0 marker code */ +#define JPEG_COM 0xFE /* COM marker code */ + + +/* If we have a brain-damaged compiler that emits warnings (or worse, errors) + * for structure definitions that are never filled in, keep it quiet by + * supplying dummy definitions for the various substructures. + */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +struct jpeg_comp_master { long dummy; }; +struct jpeg_c_main_controller { long dummy; }; +struct jpeg_c_prep_controller { long dummy; }; +struct jpeg_c_coef_controller { long dummy; }; +struct jpeg_marker_writer { long dummy; }; +struct jpeg_color_converter { long dummy; }; +struct jpeg_downsampler { long dummy; }; +struct jpeg_forward_dct { long dummy; }; +struct jpeg_entropy_encoder { long dummy; }; +struct jpeg_decomp_master { long dummy; }; +struct jpeg_d_main_controller { long dummy; }; +struct jpeg_d_coef_controller { long dummy; }; +struct jpeg_d_post_controller { long dummy; }; +struct jpeg_input_controller { long dummy; }; +struct jpeg_marker_reader { long dummy; }; +struct jpeg_entropy_decoder { long dummy; }; +struct jpeg_inverse_dct { long dummy; }; +struct jpeg_upsampler { long dummy; }; +struct jpeg_color_deconverter { long dummy; }; +struct jpeg_color_quantizer { long dummy; }; +#endif /* JPEG_INTERNALS */ +#endif /* INCOMPLETE_TYPES_BROKEN */ + + +/* + * The JPEG library modules define JPEG_INTERNALS before including this file. + * The internal structure declarations are read only when that is true. + * Applications using the library should not include jpegint.h, but may wish + * to include jerror.h. + */ + +#ifdef JPEG_INTERNALS +#include "jpegint.h" /* fetch private declarations */ +#include "jerror.h" /* fetch error codes too */ +#endif + +#ifdef __cplusplus +#ifndef DONT_USE_EXTERN_C +} +#endif +#endif + +#endif /* JPEGLIB_H */ diff --git a/duix-sdk/src/main/cpp/third/arm/include/turbojpeg/turbojpeg.h b/duix-sdk/src/main/cpp/third/arm/include/turbojpeg/turbojpeg.h new file mode 100644 index 0000000..12efcbc --- /dev/null +++ b/duix-sdk/src/main/cpp/third/arm/include/turbojpeg/turbojpeg.h @@ -0,0 +1,2286 @@ +/* + * Copyright (C)2009-2015, 2017, 2020-2023 D. R. Commander. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted 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 libjpeg-turbo Project nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 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 HOLDERS 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. + */ + +#ifndef __TURBOJPEG_H__ +#define __TURBOJPEG_H__ + +#include + +#if defined(_WIN32) && defined(DLLDEFINE) +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif +#define DLLCALL + + +/** + * @addtogroup TurboJPEG + * TurboJPEG API. This API provides an interface for generating, decoding, and + * transforming planar YUV and JPEG images in memory. + * + * @anchor YUVnotes + * YUV Image Format Notes + * ---------------------- + * Technically, the JPEG format uses the YCbCr colorspace (which is technically + * not a colorspace but a color transform), but per the convention of the + * digital video community, the TurboJPEG API uses "YUV" to refer to an image + * format consisting of Y, Cb, and Cr image planes. + * + * Each plane is simply a 2D array of bytes, each byte representing the value + * of one of the components (Y, Cb, or Cr) at a particular location in the + * image. The width and height of each plane are determined by the image + * width, height, and level of chrominance subsampling. The luminance plane + * width is the image width padded to the nearest multiple of the horizontal + * subsampling factor (1 in the case of 4:4:4, grayscale, 4:4:0, or 4:4:1; 2 in + * the case of 4:2:2 or 4:2:0; 4 in the case of 4:1:1.) Similarly, the + * luminance plane height is the image height padded to the nearest multiple of + * the vertical subsampling factor (1 in the case of 4:4:4, 4:2:2, grayscale, + * or 4:1:1; 2 in the case of 4:2:0 or 4:4:0; 4 in the case of 4:4:1.) This is + * irrespective of any additional padding that may be specified as an argument + * to the various YUV functions. The chrominance plane width is equal to the + * luminance plane width divided by the horizontal subsampling factor, and the + * chrominance plane height is equal to the luminance plane height divided by + * the vertical subsampling factor. + * + * For example, if the source image is 35 x 35 pixels and 4:2:2 subsampling is + * used, then the luminance plane would be 36 x 35 bytes, and each of the + * chrominance planes would be 18 x 35 bytes. If you specify a row alignment + * of 4 bytes on top of this, then the luminance plane would be 36 x 35 bytes, + * and each of the chrominance planes would be 20 x 35 bytes. + * + * @{ + */ + + +/** + * The number of initialization options + */ +#define TJ_NUMINIT 3 + +/** + * Initialization options. + */ +enum TJINIT { + /** + * Initialize the TurboJPEG instance for compression. + */ + TJINIT_COMPRESS, + /** + * Initialize the TurboJPEG instance for decompression. + */ + TJINIT_DECOMPRESS, + /** + * Initialize the TurboJPEG instance for lossless transformation (both + * compression and decompression.) + */ + TJINIT_TRANSFORM +}; + + +/** + * The number of chrominance subsampling options + */ +#define TJ_NUMSAMP 7 + +/** + * Chrominance subsampling options. + * When pixels are converted from RGB to YCbCr (see #TJCS_YCbCr) or from CMYK + * to YCCK (see #TJCS_YCCK) as part of the JPEG compression process, some of + * the Cb and Cr (chrominance) components can be discarded or averaged together + * to produce a smaller image with little perceptible loss of image clarity. + * (The human eye is more sensitive to small changes in brightness than to + * small changes in color.) This is called "chrominance subsampling". + */ +enum TJSAMP { + /** + * 4:4:4 chrominance subsampling (no chrominance subsampling). The JPEG or + * YUV image will contain one chrominance component for every pixel in the + * source image. + */ + TJSAMP_444, + /** + * 4:2:2 chrominance subsampling. The JPEG or YUV image will contain one + * chrominance component for every 2x1 block of pixels in the source image. + */ + TJSAMP_422, + /** + * 4:2:0 chrominance subsampling. The JPEG or YUV image will contain one + * chrominance component for every 2x2 block of pixels in the source image. + */ + TJSAMP_420, + /** + * Grayscale. The JPEG or YUV image will contain no chrominance components. + */ + TJSAMP_GRAY, + /** + * 4:4:0 chrominance subsampling. The JPEG or YUV image will contain one + * chrominance component for every 1x2 block of pixels in the source image. + * + * @note 4:4:0 subsampling is not fully accelerated in libjpeg-turbo. + */ + TJSAMP_440, + /** + * 4:1:1 chrominance subsampling. The JPEG or YUV image will contain one + * chrominance component for every 4x1 block of pixels in the source image. + * JPEG images compressed with 4:1:1 subsampling will be almost exactly the + * same size as those compressed with 4:2:0 subsampling, and in the + * aggregate, both subsampling methods produce approximately the same + * perceptual quality. However, 4:1:1 is better able to reproduce sharp + * horizontal features. + * + * @note 4:1:1 subsampling is not fully accelerated in libjpeg-turbo. + */ + TJSAMP_411, + /** + * 4:4:1 chrominance subsampling. The JPEG or YUV image will contain one + * chrominance component for every 1x4 block of pixels in the source image. + * JPEG images compressed with 4:4:1 subsampling will be almost exactly the + * same size as those compressed with 4:2:0 subsampling, and in the + * aggregate, both subsampling methods produce approximately the same + * perceptual quality. However, 4:4:1 is better able to reproduce sharp + * vertical features. + * + * @note 4:4:1 subsampling is not fully accelerated in libjpeg-turbo. + */ + TJSAMP_441, + /** + * Unknown subsampling. The JPEG image uses an unusual type of chrominance + * subsampling. Such images can be decompressed into packed-pixel images, + * but they cannot be + * - decompressed into planar YUV images, + * - losslessly transformed if #TJXOPT_CROP is specified, or + * - partially decompressed using a cropping region. + */ + TJSAMP_UNKNOWN = -1 +}; + +/** + * MCU block width (in pixels) for a given level of chrominance subsampling. + * MCU block sizes: + * - 8x8 for no subsampling or grayscale + * - 16x8 for 4:2:2 + * - 8x16 for 4:4:0 + * - 16x16 for 4:2:0 + * - 32x8 for 4:1:1 + * - 8x32 for 4:4:1 + */ +static const int tjMCUWidth[TJ_NUMSAMP] = { 8, 16, 16, 8, 8, 32, 8 }; + +/** + * MCU block height (in pixels) for a given level of chrominance subsampling. + * MCU block sizes: + * - 8x8 for no subsampling or grayscale + * - 16x8 for 4:2:2 + * - 8x16 for 4:4:0 + * - 16x16 for 4:2:0 + * - 32x8 for 4:1:1 + * - 8x32 for 4:4:1 + */ +static const int tjMCUHeight[TJ_NUMSAMP] = { 8, 8, 16, 8, 16, 8, 32 }; + + +/** + * The number of pixel formats + */ +#define TJ_NUMPF 12 + +/** + * Pixel formats + */ +enum TJPF { + /** + * RGB pixel format. The red, green, and blue components in the image are + * stored in 3-sample pixels in the order R, G, B from lowest to highest + * memory address within each pixel. + */ + TJPF_RGB, + /** + * BGR pixel format. The red, green, and blue components in the image are + * stored in 3-sample pixels in the order B, G, R from lowest to highest + * memory address within each pixel. + */ + TJPF_BGR, + /** + * RGBX pixel format. The red, green, and blue components in the image are + * stored in 4-sample pixels in the order R, G, B from lowest to highest + * memory address within each pixel. The X component is ignored when + * compressing and undefined when decompressing. + */ + TJPF_RGBX, + /** + * BGRX pixel format. The red, green, and blue components in the image are + * stored in 4-sample pixels in the order B, G, R from lowest to highest + * memory address within each pixel. The X component is ignored when + * compressing and undefined when decompressing. + */ + TJPF_BGRX, + /** + * XBGR pixel format. The red, green, and blue components in the image are + * stored in 4-sample pixels in the order R, G, B from highest to lowest + * memory address within each pixel. The X component is ignored when + * compressing and undefined when decompressing. + */ + TJPF_XBGR, + /** + * XRGB pixel format. The red, green, and blue components in the image are + * stored in 4-sample pixels in the order B, G, R from highest to lowest + * memory address within each pixel. The X component is ignored when + * compressing and undefined when decompressing. + */ + TJPF_XRGB, + /** + * Grayscale pixel format. Each 1-sample pixel represents a luminance + * (brightness) level from 0 to the maximum sample value (255 for 8-bit + * samples, 4095 for 12-bit samples, and 65535 for 16-bit samples.) + */ + TJPF_GRAY, + /** + * RGBA pixel format. This is the same as @ref TJPF_RGBX, except that when + * decompressing, the X component is guaranteed to be equal to the maximum + * sample value, which can be interpreted as an opaque alpha channel. + */ + TJPF_RGBA, + /** + * BGRA pixel format. This is the same as @ref TJPF_BGRX, except that when + * decompressing, the X component is guaranteed to be equal to the maximum + * sample value, which can be interpreted as an opaque alpha channel. + */ + TJPF_BGRA, + /** + * ABGR pixel format. This is the same as @ref TJPF_XBGR, except that when + * decompressing, the X component is guaranteed to be equal to the maximum + * sample value, which can be interpreted as an opaque alpha channel. + */ + TJPF_ABGR, + /** + * ARGB pixel format. This is the same as @ref TJPF_XRGB, except that when + * decompressing, the X component is guaranteed to be equal to the maximum + * sample value, which can be interpreted as an opaque alpha channel. + */ + TJPF_ARGB, + /** + * CMYK pixel format. Unlike RGB, which is an additive color model used + * primarily for display, CMYK (Cyan/Magenta/Yellow/Key) is a subtractive + * color model used primarily for printing. In the CMYK color model, the + * value of each color component typically corresponds to an amount of cyan, + * magenta, yellow, or black ink that is applied to a white background. In + * order to convert between CMYK and RGB, it is necessary to use a color + * management system (CMS.) A CMS will attempt to map colors within the + * printer's gamut to perceptually similar colors in the display's gamut and + * vice versa, but the mapping is typically not 1:1 or reversible, nor can it + * be defined with a simple formula. Thus, such a conversion is out of scope + * for a codec library. However, the TurboJPEG API allows for compressing + * packed-pixel CMYK images into YCCK JPEG images (see #TJCS_YCCK) and + * decompressing YCCK JPEG images into packed-pixel CMYK images. + */ + TJPF_CMYK, + /** + * Unknown pixel format. Currently this is only used by #tj3LoadImage8(), + * #tj3LoadImage12(), and #tj3LoadImage16(). + */ + TJPF_UNKNOWN = -1 +}; + +/** + * Red offset (in samples) for a given pixel format. This specifies the number + * of samples that the red component is offset from the start of the pixel. + * For instance, if an 8-bit-per-component pixel of format TJPF_BGRX is stored + * in `unsigned char pixel[]`, then the red component will be + * `pixel[tjRedOffset[TJPF_BGRX]]`. This will be -1 if the pixel format does + * not have a red component. + */ +static const int tjRedOffset[TJ_NUMPF] = { + 0, 2, 0, 2, 3, 1, -1, 0, 2, 3, 1, -1 +}; +/** + * Green offset (in samples) for a given pixel format. This specifies the + * number of samples that the green component is offset from the start of the + * pixel. For instance, if an 8-bit-per-component pixel of format TJPF_BGRX is + * stored in `unsigned char pixel[]`, then the green component will be + * `pixel[tjGreenOffset[TJPF_BGRX]]`. This will be -1 if the pixel format does + * not have a green component. + */ +static const int tjGreenOffset[TJ_NUMPF] = { + 1, 1, 1, 1, 2, 2, -1, 1, 1, 2, 2, -1 +}; +/** + * Blue offset (in samples) for a given pixel format. This specifies the + * number of samples that the blue component is offset from the start of the + * pixel. For instance, if an 8-bit-per-component pixel of format TJPF_BGRX is + * stored in `unsigned char pixel[]`, then the blue component will be + * `pixel[tjBlueOffset[TJPF_BGRX]]`. This will be -1 if the pixel format does + * not have a blue component. + */ +static const int tjBlueOffset[TJ_NUMPF] = { + 2, 0, 2, 0, 1, 3, -1, 2, 0, 1, 3, -1 +}; +/** + * Alpha offset (in samples) for a given pixel format. This specifies the + * number of samples that the alpha component is offset from the start of the + * pixel. For instance, if an 8-bit-per-component pixel of format TJPF_BGRA is + * stored in `unsigned char pixel[]`, then the alpha component will be + * `pixel[tjAlphaOffset[TJPF_BGRA]]`. This will be -1 if the pixel format does + * not have an alpha component. + */ +static const int tjAlphaOffset[TJ_NUMPF] = { + -1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0, -1 +}; +/** + * Pixel size (in samples) for a given pixel format + */ +static const int tjPixelSize[TJ_NUMPF] = { + 3, 3, 4, 4, 4, 4, 1, 4, 4, 4, 4, 4 +}; + + +/** + * The number of JPEG colorspaces + */ +#define TJ_NUMCS 5 + +/** + * JPEG colorspaces + */ +enum TJCS { + /** + * RGB colorspace. When compressing the JPEG image, the R, G, and B + * components in the source image are reordered into image planes, but no + * colorspace conversion or subsampling is performed. RGB JPEG images can be + * compressed from and decompressed to packed-pixel images with any of the + * extended RGB or grayscale pixel formats, but they cannot be compressed + * from or decompressed to planar YUV images. + */ + TJCS_RGB, + /** + * YCbCr colorspace. YCbCr is not an absolute colorspace but rather a + * mathematical transformation of RGB designed solely for storage and + * transmission. YCbCr images must be converted to RGB before they can + * actually be displayed. In the YCbCr colorspace, the Y (luminance) + * component represents the black & white portion of the original image, and + * the Cb and Cr (chrominance) components represent the color portion of the + * original image. Originally, the analog equivalent of this transformation + * allowed the same signal to drive both black & white and color televisions, + * but JPEG images use YCbCr primarily because it allows the color data to be + * optionally subsampled for the purposes of reducing network or disk usage. + * YCbCr is the most common JPEG colorspace, and YCbCr JPEG images can be + * compressed from and decompressed to packed-pixel images with any of the + * extended RGB or grayscale pixel formats. YCbCr JPEG images can also be + * compressed from and decompressed to planar YUV images. + */ + TJCS_YCbCr, + /** + * Grayscale colorspace. The JPEG image retains only the luminance data (Y + * component), and any color data from the source image is discarded. + * Grayscale JPEG images can be compressed from and decompressed to + * packed-pixel images with any of the extended RGB or grayscale pixel + * formats, or they can be compressed from and decompressed to planar YUV + * images. + */ + TJCS_GRAY, + /** + * CMYK colorspace. When compressing the JPEG image, the C, M, Y, and K + * components in the source image are reordered into image planes, but no + * colorspace conversion or subsampling is performed. CMYK JPEG images can + * only be compressed from and decompressed to packed-pixel images with the + * CMYK pixel format. + */ + TJCS_CMYK, + /** + * YCCK colorspace. YCCK (AKA "YCbCrK") is not an absolute colorspace but + * rather a mathematical transformation of CMYK designed solely for storage + * and transmission. It is to CMYK as YCbCr is to RGB. CMYK pixels can be + * reversibly transformed into YCCK, and as with YCbCr, the chrominance + * components in the YCCK pixels can be subsampled without incurring major + * perceptual loss. YCCK JPEG images can only be compressed from and + * decompressed to packed-pixel images with the CMYK pixel format. + */ + TJCS_YCCK +}; + + +/** + * The number of parameters + */ +#define TJ_NUMPARAM + +/** + * Parameters + */ +enum TJPARAM { +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + TJPARAM_MAXPIXELS = -1, +#endif + /** + * Error handling behavior + * + * **Value** + * - `0` *[default]* Allow the current compression/decompression/transform + * operation to complete unless a fatal error is encountered. + * - `1` Immediately discontinue the current + * compression/decompression/transform operation if a warning (non-fatal + * error) occurs. + */ + TJPARAM_STOPONWARNING, + /** + * Row order in packed-pixel source/destination images + * + * **Value** + * - `0` *[default]* top-down (X11) order + * - `1` bottom-up (Windows, OpenGL) order + */ + TJPARAM_BOTTOMUP, + /** + * JPEG destination buffer (re)allocation [compression, lossless + * transformation] + * + * **Value** + * - `0` *[default]* Attempt to allocate or reallocate the JPEG destination + * buffer as needed. + * - `1` Generate an error if the JPEG destination buffer is invalid or too + * small. + */ + TJPARAM_NOREALLOC, + /** + * Perceptual quality of lossy JPEG images [compression only] + * + * **Value** + * - `1`-`100` (`1` = worst quality but best compression, `100` = best + * quality but worst compression) *[no default; must be explicitly + * specified]* + */ + TJPARAM_QUALITY, + /** + * Chrominance subsampling level + * + * The JPEG or YUV image uses (decompression, decoding) or will use (lossy + * compression, encoding) the specified level of chrominance subsampling. + * + * **Value** + * - One of the @ref TJSAMP "chrominance subsampling options" *[no default; + * must be explicitly specified for lossy compression, encoding, and + * decoding]* + */ + TJPARAM_SUBSAMP, + /** + * JPEG width (in pixels) [decompression only, read-only] + */ + TJPARAM_JPEGWIDTH, + /** + * JPEG height (in pixels) [decompression only, read-only] + */ + TJPARAM_JPEGHEIGHT, + /** + * JPEG data precision (bits per sample) [decompression only, read-only] + * + * The JPEG image uses the specified number of bits per sample. + * + * **Value** + * - `8`, `12`, or `16` + * + * 12-bit data precision implies #TJPARAM_OPTIMIZE unless #TJPARAM_ARITHMETIC + * is set. + */ + TJPARAM_PRECISION, + /** + * JPEG colorspace + * + * The JPEG image uses (decompression) or will use (lossy compression) the + * specified colorspace. + * + * **Value** + * - One of the @ref TJCS "JPEG colorspaces" *[default for lossy compression: + * automatically selected based on the subsampling level and pixel format]* + */ + TJPARAM_COLORSPACE, + /** + * Chrominance upsampling algorithm [lossy decompression only] + * + * **Value** + * - `0` *[default]* Use smooth upsampling when decompressing a JPEG image + * that was compressed using chrominance subsampling. This creates a smooth + * transition between neighboring chrominance components in order to reduce + * upsampling artifacts in the decompressed image. + * - `1` Use the fastest chrominance upsampling algorithm available, which + * may combine upsampling with color conversion. + */ + TJPARAM_FASTUPSAMPLE, + /** + * DCT/IDCT algorithm [lossy compression and decompression] + * + * **Value** + * - `0` *[default]* Use the most accurate DCT/IDCT algorithm available. + * - `1` Use the fastest DCT/IDCT algorithm available. + * + * This parameter is provided mainly for backward compatibility with libjpeg, + * which historically implemented several different DCT/IDCT algorithms + * because of performance limitations with 1990s CPUs. In the libjpeg-turbo + * implementation of the TurboJPEG API: + * - The "fast" and "accurate" DCT/IDCT algorithms perform similarly on + * modern x86/x86-64 CPUs that support AVX2 instructions. + * - The "fast" algorithm is generally only about 5-15% faster than the + * "accurate" algorithm on other types of CPUs. + * - The difference in accuracy between the "fast" and "accurate" algorithms + * is the most pronounced at JPEG quality levels above 90 and tends to be + * more pronounced with decompression than with compression. + * - The "fast" algorithm degrades and is not fully accelerated for JPEG + * quality levels above 97, so it will be slower than the "accurate" + * algorithm. + */ + TJPARAM_FASTDCT, + /** + * Optimized baseline entropy coding [lossy compression only] + * + * **Value** + * - `0` *[default]* The JPEG image will use the default Huffman tables. + * - `1` Optimal Huffman tables will be computed for the JPEG image. For + * lossless transformation, this can also be specified using + * #TJXOPT_OPTIMIZE. + * + * Optimized baseline entropy coding will improve compression slightly + * (generally 5% or less), but it will reduce compression performance + * considerably. + */ + TJPARAM_OPTIMIZE, + /** + * Progressive entropy coding + * + * **Value** + * - `0` *[default for compression, lossless transformation]* The lossy JPEG + * image uses (decompression) or will use (compression, lossless + * transformation) baseline entropy coding. + * - `1` The lossy JPEG image uses (decompression) or will use (compression, + * lossless transformation) progressive entropy coding. For lossless + * transformation, this can also be specified using #TJXOPT_PROGRESSIVE. + * + * Progressive entropy coding will generally improve compression relative to + * baseline entropy coding, but it will reduce compression and decompression + * performance considerably. Can be combined with #TJPARAM_ARITHMETIC. + * Implies #TJPARAM_OPTIMIZE unless #TJPARAM_ARITHMETIC is also set. + */ + TJPARAM_PROGRESSIVE, + /** + * Progressive JPEG scan limit for lossy JPEG images [decompression, lossless + * transformation] + * + * Setting this parameter will cause the decompression and transform + * functions to return an error if the number of scans in a progressive JPEG + * image exceeds the specified limit. The primary purpose of this is to + * allow security-critical applications to guard against an exploit of the + * progressive JPEG format described in + * this report. + * + * **Value** + * - maximum number of progressive JPEG scans that the decompression and + * transform functions will process *[default: `0` (no limit)]* + * + * @see #TJPARAM_PROGRESSIVE + */ + TJPARAM_SCANLIMIT, + /** + * Arithmetic entropy coding + * + * **Value** + * - `0` *[default for compression, lossless transformation]* The lossy JPEG + * image uses (decompression) or will use (compression, lossless + * transformation) Huffman entropy coding. + * - `1` The lossy JPEG image uses (decompression) or will use (compression, + * lossless transformation) arithmetic entropy coding. For lossless + * transformation, this can also be specified using #TJXOPT_ARITHMETIC. + * + * Arithmetic entropy coding will generally improve compression relative to + * Huffman entropy coding, but it will reduce compression and decompression + * performance considerably. Can be combined with #TJPARAM_PROGRESSIVE. + */ + TJPARAM_ARITHMETIC, + /** + * Lossless JPEG + * + * **Value** + * - `0` *[default for compression]* The JPEG image is (decompression) or + * will be (compression) lossy/DCT-based. + * - `1` The JPEG image is (decompression) or will be (compression) + * lossless/predictive. + * + * In most cases, compressing and decompressing lossless JPEG images is + * considerably slower than compressing and decompressing lossy JPEG images. + * Also note that the following features are not available with lossless JPEG + * images: + * - Colorspace conversion (lossless JPEG images always use #TJCS_RGB, + * #TJCS_GRAY, or #TJCS_CMYK, depending on the pixel format of the source + * image) + * - Chrominance subsampling (lossless JPEG images always use #TJSAMP_444) + * - JPEG quality selection + * - DCT/IDCT algorithm selection + * - Progressive entropy coding + * - Arithmetic entropy coding + * - Compression from/decompression to planar YUV images + * - Decompression scaling + * - Lossless transformation + * + * @see #TJPARAM_LOSSLESSPSV, #TJPARAM_LOSSLESSPT + */ + TJPARAM_LOSSLESS, + /** + * Lossless JPEG predictor selection value (PSV) + * + * **Value** + * - `1`-`7` *[default for compression: `1`]* + * + * @see #TJPARAM_LOSSLESS + */ + TJPARAM_LOSSLESSPSV, + /** + * Lossless JPEG point transform (Pt) + * + * **Value** + * - `0` through ***precision*** *- 1*, where ***precision*** is the JPEG + * data precision in bits *[default for compression: `0`]* + * + * A point transform value of `0` is necessary in order to generate a fully + * lossless JPEG image. (A non-zero point transform value right-shifts the + * input samples by the specified number of bits, which is effectively a form + * of lossy color quantization.) + * + * @see #TJPARAM_LOSSLESS, #TJPARAM_PRECISION + */ + TJPARAM_LOSSLESSPT, + /** + * JPEG restart marker interval in MCU blocks (lossy) or samples (lossless) + * [compression only] + * + * The nature of entropy coding is such that a corrupt JPEG image cannot + * be decompressed beyond the point of corruption unless it contains restart + * markers. A restart marker stops and restarts the entropy coding algorithm + * so that, if a JPEG image is corrupted, decompression can resume at the + * next marker. Thus, adding more restart markers improves the fault + * tolerance of the JPEG image, but adding too many restart markers can + * adversely affect the compression ratio and performance. + * + * **Value** + * - the number of MCU blocks or samples between each restart marker + * *[default: `0` (no restart markers)]* + * + * Setting this parameter to a non-zero value sets #TJPARAM_RESTARTROWS to 0. + */ + TJPARAM_RESTARTBLOCKS, + /** + * JPEG restart marker interval in MCU rows (lossy) or sample rows (lossless) + * [compression only] + * + * See #TJPARAM_RESTARTBLOCKS for a description of restart markers. + * + * **Value** + * - the number of MCU rows or sample rows between each restart marker + * *[default: `0` (no restart markers)]* + * + * Setting this parameter to a non-zero value sets #TJPARAM_RESTARTBLOCKS to + * 0. + */ + TJPARAM_RESTARTROWS, + /** + * JPEG horizontal pixel density + * + * **Value** + * - The JPEG image has (decompression) or will have (compression) the + * specified horizontal pixel density *[default for compression: `1`]*. + * + * This value is stored in or read from the JPEG header. It does not affect + * the contents of the JPEG image. Note that this parameter is set by + * #tj3LoadImage8() when loading a Windows BMP file that contains pixel + * density information, and the value of this parameter is stored to a + * Windows BMP file by #tj3SaveImage8() if the value of #TJPARAM_DENSITYUNIT + * is `2`. + * + * @see TJPARAM_DENSITYUNIT + */ + TJPARAM_XDENSITY, + /** + * JPEG vertical pixel density + * + * **Value** + * - The JPEG image has (decompression) or will have (compression) the + * specified vertical pixel density *[default for compression: `1`]*. + * + * This value is stored in or read from the JPEG header. It does not affect + * the contents of the JPEG image. Note that this parameter is set by + * #tj3LoadImage8() when loading a Windows BMP file that contains pixel + * density information, and the value of this parameter is stored to a + * Windows BMP file by #tj3SaveImage8() if the value of #TJPARAM_DENSITYUNIT + * is `2`. + * + * @see TJPARAM_DENSITYUNIT + */ + TJPARAM_YDENSITY, + /** + * JPEG pixel density units + * + * **Value** + * - `0` *[default for compression]* The pixel density of the JPEG image is + * expressed (decompression) or will be expressed (compression) in unknown + * units. + * - `1` The pixel density of the JPEG image is expressed (decompression) or + * will be expressed (compression) in units of pixels/inch. + * - `2` The pixel density of the JPEG image is expressed (decompression) or + * will be expressed (compression) in units of pixels/cm. + * + * This value is stored in or read from the JPEG header. It does not affect + * the contents of the JPEG image. Note that this parameter is set by + * #tj3LoadImage8() when loading a Windows BMP file that contains pixel + * density information, and the value of this parameter is stored to a + * Windows BMP file by #tj3SaveImage8() if the value is `2`. + * + * @see TJPARAM_XDENSITY, TJPARAM_YDENSITY + */ + TJPARAM_DENSITYUNITS +}; + + +/** + * The number of error codes + */ +#define TJ_NUMERR 2 + +/** + * Error codes + */ +enum TJERR { + /** + * The error was non-fatal and recoverable, but the destination image may + * still be corrupt. + */ + TJERR_WARNING, + /** + * The error was fatal and non-recoverable. + */ + TJERR_FATAL +}; + + +/** + * The number of transform operations + */ +#define TJ_NUMXOP 8 + +/** + * Transform operations for #tj3Transform() + */ +enum TJXOP { + /** + * Do not transform the position of the image pixels + */ + TJXOP_NONE, + /** + * Flip (mirror) image horizontally. This transform is imperfect if there + * are any partial MCU blocks on the right edge (see #TJXOPT_PERFECT.) + */ + TJXOP_HFLIP, + /** + * Flip (mirror) image vertically. This transform is imperfect if there are + * any partial MCU blocks on the bottom edge (see #TJXOPT_PERFECT.) + */ + TJXOP_VFLIP, + /** + * Transpose image (flip/mirror along upper left to lower right axis.) This + * transform is always perfect. + */ + TJXOP_TRANSPOSE, + /** + * Transverse transpose image (flip/mirror along upper right to lower left + * axis.) This transform is imperfect if there are any partial MCU blocks in + * the image (see #TJXOPT_PERFECT.) + */ + TJXOP_TRANSVERSE, + /** + * Rotate image clockwise by 90 degrees. This transform is imperfect if + * there are any partial MCU blocks on the bottom edge (see + * #TJXOPT_PERFECT.) + */ + TJXOP_ROT90, + /** + * Rotate image 180 degrees. This transform is imperfect if there are any + * partial MCU blocks in the image (see #TJXOPT_PERFECT.) + */ + TJXOP_ROT180, + /** + * Rotate image counter-clockwise by 90 degrees. This transform is imperfect + * if there are any partial MCU blocks on the right edge (see + * #TJXOPT_PERFECT.) + */ + TJXOP_ROT270 +}; + + +/** + * This option will cause #tj3Transform() to return an error if the transform + * is not perfect. Lossless transforms operate on MCU blocks, whose size + * depends on the level of chrominance subsampling used (see #tjMCUWidth and + * #tjMCUHeight.) If the image's width or height is not evenly divisible by + * the MCU block size, then there will be partial MCU blocks on the right + * and/or bottom edges. It is not possible to move these partial MCU blocks to + * the top or left of the image, so any transform that would require that is + * "imperfect." If this option is not specified, then any partial MCU blocks + * that cannot be transformed will be left in place, which will create + * odd-looking strips on the right or bottom edge of the image. + */ +#define TJXOPT_PERFECT (1 << 0) +/** + * This option will cause #tj3Transform() to discard any partial MCU blocks + * that cannot be transformed. + */ +#define TJXOPT_TRIM (1 << 1) +/** + * This option will enable lossless cropping. See #tj3Transform() for more + * information. + */ +#define TJXOPT_CROP (1 << 2) +/** + * This option will discard the color data in the source image and produce a + * grayscale destination image. + */ +#define TJXOPT_GRAY (1 << 3) +/** + * This option will prevent #tj3Transform() from outputting a JPEG image for + * this particular transform. (This can be used in conjunction with a custom + * filter to capture the transformed DCT coefficients without transcoding + * them.) + */ +#define TJXOPT_NOOUTPUT (1 << 4) +/** + * This option will enable progressive entropy coding in the JPEG image + * generated by this particular transform. Progressive entropy coding will + * generally improve compression relative to baseline entropy coding (the + * default), but it will reduce decompression performance considerably. + * Can be combined with #TJXOPT_ARITHMETIC. Implies #TJXOPT_OPTIMIZE unless + * #TJXOPT_ARITHMETIC is also specified. + */ +#define TJXOPT_PROGRESSIVE (1 << 5) +/** + * This option will prevent #tj3Transform() from copying any extra markers + * (including EXIF and ICC profile data) from the source image to the + * destination image. + */ +#define TJXOPT_COPYNONE (1 << 6) +/** + * This option will enable arithmetic entropy coding in the JPEG image + * generated by this particular transform. Arithmetic entropy coding will + * generally improve compression relative to Huffman entropy coding (the + * default), but it will reduce decompression performance considerably. Can be + * combined with #TJXOPT_PROGRESSIVE. + */ +#define TJXOPT_ARITHMETIC (1 << 7) +/** + * This option will enable optimized baseline entropy coding in the JPEG image + * generated by this particular transform. Optimized baseline entropy coding + * will improve compression slightly (generally 5% or less.) + */ +#define TJXOPT_OPTIMIZE (1 << 8) + + +/** + * Scaling factor + */ +typedef struct { + /** + * Numerator + */ + int num; + /** + * Denominator + */ + int denom; +} tjscalingfactor; + +/** + * Cropping region + */ +typedef struct { + /** + * The left boundary of the cropping region. This must be evenly divisible + * by the MCU block width (see #tjMCUWidth.) + */ + int x; + /** + * The upper boundary of the cropping region. For lossless transformation, + * this must be evenly divisible by the MCU block height (see #tjMCUHeight.) + */ + int y; + /** + * The width of the cropping region. Setting this to 0 is the equivalent of + * setting it to the width of the source JPEG image - x. + */ + int w; + /** + * The height of the cropping region. Setting this to 0 is the equivalent of + * setting it to the height of the source JPEG image - y. + */ + int h; +} tjregion; + +/** + * A #tjregion structure that specifies no cropping + */ +static const tjregion TJUNCROPPED = { 0, 0, 0, 0 }; + +/** + * Lossless transform + */ +typedef struct tjtransform { + /** + * Cropping region + */ + tjregion r; + /** + * One of the @ref TJXOP "transform operations" + */ + int op; + /** + * The bitwise OR of one of more of the @ref TJXOPT_ARITHMETIC + * "transform options" + */ + int options; + /** + * Arbitrary data that can be accessed within the body of the callback + * function + */ + void *data; + /** + * A callback function that can be used to modify the DCT coefficients after + * they are losslessly transformed but before they are transcoded to a new + * JPEG image. This allows for custom filters or other transformations to be + * applied in the frequency domain. + * + * @param coeffs pointer to an array of transformed DCT coefficients. (NOTE: + * this pointer is not guaranteed to be valid once the callback returns, so + * applications wishing to hand off the DCT coefficients to another function + * or library should make a copy of them within the body of the callback.) + * + * @param arrayRegion #tjregion structure containing the width and height of + * the array pointed to by `coeffs` as well as its offset relative to the + * component plane. TurboJPEG implementations may choose to split each + * component plane into multiple DCT coefficient arrays and call the callback + * function once for each array. + * + * @param planeRegion #tjregion structure containing the width and height of + * the component plane to which `coeffs` belongs + * + * @param componentID ID number of the component plane to which `coeffs` + * belongs. (Y, Cb, and Cr have, respectively, ID's of 0, 1, and 2 in + * typical JPEG images.) + * + * @param transformID ID number of the transformed image to which `coeffs` + * belongs. This is the same as the index of the transform in the + * `transforms` array that was passed to #tj3Transform(). + * + * @param transform a pointer to a #tjtransform structure that specifies the + * parameters and/or cropping region for this transform + * + * @return 0 if the callback was successful, or -1 if an error occurred. + */ + int (*customFilter) (short *coeffs, tjregion arrayRegion, + tjregion planeRegion, int componentID, int transformID, + struct tjtransform *transform); +} tjtransform; + +/** + * TurboJPEG instance handle + */ +typedef void *tjhandle; + + +/** + * Compute the scaled value of `dimension` using the given scaling factor. + * This macro performs the integer equivalent of `ceil(dimension * + * scalingFactor)`. + */ +#define TJSCALED(dimension, scalingFactor) \ + (((dimension) * scalingFactor.num + scalingFactor.denom - 1) / \ + scalingFactor.denom) + +/** + * A #tjscalingfactor structure that specifies a scaling factor of 1/1 (no + * scaling) + */ +static const tjscalingfactor TJUNSCALED = { 1, 1 }; + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Create a new TurboJPEG instance. + * + * @param initType one of the @ref TJINIT "initialization options" + * + * @return a handle to the newly-created instance, or NULL if an error occurred + * (see #tj3GetErrorStr().) + */ +DLLEXPORT tjhandle tj3Init(int initType); + + +/** + * Set the value of a parameter. + * + * @param handle handle to a TurboJPEG instance + * + * @param param one of the @ref TJPARAM "parameters" + * + * @param value value of the parameter (refer to @ref TJPARAM + * "parameter documentation") + * + * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr().) + */ +DLLEXPORT int tj3Set(tjhandle handle, int param, int value); + + +/** + * Get the value of a parameter. + * + * @param handle handle to a TurboJPEG instance + * + * @param param one of the @ref TJPARAM "parameters" + * + * @return the value of the specified parameter, or -1 if the value is unknown. + */ +DLLEXPORT int tj3Get(tjhandle handle, int param); + + +/** + * Compress an 8-bit-per-sample packed-pixel RGB, grayscale, or CMYK image into + * an 8-bit-per-sample JPEG image. + * + * @param handle handle to a TurboJPEG instance that has been initialized for + * compression + * + * @param srcBuf pointer to a buffer containing a packed-pixel RGB, grayscale, + * or CMYK source image to be compressed. This buffer should normally be + * `pitch * height` samples in size. However, you can also use this parameter + * to compress from a specific region of a larger buffer. + * + * @param width width (in pixels) of the source image + * + * @param pitch samples per row in the source image. Normally this should be + * width * #tjPixelSize[pixelFormat], if the image is unpadded. + * (Setting this parameter to 0 is the equivalent of setting it to + * width * #tjPixelSize[pixelFormat].) However, you can also use this + * parameter to specify the row alignment/padding of the source image, to skip + * rows, or to compress from a specific region of a larger buffer. + * + * @param height height (in pixels) of the source image + * + * @param pixelFormat pixel format of the source image (see @ref TJPF + * "Pixel formats".) + * + * @param jpegBuf address of a pointer to a byte buffer that will receive the + * JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer to + * accommodate the size of the JPEG image. Thus, you can choose to: + * -# pre-allocate the JPEG buffer with an arbitrary size using #tj3Alloc() and + * let TurboJPEG grow the buffer as needed, + * -# set `*jpegBuf` to NULL to tell TurboJPEG to allocate the buffer for you, + * or + * -# pre-allocate the buffer to a "worst case" size determined by calling + * #tj3JPEGBufSize(). This should ensure that the buffer never has to be + * re-allocated. (Setting #TJPARAM_NOREALLOC guarantees that it won't be.) + * . + * If you choose option 1, then `*jpegSize` should be set to the size of your + * pre-allocated buffer. In any case, unless you have set #TJPARAM_NOREALLOC, + * you should always check `*jpegBuf` upon return from this function, as it may + * have changed. + * + * @param jpegSize pointer to a size_t variable that holds the size of the JPEG + * buffer. If `*jpegBuf` points to a pre-allocated buffer, then `*jpegSize` + * should be set to the size of the buffer. Upon return, `*jpegSize` will + * contain the size of the JPEG image (in bytes.) If `*jpegBuf` points to a + * JPEG buffer that is being reused from a previous call to one of the JPEG + * compression functions, then `*jpegSize` is ignored. + * + * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr() + * and #tj3GetErrorCode().) + */ +DLLEXPORT int tj3Compress8(tjhandle handle, const unsigned char *srcBuf, + int width, int pitch, int height, int pixelFormat, + unsigned char **jpegBuf, size_t *jpegSize); + +/** + * Compress a 12-bit-per-sample packed-pixel RGB, grayscale, or CMYK image into + * a 12-bit-per-sample JPEG image. + * + * \details \copydetails tj3Compress8() + */ +DLLEXPORT int tj3Compress12(tjhandle handle, const short *srcBuf, int width, + int pitch, int height, int pixelFormat, + unsigned char **jpegBuf, size_t *jpegSize); + +/** + * Compress a 16-bit-per-sample packed-pixel RGB, grayscale, or CMYK image into + * a 16-bit-per-sample lossless JPEG image. + * + * \details \copydetails tj3Compress8() + */ +DLLEXPORT int tj3Compress16(tjhandle handle, const unsigned short *srcBuf, + int width, int pitch, int height, int pixelFormat, + unsigned char **jpegBuf, size_t *jpegSize); + + +/** + * Compress an 8-bit-per-sample unified planar YUV image into an + * 8-bit-per-sample JPEG image. + * + * @param handle handle to a TurboJPEG instance that has been initialized for + * compression + * + * @param srcBuf pointer to a buffer containing a unified planar YUV source + * image to be compressed. The size of this buffer should match the value + * returned by #tj3YUVBufSize() for the given image width, height, row + * alignment, and level of chrominance subsampling (see #TJPARAM_SUBSAMP.) The + * Y, U (Cb), and V (Cr) image planes should be stored sequentially in the + * buffer. (Refer to @ref YUVnotes "YUV Image Format Notes".) + * + * @param width width (in pixels) of the source image. If the width is not an + * even multiple of the MCU block width (see #tjMCUWidth), then an intermediate + * buffer copy will be performed. + * + * @param align row alignment (in bytes) of the source image (must be a power + * of 2.) Setting this parameter to n indicates that each row in each plane of + * the source image is padded to the nearest multiple of n bytes + * (1 = unpadded.) + * + * @param height height (in pixels) of the source image. If the height is not + * an even multiple of the MCU block height (see #tjMCUHeight), then an + * intermediate buffer copy will be performed. + * + * @param jpegBuf address of a pointer to a byte buffer that will receive the + * JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer to + * accommodate the size of the JPEG image. Thus, you can choose to: + * -# pre-allocate the JPEG buffer with an arbitrary size using #tj3Alloc() and + * let TurboJPEG grow the buffer as needed, + * -# set `*jpegBuf` to NULL to tell TurboJPEG to allocate the buffer for you, + * or + * -# pre-allocate the buffer to a "worst case" size determined by calling + * #tj3JPEGBufSize(). This should ensure that the buffer never has to be + * re-allocated. (Setting #TJPARAM_NOREALLOC guarantees that it won't be.) + * . + * If you choose option 1, then `*jpegSize` should be set to the size of your + * pre-allocated buffer. In any case, unless you have set #TJPARAM_NOREALLOC, + * you should always check `*jpegBuf` upon return from this function, as it may + * have changed. + * + * @param jpegSize pointer to a size_t variable that holds the size of the JPEG + * buffer. If `*jpegBuf` points to a pre-allocated buffer, then `*jpegSize` + * should be set to the size of the buffer. Upon return, `*jpegSize` will + * contain the size of the JPEG image (in bytes.) If `*jpegBuf` points to a + * JPEG buffer that is being reused from a previous call to one of the JPEG + * compression functions, then `*jpegSize` is ignored. + * + * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr() + * and #tj3GetErrorCode().) + */ +DLLEXPORT int tj3CompressFromYUV8(tjhandle handle, + const unsigned char *srcBuf, int width, + int align, int height, + unsigned char **jpegBuf, size_t *jpegSize); + + +/** + * Compress a set of 8-bit-per-sample Y, U (Cb), and V (Cr) image planes into + * an 8-bit-per-sample JPEG image. + * + * @param handle handle to a TurboJPEG instance that has been initialized for + * compression + * + * @param srcPlanes an array of pointers to Y, U (Cb), and V (Cr) image planes + * (or just a Y plane, if compressing a grayscale image) that contain a YUV + * source image to be compressed. These planes can be contiguous or + * non-contiguous in memory. The size of each plane should match the value + * returned by #tj3YUVPlaneSize() for the given image width, height, strides, + * and level of chrominance subsampling (see #TJPARAM_SUBSAMP.) Refer to + * @ref YUVnotes "YUV Image Format Notes" for more details. + * + * @param width width (in pixels) of the source image. If the width is not an + * even multiple of the MCU block width (see #tjMCUWidth), then an intermediate + * buffer copy will be performed. + * + * @param strides an array of integers, each specifying the number of bytes per + * row in the corresponding plane of the YUV source image. Setting the stride + * for any plane to 0 is the same as setting it to the plane width (see + * @ref YUVnotes "YUV Image Format Notes".) If `strides` is NULL, then the + * strides for all planes will be set to their respective plane widths. You + * can adjust the strides in order to specify an arbitrary amount of row + * padding in each plane or to create a JPEG image from a subregion of a larger + * planar YUV image. + * + * @param height height (in pixels) of the source image. If the height is not + * an even multiple of the MCU block height (see #tjMCUHeight), then an + * intermediate buffer copy will be performed. + * + * @param jpegBuf address of a pointer to a byte buffer that will receive the + * JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer to + * accommodate the size of the JPEG image. Thus, you can choose to: + * -# pre-allocate the JPEG buffer with an arbitrary size using #tj3Alloc() and + * let TurboJPEG grow the buffer as needed, + * -# set `*jpegBuf` to NULL to tell TurboJPEG to allocate the buffer for you, + * or + * -# pre-allocate the buffer to a "worst case" size determined by calling + * #tj3JPEGBufSize(). This should ensure that the buffer never has to be + * re-allocated. (Setting #TJPARAM_NOREALLOC guarantees that it won't be.) + * . + * If you choose option 1, then `*jpegSize` should be set to the size of your + * pre-allocated buffer. In any case, unless you have set #TJPARAM_NOREALLOC, + * you should always check `*jpegBuf` upon return from this function, as it may + * have changed. + * + * @param jpegSize pointer to a size_t variable that holds the size of the JPEG + * buffer. If `*jpegBuf` points to a pre-allocated buffer, then `*jpegSize` + * should be set to the size of the buffer. Upon return, `*jpegSize` will + * contain the size of the JPEG image (in bytes.) If `*jpegBuf` points to a + * JPEG buffer that is being reused from a previous call to one of the JPEG + * compression functions, then `*jpegSize` is ignored. + * + * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr() + * and #tj3GetErrorCode().) + */ +DLLEXPORT int tj3CompressFromYUVPlanes8(tjhandle handle, + const unsigned char * const *srcPlanes, + int width, const int *strides, + int height, unsigned char **jpegBuf, + size_t *jpegSize); + + +/** + * The maximum size of the buffer (in bytes) required to hold a JPEG image with + * the given parameters. The number of bytes returned by this function is + * larger than the size of the uncompressed source image. The reason for this + * is that the JPEG format uses 16-bit coefficients, so it is possible for a + * very high-quality source image with very high-frequency content to expand + * rather than compress when converted to the JPEG format. Such images + * represent very rare corner cases, but since there is no way to predict the + * size of a JPEG image prior to compression, the corner cases have to be + * handled. + * + * @param width width (in pixels) of the image + * + * @param height height (in pixels) of the image + * + * @param jpegSubsamp the level of chrominance subsampling to be used when + * generating the JPEG image (see @ref TJSAMP + * "Chrominance subsampling options".) #TJSAMP_UNKNOWN is treated like + * #TJSAMP_444, since a buffer large enough to hold a JPEG image with no + * subsampling should also be large enough to hold a JPEG image with an + * arbitrary level of subsampling. Note that lossless JPEG images always + * use #TJSAMP_444. + * + * @return the maximum size of the buffer (in bytes) required to hold the + * image, or 0 if the arguments are out of bounds. + */ +DLLEXPORT size_t tj3JPEGBufSize(int width, int height, int jpegSubsamp); + + +/** + * The size of the buffer (in bytes) required to hold a unified planar YUV + * image with the given parameters. + * + * @param width width (in pixels) of the image + * + * @param align row alignment (in bytes) of the image (must be a power of 2.) + * Setting this parameter to n specifies that each row in each plane of the + * image will be padded to the nearest multiple of n bytes (1 = unpadded.) + * + * @param height height (in pixels) of the image + * + * @param subsamp level of chrominance subsampling in the image (see + * @ref TJSAMP "Chrominance subsampling options".) + * + * @return the size of the buffer (in bytes) required to hold the image, or 0 + * if the arguments are out of bounds. + */ +DLLEXPORT size_t tj3YUVBufSize(int width, int align, int height, int subsamp); + + +/** + * The size of the buffer (in bytes) required to hold a YUV image plane with + * the given parameters. + * + * @param componentID ID number of the image plane (0 = Y, 1 = U/Cb, 2 = V/Cr) + * + * @param width width (in pixels) of the YUV image. NOTE: this is the width of + * the whole image, not the plane width. + * + * @param stride bytes per row in the image plane. Setting this to 0 is the + * equivalent of setting it to the plane width. + * + * @param height height (in pixels) of the YUV image. NOTE: this is the height + * of the whole image, not the plane height. + * + * @param subsamp level of chrominance subsampling in the image (see + * @ref TJSAMP "Chrominance subsampling options".) + * + * @return the size of the buffer (in bytes) required to hold the YUV image + * plane, or 0 if the arguments are out of bounds. + */ +DLLEXPORT size_t tj3YUVPlaneSize(int componentID, int width, int stride, + int height, int subsamp); + + +/** + * The plane width of a YUV image plane with the given parameters. Refer to + * @ref YUVnotes "YUV Image Format Notes" for a description of plane width. + * + * @param componentID ID number of the image plane (0 = Y, 1 = U/Cb, 2 = V/Cr) + * + * @param width width (in pixels) of the YUV image + * + * @param subsamp level of chrominance subsampling in the image (see + * @ref TJSAMP "Chrominance subsampling options".) + * + * @return the plane width of a YUV image plane with the given parameters, or 0 + * if the arguments are out of bounds. + */ +DLLEXPORT int tj3YUVPlaneWidth(int componentID, int width, int subsamp); + + +/** + * The plane height of a YUV image plane with the given parameters. Refer to + * @ref YUVnotes "YUV Image Format Notes" for a description of plane height. + * + * @param componentID ID number of the image plane (0 = Y, 1 = U/Cb, 2 = V/Cr) + * + * @param height height (in pixels) of the YUV image + * + * @param subsamp level of chrominance subsampling in the image (see + * @ref TJSAMP "Chrominance subsampling options".) + * + * @return the plane height of a YUV image plane with the given parameters, or + * 0 if the arguments are out of bounds. + */ +DLLEXPORT int tj3YUVPlaneHeight(int componentID, int height, int subsamp); + + +/** + * Encode an 8-bit-per-sample packed-pixel RGB or grayscale image into an + * 8-bit-per-sample unified planar YUV image. This function performs color + * conversion (which is accelerated in the libjpeg-turbo implementation) but + * does not execute any of the other steps in the JPEG compression process. + * + * @param handle handle to a TurboJPEG instance that has been initialized for + * compression + * + * @param srcBuf pointer to a buffer containing a packed-pixel RGB or grayscale + * source image to be encoded. This buffer should normally be `pitch * height` + * bytes in size. However, you can also use this parameter to encode from a + * specific region of a larger buffer. + * + * @param width width (in pixels) of the source image + * + * @param pitch bytes per row in the source image. Normally this should be + * width * #tjPixelSize[pixelFormat], if the image is unpadded. + * (Setting this parameter to 0 is the equivalent of setting it to + * width * #tjPixelSize[pixelFormat].) However, you can also use this + * parameter to specify the row alignment/padding of the source image, to skip + * rows, or to encode from a specific region of a larger packed-pixel image. + * + * @param height height (in pixels) of the source image + * + * @param pixelFormat pixel format of the source image (see @ref TJPF + * "Pixel formats".) + * + * @param dstBuf pointer to a buffer that will receive the unified planar YUV + * image. Use #tj3YUVBufSize() to determine the appropriate size for this + * buffer based on the image width, height, row alignment, and level of + * chrominance subsampling (see #TJPARAM_SUBSAMP.) The Y, U (Cb), and V (Cr) + * image planes will be stored sequentially in the buffer. (Refer to + * @ref YUVnotes "YUV Image Format Notes".) + * + * @param align row alignment (in bytes) of the YUV image (must be a power of + * 2.) Setting this parameter to n will cause each row in each plane of the + * YUV image to be padded to the nearest multiple of n bytes (1 = unpadded.) + * To generate images suitable for X Video, `align` should be set to 4. + * + * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr() + * and #tj3GetErrorCode().) + */ +DLLEXPORT int tj3EncodeYUV8(tjhandle handle, const unsigned char *srcBuf, + int width, int pitch, int height, int pixelFormat, + unsigned char *dstBuf, int align); + + +/** + * Encode an 8-bit-per-sample packed-pixel RGB or grayscale image into separate + * 8-bit-per-sample Y, U (Cb), and V (Cr) image planes. This function performs + * color conversion (which is accelerated in the libjpeg-turbo implementation) + * but does not execute any of the other steps in the JPEG compression process. + * + * @param handle handle to a TurboJPEG instance that has been initialized for + * compression + * + * @param srcBuf pointer to a buffer containing a packed-pixel RGB or grayscale + * source image to be encoded. This buffer should normally be `pitch * height` + * bytes in size. However, you can also use this parameter to encode from a + * specific region of a larger buffer. + * + * + * @param width width (in pixels) of the source image + * + * @param pitch bytes per row in the source image. Normally this should be + * width * #tjPixelSize[pixelFormat], if the image is unpadded. + * (Setting this parameter to 0 is the equivalent of setting it to + * width * #tjPixelSize[pixelFormat].) However, you can also use this + * parameter to specify the row alignment/padding of the source image, to skip + * rows, or to encode from a specific region of a larger packed-pixel image. + * + * @param height height (in pixels) of the source image + * + * @param pixelFormat pixel format of the source image (see @ref TJPF + * "Pixel formats".) + * + * @param dstPlanes an array of pointers to Y, U (Cb), and V (Cr) image planes + * (or just a Y plane, if generating a grayscale image) that will receive the + * encoded image. These planes can be contiguous or non-contiguous in memory. + * Use #tj3YUVPlaneSize() to determine the appropriate size for each plane + * based on the image width, height, strides, and level of chrominance + * subsampling (see #TJPARAM_SUBSAMP.) Refer to @ref YUVnotes + * "YUV Image Format Notes" for more details. + * + * @param strides an array of integers, each specifying the number of bytes per + * row in the corresponding plane of the YUV image. Setting the stride for any + * plane to 0 is the same as setting it to the plane width (see @ref YUVnotes + * "YUV Image Format Notes".) If `strides` is NULL, then the strides for all + * planes will be set to their respective plane widths. You can adjust the + * strides in order to add an arbitrary amount of row padding to each plane or + * to encode an RGB or grayscale image into a subregion of a larger planar YUV + * image. + * + * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr() + * and #tj3GetErrorCode().) + */ +DLLEXPORT int tj3EncodeYUVPlanes8(tjhandle handle, const unsigned char *srcBuf, + int width, int pitch, int height, + int pixelFormat, unsigned char **dstPlanes, + int *strides); + + +/** + * Retrieve information about a JPEG image without decompressing it, or prime + * the decompressor with quantization and Huffman tables. If a JPEG image is + * passed to this function, then the @ref TJPARAM "parameters" that describe + * the JPEG image will be set when the function returns. + * + * @param handle handle to a TurboJPEG instance that has been initialized for + * decompression + * + * @param jpegBuf pointer to a byte buffer containing a JPEG image or an + * "abbreviated table specification" (AKA "tables-only") datastream. Passing a + * tables-only datastream to this function primes the decompressor with + * quantization and Huffman tables that can be used when decompressing + * subsequent "abbreviated image" datastreams. This is useful, for instance, + * when decompressing video streams in which all frames share the same + * quantization and Huffman tables. + * + * @param jpegSize size of the JPEG image or tables-only datastream (in bytes) + * + * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr() + * and #tj3GetErrorCode().) + */ +DLLEXPORT int tj3DecompressHeader(tjhandle handle, + const unsigned char *jpegBuf, + size_t jpegSize); + + +/** + * Returns a list of fractional scaling factors that the JPEG decompressor + * supports. + * + * @param numScalingFactors pointer to an integer variable that will receive + * the number of elements in the list + * + * @return a pointer to a list of fractional scaling factors, or NULL if an + * error is encountered (see #tj3GetErrorStr().) + */ +DLLEXPORT tjscalingfactor *tj3GetScalingFactors(int *numScalingFactors); + + +/** + * Set the scaling factor for subsequent lossy decompression operations. + * + * @param handle handle to a TurboJPEG instance that has been initialized for + * decompression + * + * @param scalingFactor #tjscalingfactor structure that specifies a fractional + * scaling factor that the decompressor supports (see #tj3GetScalingFactors()), + * or #TJUNSCALED for no scaling. Decompression scaling is a function + * of the IDCT algorithm, so scaling factors are generally limited to multiples + * of 1/8. If the entire JPEG image will be decompressed, then the width and + * height of the scaled destination image can be determined by calling + * #TJSCALED() with the JPEG width and height (see #TJPARAM_JPEGWIDTH and + * #TJPARAM_JPEGHEIGHT) and the specified scaling factor. When decompressing + * into a planar YUV image, an intermediate buffer copy will be performed if + * the width or height of the scaled destination image is not an even multiple + * of the MCU block size (see #tjMCUWidth and #tjMCUHeight.) Note that + * decompression scaling is not available (and the specified scaling factor is + * ignored) when decompressing lossless JPEG images (see #TJPARAM_LOSSLESS), + * since the IDCT algorithm is not used with those images. Note also that + * #TJPARAM_FASTDCT is ignored when decompression scaling is enabled. + * + * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr().) + */ +DLLEXPORT int tj3SetScalingFactor(tjhandle handle, + tjscalingfactor scalingFactor); + + +/** + * Set the cropping region for partially decompressing a lossy JPEG image into + * a packed-pixel image + * + * @param handle handle to a TurboJPEG instance that has been initialized for + * decompression + * + * @param croppingRegion #tjregion structure that specifies a subregion of the + * JPEG image to decompress, or #TJUNCROPPED for no cropping. The + * left boundary of the cropping region must be evenly divisible by the scaled + * MCU block width (#TJSCALED(#tjMCUWidth[subsamp], scalingFactor), + * where `subsamp` is the level of chrominance subsampling in the JPEG image + * (see #TJPARAM_SUBSAMP) and `scalingFactor` is the decompression scaling + * factor (see #tj3SetScalingFactor().) The cropping region should be + * specified relative to the scaled image dimensions. Unless `croppingRegion` + * is #TJUNCROPPED, the JPEG header must be read (see + * #tj3DecompressHeader()) prior to calling this function. + * + * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr().) + */ +DLLEXPORT int tj3SetCroppingRegion(tjhandle handle, tjregion croppingRegion); + + +/** + * Decompress an 8-bit-per-sample JPEG image into an 8-bit-per-sample + * packed-pixel RGB, grayscale, or CMYK image. The @ref TJPARAM "parameters" + * that describe the JPEG image will be set when this function returns. + * + * @param handle handle to a TurboJPEG instance that has been initialized for + * decompression + * + * @param jpegBuf pointer to a byte buffer containing the JPEG image to + * decompress + * + * @param jpegSize size of the JPEG image (in bytes) + * + * @param dstBuf pointer to a buffer that will receive the packed-pixel + * decompressed image. This buffer should normally be + * `pitch * destinationHeight` samples in size. However, you can also use this + * parameter to decompress into a specific region of a larger buffer. NOTE: + * If the JPEG image is lossy, then `destinationHeight` is either the scaled + * JPEG height (see #TJSCALED(), #TJPARAM_JPEGHEIGHT, and + * #tj3SetScalingFactor()) or the height of the cropping region (see + * #tj3SetCroppingRegion().) If the JPEG image is lossless, then + * `destinationHeight` is the JPEG height. + * + * @param pitch samples per row in the destination image. Normally this should + * be set to destinationWidth * #tjPixelSize[pixelFormat], if the + * destination image should be unpadded. (Setting this parameter to 0 is the + * equivalent of setting it to + * destinationWidth * #tjPixelSize[pixelFormat].) However, you can + * also use this parameter to specify the row alignment/padding of the + * destination image, to skip rows, or to decompress into a specific region of + * a larger buffer. NOTE: If the JPEG image is lossy, then `destinationWidth` + * is either the scaled JPEG width (see #TJSCALED(), #TJPARAM_JPEGWIDTH, and + * #tj3SetScalingFactor()) or the width of the cropping region (see + * #tj3SetCroppingRegion().) If the JPEG image is lossless, then + * `destinationWidth` is the JPEG width. + * + * @param pixelFormat pixel format of the destination image (see @ref + * TJPF "Pixel formats".) + * + * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr() + * and #tj3GetErrorCode().) + */ +DLLEXPORT int tj3Decompress8(tjhandle handle, const unsigned char *jpegBuf, + size_t jpegSize, unsigned char *dstBuf, int pitch, + int pixelFormat); + +/** + * Decompress a 12-bit-per-sample JPEG image into a 12-bit-per-sample + * packed-pixel RGB, grayscale, or CMYK image. + * + * \details \copydetails tj3Decompress8() + */ +DLLEXPORT int tj3Decompress12(tjhandle handle, const unsigned char *jpegBuf, + size_t jpegSize, short *dstBuf, int pitch, + int pixelFormat); + +/** + * Decompress a 16-bit-per-sample lossless JPEG image into a 16-bit-per-sample + * packed-pixel RGB, grayscale, or CMYK image. + * + * \details \copydetails tj3Decompress8() + */ +DLLEXPORT int tj3Decompress16(tjhandle handle, const unsigned char *jpegBuf, + size_t jpegSize, unsigned short *dstBuf, + int pitch, int pixelFormat); + + +/** + * Decompress an 8-bit-per-sample JPEG image into an 8-bit-per-sample unified + * planar YUV image. This function performs JPEG decompression but leaves out + * the color conversion step, so a planar YUV image is generated instead of a + * packed-pixel image. The @ref TJPARAM "parameters" that describe the JPEG + * image will be set when this function returns. + * + * @param handle handle to a TurboJPEG instance that has been initialized for + * decompression + * + * @param jpegBuf pointer to a byte buffer containing the JPEG image to + * decompress + * + * @param jpegSize size of the JPEG image (in bytes) + * + * @param dstBuf pointer to a buffer that will receive the unified planar YUV + * decompressed image. Use #tj3YUVBufSize() to determine the appropriate size + * for this buffer based on the scaled JPEG width and height (see #TJSCALED(), + * #TJPARAM_JPEGWIDTH, #TJPARAM_JPEGHEIGHT, and #tj3SetScalingFactor()), row + * alignment, and level of chrominance subsampling (see #TJPARAM_SUBSAMP.) The + * Y, U (Cb), and V (Cr) image planes will be stored sequentially in the + * buffer. (Refer to @ref YUVnotes "YUV Image Format Notes".) + * + * @param align row alignment (in bytes) of the YUV image (must be a power of + * 2.) Setting this parameter to n will cause each row in each plane of the + * YUV image to be padded to the nearest multiple of n bytes (1 = unpadded.) + * To generate images suitable for X Video, `align` should be set to 4. + * + * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr() + * and #tj3GetErrorCode().) + */ +DLLEXPORT int tj3DecompressToYUV8(tjhandle handle, + const unsigned char *jpegBuf, + size_t jpegSize, + unsigned char *dstBuf, int align); + + +/** + * Decompress an 8-bit-per-sample JPEG image into separate 8-bit-per-sample Y, + * U (Cb), and V (Cr) image planes. This function performs JPEG decompression + * but leaves out the color conversion step, so a planar YUV image is generated + * instead of a packed-pixel image. The @ref TJPARAM "parameters" that + * describe the JPEG image will be set when this function returns. + * + * @param handle handle to a TurboJPEG instance that has been initialized for + * decompression + * + * @param jpegBuf pointer to a byte buffer containing the JPEG image to + * decompress + * + * @param jpegSize size of the JPEG image (in bytes) + * + * @param dstPlanes an array of pointers to Y, U (Cb), and V (Cr) image planes + * (or just a Y plane, if decompressing a grayscale image) that will receive + * the decompressed image. These planes can be contiguous or non-contiguous in + * memory. Use #tj3YUVPlaneSize() to determine the appropriate size for each + * plane based on the scaled JPEG width and height (see #TJSCALED(), + * #TJPARAM_JPEGWIDTH, #TJPARAM_JPEGHEIGHT, and #tj3SetScalingFactor()), + * strides, and level of chrominance subsampling (see #TJPARAM_SUBSAMP.) Refer + * to @ref YUVnotes "YUV Image Format Notes" for more details. + * + * @param strides an array of integers, each specifying the number of bytes per + * row in the corresponding plane of the YUV image. Setting the stride for any + * plane to 0 is the same as setting it to the scaled plane width (see + * @ref YUVnotes "YUV Image Format Notes".) If `strides` is NULL, then the + * strides for all planes will be set to their respective scaled plane widths. + * You can adjust the strides in order to add an arbitrary amount of row + * padding to each plane or to decompress the JPEG image into a subregion of a + * larger planar YUV image. + * + * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr() + * and #tj3GetErrorCode().) + */ +DLLEXPORT int tj3DecompressToYUVPlanes8(tjhandle handle, + const unsigned char *jpegBuf, + size_t jpegSize, + unsigned char **dstPlanes, + int *strides); + + +/** + * Decode an 8-bit-per-sample unified planar YUV image into an 8-bit-per-sample + * packed-pixel RGB or grayscale image. This function performs color + * conversion (which is accelerated in the libjpeg-turbo implementation) but + * does not execute any of the other steps in the JPEG decompression process. + * + * @param handle handle to a TurboJPEG instance that has been initialized for + * decompression + * + * @param srcBuf pointer to a buffer containing a unified planar YUV source + * image to be decoded. The size of this buffer should match the value + * returned by #tj3YUVBufSize() for the given image width, height, row + * alignment, and level of chrominance subsampling (see #TJPARAM_SUBSAMP.) The + * Y, U (Cb), and V (Cr) image planes should be stored sequentially in the + * source buffer. (Refer to @ref YUVnotes "YUV Image Format Notes".) + * + * @param align row alignment (in bytes) of the YUV source image (must be a + * power of 2.) Setting this parameter to n indicates that each row in each + * plane of the YUV source image is padded to the nearest multiple of n bytes + * (1 = unpadded.) + * + * @param dstBuf pointer to a buffer that will receive the packed-pixel decoded + * image. This buffer should normally be `pitch * height` bytes in size. + * However, you can also use this parameter to decode into a specific region of + * a larger buffer. + * + * @param width width (in pixels) of the source and destination images + * + * @param pitch bytes per row in the destination image. Normally this should + * be set to width * #tjPixelSize[pixelFormat], if the destination + * image should be unpadded. (Setting this parameter to 0 is the equivalent of + * setting it to width * #tjPixelSize[pixelFormat].) However, you can + * also use this parameter to specify the row alignment/padding of the + * destination image, to skip rows, or to decode into a specific region of a + * larger buffer. + * + * @param height height (in pixels) of the source and destination images + * + * @param pixelFormat pixel format of the destination image (see @ref TJPF + * "Pixel formats".) + * + * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr() + * and #tj3GetErrorCode().) + */ +DLLEXPORT int tj3DecodeYUV8(tjhandle handle, const unsigned char *srcBuf, + int align, unsigned char *dstBuf, int width, + int pitch, int height, int pixelFormat); + + +/** + * Decode a set of 8-bit-per-sample Y, U (Cb), and V (Cr) image planes into an + * 8-bit-per-sample packed-pixel RGB or grayscale image. This function + * performs color conversion (which is accelerated in the libjpeg-turbo + * implementation) but does not execute any of the other steps in the JPEG + * decompression process. + * + * @param handle handle to a TurboJPEG instance that has been initialized for + * decompression + * + * @param srcPlanes an array of pointers to Y, U (Cb), and V (Cr) image planes + * (or just a Y plane, if decoding a grayscale image) that contain a YUV image + * to be decoded. These planes can be contiguous or non-contiguous in memory. + * The size of each plane should match the value returned by #tj3YUVPlaneSize() + * for the given image width, height, strides, and level of chrominance + * subsampling (see #TJPARAM_SUBSAMP.) Refer to @ref YUVnotes + * "YUV Image Format Notes" for more details. + * + * @param strides an array of integers, each specifying the number of bytes per + * row in the corresponding plane of the YUV source image. Setting the stride + * for any plane to 0 is the same as setting it to the plane width (see + * @ref YUVnotes "YUV Image Format Notes".) If `strides` is NULL, then the + * strides for all planes will be set to their respective plane widths. You + * can adjust the strides in order to specify an arbitrary amount of row + * padding in each plane or to decode a subregion of a larger planar YUV image. + * + * @param dstBuf pointer to a buffer that will receive the packed-pixel decoded + * image. This buffer should normally be `pitch * height` bytes in size. + * However, you can also use this parameter to decode into a specific region of + * a larger buffer. + * + * @param width width (in pixels) of the source and destination images + * + * @param pitch bytes per row in the destination image. Normally this should + * be set to width * #tjPixelSize[pixelFormat], if the destination + * image should be unpadded. (Setting this parameter to 0 is the equivalent of + * setting it to width * #tjPixelSize[pixelFormat].) However, you can + * also use this parameter to specify the row alignment/padding of the + * destination image, to skip rows, or to decode into a specific region of a + * larger buffer. + * + * @param height height (in pixels) of the source and destination images + * + * @param pixelFormat pixel format of the destination image (see @ref TJPF + * "Pixel formats".) + * + * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr() + * and #tj3GetErrorCode().) + */ +DLLEXPORT int tj3DecodeYUVPlanes8(tjhandle handle, + const unsigned char * const *srcPlanes, + const int *strides, unsigned char *dstBuf, + int width, int pitch, int height, + int pixelFormat); + + +/** + * Losslessly transform a JPEG image into another JPEG image. Lossless + * transforms work by moving the raw DCT coefficients from one JPEG image + * structure to another without altering the values of the coefficients. While + * this is typically faster than decompressing the image, transforming it, and + * re-compressing it, lossless transforms are not free. Each lossless + * transform requires reading and performing entropy decoding on all of the + * coefficients in the source image, regardless of the size of the destination + * image. Thus, this function provides a means of generating multiple + * transformed images from the same source or applying multiple transformations + * simultaneously, in order to eliminate the need to read the source + * coefficients multiple times. + * + * @param handle handle to a TurboJPEG instance that has been initialized for + * lossless transformation + * + * @param jpegBuf pointer to a byte buffer containing the JPEG source image to + * transform + * + * @param jpegSize size of the JPEG source image (in bytes) + * + * @param n the number of transformed JPEG images to generate + * + * @param dstBufs pointer to an array of n byte buffers. `dstBufs[i]` will + * receive a JPEG image that has been transformed using the parameters in + * `transforms[i]`. TurboJPEG has the ability to reallocate the JPEG + * destination buffer to accommodate the size of the transformed JPEG image. + * Thus, you can choose to: + * -# pre-allocate the JPEG destination buffer with an arbitrary size using + * #tj3Alloc() and let TurboJPEG grow the buffer as needed, + * -# set `dstBufs[i]` to NULL to tell TurboJPEG to allocate the buffer for + * you, or + * -# pre-allocate the buffer to a "worst case" size determined by calling + * #tj3JPEGBufSize() with the transformed or cropped width and height and the + * level of subsampling used in the source image. Under normal circumstances, + * this should ensure that the buffer never has to be re-allocated. (Setting + * #TJPARAM_NOREALLOC guarantees that it won't be.) Note, however, that there + * are some rare cases (such as transforming images with a large amount of + * embedded EXIF or ICC profile data) in which the transformed JPEG image will + * be larger than the worst-case size, and #TJPARAM_NOREALLOC cannot be used in + * those cases. + * . + * If you choose option 1, then `dstSizes[i]` should be set to the size of your + * pre-allocated buffer. In any case, unless you have set #TJPARAM_NOREALLOC, + * you should always check `dstBufs[i]` upon return from this function, as it + * may have changed. + * + * @param dstSizes pointer to an array of n size_t variables that will receive + * the actual sizes (in bytes) of each transformed JPEG image. If `dstBufs[i]` + * points to a pre-allocated buffer, then `dstSizes[i]` should be set to the + * size of the buffer. Upon return, `dstSizes[i]` will contain the size of the + * transformed JPEG image (in bytes.) + * + * @param transforms pointer to an array of n #tjtransform structures, each of + * which specifies the transform parameters and/or cropping region for the + * corresponding transformed JPEG image. + * + * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr() + * and #tj3GetErrorCode().) + */ +DLLEXPORT int tj3Transform(tjhandle handle, const unsigned char *jpegBuf, + size_t jpegSize, int n, unsigned char **dstBufs, + size_t *dstSizes, const tjtransform *transforms); + + +/** + * Destroy a TurboJPEG instance. + * + * @param handle handle to a TurboJPEG instance. If the handle is NULL, then + * this function has no effect. + */ +DLLEXPORT void tj3Destroy(tjhandle handle); + + +/** + * Allocate a byte buffer for use with TurboJPEG. You should always use this + * function to allocate the JPEG destination buffer(s) for the compression and + * transform functions unless you are disabling automatic buffer (re)allocation + * (by setting #TJPARAM_NOREALLOC.) + * + * @param bytes the number of bytes to allocate + * + * @return a pointer to a newly-allocated buffer with the specified number of + * bytes. + * + * @see tj3Free() + */ +DLLEXPORT void *tj3Alloc(size_t bytes); + + +/** + * Load an 8-bit-per-sample packed-pixel image from disk into memory. + * + * @param handle handle to a TurboJPEG instance + * + * @param filename name of a file containing a packed-pixel image in Windows + * BMP or PBMPLUS (PPM/PGM) format. Windows BMP files require 8-bit-per-sample + * data precision. If the data precision of the PBMPLUS file does not match + * the target data precision, then upconverting or downconverting will be + * performed. + * + * @param width pointer to an integer variable that will receive the width (in + * pixels) of the packed-pixel image + * + * @param align row alignment (in samples) of the packed-pixel buffer to be + * returned (must be a power of 2.) Setting this parameter to n will cause all + * rows in the buffer to be padded to the nearest multiple of n samples + * (1 = unpadded.) + * + * @param height pointer to an integer variable that will receive the height + * (in pixels) of the packed-pixel image + * + * @param pixelFormat pointer to an integer variable that specifies or will + * receive the pixel format of the packed-pixel buffer. The behavior of this + * function will vary depending on the value of `*pixelFormat` passed to the + * function: + * - @ref TJPF_UNKNOWN : The packed-pixel buffer returned by this function will + * use the most optimal pixel format for the file type, and `*pixelFormat` will + * contain the ID of that pixel format upon successful return from this + * function. + * - @ref TJPF_GRAY : Only PGM files and 8-bit-per-pixel BMP files with a + * grayscale colormap can be loaded. + * - @ref TJPF_CMYK : The RGB or grayscale pixels stored in the file will be + * converted using a quick & dirty algorithm that is suitable only for testing + * purposes. (Proper conversion between CMYK and other formats requires a + * color management system.) + * - Other @ref TJPF "pixel formats" : The packed-pixel buffer will use the + * specified pixel format, and pixel format conversion will be performed if + * necessary. + * + * @return a pointer to a newly-allocated buffer containing the packed-pixel + * image, converted to the chosen pixel format and with the chosen row + * alignment, or NULL if an error occurred (see #tj3GetErrorStr().) This + * buffer should be freed using #tj3Free(). + */ +DLLEXPORT unsigned char *tj3LoadImage8(tjhandle handle, const char *filename, + int *width, int align, int *height, + int *pixelFormat); + +/** + * Load a 12-bit-per-sample packed-pixel image from disk into memory. + * + * \details \copydetails tj3LoadImage8() + */ +DLLEXPORT short *tj3LoadImage12(tjhandle handle, const char *filename, + int *width, int align, int *height, + int *pixelFormat); + +/** + * Load a 16-bit-per-sample packed-pixel image from disk into memory. + * + * \details \copydetails tj3LoadImage8() + */ +DLLEXPORT unsigned short *tj3LoadImage16(tjhandle handle, const char *filename, + int *width, int align, int *height, + int *pixelFormat); + + +/** + * Save an 8-bit-per-sample packed-pixel image from memory to disk. + * + * @param handle handle to a TurboJPEG instance + * + * @param filename name of a file to which to save the packed-pixel image. The + * image will be stored in Windows BMP or PBMPLUS (PPM/PGM) format, depending + * on the file extension. Windows BMP files require 8-bit-per-sample data + * precision. + * + * @param buffer pointer to a buffer containing a packed-pixel RGB, grayscale, + * or CMYK image to be saved + * + * @param width width (in pixels) of the packed-pixel image + * + * @param pitch samples per row in the packed-pixel image. Setting this + * parameter to 0 is the equivalent of setting it to + * width * #tjPixelSize[pixelFormat]. + * + * @param height height (in pixels) of the packed-pixel image + * + * @param pixelFormat pixel format of the packed-pixel image (see @ref TJPF + * "Pixel formats".) If this parameter is set to @ref TJPF_GRAY, then the + * image will be stored in PGM or 8-bit-per-pixel (indexed color) BMP format. + * Otherwise, the image will be stored in PPM or 24-bit-per-pixel BMP format. + * If this parameter is set to @ref TJPF_CMYK, then the CMYK pixels will be + * converted to RGB using a quick & dirty algorithm that is suitable only for + * testing purposes. (Proper conversion between CMYK and other formats + * requires a color management system.) + * + * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr().) + */ +DLLEXPORT int tj3SaveImage8(tjhandle handle, const char *filename, + const unsigned char *buffer, int width, int pitch, + int height, int pixelFormat); + +/** + * Save a 12-bit-per-sample packed-pixel image from memory to disk. + * + * \details \copydetails tj3SaveImage8() + */ +DLLEXPORT int tj3SaveImage12(tjhandle handle, const char *filename, + const short *buffer, int width, int pitch, + int height, int pixelFormat); + +/** + * Save a 16-bit-per-sample packed-pixel image from memory to disk. + * + * \details \copydetails tj3SaveImage8() + */ +DLLEXPORT int tj3SaveImage16(tjhandle handle, const char *filename, + const unsigned short *buffer, int width, + int pitch, int height, int pixelFormat); + + +/** + * Free a byte buffer previously allocated by TurboJPEG. You should always use + * this function to free JPEG destination buffer(s) that were automatically + * (re)allocated by the compression and transform functions or that were + * manually allocated using #tj3Alloc(). + * + * @param buffer address of the buffer to free. If the address is NULL, then + * this function has no effect. + * + * @see tj3Alloc() + */ +DLLEXPORT void tj3Free(void *buffer); + + +/** + * Returns a descriptive error message explaining why the last command failed. + * + * @param handle handle to a TurboJPEG instance, or NULL if the error was + * generated by a global function (but note that retrieving the error message + * for a global function is thread-safe only on platforms that support + * thread-local storage.) + * + * @return a descriptive error message explaining why the last command failed. + */ +DLLEXPORT char *tj3GetErrorStr(tjhandle handle); + + +/** + * Returns a code indicating the severity of the last error. See + * @ref TJERR "Error codes". + * + * @param handle handle to a TurboJPEG instance + * + * @return a code indicating the severity of the last error. See + * @ref TJERR "Error codes". + */ +DLLEXPORT int tj3GetErrorCode(tjhandle handle); + + +/* Backward compatibility functions and macros (nothing to see here) */ + +/* TurboJPEG 1.0+ */ + +#define NUMSUBOPT TJ_NUMSAMP +#define TJ_444 TJSAMP_444 +#define TJ_422 TJSAMP_422 +#define TJ_420 TJSAMP_420 +#define TJ_411 TJSAMP_420 +#define TJ_GRAYSCALE TJSAMP_GRAY + +#define TJ_BGR 1 +#define TJ_BOTTOMUP TJFLAG_BOTTOMUP +#define TJ_FORCEMMX TJFLAG_FORCEMMX +#define TJ_FORCESSE TJFLAG_FORCESSE +#define TJ_FORCESSE2 TJFLAG_FORCESSE2 +#define TJ_ALPHAFIRST 64 +#define TJ_FORCESSE3 TJFLAG_FORCESSE3 +#define TJ_FASTUPSAMPLE TJFLAG_FASTUPSAMPLE + +#define TJPAD(width) (((width) + 3) & (~3)) + +DLLEXPORT unsigned long TJBUFSIZE(int width, int height); + +DLLEXPORT int tjCompress(tjhandle handle, unsigned char *srcBuf, int width, + int pitch, int height, int pixelSize, + unsigned char *dstBuf, unsigned long *compressedSize, + int jpegSubsamp, int jpegQual, int flags); + +DLLEXPORT int tjDecompress(tjhandle handle, unsigned char *jpegBuf, + unsigned long jpegSize, unsigned char *dstBuf, + int width, int pitch, int height, int pixelSize, + int flags); + +DLLEXPORT int tjDecompressHeader(tjhandle handle, unsigned char *jpegBuf, + unsigned long jpegSize, int *width, + int *height); + +DLLEXPORT int tjDestroy(tjhandle handle); + +DLLEXPORT char *tjGetErrorStr(void); + +DLLEXPORT tjhandle tjInitCompress(void); + +DLLEXPORT tjhandle tjInitDecompress(void); + +/* TurboJPEG 1.1+ */ + +#define TJ_YUV 512 + +DLLEXPORT unsigned long TJBUFSIZEYUV(int width, int height, int jpegSubsamp); + +DLLEXPORT int tjDecompressHeader2(tjhandle handle, unsigned char *jpegBuf, + unsigned long jpegSize, int *width, + int *height, int *jpegSubsamp); + +DLLEXPORT int tjDecompressToYUV(tjhandle handle, unsigned char *jpegBuf, + unsigned long jpegSize, unsigned char *dstBuf, + int flags); + +DLLEXPORT int tjEncodeYUV(tjhandle handle, unsigned char *srcBuf, int width, + int pitch, int height, int pixelSize, + unsigned char *dstBuf, int subsamp, int flags); + +/* TurboJPEG 1.2+ */ + +#define TJFLAG_BOTTOMUP 2 +#define TJFLAG_FORCEMMX 8 +#define TJFLAG_FORCESSE 16 +#define TJFLAG_FORCESSE2 32 +#define TJFLAG_FORCESSE3 128 +#define TJFLAG_FASTUPSAMPLE 256 +#define TJFLAG_NOREALLOC 1024 + +DLLEXPORT unsigned char *tjAlloc(int bytes); + +DLLEXPORT unsigned long tjBufSize(int width, int height, int jpegSubsamp); + +DLLEXPORT unsigned long tjBufSizeYUV(int width, int height, int subsamp); + +DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf, + int width, int pitch, int height, int pixelFormat, + unsigned char **jpegBuf, unsigned long *jpegSize, + int jpegSubsamp, int jpegQual, int flags); + +DLLEXPORT int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf, + unsigned long jpegSize, unsigned char *dstBuf, + int width, int pitch, int height, int pixelFormat, + int flags); + +DLLEXPORT int tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, int width, + int pitch, int height, int pixelFormat, + unsigned char *dstBuf, int subsamp, int flags); + +DLLEXPORT void tjFree(unsigned char *buffer); + +DLLEXPORT tjscalingfactor *tjGetScalingFactors(int *numscalingfactors); + +DLLEXPORT tjhandle tjInitTransform(void); + +DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf, + unsigned long jpegSize, int n, + unsigned char **dstBufs, unsigned long *dstSizes, + tjtransform *transforms, int flags); + +/* TurboJPEG 1.2.1+ */ + +#define TJFLAG_FASTDCT 2048 +#define TJFLAG_ACCURATEDCT 4096 + +/* TurboJPEG 1.4+ */ + +DLLEXPORT unsigned long tjBufSizeYUV2(int width, int align, int height, + int subsamp); + +DLLEXPORT int tjCompressFromYUV(tjhandle handle, const unsigned char *srcBuf, + int width, int align, int height, int subsamp, + unsigned char **jpegBuf, + unsigned long *jpegSize, int jpegQual, + int flags); + +DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle, + const unsigned char **srcPlanes, + int width, const int *strides, + int height, int subsamp, + unsigned char **jpegBuf, + unsigned long *jpegSize, int jpegQual, + int flags); + +DLLEXPORT int tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf, + int align, int subsamp, unsigned char *dstBuf, + int width, int pitch, int height, int pixelFormat, + int flags); + +DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle, + const unsigned char **srcPlanes, + const int *strides, int subsamp, + unsigned char *dstBuf, int width, int pitch, + int height, int pixelFormat, int flags); + +DLLEXPORT int tjDecompressHeader3(tjhandle handle, + const unsigned char *jpegBuf, + unsigned long jpegSize, int *width, + int *height, int *jpegSubsamp, + int *jpegColorspace); + +DLLEXPORT int tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf, + unsigned long jpegSize, unsigned char *dstBuf, + int width, int align, int height, int flags); + +DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle, + const unsigned char *jpegBuf, + unsigned long jpegSize, + unsigned char **dstPlanes, int width, + int *strides, int height, int flags); + +DLLEXPORT int tjEncodeYUV3(tjhandle handle, const unsigned char *srcBuf, + int width, int pitch, int height, int pixelFormat, + unsigned char *dstBuf, int align, int subsamp, + int flags); + +DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf, + int width, int pitch, int height, + int pixelFormat, unsigned char **dstPlanes, + int *strides, int subsamp, int flags); + +DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp); + +DLLEXPORT unsigned long tjPlaneSizeYUV(int componentID, int width, int stride, + int height, int subsamp); + +DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp); + +/* TurboJPEG 2.0+ */ + +#define TJFLAG_STOPONWARNING 8192 +#define TJFLAG_PROGRESSIVE 16384 + +DLLEXPORT int tjGetErrorCode(tjhandle handle); + +DLLEXPORT char *tjGetErrorStr2(tjhandle handle); + +DLLEXPORT unsigned char *tjLoadImage(const char *filename, int *width, + int align, int *height, int *pixelFormat, + int flags); + +DLLEXPORT int tjSaveImage(const char *filename, unsigned char *buffer, + int width, int pitch, int height, int pixelFormat, + int flags); + +/* TurboJPEG 2.1+ */ + +#define TJFLAG_LIMITSCANS 32768 + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/allocator.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/allocator.h new file mode 100644 index 0000000..3a5ebca --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/allocator.h @@ -0,0 +1,448 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_ALLOCATOR_H +#define NCNN_ALLOCATOR_H + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include "platform.h" + +#include + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +#include +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +// the alignment of all the allocated buffers +#if NCNN_AVX512 +#define NCNN_MALLOC_ALIGN 64 +#elif NCNN_AVX +#define NCNN_MALLOC_ALIGN 32 +#else +#define NCNN_MALLOC_ALIGN 16 +#endif + +// we have some optimized kernels that may overread buffer a bit in loop +// it is common to interleave next-loop data load with arithmetic instructions +// allocating more bytes keeps us safe from SEGV_ACCERR failure +#define NCNN_MALLOC_OVERREAD 64 + +// Aligns a pointer to the specified number of bytes +// ptr Aligned pointer +// n Alignment size that must be a power of two +template +static NCNN_FORCEINLINE _Tp* alignPtr(_Tp* ptr, int n = (int)sizeof(_Tp)) +{ + return (_Tp*)(((size_t)ptr + n - 1) & -n); +} + +// Aligns a buffer size to the specified number of bytes +// The function returns the minimum number that is greater or equal to sz and is divisible by n +// sz Buffer size to align +// n Alignment size that must be a power of two +static NCNN_FORCEINLINE size_t alignSize(size_t sz, int n) +{ + return (sz + n - 1) & -n; +} + +static NCNN_FORCEINLINE void* fastMalloc(size_t size) +{ +#if _MSC_VER + return _aligned_malloc(size, NCNN_MALLOC_ALIGN); +#elif (defined(__unix__) || defined(__APPLE__)) && _POSIX_C_SOURCE >= 200112L || (__ANDROID__ && __ANDROID_API__ >= 17) + void* ptr = 0; + if (posix_memalign(&ptr, NCNN_MALLOC_ALIGN, size + NCNN_MALLOC_OVERREAD)) + ptr = 0; + return ptr; +#elif __ANDROID__ && __ANDROID_API__ < 17 + return memalign(NCNN_MALLOC_ALIGN, size + NCNN_MALLOC_OVERREAD); +#else + unsigned char* udata = (unsigned char*)malloc(size + sizeof(void*) + NCNN_MALLOC_ALIGN + NCNN_MALLOC_OVERREAD); + if (!udata) + return 0; + unsigned char** adata = alignPtr((unsigned char**)udata + 1, NCNN_MALLOC_ALIGN); + adata[-1] = udata; + return adata; +#endif +} + +static NCNN_FORCEINLINE void fastFree(void* ptr) +{ + if (ptr) + { +#if _MSC_VER + _aligned_free(ptr); +#elif (defined(__unix__) || defined(__APPLE__)) && _POSIX_C_SOURCE >= 200112L || (__ANDROID__ && __ANDROID_API__ >= 17) + free(ptr); +#elif __ANDROID__ && __ANDROID_API__ < 17 + free(ptr); +#else + unsigned char* udata = ((unsigned char**)ptr)[-1]; + free(udata); +#endif + } +} + +#if NCNN_THREADS +// exchange-add operation for atomic operations on reference counters +#if defined __riscv && !defined __riscv_atomic +// riscv target without A extension +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#elif defined __INTEL_COMPILER && !(defined WIN32 || defined _WIN32) +// atomic increment on the linux version of the Intel(tm) compiler +#define NCNN_XADD(addr, delta) (int)_InterlockedExchangeAdd(const_cast(reinterpret_cast(addr)), delta) +#elif defined __GNUC__ +#if defined __clang__ && __clang_major__ >= 3 && !defined __ANDROID__ && !defined __EMSCRIPTEN__ && !defined(__CUDACC__) +#ifdef __ATOMIC_ACQ_REL +#define NCNN_XADD(addr, delta) __c11_atomic_fetch_add((_Atomic(int)*)(addr), delta, __ATOMIC_ACQ_REL) +#else +#define NCNN_XADD(addr, delta) __atomic_fetch_add((_Atomic(int)*)(addr), delta, 4) +#endif +#else +#if defined __ATOMIC_ACQ_REL && !defined __clang__ +// version for gcc >= 4.7 +#define NCNN_XADD(addr, delta) (int)__atomic_fetch_add((unsigned*)(addr), (unsigned)(delta), __ATOMIC_ACQ_REL) +#else +#define NCNN_XADD(addr, delta) (int)__sync_fetch_and_add((unsigned*)(addr), (unsigned)(delta)) +#endif +#endif +#elif defined _MSC_VER && !defined RC_INVOKED +#define NCNN_XADD(addr, delta) (int)_InterlockedExchangeAdd((long volatile*)addr, delta) +#else +// thread-unsafe branch +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#endif +#else // NCNN_THREADS +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#endif // NCNN_THREADS + +class NCNN_EXPORT Allocator +{ +public: + virtual ~Allocator(); + virtual void* fastMalloc(size_t size) = 0; + virtual void fastFree(void* ptr) = 0; +}; + +class PoolAllocatorPrivate; +class NCNN_EXPORT PoolAllocator : public Allocator +{ +public: + PoolAllocator(); + ~PoolAllocator(); + + // ratio range 0 ~ 1 + // default cr = 0 + void set_size_compare_ratio(float scr); + + // budget drop threshold + // default threshold = 10 + void set_size_drop_threshold(size_t); + + // release all budgets immediately + void clear(); + + virtual void* fastMalloc(size_t size); + virtual void fastFree(void* ptr); + +private: + PoolAllocator(const PoolAllocator&); + PoolAllocator& operator=(const PoolAllocator&); + +private: + PoolAllocatorPrivate* const d; +}; + +class UnlockedPoolAllocatorPrivate; +class NCNN_EXPORT UnlockedPoolAllocator : public Allocator +{ +public: + UnlockedPoolAllocator(); + ~UnlockedPoolAllocator(); + + // ratio range 0 ~ 1 + // default cr = 0 + void set_size_compare_ratio(float scr); + + // budget drop threshold + // default threshold = 10 + void set_size_drop_threshold(size_t); + + // release all budgets immediately + void clear(); + + virtual void* fastMalloc(size_t size); + virtual void fastFree(void* ptr); + +private: + UnlockedPoolAllocator(const UnlockedPoolAllocator&); + UnlockedPoolAllocator& operator=(const UnlockedPoolAllocator&); + +private: + UnlockedPoolAllocatorPrivate* const d; +}; + +#if NCNN_VULKAN + +class VulkanDevice; + +class NCNN_EXPORT VkBufferMemory +{ +public: + VkBuffer buffer; + + // the base offset assigned by allocator + size_t offset; + size_t capacity; + + VkDeviceMemory memory; + void* mapped_ptr; + + // buffer state, modified by command functions internally + mutable VkAccessFlags access_flags; + mutable VkPipelineStageFlags stage_flags; + + // initialize and modified by mat + int refcount; +}; + +class NCNN_EXPORT VkImageMemory +{ +public: + VkImage image; + VkImageView imageview; + + // underlying info assigned by allocator + int width; + int height; + int depth; + VkFormat format; + + VkDeviceMemory memory; + void* mapped_ptr; + + // the base offset assigned by allocator + size_t bind_offset; + size_t bind_capacity; + + // image state, modified by command functions internally + mutable VkAccessFlags access_flags; + mutable VkImageLayout image_layout; + mutable VkPipelineStageFlags stage_flags; + + // in-execution state, modified by command functions internally + mutable int command_refcount; + + // initialize and modified by mat + int refcount; +}; + +class NCNN_EXPORT VkAllocator +{ +public: + explicit VkAllocator(const VulkanDevice* _vkdev); + virtual ~VkAllocator(); + + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size) = 0; + virtual void fastFree(VkBufferMemory* ptr) = 0; + virtual int flush(VkBufferMemory* ptr); + virtual int invalidate(VkBufferMemory* ptr); + + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack) = 0; + virtual void fastFree(VkImageMemory* ptr) = 0; + +public: + const VulkanDevice* vkdev; + uint32_t buffer_memory_type_index; + uint32_t image_memory_type_index; + uint32_t reserved_type_index; + bool mappable; + bool coherent; + +protected: + VkBuffer create_buffer(size_t size, VkBufferUsageFlags usage); + VkDeviceMemory allocate_memory(size_t size, uint32_t memory_type_index); + VkDeviceMemory allocate_dedicated_memory(size_t size, uint32_t memory_type_index, VkImage image, VkBuffer buffer); + + VkImage create_image(int width, int height, int depth, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage); + VkImageView create_imageview(VkImage image, VkFormat format); +}; + +class VkBlobAllocatorPrivate; +class NCNN_EXPORT VkBlobAllocator : public VkAllocator +{ +public: + explicit VkBlobAllocator(const VulkanDevice* vkdev, size_t preferred_block_size = 16 * 1024 * 1024); // 16M + virtual ~VkBlobAllocator(); + +public: + // release all budgets immediately + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkBlobAllocator(const VkBlobAllocator&); + VkBlobAllocator& operator=(const VkBlobAllocator&); + +private: + VkBlobAllocatorPrivate* const d; +}; + +class VkWeightAllocatorPrivate; +class NCNN_EXPORT VkWeightAllocator : public VkAllocator +{ +public: + explicit VkWeightAllocator(const VulkanDevice* vkdev, size_t preferred_block_size = 8 * 1024 * 1024); // 8M + virtual ~VkWeightAllocator(); + +public: + // release all blocks immediately + virtual void clear(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkWeightAllocator(const VkWeightAllocator&); + VkWeightAllocator& operator=(const VkWeightAllocator&); + +private: + VkWeightAllocatorPrivate* const d; +}; + +class VkStagingAllocatorPrivate; +class NCNN_EXPORT VkStagingAllocator : public VkAllocator +{ +public: + explicit VkStagingAllocator(const VulkanDevice* vkdev); + virtual ~VkStagingAllocator(); + +public: + // ratio range 0 ~ 1 + // default cr = 0.75 + void set_size_compare_ratio(float scr); + + // release all budgets immediately + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkStagingAllocator(const VkStagingAllocator&); + VkStagingAllocator& operator=(const VkStagingAllocator&); + +private: + VkStagingAllocatorPrivate* const d; +}; + +class VkWeightStagingAllocatorPrivate; +class NCNN_EXPORT VkWeightStagingAllocator : public VkAllocator +{ +public: + explicit VkWeightStagingAllocator(const VulkanDevice* vkdev); + virtual ~VkWeightStagingAllocator(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkWeightStagingAllocator(const VkWeightStagingAllocator&); + VkWeightStagingAllocator& operator=(const VkWeightStagingAllocator&); + +private: + VkWeightStagingAllocatorPrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class NCNN_EXPORT VkAndroidHardwareBufferImageAllocator : public VkAllocator +{ +public: + VkAndroidHardwareBufferImageAllocator(const VulkanDevice* _vkdev, AHardwareBuffer* _hb); + virtual ~VkAndroidHardwareBufferImageAllocator(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkAndroidHardwareBufferImageAllocator(const VkAndroidHardwareBufferImageAllocator&); + VkAndroidHardwareBufferImageAllocator& operator=(const VkAndroidHardwareBufferImageAllocator&); + +public: + int init(); + + int width() const; + int height() const; + uint64_t external_format() const; + +public: + AHardwareBuffer* hb; + AHardwareBuffer_Desc bufferDesc; + VkAndroidHardwareBufferFormatPropertiesANDROID bufferFormatProperties; + VkAndroidHardwareBufferPropertiesANDROID bufferProperties; + VkSamplerYcbcrConversionKHR samplerYcbcrConversion; +}; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_ALLOCATOR_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/benchmark.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/benchmark.h new file mode 100644 index 0000000..3d5c0cd --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/benchmark.h @@ -0,0 +1,36 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_BENCHMARK_H +#define NCNN_BENCHMARK_H + +#include "layer.h" +#include "mat.h" +#include "platform.h" + +namespace ncnn { + +// get now timestamp in ms +NCNN_EXPORT double get_current_time(); + +#if NCNN_BENCHMARK + +NCNN_EXPORT void benchmark(const Layer* layer, double start, double end); +NCNN_EXPORT void benchmark(const Layer* layer, const Mat& bottom_blob, Mat& top_blob, double start, double end); + +#endif // NCNN_BENCHMARK + +} // namespace ncnn + +#endif // NCNN_BENCHMARK_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/blob.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/blob.h new file mode 100644 index 0000000..c9f144f --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/blob.h @@ -0,0 +1,44 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_BLOB_H +#define NCNN_BLOB_H + +#include "mat.h" +#include "platform.h" + +namespace ncnn { + +class NCNN_EXPORT Blob +{ +public: + // empty + Blob(); + +public: +#if NCNN_STRING + // blob name + std::string name; +#endif // NCNN_STRING + // layer index which produce this blob as output + int producer; + // layer index which need this blob as input + int consumer; + // shape hint + Mat shape; +}; + +} // namespace ncnn + +#endif // NCNN_BLOB_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/c_api.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/c_api.h new file mode 100644 index 0000000..b7435f8 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/c_api.h @@ -0,0 +1,327 @@ +/* Tencent is pleased to support the open source community by making ncnn available. + * + * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef NCNN_C_API_H +#define NCNN_C_API_H + +#include "platform.h" + +#if NCNN_C_API + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +NCNN_EXPORT const char* ncnn_version(); + +/* allocator api */ +typedef struct __ncnn_allocator_t* ncnn_allocator_t; +struct NCNN_EXPORT __ncnn_allocator_t +{ + void* pthis; + + void* (*fast_malloc)(ncnn_allocator_t allocator, size_t size); + void (*fast_free)(ncnn_allocator_t allocator, void* ptr); +}; + +NCNN_EXPORT ncnn_allocator_t ncnn_allocator_create_pool_allocator(); +NCNN_EXPORT ncnn_allocator_t ncnn_allocator_create_unlocked_pool_allocator(); +NCNN_EXPORT void ncnn_allocator_destroy(ncnn_allocator_t allocator); + +/* option api */ +typedef struct __ncnn_option_t* ncnn_option_t; + +NCNN_EXPORT ncnn_option_t ncnn_option_create(); +NCNN_EXPORT void ncnn_option_destroy(ncnn_option_t opt); + +NCNN_EXPORT int ncnn_option_get_num_threads(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_num_threads(ncnn_option_t opt, int num_threads); + +NCNN_EXPORT int ncnn_option_get_use_local_pool_allocator(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_use_local_pool_allocator(ncnn_option_t opt, int use_local_pool_allocator); + +NCNN_EXPORT void ncnn_option_set_blob_allocator(ncnn_option_t opt, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_option_set_workspace_allocator(ncnn_option_t opt, ncnn_allocator_t allocator); + +NCNN_EXPORT int ncnn_option_get_use_vulkan_compute(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_use_vulkan_compute(ncnn_option_t opt, int use_vulkan_compute); + +/* mat api */ +typedef struct __ncnn_mat_t* ncnn_mat_t; + +NCNN_EXPORT ncnn_mat_t ncnn_mat_create(); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_1d(int w, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_2d(int w, int h, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_3d(int w, int h, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_4d(int w, int h, int d, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_1d(int w, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_2d(int w, int h, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_3d(int w, int h, int c, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_4d(int w, int h, int d, int c, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_1d_elem(int w, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_2d_elem(int w, int h, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_3d_elem(int w, int h, int c, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_4d_elem(int w, int h, int d, int c, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_1d_elem(int w, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_2d_elem(int w, int h, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_3d_elem(int w, int h, int c, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_4d_elem(int w, int h, int d, int c, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_mat_destroy(ncnn_mat_t mat); + +NCNN_EXPORT void ncnn_mat_fill_float(ncnn_mat_t mat, float v); + +NCNN_EXPORT ncnn_mat_t ncnn_mat_clone(const ncnn_mat_t mat, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_1d(const ncnn_mat_t mat, int w, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_2d(const ncnn_mat_t mat, int w, int h, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_3d(const ncnn_mat_t mat, int w, int h, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_4d(const ncnn_mat_t mat, int w, int h, int d, int c, ncnn_allocator_t allocator); + +NCNN_EXPORT int ncnn_mat_get_dims(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_w(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_h(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_d(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_c(const ncnn_mat_t mat); +NCNN_EXPORT size_t ncnn_mat_get_elemsize(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_elempack(const ncnn_mat_t mat); +NCNN_EXPORT size_t ncnn_mat_get_cstep(const ncnn_mat_t mat); +NCNN_EXPORT void* ncnn_mat_get_data(const ncnn_mat_t mat); + +NCNN_EXPORT void* ncnn_mat_get_channel_data(const ncnn_mat_t mat, int c); + +#if NCNN_PIXEL + +/* mat pixel api */ +#define NCNN_MAT_PIXEL_RGB 1 +#define NCNN_MAT_PIXEL_BGR 2 +#define NCNN_MAT_PIXEL_GRAY 3 +#define NCNN_MAT_PIXEL_RGBA 4 +#define NCNN_MAT_PIXEL_BGRA 5 +#define NCNN_MAT_PIXEL_X2Y(X, Y) (X | (Y << 16)) +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels(const unsigned char* pixels, int type, int w, int h, int stride, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, int target_width, int target_height, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_mat_to_pixels(const ncnn_mat_t mat, unsigned char* pixels, int type, int stride); +NCNN_EXPORT void ncnn_mat_to_pixels_resize(const ncnn_mat_t mat, unsigned char* pixels, int type, int target_width, int target_height, int target_stride); + +#endif /* NCNN_PIXEL */ + +NCNN_EXPORT void ncnn_mat_substract_mean_normalize(ncnn_mat_t mat, const float* mean_vals, const float* norm_vals); + +NCNN_EXPORT void ncnn_convert_packing(const ncnn_mat_t src, ncnn_mat_t* dst, int elempack, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_flatten(const ncnn_mat_t src, ncnn_mat_t* dst, const ncnn_option_t opt); + +/* blob api */ +typedef struct __ncnn_blob_t* ncnn_blob_t; + +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_blob_get_name(const ncnn_blob_t blob); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_blob_get_producer(const ncnn_blob_t blob); +NCNN_EXPORT int ncnn_blob_get_consumer(const ncnn_blob_t blob); + +NCNN_EXPORT void ncnn_blob_get_shape(const ncnn_blob_t blob, int* dims, int* w, int* h, int* c); + +/* paramdict api */ +typedef struct __ncnn_paramdict_t* ncnn_paramdict_t; + +NCNN_EXPORT ncnn_paramdict_t ncnn_paramdict_create(); +NCNN_EXPORT void ncnn_paramdict_destroy(ncnn_paramdict_t pd); + +NCNN_EXPORT int ncnn_paramdict_get_type(const ncnn_paramdict_t pd, int id); + +NCNN_EXPORT int ncnn_paramdict_get_int(const ncnn_paramdict_t pd, int id, int def); +NCNN_EXPORT float ncnn_paramdict_get_float(const ncnn_paramdict_t pd, int id, float def); +NCNN_EXPORT ncnn_mat_t ncnn_paramdict_get_array(const ncnn_paramdict_t pd, int id, const ncnn_mat_t def); + +NCNN_EXPORT void ncnn_paramdict_set_int(ncnn_paramdict_t pd, int id, int i); +NCNN_EXPORT void ncnn_paramdict_set_float(ncnn_paramdict_t pd, int id, float f); +NCNN_EXPORT void ncnn_paramdict_set_array(ncnn_paramdict_t pd, int id, const ncnn_mat_t v); + +/* datareader api */ +typedef struct __ncnn_datareader_t* ncnn_datareader_t; +struct NCNN_EXPORT __ncnn_datareader_t +{ + void* pthis; + +#if NCNN_STRING + int (*scan)(ncnn_datareader_t dr, const char* format, void* p); +#endif /* NCNN_STRING */ + size_t (*read)(ncnn_datareader_t dr, void* buf, size_t size); +}; + +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create(); +#if NCNN_STDIO +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create_from_stdio(FILE* fp); +#endif /* NCNN_STDIO */ +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create_from_memory(const unsigned char** mem); +NCNN_EXPORT void ncnn_datareader_destroy(ncnn_datareader_t dr); + +/* modelbin api */ +typedef struct __ncnn_modelbin_t* ncnn_modelbin_t; +struct NCNN_EXPORT __ncnn_modelbin_t +{ + void* pthis; + + ncnn_mat_t (*load_1d)(const ncnn_modelbin_t mb, int w, int type); + ncnn_mat_t (*load_2d)(const ncnn_modelbin_t mb, int w, int h, int type); + ncnn_mat_t (*load_3d)(const ncnn_modelbin_t mb, int w, int h, int c, int type); +}; + +NCNN_EXPORT ncnn_modelbin_t ncnn_modelbin_create_from_datareader(const ncnn_datareader_t dr); +NCNN_EXPORT ncnn_modelbin_t ncnn_modelbin_create_from_mat_array(const ncnn_mat_t* weights, int n); +NCNN_EXPORT void ncnn_modelbin_destroy(ncnn_modelbin_t mb); + +/* layer api */ +typedef struct __ncnn_layer_t* ncnn_layer_t; +struct NCNN_EXPORT __ncnn_layer_t +{ + void* pthis; + + int (*load_param)(ncnn_layer_t layer, const ncnn_paramdict_t pd); + int (*load_model)(ncnn_layer_t layer, const ncnn_modelbin_t mb); + + int (*create_pipeline)(ncnn_layer_t layer, const ncnn_option_t opt); + int (*destroy_pipeline)(ncnn_layer_t layer, const ncnn_option_t opt); + + int (*forward_1)(const ncnn_layer_t layer, const ncnn_mat_t bottom_blob, ncnn_mat_t* top_blob, const ncnn_option_t opt); + int (*forward_n)(const ncnn_layer_t layer, const ncnn_mat_t* bottom_blobs, int n, ncnn_mat_t* top_blobs, int n2, const ncnn_option_t opt); + + int (*forward_inplace_1)(const ncnn_layer_t layer, ncnn_mat_t bottom_top_blob, const ncnn_option_t opt); + int (*forward_inplace_n)(const ncnn_layer_t layer, ncnn_mat_t* bottom_top_blobs, int n, const ncnn_option_t opt); +}; + +NCNN_EXPORT ncnn_layer_t ncnn_layer_create(); +NCNN_EXPORT ncnn_layer_t ncnn_layer_create_by_typeindex(int typeindex); +#if NCNN_STRING +NCNN_EXPORT ncnn_layer_t ncnn_layer_create_by_type(const char* type); +#endif /* NCNN_STRING */ +NCNN_EXPORT void ncnn_layer_destroy(ncnn_layer_t layer); + +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_layer_get_name(const ncnn_layer_t layer); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_layer_get_typeindex(const ncnn_layer_t layer); +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_layer_get_type(const ncnn_layer_t layer); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_layer_get_one_blob_only(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_inplace(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_vulkan(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_packing(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_bf16_storage(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_fp16_storage(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_image_storage(const ncnn_layer_t layer); + +NCNN_EXPORT void ncnn_layer_set_one_blob_only(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_inplace(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_vulkan(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_packing(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_bf16_storage(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_fp16_storage(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_image_storage(ncnn_layer_t layer, int enable); + +NCNN_EXPORT int ncnn_layer_get_bottom_count(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_bottom(const ncnn_layer_t layer, int i); +NCNN_EXPORT int ncnn_layer_get_top_count(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_top(const ncnn_layer_t layer, int i); + +NCNN_EXPORT void ncnn_blob_get_bottom_shape(const ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c); +NCNN_EXPORT void ncnn_blob_get_top_shape(const ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c); + +/* layer factory function */ +typedef ncnn_layer_t (*ncnn_layer_creator_t)(void* userdata); +typedef void (*ncnn_layer_destroyer_t)(ncnn_layer_t layer, void* userdata); + +typedef struct __ncnn_net_custom_layer_factory_t* ncnn_net_custom_layer_factory_t; +struct __ncnn_net_custom_layer_factory_t +{ + ncnn_layer_creator_t creator; + ncnn_layer_destroyer_t destroyer; + void* userdata; + ncnn_net_custom_layer_factory_t next; +}; + +/* net api */ +typedef struct __ncnn_net_t* ncnn_net_t; +struct __ncnn_net_t +{ + void* pthis; + + ncnn_net_custom_layer_factory_t custom_layer_factory; +}; + +NCNN_EXPORT ncnn_net_t ncnn_net_create(); +NCNN_EXPORT void ncnn_net_destroy(ncnn_net_t net); + +NCNN_EXPORT ncnn_option_t ncnn_net_get_option(ncnn_net_t net); +NCNN_EXPORT void ncnn_net_set_option(ncnn_net_t net, ncnn_option_t opt); + +#if NCNN_STRING +NCNN_EXPORT void ncnn_net_register_custom_layer_by_type(ncnn_net_t net, const char* type, ncnn_layer_creator_t creator, ncnn_layer_destroyer_t destroyer, void* userdata); +#endif /* NCNN_STRING */ +NCNN_EXPORT void ncnn_net_register_custom_layer_by_typeindex(ncnn_net_t net, int typeindex, ncnn_layer_creator_t creator, ncnn_layer_destroyer_t destroyer, void* userdata); + +#if NCNN_STDIO +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param(ncnn_net_t net, const char* path); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_load_param_bin(ncnn_net_t net, const char* path); +NCNN_EXPORT int ncnn_net_load_model(ncnn_net_t net, const char* path); +#endif /* NCNN_STDIO */ + +#if NCNN_STDIO +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param_memory(ncnn_net_t net, const char* mem); +#endif /* NCNN_STRING */ +#endif /* NCNN_STDIO */ +NCNN_EXPORT int ncnn_net_load_param_bin_memory(ncnn_net_t net, const unsigned char* mem); +NCNN_EXPORT int ncnn_net_load_model_memory(ncnn_net_t net, const unsigned char* mem); + +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param_datareader(ncnn_net_t net, const ncnn_datareader_t dr); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_load_param_bin_datareader(ncnn_net_t net, const ncnn_datareader_t dr); +NCNN_EXPORT int ncnn_net_load_model_datareader(ncnn_net_t net, const ncnn_datareader_t dr); + +NCNN_EXPORT void ncnn_net_clear(ncnn_net_t net); + +/* extractor api */ +typedef struct __ncnn_extractor_t* ncnn_extractor_t; + +NCNN_EXPORT ncnn_extractor_t ncnn_extractor_create(ncnn_net_t net); +NCNN_EXPORT void ncnn_extractor_destroy(ncnn_extractor_t ex); + +NCNN_EXPORT void ncnn_extractor_set_option(ncnn_extractor_t ex, const ncnn_option_t opt); + +#if NCNN_STRING +NCNN_EXPORT int ncnn_extractor_input(ncnn_extractor_t ex, const char* name, const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_extractor_extract(ncnn_extractor_t ex, const char* name, ncnn_mat_t* mat); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_extractor_input_index(ncnn_extractor_t ex, int index, const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_extractor_extract_index(ncnn_extractor_t ex, int index, ncnn_mat_t* mat); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* NCNN_C_API */ + +#endif /* NCNN_C_API_H */ diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/command.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/command.h new file mode 100644 index 0000000..337d085 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/command.h @@ -0,0 +1,136 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_COMMAND_H +#define NCNN_COMMAND_H + +#include "platform.h" + +#if NCNN_VULKAN + +#include "mat.h" + +#include + +namespace ncnn { + +class Pipeline; +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class ImportAndroidHardwareBufferPipeline; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API +class VkComputePrivate; +class NCNN_EXPORT VkCompute +{ +public: + explicit VkCompute(const VulkanDevice* vkdev); + virtual ~VkCompute(); + +public: + void record_upload(const Mat& src, VkMat& dst, const Option& opt); + + void record_upload(const Mat& src, VkImageMat& dst, const Option& opt); + + void record_download(const VkMat& src, Mat& dst, const Option& opt); + + void record_download(const VkImageMat& src, Mat& dst, const Option& opt); + + void record_buffer_to_image(const VkMat& src, VkImageMat& dst, const Option& opt); + + void record_image_to_buffer(const VkImageMat& src, VkMat& dst, const Option& opt); + + void record_clone(const Mat& src, VkMat& dst, const Option& opt); + + void record_clone(const Mat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkMat& src, Mat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, Mat& dst, const Option& opt); + + void record_clone(const VkMat& src, VkMat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkMat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, VkMat& dst, const Option& opt); + + void record_pipeline(const Pipeline* pipeline, const std::vector& bindings, const std::vector& constants, const VkMat& dispatcher); + + void record_pipeline(const Pipeline* pipeline, const std::vector& bindings, const std::vector& constants, const VkImageMat& dispatcher); + + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const VkMat& dispatcher); + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const VkImageMat& dispatcher); + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const Mat& dispatcher); + +#if NCNN_BENCHMARK + void record_write_timestamp(uint32_t query); +#endif // NCNN_BENCHMARK + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 + void record_import_android_hardware_buffer(const ImportAndroidHardwareBufferPipeline* pipeline, const VkImageMat& src, const VkMat& dst); + + void record_import_android_hardware_buffer(const ImportAndroidHardwareBufferPipeline* pipeline, const VkImageMat& src, const VkImageMat& dst); +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + + int submit_and_wait(); + + int reset(); + +#if NCNN_BENCHMARK + int create_query_pool(uint32_t query_count); + + int get_query_pool_results(uint32_t first_query, uint32_t query_count, std::vector& results); +#endif // NCNN_BENCHMARK + +protected: + const VulkanDevice* vkdev; + + void barrier_readwrite(const VkMat& binding); + void barrier_readwrite(const VkImageMat& binding); + void barrier_readonly(const VkImageMat& binding); + +private: + VkComputePrivate* const d; +}; + +class VkTransferPrivate; +class NCNN_EXPORT VkTransfer +{ +public: + explicit VkTransfer(const VulkanDevice* vkdev); + virtual ~VkTransfer(); + +public: + void record_upload(const Mat& src, VkMat& dst, const Option& opt, bool flatten = true); + + void record_upload(const Mat& src, VkImageMat& dst, const Option& opt); + + int submit_and_wait(); + +protected: + const VulkanDevice* vkdev; + +private: + VkTransferPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_VULKAN + +#endif // NCNN_COMMAND_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/cpu.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/cpu.h new file mode 100644 index 0000000..0f748f3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/cpu.h @@ -0,0 +1,169 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_CPU_H +#define NCNN_CPU_H + +#include + +#if (defined _WIN32 && !(defined __MINGW32__)) +#define WIN32_LEAN_AND_MEAN +#include +#endif +#if defined __ANDROID__ || defined __linux__ +#include // cpu_set_t +#endif + +#include "platform.h" + +namespace ncnn { + +class NCNN_EXPORT CpuSet +{ +public: + CpuSet(); + void enable(int cpu); + void disable(int cpu); + void disable_all(); + bool is_enabled(int cpu) const; + int num_enabled() const; + +public: +#if (defined _WIN32 && !(defined __MINGW32__)) + ULONG_PTR mask; +#endif +#if defined __ANDROID__ || defined __linux__ + cpu_set_t cpu_set; +#endif +#if __APPLE__ + unsigned int policy; +#endif +}; + +// test optional cpu features +// edsp = armv7 edsp +NCNN_EXPORT int cpu_support_arm_edsp(); +// neon = armv7 neon or aarch64 asimd +NCNN_EXPORT int cpu_support_arm_neon(); +// vfpv4 = armv7 fp16 + fma +NCNN_EXPORT int cpu_support_arm_vfpv4(); +// asimdhp = aarch64 asimd half precision +NCNN_EXPORT int cpu_support_arm_asimdhp(); +// asimddp = aarch64 asimd dot product +NCNN_EXPORT int cpu_support_arm_asimddp(); +// asimdfhm = aarch64 asimd fhm +NCNN_EXPORT int cpu_support_arm_asimdfhm(); +// bf16 = aarch64 bf16 +NCNN_EXPORT int cpu_support_arm_bf16(); +// i8mm = aarch64 i8mm +NCNN_EXPORT int cpu_support_arm_i8mm(); +// sve = aarch64 sve +NCNN_EXPORT int cpu_support_arm_sve(); +// sve2 = aarch64 sve2 +NCNN_EXPORT int cpu_support_arm_sve2(); +// svebf16 = aarch64 svebf16 +NCNN_EXPORT int cpu_support_arm_svebf16(); +// svei8mm = aarch64 svei8mm +NCNN_EXPORT int cpu_support_arm_svei8mm(); +// svef32mm = aarch64 svef32mm +NCNN_EXPORT int cpu_support_arm_svef32mm(); + +// avx = x86 avx +NCNN_EXPORT int cpu_support_x86_avx(); +// fma = x86 fma +NCNN_EXPORT int cpu_support_x86_fma(); +// xop = x86 xop +NCNN_EXPORT int cpu_support_x86_xop(); +// f16c = x86 f16c +NCNN_EXPORT int cpu_support_x86_f16c(); +// avx2 = x86 avx2 + fma + f16c +NCNN_EXPORT int cpu_support_x86_avx2(); +// avx_vnni = x86 avx vnni +NCNN_EXPORT int cpu_support_x86_avx_vnni(); +// avx512 = x86 avx512f + avx512cd + avx512bw + avx512dq + avx512vl +NCNN_EXPORT int cpu_support_x86_avx512(); +// avx512_vnni = x86 avx512 vnni +NCNN_EXPORT int cpu_support_x86_avx512_vnni(); +// avx512_bf16 = x86 avx512 bf16 +NCNN_EXPORT int cpu_support_x86_avx512_bf16(); +// avx512_fp16 = x86 avx512 fp16 +NCNN_EXPORT int cpu_support_x86_avx512_fp16(); + +// lsx = loongarch lsx +NCNN_EXPORT int cpu_support_loongarch_lsx(); +// lasx = loongarch lasx +NCNN_EXPORT int cpu_support_loongarch_lasx(); + +// msa = mips mas +NCNN_EXPORT int cpu_support_mips_msa(); +// mmi = loongson mmi +NCNN_EXPORT int cpu_support_loongson_mmi(); + +// v = riscv vector +NCNN_EXPORT int cpu_support_riscv_v(); +// zfh = riscv half-precision float +NCNN_EXPORT int cpu_support_riscv_zfh(); +// vlenb = riscv vector length in bytes +NCNN_EXPORT int cpu_riscv_vlenb(); + +// cpu info +NCNN_EXPORT int get_cpu_count(); +NCNN_EXPORT int get_little_cpu_count(); +NCNN_EXPORT int get_big_cpu_count(); + +NCNN_EXPORT int get_physical_cpu_count(); +NCNN_EXPORT int get_physical_little_cpu_count(); +NCNN_EXPORT int get_physical_big_cpu_count(); + +// bind all threads on little clusters if powersave enabled +// affects HMP arch cpu like ARM big.LITTLE +// only implemented on android at the moment +// switching powersave is expensive and not thread-safe +// 0 = all cores enabled(default) +// 1 = only little clusters enabled +// 2 = only big clusters enabled +// return 0 if success for setter function +NCNN_EXPORT int get_cpu_powersave(); +NCNN_EXPORT int set_cpu_powersave(int powersave); + +// convenient wrapper +NCNN_EXPORT const CpuSet& get_cpu_thread_affinity_mask(int powersave); + +// set explicit thread affinity +NCNN_EXPORT int set_cpu_thread_affinity(const CpuSet& thread_affinity_mask); + +// misc function wrapper for openmp routines +NCNN_EXPORT int get_omp_num_threads(); +NCNN_EXPORT void set_omp_num_threads(int num_threads); + +NCNN_EXPORT int get_omp_dynamic(); +NCNN_EXPORT void set_omp_dynamic(int dynamic); + +NCNN_EXPORT int get_omp_thread_num(); + +NCNN_EXPORT int get_kmp_blocktime(); +NCNN_EXPORT void set_kmp_blocktime(int time_ms); + +// need to flush denormals on Intel Chipset. +// Other architectures such as ARM can be added as needed. +// 0 = DAZ OFF, FTZ OFF +// 1 = DAZ ON , FTZ OFF +// 2 = DAZ OFF, FTZ ON +// 3 = DAZ ON, FTZ ON +NCNN_EXPORT int get_flush_denormals(); +NCNN_EXPORT int set_flush_denormals(int flush_denormals); + +} // namespace ncnn + +#endif // NCNN_CPU_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/datareader.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/datareader.h new file mode 100644 index 0000000..ed2aba3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/datareader.h @@ -0,0 +1,122 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_DATAREADER_H +#define NCNN_DATAREADER_H + +#include "platform.h" +#if NCNN_STDIO +#include +#endif + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#endif +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +// data read wrapper +class NCNN_EXPORT DataReader +{ +public: + DataReader(); + virtual ~DataReader(); + +#if NCNN_STRING + // parse plain param text + // return 1 if scan success + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + + // read binary param and model data + // return bytes read + virtual size_t read(void* buf, size_t size) const; + + // get model data reference + // return bytes referenced + virtual size_t reference(size_t size, const void** buf) const; +}; + +#if NCNN_STDIO +class DataReaderFromStdioPrivate; +class NCNN_EXPORT DataReaderFromStdio : public DataReader +{ +public: + explicit DataReaderFromStdio(FILE* fp); + virtual ~DataReaderFromStdio(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + +private: + DataReaderFromStdio(const DataReaderFromStdio&); + DataReaderFromStdio& operator=(const DataReaderFromStdio&); + +private: + DataReaderFromStdioPrivate* const d; +}; +#endif // NCNN_STDIO + +class DataReaderFromMemoryPrivate; +class NCNN_EXPORT DataReaderFromMemory : public DataReader +{ +public: + explicit DataReaderFromMemory(const unsigned char*& mem); + virtual ~DataReaderFromMemory(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + virtual size_t reference(size_t size, const void** buf) const; + +private: + DataReaderFromMemory(const DataReaderFromMemory&); + DataReaderFromMemory& operator=(const DataReaderFromMemory&); + +private: + DataReaderFromMemoryPrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +class DataReaderFromAndroidAssetPrivate; +class NCNN_EXPORT DataReaderFromAndroidAsset : public DataReader +{ +public: + explicit DataReaderFromAndroidAsset(AAsset* asset); + virtual ~DataReaderFromAndroidAsset(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + +private: + DataReaderFromAndroidAsset(const DataReaderFromAndroidAsset&); + DataReaderFromAndroidAsset& operator=(const DataReaderFromAndroidAsset&); + +private: + DataReaderFromAndroidAssetPrivate* const d; +}; +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + +} // namespace ncnn + +#endif // NCNN_DATAREADER_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/gpu.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/gpu.h new file mode 100644 index 0000000..2ef4927 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/gpu.h @@ -0,0 +1,359 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_GPU_H +#define NCNN_GPU_H + +#include "platform.h" + +#if NCNN_VULKAN + +#include "mat.h" + +#include + +#include "vulkan_header_fix.h" + +namespace ncnn { + +// instance +NCNN_EXPORT int create_gpu_instance(); +NCNN_EXPORT void destroy_gpu_instance(); + +// instance extension capability +extern int support_VK_KHR_external_memory_capabilities; +extern int support_VK_KHR_get_physical_device_properties2; +extern int support_VK_KHR_get_surface_capabilities2; +extern int support_VK_KHR_surface; +extern int support_VK_EXT_debug_utils; +#if __ANDROID_API__ >= 26 +extern int support_VK_KHR_android_surface; +#endif // __ANDROID_API__ >= 26 + +// VK_KHR_external_memory_capabilities +extern PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR vkGetPhysicalDeviceExternalBufferPropertiesKHR; + +// VK_KHR_get_physical_device_properties2 +extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; +extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; +extern PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceImageFormatProperties2KHR vkGetPhysicalDeviceImageFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR; +extern PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR; +extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR vkGetPhysicalDeviceSparseImageFormatProperties2KHR; + +// VK_KHR_get_surface_capabilities2 +extern PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR; + +// VK_KHR_surface +extern PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; +extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; +extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; +extern PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; + +#if __ANDROID_API__ >= 26 +// VK_KHR_android_surface +extern PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; +#endif // __ANDROID_API__ >= 26 + +// VK_NV_cooperative_matrix +extern PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV vkGetPhysicalDeviceCooperativeMatrixPropertiesNV; + +// get info +NCNN_EXPORT int get_gpu_count(); +NCNN_EXPORT int get_default_gpu_index(); + +class GpuInfoPrivate; +class NCNN_EXPORT GpuInfo +{ +public: + explicit GpuInfo(); + virtual ~GpuInfo(); + + // vulkan physical device + VkPhysicalDevice physical_device() const; + + // memory properties + const VkPhysicalDeviceMemoryProperties& physical_device_memory_properties() const; + + // info + uint32_t api_version() const; + uint32_t driver_version() const; + uint32_t vendor_id() const; + uint32_t device_id() const; + const char* device_name() const; + uint8_t* pipeline_cache_uuid() const; + + // 0 = discrete gpu + // 1 = integrated gpu + // 2 = virtual gpu + // 3 = cpu + int type() const; + + // hardware limit + uint32_t max_shared_memory_size() const; + uint32_t max_workgroup_count_x() const; + uint32_t max_workgroup_count_y() const; + uint32_t max_workgroup_count_z() const; + uint32_t max_workgroup_invocations() const; + uint32_t max_workgroup_size_x() const; + uint32_t max_workgroup_size_y() const; + uint32_t max_workgroup_size_z() const; + size_t memory_map_alignment() const; + size_t buffer_offset_alignment() const; + size_t non_coherent_atom_size() const; + size_t buffer_image_granularity() const; + uint32_t max_image_dimension_1d() const; + uint32_t max_image_dimension_2d() const; + uint32_t max_image_dimension_3d() const; + float timestamp_period() const; + + // runtime + uint32_t compute_queue_family_index() const; + uint32_t graphics_queue_family_index() const; + uint32_t transfer_queue_family_index() const; + + uint32_t compute_queue_count() const; + uint32_t graphics_queue_count() const; + uint32_t transfer_queue_count() const; + + // property + bool unified_compute_transfer_queue() const; + + // subgroup + uint32_t subgroup_size() const; + bool support_subgroup_basic() const; + bool support_subgroup_vote() const; + bool support_subgroup_ballot() const; + bool support_subgroup_shuffle() const; + + // bug is not feature + bool bug_storage_buffer_no_l1() const; + bool bug_corrupted_online_pipeline_cache() const; + bool bug_buffer_image_load_zero() const; + + // but sometimes bug is a feature + bool bug_implicit_fp16_arithmetic() const; + + // fp16 and int8 feature + bool support_fp16_packed() const; + bool support_fp16_storage() const; + bool support_fp16_arithmetic() const; + bool support_int8_packed() const; + bool support_int8_storage() const; + bool support_int8_arithmetic() const; + + // ycbcr conversion feature + bool support_ycbcr_conversion() const; + + // cooperative matrix feature + bool support_cooperative_matrix() const; + bool support_cooperative_matrix_16_8_8() const; + + // extension capability + int support_VK_KHR_8bit_storage() const; + int support_VK_KHR_16bit_storage() const; + int support_VK_KHR_bind_memory2() const; + int support_VK_KHR_create_renderpass2() const; + int support_VK_KHR_dedicated_allocation() const; + int support_VK_KHR_descriptor_update_template() const; + int support_VK_KHR_external_memory() const; + int support_VK_KHR_get_memory_requirements2() const; + int support_VK_KHR_maintenance1() const; + int support_VK_KHR_maintenance2() const; + int support_VK_KHR_maintenance3() const; + int support_VK_KHR_multiview() const; + int support_VK_KHR_push_descriptor() const; + int support_VK_KHR_sampler_ycbcr_conversion() const; + int support_VK_KHR_shader_float16_int8() const; + int support_VK_KHR_shader_float_controls() const; + int support_VK_KHR_storage_buffer_storage_class() const; + int support_VK_KHR_swapchain() const; + int support_VK_EXT_descriptor_indexing() const; + int support_VK_EXT_memory_budget() const; + int support_VK_EXT_queue_family_foreign() const; +#if __ANDROID_API__ >= 26 + int support_VK_ANDROID_external_memory_android_hardware_buffer() const; +#endif // __ANDROID_API__ >= 26 + int support_VK_NV_cooperative_matrix() const; + +private: + GpuInfo(const GpuInfo&); + GpuInfo& operator=(const GpuInfo&); + +private: + friend int create_gpu_instance(); + GpuInfoPrivate* const d; +}; + +NCNN_EXPORT const GpuInfo& get_gpu_info(int device_index = get_default_gpu_index()); + +class VkAllocator; +class VkCompute; +class Option; +class PipelineCache; +class VulkanDevicePrivate; +class NCNN_EXPORT VulkanDevice +{ +public: + VulkanDevice(int device_index = get_default_gpu_index()); + ~VulkanDevice(); + + const GpuInfo& info; + + VkDevice vkdevice() const; + + VkShaderModule compile_shader_module(const uint32_t* spv_data, size_t spv_data_size) const; + + // with fixed workgroup size + VkShaderModule compile_shader_module(const uint32_t* spv_data, size_t spv_data_size, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z) const; + + // helper for creating pipeline + int create_descriptorset_layout(int binding_count, const int* binding_types, VkDescriptorSetLayout* descriptorset_layout) const; + int create_pipeline_layout(int push_constant_count, VkDescriptorSetLayout descriptorset_layout, VkPipelineLayout* pipeline_layout) const; + int create_pipeline(VkShaderModule shader_module, VkPipelineLayout pipeline_layout, const std::vector& specializations, VkPipeline* pipeline) const; + int create_descriptor_update_template(int binding_count, const int* binding_types, VkDescriptorSetLayout descriptorset_layout, VkPipelineLayout pipeline_layout, VkDescriptorUpdateTemplateKHR* descriptor_update_template) const; + + uint32_t find_memory_index(uint32_t memory_type_bits, VkFlags required, VkFlags preferred, VkFlags preferred_not) const; + bool is_mappable(uint32_t memory_type_index) const; + bool is_coherent(uint32_t memory_type_index) const; + + VkQueue acquire_queue(uint32_t queue_family_index) const; + void reclaim_queue(uint32_t queue_family_index, VkQueue queue) const; + + // allocator on this device + VkAllocator* acquire_blob_allocator() const; + void reclaim_blob_allocator(VkAllocator* allocator) const; + + VkAllocator* acquire_staging_allocator() const; + void reclaim_staging_allocator(VkAllocator* allocator) const; + + // immutable sampler for texelfetch + const VkSampler* immutable_texelfetch_sampler() const; + + // dummy buffer image + VkMat get_dummy_buffer() const; + VkImageMat get_dummy_image() const; + VkImageMat get_dummy_image_readonly() const; + + // pipeline cache on this device + const PipelineCache* get_pipeline_cache() const; + + // test image allocation + bool shape_support_image_storage(const Mat& shape) const; + + // current gpu heap memory budget in MB + uint32_t get_heap_budget() const; + + // utility operator + void convert_packing(const VkMat& src, VkMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkImageMat& src, VkImageMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkMat& src, VkImageMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkImageMat& src, VkMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + + // VK_KHR_bind_memory2 + PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; + PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; + + // VK_KHR_create_renderpass2 + PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; + PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; + PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; + + // VK_KHR_descriptor_update_template + PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; + PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; + PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; + + // VK_KHR_get_memory_requirements2 + PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; + PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; + PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; + + // VK_KHR_maintenance1 + PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; + + // VK_KHR_maintenance3 + PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; + + // VK_KHR_push_descriptor + PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; + PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; + + // VK_KHR_sampler_ycbcr_conversion + PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; + PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; + + // VK_KHR_swapchain + PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; + PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; + PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; + PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; + PFN_vkQueuePresentKHR vkQueuePresentKHR; + +#if __ANDROID_API__ >= 26 + // VK_ANDROID_external_memory_android_hardware_buffer + PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; + PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; +#endif // __ANDROID_API__ >= 26 + +protected: + // device extension + int init_device_extension(); + +private: + VulkanDevice(const VulkanDevice&); + VulkanDevice& operator=(const VulkanDevice&); + +private: + VulkanDevicePrivate* const d; +}; + +NCNN_EXPORT VulkanDevice* get_gpu_device(int device_index = get_default_gpu_index()); + +// online spirv compilation +NCNN_EXPORT int compile_spirv_module(const char* comp_string, const Option& opt, std::vector& spirv); +NCNN_EXPORT int compile_spirv_module(const char* comp_data, int comp_data_size, const Option& opt, std::vector& spirv); +NCNN_EXPORT int compile_spirv_module(int shader_type_index, const Option& opt, std::vector& spirv); + +// info from spirv +class NCNN_EXPORT ShaderInfo +{ +public: + int specialization_count; + int binding_count; + int push_constant_count; + + // 0 = null + // 1 = storage buffer + // 2 = storage image + // 3 = combined image sampler + int binding_types[16]; // 16 is large enough I think ... + + int reserved_0; + int reserved_1; + int reserved_2; + int reserved_3; +}; + +NCNN_EXPORT int resolve_shader_info(const uint32_t* spv_data, size_t spv_data_size, ShaderInfo& shader_info); + +} // namespace ncnn + +#endif // NCNN_VULKAN + +#endif // NCNN_GPU_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/layer.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/layer.h new file mode 100644 index 0000000..d02f65b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/layer.h @@ -0,0 +1,214 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_H +#define NCNN_LAYER_H + +#include "mat.h" +#include "modelbin.h" +#include "option.h" +#include "paramdict.h" +#include "platform.h" + +#include + +#if NCNN_VULKAN +#include "command.h" +#include "pipeline.h" + +#include +#endif // NCNN_VULKAN + +namespace ncnn { + +class NCNN_EXPORT Layer +{ +public: + // empty + Layer(); + // virtual destructor + virtual ~Layer(); + + // load layer specific parameter from parsed dict + // return 0 if success + virtual int load_param(const ParamDict& pd); + + // load layer specific weight data from model binary + // return 0 if success + virtual int load_model(const ModelBin& mb); + + // layer implementation specific setup + // return 0 if success + virtual int create_pipeline(const Option& opt); + + // layer implementation specific clean + // return 0 if success + virtual int destroy_pipeline(const Option& opt); + +public: + // one input and one output blob + bool one_blob_only; + + // support inplace inference + bool support_inplace; + + // support vulkan compute + bool support_vulkan; + + // accept input blob with packed storage + bool support_packing; + + // accept bf16 + bool support_bf16_storage; + + // accept fp16 + bool support_fp16_storage; + + // accept int8 + bool support_int8_storage; + + // shader image storage + bool support_image_storage; + + // shader tensor storage + bool support_tensor_storage; + + bool support_reserved_00; + + bool support_reserved_0; + bool support_reserved_1; + bool support_reserved_2; + bool support_reserved_3; + bool support_reserved_4; + bool support_reserved_5; + bool support_reserved_6; + bool support_reserved_7; + bool support_reserved_8; + bool support_reserved_9; + + // feature disabled set + int featmask; + +public: + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, const Option& opt) const; + virtual int forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, const Option& opt) const; + virtual int forward_inplace(Mat& bottom_top_blob, const Option& opt) const; + +#if NCNN_VULKAN +public: + // upload weight blob from host to device + virtual int upload_model(VkTransfer& cmd, const Option& opt); + +public: + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward_inplace(VkMat& bottom_top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward_inplace(VkImageMat& bottom_top_blob, VkCompute& cmd, const Option& opt) const; + +public: + // assigned immediately after creating this layer + const VulkanDevice* vkdev; +#endif // NCNN_VULKAN + +public: + // custom user data + void* userdata; + // layer type index + int typeindex; +#if NCNN_STRING + // layer type name + std::string type; + // layer name + std::string name; +#endif // NCNN_STRING + // blob index which this layer needs as input + std::vector bottoms; + // blob index which this layer produces as output + std::vector tops; + // shape hint + std::vector bottom_shapes; + std::vector top_shapes; +}; + +// layer factory function +typedef Layer* (*layer_creator_func)(void*); +typedef void (*layer_destroyer_func)(Layer*, void*); + +struct layer_registry_entry +{ +#if NCNN_STRING + // layer type name + const char* name; +#endif // NCNN_STRING + // layer factory entry + layer_creator_func creator; +}; + +struct custom_layer_registry_entry +{ +#if NCNN_STRING + // layer type name + const char* name; +#endif // NCNN_STRING + // layer factory entry + layer_creator_func creator; + layer_destroyer_func destroyer; + void* userdata; +}; + +#if NCNN_STRING +// get layer type from type name +NCNN_EXPORT int layer_to_index(const char* type); +// create layer from type name +NCNN_EXPORT Layer* create_layer(const char* type); +#endif // NCNN_STRING +// create layer from layer type +NCNN_EXPORT Layer* create_layer(int index); + +#define DEFINE_LAYER_CREATOR(name) \ + ::ncnn::Layer* name##_layer_creator(void* /*userdata*/) \ + { \ + return new name; \ + } + +#define DEFINE_LAYER_DESTROYER(name) \ + void name##_layer_destroyer(::ncnn::Layer* layer, void* /*userdata*/) \ + { \ + delete layer; \ + } + +} // namespace ncnn + +#endif // NCNN_LAYER_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/layer_shader_type.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/layer_shader_type.h new file mode 100644 index 0000000..c143e7d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/layer_shader_type.h @@ -0,0 +1,29 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_SHADER_TYPE_H +#define NCNN_LAYER_SHADER_TYPE_H + +namespace ncnn { + +namespace LayerShaderType { +enum LayerShaderType +{ +#include "layer_shader_type_enum.h" +}; +} // namespace LayerShaderType + +} // namespace ncnn + +#endif // NCNN_LAYER_SHADER_TYPE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/layer_shader_type_enum.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/layer_shader_type_enum.h new file mode 100644 index 0000000..f11cab9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/layer_shader_type_enum.h @@ -0,0 +1,370 @@ +// Layer Shader Enum header +// +// This file is auto-generated by cmake, don't edit it. + +absval = 0, +absval_pack4 = 1, +absval_pack8 = 2, +batchnorm = 3, +batchnorm_pack4 = 4, +batchnorm_pack8 = 5, +concat = 6, +concat_pack4 = 7, +concat_pack4to1 = 8, +concat_pack8 = 9, +concat_pack8to1 = 10, +concat_pack8to4 = 11, +convolution = 12, +convolution_1x1s1d1 = 13, +convolution_3x3s1d1_winograd23_transform_input = 14, +convolution_3x3s1d1_winograd23_transform_output = 15, +convolution_3x3s1d1_winograd43_transform_input = 16, +convolution_3x3s1d1_winograd43_transform_output = 17, +convolution_3x3s1d1_winograd_gemm = 18, +convolution_gemm = 19, +convolution_pack1to4 = 20, +convolution_pack1to4_1x1s1d1 = 21, +convolution_pack1to4_3x3s1d1_winograd_gemm = 22, +convolution_pack1to4_gemm = 23, +convolution_pack1to8 = 24, +convolution_pack1to8_1x1s1d1 = 25, +convolution_pack1to8_3x3s1d1_winograd_gemm = 26, +convolution_pack1to8_gemm = 27, +convolution_pack4 = 28, +convolution_pack4_1x1s1d1 = 29, +convolution_pack4_1x1s1d1_cm_16_8_8 = 30, +convolution_pack4_3x3s1d1_winograd23_transform_input = 31, +convolution_pack4_3x3s1d1_winograd23_transform_output = 32, +convolution_pack4_3x3s1d1_winograd43_transform_input = 33, +convolution_pack4_3x3s1d1_winograd43_transform_output = 34, +convolution_pack4_3x3s1d1_winograd_gemm = 35, +convolution_pack4_3x3s1d1_winograd_gemm_cm_16_8_8 = 36, +convolution_pack4_gemm = 37, +convolution_pack4_gemm_cm_16_8_8 = 38, +convolution_pack4to1 = 39, +convolution_pack4to1_1x1s1d1 = 40, +convolution_pack4to1_3x3s1d1_winograd_gemm = 41, +convolution_pack4to1_gemm = 42, +convolution_pack4to8 = 43, +convolution_pack4to8_1x1s1d1 = 44, +convolution_pack4to8_3x3s1d1_winograd_gemm = 45, +convolution_pack4to8_gemm = 46, +convolution_pack8 = 47, +convolution_pack8_1x1s1d1 = 48, +convolution_pack8_3x3s1d1_winograd23_transform_input = 49, +convolution_pack8_3x3s1d1_winograd23_transform_output = 50, +convolution_pack8_3x3s1d1_winograd43_transform_input = 51, +convolution_pack8_3x3s1d1_winograd43_transform_output = 52, +convolution_pack8_3x3s1d1_winograd_gemm = 53, +convolution_pack8_gemm = 54, +convolution_pack8to1 = 55, +convolution_pack8to1_1x1s1d1 = 56, +convolution_pack8to1_3x3s1d1_winograd_gemm = 57, +convolution_pack8to1_gemm = 58, +convolution_pack8to4 = 59, +convolution_pack8to4_1x1s1d1 = 60, +convolution_pack8to4_3x3s1d1_winograd_gemm = 61, +convolution_pack8to4_gemm = 62, +crop = 63, +crop_pack1to4 = 64, +crop_pack1to8 = 65, +crop_pack4 = 66, +crop_pack4to1 = 67, +crop_pack4to8 = 68, +crop_pack8 = 69, +crop_pack8to1 = 70, +crop_pack8to4 = 71, +deconvolution = 72, +deconvolution_col2im = 73, +deconvolution_gemm = 74, +deconvolution_pack1to4 = 75, +deconvolution_pack1to4_gemm = 76, +deconvolution_pack1to8 = 77, +deconvolution_pack1to8_gemm = 78, +deconvolution_pack4 = 79, +deconvolution_pack4_col2im = 80, +deconvolution_pack4_gemm = 81, +deconvolution_pack4_gemm_cm_16_8_8 = 82, +deconvolution_pack4to1 = 83, +deconvolution_pack4to1_gemm = 84, +deconvolution_pack4to8 = 85, +deconvolution_pack4to8_gemm = 86, +deconvolution_pack8 = 87, +deconvolution_pack8_col2im = 88, +deconvolution_pack8_gemm = 89, +deconvolution_pack8to1 = 90, +deconvolution_pack8to1_gemm = 91, +deconvolution_pack8to4 = 92, +deconvolution_pack8to4_gemm = 93, +dropout = 94, +dropout_pack4 = 95, +dropout_pack8 = 96, +eltwise = 97, +eltwise_pack4 = 98, +eltwise_pack8 = 99, +elu = 100, +elu_pack4 = 101, +elu_pack8 = 102, +flatten = 103, +flatten_pack1to4 = 104, +flatten_pack1to8 = 105, +flatten_pack4 = 106, +flatten_pack4to8 = 107, +flatten_pack8 = 108, +innerproduct = 109, +innerproduct_gemm = 110, +innerproduct_gemm_wp1to4 = 111, +innerproduct_gemm_wp1to8 = 112, +innerproduct_gemm_wp4 = 113, +innerproduct_gemm_wp4to1 = 114, +innerproduct_gemm_wp4to8 = 115, +innerproduct_gemm_wp8 = 116, +innerproduct_gemm_wp8to1 = 117, +innerproduct_gemm_wp8to4 = 118, +innerproduct_pack1to4 = 119, +innerproduct_pack1to8 = 120, +innerproduct_pack4 = 121, +innerproduct_pack4to1 = 122, +innerproduct_pack4to8 = 123, +innerproduct_pack8 = 124, +innerproduct_pack8to1 = 125, +innerproduct_pack8to4 = 126, +innerproduct_reduce_sum8 = 127, +innerproduct_reduce_sum8_pack4 = 128, +innerproduct_reduce_sum8_pack8 = 129, +innerproduct_sum8 = 130, +innerproduct_sum8_pack1to4 = 131, +innerproduct_sum8_pack1to8 = 132, +innerproduct_sum8_pack4 = 133, +innerproduct_sum8_pack4to1 = 134, +innerproduct_sum8_pack4to8 = 135, +innerproduct_sum8_pack8 = 136, +innerproduct_sum8_pack8to1 = 137, +innerproduct_sum8_pack8to4 = 138, +lrn_norm = 139, +lrn_norm_across_channel_pack4 = 140, +lrn_norm_across_channel_pack8 = 141, +lrn_norm_within_channel_pack4 = 142, +lrn_norm_within_channel_pack8 = 143, +lrn_square_pad = 144, +lrn_square_pad_across_channel_pack4 = 145, +lrn_square_pad_across_channel_pack8 = 146, +lrn_square_pad_within_channel_pack4 = 147, +lrn_square_pad_within_channel_pack8 = 148, +pooling = 149, +pooling_adaptive = 150, +pooling_adaptive_pack4 = 151, +pooling_adaptive_pack8 = 152, +pooling_global = 153, +pooling_global_pack4 = 154, +pooling_global_pack8 = 155, +pooling_pack4 = 156, +pooling_pack8 = 157, +prelu = 158, +prelu_pack4 = 159, +prelu_pack8 = 160, +relu = 161, +relu_pack4 = 162, +relu_pack8 = 163, +reshape = 164, +reshape_pack1to4 = 165, +reshape_pack1to8 = 166, +reshape_pack4 = 167, +reshape_pack4to1 = 168, +reshape_pack4to8 = 169, +reshape_pack8 = 170, +reshape_pack8to1 = 171, +reshape_pack8to4 = 172, +scale = 173, +scale_pack4 = 174, +scale_pack8 = 175, +sigmoid = 176, +sigmoid_pack4 = 177, +sigmoid_pack8 = 178, +slice = 179, +slice_pack1to4 = 180, +slice_pack1to8 = 181, +slice_pack4 = 182, +slice_pack4to8 = 183, +slice_pack8 = 184, +softmax_div_sum = 185, +softmax_div_sum_pack4 = 186, +softmax_div_sum_pack8 = 187, +softmax_exp_sub_max = 188, +softmax_exp_sub_max_pack4 = 189, +softmax_exp_sub_max_pack8 = 190, +softmax_reduce_max = 191, +softmax_reduce_max_pack4 = 192, +softmax_reduce_max_pack8 = 193, +softmax_reduce_sum = 194, +softmax_reduce_sum_pack4 = 195, +softmax_reduce_sum_pack8 = 196, +tanh = 197, +tanh_pack4 = 198, +tanh_pack8 = 199, +binaryop = 200, +binaryop_broadcast = 201, +binaryop_broadcast_a1_pack4 = 202, +binaryop_broadcast_a1_pack8 = 203, +binaryop_broadcast_b1_pack4 = 204, +binaryop_broadcast_b1_pack8 = 205, +binaryop_broadcast_pack4 = 206, +binaryop_broadcast_pack8 = 207, +binaryop_pack4 = 208, +binaryop_pack8 = 209, +unaryop = 210, +unaryop_pack4 = 211, +unaryop_pack8 = 212, +convolutiondepthwise = 213, +convolutiondepthwise_group = 214, +convolutiondepthwise_group_pack1to4 = 215, +convolutiondepthwise_group_pack1to8 = 216, +convolutiondepthwise_group_pack4 = 217, +convolutiondepthwise_group_pack4to1 = 218, +convolutiondepthwise_group_pack4to8 = 219, +convolutiondepthwise_group_pack8 = 220, +convolutiondepthwise_group_pack8to1 = 221, +convolutiondepthwise_group_pack8to4 = 222, +convolutiondepthwise_pack4 = 223, +convolutiondepthwise_pack8 = 224, +padding = 225, +padding_3d = 226, +padding_3d_pack4 = 227, +padding_3d_pack8 = 228, +padding_pack1to4 = 229, +padding_pack1to8 = 230, +padding_pack4 = 231, +padding_pack4to1 = 232, +padding_pack4to8 = 233, +padding_pack8 = 234, +padding_pack8to1 = 235, +padding_pack8to4 = 236, +normalize_coeffs = 237, +normalize_coeffs_pack4 = 238, +normalize_coeffs_pack8 = 239, +normalize_norm = 240, +normalize_norm_pack4 = 241, +normalize_norm_pack8 = 242, +normalize_reduce_sum4_fp16_to_fp32 = 243, +normalize_reduce_sum4_fp16_to_fp32_pack4 = 244, +normalize_reduce_sum4_fp16_to_fp32_pack8 = 245, +normalize_reduce_sum4_fp32 = 246, +normalize_reduce_sum4_fp32_pack4 = 247, +normalize_reduce_sum4_fp32_pack8 = 248, +permute = 249, +permute_pack1to4 = 250, +permute_pack1to8 = 251, +permute_pack4 = 252, +permute_pack4to1 = 253, +permute_pack4to8 = 254, +permute_pack8 = 255, +permute_pack8to1 = 256, +permute_pack8to4 = 257, +priorbox = 258, +priorbox_mxnet = 259, +interp = 260, +interp_bicubic = 261, +interp_bicubic_coeffs = 262, +interp_bicubic_pack4 = 263, +interp_bicubic_pack8 = 264, +interp_pack4 = 265, +interp_pack8 = 266, +deconvolutiondepthwise = 267, +deconvolutiondepthwise_group = 268, +deconvolutiondepthwise_group_pack1to4 = 269, +deconvolutiondepthwise_group_pack1to8 = 270, +deconvolutiondepthwise_group_pack4 = 271, +deconvolutiondepthwise_group_pack4to1 = 272, +deconvolutiondepthwise_group_pack4to8 = 273, +deconvolutiondepthwise_group_pack8 = 274, +deconvolutiondepthwise_group_pack8to1 = 275, +deconvolutiondepthwise_group_pack8to4 = 276, +deconvolutiondepthwise_pack4 = 277, +deconvolutiondepthwise_pack8 = 278, +shufflechannel = 279, +shufflechannel_pack4 = 280, +shufflechannel_pack8 = 281, +instancenorm_coeffs = 282, +instancenorm_coeffs_pack4 = 283, +instancenorm_coeffs_pack8 = 284, +instancenorm_norm = 285, +instancenorm_norm_pack4 = 286, +instancenorm_norm_pack8 = 287, +instancenorm_reduce_mean = 288, +instancenorm_reduce_mean_pack4 = 289, +instancenorm_reduce_mean_pack8 = 290, +instancenorm_reduce_sum4_fp16_to_fp32 = 291, +instancenorm_reduce_sum4_fp16_to_fp32_pack4 = 292, +instancenorm_reduce_sum4_fp16_to_fp32_pack8 = 293, +instancenorm_reduce_sum4_fp32 = 294, +instancenorm_reduce_sum4_fp32_pack4 = 295, +instancenorm_reduce_sum4_fp32_pack8 = 296, +instancenorm_sub_mean_square = 297, +instancenorm_sub_mean_square_pack4 = 298, +instancenorm_sub_mean_square_pack8 = 299, +clip = 300, +clip_pack4 = 301, +clip_pack8 = 302, +reorg = 303, +reorg_pack1to4 = 304, +reorg_pack1to8 = 305, +reorg_pack4 = 306, +reorg_pack4to8 = 307, +reorg_pack8 = 308, +packing = 309, +packing_fp16_to_fp32 = 310, +packing_fp32_to_fp16 = 311, +packing_pack1to4 = 312, +packing_pack1to4_fp16_to_fp32 = 313, +packing_pack1to4_fp32_to_fp16 = 314, +packing_pack1to8 = 315, +packing_pack1to8_fp16_to_fp32 = 316, +packing_pack1to8_fp32_to_fp16 = 317, +packing_pack4 = 318, +packing_pack4_fp16_to_fp32 = 319, +packing_pack4_fp32_to_fp16 = 320, +packing_pack4to1 = 321, +packing_pack4to1_fp16_to_fp32 = 322, +packing_pack4to1_fp32_to_fp16 = 323, +packing_pack4to8 = 324, +packing_pack4to8_fp16_to_fp32 = 325, +packing_pack4to8_fp32_to_fp16 = 326, +packing_pack8 = 327, +packing_pack8_fp16_to_fp32 = 328, +packing_pack8_fp32_to_fp16 = 329, +packing_pack8to1 = 330, +packing_pack8to1_fp16_to_fp32 = 331, +packing_pack8to1_fp32_to_fp16 = 332, +packing_pack8to4 = 333, +packing_pack8to4_fp16_to_fp32 = 334, +packing_pack8to4_fp32_to_fp16 = 335, +cast_fp16_to_fp32 = 336, +cast_fp16_to_fp32_pack4 = 337, +cast_fp16_to_fp32_pack8 = 338, +cast_fp32_to_fp16 = 339, +cast_fp32_to_fp16_pack4 = 340, +cast_fp32_to_fp16_pack8 = 341, +hardsigmoid = 342, +hardsigmoid_pack4 = 343, +hardsigmoid_pack8 = 344, +hardswish = 345, +hardswish_pack4 = 346, +hardswish_pack8 = 347, +pixelshuffle = 348, +pixelshuffle_pack4 = 349, +pixelshuffle_pack4to1 = 350, +pixelshuffle_pack8 = 351, +pixelshuffle_pack8to1 = 352, +pixelshuffle_pack8to4 = 353, +deepcopy = 354, +deepcopy_pack4 = 355, +deepcopy_pack8 = 356, +mish = 357, +mish_pack4 = 358, +mish_pack8 = 359, +swish = 360, +swish_pack4 = 361, +swish_pack8 = 362, +convert_ycbcr = 363, +vulkan_activation = 364, + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/layer_type.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/layer_type.h new file mode 100644 index 0000000..511c714 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/layer_type.h @@ -0,0 +1,30 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_TYPE_H +#define NCNN_LAYER_TYPE_H + +namespace ncnn { + +namespace LayerType { +enum LayerType +{ +#include "layer_type_enum.h" + CustomBit = (1 << 8), +}; +} // namespace LayerType + +} // namespace ncnn + +#endif // NCNN_LAYER_TYPE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/layer_type_enum.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/layer_type_enum.h new file mode 100644 index 0000000..581d589 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/layer_type_enum.h @@ -0,0 +1,103 @@ +// Layer Type Enum header +// +// This file is auto-generated by cmake, don't edit it. + +AbsVal = 0, +ArgMax = 1, +BatchNorm = 2, +Bias = 3, +BNLL = 4, +Concat = 5, +Convolution = 6, +Crop = 7, +Deconvolution = 8, +Dropout = 9, +Eltwise = 10, +ELU = 11, +Embed = 12, +Exp = 13, +Flatten = 14, +InnerProduct = 15, +Input = 16, +Log = 17, +LRN = 18, +MemoryData = 19, +MVN = 20, +Pooling = 21, +Power = 22, +PReLU = 23, +Proposal = 24, +Reduction = 25, +ReLU = 26, +Reshape = 27, +ROIPooling = 28, +Scale = 29, +Sigmoid = 30, +Slice = 31, +Softmax = 32, +Split = 33, +SPP = 34, +TanH = 35, +Threshold = 36, +Tile = 37, +RNN = 38, +LSTM = 39, +BinaryOp = 40, +UnaryOp = 41, +ConvolutionDepthWise = 42, +Padding = 43, +Squeeze = 44, +ExpandDims = 45, +Normalize = 46, +Permute = 47, +PriorBox = 48, +DetectionOutput = 49, +Interp = 50, +DeconvolutionDepthWise = 51, +ShuffleChannel = 52, +InstanceNorm = 53, +Clip = 54, +Reorg = 55, +YoloDetectionOutput = 56, +Quantize = 57, +Dequantize = 58, +Yolov3DetectionOutput = 59, +PSROIPooling = 60, +ROIAlign = 61, +Packing = 62, +Requantize = 63, +Cast = 64, +HardSigmoid = 65, +SELU = 66, +HardSwish = 67, +Noop = 68, +PixelShuffle = 69, +DeepCopy = 70, +Mish = 71, +StatisticsPooling = 72, +Swish = 73, +Gemm = 74, +GroupNorm = 75, +LayerNorm = 76, +Softplus = 77, +GRU = 78, +MultiHeadAttention = 79, +GELU = 80, +Convolution1D = 81, +Pooling1D = 82, +ConvolutionDepthWise1D = 83, +Convolution3D = 84, +ConvolutionDepthWise3D = 85, +Pooling3D = 86, +MatMul = 87, +Deconvolution1D = 88, +DeconvolutionDepthWise1D = 89, +Deconvolution3D = 90, +DeconvolutionDepthWise3D = 91, +Einsum = 92, +DeformableConv2D = 93, +GLU = 94, +Fold = 95, +Unfold = 96, +GridSample = 97, + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/mat.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/mat.h new file mode 100644 index 0000000..c6f59ef --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/mat.h @@ -0,0 +1,1843 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_MAT_H +#define NCNN_MAT_H + +#include +#include +#if __ARM_NEON +#include +#endif +#if __SSE2__ +#include +#if __AVX__ +#include +#endif +#endif +#if __mips_msa +#include +#endif +#if __loongarch_sx +#include +#endif +#if __riscv_vector +#include +#include "cpu.h" // cpu_riscv_vlenb() +#endif + +#include "allocator.h" +#include "option.h" +#include "platform.h" + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#if NCNN_PIXEL +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#include +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API +#endif // NCNN_PIXEL + +namespace ncnn { + +#if NCNN_VULKAN +class VkMat; +class VkImageMat; +#endif // NCNN_VULKAN + +// the three dimension matrix +class NCNN_EXPORT Mat +{ +public: + // empty + Mat(); + // vec + Mat(int w, size_t elemsize = 4u, Allocator* allocator = 0); + // image + Mat(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0); + // dim + Mat(int w, int h, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // cube + Mat(int w, int h, int d, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // packed vec + Mat(int w, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed image + Mat(int w, int h, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed dim + Mat(int w, int h, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed cube + Mat(int w, int h, int d, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // copy + Mat(const Mat& m); + // external vec + Mat(int w, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external image + Mat(int w, int h, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external dim + Mat(int w, int h, int c, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external cube + Mat(int w, int h, int d, int c, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external packed vec + Mat(int w, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed image + Mat(int w, int h, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed dim + Mat(int w, int h, int c, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed cube + Mat(int w, int h, int d, int c, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // release + ~Mat(); + // assign + Mat& operator=(const Mat& m); + // set all + void fill(float v); + void fill(int v); +#if __ARM_NEON + void fill(float32x4_t _v); + void fill(uint16x4_t _v); + void fill(int32x4_t _v); + void fill(int32x4_t _v0, int32x4_t _v1); +#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC + void fill(float16x4_t _v); + void fill(float16x8_t _v); +#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +#endif // __ARM_NEON +#if __SSE2__ +#if __AVX__ +#if __AVX512F__ + void fill(__m512 _v); +#endif // __AVX512F__ + void fill(__m256 _v, int i = 0); +#endif // __AVX__ + void fill(__m128 _v); + void fill(__m128i _v); +#endif // __SSE2__ +#if __mips_msa + void fill(v4f32 _v); +#endif // __mips_msa +#if __loongarch_sx + void fill(__m128 _v); +#endif //__loongarch_sx +#if __riscv_vector + void fill(vfloat32m1_t _v); + void fill(vuint16m1_t _v); + void fill(vint8m1_t _v); +#if __riscv_zfh + void fill(vfloat16m1_t _v); +#endif // __riscv_zfh +#endif // __riscv_vector + template + void fill(T v); + // deep copy + Mat clone(Allocator* allocator = 0) const; + // deep copy from other mat, inplace + void clone_from(const ncnn::Mat& mat, Allocator* allocator = 0); + // reshape vec + Mat reshape(int w, Allocator* allocator = 0) const; + // reshape image + Mat reshape(int w, int h, Allocator* allocator = 0) const; + // reshape dim + Mat reshape(int w, int h, int c, Allocator* allocator = 0) const; + // reshape cube + Mat reshape(int w, int h, int d, int c, Allocator* allocator = 0) const; + // allocate vec + void create(int w, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate image + void create(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate dim + void create(int w, int h, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate like + void create_like(const Mat& m, Allocator* allocator = 0); +#if NCNN_VULKAN + // allocate like + void create_like(const VkMat& m, Allocator* allocator = 0); + // allocate like + void create_like(const VkImageMat& im, Allocator* allocator = 0); +#endif // NCNN_VULKAN + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // data reference + Mat channel(int c); + const Mat channel(int c) const; + Mat depth(int z); + const Mat depth(int z) const; + float* row(int y); + const float* row(int y) const; + template + T* row(int y); + template + const T* row(int y) const; + + // range reference + Mat channel_range(int c, int channels); + const Mat channel_range(int c, int channels) const; + Mat depth_range(int z, int depths); + const Mat depth_range(int z, int depths) const; + Mat row_range(int y, int rows); + const Mat row_range(int y, int rows) const; + Mat range(int x, int n); + const Mat range(int x, int n) const; + + // access raw data + template + operator T*(); + template + operator const T*() const; + + // convenient access float vec element + float& operator[](size_t i); + const float& operator[](size_t i) const; + +#if NCNN_PIXEL + enum PixelType + { + PIXEL_CONVERT_SHIFT = 16, + PIXEL_FORMAT_MASK = 0x0000ffff, + PIXEL_CONVERT_MASK = 0xffff0000, + + PIXEL_RGB = 1, + PIXEL_BGR = 2, + PIXEL_GRAY = 3, + PIXEL_RGBA = 4, + PIXEL_BGRA = 5, + + PIXEL_RGB2BGR = PIXEL_RGB | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2GRAY = PIXEL_RGB | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2RGBA = PIXEL_RGB | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2BGRA = PIXEL_RGB | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_BGR2RGB = PIXEL_BGR | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2GRAY = PIXEL_BGR | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2RGBA = PIXEL_BGR | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2BGRA = PIXEL_BGR | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_GRAY2RGB = PIXEL_GRAY | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2BGR = PIXEL_GRAY | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2RGBA = PIXEL_GRAY | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2BGRA = PIXEL_GRAY | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_RGBA2RGB = PIXEL_RGBA | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2BGR = PIXEL_RGBA | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2GRAY = PIXEL_RGBA | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2BGRA = PIXEL_RGBA | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_BGRA2RGB = PIXEL_BGRA | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2BGR = PIXEL_BGRA | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2GRAY = PIXEL_BGRA | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2RGBA = PIXEL_BGRA | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + }; + // convenient construct from pixel data + static Mat from_pixels(const unsigned char* pixels, int type, int w, int h, Allocator* allocator = 0); + // convenient construct from pixel data with stride(bytes-per-row) parameter + static Mat from_pixels(const unsigned char* pixels, int type, int w, int h, int stride, Allocator* allocator = 0); + // convenient construct from pixel data and resize to specific size + static Mat from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data and resize to specific size with stride(bytes-per-row) parameter + static Mat from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data roi + static Mat from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from pixel data roi with stride(bytes-per-row) parameter + static Mat from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from pixel data roi and resize to specific size + static Mat from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data roi and resize to specific size with stride(bytes-per-row) parameter + static Mat from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + + // convenient export to pixel data + void to_pixels(unsigned char* pixels, int type) const; + // convenient export to pixel data with stride(bytes-per-row) parameter + void to_pixels(unsigned char* pixels, int type, int stride) const; + // convenient export to pixel data and resize to specific size + void to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height) const; + // convenient export to pixel data and resize to specific size with stride(bytes-per-row) parameter + void to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height, int target_stride) const; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 + // convenient construct from android Bitmap + static Mat from_android_bitmap(JNIEnv* env, jobject bitmap, int type_to, Allocator* allocator = 0); + // convenient construct from android Bitmap and resize to specific size + static Mat from_android_bitmap_resize(JNIEnv* env, jobject bitmap, int type_to, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from android Bitmap roi + static Mat from_android_bitmap_roi(JNIEnv* env, jobject bitmap, int type_to, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from android Bitmap roi and resize to specific size + static Mat from_android_bitmap_roi_resize(JNIEnv* env, jobject bitmap, int type_to, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + // convenient export to android Bitmap and resize to the android Bitmap size + void to_android_bitmap(JNIEnv* env, jobject bitmap, int type_from) const; +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API +#endif // NCNN_PIXEL + + // substract channel-wise mean values, then multiply by normalize values, pass 0 to skip + void substract_mean_normalize(const float* mean_vals, const float* norm_vals); + + // convenient construct from half precision floating point data + static Mat from_float16(const unsigned short* data, int size); + + // pointer to the data + void* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + Allocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; + + size_t cstep; +}; + +#if NCNN_VULKAN + +// the three dimension matrix, vulkan version +class NCNN_EXPORT VkMat +{ +public: + // empty + VkMat(); + // vec + VkMat(int w, size_t elemsize, VkAllocator* allocator); + // image + VkMat(int w, int h, size_t elemsize, VkAllocator* allocator); + // dim + VkMat(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // cube + VkMat(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // packed vec + VkMat(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // packed image + VkMat(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // packed dim + VkMat(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // packed cube + VkMat(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // copy + VkMat(const VkMat& m); + // external vec + VkMat(int w, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external image + VkMat(int w, int h, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external dim + VkMat(int w, int h, int c, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external cube + VkMat(int w, int h, int d, int c, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external packed vec + VkMat(int w, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed image + VkMat(int w, int h, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed dim + VkMat(int w, int h, int c, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed cube + VkMat(int w, int h, int d, int c, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // release + ~VkMat(); + // assign + VkMat& operator=(const VkMat& m); + // allocate vec + void create(int w, size_t elemsize, VkAllocator* allocator); + // allocate image + void create(int w, int h, size_t elemsize, VkAllocator* allocator); + // allocate dim + void create(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate like + void create_like(const Mat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkMat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkImageMat& im, VkAllocator* allocator); + + // mapped + Mat mapped() const; + void* mapped_ptr() const; + + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // low-level reference + VkBuffer buffer() const; + size_t buffer_offset() const; + size_t buffer_capacity() const; + + // device buffer + VkBufferMemory* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + VkAllocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; + + size_t cstep; +}; + +class NCNN_EXPORT VkImageMat +{ +public: + // empty + VkImageMat(); + // vec + VkImageMat(int w, size_t elemsize, VkAllocator* allocator); + // image + VkImageMat(int w, int h, size_t elemsize, VkAllocator* allocator); + // dim + VkImageMat(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // cube + VkImageMat(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // packed vec + VkImageMat(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // packed image + VkImageMat(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // packed dim + VkImageMat(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // packed cube + VkImageMat(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // copy + VkImageMat(const VkImageMat& m); + // external vec + VkImageMat(int w, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external image + VkImageMat(int w, int h, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external dim + VkImageMat(int w, int h, int c, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external cube + VkImageMat(int w, int h, int d, int c, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external packed vec + VkImageMat(int w, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed image + VkImageMat(int w, int h, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed dim + VkImageMat(int w, int h, int c, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed cube + VkImageMat(int w, int h, int d, int c, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // release + ~VkImageMat(); + // assign + VkImageMat& operator=(const VkImageMat& m); + // allocate vec + void create(int w, size_t elemsize, VkAllocator* allocator); + // allocate image + void create(int w, int h, size_t elemsize, VkAllocator* allocator); + // allocate dim + void create(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate like + void create_like(const Mat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkMat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkImageMat& im, VkAllocator* allocator); + + // mapped + Mat mapped() const; + void* mapped_ptr() const; + + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // low-level reference + VkImage image() const; + VkImageView imageview() const; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 + // convenient construct from android hardware buffer + static VkImageMat from_android_hardware_buffer(VkAndroidHardwareBufferImageAllocator* allocator); +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + + // device image + VkImageMemory* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + VkAllocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; +}; + +// type for vulkan specialization constant and push constant +union vk_specialization_type +{ + int i; + float f; + uint32_t u32; +}; +union vk_constant_type +{ + int i; + float f; +}; +#endif // NCNN_VULKAN + +// misc function +#if NCNN_PIXEL +// convert yuv420sp(nv21) to rgb, the fast approximate version +NCNN_EXPORT void yuv420sp2rgb(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// convert yuv420sp(nv12) to rgb, the fast approximate version +NCNN_EXPORT void yuv420sp2rgb_nv12(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// convert yuv420sp(nv21) to rgb with half resize, the faster approximate version +NCNN_EXPORT void yuv420sp2rgb_half(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// image pixel bilinear resize +NCNN_EXPORT void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +// image pixel bilinear resize with stride(bytes-per-row) parameter +NCNN_EXPORT void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +// image pixel bilinear resize, convenient wrapper for yuv420sp(nv21/nv12) +NCNN_EXPORT void resize_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +#endif // NCNN_PIXEL +#if NCNN_PIXEL_ROTATE +// type is the from type, 6 means rotating from 6 to 1 +// +// 1 2 3 4 5 6 7 8 +// +// 888888 888888 88 88 8888888888 88 88 8888888888 +// 88 88 88 88 88 88 88 88 88 88 88 88 +// 8888 8888 8888 8888 88 8888888888 8888888888 88 +// 88 88 88 88 +// 88 88 888888 888888 +// +// ref http://sylvana.net/jpegcrop/exif_orientation.html +// image pixel kanna rotate +NCNN_EXPORT void kanna_rotate_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +// image pixel kanna rotate with stride(bytes-per-row) parameter +NCNN_EXPORT void kanna_rotate_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +// image pixel kanna rotate, convenient wrapper for yuv420sp(nv21/nv12) +NCNN_EXPORT void kanna_rotate_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +#endif // NCNN_PIXEL_ROTATE +#if NCNN_PIXEL_AFFINE +// resolve affine transform matrix from rotation angle, scale factor and x y offset +NCNN_EXPORT void get_rotation_matrix(float angle, float scale, float dx, float dy, float* tm); +// resolve affine transform matrix from two set of points, num_point must be >= 2 +NCNN_EXPORT void get_affine_transform(const float* points_from, const float* points_to, int num_point, float* tm); +// resolve the inversion affine transform matrix +NCNN_EXPORT void invert_affine_transform(const float* tm, float* tm_inv); +// image pixel bilinear warpaffine inverse transform, set -233 for transparent border color, the color RGBA is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +// image pixel bilinear warpaffine inverse transform with stride(bytes-per-row) parameter, set -233 for transparent border color, the color RGBA is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +// image pixel bilinear warpaffine, convenient wrapper for yuv420sp(nv21/nv12), set -233 for transparent border color, the color YUV_ is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +#endif // NCNN_PIXEL_AFFINE +#if NCNN_PIXEL_DRAWING +// draw rectangle, set thickness -1 for filled rectangle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_rectangle_c1(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c2(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c3(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c4(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw rectangle with stride(bytes-per-row) parameter, set thickness -1 for filled rectangle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_rectangle_c1(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c2(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c3(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c4(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw rectangle, convenient wrapper for yuv420sp(nv21/nv12), set thickness -1 for filled rectangle, the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_rectangle_yuv420sp(unsigned char* yuv420sp, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw circle, set thickness -1 for filled circle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_circle_c1(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c2(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c3(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c4(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +// draw circle with stride(bytes-per-row) parameter, set thickness -1 for filled circle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_circle_c1(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c2(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c3(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c4(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +// draw circle, convenient wrapper for yuv420sp(nv21/nv12), set thickness -1 for filled circle, the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_circle_yuv420sp(unsigned char* yuv420sp, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +// draw line, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_line_c1(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c2(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c3(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c4(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// draw line with stride(bytes-per-row) parameter, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_line_c1(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c2(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c3(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c4(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// draw line, convenient wrapper for yuv420sp(nv21/nv12), the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_line_yuv420sp(unsigned char* yuv420sp, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// resolve text bounding box size +NCNN_EXPORT void get_text_drawing_size(const char* text, int fontpixelsize, int* w, int* h); +// draw ascii printables and newline, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_text_c1(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c2(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c3(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c4(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +// draw ascii printables and newline with stride(bytes-per-row) parameter, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_text_c1(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c2(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c3(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c4(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +// draw ascii printables and newline, convenient wrapper for yuv420sp(nv21/nv12), the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_text_yuv420sp(unsigned char* yuv420sp, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +#endif // NCNN_PIXEL_DRAWING + +// type conversion +// convert float to half precision floating point +NCNN_EXPORT unsigned short float32_to_float16(float value); +// convert half precision floating point to float +NCNN_EXPORT float float16_to_float32(unsigned short value); +// convert float to brain half +NCNN_EXPORT NCNN_FORCEINLINE unsigned short float32_to_bfloat16(float value) +{ + // 16 : 16 + union + { + unsigned int u; + float f; + } tmp; + tmp.f = value; + return tmp.u >> 16; +} +// convert brain half to float +NCNN_EXPORT NCNN_FORCEINLINE float bfloat16_to_float32(unsigned short value) +{ + // 16 : 16 + union + { + unsigned int u; + float f; + } tmp; + tmp.u = value << 16; + return tmp.f; +} + +// mat process +enum BorderType +{ + BORDER_CONSTANT = 0, + BORDER_REPLICATE = 1, + BORDER_REFLECT = 2, + BORDER_TRANSPARENT = -233, +}; +NCNN_EXPORT void copy_make_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int type, float v, const Option& opt = Option()); +NCNN_EXPORT void copy_make_border_3d(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int front, int behind, int type, float v, const Option& opt = Option()); +NCNN_EXPORT void copy_cut_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, const Option& opt = Option()); +NCNN_EXPORT void copy_cut_border_3d(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int front, int behind, const Option& opt = Option()); +NCNN_EXPORT void resize_nearest(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void resize_bilinear(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void resize_bicubic(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void convert_packing(const Mat& src, Mat& dst, int elempack, const Option& opt = Option()); +NCNN_EXPORT void flatten(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float32_to_float16(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float16_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_int8_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float32_to_bfloat16(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_bfloat16_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void quantize_to_int8(const Mat& src, Mat& dst, const Mat& scale_data, const Option& opt = Option()); +NCNN_EXPORT void dequantize_from_int32(const Mat& src, Mat& dst, const Mat& scale_data, const Mat& bias_data, const Option& opt = Option()); +NCNN_EXPORT void requantize_from_int32_to_int8(const Mat& src, Mat& dst, const Mat& scale_in_data, const Mat& scale_out_data, const Mat& bias_data, int activation_type, const Mat& activation_params, const Option& opt = Option()); + +NCNN_FORCEINLINE Mat::Mat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ +} + +NCNN_FORCEINLINE Mat::Mat(int _w, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(const Mat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c), cstep(m.cstep) +{ + addref(); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = (size_t)w * h; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = (size_t)w * h; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::~Mat() +{ + release(); +} + +NCNN_FORCEINLINE void Mat::fill(float _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + + int i = 0; +#if __ARM_NEON + float32x4_t _c = vdupq_n_f32(_v); + for (; i + 3 < size; i += 4) + { + vst1q_f32(ptr, _c); + ptr += 4; + } +#endif // __ARM_NEON + for (; i < size; i++) + { + *ptr++ = _v; + } +} + +NCNN_FORCEINLINE void Mat::fill(int _v) +{ + int size = (int)total(); + int* ptr = (int*)data; + + int i = 0; +#if __ARM_NEON + int32x4_t _c = vdupq_n_s32(_v); + for (; i + 3 < size; i += 4) + { + vst1q_s32(ptr, _c); + ptr += 4; + } +#endif // __ARM_NEON + for (; i < size; i++) + { + *ptr++ = _v; + } +} + +#if __ARM_NEON +NCNN_FORCEINLINE void Mat::fill(float32x4_t _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + vst1q_f32(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(uint16x4_t _v) +{ + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + vst1_u16(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(int32x4_t _v) +{ + int size = (int)total(); + int* ptr = (int*)data; + for (int i = 0; i < size; i++) + { + vst1q_s32(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(int32x4_t _v0, int32x4_t _v1) +{ + int size = (int)total(); + int* ptr = (int*)data; + for (int i = 0; i < size; i++) + { + vst1q_s32(ptr, _v0); + vst1q_s32(ptr + 4, _v1); + ptr += 8; + } +} +#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +NCNN_FORCEINLINE void Mat::fill(float16x4_t _v) +{ + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vst1_f16(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(float16x8_t _v) +{ + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vst1q_f16(ptr, _v); + ptr += 8; + } +} +#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +#endif // __ARM_NEON + +#if __SSE2__ +#if __AVX__ +#if __AVX512F__ +NCNN_FORCEINLINE void Mat::fill(__m512 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm512_storeu_ps(ptr, _v); + ptr += 16; + } +} +#endif // __AVX512F__ +NCNN_FORCEINLINE void Mat::fill(__m256 _v, int _i) +{ + // old gcc cannot overload __m128 and __m256 type + // add a dummy int parameter for different mangled function symbol + (void)_i; + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm256_storeu_ps(ptr, _v); + ptr += 8; + } +} +#endif // __AVX__ +NCNN_FORCEINLINE void Mat::fill(__m128 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm_storeu_ps(ptr, _v); + ptr += 4; + } +} +NCNN_FORCEINLINE void Mat::fill(__m128i _v) +{ + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + _mm_store_si128((__m128i*)ptr, _v); + ptr += 8; + } +} +#endif // __SSE2__ + +#if __mips_msa +NCNN_FORCEINLINE void Mat::fill(v4f32 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + __msa_st_w((v4i32)_v, ptr, 0); + ptr += 4; + } +} +#endif // __mips_msa + +#if __loongarch_sx +NCNN_FORCEINLINE void Mat::fill(__m128 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + __lsx_vst(_v, ptr, 0); + ptr += 4; + } +} +#endif // __loongarch_sx +#if __riscv_vector +NCNN_FORCEINLINE void Mat::fill(vfloat32m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 4; + const size_t vl = vsetvl_e32m1(packn); + + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + vse32_v_f32m1(ptr, _v, vl); + ptr += packn; + } +} + +NCNN_FORCEINLINE void Mat::fill(vuint16m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 2; + const size_t vl = vsetvl_e16m1(packn); + + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + vse16_v_u16m1(ptr, _v, vl); + ptr += packn; + } +} + +NCNN_FORCEINLINE void Mat::fill(vint8m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 1; + const size_t vl = vsetvl_e8m1(packn); + + int size = (int)total(); + signed char* ptr = (signed char*)data; + for (int i = 0; i < size; i++) + { + vse8_v_i8m1(ptr, _v, vl); + ptr += packn; + } +} +#if __riscv_zfh +NCNN_FORCEINLINE void Mat::fill(vfloat16m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 2; + const size_t vl = vsetvl_e16m1(packn); + + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vse16_v_f16m1(ptr, _v, vl); + ptr += packn; + } +} +#endif // __riscv_zfh +#endif // __riscv_vector + +template +NCNN_FORCEINLINE void Mat::fill(T _v) +{ + int size = (int)total(); + T* ptr = (T*)data; + for (int i = 0; i < size; i++) + { + ptr[i] = _v; + } +} + +NCNN_FORCEINLINE Mat& Mat::operator=(const Mat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + cstep = m.cstep; + + return *this; +} + +NCNN_FORCEINLINE void Mat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void Mat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator) + allocator->fastFree(data); + else + fastFree(data); + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + cstep = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool Mat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t Mat::total() const +{ + return cstep * c; +} + +NCNN_FORCEINLINE int Mat::elembits() const +{ + return elempack ? static_cast(elemsize * 8) / elempack : 0; +} + +NCNN_FORCEINLINE Mat Mat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE Mat Mat::channel(int _c) +{ + Mat m(w, h, d, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims - 1; + if (dims == 4) + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::channel(int _c) const +{ + Mat m(w, h, d, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims - 1; + if (dims == 4) + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE Mat Mat::depth(int z) +{ + return Mat(w, h, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::depth(int z) const +{ + return Mat(w, h, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE float* Mat::row(int y) +{ + return (float*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +NCNN_FORCEINLINE const float* Mat::row(int y) const +{ + return (const float*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +template +NCNN_FORCEINLINE T* Mat::row(int y) +{ + return (T*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +template +NCNN_FORCEINLINE const T* Mat::row(int y) const +{ + return (const T*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +NCNN_FORCEINLINE Mat Mat::channel_range(int _c, int channels) +{ + Mat m(w, h, d, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::channel_range(int _c, int channels) const +{ + Mat m(w, h, d, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims; + return m; +} + +NCNN_FORCEINLINE Mat Mat::depth_range(int z, int depths) +{ + Mat m(w, h, depths, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::depth_range(int z, int depths) const +{ + Mat m(w, h, depths, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE Mat Mat::row_range(int y, int rows) +{ + return Mat(w, rows, (unsigned char*)data + (size_t)w * y * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::row_range(int y, int rows) const +{ + return Mat(w, rows, (unsigned char*)data + (size_t)w * y * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE Mat Mat::range(int x, int n) +{ + return Mat(n, (unsigned char*)data + x * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::range(int x, int n) const +{ + return Mat(n, (unsigned char*)data + x * elemsize, elemsize, elempack, allocator); +} + +template +NCNN_FORCEINLINE Mat::operator T*() +{ + return (T*)data; +} + +template +NCNN_FORCEINLINE Mat::operator const T*() const +{ + return (const T*)data; +} + +NCNN_FORCEINLINE float& Mat::operator[](size_t i) +{ + return ((float*)data)[i]; +} + +NCNN_FORCEINLINE const float& Mat::operator[](size_t i) const +{ + return ((const float*)data)[i]; +} + +#if NCNN_VULKAN + +NCNN_FORCEINLINE VkMat::VkMat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(const VkMat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c) +{ + addref(); + + cstep = m.cstep; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = w * h; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize(w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = w * h; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize(w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::~VkMat() +{ + release(); +} + +NCNN_FORCEINLINE VkMat& VkMat::operator=(const VkMat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + cstep = m.cstep; + + return *this; +} + +NCNN_FORCEINLINE Mat VkMat::mapped() const +{ + if (!allocator->mappable) + return Mat(); + + if (dims == 1) + return Mat(w, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 2) + return Mat(w, h, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 3) + return Mat(w, h, c, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 4) + return Mat(w, h, d, c, mapped_ptr(), elemsize, elempack, 0); + + return Mat(); +} + +NCNN_FORCEINLINE void* VkMat::mapped_ptr() const +{ + if (!allocator->mappable) + return 0; + + return (unsigned char*)data->mapped_ptr + data->offset; +} + +NCNN_FORCEINLINE void VkMat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void VkMat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator && data) + { + allocator->fastFree(data); + } + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + cstep = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool VkMat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t VkMat::total() const +{ + return cstep * c; +} + +NCNN_FORCEINLINE int VkMat::elembits() const +{ + return elempack ? static_cast(elemsize) * 8 / elempack : 0; +} + +NCNN_FORCEINLINE Mat VkMat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE VkBuffer VkMat::buffer() const +{ + return data->buffer; +} + +NCNN_FORCEINLINE size_t VkMat::buffer_offset() const +{ + return data->offset; +} + +NCNN_FORCEINLINE size_t VkMat::buffer_capacity() const +{ + return data->capacity; +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(const VkImageMat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c) +{ + addref(); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::~VkImageMat() +{ + release(); +} + +NCNN_FORCEINLINE VkImageMat& VkImageMat::operator=(const VkImageMat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + return *this; +} + +NCNN_FORCEINLINE Mat VkImageMat::mapped() const +{ + if (!allocator->mappable || !data->mapped_ptr) + return Mat(); + + if (dims == 1) + return Mat(w, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 2) + return Mat(w, h, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 3) + return Mat(w, h, c, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 4) + return Mat(w, h, d, c, mapped_ptr(), elemsize, elempack, 0); + + return Mat(); +} + +NCNN_FORCEINLINE void* VkImageMat::mapped_ptr() const +{ + if (!allocator->mappable || !data->mapped_ptr) + return 0; + + return (unsigned char*)data->mapped_ptr + data->bind_offset; +} + +NCNN_FORCEINLINE void VkImageMat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void VkImageMat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator && data) + { + allocator->fastFree(data); + } + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool VkImageMat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t VkImageMat::total() const +{ + return w * h * d * c; +} + +NCNN_FORCEINLINE int VkImageMat::elembits() const +{ + return elempack ? static_cast(elemsize) * 8 / elempack : 0; +} + +NCNN_FORCEINLINE Mat VkImageMat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE VkImage VkImageMat::image() const +{ + return data->image; +} + +NCNN_FORCEINLINE VkImageView VkImageMat::imageview() const +{ + return data->imageview; +} + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_MAT_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/modelbin.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/modelbin.h new file mode 100644 index 0000000..15d2b9c --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/modelbin.h @@ -0,0 +1,80 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_MODELBIN_H +#define NCNN_MODELBIN_H + +#include "mat.h" + +namespace ncnn { + +class DataReader; +class NCNN_EXPORT ModelBin +{ +public: + ModelBin(); + virtual ~ModelBin(); + // element type + // 0 = auto + // 1 = float32 + // 2 = float16 + // 3 = int8 + // load vec + virtual Mat load(int w, int type) const = 0; + // load image + virtual Mat load(int w, int h, int type) const; + // load dim + virtual Mat load(int w, int h, int c, int type) const; + // load cube + virtual Mat load(int w, int h, int d, int c, int type) const; +}; + +class ModelBinFromDataReaderPrivate; +class NCNN_EXPORT ModelBinFromDataReader : public ModelBin +{ +public: + explicit ModelBinFromDataReader(const DataReader& dr); + virtual ~ModelBinFromDataReader(); + + virtual Mat load(int w, int type) const; + +private: + ModelBinFromDataReader(const ModelBinFromDataReader&); + ModelBinFromDataReader& operator=(const ModelBinFromDataReader&); + +private: + ModelBinFromDataReaderPrivate* const d; +}; + +class ModelBinFromMatArrayPrivate; +class NCNN_EXPORT ModelBinFromMatArray : public ModelBin +{ +public: + // construct from weight blob array + explicit ModelBinFromMatArray(const Mat* weights); + virtual ~ModelBinFromMatArray(); + + virtual Mat load(int w, int type) const; + +private: + ModelBinFromMatArray(const ModelBinFromMatArray&); + ModelBinFromMatArray& operator=(const ModelBinFromMatArray&); + +private: + ModelBinFromMatArrayPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_MODELBIN_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/ncnn_export.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/ncnn_export.h new file mode 100644 index 0000000..e2f5fde --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/ncnn_export.h @@ -0,0 +1,42 @@ + +#ifndef NCNN_EXPORT_H +#define NCNN_EXPORT_H + +#ifdef NCNN_STATIC_DEFINE +# define NCNN_EXPORT +# define NCNN_NO_EXPORT +#else +# ifndef NCNN_EXPORT +# ifdef ncnn_EXPORTS + /* We are building this library */ +# define NCNN_EXPORT __attribute__((visibility("default"))) +# else + /* We are using this library */ +# define NCNN_EXPORT __attribute__((visibility("default"))) +# endif +# endif + +# ifndef NCNN_NO_EXPORT +# define NCNN_NO_EXPORT __attribute__((visibility("hidden"))) +# endif +#endif + +#ifndef NCNN_DEPRECATED +# define NCNN_DEPRECATED __attribute__ ((__deprecated__)) +#endif + +#ifndef NCNN_DEPRECATED_EXPORT +# define NCNN_DEPRECATED_EXPORT NCNN_EXPORT NCNN_DEPRECATED +#endif + +#ifndef NCNN_DEPRECATED_NO_EXPORT +# define NCNN_DEPRECATED_NO_EXPORT NCNN_NO_EXPORT NCNN_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef NCNN_NO_DEPRECATED +# define NCNN_NO_DEPRECATED +# endif +#endif + +#endif /* NCNN_EXPORT_H */ diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/net.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/net.h new file mode 100644 index 0000000..9407042 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/net.h @@ -0,0 +1,272 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_NET_H +#define NCNN_NET_H + +#include "blob.h" +#include "layer.h" +#include "mat.h" +#include "option.h" +#include "platform.h" + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +#if NCNN_VULKAN +class VkCompute; +#endif // NCNN_VULKAN +class DataReader; +class Extractor; +class NetPrivate; +class NCNN_EXPORT Net +{ +public: + // empty init + Net(); + // clear and destroy + virtual ~Net(); + +public: + // option can be changed before loading + Option opt; + +#if NCNN_VULKAN + // set gpu device by index + void set_vulkan_device(int device_index); + + // set gpu device by device handle, no owner transfer + void set_vulkan_device(const VulkanDevice* vkdev); + + const VulkanDevice* vulkan_device() const; +#endif // NCNN_VULKAN + +#if NCNN_STRING + // register custom layer by layer type name + // return 0 if success + int register_custom_layer(const char* type, layer_creator_func creator, layer_destroyer_func destroyer = 0, void* userdata = 0); + virtual int custom_layer_to_index(const char* type); +#endif // NCNN_STRING + // register custom layer by layer type + // return 0 if success + int register_custom_layer(int index, layer_creator_func creator, layer_destroyer_func destroyer = 0, void* userdata = 0); + +#if NCNN_STRING + int load_param(const DataReader& dr); +#endif // NCNN_STRING + + int load_param_bin(const DataReader& dr); + + int load_model(const DataReader& dr); + +#if NCNN_STDIO +#if NCNN_STRING + // load network structure from plain param file + // return 0 if success + int load_param(FILE* fp); + int load_param(const char* protopath); + int load_param_mem(const char* mem); +#endif // NCNN_STRING + // load network structure from binary param file + // return 0 if success + int load_param_bin(FILE* fp); + int load_param_bin(const char* protopath); + + // load network weight data from model file + // return 0 if success + int load_model(FILE* fp); + int load_model(const char* modelpath); +#endif // NCNN_STDIO + + // load network structure from external memory + // memory pointer must be 32-bit aligned + // return bytes consumed + int load_param(const unsigned char* mem); + + // reference network weight data from external memory + // weight data is not copied but referenced + // so external memory should be retained when used + // memory pointer must be 32-bit aligned + // return bytes consumed + int load_model(const unsigned char* mem); + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#if NCNN_STRING + // convenient load network structure from android asset plain param file + int load_param(AAsset* asset); + int load_param(AAssetManager* mgr, const char* assetpath); +#endif // NCNN_STRING + // convenient load network structure from android asset binary param file + int load_param_bin(AAsset* asset); + int load_param_bin(AAssetManager* mgr, const char* assetpath); + + // convenient load network weight data from android asset model file + int load_model(AAsset* asset); + int load_model(AAssetManager* mgr, const char* assetpath); +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + + // unload network structure and weight data + void clear(); + + // construct an Extractor from network + Extractor create_extractor() const; + + // get input/output indexes/names + const std::vector& input_indexes() const; + const std::vector& output_indexes() const; +#if NCNN_STRING + const std::vector& input_names() const; + const std::vector& output_names() const; +#endif + + const std::vector& blobs() const; + const std::vector& layers() const; + + std::vector& mutable_blobs(); + std::vector& mutable_layers(); + +protected: + friend class Extractor; +#if NCNN_STRING + int find_blob_index_by_name(const char* name) const; + int find_layer_index_by_name(const char* name) const; + virtual Layer* create_custom_layer(const char* type); +#endif // NCNN_STRING + virtual Layer* create_custom_layer(int index); + +private: + Net(const Net&); + Net& operator=(const Net&); + +private: + NetPrivate* const d; +}; + +class ExtractorPrivate; +class NCNN_EXPORT Extractor +{ +public: + virtual ~Extractor(); + + // copy + Extractor(const Extractor&); + + // assign + Extractor& operator=(const Extractor&); + + // clear blob mats and alloctors + void clear(); + + // enable light mode + // intermediate blob will be recycled when enabled + // enabled by default + void set_light_mode(bool enable); + + // set thread count for this extractor + // this will overwrite the global setting + // default count is system depended + void set_num_threads(int num_threads); + + // set blob memory allocator + void set_blob_allocator(Allocator* allocator); + + // set workspace memory allocator + void set_workspace_allocator(Allocator* allocator); + +#if NCNN_VULKAN + void set_vulkan_compute(bool enable); + + void set_blob_vkallocator(VkAllocator* allocator); + + void set_workspace_vkallocator(VkAllocator* allocator); + + void set_staging_vkallocator(VkAllocator* allocator); +#endif // NCNN_VULKAN + +#if NCNN_STRING + // set input by blob name + // return 0 if success + int input(const char* blob_name, const Mat& in); + + // get result by blob name + // return 0 if success + // type = 0, default + // type = 1, do not convert fp16/bf16 or / and packing + int extract(const char* blob_name, Mat& feat, int type = 0); +#endif // NCNN_STRING + + // set input by blob index + // return 0 if success + int input(int blob_index, const Mat& in); + + // get result by blob index + // return 0 if success + // type = 0, default + // type = 1, do not convert fp16/bf16 or / and packing + int extract(int blob_index, Mat& feat, int type = 0); + +#if NCNN_VULKAN +#if NCNN_STRING + // set input by blob name + // return 0 if success + int input(const char* blob_name, const VkMat& in); + + // get result by blob name + // return 0 if success + int extract(const char* blob_name, VkMat& feat, VkCompute& cmd); + + // set input by blob name + // return 0 if success + int input(const char* blob_name, const VkImageMat& in); + + // get result by blob name + // return 0 if success + int extract(const char* blob_name, VkImageMat& feat, VkCompute& cmd); +#endif // NCNN_STRING + + // set input by blob index + // return 0 if success + int input(int blob_index, const VkMat& in); + + // get result by blob index + // return 0 if success + int extract(int blob_index, VkMat& feat, VkCompute& cmd); + + // set input by blob index + // return 0 if success + int input(int blob_index, const VkImageMat& in); + + // get result by blob index + // return 0 if success + int extract(int blob_index, VkImageMat& feat, VkCompute& cmd); +#endif // NCNN_VULKAN + +protected: + friend Extractor Net::create_extractor() const; + Extractor(const Net* net, size_t blob_count); + +private: + ExtractorPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_NET_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/option.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/option.h new file mode 100644 index 0000000..3fda808 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/option.h @@ -0,0 +1,153 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_OPTION_H +#define NCNN_OPTION_H + +#include "platform.h" + +namespace ncnn { + +#if NCNN_VULKAN +class VkAllocator; +class PipelineCache; +#endif // NCNN_VULKAN + +class Allocator; +class NCNN_EXPORT Option +{ +public: + // default option + Option(); + +public: + // light mode + // intermediate blob will be recycled when enabled + // enabled by default + bool lightmode; + + // thread count + // default value is the one returned by get_cpu_count() + int num_threads; + + // blob memory allocator + Allocator* blob_allocator; + + // workspace memory allocator + Allocator* workspace_allocator; + +#if NCNN_VULKAN + // blob memory allocator + VkAllocator* blob_vkallocator; + + // workspace memory allocator + VkAllocator* workspace_vkallocator; + + // staging memory allocator + VkAllocator* staging_vkallocator; + + // pipeline cache + PipelineCache* pipeline_cache; +#endif // NCNN_VULKAN + + // the time openmp threads busy-wait for more work before going to sleep + // default value is 20ms to keep the cores enabled + // without too much extra power consumption afterwards + int openmp_blocktime; + + // enable winograd convolution optimization + // improve convolution 3x3 stride1 performance, may consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_winograd_convolution; + + // enable sgemm convolution optimization + // improve convolution 1x1 stride1 performance, may consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_sgemm_convolution; + + // enable quantized int8 inference + // use low-precision int8 path for quantized model + // changes should be applied before loading network structure and weight + // enabled by default + bool use_int8_inference; + + // enable vulkan compute + bool use_vulkan_compute; + + // enable bf16 data type for storage + // improve most operator performance on all arm devices, may consume more memory + bool use_bf16_storage; + + // enable options for gpu inference + bool use_fp16_packed; + bool use_fp16_storage; + bool use_fp16_arithmetic; + bool use_int8_packed; + bool use_int8_storage; + bool use_int8_arithmetic; + + // enable simd-friendly packed memory layout + // improve all operator performance on all arm devices, will consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_packing_layout; + + bool use_shader_pack8; + + // subgroup option + bool use_subgroup_basic; + bool use_subgroup_vote; + bool use_subgroup_ballot; + bool use_subgroup_shuffle; + + // turn on for adreno + bool use_image_storage; + bool use_tensor_storage; + + bool use_reserved_0; + + // enable DAZ(Denormals-Are-Zero) and FTZ(Flush-To-Zero) + // default value is 3 + // 0 = DAZ OFF, FTZ OFF + // 1 = DAZ ON , FTZ OFF + // 2 = DAZ OFF, FTZ ON + // 3 = DAZ ON, FTZ ON + int flush_denormals; + + bool use_local_pool_allocator; + + // enable local memory optimization for gpu inference + bool use_shader_local_memory; + + // enable cooperative matrix optimization for gpu inference + bool use_cooperative_matrix; + + // more fine-grained control of winograd convolution + bool use_winograd23_convolution; + bool use_winograd43_convolution; + bool use_winograd63_convolution; + + bool use_reserved_6; + bool use_reserved_7; + bool use_reserved_8; + bool use_reserved_9; + bool use_reserved_10; + bool use_reserved_11; +}; + +} // namespace ncnn + +#endif // NCNN_OPTION_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/paramdict.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/paramdict.h new file mode 100644 index 0000000..c2ef160 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/paramdict.h @@ -0,0 +1,73 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PARAMDICT_H +#define NCNN_PARAMDICT_H + +#include "mat.h" + +// at most 32 parameters +#define NCNN_MAX_PARAM_COUNT 32 + +namespace ncnn { + +class DataReader; +class Net; +class ParamDictPrivate; +class NCNN_EXPORT ParamDict +{ +public: + // empty + ParamDict(); + + virtual ~ParamDict(); + + // copy + ParamDict(const ParamDict&); + + // assign + ParamDict& operator=(const ParamDict&); + + // get type + int type(int id) const; + + // get int + int get(int id, int def) const; + // get float + float get(int id, float def) const; + // get array + Mat get(int id, const Mat& def) const; + + // set int + void set(int id, int i); + // set float + void set(int id, float f); + // set array + void set(int id, const Mat& v); + +protected: + friend class Net; + + void clear(); + + int load_param(const DataReader& dr); + int load_param_bin(const DataReader& dr); + +private: + ParamDictPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_PARAMDICT_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/pipeline.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/pipeline.h new file mode 100644 index 0000000..c284a14 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/pipeline.h @@ -0,0 +1,113 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PIPELINE_H +#define NCNN_PIPELINE_H + +#include "mat.h" +#include "platform.h" +#if NCNN_VULKAN +#include "gpu.h" + +#include +#endif // NCNN_VULKAN + +namespace ncnn { + +#if NCNN_VULKAN +class Option; +class PipelinePrivate; +class NCNN_EXPORT Pipeline +{ +public: + explicit Pipeline(const VulkanDevice* vkdev); + virtual ~Pipeline(); + +public: + void set_optimal_local_size_xyz(int w = 4, int h = 4, int c = 4); + void set_optimal_local_size_xyz(const Mat& local_size_xyz); + void set_local_size_xyz(int w, int h, int c); + + int create(const uint32_t* spv_data, size_t spv_data_size, const std::vector& specializations); + + int create(int shader_type_index, const Option& opt, const std::vector& specializations); + +public: + VkShaderModule shader_module() const; + VkDescriptorSetLayout descriptorset_layout() const; + VkPipelineLayout pipeline_layout() const; + VkPipeline pipeline() const; + VkDescriptorUpdateTemplateKHR descriptor_update_template() const; + + const ShaderInfo& shader_info() const; + + uint32_t local_size_x() const; + uint32_t local_size_y() const; + uint32_t local_size_z() const; + +protected: + void set_shader_module(VkShaderModule shader_module); + void set_descriptorset_layout(VkDescriptorSetLayout descriptorset_layout); + void set_pipeline_layout(VkPipelineLayout pipeline_layout); + void set_pipeline(VkPipeline pipeline); + void set_descriptor_update_template(VkDescriptorUpdateTemplateKHR descriptor_update_template); + + void set_shader_info(const ShaderInfo& shader_info); + +public: + const VulkanDevice* vkdev; + +private: + Pipeline(const Pipeline&); + Pipeline& operator=(const Pipeline&); + +private: + PipelinePrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class VkCompute; +class NCNN_EXPORT ImportAndroidHardwareBufferPipeline : private Pipeline +{ +public: + explicit ImportAndroidHardwareBufferPipeline(const VulkanDevice* vkdev); + virtual ~ImportAndroidHardwareBufferPipeline(); + + int create(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator, int type_to, int rotate_from, const Option& opt); + int create(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator, int type_to, int rotate_from, int target_width, int target_height, const Option& opt); + void destroy(); + + friend class VkCompute; + +protected: + int create_shader_module(const Option& opt); + int create_sampler(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator); + int create_descriptorset_layout(); + +public: + int type_to; + int rotate_from; + bool need_resize; + + VkSampler sampler; +}; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_PIPELINE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/pipelinecache.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/pipelinecache.h new file mode 100644 index 0000000..bb6b8fb --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/pipelinecache.h @@ -0,0 +1,85 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PIPELINECACHE_H +#define NCNN_PIPELINECACHE_H + +#include "platform.h" + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#include "mat.h" +#include "gpu.h" + +namespace ncnn { + +#if NCNN_VULKAN + +class VulkanDevice; +class PipelineCachePrivate; +class NCNN_EXPORT PipelineCache +{ +public: + explicit PipelineCache(const VulkanDevice* _vkdev); + + virtual ~PipelineCache(); + + void clear(); + + int get_pipeline(const uint32_t* spv_data, size_t spv_data_size, const std::vector& specializations, + uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* shader_module, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template, + ShaderInfo& shader_info) const; + + int get_pipeline(int shader_type_index, const Option& opt, const std::vector& specializations, + uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* shader_module, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template, + ShaderInfo& shader_info) const; + +protected: + int create_shader_module(int shader_type_index, const Option& opt, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* _shader_module, ShaderInfo& si) const; + + int new_pipeline(VkShaderModule shader_module, const ShaderInfo& shader_info, const std::vector& specializations, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template) const; + +protected: + const VulkanDevice* vkdev; + +private: + PipelineCache(const PipelineCache&); + PipelineCache& operator=(const PipelineCache&); + +private: + PipelineCachePrivate* const d; +}; + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_PIPELINECACHE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/platform.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/platform.h new file mode 100644 index 0000000..a353fd1 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/platform.h @@ -0,0 +1,285 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PLATFORM_H +#define NCNN_PLATFORM_H + +#define NCNN_STDIO 1 +#define NCNN_STRING 1 +#define NCNN_SIMPLEOCV 0 +#define NCNN_SIMPLEOMP 0 +#define NCNN_SIMPLESTL 0 +#define NCNN_THREADS 1 +#define NCNN_BENCHMARK 0 +#define NCNN_C_API 1 +#define NCNN_PLATFORM_API 1 +#define NCNN_PIXEL 1 +#define NCNN_PIXEL_ROTATE 1 +#define NCNN_PIXEL_AFFINE 1 +#define NCNN_PIXEL_DRAWING 1 +#define NCNN_VULKAN 1 +#define NCNN_SYSTEM_GLSLANG 0 +#define NCNN_RUNTIME_CPU 1 +#define NCNN_AVX 0 +#define NCNN_XOP 0 +#define NCNN_FMA 0 +#define NCNN_F16C 0 +#define NCNN_AVX2 0 +#define NCNN_AVXVNNI 0 +#define NCNN_AVX512 0 +#define NCNN_AVX512VNNI 0 +#define NCNN_AVX512BF16 0 +#define NCNN_AVX512FP16 0 +#define NCNN_VFPV4 1 +#if __aarch64__ +#define NCNN_ARM82 1 +#define NCNN_ARM82DOT 1 +#define NCNN_ARM82FP16FML 1 +#define NCNN_ARM84BF16 1 +#define NCNN_ARM84I8MM 1 +#define NCNN_ARM86SVE 1 +#define NCNN_ARM86SVE2 1 +#define NCNN_ARM86SVEBF16 1 +#define NCNN_ARM86SVEI8MM 1 +#define NCNN_ARM86SVEF32MM 1 +#endif // __aarch64__ +#define NCNN_MSA 0 +#define NCNN_LSX 0 +#define NCNN_MMI 0 +#define NCNN_RVV 0 +#define NCNN_INT8 1 +#define NCNN_BF16 1 +#define NCNN_FORCE_INLINE 1 + +#define NCNN_VERSION_STRING "1.0.20221128" + +#include "ncnn_export.h" + +#ifdef __cplusplus + +#if NCNN_THREADS +#if (defined _WIN32 && !(defined __MINGW32__)) +#define WIN32_LEAN_AND_MEAN +#include +#include +#else +#include +#endif +#endif // NCNN_THREADS + +#if __ANDROID_API__ >= 26 +#define VK_USE_PLATFORM_ANDROID_KHR +#endif // __ANDROID_API__ >= 26 + +namespace ncnn { + +#if NCNN_THREADS +#if (defined _WIN32 && !(defined __MINGW32__)) +class NCNN_EXPORT Mutex +{ +public: + Mutex() { InitializeSRWLock(&srwlock); } + ~Mutex() {} + void lock() { AcquireSRWLockExclusive(&srwlock); } + void unlock() { ReleaseSRWLockExclusive(&srwlock); } +private: + friend class ConditionVariable; + // NOTE SRWLock is available from windows vista + SRWLOCK srwlock; +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() { InitializeConditionVariable(&condvar); } + ~ConditionVariable() {} + void wait(Mutex& mutex) { SleepConditionVariableSRW(&condvar, &mutex.srwlock, INFINITE, 0); } + void broadcast() { WakeAllConditionVariable(&condvar); } + void signal() { WakeConditionVariable(&condvar); } +private: + CONDITION_VARIABLE condvar; +}; + +static unsigned __stdcall start_wrapper(void* args); +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*start)(void*), void* args = 0) { _start = start; _args = args; handle = (HANDLE)_beginthreadex(0, 0, start_wrapper, this, 0, 0); } + ~Thread() {} + void join() { WaitForSingleObject(handle, INFINITE); CloseHandle(handle); } +private: + friend unsigned __stdcall start_wrapper(void* args) + { + Thread* t = (Thread*)args; + t->_start(t->_args); + return 0; + } + HANDLE handle; + void* (*_start)(void*); + void* _args; +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { key = TlsAlloc(); } + ~ThreadLocalStorage() { TlsFree(key); } + void set(void* value) { TlsSetValue(key, (LPVOID)value); } + void* get() { return (void*)TlsGetValue(key); } +private: + DWORD key; +}; +#else // (defined _WIN32 && !(defined __MINGW32__)) +class NCNN_EXPORT Mutex +{ +public: + Mutex() { pthread_mutex_init(&mutex, 0); } + ~Mutex() { pthread_mutex_destroy(&mutex); } + void lock() { pthread_mutex_lock(&mutex); } + void unlock() { pthread_mutex_unlock(&mutex); } +private: + friend class ConditionVariable; + pthread_mutex_t mutex; +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() { pthread_cond_init(&cond, 0); } + ~ConditionVariable() { pthread_cond_destroy(&cond); } + void wait(Mutex& mutex) { pthread_cond_wait(&cond, &mutex.mutex); } + void broadcast() { pthread_cond_broadcast(&cond); } + void signal() { pthread_cond_signal(&cond); } +private: + pthread_cond_t cond; +}; + +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*start)(void*), void* args = 0) { pthread_create(&t, 0, start, args); } + ~Thread() {} + void join() { pthread_join(t, 0); } +private: + pthread_t t; +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { pthread_key_create(&key, 0); } + ~ThreadLocalStorage() { pthread_key_delete(key); } + void set(void* value) { pthread_setspecific(key, value); } + void* get() { return pthread_getspecific(key); } +private: + pthread_key_t key; +}; +#endif // (defined _WIN32 && !(defined __MINGW32__)) +#else // NCNN_THREADS +class NCNN_EXPORT Mutex +{ +public: + Mutex() {} + ~Mutex() {} + void lock() {} + void unlock() {} +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() {} + ~ConditionVariable() {} + void wait(Mutex& /*mutex*/) {} + void broadcast() {} + void signal() {} +}; + +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*/*start*/)(void*), void* /*args*/ = 0) {} + ~Thread() {} + void join() {} +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { data = 0; } + ~ThreadLocalStorage() {} + void set(void* value) { data = value; } + void* get() { return data; } +private: + void* data; +}; +#endif // NCNN_THREADS + +class NCNN_EXPORT MutexLockGuard +{ +public: + MutexLockGuard(Mutex& _mutex) : mutex(_mutex) { mutex.lock(); } + ~MutexLockGuard() { mutex.unlock(); } +private: + Mutex& mutex; +}; + +} // namespace ncnn + +#if NCNN_SIMPLESTL +#include "simplestl.h" +#else +#include +#include +#include +#include +#endif + +#endif // __cplusplus + +#if NCNN_STDIO +#if NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#include +#define NCNN_LOGE(...) do { \ + fprintf(stderr, ##__VA_ARGS__); fprintf(stderr, "\n"); \ + __android_log_print(ANDROID_LOG_WARN, "ncnn", ##__VA_ARGS__); } while(0) +#else // NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#include +#define NCNN_LOGE(...) do { \ + fprintf(stderr, ##__VA_ARGS__); fprintf(stderr, "\n"); } while(0) +#endif // NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#else +#define NCNN_LOGE(...) +#endif + + +#if NCNN_FORCE_INLINE +#ifdef _MSC_VER + #define NCNN_FORCEINLINE __forceinline +#elif defined(__GNUC__) + #define NCNN_FORCEINLINE inline __attribute__((__always_inline__)) +#elif defined(__CLANG__) + #if __has_attribute(__always_inline__) + #define NCNN_FORCEINLINE inline __attribute__((__always_inline__)) + #else + #define NCNN_FORCEINLINE inline + #endif +#else + #define NCNN_FORCEINLINE inline +#endif +#else + #define NCNN_FORCEINLINE inline +#endif + +#endif // NCNN_PLATFORM_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/simpleocv.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/simpleocv.h new file mode 100644 index 0000000..55ede15 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/simpleocv.h @@ -0,0 +1,501 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEOCV_H +#define NCNN_SIMPLEOCV_H + +#include "platform.h" + +#if NCNN_SIMPLEOCV + +#include +#include +#include "allocator.h" +#include "mat.h" + +#if defined(_MSC_VER) || defined(__GNUC__) +#pragma push_macro("min") +#pragma push_macro("max") +#undef min +#undef max +#endif + +#ifndef NCNN_XADD +using ncnn::NCNN_XADD; +#endif + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; + +enum +{ + CV_LOAD_IMAGE_UNCHANGED = -1, + CV_LOAD_IMAGE_GRAYSCALE = 0, + CV_LOAD_IMAGE_COLOR = 1, +}; + +enum +{ + CV_IMWRITE_JPEG_QUALITY = 1 +}; + +// minimal opencv style data structure implementation +namespace cv { + +template +static inline _Tp saturate_cast(int v) +{ + return _Tp(v); +} +template<> +inline uchar saturate_cast(int v) +{ + return (uchar)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); +} + +template +struct Scalar_ +{ + Scalar_() + { + v[0] = 0; + v[1] = 0; + v[2] = 0; + v[3] = 0; + } + Scalar_(_Tp _v0) + { + v[0] = _v0; + v[1] = 0; + v[2] = 0; + v[3] = 0; + } + Scalar_(_Tp _v0, _Tp _v1, _Tp _v2) + { + v[0] = _v0; + v[1] = _v1; + v[2] = _v2; + v[3] = 0; + } + Scalar_(_Tp _v0, _Tp _v1, _Tp _v2, _Tp _v3) + { + v[0] = _v0; + v[1] = _v1; + v[2] = _v2; + v[3] = _v3; + } + + const _Tp operator[](const int i) const + { + return v[i]; + } + + _Tp operator[](const int i) + { + return v[i]; + } + + _Tp v[4]; +}; + +typedef Scalar_ Scalar; + +template +struct Point_ +{ + Point_() + : x(0), y(0) + { + } + Point_(_Tp _x, _Tp _y) + : x(_x), y(_y) + { + } + + template + operator Point_<_Tp2>() const + { + return Point_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y)); + } + + _Tp x; + _Tp y; +}; + +typedef Point_ Point; +typedef Point_ Point2f; + +template +struct Size_ +{ + Size_() + : width(0), height(0) + { + } + Size_(_Tp _w, _Tp _h) + : width(_w), height(_h) + { + } + + template + operator Size_<_Tp2>() const + { + return Size_<_Tp2>(saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); + } + + _Tp width; + _Tp height; +}; + +typedef Size_ Size; +typedef Size_ Size2f; + +template +struct Rect_ +{ + Rect_() + : x(0), y(0), width(0), height(0) + { + } + Rect_(_Tp _x, _Tp _y, _Tp _w, _Tp _h) + : x(_x), y(_y), width(_w), height(_h) + { + } + Rect_(Point_<_Tp> _p, Size_<_Tp> _size) + : x(_p.x), y(_p.y), width(_size.width), height(_size.height) + { + } + + template + operator Rect_<_Tp2>() const + { + return Rect_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y), saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); + } + + _Tp x; + _Tp y; + _Tp width; + _Tp height; + + // area + _Tp area() const + { + return width * height; + } +}; + +template +static inline Rect_<_Tp>& operator&=(Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + _Tp x1 = std::max(a.x, b.x), y1 = std::max(a.y, b.y); + a.width = std::min(a.x + a.width, b.x + b.width) - x1; + a.height = std::min(a.y + a.height, b.y + b.height) - y1; + a.x = x1; + a.y = y1; + if (a.width <= 0 || a.height <= 0) + a = Rect_<_Tp>(); + return a; +} + +template +static inline Rect_<_Tp>& operator|=(Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + _Tp x1 = std::min(a.x, b.x), y1 = std::min(a.y, b.y); + a.width = std::max(a.x + a.width, b.x + b.width) - x1; + a.height = std::max(a.y + a.height, b.y + b.height) - y1; + a.x = x1; + a.y = y1; + return a; +} + +template +static inline Rect_<_Tp> operator&(const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c &= b; +} + +template +static inline Rect_<_Tp> operator|(const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c |= b; +} + +typedef Rect_ Rect; +typedef Rect_ Rect2f; + +#define CV_8UC1 1 +#define CV_8UC3 3 +#define CV_8UC4 4 +#define CV_32FC1 4 + +struct NCNN_EXPORT Mat +{ + Mat() + : data(0), refcount(0), rows(0), cols(0), c(0) + { + } + + Mat(int _rows, int _cols, int flags) + : data(0), refcount(0) + { + create(_rows, _cols, flags); + } + + // copy + Mat(const Mat& m) + : data(m.data), refcount(m.refcount) + { + if (refcount) + NCNN_XADD(refcount, 1); + + rows = m.rows; + cols = m.cols; + c = m.c; + } + + Mat(int _rows, int _cols, int flags, void* _data) + : data((unsigned char*)_data), refcount(0) + { + rows = _rows; + cols = _cols; + c = flags; + } + + ~Mat() + { + release(); + } + + // assign + Mat& operator=(const Mat& m) + { + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + + rows = m.rows; + cols = m.cols; + c = m.c; + + return *this; + } + + Mat& operator=(const Scalar& s) + { + if (total() > 0) + { + uchar* p = data; + for (int i = 0; i < cols * rows; i++) + { + for (int j = 0; j < c; j++) + { + *p++ = s[j]; + } + } + } + + return *this; + } + + void create(int _rows, int _cols, int flags) + { + release(); + + rows = _rows; + cols = _cols; + c = flags; + + if (total() > 0) + { + // refcount address must be aligned, so we expand totalsize here + size_t totalsize = (total() + 3) >> 2 << 2; + data = (uchar*)ncnn::fastMalloc(totalsize + (int)sizeof(*refcount)); + refcount = (int*)(((uchar*)data) + totalsize); + *refcount = 1; + } + } + + void release() + { + if (refcount && NCNN_XADD(refcount, -1) == 1) + ncnn::fastFree(data); + + data = 0; + + rows = 0; + cols = 0; + c = 0; + + refcount = 0; + } + + Mat clone() const + { + if (empty()) + return Mat(); + + Mat m(rows, cols, c); + + if (total() > 0) + { + memcpy(m.data, data, total()); + } + + return m; + } + + bool empty() const + { + return data == 0 || total() == 0; + } + + int channels() const + { + return c; + } + + int type() const + { + return c; + } + + size_t total() const + { + return cols * rows * c; + } + + const uchar* ptr(int y) const + { + return data + y * cols * c; + } + + uchar* ptr(int y) + { + return data + y * cols * c; + } + + template + const _Tp* ptr(int y) const + { + return (const _Tp*)data + y * cols * c; + } + + template + _Tp* ptr(int y) + { + return (_Tp*)data + y * cols * c; + } + + // roi + Mat operator()(const Rect& roi) const + { + if (empty()) + return Mat(); + + Mat m(roi.height, roi.width, c); + + int sy = roi.y; + for (int y = 0; y < roi.height; y++) + { + const uchar* sptr = ptr(sy) + roi.x * c; + uchar* dptr = m.ptr(y); + memcpy(dptr, sptr, roi.width * c); + sy++; + } + + return m; + } + + uchar* data; + + // pointer to the reference counter; + // when points to user-allocated data, the pointer is NULL + int* refcount; + + int rows; + int cols; + + int c; +}; + +enum ImreadModes +{ + IMREAD_UNCHANGED = -1, + IMREAD_GRAYSCALE = 0, + IMREAD_COLOR = 1 +}; + +NCNN_EXPORT Mat imread(const std::string& path, int flags = IMREAD_COLOR); + +enum ImwriteFlags +{ + IMWRITE_JPEG_QUALITY = 1 +}; + +NCNN_EXPORT bool imwrite(const std::string& path, const Mat& m, const std::vector& params = std::vector()); + +NCNN_EXPORT void imshow(const std::string& name, const Mat& m); + +NCNN_EXPORT int waitKey(int delay = 0); + +#if NCNN_PIXEL +NCNN_EXPORT void resize(const Mat& src, Mat& dst, const Size& size, float sw = 0.f, float sh = 0.f, int flags = 0); +#endif // NCNN_PIXEL + +#if NCNN_PIXEL_DRAWING + +enum +{ + FILLED = -1 +}; + +NCNN_EXPORT void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void rectangle(Mat& img, Rect rec, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void circle(Mat& img, Point center, int radius, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void line(Mat& img, Point p0, Point p1, const Scalar& color, int thickness = 1); + +enum +{ + FONT_HERSHEY_SIMPLEX = 0 +}; + +NCNN_EXPORT void putText(Mat& img, const std::string& text, Point org, int fontFace, double fontScale, Scalar color, int thickness = 1); + +NCNN_EXPORT Size getTextSize(const std::string& text, int fontFace, double fontScale, int thickness, int* baseLine); + +#endif // NCNN_PIXEL_DRAWING + +} // namespace cv + +#if defined(_MSC_VER) || defined(__GNUC__) +#pragma pop_macro("min") +#pragma pop_macro("max") +#endif + +#endif // NCNN_SIMPLEOCV + +#endif // NCNN_SIMPLEOCV_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/simpleomp.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/simpleomp.h new file mode 100644 index 0000000..13e2452 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/simpleomp.h @@ -0,0 +1,53 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEOMP_H +#define NCNN_SIMPLEOMP_H + +#include "platform.h" + +#if NCNN_SIMPLEOMP + +#include + +// This minimal openmp runtime implementation only supports the llvm openmp abi +// and only supports #pragma omp parallel for num_threads(X) + +#ifdef __cplusplus +extern "C" { +#endif + +NCNN_EXPORT int omp_get_max_threads(); + +NCNN_EXPORT void omp_set_num_threads(int num_threads); + +NCNN_EXPORT int omp_get_dynamic(); + +NCNN_EXPORT void omp_set_dynamic(int dynamic); + +NCNN_EXPORT int omp_get_num_threads(); + +NCNN_EXPORT int omp_get_thread_num(); + +NCNN_EXPORT int kmp_get_blocktime(); + +NCNN_EXPORT void kmp_set_blocktime(int blocktime); + +#ifdef __cplusplus +} +#endif + +#endif // NCNN_SIMPLEOMP + +#endif // NCNN_SIMPLEOMP_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/simplestl.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/simplestl.h new file mode 100644 index 0000000..00ff468 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/simplestl.h @@ -0,0 +1,565 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLESTL_H +#define NCNN_SIMPLESTL_H + +#include +#include +#include + +#if !NCNN_SIMPLESTL + +#include + +#else + +// allocation functions +NCNN_EXPORT void* operator new(size_t size); +NCNN_EXPORT void* operator new[](size_t size); +// placement allocation functions +NCNN_EXPORT void* operator new(size_t size, void* ptr); +NCNN_EXPORT void* operator new[](size_t size, void* ptr); +// deallocation functions +NCNN_EXPORT void operator delete(void* ptr); +NCNN_EXPORT void operator delete[](void* ptr); +// deallocation functions since c++14 +#if __cplusplus >= 201402L +NCNN_EXPORT void operator delete(void* ptr, size_t sz); +NCNN_EXPORT void operator delete[](void* ptr, size_t sz); +#endif +// placement deallocation functions +NCNN_EXPORT void operator delete(void* ptr, void* voidptr2); +NCNN_EXPORT void operator delete[](void* ptr, void* voidptr2); + +#endif + +// minimal stl data structure implementation +namespace std { + +template +const T& max(const T& a, const T& b) +{ + return (a < b) ? b : a; +} + +template +const T& min(const T& a, const T& b) +{ + return (a > b) ? b : a; +} + +template +void swap(T& a, T& b) +{ + T temp(a); + a = b; + b = temp; +} + +template +struct pair +{ + pair() + : first(), second() + { + } + pair(const T1& t1, const T2& t2) + : first(t1), second(t2) + { + } + + T1 first; + T2 second; +}; + +template +bool operator==(const pair& x, const pair& y) +{ + return (x.first == y.first && x.second == y.second); +} +template +bool operator<(const pair& x, const pair& y) +{ + return x.first < y.first || (!(y.first < x.first) && x.second < y.second); +} +template +bool operator!=(const pair& x, const pair& y) +{ + return !(x == y); +} +template +bool operator>(const pair& x, const pair& y) +{ + return y < x; +} +template +bool operator<=(const pair& x, const pair& y) +{ + return !(y < x); +} +template +bool operator>=(const pair& x, const pair& y) +{ + return !(x < y); +} + +template +pair make_pair(const T1& t1, const T2& t2) +{ + return pair(t1, t2); +} + +template +struct node +{ + node* prev_; + node* next_; + T data_; + + node() + : prev_(0), next_(0), data_() + { + } + node(const T& t) + : prev_(0), next_(0), data_(t) + { + } +}; + +template +struct iter_list +{ + iter_list() + : curr_(0) + { + } + iter_list(node* n) + : curr_(n) + { + } + iter_list(const iter_list& i) + : curr_(i.curr_) + { + } + ~iter_list() + { + } + + iter_list& operator=(const iter_list& i) + { + curr_ = i.curr_; + return *this; + } + + T& operator*() + { + return curr_->data_; + } + T* operator->() + { + return &(curr_->data_); + } + + bool operator==(const iter_list& i) + { + return curr_ == i.curr_; + } + bool operator!=(const iter_list& i) + { + return curr_ != i.curr_; + } + + iter_list& operator++() + { + curr_ = curr_->next_; + return *this; + } + iter_list& operator--() + { + curr_ = curr_->prev_; + return *this; + } + + node* curr_; +}; + +template +struct list +{ + typedef iter_list iterator; + + list() + { + head_ = new node(); + tail_ = head_; + count_ = 0; + } + ~list() + { + clear(); + delete head_; + } + list(const list& l) + { + head_ = new node(); + tail_ = head_; + count_ = 0; + + for (iter_list i = l.begin(); i != l.end(); ++i) + { + push_back(*i); + } + } + + list& operator=(const list& l) + { + if (this == &l) + { + return *this; + } + clear(); + + for (iter_list i = l.begin(); i != l.end(); ++i) + { + push_back(*i); + } + return *this; + } + + void clear() + { + while (count_ > 0) + { + pop_front(); + } + } + + void pop_front() + { + if (count_ > 0) + { + head_ = head_->next_; + delete head_->prev_; + head_->prev_ = 0; + --count_; + } + } + + size_t size() const + { + return count_; + } + iter_list begin() const + { + return iter_list(head_); + } + iter_list end() const + { + return iter_list(tail_); + } + bool empty() const + { + return count_ == 0; + } + + void push_back(const T& t) + { + if (count_ == 0) + { + head_ = new node(t); + head_->prev_ = 0; + head_->next_ = tail_; + tail_->prev_ = head_; + count_ = 1; + } + else + { + node* temp = new node(t); + temp->prev_ = tail_->prev_; + temp->next_ = tail_; + tail_->prev_->next_ = temp; + tail_->prev_ = temp; + ++count_; + } + } + + iter_list erase(iter_list pos) + { + if (pos != end()) + { + node* temp = pos.curr_; + if (temp == head_) + { + ++pos; + temp->next_->prev_ = 0; + head_ = temp->next_; + } + else + { + --pos; + temp->next_->prev_ = temp->prev_; + temp->prev_->next_ = temp->next_; + ++pos; + } + delete temp; + --count_; + } + return pos; + } + +protected: + node* head_; + node* tail_; + size_t count_; +}; + +template +struct greater +{ + bool operator()(const T& x, const T& y) const + { + return (x > y); + } +}; + +template +struct less +{ + bool operator()(const T& x, const T& y) const + { + return (x < y); + } +}; + +template +void partial_sort(RandomAccessIter first, RandomAccessIter middle, RandomAccessIter last, Compare comp) +{ + // [TODO] heap sort should be used here, but we simply use bubble sort now + for (RandomAccessIter i = first; i < middle; ++i) + { + // bubble sort + for (RandomAccessIter j = last - 1; j > first; --j) + { + if (comp(*j, *(j - 1))) + { + swap(*j, *(j - 1)); + } + } + } +} + +template +struct vector +{ + vector() + : data_(0), size_(0), capacity_(0) + { + } + vector(const size_t new_size, const T& value = T()) + : data_(0), size_(0), capacity_(0) + { + resize(new_size, value); + } + ~vector() + { + clear(); + } + vector(const vector& v) + : data_(0), size_(0), capacity_(0) + { + resize(v.size()); + for (size_t i = 0; i < size_; i++) + { + data_[i] = v.data_[i]; + } + } + + vector& operator=(const vector& v) + { + if (this == &v) + { + return *this; + } + resize(0); + resize(v.size()); + for (size_t i = 0; i < size_; i++) + { + data_[i] = v.data_[i]; + } + return *this; + } + + void resize(const size_t new_size, const T& value = T()) + { + try_alloc(new_size); + if (new_size > size_) + { + for (size_t i = size_; i < new_size; i++) + { + new (&data_[i]) T(value); + } + } + else if (new_size < size_) + { + for (size_t i = new_size; i < size_; i++) + { + data_[i].~T(); + } + } + size_ = new_size; + } + + void clear() + { + for (size_t i = 0; i < size_; i++) + { + data_[i].~T(); + } + delete[](char*) data_; + data_ = 0; + size_ = 0; + capacity_ = 0; + } + + T* data() const + { + return data_; + } + size_t size() const + { + return size_; + } + T& operator[](size_t i) const + { + return data_[i]; + } + T* begin() const + { + return &data_[0]; + } + T* end() const + { + return &data_[size_]; + } + bool empty() const + { + return size_ == 0; + } + + void push_back(const T& t) + { + try_alloc(size_ + 1); + new (&data_[size_]) T(t); + size_++; + } + + void insert(T* pos, T* b, T* e) + { + vector* v = 0; + if (b >= begin() && b < end()) + { + //the same vector + v = new vector(*this); + b = v->begin() + (b - begin()); + e = v->begin() + (e - begin()); + } + size_t diff = pos - begin(); + try_alloc(size_ + (e - b)); + pos = begin() + diff; + memmove(pos + (e - b), pos, (end() - pos) * sizeof(T)); + size_t len = e - b; + size_ += len; + for (size_t i = 0; i < len; i++) + { + *pos = *b; + pos++; + b++; + } + delete v; + } + + T* erase(T* pos) + { + pos->~T(); + memmove(pos, pos + 1, (end() - pos - 1) * sizeof(T)); + size_--; + return pos; + } + +protected: + T* data_; + size_t size_; + size_t capacity_; + void try_alloc(size_t new_size) + { + if (new_size * 3 / 2 > capacity_ / 2) + { + capacity_ = new_size * 2; + T* new_data = (T*)new char[capacity_ * sizeof(T)]; + memset(static_cast(new_data), 0, capacity_ * sizeof(T)); + if (data_) + { + memmove(new_data, data_, sizeof(T) * size_); + delete[](char*) data_; + } + data_ = new_data; + } + } +}; + +struct NCNN_EXPORT string : public vector +{ + string() + { + } + string(const char* str) + { + size_t len = strlen(str); + resize(len); + memcpy(data_, str, len); + } + const char* c_str() const + { + return (const char*)data_; + } + bool operator==(const string& str2) const + { + return strcmp(data_, str2.data_) == 0; + } + bool operator==(const char* str2) const + { + return strcmp(data_, str2) == 0; + } + bool operator!=(const char* str2) const + { + return strcmp(data_, str2) != 0; + } + string& operator+=(const string& str1) + { + insert(end(), str1.begin(), str1.end()); + return *this; + } +}; + +inline string operator+(const string& str1, const string& str2) +{ + string str(str1); + str.insert(str.end(), str2.begin(), str2.end()); + return str; +} + +} // namespace std + +#endif // NCNN_SIMPLESTL_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/vulkan_header_fix.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/vulkan_header_fix.h new file mode 100644 index 0000000..e7a7e8e --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/include/ncnn/vulkan_header_fix.h @@ -0,0 +1,251 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_VULKAN_HEADER_FIX_H +#define NCNN_VULKAN_HEADER_FIX_H + +#include + +// This header contains new structure and function declearation to fix build with old vulkan sdk + +#if VK_HEADER_VERSION < 70 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES (VkStructureType)1000094000 +typedef enum VkSubgroupFeatureFlagBits +{ + VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001, + VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002, + VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004, + VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008, + VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010, + VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020, + VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040, + VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080, + VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 0x00000100, + VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubgroupFeatureFlagBits; +typedef VkFlags VkSubgroupFeatureFlags; +typedef struct VkPhysicalDeviceSubgroupProperties +{ + VkStructureType sType; + void* pNext; + uint32_t subgroupSize; + VkShaderStageFlags supportedStages; + VkSubgroupFeatureFlags supportedOperations; + VkBool32 quadOperationsInAllStages; +} VkPhysicalDeviceSubgroupProperties; +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES (VkStructureType)1000168000 +#define VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT (VkStructureType)1000168001 +typedef struct VkPhysicalDeviceMaintenance3Properties +{ + VkStructureType sType; + void* pNext; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceMaintenance3Properties; +typedef struct VkDescriptorSetLayoutSupport +{ + VkStructureType sType; + void* pNext; + VkBool32 supported; +} VkDescriptorSetLayoutSupport; +typedef VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; +typedef VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; +typedef void(VKAPI_PTR* PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); +#endif // VK_HEADER_VERSION < 70 + +#if VK_HEADER_VERSION < 80 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR (VkStructureType)1000177000 +typedef struct VkPhysicalDevice8BitStorageFeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; +} VkPhysicalDevice8BitStorageFeaturesKHR; +#define VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR (VkStructureType)1000109000 +#define VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR (VkStructureType)1000109001 +#define VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR (VkStructureType)1000109002 +#define VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR (VkStructureType)1000109003 +#define VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR (VkStructureType)1000109004 +#define VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR (VkStructureType)1000109005 +#define VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR (VkStructureType)1000109006 +typedef struct VkAttachmentDescription2KHR +{ + VkStructureType sType; + const void* pNext; + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription2KHR; +typedef struct VkAttachmentReference2KHR +{ + VkStructureType sType; + const void* pNext; + uint32_t attachment; + VkImageLayout layout; + VkImageAspectFlags aspectMask; +} VkAttachmentReference2KHR; +typedef struct VkSubpassDescription2KHR +{ + VkStructureType sType; + const void* pNext; + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t viewMask; + uint32_t inputAttachmentCount; + const VkAttachmentReference2KHR* pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference2KHR* pColorAttachments; + const VkAttachmentReference2KHR* pResolveAttachments; + const VkAttachmentReference2KHR* pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t* pPreserveAttachments; +} VkSubpassDescription2KHR; +typedef struct VkSubpassDependency2KHR +{ + VkStructureType sType; + const void* pNext; + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; + int32_t viewOffset; +} VkSubpassDependency2KHR; +typedef struct VkRenderPassCreateInfo2KHR +{ + VkStructureType sType; + const void* pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription2KHR* pAttachments; + uint32_t subpassCount; + const VkSubpassDescription2KHR* pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency2KHR* pDependencies; + uint32_t correlatedViewMaskCount; + const uint32_t* pCorrelatedViewMasks; +} VkRenderPassCreateInfo2KHR; +typedef struct VkSubpassBeginInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkSubpassContents contents; +} VkSubpassBeginInfoKHR; + +typedef struct VkSubpassEndInfoKHR +{ + VkStructureType sType; + const void* pNext; +} VkSubpassEndInfoKHR; +typedef VkResult(VKAPI_PTR* PFN_vkCreateRenderPass2KHR)(VkDevice device, const VkRenderPassCreateInfo2KHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void(VKAPI_PTR* PFN_vkCmdBeginRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfoKHR* pSubpassBeginInfo); +typedef void(VKAPI_PTR* PFN_vkCmdNextSubpass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfoKHR* pSubpassBeginInfo, const VkSubpassEndInfoKHR* pSubpassEndInfo); +typedef void(VKAPI_PTR* PFN_vkCmdEndRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassEndInfoKHR* pSubpassEndInfo); +#endif // VK_HEADER_VERSION < 80 + +#if VK_HEADER_VERSION < 95 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR (VkStructureType)1000082000 +typedef struct VkPhysicalDeviceFloat16Int8FeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; +} VkPhysicalDeviceFloat16Int8FeaturesKHR; +#endif // VK_HEADER_VERSION < 95 + +#if VK_HEADER_VERSION < 97 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT (VkStructureType)1000237000 +typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT +{ + VkStructureType sType; + void* pNext; + VkDeviceSize heapBudget[VK_MAX_MEMORY_HEAPS]; + VkDeviceSize heapUsage[VK_MAX_MEMORY_HEAPS]; +} VkPhysicalDeviceMemoryBudgetPropertiesEXT; +#endif // VK_HEADER_VERSION < 97 + +#if VK_HEADER_VERSION < 101 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV (VkStructureType)1000249000 +#define VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV (VkStructureType)1000249001 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV (VkStructureType)1000249002 +typedef enum VkComponentTypeNV +{ + VK_COMPONENT_TYPE_FLOAT16_NV = 0, + VK_COMPONENT_TYPE_FLOAT32_NV = 1, + VK_COMPONENT_TYPE_FLOAT64_NV = 2, + VK_COMPONENT_TYPE_SINT8_NV = 3, + VK_COMPONENT_TYPE_SINT16_NV = 4, + VK_COMPONENT_TYPE_SINT32_NV = 5, + VK_COMPONENT_TYPE_SINT64_NV = 6, + VK_COMPONENT_TYPE_UINT8_NV = 7, + VK_COMPONENT_TYPE_UINT16_NV = 8, + VK_COMPONENT_TYPE_UINT32_NV = 9, + VK_COMPONENT_TYPE_UINT64_NV = 10, + VK_COMPONENT_TYPE_BEGIN_RANGE_NV = VK_COMPONENT_TYPE_FLOAT16_NV, + VK_COMPONENT_TYPE_END_RANGE_NV = VK_COMPONENT_TYPE_UINT64_NV, + VK_COMPONENT_TYPE_RANGE_SIZE_NV = (VK_COMPONENT_TYPE_UINT64_NV - VK_COMPONENT_TYPE_FLOAT16_NV + 1), + VK_COMPONENT_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkComponentTypeNV; +typedef enum VkScopeNV +{ + VK_SCOPE_DEVICE_NV = 1, + VK_SCOPE_WORKGROUP_NV = 2, + VK_SCOPE_SUBGROUP_NV = 3, + VK_SCOPE_QUEUE_FAMILY_NV = 5, + VK_SCOPE_BEGIN_RANGE_NV = VK_SCOPE_DEVICE_NV, + VK_SCOPE_END_RANGE_NV = VK_SCOPE_QUEUE_FAMILY_NV, + VK_SCOPE_RANGE_SIZE_NV = (VK_SCOPE_QUEUE_FAMILY_NV - VK_SCOPE_DEVICE_NV + 1), + VK_SCOPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkScopeNV; +typedef struct VkCooperativeMatrixPropertiesNV +{ + VkStructureType sType; + void* pNext; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeNV AType; + VkComponentTypeNV BType; + VkComponentTypeNV CType; + VkComponentTypeNV DType; + VkScopeNV scope; +} VkCooperativeMatrixPropertiesNV; +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesNV +{ + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesNV; +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesNV +{ + VkStructureType sType; + void* pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesNV; +typedef VkResult(VKAPI_PTR* PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixPropertiesNV* pProperties); +#endif // VK_HEADER_VERSION < 101 + +#endif // NCNN_VULKAN_HEADER_FIX_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/lib/cmake/ncnn/ncnn-release.cmake b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/lib/cmake/ncnn/ncnn-release.cmake new file mode 100644 index 0000000..1fb8660 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/lib/cmake/ncnn/ncnn-release.cmake @@ -0,0 +1,19 @@ +#---------------------------------------------------------------- +# Generated CMake target import file for configuration "Release". +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "ncnn" for configuration "Release" +set_property(TARGET ncnn APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(ncnn PROPERTIES + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libncnn.so" + IMPORTED_SONAME_RELEASE "libncnn.so" + ) + +list(APPEND _cmake_import_check_targets ncnn ) +list(APPEND _cmake_import_check_files_for_ncnn "${_IMPORT_PREFIX}/lib/libncnn.so" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/lib/cmake/ncnn/ncnn.cmake b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/lib/cmake/ncnn/ncnn.cmake new file mode 100644 index 0000000..53b9fae --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/lib/cmake/ncnn/ncnn.cmake @@ -0,0 +1,109 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8) + message(FATAL_ERROR "CMake >= 2.8.0 required") +endif() +if(CMAKE_VERSION VERSION_LESS "2.8.3") + message(FATAL_ERROR "CMake >= 2.8.3 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.8.3...3.23) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_cmake_targets_defined "") +set(_cmake_targets_not_defined "") +set(_cmake_expected_targets "") +foreach(_cmake_expected_target IN ITEMS ncnn) + list(APPEND _cmake_expected_targets "${_cmake_expected_target}") + if(TARGET "${_cmake_expected_target}") + list(APPEND _cmake_targets_defined "${_cmake_expected_target}") + else() + list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") + endif() +endforeach() +unset(_cmake_expected_target) +if(_cmake_targets_defined STREQUAL _cmake_expected_targets) + unset(_cmake_targets_defined) + unset(_cmake_targets_not_defined) + unset(_cmake_expected_targets) + unset(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT _cmake_targets_defined STREQUAL "") + string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") + string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") +endif() +unset(_cmake_targets_defined) +unset(_cmake_targets_not_defined) +unset(_cmake_expected_targets) + + +# Compute the installation prefix relative to this file. +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +if(_IMPORT_PREFIX STREQUAL "/") + set(_IMPORT_PREFIX "") +endif() + +# Create imported target ncnn +add_library(ncnn SHARED IMPORTED) + +set_target_properties(ncnn PROPERTIES + INTERFACE_COMPILE_OPTIONS "-fno-rtti;-fno-exceptions" + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include/ncnn" + INTERFACE_LINK_LIBRARIES "-fopenmp;-static-openmp;-Wl,-wrap,__kmp_affinity_determine_capable;Threads::Threads;Vulkan::Vulkan;android;jnigraphics;log" + INTERFACE_POSITION_INDEPENDENT_CODE "ON" +) + +if(CMAKE_VERSION VERSION_LESS 2.8.12) + message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.") +endif() + +# Load information for each installed configuration. +file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/ncnn-*.cmake") +foreach(_cmake_config_file IN LISTS _cmake_config_files) + include("${_cmake_config_file}") +endforeach() +unset(_cmake_config_file) +unset(_cmake_config_files) + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(_cmake_target IN LISTS _cmake_import_check_targets) + foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}") + if(NOT EXISTS "${_cmake_file}") + message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file + \"${_cmake_file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + unset(_cmake_file) + unset("_cmake_import_check_files_for_${_cmake_target}") +endforeach() +unset(_cmake_target) +unset(_cmake_import_check_targets) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/lib/cmake/ncnn/ncnnConfig.cmake b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/lib/cmake/ncnn/ncnnConfig.cmake new file mode 100644 index 0000000..abb2dd6 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/lib/cmake/ncnn/ncnnConfig.cmake @@ -0,0 +1,42 @@ +set(NCNN_OPENMP ON) +set(NCNN_THREADS ON) +set(NCNN_VULKAN ON) +set(NCNN_SHARED_LIB ON) +set(NCNN_SYSTEM_GLSLANG OFF) + +if(NCNN_OPENMP) + find_package(OpenMP) +endif() + +if(NCNN_THREADS) + set(CMAKE_THREAD_PREFER_PTHREAD TRUE) + set(THREADS_PREFER_PTHREAD_FLAG TRUE) + find_package(Threads REQUIRED) +endif() + +if(NCNN_VULKAN) + find_package(Vulkan REQUIRED) + + if(NOT NCNN_SHARED_LIB) + if(NCNN_SYSTEM_GLSLANG) + find_package(glslang QUIET) + if(NOT glslang_FOUND) + set(GLSLANG_TARGET_DIR "") + include(${GLSLANG_TARGET_DIR}/OSDependentTargets.cmake) + include(${GLSLANG_TARGET_DIR}/OGLCompilerTargets.cmake) + if(EXISTS "${GLSLANG_TARGET_DIR}/HLSLTargets.cmake") + # hlsl support can be optional + include("${GLSLANG_TARGET_DIR}/HLSLTargets.cmake") + endif() + include(${GLSLANG_TARGET_DIR}/glslangTargets.cmake) + include(${GLSLANG_TARGET_DIR}/SPIRVTargets.cmake) + endif() + else() + set(glslang_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../lib/cmake/glslang") + find_package(glslang QUIET) + endif() + + endif() +endif() + +include(${CMAKE_CURRENT_LIST_DIR}/ncnn.cmake) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/lib/pkgconfig/ncnn.pc b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/lib/pkgconfig/ncnn.pc new file mode 100644 index 0000000..2ae00de --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/arm64-v8a/lib/pkgconfig/ncnn.pc @@ -0,0 +1,11 @@ +prefix=${pcfiledir}/../.. +librarydir=${prefix}/lib +includedir=${prefix}/include + +Name: ncnn +Description: high-performance neural network inference framework optimized for the mobile platform +Version: 1.0.20221128 +URL: https://github.com/Tencent/ncnn +Libs: -L"${librarydir}" -lncnn +Cflags: -I"${includedir}" + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/allocator.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/allocator.h new file mode 100644 index 0000000..3a5ebca --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/allocator.h @@ -0,0 +1,448 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_ALLOCATOR_H +#define NCNN_ALLOCATOR_H + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include "platform.h" + +#include + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +#include +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +// the alignment of all the allocated buffers +#if NCNN_AVX512 +#define NCNN_MALLOC_ALIGN 64 +#elif NCNN_AVX +#define NCNN_MALLOC_ALIGN 32 +#else +#define NCNN_MALLOC_ALIGN 16 +#endif + +// we have some optimized kernels that may overread buffer a bit in loop +// it is common to interleave next-loop data load with arithmetic instructions +// allocating more bytes keeps us safe from SEGV_ACCERR failure +#define NCNN_MALLOC_OVERREAD 64 + +// Aligns a pointer to the specified number of bytes +// ptr Aligned pointer +// n Alignment size that must be a power of two +template +static NCNN_FORCEINLINE _Tp* alignPtr(_Tp* ptr, int n = (int)sizeof(_Tp)) +{ + return (_Tp*)(((size_t)ptr + n - 1) & -n); +} + +// Aligns a buffer size to the specified number of bytes +// The function returns the minimum number that is greater or equal to sz and is divisible by n +// sz Buffer size to align +// n Alignment size that must be a power of two +static NCNN_FORCEINLINE size_t alignSize(size_t sz, int n) +{ + return (sz + n - 1) & -n; +} + +static NCNN_FORCEINLINE void* fastMalloc(size_t size) +{ +#if _MSC_VER + return _aligned_malloc(size, NCNN_MALLOC_ALIGN); +#elif (defined(__unix__) || defined(__APPLE__)) && _POSIX_C_SOURCE >= 200112L || (__ANDROID__ && __ANDROID_API__ >= 17) + void* ptr = 0; + if (posix_memalign(&ptr, NCNN_MALLOC_ALIGN, size + NCNN_MALLOC_OVERREAD)) + ptr = 0; + return ptr; +#elif __ANDROID__ && __ANDROID_API__ < 17 + return memalign(NCNN_MALLOC_ALIGN, size + NCNN_MALLOC_OVERREAD); +#else + unsigned char* udata = (unsigned char*)malloc(size + sizeof(void*) + NCNN_MALLOC_ALIGN + NCNN_MALLOC_OVERREAD); + if (!udata) + return 0; + unsigned char** adata = alignPtr((unsigned char**)udata + 1, NCNN_MALLOC_ALIGN); + adata[-1] = udata; + return adata; +#endif +} + +static NCNN_FORCEINLINE void fastFree(void* ptr) +{ + if (ptr) + { +#if _MSC_VER + _aligned_free(ptr); +#elif (defined(__unix__) || defined(__APPLE__)) && _POSIX_C_SOURCE >= 200112L || (__ANDROID__ && __ANDROID_API__ >= 17) + free(ptr); +#elif __ANDROID__ && __ANDROID_API__ < 17 + free(ptr); +#else + unsigned char* udata = ((unsigned char**)ptr)[-1]; + free(udata); +#endif + } +} + +#if NCNN_THREADS +// exchange-add operation for atomic operations on reference counters +#if defined __riscv && !defined __riscv_atomic +// riscv target without A extension +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#elif defined __INTEL_COMPILER && !(defined WIN32 || defined _WIN32) +// atomic increment on the linux version of the Intel(tm) compiler +#define NCNN_XADD(addr, delta) (int)_InterlockedExchangeAdd(const_cast(reinterpret_cast(addr)), delta) +#elif defined __GNUC__ +#if defined __clang__ && __clang_major__ >= 3 && !defined __ANDROID__ && !defined __EMSCRIPTEN__ && !defined(__CUDACC__) +#ifdef __ATOMIC_ACQ_REL +#define NCNN_XADD(addr, delta) __c11_atomic_fetch_add((_Atomic(int)*)(addr), delta, __ATOMIC_ACQ_REL) +#else +#define NCNN_XADD(addr, delta) __atomic_fetch_add((_Atomic(int)*)(addr), delta, 4) +#endif +#else +#if defined __ATOMIC_ACQ_REL && !defined __clang__ +// version for gcc >= 4.7 +#define NCNN_XADD(addr, delta) (int)__atomic_fetch_add((unsigned*)(addr), (unsigned)(delta), __ATOMIC_ACQ_REL) +#else +#define NCNN_XADD(addr, delta) (int)__sync_fetch_and_add((unsigned*)(addr), (unsigned)(delta)) +#endif +#endif +#elif defined _MSC_VER && !defined RC_INVOKED +#define NCNN_XADD(addr, delta) (int)_InterlockedExchangeAdd((long volatile*)addr, delta) +#else +// thread-unsafe branch +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#endif +#else // NCNN_THREADS +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#endif // NCNN_THREADS + +class NCNN_EXPORT Allocator +{ +public: + virtual ~Allocator(); + virtual void* fastMalloc(size_t size) = 0; + virtual void fastFree(void* ptr) = 0; +}; + +class PoolAllocatorPrivate; +class NCNN_EXPORT PoolAllocator : public Allocator +{ +public: + PoolAllocator(); + ~PoolAllocator(); + + // ratio range 0 ~ 1 + // default cr = 0 + void set_size_compare_ratio(float scr); + + // budget drop threshold + // default threshold = 10 + void set_size_drop_threshold(size_t); + + // release all budgets immediately + void clear(); + + virtual void* fastMalloc(size_t size); + virtual void fastFree(void* ptr); + +private: + PoolAllocator(const PoolAllocator&); + PoolAllocator& operator=(const PoolAllocator&); + +private: + PoolAllocatorPrivate* const d; +}; + +class UnlockedPoolAllocatorPrivate; +class NCNN_EXPORT UnlockedPoolAllocator : public Allocator +{ +public: + UnlockedPoolAllocator(); + ~UnlockedPoolAllocator(); + + // ratio range 0 ~ 1 + // default cr = 0 + void set_size_compare_ratio(float scr); + + // budget drop threshold + // default threshold = 10 + void set_size_drop_threshold(size_t); + + // release all budgets immediately + void clear(); + + virtual void* fastMalloc(size_t size); + virtual void fastFree(void* ptr); + +private: + UnlockedPoolAllocator(const UnlockedPoolAllocator&); + UnlockedPoolAllocator& operator=(const UnlockedPoolAllocator&); + +private: + UnlockedPoolAllocatorPrivate* const d; +}; + +#if NCNN_VULKAN + +class VulkanDevice; + +class NCNN_EXPORT VkBufferMemory +{ +public: + VkBuffer buffer; + + // the base offset assigned by allocator + size_t offset; + size_t capacity; + + VkDeviceMemory memory; + void* mapped_ptr; + + // buffer state, modified by command functions internally + mutable VkAccessFlags access_flags; + mutable VkPipelineStageFlags stage_flags; + + // initialize and modified by mat + int refcount; +}; + +class NCNN_EXPORT VkImageMemory +{ +public: + VkImage image; + VkImageView imageview; + + // underlying info assigned by allocator + int width; + int height; + int depth; + VkFormat format; + + VkDeviceMemory memory; + void* mapped_ptr; + + // the base offset assigned by allocator + size_t bind_offset; + size_t bind_capacity; + + // image state, modified by command functions internally + mutable VkAccessFlags access_flags; + mutable VkImageLayout image_layout; + mutable VkPipelineStageFlags stage_flags; + + // in-execution state, modified by command functions internally + mutable int command_refcount; + + // initialize and modified by mat + int refcount; +}; + +class NCNN_EXPORT VkAllocator +{ +public: + explicit VkAllocator(const VulkanDevice* _vkdev); + virtual ~VkAllocator(); + + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size) = 0; + virtual void fastFree(VkBufferMemory* ptr) = 0; + virtual int flush(VkBufferMemory* ptr); + virtual int invalidate(VkBufferMemory* ptr); + + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack) = 0; + virtual void fastFree(VkImageMemory* ptr) = 0; + +public: + const VulkanDevice* vkdev; + uint32_t buffer_memory_type_index; + uint32_t image_memory_type_index; + uint32_t reserved_type_index; + bool mappable; + bool coherent; + +protected: + VkBuffer create_buffer(size_t size, VkBufferUsageFlags usage); + VkDeviceMemory allocate_memory(size_t size, uint32_t memory_type_index); + VkDeviceMemory allocate_dedicated_memory(size_t size, uint32_t memory_type_index, VkImage image, VkBuffer buffer); + + VkImage create_image(int width, int height, int depth, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage); + VkImageView create_imageview(VkImage image, VkFormat format); +}; + +class VkBlobAllocatorPrivate; +class NCNN_EXPORT VkBlobAllocator : public VkAllocator +{ +public: + explicit VkBlobAllocator(const VulkanDevice* vkdev, size_t preferred_block_size = 16 * 1024 * 1024); // 16M + virtual ~VkBlobAllocator(); + +public: + // release all budgets immediately + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkBlobAllocator(const VkBlobAllocator&); + VkBlobAllocator& operator=(const VkBlobAllocator&); + +private: + VkBlobAllocatorPrivate* const d; +}; + +class VkWeightAllocatorPrivate; +class NCNN_EXPORT VkWeightAllocator : public VkAllocator +{ +public: + explicit VkWeightAllocator(const VulkanDevice* vkdev, size_t preferred_block_size = 8 * 1024 * 1024); // 8M + virtual ~VkWeightAllocator(); + +public: + // release all blocks immediately + virtual void clear(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkWeightAllocator(const VkWeightAllocator&); + VkWeightAllocator& operator=(const VkWeightAllocator&); + +private: + VkWeightAllocatorPrivate* const d; +}; + +class VkStagingAllocatorPrivate; +class NCNN_EXPORT VkStagingAllocator : public VkAllocator +{ +public: + explicit VkStagingAllocator(const VulkanDevice* vkdev); + virtual ~VkStagingAllocator(); + +public: + // ratio range 0 ~ 1 + // default cr = 0.75 + void set_size_compare_ratio(float scr); + + // release all budgets immediately + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkStagingAllocator(const VkStagingAllocator&); + VkStagingAllocator& operator=(const VkStagingAllocator&); + +private: + VkStagingAllocatorPrivate* const d; +}; + +class VkWeightStagingAllocatorPrivate; +class NCNN_EXPORT VkWeightStagingAllocator : public VkAllocator +{ +public: + explicit VkWeightStagingAllocator(const VulkanDevice* vkdev); + virtual ~VkWeightStagingAllocator(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkWeightStagingAllocator(const VkWeightStagingAllocator&); + VkWeightStagingAllocator& operator=(const VkWeightStagingAllocator&); + +private: + VkWeightStagingAllocatorPrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class NCNN_EXPORT VkAndroidHardwareBufferImageAllocator : public VkAllocator +{ +public: + VkAndroidHardwareBufferImageAllocator(const VulkanDevice* _vkdev, AHardwareBuffer* _hb); + virtual ~VkAndroidHardwareBufferImageAllocator(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkAndroidHardwareBufferImageAllocator(const VkAndroidHardwareBufferImageAllocator&); + VkAndroidHardwareBufferImageAllocator& operator=(const VkAndroidHardwareBufferImageAllocator&); + +public: + int init(); + + int width() const; + int height() const; + uint64_t external_format() const; + +public: + AHardwareBuffer* hb; + AHardwareBuffer_Desc bufferDesc; + VkAndroidHardwareBufferFormatPropertiesANDROID bufferFormatProperties; + VkAndroidHardwareBufferPropertiesANDROID bufferProperties; + VkSamplerYcbcrConversionKHR samplerYcbcrConversion; +}; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_ALLOCATOR_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/benchmark.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/benchmark.h new file mode 100644 index 0000000..3d5c0cd --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/benchmark.h @@ -0,0 +1,36 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_BENCHMARK_H +#define NCNN_BENCHMARK_H + +#include "layer.h" +#include "mat.h" +#include "platform.h" + +namespace ncnn { + +// get now timestamp in ms +NCNN_EXPORT double get_current_time(); + +#if NCNN_BENCHMARK + +NCNN_EXPORT void benchmark(const Layer* layer, double start, double end); +NCNN_EXPORT void benchmark(const Layer* layer, const Mat& bottom_blob, Mat& top_blob, double start, double end); + +#endif // NCNN_BENCHMARK + +} // namespace ncnn + +#endif // NCNN_BENCHMARK_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/blob.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/blob.h new file mode 100644 index 0000000..c9f144f --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/blob.h @@ -0,0 +1,44 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_BLOB_H +#define NCNN_BLOB_H + +#include "mat.h" +#include "platform.h" + +namespace ncnn { + +class NCNN_EXPORT Blob +{ +public: + // empty + Blob(); + +public: +#if NCNN_STRING + // blob name + std::string name; +#endif // NCNN_STRING + // layer index which produce this blob as output + int producer; + // layer index which need this blob as input + int consumer; + // shape hint + Mat shape; +}; + +} // namespace ncnn + +#endif // NCNN_BLOB_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/c_api.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/c_api.h new file mode 100644 index 0000000..b7435f8 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/c_api.h @@ -0,0 +1,327 @@ +/* Tencent is pleased to support the open source community by making ncnn available. + * + * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef NCNN_C_API_H +#define NCNN_C_API_H + +#include "platform.h" + +#if NCNN_C_API + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +NCNN_EXPORT const char* ncnn_version(); + +/* allocator api */ +typedef struct __ncnn_allocator_t* ncnn_allocator_t; +struct NCNN_EXPORT __ncnn_allocator_t +{ + void* pthis; + + void* (*fast_malloc)(ncnn_allocator_t allocator, size_t size); + void (*fast_free)(ncnn_allocator_t allocator, void* ptr); +}; + +NCNN_EXPORT ncnn_allocator_t ncnn_allocator_create_pool_allocator(); +NCNN_EXPORT ncnn_allocator_t ncnn_allocator_create_unlocked_pool_allocator(); +NCNN_EXPORT void ncnn_allocator_destroy(ncnn_allocator_t allocator); + +/* option api */ +typedef struct __ncnn_option_t* ncnn_option_t; + +NCNN_EXPORT ncnn_option_t ncnn_option_create(); +NCNN_EXPORT void ncnn_option_destroy(ncnn_option_t opt); + +NCNN_EXPORT int ncnn_option_get_num_threads(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_num_threads(ncnn_option_t opt, int num_threads); + +NCNN_EXPORT int ncnn_option_get_use_local_pool_allocator(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_use_local_pool_allocator(ncnn_option_t opt, int use_local_pool_allocator); + +NCNN_EXPORT void ncnn_option_set_blob_allocator(ncnn_option_t opt, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_option_set_workspace_allocator(ncnn_option_t opt, ncnn_allocator_t allocator); + +NCNN_EXPORT int ncnn_option_get_use_vulkan_compute(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_use_vulkan_compute(ncnn_option_t opt, int use_vulkan_compute); + +/* mat api */ +typedef struct __ncnn_mat_t* ncnn_mat_t; + +NCNN_EXPORT ncnn_mat_t ncnn_mat_create(); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_1d(int w, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_2d(int w, int h, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_3d(int w, int h, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_4d(int w, int h, int d, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_1d(int w, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_2d(int w, int h, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_3d(int w, int h, int c, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_4d(int w, int h, int d, int c, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_1d_elem(int w, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_2d_elem(int w, int h, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_3d_elem(int w, int h, int c, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_4d_elem(int w, int h, int d, int c, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_1d_elem(int w, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_2d_elem(int w, int h, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_3d_elem(int w, int h, int c, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_4d_elem(int w, int h, int d, int c, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_mat_destroy(ncnn_mat_t mat); + +NCNN_EXPORT void ncnn_mat_fill_float(ncnn_mat_t mat, float v); + +NCNN_EXPORT ncnn_mat_t ncnn_mat_clone(const ncnn_mat_t mat, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_1d(const ncnn_mat_t mat, int w, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_2d(const ncnn_mat_t mat, int w, int h, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_3d(const ncnn_mat_t mat, int w, int h, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_4d(const ncnn_mat_t mat, int w, int h, int d, int c, ncnn_allocator_t allocator); + +NCNN_EXPORT int ncnn_mat_get_dims(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_w(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_h(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_d(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_c(const ncnn_mat_t mat); +NCNN_EXPORT size_t ncnn_mat_get_elemsize(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_elempack(const ncnn_mat_t mat); +NCNN_EXPORT size_t ncnn_mat_get_cstep(const ncnn_mat_t mat); +NCNN_EXPORT void* ncnn_mat_get_data(const ncnn_mat_t mat); + +NCNN_EXPORT void* ncnn_mat_get_channel_data(const ncnn_mat_t mat, int c); + +#if NCNN_PIXEL + +/* mat pixel api */ +#define NCNN_MAT_PIXEL_RGB 1 +#define NCNN_MAT_PIXEL_BGR 2 +#define NCNN_MAT_PIXEL_GRAY 3 +#define NCNN_MAT_PIXEL_RGBA 4 +#define NCNN_MAT_PIXEL_BGRA 5 +#define NCNN_MAT_PIXEL_X2Y(X, Y) (X | (Y << 16)) +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels(const unsigned char* pixels, int type, int w, int h, int stride, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, int target_width, int target_height, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_mat_to_pixels(const ncnn_mat_t mat, unsigned char* pixels, int type, int stride); +NCNN_EXPORT void ncnn_mat_to_pixels_resize(const ncnn_mat_t mat, unsigned char* pixels, int type, int target_width, int target_height, int target_stride); + +#endif /* NCNN_PIXEL */ + +NCNN_EXPORT void ncnn_mat_substract_mean_normalize(ncnn_mat_t mat, const float* mean_vals, const float* norm_vals); + +NCNN_EXPORT void ncnn_convert_packing(const ncnn_mat_t src, ncnn_mat_t* dst, int elempack, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_flatten(const ncnn_mat_t src, ncnn_mat_t* dst, const ncnn_option_t opt); + +/* blob api */ +typedef struct __ncnn_blob_t* ncnn_blob_t; + +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_blob_get_name(const ncnn_blob_t blob); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_blob_get_producer(const ncnn_blob_t blob); +NCNN_EXPORT int ncnn_blob_get_consumer(const ncnn_blob_t blob); + +NCNN_EXPORT void ncnn_blob_get_shape(const ncnn_blob_t blob, int* dims, int* w, int* h, int* c); + +/* paramdict api */ +typedef struct __ncnn_paramdict_t* ncnn_paramdict_t; + +NCNN_EXPORT ncnn_paramdict_t ncnn_paramdict_create(); +NCNN_EXPORT void ncnn_paramdict_destroy(ncnn_paramdict_t pd); + +NCNN_EXPORT int ncnn_paramdict_get_type(const ncnn_paramdict_t pd, int id); + +NCNN_EXPORT int ncnn_paramdict_get_int(const ncnn_paramdict_t pd, int id, int def); +NCNN_EXPORT float ncnn_paramdict_get_float(const ncnn_paramdict_t pd, int id, float def); +NCNN_EXPORT ncnn_mat_t ncnn_paramdict_get_array(const ncnn_paramdict_t pd, int id, const ncnn_mat_t def); + +NCNN_EXPORT void ncnn_paramdict_set_int(ncnn_paramdict_t pd, int id, int i); +NCNN_EXPORT void ncnn_paramdict_set_float(ncnn_paramdict_t pd, int id, float f); +NCNN_EXPORT void ncnn_paramdict_set_array(ncnn_paramdict_t pd, int id, const ncnn_mat_t v); + +/* datareader api */ +typedef struct __ncnn_datareader_t* ncnn_datareader_t; +struct NCNN_EXPORT __ncnn_datareader_t +{ + void* pthis; + +#if NCNN_STRING + int (*scan)(ncnn_datareader_t dr, const char* format, void* p); +#endif /* NCNN_STRING */ + size_t (*read)(ncnn_datareader_t dr, void* buf, size_t size); +}; + +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create(); +#if NCNN_STDIO +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create_from_stdio(FILE* fp); +#endif /* NCNN_STDIO */ +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create_from_memory(const unsigned char** mem); +NCNN_EXPORT void ncnn_datareader_destroy(ncnn_datareader_t dr); + +/* modelbin api */ +typedef struct __ncnn_modelbin_t* ncnn_modelbin_t; +struct NCNN_EXPORT __ncnn_modelbin_t +{ + void* pthis; + + ncnn_mat_t (*load_1d)(const ncnn_modelbin_t mb, int w, int type); + ncnn_mat_t (*load_2d)(const ncnn_modelbin_t mb, int w, int h, int type); + ncnn_mat_t (*load_3d)(const ncnn_modelbin_t mb, int w, int h, int c, int type); +}; + +NCNN_EXPORT ncnn_modelbin_t ncnn_modelbin_create_from_datareader(const ncnn_datareader_t dr); +NCNN_EXPORT ncnn_modelbin_t ncnn_modelbin_create_from_mat_array(const ncnn_mat_t* weights, int n); +NCNN_EXPORT void ncnn_modelbin_destroy(ncnn_modelbin_t mb); + +/* layer api */ +typedef struct __ncnn_layer_t* ncnn_layer_t; +struct NCNN_EXPORT __ncnn_layer_t +{ + void* pthis; + + int (*load_param)(ncnn_layer_t layer, const ncnn_paramdict_t pd); + int (*load_model)(ncnn_layer_t layer, const ncnn_modelbin_t mb); + + int (*create_pipeline)(ncnn_layer_t layer, const ncnn_option_t opt); + int (*destroy_pipeline)(ncnn_layer_t layer, const ncnn_option_t opt); + + int (*forward_1)(const ncnn_layer_t layer, const ncnn_mat_t bottom_blob, ncnn_mat_t* top_blob, const ncnn_option_t opt); + int (*forward_n)(const ncnn_layer_t layer, const ncnn_mat_t* bottom_blobs, int n, ncnn_mat_t* top_blobs, int n2, const ncnn_option_t opt); + + int (*forward_inplace_1)(const ncnn_layer_t layer, ncnn_mat_t bottom_top_blob, const ncnn_option_t opt); + int (*forward_inplace_n)(const ncnn_layer_t layer, ncnn_mat_t* bottom_top_blobs, int n, const ncnn_option_t opt); +}; + +NCNN_EXPORT ncnn_layer_t ncnn_layer_create(); +NCNN_EXPORT ncnn_layer_t ncnn_layer_create_by_typeindex(int typeindex); +#if NCNN_STRING +NCNN_EXPORT ncnn_layer_t ncnn_layer_create_by_type(const char* type); +#endif /* NCNN_STRING */ +NCNN_EXPORT void ncnn_layer_destroy(ncnn_layer_t layer); + +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_layer_get_name(const ncnn_layer_t layer); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_layer_get_typeindex(const ncnn_layer_t layer); +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_layer_get_type(const ncnn_layer_t layer); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_layer_get_one_blob_only(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_inplace(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_vulkan(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_packing(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_bf16_storage(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_fp16_storage(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_image_storage(const ncnn_layer_t layer); + +NCNN_EXPORT void ncnn_layer_set_one_blob_only(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_inplace(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_vulkan(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_packing(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_bf16_storage(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_fp16_storage(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_image_storage(ncnn_layer_t layer, int enable); + +NCNN_EXPORT int ncnn_layer_get_bottom_count(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_bottom(const ncnn_layer_t layer, int i); +NCNN_EXPORT int ncnn_layer_get_top_count(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_top(const ncnn_layer_t layer, int i); + +NCNN_EXPORT void ncnn_blob_get_bottom_shape(const ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c); +NCNN_EXPORT void ncnn_blob_get_top_shape(const ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c); + +/* layer factory function */ +typedef ncnn_layer_t (*ncnn_layer_creator_t)(void* userdata); +typedef void (*ncnn_layer_destroyer_t)(ncnn_layer_t layer, void* userdata); + +typedef struct __ncnn_net_custom_layer_factory_t* ncnn_net_custom_layer_factory_t; +struct __ncnn_net_custom_layer_factory_t +{ + ncnn_layer_creator_t creator; + ncnn_layer_destroyer_t destroyer; + void* userdata; + ncnn_net_custom_layer_factory_t next; +}; + +/* net api */ +typedef struct __ncnn_net_t* ncnn_net_t; +struct __ncnn_net_t +{ + void* pthis; + + ncnn_net_custom_layer_factory_t custom_layer_factory; +}; + +NCNN_EXPORT ncnn_net_t ncnn_net_create(); +NCNN_EXPORT void ncnn_net_destroy(ncnn_net_t net); + +NCNN_EXPORT ncnn_option_t ncnn_net_get_option(ncnn_net_t net); +NCNN_EXPORT void ncnn_net_set_option(ncnn_net_t net, ncnn_option_t opt); + +#if NCNN_STRING +NCNN_EXPORT void ncnn_net_register_custom_layer_by_type(ncnn_net_t net, const char* type, ncnn_layer_creator_t creator, ncnn_layer_destroyer_t destroyer, void* userdata); +#endif /* NCNN_STRING */ +NCNN_EXPORT void ncnn_net_register_custom_layer_by_typeindex(ncnn_net_t net, int typeindex, ncnn_layer_creator_t creator, ncnn_layer_destroyer_t destroyer, void* userdata); + +#if NCNN_STDIO +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param(ncnn_net_t net, const char* path); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_load_param_bin(ncnn_net_t net, const char* path); +NCNN_EXPORT int ncnn_net_load_model(ncnn_net_t net, const char* path); +#endif /* NCNN_STDIO */ + +#if NCNN_STDIO +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param_memory(ncnn_net_t net, const char* mem); +#endif /* NCNN_STRING */ +#endif /* NCNN_STDIO */ +NCNN_EXPORT int ncnn_net_load_param_bin_memory(ncnn_net_t net, const unsigned char* mem); +NCNN_EXPORT int ncnn_net_load_model_memory(ncnn_net_t net, const unsigned char* mem); + +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param_datareader(ncnn_net_t net, const ncnn_datareader_t dr); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_load_param_bin_datareader(ncnn_net_t net, const ncnn_datareader_t dr); +NCNN_EXPORT int ncnn_net_load_model_datareader(ncnn_net_t net, const ncnn_datareader_t dr); + +NCNN_EXPORT void ncnn_net_clear(ncnn_net_t net); + +/* extractor api */ +typedef struct __ncnn_extractor_t* ncnn_extractor_t; + +NCNN_EXPORT ncnn_extractor_t ncnn_extractor_create(ncnn_net_t net); +NCNN_EXPORT void ncnn_extractor_destroy(ncnn_extractor_t ex); + +NCNN_EXPORT void ncnn_extractor_set_option(ncnn_extractor_t ex, const ncnn_option_t opt); + +#if NCNN_STRING +NCNN_EXPORT int ncnn_extractor_input(ncnn_extractor_t ex, const char* name, const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_extractor_extract(ncnn_extractor_t ex, const char* name, ncnn_mat_t* mat); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_extractor_input_index(ncnn_extractor_t ex, int index, const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_extractor_extract_index(ncnn_extractor_t ex, int index, ncnn_mat_t* mat); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* NCNN_C_API */ + +#endif /* NCNN_C_API_H */ diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/command.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/command.h new file mode 100644 index 0000000..337d085 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/command.h @@ -0,0 +1,136 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_COMMAND_H +#define NCNN_COMMAND_H + +#include "platform.h" + +#if NCNN_VULKAN + +#include "mat.h" + +#include + +namespace ncnn { + +class Pipeline; +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class ImportAndroidHardwareBufferPipeline; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API +class VkComputePrivate; +class NCNN_EXPORT VkCompute +{ +public: + explicit VkCompute(const VulkanDevice* vkdev); + virtual ~VkCompute(); + +public: + void record_upload(const Mat& src, VkMat& dst, const Option& opt); + + void record_upload(const Mat& src, VkImageMat& dst, const Option& opt); + + void record_download(const VkMat& src, Mat& dst, const Option& opt); + + void record_download(const VkImageMat& src, Mat& dst, const Option& opt); + + void record_buffer_to_image(const VkMat& src, VkImageMat& dst, const Option& opt); + + void record_image_to_buffer(const VkImageMat& src, VkMat& dst, const Option& opt); + + void record_clone(const Mat& src, VkMat& dst, const Option& opt); + + void record_clone(const Mat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkMat& src, Mat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, Mat& dst, const Option& opt); + + void record_clone(const VkMat& src, VkMat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkMat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, VkMat& dst, const Option& opt); + + void record_pipeline(const Pipeline* pipeline, const std::vector& bindings, const std::vector& constants, const VkMat& dispatcher); + + void record_pipeline(const Pipeline* pipeline, const std::vector& bindings, const std::vector& constants, const VkImageMat& dispatcher); + + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const VkMat& dispatcher); + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const VkImageMat& dispatcher); + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const Mat& dispatcher); + +#if NCNN_BENCHMARK + void record_write_timestamp(uint32_t query); +#endif // NCNN_BENCHMARK + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 + void record_import_android_hardware_buffer(const ImportAndroidHardwareBufferPipeline* pipeline, const VkImageMat& src, const VkMat& dst); + + void record_import_android_hardware_buffer(const ImportAndroidHardwareBufferPipeline* pipeline, const VkImageMat& src, const VkImageMat& dst); +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + + int submit_and_wait(); + + int reset(); + +#if NCNN_BENCHMARK + int create_query_pool(uint32_t query_count); + + int get_query_pool_results(uint32_t first_query, uint32_t query_count, std::vector& results); +#endif // NCNN_BENCHMARK + +protected: + const VulkanDevice* vkdev; + + void barrier_readwrite(const VkMat& binding); + void barrier_readwrite(const VkImageMat& binding); + void barrier_readonly(const VkImageMat& binding); + +private: + VkComputePrivate* const d; +}; + +class VkTransferPrivate; +class NCNN_EXPORT VkTransfer +{ +public: + explicit VkTransfer(const VulkanDevice* vkdev); + virtual ~VkTransfer(); + +public: + void record_upload(const Mat& src, VkMat& dst, const Option& opt, bool flatten = true); + + void record_upload(const Mat& src, VkImageMat& dst, const Option& opt); + + int submit_and_wait(); + +protected: + const VulkanDevice* vkdev; + +private: + VkTransferPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_VULKAN + +#endif // NCNN_COMMAND_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/cpu.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/cpu.h new file mode 100644 index 0000000..0f748f3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/cpu.h @@ -0,0 +1,169 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_CPU_H +#define NCNN_CPU_H + +#include + +#if (defined _WIN32 && !(defined __MINGW32__)) +#define WIN32_LEAN_AND_MEAN +#include +#endif +#if defined __ANDROID__ || defined __linux__ +#include // cpu_set_t +#endif + +#include "platform.h" + +namespace ncnn { + +class NCNN_EXPORT CpuSet +{ +public: + CpuSet(); + void enable(int cpu); + void disable(int cpu); + void disable_all(); + bool is_enabled(int cpu) const; + int num_enabled() const; + +public: +#if (defined _WIN32 && !(defined __MINGW32__)) + ULONG_PTR mask; +#endif +#if defined __ANDROID__ || defined __linux__ + cpu_set_t cpu_set; +#endif +#if __APPLE__ + unsigned int policy; +#endif +}; + +// test optional cpu features +// edsp = armv7 edsp +NCNN_EXPORT int cpu_support_arm_edsp(); +// neon = armv7 neon or aarch64 asimd +NCNN_EXPORT int cpu_support_arm_neon(); +// vfpv4 = armv7 fp16 + fma +NCNN_EXPORT int cpu_support_arm_vfpv4(); +// asimdhp = aarch64 asimd half precision +NCNN_EXPORT int cpu_support_arm_asimdhp(); +// asimddp = aarch64 asimd dot product +NCNN_EXPORT int cpu_support_arm_asimddp(); +// asimdfhm = aarch64 asimd fhm +NCNN_EXPORT int cpu_support_arm_asimdfhm(); +// bf16 = aarch64 bf16 +NCNN_EXPORT int cpu_support_arm_bf16(); +// i8mm = aarch64 i8mm +NCNN_EXPORT int cpu_support_arm_i8mm(); +// sve = aarch64 sve +NCNN_EXPORT int cpu_support_arm_sve(); +// sve2 = aarch64 sve2 +NCNN_EXPORT int cpu_support_arm_sve2(); +// svebf16 = aarch64 svebf16 +NCNN_EXPORT int cpu_support_arm_svebf16(); +// svei8mm = aarch64 svei8mm +NCNN_EXPORT int cpu_support_arm_svei8mm(); +// svef32mm = aarch64 svef32mm +NCNN_EXPORT int cpu_support_arm_svef32mm(); + +// avx = x86 avx +NCNN_EXPORT int cpu_support_x86_avx(); +// fma = x86 fma +NCNN_EXPORT int cpu_support_x86_fma(); +// xop = x86 xop +NCNN_EXPORT int cpu_support_x86_xop(); +// f16c = x86 f16c +NCNN_EXPORT int cpu_support_x86_f16c(); +// avx2 = x86 avx2 + fma + f16c +NCNN_EXPORT int cpu_support_x86_avx2(); +// avx_vnni = x86 avx vnni +NCNN_EXPORT int cpu_support_x86_avx_vnni(); +// avx512 = x86 avx512f + avx512cd + avx512bw + avx512dq + avx512vl +NCNN_EXPORT int cpu_support_x86_avx512(); +// avx512_vnni = x86 avx512 vnni +NCNN_EXPORT int cpu_support_x86_avx512_vnni(); +// avx512_bf16 = x86 avx512 bf16 +NCNN_EXPORT int cpu_support_x86_avx512_bf16(); +// avx512_fp16 = x86 avx512 fp16 +NCNN_EXPORT int cpu_support_x86_avx512_fp16(); + +// lsx = loongarch lsx +NCNN_EXPORT int cpu_support_loongarch_lsx(); +// lasx = loongarch lasx +NCNN_EXPORT int cpu_support_loongarch_lasx(); + +// msa = mips mas +NCNN_EXPORT int cpu_support_mips_msa(); +// mmi = loongson mmi +NCNN_EXPORT int cpu_support_loongson_mmi(); + +// v = riscv vector +NCNN_EXPORT int cpu_support_riscv_v(); +// zfh = riscv half-precision float +NCNN_EXPORT int cpu_support_riscv_zfh(); +// vlenb = riscv vector length in bytes +NCNN_EXPORT int cpu_riscv_vlenb(); + +// cpu info +NCNN_EXPORT int get_cpu_count(); +NCNN_EXPORT int get_little_cpu_count(); +NCNN_EXPORT int get_big_cpu_count(); + +NCNN_EXPORT int get_physical_cpu_count(); +NCNN_EXPORT int get_physical_little_cpu_count(); +NCNN_EXPORT int get_physical_big_cpu_count(); + +// bind all threads on little clusters if powersave enabled +// affects HMP arch cpu like ARM big.LITTLE +// only implemented on android at the moment +// switching powersave is expensive and not thread-safe +// 0 = all cores enabled(default) +// 1 = only little clusters enabled +// 2 = only big clusters enabled +// return 0 if success for setter function +NCNN_EXPORT int get_cpu_powersave(); +NCNN_EXPORT int set_cpu_powersave(int powersave); + +// convenient wrapper +NCNN_EXPORT const CpuSet& get_cpu_thread_affinity_mask(int powersave); + +// set explicit thread affinity +NCNN_EXPORT int set_cpu_thread_affinity(const CpuSet& thread_affinity_mask); + +// misc function wrapper for openmp routines +NCNN_EXPORT int get_omp_num_threads(); +NCNN_EXPORT void set_omp_num_threads(int num_threads); + +NCNN_EXPORT int get_omp_dynamic(); +NCNN_EXPORT void set_omp_dynamic(int dynamic); + +NCNN_EXPORT int get_omp_thread_num(); + +NCNN_EXPORT int get_kmp_blocktime(); +NCNN_EXPORT void set_kmp_blocktime(int time_ms); + +// need to flush denormals on Intel Chipset. +// Other architectures such as ARM can be added as needed. +// 0 = DAZ OFF, FTZ OFF +// 1 = DAZ ON , FTZ OFF +// 2 = DAZ OFF, FTZ ON +// 3 = DAZ ON, FTZ ON +NCNN_EXPORT int get_flush_denormals(); +NCNN_EXPORT int set_flush_denormals(int flush_denormals); + +} // namespace ncnn + +#endif // NCNN_CPU_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/datareader.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/datareader.h new file mode 100644 index 0000000..ed2aba3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/datareader.h @@ -0,0 +1,122 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_DATAREADER_H +#define NCNN_DATAREADER_H + +#include "platform.h" +#if NCNN_STDIO +#include +#endif + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#endif +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +// data read wrapper +class NCNN_EXPORT DataReader +{ +public: + DataReader(); + virtual ~DataReader(); + +#if NCNN_STRING + // parse plain param text + // return 1 if scan success + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + + // read binary param and model data + // return bytes read + virtual size_t read(void* buf, size_t size) const; + + // get model data reference + // return bytes referenced + virtual size_t reference(size_t size, const void** buf) const; +}; + +#if NCNN_STDIO +class DataReaderFromStdioPrivate; +class NCNN_EXPORT DataReaderFromStdio : public DataReader +{ +public: + explicit DataReaderFromStdio(FILE* fp); + virtual ~DataReaderFromStdio(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + +private: + DataReaderFromStdio(const DataReaderFromStdio&); + DataReaderFromStdio& operator=(const DataReaderFromStdio&); + +private: + DataReaderFromStdioPrivate* const d; +}; +#endif // NCNN_STDIO + +class DataReaderFromMemoryPrivate; +class NCNN_EXPORT DataReaderFromMemory : public DataReader +{ +public: + explicit DataReaderFromMemory(const unsigned char*& mem); + virtual ~DataReaderFromMemory(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + virtual size_t reference(size_t size, const void** buf) const; + +private: + DataReaderFromMemory(const DataReaderFromMemory&); + DataReaderFromMemory& operator=(const DataReaderFromMemory&); + +private: + DataReaderFromMemoryPrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +class DataReaderFromAndroidAssetPrivate; +class NCNN_EXPORT DataReaderFromAndroidAsset : public DataReader +{ +public: + explicit DataReaderFromAndroidAsset(AAsset* asset); + virtual ~DataReaderFromAndroidAsset(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + +private: + DataReaderFromAndroidAsset(const DataReaderFromAndroidAsset&); + DataReaderFromAndroidAsset& operator=(const DataReaderFromAndroidAsset&); + +private: + DataReaderFromAndroidAssetPrivate* const d; +}; +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + +} // namespace ncnn + +#endif // NCNN_DATAREADER_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/gpu.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/gpu.h new file mode 100644 index 0000000..2ef4927 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/gpu.h @@ -0,0 +1,359 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_GPU_H +#define NCNN_GPU_H + +#include "platform.h" + +#if NCNN_VULKAN + +#include "mat.h" + +#include + +#include "vulkan_header_fix.h" + +namespace ncnn { + +// instance +NCNN_EXPORT int create_gpu_instance(); +NCNN_EXPORT void destroy_gpu_instance(); + +// instance extension capability +extern int support_VK_KHR_external_memory_capabilities; +extern int support_VK_KHR_get_physical_device_properties2; +extern int support_VK_KHR_get_surface_capabilities2; +extern int support_VK_KHR_surface; +extern int support_VK_EXT_debug_utils; +#if __ANDROID_API__ >= 26 +extern int support_VK_KHR_android_surface; +#endif // __ANDROID_API__ >= 26 + +// VK_KHR_external_memory_capabilities +extern PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR vkGetPhysicalDeviceExternalBufferPropertiesKHR; + +// VK_KHR_get_physical_device_properties2 +extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; +extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; +extern PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceImageFormatProperties2KHR vkGetPhysicalDeviceImageFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR; +extern PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR; +extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR vkGetPhysicalDeviceSparseImageFormatProperties2KHR; + +// VK_KHR_get_surface_capabilities2 +extern PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR; + +// VK_KHR_surface +extern PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; +extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; +extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; +extern PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; + +#if __ANDROID_API__ >= 26 +// VK_KHR_android_surface +extern PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; +#endif // __ANDROID_API__ >= 26 + +// VK_NV_cooperative_matrix +extern PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV vkGetPhysicalDeviceCooperativeMatrixPropertiesNV; + +// get info +NCNN_EXPORT int get_gpu_count(); +NCNN_EXPORT int get_default_gpu_index(); + +class GpuInfoPrivate; +class NCNN_EXPORT GpuInfo +{ +public: + explicit GpuInfo(); + virtual ~GpuInfo(); + + // vulkan physical device + VkPhysicalDevice physical_device() const; + + // memory properties + const VkPhysicalDeviceMemoryProperties& physical_device_memory_properties() const; + + // info + uint32_t api_version() const; + uint32_t driver_version() const; + uint32_t vendor_id() const; + uint32_t device_id() const; + const char* device_name() const; + uint8_t* pipeline_cache_uuid() const; + + // 0 = discrete gpu + // 1 = integrated gpu + // 2 = virtual gpu + // 3 = cpu + int type() const; + + // hardware limit + uint32_t max_shared_memory_size() const; + uint32_t max_workgroup_count_x() const; + uint32_t max_workgroup_count_y() const; + uint32_t max_workgroup_count_z() const; + uint32_t max_workgroup_invocations() const; + uint32_t max_workgroup_size_x() const; + uint32_t max_workgroup_size_y() const; + uint32_t max_workgroup_size_z() const; + size_t memory_map_alignment() const; + size_t buffer_offset_alignment() const; + size_t non_coherent_atom_size() const; + size_t buffer_image_granularity() const; + uint32_t max_image_dimension_1d() const; + uint32_t max_image_dimension_2d() const; + uint32_t max_image_dimension_3d() const; + float timestamp_period() const; + + // runtime + uint32_t compute_queue_family_index() const; + uint32_t graphics_queue_family_index() const; + uint32_t transfer_queue_family_index() const; + + uint32_t compute_queue_count() const; + uint32_t graphics_queue_count() const; + uint32_t transfer_queue_count() const; + + // property + bool unified_compute_transfer_queue() const; + + // subgroup + uint32_t subgroup_size() const; + bool support_subgroup_basic() const; + bool support_subgroup_vote() const; + bool support_subgroup_ballot() const; + bool support_subgroup_shuffle() const; + + // bug is not feature + bool bug_storage_buffer_no_l1() const; + bool bug_corrupted_online_pipeline_cache() const; + bool bug_buffer_image_load_zero() const; + + // but sometimes bug is a feature + bool bug_implicit_fp16_arithmetic() const; + + // fp16 and int8 feature + bool support_fp16_packed() const; + bool support_fp16_storage() const; + bool support_fp16_arithmetic() const; + bool support_int8_packed() const; + bool support_int8_storage() const; + bool support_int8_arithmetic() const; + + // ycbcr conversion feature + bool support_ycbcr_conversion() const; + + // cooperative matrix feature + bool support_cooperative_matrix() const; + bool support_cooperative_matrix_16_8_8() const; + + // extension capability + int support_VK_KHR_8bit_storage() const; + int support_VK_KHR_16bit_storage() const; + int support_VK_KHR_bind_memory2() const; + int support_VK_KHR_create_renderpass2() const; + int support_VK_KHR_dedicated_allocation() const; + int support_VK_KHR_descriptor_update_template() const; + int support_VK_KHR_external_memory() const; + int support_VK_KHR_get_memory_requirements2() const; + int support_VK_KHR_maintenance1() const; + int support_VK_KHR_maintenance2() const; + int support_VK_KHR_maintenance3() const; + int support_VK_KHR_multiview() const; + int support_VK_KHR_push_descriptor() const; + int support_VK_KHR_sampler_ycbcr_conversion() const; + int support_VK_KHR_shader_float16_int8() const; + int support_VK_KHR_shader_float_controls() const; + int support_VK_KHR_storage_buffer_storage_class() const; + int support_VK_KHR_swapchain() const; + int support_VK_EXT_descriptor_indexing() const; + int support_VK_EXT_memory_budget() const; + int support_VK_EXT_queue_family_foreign() const; +#if __ANDROID_API__ >= 26 + int support_VK_ANDROID_external_memory_android_hardware_buffer() const; +#endif // __ANDROID_API__ >= 26 + int support_VK_NV_cooperative_matrix() const; + +private: + GpuInfo(const GpuInfo&); + GpuInfo& operator=(const GpuInfo&); + +private: + friend int create_gpu_instance(); + GpuInfoPrivate* const d; +}; + +NCNN_EXPORT const GpuInfo& get_gpu_info(int device_index = get_default_gpu_index()); + +class VkAllocator; +class VkCompute; +class Option; +class PipelineCache; +class VulkanDevicePrivate; +class NCNN_EXPORT VulkanDevice +{ +public: + VulkanDevice(int device_index = get_default_gpu_index()); + ~VulkanDevice(); + + const GpuInfo& info; + + VkDevice vkdevice() const; + + VkShaderModule compile_shader_module(const uint32_t* spv_data, size_t spv_data_size) const; + + // with fixed workgroup size + VkShaderModule compile_shader_module(const uint32_t* spv_data, size_t spv_data_size, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z) const; + + // helper for creating pipeline + int create_descriptorset_layout(int binding_count, const int* binding_types, VkDescriptorSetLayout* descriptorset_layout) const; + int create_pipeline_layout(int push_constant_count, VkDescriptorSetLayout descriptorset_layout, VkPipelineLayout* pipeline_layout) const; + int create_pipeline(VkShaderModule shader_module, VkPipelineLayout pipeline_layout, const std::vector& specializations, VkPipeline* pipeline) const; + int create_descriptor_update_template(int binding_count, const int* binding_types, VkDescriptorSetLayout descriptorset_layout, VkPipelineLayout pipeline_layout, VkDescriptorUpdateTemplateKHR* descriptor_update_template) const; + + uint32_t find_memory_index(uint32_t memory_type_bits, VkFlags required, VkFlags preferred, VkFlags preferred_not) const; + bool is_mappable(uint32_t memory_type_index) const; + bool is_coherent(uint32_t memory_type_index) const; + + VkQueue acquire_queue(uint32_t queue_family_index) const; + void reclaim_queue(uint32_t queue_family_index, VkQueue queue) const; + + // allocator on this device + VkAllocator* acquire_blob_allocator() const; + void reclaim_blob_allocator(VkAllocator* allocator) const; + + VkAllocator* acquire_staging_allocator() const; + void reclaim_staging_allocator(VkAllocator* allocator) const; + + // immutable sampler for texelfetch + const VkSampler* immutable_texelfetch_sampler() const; + + // dummy buffer image + VkMat get_dummy_buffer() const; + VkImageMat get_dummy_image() const; + VkImageMat get_dummy_image_readonly() const; + + // pipeline cache on this device + const PipelineCache* get_pipeline_cache() const; + + // test image allocation + bool shape_support_image_storage(const Mat& shape) const; + + // current gpu heap memory budget in MB + uint32_t get_heap_budget() const; + + // utility operator + void convert_packing(const VkMat& src, VkMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkImageMat& src, VkImageMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkMat& src, VkImageMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkImageMat& src, VkMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + + // VK_KHR_bind_memory2 + PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; + PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; + + // VK_KHR_create_renderpass2 + PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; + PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; + PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; + + // VK_KHR_descriptor_update_template + PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; + PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; + PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; + + // VK_KHR_get_memory_requirements2 + PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; + PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; + PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; + + // VK_KHR_maintenance1 + PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; + + // VK_KHR_maintenance3 + PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; + + // VK_KHR_push_descriptor + PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; + PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; + + // VK_KHR_sampler_ycbcr_conversion + PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; + PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; + + // VK_KHR_swapchain + PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; + PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; + PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; + PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; + PFN_vkQueuePresentKHR vkQueuePresentKHR; + +#if __ANDROID_API__ >= 26 + // VK_ANDROID_external_memory_android_hardware_buffer + PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; + PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; +#endif // __ANDROID_API__ >= 26 + +protected: + // device extension + int init_device_extension(); + +private: + VulkanDevice(const VulkanDevice&); + VulkanDevice& operator=(const VulkanDevice&); + +private: + VulkanDevicePrivate* const d; +}; + +NCNN_EXPORT VulkanDevice* get_gpu_device(int device_index = get_default_gpu_index()); + +// online spirv compilation +NCNN_EXPORT int compile_spirv_module(const char* comp_string, const Option& opt, std::vector& spirv); +NCNN_EXPORT int compile_spirv_module(const char* comp_data, int comp_data_size, const Option& opt, std::vector& spirv); +NCNN_EXPORT int compile_spirv_module(int shader_type_index, const Option& opt, std::vector& spirv); + +// info from spirv +class NCNN_EXPORT ShaderInfo +{ +public: + int specialization_count; + int binding_count; + int push_constant_count; + + // 0 = null + // 1 = storage buffer + // 2 = storage image + // 3 = combined image sampler + int binding_types[16]; // 16 is large enough I think ... + + int reserved_0; + int reserved_1; + int reserved_2; + int reserved_3; +}; + +NCNN_EXPORT int resolve_shader_info(const uint32_t* spv_data, size_t spv_data_size, ShaderInfo& shader_info); + +} // namespace ncnn + +#endif // NCNN_VULKAN + +#endif // NCNN_GPU_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/layer.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/layer.h new file mode 100644 index 0000000..d02f65b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/layer.h @@ -0,0 +1,214 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_H +#define NCNN_LAYER_H + +#include "mat.h" +#include "modelbin.h" +#include "option.h" +#include "paramdict.h" +#include "platform.h" + +#include + +#if NCNN_VULKAN +#include "command.h" +#include "pipeline.h" + +#include +#endif // NCNN_VULKAN + +namespace ncnn { + +class NCNN_EXPORT Layer +{ +public: + // empty + Layer(); + // virtual destructor + virtual ~Layer(); + + // load layer specific parameter from parsed dict + // return 0 if success + virtual int load_param(const ParamDict& pd); + + // load layer specific weight data from model binary + // return 0 if success + virtual int load_model(const ModelBin& mb); + + // layer implementation specific setup + // return 0 if success + virtual int create_pipeline(const Option& opt); + + // layer implementation specific clean + // return 0 if success + virtual int destroy_pipeline(const Option& opt); + +public: + // one input and one output blob + bool one_blob_only; + + // support inplace inference + bool support_inplace; + + // support vulkan compute + bool support_vulkan; + + // accept input blob with packed storage + bool support_packing; + + // accept bf16 + bool support_bf16_storage; + + // accept fp16 + bool support_fp16_storage; + + // accept int8 + bool support_int8_storage; + + // shader image storage + bool support_image_storage; + + // shader tensor storage + bool support_tensor_storage; + + bool support_reserved_00; + + bool support_reserved_0; + bool support_reserved_1; + bool support_reserved_2; + bool support_reserved_3; + bool support_reserved_4; + bool support_reserved_5; + bool support_reserved_6; + bool support_reserved_7; + bool support_reserved_8; + bool support_reserved_9; + + // feature disabled set + int featmask; + +public: + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, const Option& opt) const; + virtual int forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, const Option& opt) const; + virtual int forward_inplace(Mat& bottom_top_blob, const Option& opt) const; + +#if NCNN_VULKAN +public: + // upload weight blob from host to device + virtual int upload_model(VkTransfer& cmd, const Option& opt); + +public: + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward_inplace(VkMat& bottom_top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward_inplace(VkImageMat& bottom_top_blob, VkCompute& cmd, const Option& opt) const; + +public: + // assigned immediately after creating this layer + const VulkanDevice* vkdev; +#endif // NCNN_VULKAN + +public: + // custom user data + void* userdata; + // layer type index + int typeindex; +#if NCNN_STRING + // layer type name + std::string type; + // layer name + std::string name; +#endif // NCNN_STRING + // blob index which this layer needs as input + std::vector bottoms; + // blob index which this layer produces as output + std::vector tops; + // shape hint + std::vector bottom_shapes; + std::vector top_shapes; +}; + +// layer factory function +typedef Layer* (*layer_creator_func)(void*); +typedef void (*layer_destroyer_func)(Layer*, void*); + +struct layer_registry_entry +{ +#if NCNN_STRING + // layer type name + const char* name; +#endif // NCNN_STRING + // layer factory entry + layer_creator_func creator; +}; + +struct custom_layer_registry_entry +{ +#if NCNN_STRING + // layer type name + const char* name; +#endif // NCNN_STRING + // layer factory entry + layer_creator_func creator; + layer_destroyer_func destroyer; + void* userdata; +}; + +#if NCNN_STRING +// get layer type from type name +NCNN_EXPORT int layer_to_index(const char* type); +// create layer from type name +NCNN_EXPORT Layer* create_layer(const char* type); +#endif // NCNN_STRING +// create layer from layer type +NCNN_EXPORT Layer* create_layer(int index); + +#define DEFINE_LAYER_CREATOR(name) \ + ::ncnn::Layer* name##_layer_creator(void* /*userdata*/) \ + { \ + return new name; \ + } + +#define DEFINE_LAYER_DESTROYER(name) \ + void name##_layer_destroyer(::ncnn::Layer* layer, void* /*userdata*/) \ + { \ + delete layer; \ + } + +} // namespace ncnn + +#endif // NCNN_LAYER_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/layer_shader_type.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/layer_shader_type.h new file mode 100644 index 0000000..c143e7d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/layer_shader_type.h @@ -0,0 +1,29 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_SHADER_TYPE_H +#define NCNN_LAYER_SHADER_TYPE_H + +namespace ncnn { + +namespace LayerShaderType { +enum LayerShaderType +{ +#include "layer_shader_type_enum.h" +}; +} // namespace LayerShaderType + +} // namespace ncnn + +#endif // NCNN_LAYER_SHADER_TYPE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/layer_shader_type_enum.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/layer_shader_type_enum.h new file mode 100644 index 0000000..f11cab9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/layer_shader_type_enum.h @@ -0,0 +1,370 @@ +// Layer Shader Enum header +// +// This file is auto-generated by cmake, don't edit it. + +absval = 0, +absval_pack4 = 1, +absval_pack8 = 2, +batchnorm = 3, +batchnorm_pack4 = 4, +batchnorm_pack8 = 5, +concat = 6, +concat_pack4 = 7, +concat_pack4to1 = 8, +concat_pack8 = 9, +concat_pack8to1 = 10, +concat_pack8to4 = 11, +convolution = 12, +convolution_1x1s1d1 = 13, +convolution_3x3s1d1_winograd23_transform_input = 14, +convolution_3x3s1d1_winograd23_transform_output = 15, +convolution_3x3s1d1_winograd43_transform_input = 16, +convolution_3x3s1d1_winograd43_transform_output = 17, +convolution_3x3s1d1_winograd_gemm = 18, +convolution_gemm = 19, +convolution_pack1to4 = 20, +convolution_pack1to4_1x1s1d1 = 21, +convolution_pack1to4_3x3s1d1_winograd_gemm = 22, +convolution_pack1to4_gemm = 23, +convolution_pack1to8 = 24, +convolution_pack1to8_1x1s1d1 = 25, +convolution_pack1to8_3x3s1d1_winograd_gemm = 26, +convolution_pack1to8_gemm = 27, +convolution_pack4 = 28, +convolution_pack4_1x1s1d1 = 29, +convolution_pack4_1x1s1d1_cm_16_8_8 = 30, +convolution_pack4_3x3s1d1_winograd23_transform_input = 31, +convolution_pack4_3x3s1d1_winograd23_transform_output = 32, +convolution_pack4_3x3s1d1_winograd43_transform_input = 33, +convolution_pack4_3x3s1d1_winograd43_transform_output = 34, +convolution_pack4_3x3s1d1_winograd_gemm = 35, +convolution_pack4_3x3s1d1_winograd_gemm_cm_16_8_8 = 36, +convolution_pack4_gemm = 37, +convolution_pack4_gemm_cm_16_8_8 = 38, +convolution_pack4to1 = 39, +convolution_pack4to1_1x1s1d1 = 40, +convolution_pack4to1_3x3s1d1_winograd_gemm = 41, +convolution_pack4to1_gemm = 42, +convolution_pack4to8 = 43, +convolution_pack4to8_1x1s1d1 = 44, +convolution_pack4to8_3x3s1d1_winograd_gemm = 45, +convolution_pack4to8_gemm = 46, +convolution_pack8 = 47, +convolution_pack8_1x1s1d1 = 48, +convolution_pack8_3x3s1d1_winograd23_transform_input = 49, +convolution_pack8_3x3s1d1_winograd23_transform_output = 50, +convolution_pack8_3x3s1d1_winograd43_transform_input = 51, +convolution_pack8_3x3s1d1_winograd43_transform_output = 52, +convolution_pack8_3x3s1d1_winograd_gemm = 53, +convolution_pack8_gemm = 54, +convolution_pack8to1 = 55, +convolution_pack8to1_1x1s1d1 = 56, +convolution_pack8to1_3x3s1d1_winograd_gemm = 57, +convolution_pack8to1_gemm = 58, +convolution_pack8to4 = 59, +convolution_pack8to4_1x1s1d1 = 60, +convolution_pack8to4_3x3s1d1_winograd_gemm = 61, +convolution_pack8to4_gemm = 62, +crop = 63, +crop_pack1to4 = 64, +crop_pack1to8 = 65, +crop_pack4 = 66, +crop_pack4to1 = 67, +crop_pack4to8 = 68, +crop_pack8 = 69, +crop_pack8to1 = 70, +crop_pack8to4 = 71, +deconvolution = 72, +deconvolution_col2im = 73, +deconvolution_gemm = 74, +deconvolution_pack1to4 = 75, +deconvolution_pack1to4_gemm = 76, +deconvolution_pack1to8 = 77, +deconvolution_pack1to8_gemm = 78, +deconvolution_pack4 = 79, +deconvolution_pack4_col2im = 80, +deconvolution_pack4_gemm = 81, +deconvolution_pack4_gemm_cm_16_8_8 = 82, +deconvolution_pack4to1 = 83, +deconvolution_pack4to1_gemm = 84, +deconvolution_pack4to8 = 85, +deconvolution_pack4to8_gemm = 86, +deconvolution_pack8 = 87, +deconvolution_pack8_col2im = 88, +deconvolution_pack8_gemm = 89, +deconvolution_pack8to1 = 90, +deconvolution_pack8to1_gemm = 91, +deconvolution_pack8to4 = 92, +deconvolution_pack8to4_gemm = 93, +dropout = 94, +dropout_pack4 = 95, +dropout_pack8 = 96, +eltwise = 97, +eltwise_pack4 = 98, +eltwise_pack8 = 99, +elu = 100, +elu_pack4 = 101, +elu_pack8 = 102, +flatten = 103, +flatten_pack1to4 = 104, +flatten_pack1to8 = 105, +flatten_pack4 = 106, +flatten_pack4to8 = 107, +flatten_pack8 = 108, +innerproduct = 109, +innerproduct_gemm = 110, +innerproduct_gemm_wp1to4 = 111, +innerproduct_gemm_wp1to8 = 112, +innerproduct_gemm_wp4 = 113, +innerproduct_gemm_wp4to1 = 114, +innerproduct_gemm_wp4to8 = 115, +innerproduct_gemm_wp8 = 116, +innerproduct_gemm_wp8to1 = 117, +innerproduct_gemm_wp8to4 = 118, +innerproduct_pack1to4 = 119, +innerproduct_pack1to8 = 120, +innerproduct_pack4 = 121, +innerproduct_pack4to1 = 122, +innerproduct_pack4to8 = 123, +innerproduct_pack8 = 124, +innerproduct_pack8to1 = 125, +innerproduct_pack8to4 = 126, +innerproduct_reduce_sum8 = 127, +innerproduct_reduce_sum8_pack4 = 128, +innerproduct_reduce_sum8_pack8 = 129, +innerproduct_sum8 = 130, +innerproduct_sum8_pack1to4 = 131, +innerproduct_sum8_pack1to8 = 132, +innerproduct_sum8_pack4 = 133, +innerproduct_sum8_pack4to1 = 134, +innerproduct_sum8_pack4to8 = 135, +innerproduct_sum8_pack8 = 136, +innerproduct_sum8_pack8to1 = 137, +innerproduct_sum8_pack8to4 = 138, +lrn_norm = 139, +lrn_norm_across_channel_pack4 = 140, +lrn_norm_across_channel_pack8 = 141, +lrn_norm_within_channel_pack4 = 142, +lrn_norm_within_channel_pack8 = 143, +lrn_square_pad = 144, +lrn_square_pad_across_channel_pack4 = 145, +lrn_square_pad_across_channel_pack8 = 146, +lrn_square_pad_within_channel_pack4 = 147, +lrn_square_pad_within_channel_pack8 = 148, +pooling = 149, +pooling_adaptive = 150, +pooling_adaptive_pack4 = 151, +pooling_adaptive_pack8 = 152, +pooling_global = 153, +pooling_global_pack4 = 154, +pooling_global_pack8 = 155, +pooling_pack4 = 156, +pooling_pack8 = 157, +prelu = 158, +prelu_pack4 = 159, +prelu_pack8 = 160, +relu = 161, +relu_pack4 = 162, +relu_pack8 = 163, +reshape = 164, +reshape_pack1to4 = 165, +reshape_pack1to8 = 166, +reshape_pack4 = 167, +reshape_pack4to1 = 168, +reshape_pack4to8 = 169, +reshape_pack8 = 170, +reshape_pack8to1 = 171, +reshape_pack8to4 = 172, +scale = 173, +scale_pack4 = 174, +scale_pack8 = 175, +sigmoid = 176, +sigmoid_pack4 = 177, +sigmoid_pack8 = 178, +slice = 179, +slice_pack1to4 = 180, +slice_pack1to8 = 181, +slice_pack4 = 182, +slice_pack4to8 = 183, +slice_pack8 = 184, +softmax_div_sum = 185, +softmax_div_sum_pack4 = 186, +softmax_div_sum_pack8 = 187, +softmax_exp_sub_max = 188, +softmax_exp_sub_max_pack4 = 189, +softmax_exp_sub_max_pack8 = 190, +softmax_reduce_max = 191, +softmax_reduce_max_pack4 = 192, +softmax_reduce_max_pack8 = 193, +softmax_reduce_sum = 194, +softmax_reduce_sum_pack4 = 195, +softmax_reduce_sum_pack8 = 196, +tanh = 197, +tanh_pack4 = 198, +tanh_pack8 = 199, +binaryop = 200, +binaryop_broadcast = 201, +binaryop_broadcast_a1_pack4 = 202, +binaryop_broadcast_a1_pack8 = 203, +binaryop_broadcast_b1_pack4 = 204, +binaryop_broadcast_b1_pack8 = 205, +binaryop_broadcast_pack4 = 206, +binaryop_broadcast_pack8 = 207, +binaryop_pack4 = 208, +binaryop_pack8 = 209, +unaryop = 210, +unaryop_pack4 = 211, +unaryop_pack8 = 212, +convolutiondepthwise = 213, +convolutiondepthwise_group = 214, +convolutiondepthwise_group_pack1to4 = 215, +convolutiondepthwise_group_pack1to8 = 216, +convolutiondepthwise_group_pack4 = 217, +convolutiondepthwise_group_pack4to1 = 218, +convolutiondepthwise_group_pack4to8 = 219, +convolutiondepthwise_group_pack8 = 220, +convolutiondepthwise_group_pack8to1 = 221, +convolutiondepthwise_group_pack8to4 = 222, +convolutiondepthwise_pack4 = 223, +convolutiondepthwise_pack8 = 224, +padding = 225, +padding_3d = 226, +padding_3d_pack4 = 227, +padding_3d_pack8 = 228, +padding_pack1to4 = 229, +padding_pack1to8 = 230, +padding_pack4 = 231, +padding_pack4to1 = 232, +padding_pack4to8 = 233, +padding_pack8 = 234, +padding_pack8to1 = 235, +padding_pack8to4 = 236, +normalize_coeffs = 237, +normalize_coeffs_pack4 = 238, +normalize_coeffs_pack8 = 239, +normalize_norm = 240, +normalize_norm_pack4 = 241, +normalize_norm_pack8 = 242, +normalize_reduce_sum4_fp16_to_fp32 = 243, +normalize_reduce_sum4_fp16_to_fp32_pack4 = 244, +normalize_reduce_sum4_fp16_to_fp32_pack8 = 245, +normalize_reduce_sum4_fp32 = 246, +normalize_reduce_sum4_fp32_pack4 = 247, +normalize_reduce_sum4_fp32_pack8 = 248, +permute = 249, +permute_pack1to4 = 250, +permute_pack1to8 = 251, +permute_pack4 = 252, +permute_pack4to1 = 253, +permute_pack4to8 = 254, +permute_pack8 = 255, +permute_pack8to1 = 256, +permute_pack8to4 = 257, +priorbox = 258, +priorbox_mxnet = 259, +interp = 260, +interp_bicubic = 261, +interp_bicubic_coeffs = 262, +interp_bicubic_pack4 = 263, +interp_bicubic_pack8 = 264, +interp_pack4 = 265, +interp_pack8 = 266, +deconvolutiondepthwise = 267, +deconvolutiondepthwise_group = 268, +deconvolutiondepthwise_group_pack1to4 = 269, +deconvolutiondepthwise_group_pack1to8 = 270, +deconvolutiondepthwise_group_pack4 = 271, +deconvolutiondepthwise_group_pack4to1 = 272, +deconvolutiondepthwise_group_pack4to8 = 273, +deconvolutiondepthwise_group_pack8 = 274, +deconvolutiondepthwise_group_pack8to1 = 275, +deconvolutiondepthwise_group_pack8to4 = 276, +deconvolutiondepthwise_pack4 = 277, +deconvolutiondepthwise_pack8 = 278, +shufflechannel = 279, +shufflechannel_pack4 = 280, +shufflechannel_pack8 = 281, +instancenorm_coeffs = 282, +instancenorm_coeffs_pack4 = 283, +instancenorm_coeffs_pack8 = 284, +instancenorm_norm = 285, +instancenorm_norm_pack4 = 286, +instancenorm_norm_pack8 = 287, +instancenorm_reduce_mean = 288, +instancenorm_reduce_mean_pack4 = 289, +instancenorm_reduce_mean_pack8 = 290, +instancenorm_reduce_sum4_fp16_to_fp32 = 291, +instancenorm_reduce_sum4_fp16_to_fp32_pack4 = 292, +instancenorm_reduce_sum4_fp16_to_fp32_pack8 = 293, +instancenorm_reduce_sum4_fp32 = 294, +instancenorm_reduce_sum4_fp32_pack4 = 295, +instancenorm_reduce_sum4_fp32_pack8 = 296, +instancenorm_sub_mean_square = 297, +instancenorm_sub_mean_square_pack4 = 298, +instancenorm_sub_mean_square_pack8 = 299, +clip = 300, +clip_pack4 = 301, +clip_pack8 = 302, +reorg = 303, +reorg_pack1to4 = 304, +reorg_pack1to8 = 305, +reorg_pack4 = 306, +reorg_pack4to8 = 307, +reorg_pack8 = 308, +packing = 309, +packing_fp16_to_fp32 = 310, +packing_fp32_to_fp16 = 311, +packing_pack1to4 = 312, +packing_pack1to4_fp16_to_fp32 = 313, +packing_pack1to4_fp32_to_fp16 = 314, +packing_pack1to8 = 315, +packing_pack1to8_fp16_to_fp32 = 316, +packing_pack1to8_fp32_to_fp16 = 317, +packing_pack4 = 318, +packing_pack4_fp16_to_fp32 = 319, +packing_pack4_fp32_to_fp16 = 320, +packing_pack4to1 = 321, +packing_pack4to1_fp16_to_fp32 = 322, +packing_pack4to1_fp32_to_fp16 = 323, +packing_pack4to8 = 324, +packing_pack4to8_fp16_to_fp32 = 325, +packing_pack4to8_fp32_to_fp16 = 326, +packing_pack8 = 327, +packing_pack8_fp16_to_fp32 = 328, +packing_pack8_fp32_to_fp16 = 329, +packing_pack8to1 = 330, +packing_pack8to1_fp16_to_fp32 = 331, +packing_pack8to1_fp32_to_fp16 = 332, +packing_pack8to4 = 333, +packing_pack8to4_fp16_to_fp32 = 334, +packing_pack8to4_fp32_to_fp16 = 335, +cast_fp16_to_fp32 = 336, +cast_fp16_to_fp32_pack4 = 337, +cast_fp16_to_fp32_pack8 = 338, +cast_fp32_to_fp16 = 339, +cast_fp32_to_fp16_pack4 = 340, +cast_fp32_to_fp16_pack8 = 341, +hardsigmoid = 342, +hardsigmoid_pack4 = 343, +hardsigmoid_pack8 = 344, +hardswish = 345, +hardswish_pack4 = 346, +hardswish_pack8 = 347, +pixelshuffle = 348, +pixelshuffle_pack4 = 349, +pixelshuffle_pack4to1 = 350, +pixelshuffle_pack8 = 351, +pixelshuffle_pack8to1 = 352, +pixelshuffle_pack8to4 = 353, +deepcopy = 354, +deepcopy_pack4 = 355, +deepcopy_pack8 = 356, +mish = 357, +mish_pack4 = 358, +mish_pack8 = 359, +swish = 360, +swish_pack4 = 361, +swish_pack8 = 362, +convert_ycbcr = 363, +vulkan_activation = 364, + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/layer_type.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/layer_type.h new file mode 100644 index 0000000..511c714 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/layer_type.h @@ -0,0 +1,30 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_TYPE_H +#define NCNN_LAYER_TYPE_H + +namespace ncnn { + +namespace LayerType { +enum LayerType +{ +#include "layer_type_enum.h" + CustomBit = (1 << 8), +}; +} // namespace LayerType + +} // namespace ncnn + +#endif // NCNN_LAYER_TYPE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/layer_type_enum.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/layer_type_enum.h new file mode 100644 index 0000000..581d589 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/layer_type_enum.h @@ -0,0 +1,103 @@ +// Layer Type Enum header +// +// This file is auto-generated by cmake, don't edit it. + +AbsVal = 0, +ArgMax = 1, +BatchNorm = 2, +Bias = 3, +BNLL = 4, +Concat = 5, +Convolution = 6, +Crop = 7, +Deconvolution = 8, +Dropout = 9, +Eltwise = 10, +ELU = 11, +Embed = 12, +Exp = 13, +Flatten = 14, +InnerProduct = 15, +Input = 16, +Log = 17, +LRN = 18, +MemoryData = 19, +MVN = 20, +Pooling = 21, +Power = 22, +PReLU = 23, +Proposal = 24, +Reduction = 25, +ReLU = 26, +Reshape = 27, +ROIPooling = 28, +Scale = 29, +Sigmoid = 30, +Slice = 31, +Softmax = 32, +Split = 33, +SPP = 34, +TanH = 35, +Threshold = 36, +Tile = 37, +RNN = 38, +LSTM = 39, +BinaryOp = 40, +UnaryOp = 41, +ConvolutionDepthWise = 42, +Padding = 43, +Squeeze = 44, +ExpandDims = 45, +Normalize = 46, +Permute = 47, +PriorBox = 48, +DetectionOutput = 49, +Interp = 50, +DeconvolutionDepthWise = 51, +ShuffleChannel = 52, +InstanceNorm = 53, +Clip = 54, +Reorg = 55, +YoloDetectionOutput = 56, +Quantize = 57, +Dequantize = 58, +Yolov3DetectionOutput = 59, +PSROIPooling = 60, +ROIAlign = 61, +Packing = 62, +Requantize = 63, +Cast = 64, +HardSigmoid = 65, +SELU = 66, +HardSwish = 67, +Noop = 68, +PixelShuffle = 69, +DeepCopy = 70, +Mish = 71, +StatisticsPooling = 72, +Swish = 73, +Gemm = 74, +GroupNorm = 75, +LayerNorm = 76, +Softplus = 77, +GRU = 78, +MultiHeadAttention = 79, +GELU = 80, +Convolution1D = 81, +Pooling1D = 82, +ConvolutionDepthWise1D = 83, +Convolution3D = 84, +ConvolutionDepthWise3D = 85, +Pooling3D = 86, +MatMul = 87, +Deconvolution1D = 88, +DeconvolutionDepthWise1D = 89, +Deconvolution3D = 90, +DeconvolutionDepthWise3D = 91, +Einsum = 92, +DeformableConv2D = 93, +GLU = 94, +Fold = 95, +Unfold = 96, +GridSample = 97, + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/mat.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/mat.h new file mode 100644 index 0000000..c6f59ef --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/mat.h @@ -0,0 +1,1843 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_MAT_H +#define NCNN_MAT_H + +#include +#include +#if __ARM_NEON +#include +#endif +#if __SSE2__ +#include +#if __AVX__ +#include +#endif +#endif +#if __mips_msa +#include +#endif +#if __loongarch_sx +#include +#endif +#if __riscv_vector +#include +#include "cpu.h" // cpu_riscv_vlenb() +#endif + +#include "allocator.h" +#include "option.h" +#include "platform.h" + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#if NCNN_PIXEL +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#include +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API +#endif // NCNN_PIXEL + +namespace ncnn { + +#if NCNN_VULKAN +class VkMat; +class VkImageMat; +#endif // NCNN_VULKAN + +// the three dimension matrix +class NCNN_EXPORT Mat +{ +public: + // empty + Mat(); + // vec + Mat(int w, size_t elemsize = 4u, Allocator* allocator = 0); + // image + Mat(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0); + // dim + Mat(int w, int h, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // cube + Mat(int w, int h, int d, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // packed vec + Mat(int w, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed image + Mat(int w, int h, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed dim + Mat(int w, int h, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed cube + Mat(int w, int h, int d, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // copy + Mat(const Mat& m); + // external vec + Mat(int w, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external image + Mat(int w, int h, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external dim + Mat(int w, int h, int c, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external cube + Mat(int w, int h, int d, int c, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external packed vec + Mat(int w, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed image + Mat(int w, int h, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed dim + Mat(int w, int h, int c, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed cube + Mat(int w, int h, int d, int c, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // release + ~Mat(); + // assign + Mat& operator=(const Mat& m); + // set all + void fill(float v); + void fill(int v); +#if __ARM_NEON + void fill(float32x4_t _v); + void fill(uint16x4_t _v); + void fill(int32x4_t _v); + void fill(int32x4_t _v0, int32x4_t _v1); +#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC + void fill(float16x4_t _v); + void fill(float16x8_t _v); +#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +#endif // __ARM_NEON +#if __SSE2__ +#if __AVX__ +#if __AVX512F__ + void fill(__m512 _v); +#endif // __AVX512F__ + void fill(__m256 _v, int i = 0); +#endif // __AVX__ + void fill(__m128 _v); + void fill(__m128i _v); +#endif // __SSE2__ +#if __mips_msa + void fill(v4f32 _v); +#endif // __mips_msa +#if __loongarch_sx + void fill(__m128 _v); +#endif //__loongarch_sx +#if __riscv_vector + void fill(vfloat32m1_t _v); + void fill(vuint16m1_t _v); + void fill(vint8m1_t _v); +#if __riscv_zfh + void fill(vfloat16m1_t _v); +#endif // __riscv_zfh +#endif // __riscv_vector + template + void fill(T v); + // deep copy + Mat clone(Allocator* allocator = 0) const; + // deep copy from other mat, inplace + void clone_from(const ncnn::Mat& mat, Allocator* allocator = 0); + // reshape vec + Mat reshape(int w, Allocator* allocator = 0) const; + // reshape image + Mat reshape(int w, int h, Allocator* allocator = 0) const; + // reshape dim + Mat reshape(int w, int h, int c, Allocator* allocator = 0) const; + // reshape cube + Mat reshape(int w, int h, int d, int c, Allocator* allocator = 0) const; + // allocate vec + void create(int w, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate image + void create(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate dim + void create(int w, int h, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate like + void create_like(const Mat& m, Allocator* allocator = 0); +#if NCNN_VULKAN + // allocate like + void create_like(const VkMat& m, Allocator* allocator = 0); + // allocate like + void create_like(const VkImageMat& im, Allocator* allocator = 0); +#endif // NCNN_VULKAN + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // data reference + Mat channel(int c); + const Mat channel(int c) const; + Mat depth(int z); + const Mat depth(int z) const; + float* row(int y); + const float* row(int y) const; + template + T* row(int y); + template + const T* row(int y) const; + + // range reference + Mat channel_range(int c, int channels); + const Mat channel_range(int c, int channels) const; + Mat depth_range(int z, int depths); + const Mat depth_range(int z, int depths) const; + Mat row_range(int y, int rows); + const Mat row_range(int y, int rows) const; + Mat range(int x, int n); + const Mat range(int x, int n) const; + + // access raw data + template + operator T*(); + template + operator const T*() const; + + // convenient access float vec element + float& operator[](size_t i); + const float& operator[](size_t i) const; + +#if NCNN_PIXEL + enum PixelType + { + PIXEL_CONVERT_SHIFT = 16, + PIXEL_FORMAT_MASK = 0x0000ffff, + PIXEL_CONVERT_MASK = 0xffff0000, + + PIXEL_RGB = 1, + PIXEL_BGR = 2, + PIXEL_GRAY = 3, + PIXEL_RGBA = 4, + PIXEL_BGRA = 5, + + PIXEL_RGB2BGR = PIXEL_RGB | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2GRAY = PIXEL_RGB | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2RGBA = PIXEL_RGB | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2BGRA = PIXEL_RGB | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_BGR2RGB = PIXEL_BGR | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2GRAY = PIXEL_BGR | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2RGBA = PIXEL_BGR | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2BGRA = PIXEL_BGR | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_GRAY2RGB = PIXEL_GRAY | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2BGR = PIXEL_GRAY | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2RGBA = PIXEL_GRAY | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2BGRA = PIXEL_GRAY | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_RGBA2RGB = PIXEL_RGBA | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2BGR = PIXEL_RGBA | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2GRAY = PIXEL_RGBA | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2BGRA = PIXEL_RGBA | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_BGRA2RGB = PIXEL_BGRA | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2BGR = PIXEL_BGRA | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2GRAY = PIXEL_BGRA | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2RGBA = PIXEL_BGRA | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + }; + // convenient construct from pixel data + static Mat from_pixels(const unsigned char* pixels, int type, int w, int h, Allocator* allocator = 0); + // convenient construct from pixel data with stride(bytes-per-row) parameter + static Mat from_pixels(const unsigned char* pixels, int type, int w, int h, int stride, Allocator* allocator = 0); + // convenient construct from pixel data and resize to specific size + static Mat from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data and resize to specific size with stride(bytes-per-row) parameter + static Mat from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data roi + static Mat from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from pixel data roi with stride(bytes-per-row) parameter + static Mat from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from pixel data roi and resize to specific size + static Mat from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data roi and resize to specific size with stride(bytes-per-row) parameter + static Mat from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + + // convenient export to pixel data + void to_pixels(unsigned char* pixels, int type) const; + // convenient export to pixel data with stride(bytes-per-row) parameter + void to_pixels(unsigned char* pixels, int type, int stride) const; + // convenient export to pixel data and resize to specific size + void to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height) const; + // convenient export to pixel data and resize to specific size with stride(bytes-per-row) parameter + void to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height, int target_stride) const; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 + // convenient construct from android Bitmap + static Mat from_android_bitmap(JNIEnv* env, jobject bitmap, int type_to, Allocator* allocator = 0); + // convenient construct from android Bitmap and resize to specific size + static Mat from_android_bitmap_resize(JNIEnv* env, jobject bitmap, int type_to, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from android Bitmap roi + static Mat from_android_bitmap_roi(JNIEnv* env, jobject bitmap, int type_to, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from android Bitmap roi and resize to specific size + static Mat from_android_bitmap_roi_resize(JNIEnv* env, jobject bitmap, int type_to, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + // convenient export to android Bitmap and resize to the android Bitmap size + void to_android_bitmap(JNIEnv* env, jobject bitmap, int type_from) const; +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API +#endif // NCNN_PIXEL + + // substract channel-wise mean values, then multiply by normalize values, pass 0 to skip + void substract_mean_normalize(const float* mean_vals, const float* norm_vals); + + // convenient construct from half precision floating point data + static Mat from_float16(const unsigned short* data, int size); + + // pointer to the data + void* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + Allocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; + + size_t cstep; +}; + +#if NCNN_VULKAN + +// the three dimension matrix, vulkan version +class NCNN_EXPORT VkMat +{ +public: + // empty + VkMat(); + // vec + VkMat(int w, size_t elemsize, VkAllocator* allocator); + // image + VkMat(int w, int h, size_t elemsize, VkAllocator* allocator); + // dim + VkMat(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // cube + VkMat(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // packed vec + VkMat(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // packed image + VkMat(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // packed dim + VkMat(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // packed cube + VkMat(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // copy + VkMat(const VkMat& m); + // external vec + VkMat(int w, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external image + VkMat(int w, int h, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external dim + VkMat(int w, int h, int c, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external cube + VkMat(int w, int h, int d, int c, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external packed vec + VkMat(int w, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed image + VkMat(int w, int h, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed dim + VkMat(int w, int h, int c, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed cube + VkMat(int w, int h, int d, int c, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // release + ~VkMat(); + // assign + VkMat& operator=(const VkMat& m); + // allocate vec + void create(int w, size_t elemsize, VkAllocator* allocator); + // allocate image + void create(int w, int h, size_t elemsize, VkAllocator* allocator); + // allocate dim + void create(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate like + void create_like(const Mat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkMat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkImageMat& im, VkAllocator* allocator); + + // mapped + Mat mapped() const; + void* mapped_ptr() const; + + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // low-level reference + VkBuffer buffer() const; + size_t buffer_offset() const; + size_t buffer_capacity() const; + + // device buffer + VkBufferMemory* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + VkAllocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; + + size_t cstep; +}; + +class NCNN_EXPORT VkImageMat +{ +public: + // empty + VkImageMat(); + // vec + VkImageMat(int w, size_t elemsize, VkAllocator* allocator); + // image + VkImageMat(int w, int h, size_t elemsize, VkAllocator* allocator); + // dim + VkImageMat(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // cube + VkImageMat(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // packed vec + VkImageMat(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // packed image + VkImageMat(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // packed dim + VkImageMat(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // packed cube + VkImageMat(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // copy + VkImageMat(const VkImageMat& m); + // external vec + VkImageMat(int w, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external image + VkImageMat(int w, int h, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external dim + VkImageMat(int w, int h, int c, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external cube + VkImageMat(int w, int h, int d, int c, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external packed vec + VkImageMat(int w, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed image + VkImageMat(int w, int h, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed dim + VkImageMat(int w, int h, int c, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed cube + VkImageMat(int w, int h, int d, int c, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // release + ~VkImageMat(); + // assign + VkImageMat& operator=(const VkImageMat& m); + // allocate vec + void create(int w, size_t elemsize, VkAllocator* allocator); + // allocate image + void create(int w, int h, size_t elemsize, VkAllocator* allocator); + // allocate dim + void create(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate like + void create_like(const Mat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkMat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkImageMat& im, VkAllocator* allocator); + + // mapped + Mat mapped() const; + void* mapped_ptr() const; + + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // low-level reference + VkImage image() const; + VkImageView imageview() const; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 + // convenient construct from android hardware buffer + static VkImageMat from_android_hardware_buffer(VkAndroidHardwareBufferImageAllocator* allocator); +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + + // device image + VkImageMemory* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + VkAllocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; +}; + +// type for vulkan specialization constant and push constant +union vk_specialization_type +{ + int i; + float f; + uint32_t u32; +}; +union vk_constant_type +{ + int i; + float f; +}; +#endif // NCNN_VULKAN + +// misc function +#if NCNN_PIXEL +// convert yuv420sp(nv21) to rgb, the fast approximate version +NCNN_EXPORT void yuv420sp2rgb(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// convert yuv420sp(nv12) to rgb, the fast approximate version +NCNN_EXPORT void yuv420sp2rgb_nv12(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// convert yuv420sp(nv21) to rgb with half resize, the faster approximate version +NCNN_EXPORT void yuv420sp2rgb_half(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// image pixel bilinear resize +NCNN_EXPORT void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +// image pixel bilinear resize with stride(bytes-per-row) parameter +NCNN_EXPORT void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +// image pixel bilinear resize, convenient wrapper for yuv420sp(nv21/nv12) +NCNN_EXPORT void resize_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +#endif // NCNN_PIXEL +#if NCNN_PIXEL_ROTATE +// type is the from type, 6 means rotating from 6 to 1 +// +// 1 2 3 4 5 6 7 8 +// +// 888888 888888 88 88 8888888888 88 88 8888888888 +// 88 88 88 88 88 88 88 88 88 88 88 88 +// 8888 8888 8888 8888 88 8888888888 8888888888 88 +// 88 88 88 88 +// 88 88 888888 888888 +// +// ref http://sylvana.net/jpegcrop/exif_orientation.html +// image pixel kanna rotate +NCNN_EXPORT void kanna_rotate_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +// image pixel kanna rotate with stride(bytes-per-row) parameter +NCNN_EXPORT void kanna_rotate_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +// image pixel kanna rotate, convenient wrapper for yuv420sp(nv21/nv12) +NCNN_EXPORT void kanna_rotate_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +#endif // NCNN_PIXEL_ROTATE +#if NCNN_PIXEL_AFFINE +// resolve affine transform matrix from rotation angle, scale factor and x y offset +NCNN_EXPORT void get_rotation_matrix(float angle, float scale, float dx, float dy, float* tm); +// resolve affine transform matrix from two set of points, num_point must be >= 2 +NCNN_EXPORT void get_affine_transform(const float* points_from, const float* points_to, int num_point, float* tm); +// resolve the inversion affine transform matrix +NCNN_EXPORT void invert_affine_transform(const float* tm, float* tm_inv); +// image pixel bilinear warpaffine inverse transform, set -233 for transparent border color, the color RGBA is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +// image pixel bilinear warpaffine inverse transform with stride(bytes-per-row) parameter, set -233 for transparent border color, the color RGBA is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +// image pixel bilinear warpaffine, convenient wrapper for yuv420sp(nv21/nv12), set -233 for transparent border color, the color YUV_ is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +#endif // NCNN_PIXEL_AFFINE +#if NCNN_PIXEL_DRAWING +// draw rectangle, set thickness -1 for filled rectangle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_rectangle_c1(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c2(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c3(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c4(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw rectangle with stride(bytes-per-row) parameter, set thickness -1 for filled rectangle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_rectangle_c1(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c2(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c3(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c4(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw rectangle, convenient wrapper for yuv420sp(nv21/nv12), set thickness -1 for filled rectangle, the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_rectangle_yuv420sp(unsigned char* yuv420sp, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw circle, set thickness -1 for filled circle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_circle_c1(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c2(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c3(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c4(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +// draw circle with stride(bytes-per-row) parameter, set thickness -1 for filled circle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_circle_c1(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c2(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c3(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c4(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +// draw circle, convenient wrapper for yuv420sp(nv21/nv12), set thickness -1 for filled circle, the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_circle_yuv420sp(unsigned char* yuv420sp, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +// draw line, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_line_c1(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c2(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c3(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c4(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// draw line with stride(bytes-per-row) parameter, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_line_c1(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c2(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c3(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c4(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// draw line, convenient wrapper for yuv420sp(nv21/nv12), the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_line_yuv420sp(unsigned char* yuv420sp, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// resolve text bounding box size +NCNN_EXPORT void get_text_drawing_size(const char* text, int fontpixelsize, int* w, int* h); +// draw ascii printables and newline, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_text_c1(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c2(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c3(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c4(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +// draw ascii printables and newline with stride(bytes-per-row) parameter, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_text_c1(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c2(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c3(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c4(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +// draw ascii printables and newline, convenient wrapper for yuv420sp(nv21/nv12), the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_text_yuv420sp(unsigned char* yuv420sp, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +#endif // NCNN_PIXEL_DRAWING + +// type conversion +// convert float to half precision floating point +NCNN_EXPORT unsigned short float32_to_float16(float value); +// convert half precision floating point to float +NCNN_EXPORT float float16_to_float32(unsigned short value); +// convert float to brain half +NCNN_EXPORT NCNN_FORCEINLINE unsigned short float32_to_bfloat16(float value) +{ + // 16 : 16 + union + { + unsigned int u; + float f; + } tmp; + tmp.f = value; + return tmp.u >> 16; +} +// convert brain half to float +NCNN_EXPORT NCNN_FORCEINLINE float bfloat16_to_float32(unsigned short value) +{ + // 16 : 16 + union + { + unsigned int u; + float f; + } tmp; + tmp.u = value << 16; + return tmp.f; +} + +// mat process +enum BorderType +{ + BORDER_CONSTANT = 0, + BORDER_REPLICATE = 1, + BORDER_REFLECT = 2, + BORDER_TRANSPARENT = -233, +}; +NCNN_EXPORT void copy_make_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int type, float v, const Option& opt = Option()); +NCNN_EXPORT void copy_make_border_3d(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int front, int behind, int type, float v, const Option& opt = Option()); +NCNN_EXPORT void copy_cut_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, const Option& opt = Option()); +NCNN_EXPORT void copy_cut_border_3d(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int front, int behind, const Option& opt = Option()); +NCNN_EXPORT void resize_nearest(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void resize_bilinear(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void resize_bicubic(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void convert_packing(const Mat& src, Mat& dst, int elempack, const Option& opt = Option()); +NCNN_EXPORT void flatten(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float32_to_float16(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float16_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_int8_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float32_to_bfloat16(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_bfloat16_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void quantize_to_int8(const Mat& src, Mat& dst, const Mat& scale_data, const Option& opt = Option()); +NCNN_EXPORT void dequantize_from_int32(const Mat& src, Mat& dst, const Mat& scale_data, const Mat& bias_data, const Option& opt = Option()); +NCNN_EXPORT void requantize_from_int32_to_int8(const Mat& src, Mat& dst, const Mat& scale_in_data, const Mat& scale_out_data, const Mat& bias_data, int activation_type, const Mat& activation_params, const Option& opt = Option()); + +NCNN_FORCEINLINE Mat::Mat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ +} + +NCNN_FORCEINLINE Mat::Mat(int _w, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(const Mat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c), cstep(m.cstep) +{ + addref(); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = (size_t)w * h; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = (size_t)w * h; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::~Mat() +{ + release(); +} + +NCNN_FORCEINLINE void Mat::fill(float _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + + int i = 0; +#if __ARM_NEON + float32x4_t _c = vdupq_n_f32(_v); + for (; i + 3 < size; i += 4) + { + vst1q_f32(ptr, _c); + ptr += 4; + } +#endif // __ARM_NEON + for (; i < size; i++) + { + *ptr++ = _v; + } +} + +NCNN_FORCEINLINE void Mat::fill(int _v) +{ + int size = (int)total(); + int* ptr = (int*)data; + + int i = 0; +#if __ARM_NEON + int32x4_t _c = vdupq_n_s32(_v); + for (; i + 3 < size; i += 4) + { + vst1q_s32(ptr, _c); + ptr += 4; + } +#endif // __ARM_NEON + for (; i < size; i++) + { + *ptr++ = _v; + } +} + +#if __ARM_NEON +NCNN_FORCEINLINE void Mat::fill(float32x4_t _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + vst1q_f32(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(uint16x4_t _v) +{ + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + vst1_u16(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(int32x4_t _v) +{ + int size = (int)total(); + int* ptr = (int*)data; + for (int i = 0; i < size; i++) + { + vst1q_s32(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(int32x4_t _v0, int32x4_t _v1) +{ + int size = (int)total(); + int* ptr = (int*)data; + for (int i = 0; i < size; i++) + { + vst1q_s32(ptr, _v0); + vst1q_s32(ptr + 4, _v1); + ptr += 8; + } +} +#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +NCNN_FORCEINLINE void Mat::fill(float16x4_t _v) +{ + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vst1_f16(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(float16x8_t _v) +{ + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vst1q_f16(ptr, _v); + ptr += 8; + } +} +#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +#endif // __ARM_NEON + +#if __SSE2__ +#if __AVX__ +#if __AVX512F__ +NCNN_FORCEINLINE void Mat::fill(__m512 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm512_storeu_ps(ptr, _v); + ptr += 16; + } +} +#endif // __AVX512F__ +NCNN_FORCEINLINE void Mat::fill(__m256 _v, int _i) +{ + // old gcc cannot overload __m128 and __m256 type + // add a dummy int parameter for different mangled function symbol + (void)_i; + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm256_storeu_ps(ptr, _v); + ptr += 8; + } +} +#endif // __AVX__ +NCNN_FORCEINLINE void Mat::fill(__m128 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm_storeu_ps(ptr, _v); + ptr += 4; + } +} +NCNN_FORCEINLINE void Mat::fill(__m128i _v) +{ + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + _mm_store_si128((__m128i*)ptr, _v); + ptr += 8; + } +} +#endif // __SSE2__ + +#if __mips_msa +NCNN_FORCEINLINE void Mat::fill(v4f32 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + __msa_st_w((v4i32)_v, ptr, 0); + ptr += 4; + } +} +#endif // __mips_msa + +#if __loongarch_sx +NCNN_FORCEINLINE void Mat::fill(__m128 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + __lsx_vst(_v, ptr, 0); + ptr += 4; + } +} +#endif // __loongarch_sx +#if __riscv_vector +NCNN_FORCEINLINE void Mat::fill(vfloat32m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 4; + const size_t vl = vsetvl_e32m1(packn); + + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + vse32_v_f32m1(ptr, _v, vl); + ptr += packn; + } +} + +NCNN_FORCEINLINE void Mat::fill(vuint16m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 2; + const size_t vl = vsetvl_e16m1(packn); + + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + vse16_v_u16m1(ptr, _v, vl); + ptr += packn; + } +} + +NCNN_FORCEINLINE void Mat::fill(vint8m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 1; + const size_t vl = vsetvl_e8m1(packn); + + int size = (int)total(); + signed char* ptr = (signed char*)data; + for (int i = 0; i < size; i++) + { + vse8_v_i8m1(ptr, _v, vl); + ptr += packn; + } +} +#if __riscv_zfh +NCNN_FORCEINLINE void Mat::fill(vfloat16m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 2; + const size_t vl = vsetvl_e16m1(packn); + + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vse16_v_f16m1(ptr, _v, vl); + ptr += packn; + } +} +#endif // __riscv_zfh +#endif // __riscv_vector + +template +NCNN_FORCEINLINE void Mat::fill(T _v) +{ + int size = (int)total(); + T* ptr = (T*)data; + for (int i = 0; i < size; i++) + { + ptr[i] = _v; + } +} + +NCNN_FORCEINLINE Mat& Mat::operator=(const Mat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + cstep = m.cstep; + + return *this; +} + +NCNN_FORCEINLINE void Mat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void Mat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator) + allocator->fastFree(data); + else + fastFree(data); + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + cstep = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool Mat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t Mat::total() const +{ + return cstep * c; +} + +NCNN_FORCEINLINE int Mat::elembits() const +{ + return elempack ? static_cast(elemsize * 8) / elempack : 0; +} + +NCNN_FORCEINLINE Mat Mat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE Mat Mat::channel(int _c) +{ + Mat m(w, h, d, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims - 1; + if (dims == 4) + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::channel(int _c) const +{ + Mat m(w, h, d, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims - 1; + if (dims == 4) + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE Mat Mat::depth(int z) +{ + return Mat(w, h, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::depth(int z) const +{ + return Mat(w, h, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE float* Mat::row(int y) +{ + return (float*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +NCNN_FORCEINLINE const float* Mat::row(int y) const +{ + return (const float*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +template +NCNN_FORCEINLINE T* Mat::row(int y) +{ + return (T*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +template +NCNN_FORCEINLINE const T* Mat::row(int y) const +{ + return (const T*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +NCNN_FORCEINLINE Mat Mat::channel_range(int _c, int channels) +{ + Mat m(w, h, d, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::channel_range(int _c, int channels) const +{ + Mat m(w, h, d, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims; + return m; +} + +NCNN_FORCEINLINE Mat Mat::depth_range(int z, int depths) +{ + Mat m(w, h, depths, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::depth_range(int z, int depths) const +{ + Mat m(w, h, depths, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE Mat Mat::row_range(int y, int rows) +{ + return Mat(w, rows, (unsigned char*)data + (size_t)w * y * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::row_range(int y, int rows) const +{ + return Mat(w, rows, (unsigned char*)data + (size_t)w * y * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE Mat Mat::range(int x, int n) +{ + return Mat(n, (unsigned char*)data + x * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::range(int x, int n) const +{ + return Mat(n, (unsigned char*)data + x * elemsize, elemsize, elempack, allocator); +} + +template +NCNN_FORCEINLINE Mat::operator T*() +{ + return (T*)data; +} + +template +NCNN_FORCEINLINE Mat::operator const T*() const +{ + return (const T*)data; +} + +NCNN_FORCEINLINE float& Mat::operator[](size_t i) +{ + return ((float*)data)[i]; +} + +NCNN_FORCEINLINE const float& Mat::operator[](size_t i) const +{ + return ((const float*)data)[i]; +} + +#if NCNN_VULKAN + +NCNN_FORCEINLINE VkMat::VkMat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(const VkMat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c) +{ + addref(); + + cstep = m.cstep; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = w * h; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize(w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = w * h; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize(w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::~VkMat() +{ + release(); +} + +NCNN_FORCEINLINE VkMat& VkMat::operator=(const VkMat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + cstep = m.cstep; + + return *this; +} + +NCNN_FORCEINLINE Mat VkMat::mapped() const +{ + if (!allocator->mappable) + return Mat(); + + if (dims == 1) + return Mat(w, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 2) + return Mat(w, h, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 3) + return Mat(w, h, c, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 4) + return Mat(w, h, d, c, mapped_ptr(), elemsize, elempack, 0); + + return Mat(); +} + +NCNN_FORCEINLINE void* VkMat::mapped_ptr() const +{ + if (!allocator->mappable) + return 0; + + return (unsigned char*)data->mapped_ptr + data->offset; +} + +NCNN_FORCEINLINE void VkMat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void VkMat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator && data) + { + allocator->fastFree(data); + } + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + cstep = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool VkMat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t VkMat::total() const +{ + return cstep * c; +} + +NCNN_FORCEINLINE int VkMat::elembits() const +{ + return elempack ? static_cast(elemsize) * 8 / elempack : 0; +} + +NCNN_FORCEINLINE Mat VkMat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE VkBuffer VkMat::buffer() const +{ + return data->buffer; +} + +NCNN_FORCEINLINE size_t VkMat::buffer_offset() const +{ + return data->offset; +} + +NCNN_FORCEINLINE size_t VkMat::buffer_capacity() const +{ + return data->capacity; +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(const VkImageMat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c) +{ + addref(); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::~VkImageMat() +{ + release(); +} + +NCNN_FORCEINLINE VkImageMat& VkImageMat::operator=(const VkImageMat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + return *this; +} + +NCNN_FORCEINLINE Mat VkImageMat::mapped() const +{ + if (!allocator->mappable || !data->mapped_ptr) + return Mat(); + + if (dims == 1) + return Mat(w, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 2) + return Mat(w, h, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 3) + return Mat(w, h, c, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 4) + return Mat(w, h, d, c, mapped_ptr(), elemsize, elempack, 0); + + return Mat(); +} + +NCNN_FORCEINLINE void* VkImageMat::mapped_ptr() const +{ + if (!allocator->mappable || !data->mapped_ptr) + return 0; + + return (unsigned char*)data->mapped_ptr + data->bind_offset; +} + +NCNN_FORCEINLINE void VkImageMat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void VkImageMat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator && data) + { + allocator->fastFree(data); + } + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool VkImageMat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t VkImageMat::total() const +{ + return w * h * d * c; +} + +NCNN_FORCEINLINE int VkImageMat::elembits() const +{ + return elempack ? static_cast(elemsize) * 8 / elempack : 0; +} + +NCNN_FORCEINLINE Mat VkImageMat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE VkImage VkImageMat::image() const +{ + return data->image; +} + +NCNN_FORCEINLINE VkImageView VkImageMat::imageview() const +{ + return data->imageview; +} + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_MAT_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/modelbin.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/modelbin.h new file mode 100644 index 0000000..15d2b9c --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/modelbin.h @@ -0,0 +1,80 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_MODELBIN_H +#define NCNN_MODELBIN_H + +#include "mat.h" + +namespace ncnn { + +class DataReader; +class NCNN_EXPORT ModelBin +{ +public: + ModelBin(); + virtual ~ModelBin(); + // element type + // 0 = auto + // 1 = float32 + // 2 = float16 + // 3 = int8 + // load vec + virtual Mat load(int w, int type) const = 0; + // load image + virtual Mat load(int w, int h, int type) const; + // load dim + virtual Mat load(int w, int h, int c, int type) const; + // load cube + virtual Mat load(int w, int h, int d, int c, int type) const; +}; + +class ModelBinFromDataReaderPrivate; +class NCNN_EXPORT ModelBinFromDataReader : public ModelBin +{ +public: + explicit ModelBinFromDataReader(const DataReader& dr); + virtual ~ModelBinFromDataReader(); + + virtual Mat load(int w, int type) const; + +private: + ModelBinFromDataReader(const ModelBinFromDataReader&); + ModelBinFromDataReader& operator=(const ModelBinFromDataReader&); + +private: + ModelBinFromDataReaderPrivate* const d; +}; + +class ModelBinFromMatArrayPrivate; +class NCNN_EXPORT ModelBinFromMatArray : public ModelBin +{ +public: + // construct from weight blob array + explicit ModelBinFromMatArray(const Mat* weights); + virtual ~ModelBinFromMatArray(); + + virtual Mat load(int w, int type) const; + +private: + ModelBinFromMatArray(const ModelBinFromMatArray&); + ModelBinFromMatArray& operator=(const ModelBinFromMatArray&); + +private: + ModelBinFromMatArrayPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_MODELBIN_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/ncnn_export.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/ncnn_export.h new file mode 100644 index 0000000..e2f5fde --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/ncnn_export.h @@ -0,0 +1,42 @@ + +#ifndef NCNN_EXPORT_H +#define NCNN_EXPORT_H + +#ifdef NCNN_STATIC_DEFINE +# define NCNN_EXPORT +# define NCNN_NO_EXPORT +#else +# ifndef NCNN_EXPORT +# ifdef ncnn_EXPORTS + /* We are building this library */ +# define NCNN_EXPORT __attribute__((visibility("default"))) +# else + /* We are using this library */ +# define NCNN_EXPORT __attribute__((visibility("default"))) +# endif +# endif + +# ifndef NCNN_NO_EXPORT +# define NCNN_NO_EXPORT __attribute__((visibility("hidden"))) +# endif +#endif + +#ifndef NCNN_DEPRECATED +# define NCNN_DEPRECATED __attribute__ ((__deprecated__)) +#endif + +#ifndef NCNN_DEPRECATED_EXPORT +# define NCNN_DEPRECATED_EXPORT NCNN_EXPORT NCNN_DEPRECATED +#endif + +#ifndef NCNN_DEPRECATED_NO_EXPORT +# define NCNN_DEPRECATED_NO_EXPORT NCNN_NO_EXPORT NCNN_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef NCNN_NO_DEPRECATED +# define NCNN_NO_DEPRECATED +# endif +#endif + +#endif /* NCNN_EXPORT_H */ diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/net.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/net.h new file mode 100644 index 0000000..9407042 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/net.h @@ -0,0 +1,272 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_NET_H +#define NCNN_NET_H + +#include "blob.h" +#include "layer.h" +#include "mat.h" +#include "option.h" +#include "platform.h" + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +#if NCNN_VULKAN +class VkCompute; +#endif // NCNN_VULKAN +class DataReader; +class Extractor; +class NetPrivate; +class NCNN_EXPORT Net +{ +public: + // empty init + Net(); + // clear and destroy + virtual ~Net(); + +public: + // option can be changed before loading + Option opt; + +#if NCNN_VULKAN + // set gpu device by index + void set_vulkan_device(int device_index); + + // set gpu device by device handle, no owner transfer + void set_vulkan_device(const VulkanDevice* vkdev); + + const VulkanDevice* vulkan_device() const; +#endif // NCNN_VULKAN + +#if NCNN_STRING + // register custom layer by layer type name + // return 0 if success + int register_custom_layer(const char* type, layer_creator_func creator, layer_destroyer_func destroyer = 0, void* userdata = 0); + virtual int custom_layer_to_index(const char* type); +#endif // NCNN_STRING + // register custom layer by layer type + // return 0 if success + int register_custom_layer(int index, layer_creator_func creator, layer_destroyer_func destroyer = 0, void* userdata = 0); + +#if NCNN_STRING + int load_param(const DataReader& dr); +#endif // NCNN_STRING + + int load_param_bin(const DataReader& dr); + + int load_model(const DataReader& dr); + +#if NCNN_STDIO +#if NCNN_STRING + // load network structure from plain param file + // return 0 if success + int load_param(FILE* fp); + int load_param(const char* protopath); + int load_param_mem(const char* mem); +#endif // NCNN_STRING + // load network structure from binary param file + // return 0 if success + int load_param_bin(FILE* fp); + int load_param_bin(const char* protopath); + + // load network weight data from model file + // return 0 if success + int load_model(FILE* fp); + int load_model(const char* modelpath); +#endif // NCNN_STDIO + + // load network structure from external memory + // memory pointer must be 32-bit aligned + // return bytes consumed + int load_param(const unsigned char* mem); + + // reference network weight data from external memory + // weight data is not copied but referenced + // so external memory should be retained when used + // memory pointer must be 32-bit aligned + // return bytes consumed + int load_model(const unsigned char* mem); + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#if NCNN_STRING + // convenient load network structure from android asset plain param file + int load_param(AAsset* asset); + int load_param(AAssetManager* mgr, const char* assetpath); +#endif // NCNN_STRING + // convenient load network structure from android asset binary param file + int load_param_bin(AAsset* asset); + int load_param_bin(AAssetManager* mgr, const char* assetpath); + + // convenient load network weight data from android asset model file + int load_model(AAsset* asset); + int load_model(AAssetManager* mgr, const char* assetpath); +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + + // unload network structure and weight data + void clear(); + + // construct an Extractor from network + Extractor create_extractor() const; + + // get input/output indexes/names + const std::vector& input_indexes() const; + const std::vector& output_indexes() const; +#if NCNN_STRING + const std::vector& input_names() const; + const std::vector& output_names() const; +#endif + + const std::vector& blobs() const; + const std::vector& layers() const; + + std::vector& mutable_blobs(); + std::vector& mutable_layers(); + +protected: + friend class Extractor; +#if NCNN_STRING + int find_blob_index_by_name(const char* name) const; + int find_layer_index_by_name(const char* name) const; + virtual Layer* create_custom_layer(const char* type); +#endif // NCNN_STRING + virtual Layer* create_custom_layer(int index); + +private: + Net(const Net&); + Net& operator=(const Net&); + +private: + NetPrivate* const d; +}; + +class ExtractorPrivate; +class NCNN_EXPORT Extractor +{ +public: + virtual ~Extractor(); + + // copy + Extractor(const Extractor&); + + // assign + Extractor& operator=(const Extractor&); + + // clear blob mats and alloctors + void clear(); + + // enable light mode + // intermediate blob will be recycled when enabled + // enabled by default + void set_light_mode(bool enable); + + // set thread count for this extractor + // this will overwrite the global setting + // default count is system depended + void set_num_threads(int num_threads); + + // set blob memory allocator + void set_blob_allocator(Allocator* allocator); + + // set workspace memory allocator + void set_workspace_allocator(Allocator* allocator); + +#if NCNN_VULKAN + void set_vulkan_compute(bool enable); + + void set_blob_vkallocator(VkAllocator* allocator); + + void set_workspace_vkallocator(VkAllocator* allocator); + + void set_staging_vkallocator(VkAllocator* allocator); +#endif // NCNN_VULKAN + +#if NCNN_STRING + // set input by blob name + // return 0 if success + int input(const char* blob_name, const Mat& in); + + // get result by blob name + // return 0 if success + // type = 0, default + // type = 1, do not convert fp16/bf16 or / and packing + int extract(const char* blob_name, Mat& feat, int type = 0); +#endif // NCNN_STRING + + // set input by blob index + // return 0 if success + int input(int blob_index, const Mat& in); + + // get result by blob index + // return 0 if success + // type = 0, default + // type = 1, do not convert fp16/bf16 or / and packing + int extract(int blob_index, Mat& feat, int type = 0); + +#if NCNN_VULKAN +#if NCNN_STRING + // set input by blob name + // return 0 if success + int input(const char* blob_name, const VkMat& in); + + // get result by blob name + // return 0 if success + int extract(const char* blob_name, VkMat& feat, VkCompute& cmd); + + // set input by blob name + // return 0 if success + int input(const char* blob_name, const VkImageMat& in); + + // get result by blob name + // return 0 if success + int extract(const char* blob_name, VkImageMat& feat, VkCompute& cmd); +#endif // NCNN_STRING + + // set input by blob index + // return 0 if success + int input(int blob_index, const VkMat& in); + + // get result by blob index + // return 0 if success + int extract(int blob_index, VkMat& feat, VkCompute& cmd); + + // set input by blob index + // return 0 if success + int input(int blob_index, const VkImageMat& in); + + // get result by blob index + // return 0 if success + int extract(int blob_index, VkImageMat& feat, VkCompute& cmd); +#endif // NCNN_VULKAN + +protected: + friend Extractor Net::create_extractor() const; + Extractor(const Net* net, size_t blob_count); + +private: + ExtractorPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_NET_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/option.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/option.h new file mode 100644 index 0000000..3fda808 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/option.h @@ -0,0 +1,153 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_OPTION_H +#define NCNN_OPTION_H + +#include "platform.h" + +namespace ncnn { + +#if NCNN_VULKAN +class VkAllocator; +class PipelineCache; +#endif // NCNN_VULKAN + +class Allocator; +class NCNN_EXPORT Option +{ +public: + // default option + Option(); + +public: + // light mode + // intermediate blob will be recycled when enabled + // enabled by default + bool lightmode; + + // thread count + // default value is the one returned by get_cpu_count() + int num_threads; + + // blob memory allocator + Allocator* blob_allocator; + + // workspace memory allocator + Allocator* workspace_allocator; + +#if NCNN_VULKAN + // blob memory allocator + VkAllocator* blob_vkallocator; + + // workspace memory allocator + VkAllocator* workspace_vkallocator; + + // staging memory allocator + VkAllocator* staging_vkallocator; + + // pipeline cache + PipelineCache* pipeline_cache; +#endif // NCNN_VULKAN + + // the time openmp threads busy-wait for more work before going to sleep + // default value is 20ms to keep the cores enabled + // without too much extra power consumption afterwards + int openmp_blocktime; + + // enable winograd convolution optimization + // improve convolution 3x3 stride1 performance, may consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_winograd_convolution; + + // enable sgemm convolution optimization + // improve convolution 1x1 stride1 performance, may consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_sgemm_convolution; + + // enable quantized int8 inference + // use low-precision int8 path for quantized model + // changes should be applied before loading network structure and weight + // enabled by default + bool use_int8_inference; + + // enable vulkan compute + bool use_vulkan_compute; + + // enable bf16 data type for storage + // improve most operator performance on all arm devices, may consume more memory + bool use_bf16_storage; + + // enable options for gpu inference + bool use_fp16_packed; + bool use_fp16_storage; + bool use_fp16_arithmetic; + bool use_int8_packed; + bool use_int8_storage; + bool use_int8_arithmetic; + + // enable simd-friendly packed memory layout + // improve all operator performance on all arm devices, will consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_packing_layout; + + bool use_shader_pack8; + + // subgroup option + bool use_subgroup_basic; + bool use_subgroup_vote; + bool use_subgroup_ballot; + bool use_subgroup_shuffle; + + // turn on for adreno + bool use_image_storage; + bool use_tensor_storage; + + bool use_reserved_0; + + // enable DAZ(Denormals-Are-Zero) and FTZ(Flush-To-Zero) + // default value is 3 + // 0 = DAZ OFF, FTZ OFF + // 1 = DAZ ON , FTZ OFF + // 2 = DAZ OFF, FTZ ON + // 3 = DAZ ON, FTZ ON + int flush_denormals; + + bool use_local_pool_allocator; + + // enable local memory optimization for gpu inference + bool use_shader_local_memory; + + // enable cooperative matrix optimization for gpu inference + bool use_cooperative_matrix; + + // more fine-grained control of winograd convolution + bool use_winograd23_convolution; + bool use_winograd43_convolution; + bool use_winograd63_convolution; + + bool use_reserved_6; + bool use_reserved_7; + bool use_reserved_8; + bool use_reserved_9; + bool use_reserved_10; + bool use_reserved_11; +}; + +} // namespace ncnn + +#endif // NCNN_OPTION_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/paramdict.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/paramdict.h new file mode 100644 index 0000000..c2ef160 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/paramdict.h @@ -0,0 +1,73 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PARAMDICT_H +#define NCNN_PARAMDICT_H + +#include "mat.h" + +// at most 32 parameters +#define NCNN_MAX_PARAM_COUNT 32 + +namespace ncnn { + +class DataReader; +class Net; +class ParamDictPrivate; +class NCNN_EXPORT ParamDict +{ +public: + // empty + ParamDict(); + + virtual ~ParamDict(); + + // copy + ParamDict(const ParamDict&); + + // assign + ParamDict& operator=(const ParamDict&); + + // get type + int type(int id) const; + + // get int + int get(int id, int def) const; + // get float + float get(int id, float def) const; + // get array + Mat get(int id, const Mat& def) const; + + // set int + void set(int id, int i); + // set float + void set(int id, float f); + // set array + void set(int id, const Mat& v); + +protected: + friend class Net; + + void clear(); + + int load_param(const DataReader& dr); + int load_param_bin(const DataReader& dr); + +private: + ParamDictPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_PARAMDICT_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/pipeline.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/pipeline.h new file mode 100644 index 0000000..c284a14 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/pipeline.h @@ -0,0 +1,113 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PIPELINE_H +#define NCNN_PIPELINE_H + +#include "mat.h" +#include "platform.h" +#if NCNN_VULKAN +#include "gpu.h" + +#include +#endif // NCNN_VULKAN + +namespace ncnn { + +#if NCNN_VULKAN +class Option; +class PipelinePrivate; +class NCNN_EXPORT Pipeline +{ +public: + explicit Pipeline(const VulkanDevice* vkdev); + virtual ~Pipeline(); + +public: + void set_optimal_local_size_xyz(int w = 4, int h = 4, int c = 4); + void set_optimal_local_size_xyz(const Mat& local_size_xyz); + void set_local_size_xyz(int w, int h, int c); + + int create(const uint32_t* spv_data, size_t spv_data_size, const std::vector& specializations); + + int create(int shader_type_index, const Option& opt, const std::vector& specializations); + +public: + VkShaderModule shader_module() const; + VkDescriptorSetLayout descriptorset_layout() const; + VkPipelineLayout pipeline_layout() const; + VkPipeline pipeline() const; + VkDescriptorUpdateTemplateKHR descriptor_update_template() const; + + const ShaderInfo& shader_info() const; + + uint32_t local_size_x() const; + uint32_t local_size_y() const; + uint32_t local_size_z() const; + +protected: + void set_shader_module(VkShaderModule shader_module); + void set_descriptorset_layout(VkDescriptorSetLayout descriptorset_layout); + void set_pipeline_layout(VkPipelineLayout pipeline_layout); + void set_pipeline(VkPipeline pipeline); + void set_descriptor_update_template(VkDescriptorUpdateTemplateKHR descriptor_update_template); + + void set_shader_info(const ShaderInfo& shader_info); + +public: + const VulkanDevice* vkdev; + +private: + Pipeline(const Pipeline&); + Pipeline& operator=(const Pipeline&); + +private: + PipelinePrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class VkCompute; +class NCNN_EXPORT ImportAndroidHardwareBufferPipeline : private Pipeline +{ +public: + explicit ImportAndroidHardwareBufferPipeline(const VulkanDevice* vkdev); + virtual ~ImportAndroidHardwareBufferPipeline(); + + int create(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator, int type_to, int rotate_from, const Option& opt); + int create(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator, int type_to, int rotate_from, int target_width, int target_height, const Option& opt); + void destroy(); + + friend class VkCompute; + +protected: + int create_shader_module(const Option& opt); + int create_sampler(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator); + int create_descriptorset_layout(); + +public: + int type_to; + int rotate_from; + bool need_resize; + + VkSampler sampler; +}; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_PIPELINE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/pipelinecache.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/pipelinecache.h new file mode 100644 index 0000000..bb6b8fb --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/pipelinecache.h @@ -0,0 +1,85 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PIPELINECACHE_H +#define NCNN_PIPELINECACHE_H + +#include "platform.h" + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#include "mat.h" +#include "gpu.h" + +namespace ncnn { + +#if NCNN_VULKAN + +class VulkanDevice; +class PipelineCachePrivate; +class NCNN_EXPORT PipelineCache +{ +public: + explicit PipelineCache(const VulkanDevice* _vkdev); + + virtual ~PipelineCache(); + + void clear(); + + int get_pipeline(const uint32_t* spv_data, size_t spv_data_size, const std::vector& specializations, + uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* shader_module, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template, + ShaderInfo& shader_info) const; + + int get_pipeline(int shader_type_index, const Option& opt, const std::vector& specializations, + uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* shader_module, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template, + ShaderInfo& shader_info) const; + +protected: + int create_shader_module(int shader_type_index, const Option& opt, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* _shader_module, ShaderInfo& si) const; + + int new_pipeline(VkShaderModule shader_module, const ShaderInfo& shader_info, const std::vector& specializations, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template) const; + +protected: + const VulkanDevice* vkdev; + +private: + PipelineCache(const PipelineCache&); + PipelineCache& operator=(const PipelineCache&); + +private: + PipelineCachePrivate* const d; +}; + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_PIPELINECACHE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/platform.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/platform.h new file mode 100644 index 0000000..95e8a25 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/platform.h @@ -0,0 +1,285 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PLATFORM_H +#define NCNN_PLATFORM_H + +#define NCNN_STDIO 1 +#define NCNN_STRING 1 +#define NCNN_SIMPLEOCV 0 +#define NCNN_SIMPLEOMP 0 +#define NCNN_SIMPLESTL 0 +#define NCNN_THREADS 1 +#define NCNN_BENCHMARK 0 +#define NCNN_C_API 1 +#define NCNN_PLATFORM_API 1 +#define NCNN_PIXEL 1 +#define NCNN_PIXEL_ROTATE 1 +#define NCNN_PIXEL_AFFINE 1 +#define NCNN_PIXEL_DRAWING 1 +#define NCNN_VULKAN 1 +#define NCNN_SYSTEM_GLSLANG 0 +#define NCNN_RUNTIME_CPU 1 +#define NCNN_AVX 0 +#define NCNN_XOP 0 +#define NCNN_FMA 0 +#define NCNN_F16C 0 +#define NCNN_AVX2 0 +#define NCNN_AVXVNNI 0 +#define NCNN_AVX512 0 +#define NCNN_AVX512VNNI 0 +#define NCNN_AVX512BF16 0 +#define NCNN_AVX512FP16 0 +#define NCNN_VFPV4 1 +#if __aarch64__ +#define NCNN_ARM82 1 +#define NCNN_ARM82DOT 1 +#define NCNN_ARM82FP16FML 0 +#define NCNN_ARM84BF16 0 +#define NCNN_ARM84I8MM 0 +#define NCNN_ARM86SVE 0 +#define NCNN_ARM86SVE2 0 +#define NCNN_ARM86SVEBF16 0 +#define NCNN_ARM86SVEI8MM 0 +#define NCNN_ARM86SVEF32MM 0 +#endif // __aarch64__ +#define NCNN_MSA 0 +#define NCNN_LSX 0 +#define NCNN_MMI 0 +#define NCNN_RVV 0 +#define NCNN_INT8 1 +#define NCNN_BF16 1 +#define NCNN_FORCE_INLINE 1 + +#define NCNN_VERSION_STRING "1.0.20221128" + +#include "ncnn_export.h" + +#ifdef __cplusplus + +#if NCNN_THREADS +#if (defined _WIN32 && !(defined __MINGW32__)) +#define WIN32_LEAN_AND_MEAN +#include +#include +#else +#include +#endif +#endif // NCNN_THREADS + +#if __ANDROID_API__ >= 26 +#define VK_USE_PLATFORM_ANDROID_KHR +#endif // __ANDROID_API__ >= 26 + +namespace ncnn { + +#if NCNN_THREADS +#if (defined _WIN32 && !(defined __MINGW32__)) +class NCNN_EXPORT Mutex +{ +public: + Mutex() { InitializeSRWLock(&srwlock); } + ~Mutex() {} + void lock() { AcquireSRWLockExclusive(&srwlock); } + void unlock() { ReleaseSRWLockExclusive(&srwlock); } +private: + friend class ConditionVariable; + // NOTE SRWLock is available from windows vista + SRWLOCK srwlock; +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() { InitializeConditionVariable(&condvar); } + ~ConditionVariable() {} + void wait(Mutex& mutex) { SleepConditionVariableSRW(&condvar, &mutex.srwlock, INFINITE, 0); } + void broadcast() { WakeAllConditionVariable(&condvar); } + void signal() { WakeConditionVariable(&condvar); } +private: + CONDITION_VARIABLE condvar; +}; + +static unsigned __stdcall start_wrapper(void* args); +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*start)(void*), void* args = 0) { _start = start; _args = args; handle = (HANDLE)_beginthreadex(0, 0, start_wrapper, this, 0, 0); } + ~Thread() {} + void join() { WaitForSingleObject(handle, INFINITE); CloseHandle(handle); } +private: + friend unsigned __stdcall start_wrapper(void* args) + { + Thread* t = (Thread*)args; + t->_start(t->_args); + return 0; + } + HANDLE handle; + void* (*_start)(void*); + void* _args; +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { key = TlsAlloc(); } + ~ThreadLocalStorage() { TlsFree(key); } + void set(void* value) { TlsSetValue(key, (LPVOID)value); } + void* get() { return (void*)TlsGetValue(key); } +private: + DWORD key; +}; +#else // (defined _WIN32 && !(defined __MINGW32__)) +class NCNN_EXPORT Mutex +{ +public: + Mutex() { pthread_mutex_init(&mutex, 0); } + ~Mutex() { pthread_mutex_destroy(&mutex); } + void lock() { pthread_mutex_lock(&mutex); } + void unlock() { pthread_mutex_unlock(&mutex); } +private: + friend class ConditionVariable; + pthread_mutex_t mutex; +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() { pthread_cond_init(&cond, 0); } + ~ConditionVariable() { pthread_cond_destroy(&cond); } + void wait(Mutex& mutex) { pthread_cond_wait(&cond, &mutex.mutex); } + void broadcast() { pthread_cond_broadcast(&cond); } + void signal() { pthread_cond_signal(&cond); } +private: + pthread_cond_t cond; +}; + +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*start)(void*), void* args = 0) { pthread_create(&t, 0, start, args); } + ~Thread() {} + void join() { pthread_join(t, 0); } +private: + pthread_t t; +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { pthread_key_create(&key, 0); } + ~ThreadLocalStorage() { pthread_key_delete(key); } + void set(void* value) { pthread_setspecific(key, value); } + void* get() { return pthread_getspecific(key); } +private: + pthread_key_t key; +}; +#endif // (defined _WIN32 && !(defined __MINGW32__)) +#else // NCNN_THREADS +class NCNN_EXPORT Mutex +{ +public: + Mutex() {} + ~Mutex() {} + void lock() {} + void unlock() {} +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() {} + ~ConditionVariable() {} + void wait(Mutex& /*mutex*/) {} + void broadcast() {} + void signal() {} +}; + +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*/*start*/)(void*), void* /*args*/ = 0) {} + ~Thread() {} + void join() {} +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { data = 0; } + ~ThreadLocalStorage() {} + void set(void* value) { data = value; } + void* get() { return data; } +private: + void* data; +}; +#endif // NCNN_THREADS + +class NCNN_EXPORT MutexLockGuard +{ +public: + MutexLockGuard(Mutex& _mutex) : mutex(_mutex) { mutex.lock(); } + ~MutexLockGuard() { mutex.unlock(); } +private: + Mutex& mutex; +}; + +} // namespace ncnn + +#if NCNN_SIMPLESTL +#include "simplestl.h" +#else +#include +#include +#include +#include +#endif + +#endif // __cplusplus + +#if NCNN_STDIO +#if NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#include +#define NCNN_LOGE(...) do { \ + fprintf(stderr, ##__VA_ARGS__); fprintf(stderr, "\n"); \ + __android_log_print(ANDROID_LOG_WARN, "ncnn", ##__VA_ARGS__); } while(0) +#else // NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#include +#define NCNN_LOGE(...) do { \ + fprintf(stderr, ##__VA_ARGS__); fprintf(stderr, "\n"); } while(0) +#endif // NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#else +#define NCNN_LOGE(...) +#endif + + +#if NCNN_FORCE_INLINE +#ifdef _MSC_VER + #define NCNN_FORCEINLINE __forceinline +#elif defined(__GNUC__) + #define NCNN_FORCEINLINE inline __attribute__((__always_inline__)) +#elif defined(__CLANG__) + #if __has_attribute(__always_inline__) + #define NCNN_FORCEINLINE inline __attribute__((__always_inline__)) + #else + #define NCNN_FORCEINLINE inline + #endif +#else + #define NCNN_FORCEINLINE inline +#endif +#else + #define NCNN_FORCEINLINE inline +#endif + +#endif // NCNN_PLATFORM_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/simpleocv.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/simpleocv.h new file mode 100644 index 0000000..55ede15 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/simpleocv.h @@ -0,0 +1,501 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEOCV_H +#define NCNN_SIMPLEOCV_H + +#include "platform.h" + +#if NCNN_SIMPLEOCV + +#include +#include +#include "allocator.h" +#include "mat.h" + +#if defined(_MSC_VER) || defined(__GNUC__) +#pragma push_macro("min") +#pragma push_macro("max") +#undef min +#undef max +#endif + +#ifndef NCNN_XADD +using ncnn::NCNN_XADD; +#endif + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; + +enum +{ + CV_LOAD_IMAGE_UNCHANGED = -1, + CV_LOAD_IMAGE_GRAYSCALE = 0, + CV_LOAD_IMAGE_COLOR = 1, +}; + +enum +{ + CV_IMWRITE_JPEG_QUALITY = 1 +}; + +// minimal opencv style data structure implementation +namespace cv { + +template +static inline _Tp saturate_cast(int v) +{ + return _Tp(v); +} +template<> +inline uchar saturate_cast(int v) +{ + return (uchar)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); +} + +template +struct Scalar_ +{ + Scalar_() + { + v[0] = 0; + v[1] = 0; + v[2] = 0; + v[3] = 0; + } + Scalar_(_Tp _v0) + { + v[0] = _v0; + v[1] = 0; + v[2] = 0; + v[3] = 0; + } + Scalar_(_Tp _v0, _Tp _v1, _Tp _v2) + { + v[0] = _v0; + v[1] = _v1; + v[2] = _v2; + v[3] = 0; + } + Scalar_(_Tp _v0, _Tp _v1, _Tp _v2, _Tp _v3) + { + v[0] = _v0; + v[1] = _v1; + v[2] = _v2; + v[3] = _v3; + } + + const _Tp operator[](const int i) const + { + return v[i]; + } + + _Tp operator[](const int i) + { + return v[i]; + } + + _Tp v[4]; +}; + +typedef Scalar_ Scalar; + +template +struct Point_ +{ + Point_() + : x(0), y(0) + { + } + Point_(_Tp _x, _Tp _y) + : x(_x), y(_y) + { + } + + template + operator Point_<_Tp2>() const + { + return Point_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y)); + } + + _Tp x; + _Tp y; +}; + +typedef Point_ Point; +typedef Point_ Point2f; + +template +struct Size_ +{ + Size_() + : width(0), height(0) + { + } + Size_(_Tp _w, _Tp _h) + : width(_w), height(_h) + { + } + + template + operator Size_<_Tp2>() const + { + return Size_<_Tp2>(saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); + } + + _Tp width; + _Tp height; +}; + +typedef Size_ Size; +typedef Size_ Size2f; + +template +struct Rect_ +{ + Rect_() + : x(0), y(0), width(0), height(0) + { + } + Rect_(_Tp _x, _Tp _y, _Tp _w, _Tp _h) + : x(_x), y(_y), width(_w), height(_h) + { + } + Rect_(Point_<_Tp> _p, Size_<_Tp> _size) + : x(_p.x), y(_p.y), width(_size.width), height(_size.height) + { + } + + template + operator Rect_<_Tp2>() const + { + return Rect_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y), saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); + } + + _Tp x; + _Tp y; + _Tp width; + _Tp height; + + // area + _Tp area() const + { + return width * height; + } +}; + +template +static inline Rect_<_Tp>& operator&=(Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + _Tp x1 = std::max(a.x, b.x), y1 = std::max(a.y, b.y); + a.width = std::min(a.x + a.width, b.x + b.width) - x1; + a.height = std::min(a.y + a.height, b.y + b.height) - y1; + a.x = x1; + a.y = y1; + if (a.width <= 0 || a.height <= 0) + a = Rect_<_Tp>(); + return a; +} + +template +static inline Rect_<_Tp>& operator|=(Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + _Tp x1 = std::min(a.x, b.x), y1 = std::min(a.y, b.y); + a.width = std::max(a.x + a.width, b.x + b.width) - x1; + a.height = std::max(a.y + a.height, b.y + b.height) - y1; + a.x = x1; + a.y = y1; + return a; +} + +template +static inline Rect_<_Tp> operator&(const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c &= b; +} + +template +static inline Rect_<_Tp> operator|(const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c |= b; +} + +typedef Rect_ Rect; +typedef Rect_ Rect2f; + +#define CV_8UC1 1 +#define CV_8UC3 3 +#define CV_8UC4 4 +#define CV_32FC1 4 + +struct NCNN_EXPORT Mat +{ + Mat() + : data(0), refcount(0), rows(0), cols(0), c(0) + { + } + + Mat(int _rows, int _cols, int flags) + : data(0), refcount(0) + { + create(_rows, _cols, flags); + } + + // copy + Mat(const Mat& m) + : data(m.data), refcount(m.refcount) + { + if (refcount) + NCNN_XADD(refcount, 1); + + rows = m.rows; + cols = m.cols; + c = m.c; + } + + Mat(int _rows, int _cols, int flags, void* _data) + : data((unsigned char*)_data), refcount(0) + { + rows = _rows; + cols = _cols; + c = flags; + } + + ~Mat() + { + release(); + } + + // assign + Mat& operator=(const Mat& m) + { + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + + rows = m.rows; + cols = m.cols; + c = m.c; + + return *this; + } + + Mat& operator=(const Scalar& s) + { + if (total() > 0) + { + uchar* p = data; + for (int i = 0; i < cols * rows; i++) + { + for (int j = 0; j < c; j++) + { + *p++ = s[j]; + } + } + } + + return *this; + } + + void create(int _rows, int _cols, int flags) + { + release(); + + rows = _rows; + cols = _cols; + c = flags; + + if (total() > 0) + { + // refcount address must be aligned, so we expand totalsize here + size_t totalsize = (total() + 3) >> 2 << 2; + data = (uchar*)ncnn::fastMalloc(totalsize + (int)sizeof(*refcount)); + refcount = (int*)(((uchar*)data) + totalsize); + *refcount = 1; + } + } + + void release() + { + if (refcount && NCNN_XADD(refcount, -1) == 1) + ncnn::fastFree(data); + + data = 0; + + rows = 0; + cols = 0; + c = 0; + + refcount = 0; + } + + Mat clone() const + { + if (empty()) + return Mat(); + + Mat m(rows, cols, c); + + if (total() > 0) + { + memcpy(m.data, data, total()); + } + + return m; + } + + bool empty() const + { + return data == 0 || total() == 0; + } + + int channels() const + { + return c; + } + + int type() const + { + return c; + } + + size_t total() const + { + return cols * rows * c; + } + + const uchar* ptr(int y) const + { + return data + y * cols * c; + } + + uchar* ptr(int y) + { + return data + y * cols * c; + } + + template + const _Tp* ptr(int y) const + { + return (const _Tp*)data + y * cols * c; + } + + template + _Tp* ptr(int y) + { + return (_Tp*)data + y * cols * c; + } + + // roi + Mat operator()(const Rect& roi) const + { + if (empty()) + return Mat(); + + Mat m(roi.height, roi.width, c); + + int sy = roi.y; + for (int y = 0; y < roi.height; y++) + { + const uchar* sptr = ptr(sy) + roi.x * c; + uchar* dptr = m.ptr(y); + memcpy(dptr, sptr, roi.width * c); + sy++; + } + + return m; + } + + uchar* data; + + // pointer to the reference counter; + // when points to user-allocated data, the pointer is NULL + int* refcount; + + int rows; + int cols; + + int c; +}; + +enum ImreadModes +{ + IMREAD_UNCHANGED = -1, + IMREAD_GRAYSCALE = 0, + IMREAD_COLOR = 1 +}; + +NCNN_EXPORT Mat imread(const std::string& path, int flags = IMREAD_COLOR); + +enum ImwriteFlags +{ + IMWRITE_JPEG_QUALITY = 1 +}; + +NCNN_EXPORT bool imwrite(const std::string& path, const Mat& m, const std::vector& params = std::vector()); + +NCNN_EXPORT void imshow(const std::string& name, const Mat& m); + +NCNN_EXPORT int waitKey(int delay = 0); + +#if NCNN_PIXEL +NCNN_EXPORT void resize(const Mat& src, Mat& dst, const Size& size, float sw = 0.f, float sh = 0.f, int flags = 0); +#endif // NCNN_PIXEL + +#if NCNN_PIXEL_DRAWING + +enum +{ + FILLED = -1 +}; + +NCNN_EXPORT void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void rectangle(Mat& img, Rect rec, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void circle(Mat& img, Point center, int radius, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void line(Mat& img, Point p0, Point p1, const Scalar& color, int thickness = 1); + +enum +{ + FONT_HERSHEY_SIMPLEX = 0 +}; + +NCNN_EXPORT void putText(Mat& img, const std::string& text, Point org, int fontFace, double fontScale, Scalar color, int thickness = 1); + +NCNN_EXPORT Size getTextSize(const std::string& text, int fontFace, double fontScale, int thickness, int* baseLine); + +#endif // NCNN_PIXEL_DRAWING + +} // namespace cv + +#if defined(_MSC_VER) || defined(__GNUC__) +#pragma pop_macro("min") +#pragma pop_macro("max") +#endif + +#endif // NCNN_SIMPLEOCV + +#endif // NCNN_SIMPLEOCV_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/simpleomp.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/simpleomp.h new file mode 100644 index 0000000..13e2452 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/simpleomp.h @@ -0,0 +1,53 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEOMP_H +#define NCNN_SIMPLEOMP_H + +#include "platform.h" + +#if NCNN_SIMPLEOMP + +#include + +// This minimal openmp runtime implementation only supports the llvm openmp abi +// and only supports #pragma omp parallel for num_threads(X) + +#ifdef __cplusplus +extern "C" { +#endif + +NCNN_EXPORT int omp_get_max_threads(); + +NCNN_EXPORT void omp_set_num_threads(int num_threads); + +NCNN_EXPORT int omp_get_dynamic(); + +NCNN_EXPORT void omp_set_dynamic(int dynamic); + +NCNN_EXPORT int omp_get_num_threads(); + +NCNN_EXPORT int omp_get_thread_num(); + +NCNN_EXPORT int kmp_get_blocktime(); + +NCNN_EXPORT void kmp_set_blocktime(int blocktime); + +#ifdef __cplusplus +} +#endif + +#endif // NCNN_SIMPLEOMP + +#endif // NCNN_SIMPLEOMP_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/simplestl.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/simplestl.h new file mode 100644 index 0000000..00ff468 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/simplestl.h @@ -0,0 +1,565 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLESTL_H +#define NCNN_SIMPLESTL_H + +#include +#include +#include + +#if !NCNN_SIMPLESTL + +#include + +#else + +// allocation functions +NCNN_EXPORT void* operator new(size_t size); +NCNN_EXPORT void* operator new[](size_t size); +// placement allocation functions +NCNN_EXPORT void* operator new(size_t size, void* ptr); +NCNN_EXPORT void* operator new[](size_t size, void* ptr); +// deallocation functions +NCNN_EXPORT void operator delete(void* ptr); +NCNN_EXPORT void operator delete[](void* ptr); +// deallocation functions since c++14 +#if __cplusplus >= 201402L +NCNN_EXPORT void operator delete(void* ptr, size_t sz); +NCNN_EXPORT void operator delete[](void* ptr, size_t sz); +#endif +// placement deallocation functions +NCNN_EXPORT void operator delete(void* ptr, void* voidptr2); +NCNN_EXPORT void operator delete[](void* ptr, void* voidptr2); + +#endif + +// minimal stl data structure implementation +namespace std { + +template +const T& max(const T& a, const T& b) +{ + return (a < b) ? b : a; +} + +template +const T& min(const T& a, const T& b) +{ + return (a > b) ? b : a; +} + +template +void swap(T& a, T& b) +{ + T temp(a); + a = b; + b = temp; +} + +template +struct pair +{ + pair() + : first(), second() + { + } + pair(const T1& t1, const T2& t2) + : first(t1), second(t2) + { + } + + T1 first; + T2 second; +}; + +template +bool operator==(const pair& x, const pair& y) +{ + return (x.first == y.first && x.second == y.second); +} +template +bool operator<(const pair& x, const pair& y) +{ + return x.first < y.first || (!(y.first < x.first) && x.second < y.second); +} +template +bool operator!=(const pair& x, const pair& y) +{ + return !(x == y); +} +template +bool operator>(const pair& x, const pair& y) +{ + return y < x; +} +template +bool operator<=(const pair& x, const pair& y) +{ + return !(y < x); +} +template +bool operator>=(const pair& x, const pair& y) +{ + return !(x < y); +} + +template +pair make_pair(const T1& t1, const T2& t2) +{ + return pair(t1, t2); +} + +template +struct node +{ + node* prev_; + node* next_; + T data_; + + node() + : prev_(0), next_(0), data_() + { + } + node(const T& t) + : prev_(0), next_(0), data_(t) + { + } +}; + +template +struct iter_list +{ + iter_list() + : curr_(0) + { + } + iter_list(node* n) + : curr_(n) + { + } + iter_list(const iter_list& i) + : curr_(i.curr_) + { + } + ~iter_list() + { + } + + iter_list& operator=(const iter_list& i) + { + curr_ = i.curr_; + return *this; + } + + T& operator*() + { + return curr_->data_; + } + T* operator->() + { + return &(curr_->data_); + } + + bool operator==(const iter_list& i) + { + return curr_ == i.curr_; + } + bool operator!=(const iter_list& i) + { + return curr_ != i.curr_; + } + + iter_list& operator++() + { + curr_ = curr_->next_; + return *this; + } + iter_list& operator--() + { + curr_ = curr_->prev_; + return *this; + } + + node* curr_; +}; + +template +struct list +{ + typedef iter_list iterator; + + list() + { + head_ = new node(); + tail_ = head_; + count_ = 0; + } + ~list() + { + clear(); + delete head_; + } + list(const list& l) + { + head_ = new node(); + tail_ = head_; + count_ = 0; + + for (iter_list i = l.begin(); i != l.end(); ++i) + { + push_back(*i); + } + } + + list& operator=(const list& l) + { + if (this == &l) + { + return *this; + } + clear(); + + for (iter_list i = l.begin(); i != l.end(); ++i) + { + push_back(*i); + } + return *this; + } + + void clear() + { + while (count_ > 0) + { + pop_front(); + } + } + + void pop_front() + { + if (count_ > 0) + { + head_ = head_->next_; + delete head_->prev_; + head_->prev_ = 0; + --count_; + } + } + + size_t size() const + { + return count_; + } + iter_list begin() const + { + return iter_list(head_); + } + iter_list end() const + { + return iter_list(tail_); + } + bool empty() const + { + return count_ == 0; + } + + void push_back(const T& t) + { + if (count_ == 0) + { + head_ = new node(t); + head_->prev_ = 0; + head_->next_ = tail_; + tail_->prev_ = head_; + count_ = 1; + } + else + { + node* temp = new node(t); + temp->prev_ = tail_->prev_; + temp->next_ = tail_; + tail_->prev_->next_ = temp; + tail_->prev_ = temp; + ++count_; + } + } + + iter_list erase(iter_list pos) + { + if (pos != end()) + { + node* temp = pos.curr_; + if (temp == head_) + { + ++pos; + temp->next_->prev_ = 0; + head_ = temp->next_; + } + else + { + --pos; + temp->next_->prev_ = temp->prev_; + temp->prev_->next_ = temp->next_; + ++pos; + } + delete temp; + --count_; + } + return pos; + } + +protected: + node* head_; + node* tail_; + size_t count_; +}; + +template +struct greater +{ + bool operator()(const T& x, const T& y) const + { + return (x > y); + } +}; + +template +struct less +{ + bool operator()(const T& x, const T& y) const + { + return (x < y); + } +}; + +template +void partial_sort(RandomAccessIter first, RandomAccessIter middle, RandomAccessIter last, Compare comp) +{ + // [TODO] heap sort should be used here, but we simply use bubble sort now + for (RandomAccessIter i = first; i < middle; ++i) + { + // bubble sort + for (RandomAccessIter j = last - 1; j > first; --j) + { + if (comp(*j, *(j - 1))) + { + swap(*j, *(j - 1)); + } + } + } +} + +template +struct vector +{ + vector() + : data_(0), size_(0), capacity_(0) + { + } + vector(const size_t new_size, const T& value = T()) + : data_(0), size_(0), capacity_(0) + { + resize(new_size, value); + } + ~vector() + { + clear(); + } + vector(const vector& v) + : data_(0), size_(0), capacity_(0) + { + resize(v.size()); + for (size_t i = 0; i < size_; i++) + { + data_[i] = v.data_[i]; + } + } + + vector& operator=(const vector& v) + { + if (this == &v) + { + return *this; + } + resize(0); + resize(v.size()); + for (size_t i = 0; i < size_; i++) + { + data_[i] = v.data_[i]; + } + return *this; + } + + void resize(const size_t new_size, const T& value = T()) + { + try_alloc(new_size); + if (new_size > size_) + { + for (size_t i = size_; i < new_size; i++) + { + new (&data_[i]) T(value); + } + } + else if (new_size < size_) + { + for (size_t i = new_size; i < size_; i++) + { + data_[i].~T(); + } + } + size_ = new_size; + } + + void clear() + { + for (size_t i = 0; i < size_; i++) + { + data_[i].~T(); + } + delete[](char*) data_; + data_ = 0; + size_ = 0; + capacity_ = 0; + } + + T* data() const + { + return data_; + } + size_t size() const + { + return size_; + } + T& operator[](size_t i) const + { + return data_[i]; + } + T* begin() const + { + return &data_[0]; + } + T* end() const + { + return &data_[size_]; + } + bool empty() const + { + return size_ == 0; + } + + void push_back(const T& t) + { + try_alloc(size_ + 1); + new (&data_[size_]) T(t); + size_++; + } + + void insert(T* pos, T* b, T* e) + { + vector* v = 0; + if (b >= begin() && b < end()) + { + //the same vector + v = new vector(*this); + b = v->begin() + (b - begin()); + e = v->begin() + (e - begin()); + } + size_t diff = pos - begin(); + try_alloc(size_ + (e - b)); + pos = begin() + diff; + memmove(pos + (e - b), pos, (end() - pos) * sizeof(T)); + size_t len = e - b; + size_ += len; + for (size_t i = 0; i < len; i++) + { + *pos = *b; + pos++; + b++; + } + delete v; + } + + T* erase(T* pos) + { + pos->~T(); + memmove(pos, pos + 1, (end() - pos - 1) * sizeof(T)); + size_--; + return pos; + } + +protected: + T* data_; + size_t size_; + size_t capacity_; + void try_alloc(size_t new_size) + { + if (new_size * 3 / 2 > capacity_ / 2) + { + capacity_ = new_size * 2; + T* new_data = (T*)new char[capacity_ * sizeof(T)]; + memset(static_cast(new_data), 0, capacity_ * sizeof(T)); + if (data_) + { + memmove(new_data, data_, sizeof(T) * size_); + delete[](char*) data_; + } + data_ = new_data; + } + } +}; + +struct NCNN_EXPORT string : public vector +{ + string() + { + } + string(const char* str) + { + size_t len = strlen(str); + resize(len); + memcpy(data_, str, len); + } + const char* c_str() const + { + return (const char*)data_; + } + bool operator==(const string& str2) const + { + return strcmp(data_, str2.data_) == 0; + } + bool operator==(const char* str2) const + { + return strcmp(data_, str2) == 0; + } + bool operator!=(const char* str2) const + { + return strcmp(data_, str2) != 0; + } + string& operator+=(const string& str1) + { + insert(end(), str1.begin(), str1.end()); + return *this; + } +}; + +inline string operator+(const string& str1, const string& str2) +{ + string str(str1); + str.insert(str.end(), str2.begin(), str2.end()); + return str; +} + +} // namespace std + +#endif // NCNN_SIMPLESTL_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/vulkan_header_fix.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/vulkan_header_fix.h new file mode 100644 index 0000000..e7a7e8e --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/include/ncnn/vulkan_header_fix.h @@ -0,0 +1,251 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_VULKAN_HEADER_FIX_H +#define NCNN_VULKAN_HEADER_FIX_H + +#include + +// This header contains new structure and function declearation to fix build with old vulkan sdk + +#if VK_HEADER_VERSION < 70 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES (VkStructureType)1000094000 +typedef enum VkSubgroupFeatureFlagBits +{ + VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001, + VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002, + VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004, + VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008, + VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010, + VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020, + VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040, + VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080, + VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 0x00000100, + VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubgroupFeatureFlagBits; +typedef VkFlags VkSubgroupFeatureFlags; +typedef struct VkPhysicalDeviceSubgroupProperties +{ + VkStructureType sType; + void* pNext; + uint32_t subgroupSize; + VkShaderStageFlags supportedStages; + VkSubgroupFeatureFlags supportedOperations; + VkBool32 quadOperationsInAllStages; +} VkPhysicalDeviceSubgroupProperties; +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES (VkStructureType)1000168000 +#define VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT (VkStructureType)1000168001 +typedef struct VkPhysicalDeviceMaintenance3Properties +{ + VkStructureType sType; + void* pNext; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceMaintenance3Properties; +typedef struct VkDescriptorSetLayoutSupport +{ + VkStructureType sType; + void* pNext; + VkBool32 supported; +} VkDescriptorSetLayoutSupport; +typedef VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; +typedef VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; +typedef void(VKAPI_PTR* PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); +#endif // VK_HEADER_VERSION < 70 + +#if VK_HEADER_VERSION < 80 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR (VkStructureType)1000177000 +typedef struct VkPhysicalDevice8BitStorageFeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; +} VkPhysicalDevice8BitStorageFeaturesKHR; +#define VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR (VkStructureType)1000109000 +#define VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR (VkStructureType)1000109001 +#define VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR (VkStructureType)1000109002 +#define VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR (VkStructureType)1000109003 +#define VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR (VkStructureType)1000109004 +#define VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR (VkStructureType)1000109005 +#define VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR (VkStructureType)1000109006 +typedef struct VkAttachmentDescription2KHR +{ + VkStructureType sType; + const void* pNext; + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription2KHR; +typedef struct VkAttachmentReference2KHR +{ + VkStructureType sType; + const void* pNext; + uint32_t attachment; + VkImageLayout layout; + VkImageAspectFlags aspectMask; +} VkAttachmentReference2KHR; +typedef struct VkSubpassDescription2KHR +{ + VkStructureType sType; + const void* pNext; + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t viewMask; + uint32_t inputAttachmentCount; + const VkAttachmentReference2KHR* pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference2KHR* pColorAttachments; + const VkAttachmentReference2KHR* pResolveAttachments; + const VkAttachmentReference2KHR* pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t* pPreserveAttachments; +} VkSubpassDescription2KHR; +typedef struct VkSubpassDependency2KHR +{ + VkStructureType sType; + const void* pNext; + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; + int32_t viewOffset; +} VkSubpassDependency2KHR; +typedef struct VkRenderPassCreateInfo2KHR +{ + VkStructureType sType; + const void* pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription2KHR* pAttachments; + uint32_t subpassCount; + const VkSubpassDescription2KHR* pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency2KHR* pDependencies; + uint32_t correlatedViewMaskCount; + const uint32_t* pCorrelatedViewMasks; +} VkRenderPassCreateInfo2KHR; +typedef struct VkSubpassBeginInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkSubpassContents contents; +} VkSubpassBeginInfoKHR; + +typedef struct VkSubpassEndInfoKHR +{ + VkStructureType sType; + const void* pNext; +} VkSubpassEndInfoKHR; +typedef VkResult(VKAPI_PTR* PFN_vkCreateRenderPass2KHR)(VkDevice device, const VkRenderPassCreateInfo2KHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void(VKAPI_PTR* PFN_vkCmdBeginRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfoKHR* pSubpassBeginInfo); +typedef void(VKAPI_PTR* PFN_vkCmdNextSubpass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfoKHR* pSubpassBeginInfo, const VkSubpassEndInfoKHR* pSubpassEndInfo); +typedef void(VKAPI_PTR* PFN_vkCmdEndRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassEndInfoKHR* pSubpassEndInfo); +#endif // VK_HEADER_VERSION < 80 + +#if VK_HEADER_VERSION < 95 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR (VkStructureType)1000082000 +typedef struct VkPhysicalDeviceFloat16Int8FeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; +} VkPhysicalDeviceFloat16Int8FeaturesKHR; +#endif // VK_HEADER_VERSION < 95 + +#if VK_HEADER_VERSION < 97 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT (VkStructureType)1000237000 +typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT +{ + VkStructureType sType; + void* pNext; + VkDeviceSize heapBudget[VK_MAX_MEMORY_HEAPS]; + VkDeviceSize heapUsage[VK_MAX_MEMORY_HEAPS]; +} VkPhysicalDeviceMemoryBudgetPropertiesEXT; +#endif // VK_HEADER_VERSION < 97 + +#if VK_HEADER_VERSION < 101 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV (VkStructureType)1000249000 +#define VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV (VkStructureType)1000249001 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV (VkStructureType)1000249002 +typedef enum VkComponentTypeNV +{ + VK_COMPONENT_TYPE_FLOAT16_NV = 0, + VK_COMPONENT_TYPE_FLOAT32_NV = 1, + VK_COMPONENT_TYPE_FLOAT64_NV = 2, + VK_COMPONENT_TYPE_SINT8_NV = 3, + VK_COMPONENT_TYPE_SINT16_NV = 4, + VK_COMPONENT_TYPE_SINT32_NV = 5, + VK_COMPONENT_TYPE_SINT64_NV = 6, + VK_COMPONENT_TYPE_UINT8_NV = 7, + VK_COMPONENT_TYPE_UINT16_NV = 8, + VK_COMPONENT_TYPE_UINT32_NV = 9, + VK_COMPONENT_TYPE_UINT64_NV = 10, + VK_COMPONENT_TYPE_BEGIN_RANGE_NV = VK_COMPONENT_TYPE_FLOAT16_NV, + VK_COMPONENT_TYPE_END_RANGE_NV = VK_COMPONENT_TYPE_UINT64_NV, + VK_COMPONENT_TYPE_RANGE_SIZE_NV = (VK_COMPONENT_TYPE_UINT64_NV - VK_COMPONENT_TYPE_FLOAT16_NV + 1), + VK_COMPONENT_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkComponentTypeNV; +typedef enum VkScopeNV +{ + VK_SCOPE_DEVICE_NV = 1, + VK_SCOPE_WORKGROUP_NV = 2, + VK_SCOPE_SUBGROUP_NV = 3, + VK_SCOPE_QUEUE_FAMILY_NV = 5, + VK_SCOPE_BEGIN_RANGE_NV = VK_SCOPE_DEVICE_NV, + VK_SCOPE_END_RANGE_NV = VK_SCOPE_QUEUE_FAMILY_NV, + VK_SCOPE_RANGE_SIZE_NV = (VK_SCOPE_QUEUE_FAMILY_NV - VK_SCOPE_DEVICE_NV + 1), + VK_SCOPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkScopeNV; +typedef struct VkCooperativeMatrixPropertiesNV +{ + VkStructureType sType; + void* pNext; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeNV AType; + VkComponentTypeNV BType; + VkComponentTypeNV CType; + VkComponentTypeNV DType; + VkScopeNV scope; +} VkCooperativeMatrixPropertiesNV; +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesNV +{ + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesNV; +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesNV +{ + VkStructureType sType; + void* pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesNV; +typedef VkResult(VKAPI_PTR* PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixPropertiesNV* pProperties); +#endif // VK_HEADER_VERSION < 101 + +#endif // NCNN_VULKAN_HEADER_FIX_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/lib/cmake/ncnn/ncnn-release.cmake b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/lib/cmake/ncnn/ncnn-release.cmake new file mode 100644 index 0000000..1fb8660 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/lib/cmake/ncnn/ncnn-release.cmake @@ -0,0 +1,19 @@ +#---------------------------------------------------------------- +# Generated CMake target import file for configuration "Release". +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "ncnn" for configuration "Release" +set_property(TARGET ncnn APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(ncnn PROPERTIES + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libncnn.so" + IMPORTED_SONAME_RELEASE "libncnn.so" + ) + +list(APPEND _cmake_import_check_targets ncnn ) +list(APPEND _cmake_import_check_files_for_ncnn "${_IMPORT_PREFIX}/lib/libncnn.so" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/lib/cmake/ncnn/ncnn.cmake b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/lib/cmake/ncnn/ncnn.cmake new file mode 100644 index 0000000..53b9fae --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/lib/cmake/ncnn/ncnn.cmake @@ -0,0 +1,109 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8) + message(FATAL_ERROR "CMake >= 2.8.0 required") +endif() +if(CMAKE_VERSION VERSION_LESS "2.8.3") + message(FATAL_ERROR "CMake >= 2.8.3 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.8.3...3.23) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_cmake_targets_defined "") +set(_cmake_targets_not_defined "") +set(_cmake_expected_targets "") +foreach(_cmake_expected_target IN ITEMS ncnn) + list(APPEND _cmake_expected_targets "${_cmake_expected_target}") + if(TARGET "${_cmake_expected_target}") + list(APPEND _cmake_targets_defined "${_cmake_expected_target}") + else() + list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") + endif() +endforeach() +unset(_cmake_expected_target) +if(_cmake_targets_defined STREQUAL _cmake_expected_targets) + unset(_cmake_targets_defined) + unset(_cmake_targets_not_defined) + unset(_cmake_expected_targets) + unset(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT _cmake_targets_defined STREQUAL "") + string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") + string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") +endif() +unset(_cmake_targets_defined) +unset(_cmake_targets_not_defined) +unset(_cmake_expected_targets) + + +# Compute the installation prefix relative to this file. +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +if(_IMPORT_PREFIX STREQUAL "/") + set(_IMPORT_PREFIX "") +endif() + +# Create imported target ncnn +add_library(ncnn SHARED IMPORTED) + +set_target_properties(ncnn PROPERTIES + INTERFACE_COMPILE_OPTIONS "-fno-rtti;-fno-exceptions" + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include/ncnn" + INTERFACE_LINK_LIBRARIES "-fopenmp;-static-openmp;-Wl,-wrap,__kmp_affinity_determine_capable;Threads::Threads;Vulkan::Vulkan;android;jnigraphics;log" + INTERFACE_POSITION_INDEPENDENT_CODE "ON" +) + +if(CMAKE_VERSION VERSION_LESS 2.8.12) + message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.") +endif() + +# Load information for each installed configuration. +file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/ncnn-*.cmake") +foreach(_cmake_config_file IN LISTS _cmake_config_files) + include("${_cmake_config_file}") +endforeach() +unset(_cmake_config_file) +unset(_cmake_config_files) + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(_cmake_target IN LISTS _cmake_import_check_targets) + foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}") + if(NOT EXISTS "${_cmake_file}") + message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file + \"${_cmake_file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + unset(_cmake_file) + unset("_cmake_import_check_files_for_${_cmake_target}") +endforeach() +unset(_cmake_target) +unset(_cmake_import_check_targets) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/lib/cmake/ncnn/ncnnConfig.cmake b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/lib/cmake/ncnn/ncnnConfig.cmake new file mode 100644 index 0000000..abb2dd6 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/lib/cmake/ncnn/ncnnConfig.cmake @@ -0,0 +1,42 @@ +set(NCNN_OPENMP ON) +set(NCNN_THREADS ON) +set(NCNN_VULKAN ON) +set(NCNN_SHARED_LIB ON) +set(NCNN_SYSTEM_GLSLANG OFF) + +if(NCNN_OPENMP) + find_package(OpenMP) +endif() + +if(NCNN_THREADS) + set(CMAKE_THREAD_PREFER_PTHREAD TRUE) + set(THREADS_PREFER_PTHREAD_FLAG TRUE) + find_package(Threads REQUIRED) +endif() + +if(NCNN_VULKAN) + find_package(Vulkan REQUIRED) + + if(NOT NCNN_SHARED_LIB) + if(NCNN_SYSTEM_GLSLANG) + find_package(glslang QUIET) + if(NOT glslang_FOUND) + set(GLSLANG_TARGET_DIR "") + include(${GLSLANG_TARGET_DIR}/OSDependentTargets.cmake) + include(${GLSLANG_TARGET_DIR}/OGLCompilerTargets.cmake) + if(EXISTS "${GLSLANG_TARGET_DIR}/HLSLTargets.cmake") + # hlsl support can be optional + include("${GLSLANG_TARGET_DIR}/HLSLTargets.cmake") + endif() + include(${GLSLANG_TARGET_DIR}/glslangTargets.cmake) + include(${GLSLANG_TARGET_DIR}/SPIRVTargets.cmake) + endif() + else() + set(glslang_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../lib/cmake/glslang") + find_package(glslang QUIET) + endif() + + endif() +endif() + +include(${CMAKE_CURRENT_LIST_DIR}/ncnn.cmake) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/lib/pkgconfig/ncnn.pc b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/lib/pkgconfig/ncnn.pc new file mode 100644 index 0000000..2ae00de --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/armeabi-v7a/lib/pkgconfig/ncnn.pc @@ -0,0 +1,11 @@ +prefix=${pcfiledir}/../.. +librarydir=${prefix}/lib +includedir=${prefix}/include + +Name: ncnn +Description: high-performance neural network inference framework optimized for the mobile platform +Version: 1.0.20221128 +URL: https://github.com/Tencent/ncnn +Libs: -L"${librarydir}" -lncnn +Cflags: -I"${includedir}" + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/allocator.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/allocator.h new file mode 100644 index 0000000..3a5ebca --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/allocator.h @@ -0,0 +1,448 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_ALLOCATOR_H +#define NCNN_ALLOCATOR_H + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include "platform.h" + +#include + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +#include +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +// the alignment of all the allocated buffers +#if NCNN_AVX512 +#define NCNN_MALLOC_ALIGN 64 +#elif NCNN_AVX +#define NCNN_MALLOC_ALIGN 32 +#else +#define NCNN_MALLOC_ALIGN 16 +#endif + +// we have some optimized kernels that may overread buffer a bit in loop +// it is common to interleave next-loop data load with arithmetic instructions +// allocating more bytes keeps us safe from SEGV_ACCERR failure +#define NCNN_MALLOC_OVERREAD 64 + +// Aligns a pointer to the specified number of bytes +// ptr Aligned pointer +// n Alignment size that must be a power of two +template +static NCNN_FORCEINLINE _Tp* alignPtr(_Tp* ptr, int n = (int)sizeof(_Tp)) +{ + return (_Tp*)(((size_t)ptr + n - 1) & -n); +} + +// Aligns a buffer size to the specified number of bytes +// The function returns the minimum number that is greater or equal to sz and is divisible by n +// sz Buffer size to align +// n Alignment size that must be a power of two +static NCNN_FORCEINLINE size_t alignSize(size_t sz, int n) +{ + return (sz + n - 1) & -n; +} + +static NCNN_FORCEINLINE void* fastMalloc(size_t size) +{ +#if _MSC_VER + return _aligned_malloc(size, NCNN_MALLOC_ALIGN); +#elif (defined(__unix__) || defined(__APPLE__)) && _POSIX_C_SOURCE >= 200112L || (__ANDROID__ && __ANDROID_API__ >= 17) + void* ptr = 0; + if (posix_memalign(&ptr, NCNN_MALLOC_ALIGN, size + NCNN_MALLOC_OVERREAD)) + ptr = 0; + return ptr; +#elif __ANDROID__ && __ANDROID_API__ < 17 + return memalign(NCNN_MALLOC_ALIGN, size + NCNN_MALLOC_OVERREAD); +#else + unsigned char* udata = (unsigned char*)malloc(size + sizeof(void*) + NCNN_MALLOC_ALIGN + NCNN_MALLOC_OVERREAD); + if (!udata) + return 0; + unsigned char** adata = alignPtr((unsigned char**)udata + 1, NCNN_MALLOC_ALIGN); + adata[-1] = udata; + return adata; +#endif +} + +static NCNN_FORCEINLINE void fastFree(void* ptr) +{ + if (ptr) + { +#if _MSC_VER + _aligned_free(ptr); +#elif (defined(__unix__) || defined(__APPLE__)) && _POSIX_C_SOURCE >= 200112L || (__ANDROID__ && __ANDROID_API__ >= 17) + free(ptr); +#elif __ANDROID__ && __ANDROID_API__ < 17 + free(ptr); +#else + unsigned char* udata = ((unsigned char**)ptr)[-1]; + free(udata); +#endif + } +} + +#if NCNN_THREADS +// exchange-add operation for atomic operations on reference counters +#if defined __riscv && !defined __riscv_atomic +// riscv target without A extension +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#elif defined __INTEL_COMPILER && !(defined WIN32 || defined _WIN32) +// atomic increment on the linux version of the Intel(tm) compiler +#define NCNN_XADD(addr, delta) (int)_InterlockedExchangeAdd(const_cast(reinterpret_cast(addr)), delta) +#elif defined __GNUC__ +#if defined __clang__ && __clang_major__ >= 3 && !defined __ANDROID__ && !defined __EMSCRIPTEN__ && !defined(__CUDACC__) +#ifdef __ATOMIC_ACQ_REL +#define NCNN_XADD(addr, delta) __c11_atomic_fetch_add((_Atomic(int)*)(addr), delta, __ATOMIC_ACQ_REL) +#else +#define NCNN_XADD(addr, delta) __atomic_fetch_add((_Atomic(int)*)(addr), delta, 4) +#endif +#else +#if defined __ATOMIC_ACQ_REL && !defined __clang__ +// version for gcc >= 4.7 +#define NCNN_XADD(addr, delta) (int)__atomic_fetch_add((unsigned*)(addr), (unsigned)(delta), __ATOMIC_ACQ_REL) +#else +#define NCNN_XADD(addr, delta) (int)__sync_fetch_and_add((unsigned*)(addr), (unsigned)(delta)) +#endif +#endif +#elif defined _MSC_VER && !defined RC_INVOKED +#define NCNN_XADD(addr, delta) (int)_InterlockedExchangeAdd((long volatile*)addr, delta) +#else +// thread-unsafe branch +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#endif +#else // NCNN_THREADS +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#endif // NCNN_THREADS + +class NCNN_EXPORT Allocator +{ +public: + virtual ~Allocator(); + virtual void* fastMalloc(size_t size) = 0; + virtual void fastFree(void* ptr) = 0; +}; + +class PoolAllocatorPrivate; +class NCNN_EXPORT PoolAllocator : public Allocator +{ +public: + PoolAllocator(); + ~PoolAllocator(); + + // ratio range 0 ~ 1 + // default cr = 0 + void set_size_compare_ratio(float scr); + + // budget drop threshold + // default threshold = 10 + void set_size_drop_threshold(size_t); + + // release all budgets immediately + void clear(); + + virtual void* fastMalloc(size_t size); + virtual void fastFree(void* ptr); + +private: + PoolAllocator(const PoolAllocator&); + PoolAllocator& operator=(const PoolAllocator&); + +private: + PoolAllocatorPrivate* const d; +}; + +class UnlockedPoolAllocatorPrivate; +class NCNN_EXPORT UnlockedPoolAllocator : public Allocator +{ +public: + UnlockedPoolAllocator(); + ~UnlockedPoolAllocator(); + + // ratio range 0 ~ 1 + // default cr = 0 + void set_size_compare_ratio(float scr); + + // budget drop threshold + // default threshold = 10 + void set_size_drop_threshold(size_t); + + // release all budgets immediately + void clear(); + + virtual void* fastMalloc(size_t size); + virtual void fastFree(void* ptr); + +private: + UnlockedPoolAllocator(const UnlockedPoolAllocator&); + UnlockedPoolAllocator& operator=(const UnlockedPoolAllocator&); + +private: + UnlockedPoolAllocatorPrivate* const d; +}; + +#if NCNN_VULKAN + +class VulkanDevice; + +class NCNN_EXPORT VkBufferMemory +{ +public: + VkBuffer buffer; + + // the base offset assigned by allocator + size_t offset; + size_t capacity; + + VkDeviceMemory memory; + void* mapped_ptr; + + // buffer state, modified by command functions internally + mutable VkAccessFlags access_flags; + mutable VkPipelineStageFlags stage_flags; + + // initialize and modified by mat + int refcount; +}; + +class NCNN_EXPORT VkImageMemory +{ +public: + VkImage image; + VkImageView imageview; + + // underlying info assigned by allocator + int width; + int height; + int depth; + VkFormat format; + + VkDeviceMemory memory; + void* mapped_ptr; + + // the base offset assigned by allocator + size_t bind_offset; + size_t bind_capacity; + + // image state, modified by command functions internally + mutable VkAccessFlags access_flags; + mutable VkImageLayout image_layout; + mutable VkPipelineStageFlags stage_flags; + + // in-execution state, modified by command functions internally + mutable int command_refcount; + + // initialize and modified by mat + int refcount; +}; + +class NCNN_EXPORT VkAllocator +{ +public: + explicit VkAllocator(const VulkanDevice* _vkdev); + virtual ~VkAllocator(); + + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size) = 0; + virtual void fastFree(VkBufferMemory* ptr) = 0; + virtual int flush(VkBufferMemory* ptr); + virtual int invalidate(VkBufferMemory* ptr); + + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack) = 0; + virtual void fastFree(VkImageMemory* ptr) = 0; + +public: + const VulkanDevice* vkdev; + uint32_t buffer_memory_type_index; + uint32_t image_memory_type_index; + uint32_t reserved_type_index; + bool mappable; + bool coherent; + +protected: + VkBuffer create_buffer(size_t size, VkBufferUsageFlags usage); + VkDeviceMemory allocate_memory(size_t size, uint32_t memory_type_index); + VkDeviceMemory allocate_dedicated_memory(size_t size, uint32_t memory_type_index, VkImage image, VkBuffer buffer); + + VkImage create_image(int width, int height, int depth, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage); + VkImageView create_imageview(VkImage image, VkFormat format); +}; + +class VkBlobAllocatorPrivate; +class NCNN_EXPORT VkBlobAllocator : public VkAllocator +{ +public: + explicit VkBlobAllocator(const VulkanDevice* vkdev, size_t preferred_block_size = 16 * 1024 * 1024); // 16M + virtual ~VkBlobAllocator(); + +public: + // release all budgets immediately + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkBlobAllocator(const VkBlobAllocator&); + VkBlobAllocator& operator=(const VkBlobAllocator&); + +private: + VkBlobAllocatorPrivate* const d; +}; + +class VkWeightAllocatorPrivate; +class NCNN_EXPORT VkWeightAllocator : public VkAllocator +{ +public: + explicit VkWeightAllocator(const VulkanDevice* vkdev, size_t preferred_block_size = 8 * 1024 * 1024); // 8M + virtual ~VkWeightAllocator(); + +public: + // release all blocks immediately + virtual void clear(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkWeightAllocator(const VkWeightAllocator&); + VkWeightAllocator& operator=(const VkWeightAllocator&); + +private: + VkWeightAllocatorPrivate* const d; +}; + +class VkStagingAllocatorPrivate; +class NCNN_EXPORT VkStagingAllocator : public VkAllocator +{ +public: + explicit VkStagingAllocator(const VulkanDevice* vkdev); + virtual ~VkStagingAllocator(); + +public: + // ratio range 0 ~ 1 + // default cr = 0.75 + void set_size_compare_ratio(float scr); + + // release all budgets immediately + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkStagingAllocator(const VkStagingAllocator&); + VkStagingAllocator& operator=(const VkStagingAllocator&); + +private: + VkStagingAllocatorPrivate* const d; +}; + +class VkWeightStagingAllocatorPrivate; +class NCNN_EXPORT VkWeightStagingAllocator : public VkAllocator +{ +public: + explicit VkWeightStagingAllocator(const VulkanDevice* vkdev); + virtual ~VkWeightStagingAllocator(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkWeightStagingAllocator(const VkWeightStagingAllocator&); + VkWeightStagingAllocator& operator=(const VkWeightStagingAllocator&); + +private: + VkWeightStagingAllocatorPrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class NCNN_EXPORT VkAndroidHardwareBufferImageAllocator : public VkAllocator +{ +public: + VkAndroidHardwareBufferImageAllocator(const VulkanDevice* _vkdev, AHardwareBuffer* _hb); + virtual ~VkAndroidHardwareBufferImageAllocator(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkAndroidHardwareBufferImageAllocator(const VkAndroidHardwareBufferImageAllocator&); + VkAndroidHardwareBufferImageAllocator& operator=(const VkAndroidHardwareBufferImageAllocator&); + +public: + int init(); + + int width() const; + int height() const; + uint64_t external_format() const; + +public: + AHardwareBuffer* hb; + AHardwareBuffer_Desc bufferDesc; + VkAndroidHardwareBufferFormatPropertiesANDROID bufferFormatProperties; + VkAndroidHardwareBufferPropertiesANDROID bufferProperties; + VkSamplerYcbcrConversionKHR samplerYcbcrConversion; +}; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_ALLOCATOR_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/benchmark.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/benchmark.h new file mode 100644 index 0000000..3d5c0cd --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/benchmark.h @@ -0,0 +1,36 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_BENCHMARK_H +#define NCNN_BENCHMARK_H + +#include "layer.h" +#include "mat.h" +#include "platform.h" + +namespace ncnn { + +// get now timestamp in ms +NCNN_EXPORT double get_current_time(); + +#if NCNN_BENCHMARK + +NCNN_EXPORT void benchmark(const Layer* layer, double start, double end); +NCNN_EXPORT void benchmark(const Layer* layer, const Mat& bottom_blob, Mat& top_blob, double start, double end); + +#endif // NCNN_BENCHMARK + +} // namespace ncnn + +#endif // NCNN_BENCHMARK_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/blob.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/blob.h new file mode 100644 index 0000000..c9f144f --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/blob.h @@ -0,0 +1,44 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_BLOB_H +#define NCNN_BLOB_H + +#include "mat.h" +#include "platform.h" + +namespace ncnn { + +class NCNN_EXPORT Blob +{ +public: + // empty + Blob(); + +public: +#if NCNN_STRING + // blob name + std::string name; +#endif // NCNN_STRING + // layer index which produce this blob as output + int producer; + // layer index which need this blob as input + int consumer; + // shape hint + Mat shape; +}; + +} // namespace ncnn + +#endif // NCNN_BLOB_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/c_api.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/c_api.h new file mode 100644 index 0000000..b7435f8 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/c_api.h @@ -0,0 +1,327 @@ +/* Tencent is pleased to support the open source community by making ncnn available. + * + * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef NCNN_C_API_H +#define NCNN_C_API_H + +#include "platform.h" + +#if NCNN_C_API + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +NCNN_EXPORT const char* ncnn_version(); + +/* allocator api */ +typedef struct __ncnn_allocator_t* ncnn_allocator_t; +struct NCNN_EXPORT __ncnn_allocator_t +{ + void* pthis; + + void* (*fast_malloc)(ncnn_allocator_t allocator, size_t size); + void (*fast_free)(ncnn_allocator_t allocator, void* ptr); +}; + +NCNN_EXPORT ncnn_allocator_t ncnn_allocator_create_pool_allocator(); +NCNN_EXPORT ncnn_allocator_t ncnn_allocator_create_unlocked_pool_allocator(); +NCNN_EXPORT void ncnn_allocator_destroy(ncnn_allocator_t allocator); + +/* option api */ +typedef struct __ncnn_option_t* ncnn_option_t; + +NCNN_EXPORT ncnn_option_t ncnn_option_create(); +NCNN_EXPORT void ncnn_option_destroy(ncnn_option_t opt); + +NCNN_EXPORT int ncnn_option_get_num_threads(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_num_threads(ncnn_option_t opt, int num_threads); + +NCNN_EXPORT int ncnn_option_get_use_local_pool_allocator(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_use_local_pool_allocator(ncnn_option_t opt, int use_local_pool_allocator); + +NCNN_EXPORT void ncnn_option_set_blob_allocator(ncnn_option_t opt, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_option_set_workspace_allocator(ncnn_option_t opt, ncnn_allocator_t allocator); + +NCNN_EXPORT int ncnn_option_get_use_vulkan_compute(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_use_vulkan_compute(ncnn_option_t opt, int use_vulkan_compute); + +/* mat api */ +typedef struct __ncnn_mat_t* ncnn_mat_t; + +NCNN_EXPORT ncnn_mat_t ncnn_mat_create(); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_1d(int w, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_2d(int w, int h, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_3d(int w, int h, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_4d(int w, int h, int d, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_1d(int w, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_2d(int w, int h, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_3d(int w, int h, int c, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_4d(int w, int h, int d, int c, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_1d_elem(int w, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_2d_elem(int w, int h, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_3d_elem(int w, int h, int c, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_4d_elem(int w, int h, int d, int c, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_1d_elem(int w, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_2d_elem(int w, int h, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_3d_elem(int w, int h, int c, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_4d_elem(int w, int h, int d, int c, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_mat_destroy(ncnn_mat_t mat); + +NCNN_EXPORT void ncnn_mat_fill_float(ncnn_mat_t mat, float v); + +NCNN_EXPORT ncnn_mat_t ncnn_mat_clone(const ncnn_mat_t mat, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_1d(const ncnn_mat_t mat, int w, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_2d(const ncnn_mat_t mat, int w, int h, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_3d(const ncnn_mat_t mat, int w, int h, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_4d(const ncnn_mat_t mat, int w, int h, int d, int c, ncnn_allocator_t allocator); + +NCNN_EXPORT int ncnn_mat_get_dims(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_w(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_h(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_d(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_c(const ncnn_mat_t mat); +NCNN_EXPORT size_t ncnn_mat_get_elemsize(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_elempack(const ncnn_mat_t mat); +NCNN_EXPORT size_t ncnn_mat_get_cstep(const ncnn_mat_t mat); +NCNN_EXPORT void* ncnn_mat_get_data(const ncnn_mat_t mat); + +NCNN_EXPORT void* ncnn_mat_get_channel_data(const ncnn_mat_t mat, int c); + +#if NCNN_PIXEL + +/* mat pixel api */ +#define NCNN_MAT_PIXEL_RGB 1 +#define NCNN_MAT_PIXEL_BGR 2 +#define NCNN_MAT_PIXEL_GRAY 3 +#define NCNN_MAT_PIXEL_RGBA 4 +#define NCNN_MAT_PIXEL_BGRA 5 +#define NCNN_MAT_PIXEL_X2Y(X, Y) (X | (Y << 16)) +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels(const unsigned char* pixels, int type, int w, int h, int stride, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, int target_width, int target_height, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_mat_to_pixels(const ncnn_mat_t mat, unsigned char* pixels, int type, int stride); +NCNN_EXPORT void ncnn_mat_to_pixels_resize(const ncnn_mat_t mat, unsigned char* pixels, int type, int target_width, int target_height, int target_stride); + +#endif /* NCNN_PIXEL */ + +NCNN_EXPORT void ncnn_mat_substract_mean_normalize(ncnn_mat_t mat, const float* mean_vals, const float* norm_vals); + +NCNN_EXPORT void ncnn_convert_packing(const ncnn_mat_t src, ncnn_mat_t* dst, int elempack, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_flatten(const ncnn_mat_t src, ncnn_mat_t* dst, const ncnn_option_t opt); + +/* blob api */ +typedef struct __ncnn_blob_t* ncnn_blob_t; + +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_blob_get_name(const ncnn_blob_t blob); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_blob_get_producer(const ncnn_blob_t blob); +NCNN_EXPORT int ncnn_blob_get_consumer(const ncnn_blob_t blob); + +NCNN_EXPORT void ncnn_blob_get_shape(const ncnn_blob_t blob, int* dims, int* w, int* h, int* c); + +/* paramdict api */ +typedef struct __ncnn_paramdict_t* ncnn_paramdict_t; + +NCNN_EXPORT ncnn_paramdict_t ncnn_paramdict_create(); +NCNN_EXPORT void ncnn_paramdict_destroy(ncnn_paramdict_t pd); + +NCNN_EXPORT int ncnn_paramdict_get_type(const ncnn_paramdict_t pd, int id); + +NCNN_EXPORT int ncnn_paramdict_get_int(const ncnn_paramdict_t pd, int id, int def); +NCNN_EXPORT float ncnn_paramdict_get_float(const ncnn_paramdict_t pd, int id, float def); +NCNN_EXPORT ncnn_mat_t ncnn_paramdict_get_array(const ncnn_paramdict_t pd, int id, const ncnn_mat_t def); + +NCNN_EXPORT void ncnn_paramdict_set_int(ncnn_paramdict_t pd, int id, int i); +NCNN_EXPORT void ncnn_paramdict_set_float(ncnn_paramdict_t pd, int id, float f); +NCNN_EXPORT void ncnn_paramdict_set_array(ncnn_paramdict_t pd, int id, const ncnn_mat_t v); + +/* datareader api */ +typedef struct __ncnn_datareader_t* ncnn_datareader_t; +struct NCNN_EXPORT __ncnn_datareader_t +{ + void* pthis; + +#if NCNN_STRING + int (*scan)(ncnn_datareader_t dr, const char* format, void* p); +#endif /* NCNN_STRING */ + size_t (*read)(ncnn_datareader_t dr, void* buf, size_t size); +}; + +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create(); +#if NCNN_STDIO +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create_from_stdio(FILE* fp); +#endif /* NCNN_STDIO */ +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create_from_memory(const unsigned char** mem); +NCNN_EXPORT void ncnn_datareader_destroy(ncnn_datareader_t dr); + +/* modelbin api */ +typedef struct __ncnn_modelbin_t* ncnn_modelbin_t; +struct NCNN_EXPORT __ncnn_modelbin_t +{ + void* pthis; + + ncnn_mat_t (*load_1d)(const ncnn_modelbin_t mb, int w, int type); + ncnn_mat_t (*load_2d)(const ncnn_modelbin_t mb, int w, int h, int type); + ncnn_mat_t (*load_3d)(const ncnn_modelbin_t mb, int w, int h, int c, int type); +}; + +NCNN_EXPORT ncnn_modelbin_t ncnn_modelbin_create_from_datareader(const ncnn_datareader_t dr); +NCNN_EXPORT ncnn_modelbin_t ncnn_modelbin_create_from_mat_array(const ncnn_mat_t* weights, int n); +NCNN_EXPORT void ncnn_modelbin_destroy(ncnn_modelbin_t mb); + +/* layer api */ +typedef struct __ncnn_layer_t* ncnn_layer_t; +struct NCNN_EXPORT __ncnn_layer_t +{ + void* pthis; + + int (*load_param)(ncnn_layer_t layer, const ncnn_paramdict_t pd); + int (*load_model)(ncnn_layer_t layer, const ncnn_modelbin_t mb); + + int (*create_pipeline)(ncnn_layer_t layer, const ncnn_option_t opt); + int (*destroy_pipeline)(ncnn_layer_t layer, const ncnn_option_t opt); + + int (*forward_1)(const ncnn_layer_t layer, const ncnn_mat_t bottom_blob, ncnn_mat_t* top_blob, const ncnn_option_t opt); + int (*forward_n)(const ncnn_layer_t layer, const ncnn_mat_t* bottom_blobs, int n, ncnn_mat_t* top_blobs, int n2, const ncnn_option_t opt); + + int (*forward_inplace_1)(const ncnn_layer_t layer, ncnn_mat_t bottom_top_blob, const ncnn_option_t opt); + int (*forward_inplace_n)(const ncnn_layer_t layer, ncnn_mat_t* bottom_top_blobs, int n, const ncnn_option_t opt); +}; + +NCNN_EXPORT ncnn_layer_t ncnn_layer_create(); +NCNN_EXPORT ncnn_layer_t ncnn_layer_create_by_typeindex(int typeindex); +#if NCNN_STRING +NCNN_EXPORT ncnn_layer_t ncnn_layer_create_by_type(const char* type); +#endif /* NCNN_STRING */ +NCNN_EXPORT void ncnn_layer_destroy(ncnn_layer_t layer); + +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_layer_get_name(const ncnn_layer_t layer); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_layer_get_typeindex(const ncnn_layer_t layer); +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_layer_get_type(const ncnn_layer_t layer); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_layer_get_one_blob_only(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_inplace(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_vulkan(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_packing(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_bf16_storage(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_fp16_storage(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_image_storage(const ncnn_layer_t layer); + +NCNN_EXPORT void ncnn_layer_set_one_blob_only(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_inplace(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_vulkan(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_packing(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_bf16_storage(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_fp16_storage(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_image_storage(ncnn_layer_t layer, int enable); + +NCNN_EXPORT int ncnn_layer_get_bottom_count(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_bottom(const ncnn_layer_t layer, int i); +NCNN_EXPORT int ncnn_layer_get_top_count(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_top(const ncnn_layer_t layer, int i); + +NCNN_EXPORT void ncnn_blob_get_bottom_shape(const ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c); +NCNN_EXPORT void ncnn_blob_get_top_shape(const ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c); + +/* layer factory function */ +typedef ncnn_layer_t (*ncnn_layer_creator_t)(void* userdata); +typedef void (*ncnn_layer_destroyer_t)(ncnn_layer_t layer, void* userdata); + +typedef struct __ncnn_net_custom_layer_factory_t* ncnn_net_custom_layer_factory_t; +struct __ncnn_net_custom_layer_factory_t +{ + ncnn_layer_creator_t creator; + ncnn_layer_destroyer_t destroyer; + void* userdata; + ncnn_net_custom_layer_factory_t next; +}; + +/* net api */ +typedef struct __ncnn_net_t* ncnn_net_t; +struct __ncnn_net_t +{ + void* pthis; + + ncnn_net_custom_layer_factory_t custom_layer_factory; +}; + +NCNN_EXPORT ncnn_net_t ncnn_net_create(); +NCNN_EXPORT void ncnn_net_destroy(ncnn_net_t net); + +NCNN_EXPORT ncnn_option_t ncnn_net_get_option(ncnn_net_t net); +NCNN_EXPORT void ncnn_net_set_option(ncnn_net_t net, ncnn_option_t opt); + +#if NCNN_STRING +NCNN_EXPORT void ncnn_net_register_custom_layer_by_type(ncnn_net_t net, const char* type, ncnn_layer_creator_t creator, ncnn_layer_destroyer_t destroyer, void* userdata); +#endif /* NCNN_STRING */ +NCNN_EXPORT void ncnn_net_register_custom_layer_by_typeindex(ncnn_net_t net, int typeindex, ncnn_layer_creator_t creator, ncnn_layer_destroyer_t destroyer, void* userdata); + +#if NCNN_STDIO +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param(ncnn_net_t net, const char* path); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_load_param_bin(ncnn_net_t net, const char* path); +NCNN_EXPORT int ncnn_net_load_model(ncnn_net_t net, const char* path); +#endif /* NCNN_STDIO */ + +#if NCNN_STDIO +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param_memory(ncnn_net_t net, const char* mem); +#endif /* NCNN_STRING */ +#endif /* NCNN_STDIO */ +NCNN_EXPORT int ncnn_net_load_param_bin_memory(ncnn_net_t net, const unsigned char* mem); +NCNN_EXPORT int ncnn_net_load_model_memory(ncnn_net_t net, const unsigned char* mem); + +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param_datareader(ncnn_net_t net, const ncnn_datareader_t dr); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_load_param_bin_datareader(ncnn_net_t net, const ncnn_datareader_t dr); +NCNN_EXPORT int ncnn_net_load_model_datareader(ncnn_net_t net, const ncnn_datareader_t dr); + +NCNN_EXPORT void ncnn_net_clear(ncnn_net_t net); + +/* extractor api */ +typedef struct __ncnn_extractor_t* ncnn_extractor_t; + +NCNN_EXPORT ncnn_extractor_t ncnn_extractor_create(ncnn_net_t net); +NCNN_EXPORT void ncnn_extractor_destroy(ncnn_extractor_t ex); + +NCNN_EXPORT void ncnn_extractor_set_option(ncnn_extractor_t ex, const ncnn_option_t opt); + +#if NCNN_STRING +NCNN_EXPORT int ncnn_extractor_input(ncnn_extractor_t ex, const char* name, const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_extractor_extract(ncnn_extractor_t ex, const char* name, ncnn_mat_t* mat); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_extractor_input_index(ncnn_extractor_t ex, int index, const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_extractor_extract_index(ncnn_extractor_t ex, int index, ncnn_mat_t* mat); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* NCNN_C_API */ + +#endif /* NCNN_C_API_H */ diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/command.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/command.h new file mode 100644 index 0000000..337d085 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/command.h @@ -0,0 +1,136 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_COMMAND_H +#define NCNN_COMMAND_H + +#include "platform.h" + +#if NCNN_VULKAN + +#include "mat.h" + +#include + +namespace ncnn { + +class Pipeline; +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class ImportAndroidHardwareBufferPipeline; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API +class VkComputePrivate; +class NCNN_EXPORT VkCompute +{ +public: + explicit VkCompute(const VulkanDevice* vkdev); + virtual ~VkCompute(); + +public: + void record_upload(const Mat& src, VkMat& dst, const Option& opt); + + void record_upload(const Mat& src, VkImageMat& dst, const Option& opt); + + void record_download(const VkMat& src, Mat& dst, const Option& opt); + + void record_download(const VkImageMat& src, Mat& dst, const Option& opt); + + void record_buffer_to_image(const VkMat& src, VkImageMat& dst, const Option& opt); + + void record_image_to_buffer(const VkImageMat& src, VkMat& dst, const Option& opt); + + void record_clone(const Mat& src, VkMat& dst, const Option& opt); + + void record_clone(const Mat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkMat& src, Mat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, Mat& dst, const Option& opt); + + void record_clone(const VkMat& src, VkMat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkMat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, VkMat& dst, const Option& opt); + + void record_pipeline(const Pipeline* pipeline, const std::vector& bindings, const std::vector& constants, const VkMat& dispatcher); + + void record_pipeline(const Pipeline* pipeline, const std::vector& bindings, const std::vector& constants, const VkImageMat& dispatcher); + + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const VkMat& dispatcher); + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const VkImageMat& dispatcher); + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const Mat& dispatcher); + +#if NCNN_BENCHMARK + void record_write_timestamp(uint32_t query); +#endif // NCNN_BENCHMARK + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 + void record_import_android_hardware_buffer(const ImportAndroidHardwareBufferPipeline* pipeline, const VkImageMat& src, const VkMat& dst); + + void record_import_android_hardware_buffer(const ImportAndroidHardwareBufferPipeline* pipeline, const VkImageMat& src, const VkImageMat& dst); +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + + int submit_and_wait(); + + int reset(); + +#if NCNN_BENCHMARK + int create_query_pool(uint32_t query_count); + + int get_query_pool_results(uint32_t first_query, uint32_t query_count, std::vector& results); +#endif // NCNN_BENCHMARK + +protected: + const VulkanDevice* vkdev; + + void barrier_readwrite(const VkMat& binding); + void barrier_readwrite(const VkImageMat& binding); + void barrier_readonly(const VkImageMat& binding); + +private: + VkComputePrivate* const d; +}; + +class VkTransferPrivate; +class NCNN_EXPORT VkTransfer +{ +public: + explicit VkTransfer(const VulkanDevice* vkdev); + virtual ~VkTransfer(); + +public: + void record_upload(const Mat& src, VkMat& dst, const Option& opt, bool flatten = true); + + void record_upload(const Mat& src, VkImageMat& dst, const Option& opt); + + int submit_and_wait(); + +protected: + const VulkanDevice* vkdev; + +private: + VkTransferPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_VULKAN + +#endif // NCNN_COMMAND_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/cpu.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/cpu.h new file mode 100644 index 0000000..0f748f3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/cpu.h @@ -0,0 +1,169 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_CPU_H +#define NCNN_CPU_H + +#include + +#if (defined _WIN32 && !(defined __MINGW32__)) +#define WIN32_LEAN_AND_MEAN +#include +#endif +#if defined __ANDROID__ || defined __linux__ +#include // cpu_set_t +#endif + +#include "platform.h" + +namespace ncnn { + +class NCNN_EXPORT CpuSet +{ +public: + CpuSet(); + void enable(int cpu); + void disable(int cpu); + void disable_all(); + bool is_enabled(int cpu) const; + int num_enabled() const; + +public: +#if (defined _WIN32 && !(defined __MINGW32__)) + ULONG_PTR mask; +#endif +#if defined __ANDROID__ || defined __linux__ + cpu_set_t cpu_set; +#endif +#if __APPLE__ + unsigned int policy; +#endif +}; + +// test optional cpu features +// edsp = armv7 edsp +NCNN_EXPORT int cpu_support_arm_edsp(); +// neon = armv7 neon or aarch64 asimd +NCNN_EXPORT int cpu_support_arm_neon(); +// vfpv4 = armv7 fp16 + fma +NCNN_EXPORT int cpu_support_arm_vfpv4(); +// asimdhp = aarch64 asimd half precision +NCNN_EXPORT int cpu_support_arm_asimdhp(); +// asimddp = aarch64 asimd dot product +NCNN_EXPORT int cpu_support_arm_asimddp(); +// asimdfhm = aarch64 asimd fhm +NCNN_EXPORT int cpu_support_arm_asimdfhm(); +// bf16 = aarch64 bf16 +NCNN_EXPORT int cpu_support_arm_bf16(); +// i8mm = aarch64 i8mm +NCNN_EXPORT int cpu_support_arm_i8mm(); +// sve = aarch64 sve +NCNN_EXPORT int cpu_support_arm_sve(); +// sve2 = aarch64 sve2 +NCNN_EXPORT int cpu_support_arm_sve2(); +// svebf16 = aarch64 svebf16 +NCNN_EXPORT int cpu_support_arm_svebf16(); +// svei8mm = aarch64 svei8mm +NCNN_EXPORT int cpu_support_arm_svei8mm(); +// svef32mm = aarch64 svef32mm +NCNN_EXPORT int cpu_support_arm_svef32mm(); + +// avx = x86 avx +NCNN_EXPORT int cpu_support_x86_avx(); +// fma = x86 fma +NCNN_EXPORT int cpu_support_x86_fma(); +// xop = x86 xop +NCNN_EXPORT int cpu_support_x86_xop(); +// f16c = x86 f16c +NCNN_EXPORT int cpu_support_x86_f16c(); +// avx2 = x86 avx2 + fma + f16c +NCNN_EXPORT int cpu_support_x86_avx2(); +// avx_vnni = x86 avx vnni +NCNN_EXPORT int cpu_support_x86_avx_vnni(); +// avx512 = x86 avx512f + avx512cd + avx512bw + avx512dq + avx512vl +NCNN_EXPORT int cpu_support_x86_avx512(); +// avx512_vnni = x86 avx512 vnni +NCNN_EXPORT int cpu_support_x86_avx512_vnni(); +// avx512_bf16 = x86 avx512 bf16 +NCNN_EXPORT int cpu_support_x86_avx512_bf16(); +// avx512_fp16 = x86 avx512 fp16 +NCNN_EXPORT int cpu_support_x86_avx512_fp16(); + +// lsx = loongarch lsx +NCNN_EXPORT int cpu_support_loongarch_lsx(); +// lasx = loongarch lasx +NCNN_EXPORT int cpu_support_loongarch_lasx(); + +// msa = mips mas +NCNN_EXPORT int cpu_support_mips_msa(); +// mmi = loongson mmi +NCNN_EXPORT int cpu_support_loongson_mmi(); + +// v = riscv vector +NCNN_EXPORT int cpu_support_riscv_v(); +// zfh = riscv half-precision float +NCNN_EXPORT int cpu_support_riscv_zfh(); +// vlenb = riscv vector length in bytes +NCNN_EXPORT int cpu_riscv_vlenb(); + +// cpu info +NCNN_EXPORT int get_cpu_count(); +NCNN_EXPORT int get_little_cpu_count(); +NCNN_EXPORT int get_big_cpu_count(); + +NCNN_EXPORT int get_physical_cpu_count(); +NCNN_EXPORT int get_physical_little_cpu_count(); +NCNN_EXPORT int get_physical_big_cpu_count(); + +// bind all threads on little clusters if powersave enabled +// affects HMP arch cpu like ARM big.LITTLE +// only implemented on android at the moment +// switching powersave is expensive and not thread-safe +// 0 = all cores enabled(default) +// 1 = only little clusters enabled +// 2 = only big clusters enabled +// return 0 if success for setter function +NCNN_EXPORT int get_cpu_powersave(); +NCNN_EXPORT int set_cpu_powersave(int powersave); + +// convenient wrapper +NCNN_EXPORT const CpuSet& get_cpu_thread_affinity_mask(int powersave); + +// set explicit thread affinity +NCNN_EXPORT int set_cpu_thread_affinity(const CpuSet& thread_affinity_mask); + +// misc function wrapper for openmp routines +NCNN_EXPORT int get_omp_num_threads(); +NCNN_EXPORT void set_omp_num_threads(int num_threads); + +NCNN_EXPORT int get_omp_dynamic(); +NCNN_EXPORT void set_omp_dynamic(int dynamic); + +NCNN_EXPORT int get_omp_thread_num(); + +NCNN_EXPORT int get_kmp_blocktime(); +NCNN_EXPORT void set_kmp_blocktime(int time_ms); + +// need to flush denormals on Intel Chipset. +// Other architectures such as ARM can be added as needed. +// 0 = DAZ OFF, FTZ OFF +// 1 = DAZ ON , FTZ OFF +// 2 = DAZ OFF, FTZ ON +// 3 = DAZ ON, FTZ ON +NCNN_EXPORT int get_flush_denormals(); +NCNN_EXPORT int set_flush_denormals(int flush_denormals); + +} // namespace ncnn + +#endif // NCNN_CPU_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/datareader.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/datareader.h new file mode 100644 index 0000000..ed2aba3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/datareader.h @@ -0,0 +1,122 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_DATAREADER_H +#define NCNN_DATAREADER_H + +#include "platform.h" +#if NCNN_STDIO +#include +#endif + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#endif +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +// data read wrapper +class NCNN_EXPORT DataReader +{ +public: + DataReader(); + virtual ~DataReader(); + +#if NCNN_STRING + // parse plain param text + // return 1 if scan success + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + + // read binary param and model data + // return bytes read + virtual size_t read(void* buf, size_t size) const; + + // get model data reference + // return bytes referenced + virtual size_t reference(size_t size, const void** buf) const; +}; + +#if NCNN_STDIO +class DataReaderFromStdioPrivate; +class NCNN_EXPORT DataReaderFromStdio : public DataReader +{ +public: + explicit DataReaderFromStdio(FILE* fp); + virtual ~DataReaderFromStdio(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + +private: + DataReaderFromStdio(const DataReaderFromStdio&); + DataReaderFromStdio& operator=(const DataReaderFromStdio&); + +private: + DataReaderFromStdioPrivate* const d; +}; +#endif // NCNN_STDIO + +class DataReaderFromMemoryPrivate; +class NCNN_EXPORT DataReaderFromMemory : public DataReader +{ +public: + explicit DataReaderFromMemory(const unsigned char*& mem); + virtual ~DataReaderFromMemory(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + virtual size_t reference(size_t size, const void** buf) const; + +private: + DataReaderFromMemory(const DataReaderFromMemory&); + DataReaderFromMemory& operator=(const DataReaderFromMemory&); + +private: + DataReaderFromMemoryPrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +class DataReaderFromAndroidAssetPrivate; +class NCNN_EXPORT DataReaderFromAndroidAsset : public DataReader +{ +public: + explicit DataReaderFromAndroidAsset(AAsset* asset); + virtual ~DataReaderFromAndroidAsset(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + +private: + DataReaderFromAndroidAsset(const DataReaderFromAndroidAsset&); + DataReaderFromAndroidAsset& operator=(const DataReaderFromAndroidAsset&); + +private: + DataReaderFromAndroidAssetPrivate* const d; +}; +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + +} // namespace ncnn + +#endif // NCNN_DATAREADER_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/gpu.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/gpu.h new file mode 100644 index 0000000..2ef4927 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/gpu.h @@ -0,0 +1,359 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_GPU_H +#define NCNN_GPU_H + +#include "platform.h" + +#if NCNN_VULKAN + +#include "mat.h" + +#include + +#include "vulkan_header_fix.h" + +namespace ncnn { + +// instance +NCNN_EXPORT int create_gpu_instance(); +NCNN_EXPORT void destroy_gpu_instance(); + +// instance extension capability +extern int support_VK_KHR_external_memory_capabilities; +extern int support_VK_KHR_get_physical_device_properties2; +extern int support_VK_KHR_get_surface_capabilities2; +extern int support_VK_KHR_surface; +extern int support_VK_EXT_debug_utils; +#if __ANDROID_API__ >= 26 +extern int support_VK_KHR_android_surface; +#endif // __ANDROID_API__ >= 26 + +// VK_KHR_external_memory_capabilities +extern PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR vkGetPhysicalDeviceExternalBufferPropertiesKHR; + +// VK_KHR_get_physical_device_properties2 +extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; +extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; +extern PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceImageFormatProperties2KHR vkGetPhysicalDeviceImageFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR; +extern PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR; +extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR vkGetPhysicalDeviceSparseImageFormatProperties2KHR; + +// VK_KHR_get_surface_capabilities2 +extern PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR; + +// VK_KHR_surface +extern PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; +extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; +extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; +extern PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; + +#if __ANDROID_API__ >= 26 +// VK_KHR_android_surface +extern PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; +#endif // __ANDROID_API__ >= 26 + +// VK_NV_cooperative_matrix +extern PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV vkGetPhysicalDeviceCooperativeMatrixPropertiesNV; + +// get info +NCNN_EXPORT int get_gpu_count(); +NCNN_EXPORT int get_default_gpu_index(); + +class GpuInfoPrivate; +class NCNN_EXPORT GpuInfo +{ +public: + explicit GpuInfo(); + virtual ~GpuInfo(); + + // vulkan physical device + VkPhysicalDevice physical_device() const; + + // memory properties + const VkPhysicalDeviceMemoryProperties& physical_device_memory_properties() const; + + // info + uint32_t api_version() const; + uint32_t driver_version() const; + uint32_t vendor_id() const; + uint32_t device_id() const; + const char* device_name() const; + uint8_t* pipeline_cache_uuid() const; + + // 0 = discrete gpu + // 1 = integrated gpu + // 2 = virtual gpu + // 3 = cpu + int type() const; + + // hardware limit + uint32_t max_shared_memory_size() const; + uint32_t max_workgroup_count_x() const; + uint32_t max_workgroup_count_y() const; + uint32_t max_workgroup_count_z() const; + uint32_t max_workgroup_invocations() const; + uint32_t max_workgroup_size_x() const; + uint32_t max_workgroup_size_y() const; + uint32_t max_workgroup_size_z() const; + size_t memory_map_alignment() const; + size_t buffer_offset_alignment() const; + size_t non_coherent_atom_size() const; + size_t buffer_image_granularity() const; + uint32_t max_image_dimension_1d() const; + uint32_t max_image_dimension_2d() const; + uint32_t max_image_dimension_3d() const; + float timestamp_period() const; + + // runtime + uint32_t compute_queue_family_index() const; + uint32_t graphics_queue_family_index() const; + uint32_t transfer_queue_family_index() const; + + uint32_t compute_queue_count() const; + uint32_t graphics_queue_count() const; + uint32_t transfer_queue_count() const; + + // property + bool unified_compute_transfer_queue() const; + + // subgroup + uint32_t subgroup_size() const; + bool support_subgroup_basic() const; + bool support_subgroup_vote() const; + bool support_subgroup_ballot() const; + bool support_subgroup_shuffle() const; + + // bug is not feature + bool bug_storage_buffer_no_l1() const; + bool bug_corrupted_online_pipeline_cache() const; + bool bug_buffer_image_load_zero() const; + + // but sometimes bug is a feature + bool bug_implicit_fp16_arithmetic() const; + + // fp16 and int8 feature + bool support_fp16_packed() const; + bool support_fp16_storage() const; + bool support_fp16_arithmetic() const; + bool support_int8_packed() const; + bool support_int8_storage() const; + bool support_int8_arithmetic() const; + + // ycbcr conversion feature + bool support_ycbcr_conversion() const; + + // cooperative matrix feature + bool support_cooperative_matrix() const; + bool support_cooperative_matrix_16_8_8() const; + + // extension capability + int support_VK_KHR_8bit_storage() const; + int support_VK_KHR_16bit_storage() const; + int support_VK_KHR_bind_memory2() const; + int support_VK_KHR_create_renderpass2() const; + int support_VK_KHR_dedicated_allocation() const; + int support_VK_KHR_descriptor_update_template() const; + int support_VK_KHR_external_memory() const; + int support_VK_KHR_get_memory_requirements2() const; + int support_VK_KHR_maintenance1() const; + int support_VK_KHR_maintenance2() const; + int support_VK_KHR_maintenance3() const; + int support_VK_KHR_multiview() const; + int support_VK_KHR_push_descriptor() const; + int support_VK_KHR_sampler_ycbcr_conversion() const; + int support_VK_KHR_shader_float16_int8() const; + int support_VK_KHR_shader_float_controls() const; + int support_VK_KHR_storage_buffer_storage_class() const; + int support_VK_KHR_swapchain() const; + int support_VK_EXT_descriptor_indexing() const; + int support_VK_EXT_memory_budget() const; + int support_VK_EXT_queue_family_foreign() const; +#if __ANDROID_API__ >= 26 + int support_VK_ANDROID_external_memory_android_hardware_buffer() const; +#endif // __ANDROID_API__ >= 26 + int support_VK_NV_cooperative_matrix() const; + +private: + GpuInfo(const GpuInfo&); + GpuInfo& operator=(const GpuInfo&); + +private: + friend int create_gpu_instance(); + GpuInfoPrivate* const d; +}; + +NCNN_EXPORT const GpuInfo& get_gpu_info(int device_index = get_default_gpu_index()); + +class VkAllocator; +class VkCompute; +class Option; +class PipelineCache; +class VulkanDevicePrivate; +class NCNN_EXPORT VulkanDevice +{ +public: + VulkanDevice(int device_index = get_default_gpu_index()); + ~VulkanDevice(); + + const GpuInfo& info; + + VkDevice vkdevice() const; + + VkShaderModule compile_shader_module(const uint32_t* spv_data, size_t spv_data_size) const; + + // with fixed workgroup size + VkShaderModule compile_shader_module(const uint32_t* spv_data, size_t spv_data_size, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z) const; + + // helper for creating pipeline + int create_descriptorset_layout(int binding_count, const int* binding_types, VkDescriptorSetLayout* descriptorset_layout) const; + int create_pipeline_layout(int push_constant_count, VkDescriptorSetLayout descriptorset_layout, VkPipelineLayout* pipeline_layout) const; + int create_pipeline(VkShaderModule shader_module, VkPipelineLayout pipeline_layout, const std::vector& specializations, VkPipeline* pipeline) const; + int create_descriptor_update_template(int binding_count, const int* binding_types, VkDescriptorSetLayout descriptorset_layout, VkPipelineLayout pipeline_layout, VkDescriptorUpdateTemplateKHR* descriptor_update_template) const; + + uint32_t find_memory_index(uint32_t memory_type_bits, VkFlags required, VkFlags preferred, VkFlags preferred_not) const; + bool is_mappable(uint32_t memory_type_index) const; + bool is_coherent(uint32_t memory_type_index) const; + + VkQueue acquire_queue(uint32_t queue_family_index) const; + void reclaim_queue(uint32_t queue_family_index, VkQueue queue) const; + + // allocator on this device + VkAllocator* acquire_blob_allocator() const; + void reclaim_blob_allocator(VkAllocator* allocator) const; + + VkAllocator* acquire_staging_allocator() const; + void reclaim_staging_allocator(VkAllocator* allocator) const; + + // immutable sampler for texelfetch + const VkSampler* immutable_texelfetch_sampler() const; + + // dummy buffer image + VkMat get_dummy_buffer() const; + VkImageMat get_dummy_image() const; + VkImageMat get_dummy_image_readonly() const; + + // pipeline cache on this device + const PipelineCache* get_pipeline_cache() const; + + // test image allocation + bool shape_support_image_storage(const Mat& shape) const; + + // current gpu heap memory budget in MB + uint32_t get_heap_budget() const; + + // utility operator + void convert_packing(const VkMat& src, VkMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkImageMat& src, VkImageMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkMat& src, VkImageMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkImageMat& src, VkMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + + // VK_KHR_bind_memory2 + PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; + PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; + + // VK_KHR_create_renderpass2 + PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; + PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; + PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; + + // VK_KHR_descriptor_update_template + PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; + PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; + PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; + + // VK_KHR_get_memory_requirements2 + PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; + PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; + PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; + + // VK_KHR_maintenance1 + PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; + + // VK_KHR_maintenance3 + PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; + + // VK_KHR_push_descriptor + PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; + PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; + + // VK_KHR_sampler_ycbcr_conversion + PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; + PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; + + // VK_KHR_swapchain + PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; + PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; + PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; + PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; + PFN_vkQueuePresentKHR vkQueuePresentKHR; + +#if __ANDROID_API__ >= 26 + // VK_ANDROID_external_memory_android_hardware_buffer + PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; + PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; +#endif // __ANDROID_API__ >= 26 + +protected: + // device extension + int init_device_extension(); + +private: + VulkanDevice(const VulkanDevice&); + VulkanDevice& operator=(const VulkanDevice&); + +private: + VulkanDevicePrivate* const d; +}; + +NCNN_EXPORT VulkanDevice* get_gpu_device(int device_index = get_default_gpu_index()); + +// online spirv compilation +NCNN_EXPORT int compile_spirv_module(const char* comp_string, const Option& opt, std::vector& spirv); +NCNN_EXPORT int compile_spirv_module(const char* comp_data, int comp_data_size, const Option& opt, std::vector& spirv); +NCNN_EXPORT int compile_spirv_module(int shader_type_index, const Option& opt, std::vector& spirv); + +// info from spirv +class NCNN_EXPORT ShaderInfo +{ +public: + int specialization_count; + int binding_count; + int push_constant_count; + + // 0 = null + // 1 = storage buffer + // 2 = storage image + // 3 = combined image sampler + int binding_types[16]; // 16 is large enough I think ... + + int reserved_0; + int reserved_1; + int reserved_2; + int reserved_3; +}; + +NCNN_EXPORT int resolve_shader_info(const uint32_t* spv_data, size_t spv_data_size, ShaderInfo& shader_info); + +} // namespace ncnn + +#endif // NCNN_VULKAN + +#endif // NCNN_GPU_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/layer.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/layer.h new file mode 100644 index 0000000..d02f65b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/layer.h @@ -0,0 +1,214 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_H +#define NCNN_LAYER_H + +#include "mat.h" +#include "modelbin.h" +#include "option.h" +#include "paramdict.h" +#include "platform.h" + +#include + +#if NCNN_VULKAN +#include "command.h" +#include "pipeline.h" + +#include +#endif // NCNN_VULKAN + +namespace ncnn { + +class NCNN_EXPORT Layer +{ +public: + // empty + Layer(); + // virtual destructor + virtual ~Layer(); + + // load layer specific parameter from parsed dict + // return 0 if success + virtual int load_param(const ParamDict& pd); + + // load layer specific weight data from model binary + // return 0 if success + virtual int load_model(const ModelBin& mb); + + // layer implementation specific setup + // return 0 if success + virtual int create_pipeline(const Option& opt); + + // layer implementation specific clean + // return 0 if success + virtual int destroy_pipeline(const Option& opt); + +public: + // one input and one output blob + bool one_blob_only; + + // support inplace inference + bool support_inplace; + + // support vulkan compute + bool support_vulkan; + + // accept input blob with packed storage + bool support_packing; + + // accept bf16 + bool support_bf16_storage; + + // accept fp16 + bool support_fp16_storage; + + // accept int8 + bool support_int8_storage; + + // shader image storage + bool support_image_storage; + + // shader tensor storage + bool support_tensor_storage; + + bool support_reserved_00; + + bool support_reserved_0; + bool support_reserved_1; + bool support_reserved_2; + bool support_reserved_3; + bool support_reserved_4; + bool support_reserved_5; + bool support_reserved_6; + bool support_reserved_7; + bool support_reserved_8; + bool support_reserved_9; + + // feature disabled set + int featmask; + +public: + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, const Option& opt) const; + virtual int forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, const Option& opt) const; + virtual int forward_inplace(Mat& bottom_top_blob, const Option& opt) const; + +#if NCNN_VULKAN +public: + // upload weight blob from host to device + virtual int upload_model(VkTransfer& cmd, const Option& opt); + +public: + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward_inplace(VkMat& bottom_top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward_inplace(VkImageMat& bottom_top_blob, VkCompute& cmd, const Option& opt) const; + +public: + // assigned immediately after creating this layer + const VulkanDevice* vkdev; +#endif // NCNN_VULKAN + +public: + // custom user data + void* userdata; + // layer type index + int typeindex; +#if NCNN_STRING + // layer type name + std::string type; + // layer name + std::string name; +#endif // NCNN_STRING + // blob index which this layer needs as input + std::vector bottoms; + // blob index which this layer produces as output + std::vector tops; + // shape hint + std::vector bottom_shapes; + std::vector top_shapes; +}; + +// layer factory function +typedef Layer* (*layer_creator_func)(void*); +typedef void (*layer_destroyer_func)(Layer*, void*); + +struct layer_registry_entry +{ +#if NCNN_STRING + // layer type name + const char* name; +#endif // NCNN_STRING + // layer factory entry + layer_creator_func creator; +}; + +struct custom_layer_registry_entry +{ +#if NCNN_STRING + // layer type name + const char* name; +#endif // NCNN_STRING + // layer factory entry + layer_creator_func creator; + layer_destroyer_func destroyer; + void* userdata; +}; + +#if NCNN_STRING +// get layer type from type name +NCNN_EXPORT int layer_to_index(const char* type); +// create layer from type name +NCNN_EXPORT Layer* create_layer(const char* type); +#endif // NCNN_STRING +// create layer from layer type +NCNN_EXPORT Layer* create_layer(int index); + +#define DEFINE_LAYER_CREATOR(name) \ + ::ncnn::Layer* name##_layer_creator(void* /*userdata*/) \ + { \ + return new name; \ + } + +#define DEFINE_LAYER_DESTROYER(name) \ + void name##_layer_destroyer(::ncnn::Layer* layer, void* /*userdata*/) \ + { \ + delete layer; \ + } + +} // namespace ncnn + +#endif // NCNN_LAYER_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/layer_shader_type.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/layer_shader_type.h new file mode 100644 index 0000000..c143e7d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/layer_shader_type.h @@ -0,0 +1,29 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_SHADER_TYPE_H +#define NCNN_LAYER_SHADER_TYPE_H + +namespace ncnn { + +namespace LayerShaderType { +enum LayerShaderType +{ +#include "layer_shader_type_enum.h" +}; +} // namespace LayerShaderType + +} // namespace ncnn + +#endif // NCNN_LAYER_SHADER_TYPE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/layer_shader_type_enum.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/layer_shader_type_enum.h new file mode 100644 index 0000000..f11cab9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/layer_shader_type_enum.h @@ -0,0 +1,370 @@ +// Layer Shader Enum header +// +// This file is auto-generated by cmake, don't edit it. + +absval = 0, +absval_pack4 = 1, +absval_pack8 = 2, +batchnorm = 3, +batchnorm_pack4 = 4, +batchnorm_pack8 = 5, +concat = 6, +concat_pack4 = 7, +concat_pack4to1 = 8, +concat_pack8 = 9, +concat_pack8to1 = 10, +concat_pack8to4 = 11, +convolution = 12, +convolution_1x1s1d1 = 13, +convolution_3x3s1d1_winograd23_transform_input = 14, +convolution_3x3s1d1_winograd23_transform_output = 15, +convolution_3x3s1d1_winograd43_transform_input = 16, +convolution_3x3s1d1_winograd43_transform_output = 17, +convolution_3x3s1d1_winograd_gemm = 18, +convolution_gemm = 19, +convolution_pack1to4 = 20, +convolution_pack1to4_1x1s1d1 = 21, +convolution_pack1to4_3x3s1d1_winograd_gemm = 22, +convolution_pack1to4_gemm = 23, +convolution_pack1to8 = 24, +convolution_pack1to8_1x1s1d1 = 25, +convolution_pack1to8_3x3s1d1_winograd_gemm = 26, +convolution_pack1to8_gemm = 27, +convolution_pack4 = 28, +convolution_pack4_1x1s1d1 = 29, +convolution_pack4_1x1s1d1_cm_16_8_8 = 30, +convolution_pack4_3x3s1d1_winograd23_transform_input = 31, +convolution_pack4_3x3s1d1_winograd23_transform_output = 32, +convolution_pack4_3x3s1d1_winograd43_transform_input = 33, +convolution_pack4_3x3s1d1_winograd43_transform_output = 34, +convolution_pack4_3x3s1d1_winograd_gemm = 35, +convolution_pack4_3x3s1d1_winograd_gemm_cm_16_8_8 = 36, +convolution_pack4_gemm = 37, +convolution_pack4_gemm_cm_16_8_8 = 38, +convolution_pack4to1 = 39, +convolution_pack4to1_1x1s1d1 = 40, +convolution_pack4to1_3x3s1d1_winograd_gemm = 41, +convolution_pack4to1_gemm = 42, +convolution_pack4to8 = 43, +convolution_pack4to8_1x1s1d1 = 44, +convolution_pack4to8_3x3s1d1_winograd_gemm = 45, +convolution_pack4to8_gemm = 46, +convolution_pack8 = 47, +convolution_pack8_1x1s1d1 = 48, +convolution_pack8_3x3s1d1_winograd23_transform_input = 49, +convolution_pack8_3x3s1d1_winograd23_transform_output = 50, +convolution_pack8_3x3s1d1_winograd43_transform_input = 51, +convolution_pack8_3x3s1d1_winograd43_transform_output = 52, +convolution_pack8_3x3s1d1_winograd_gemm = 53, +convolution_pack8_gemm = 54, +convolution_pack8to1 = 55, +convolution_pack8to1_1x1s1d1 = 56, +convolution_pack8to1_3x3s1d1_winograd_gemm = 57, +convolution_pack8to1_gemm = 58, +convolution_pack8to4 = 59, +convolution_pack8to4_1x1s1d1 = 60, +convolution_pack8to4_3x3s1d1_winograd_gemm = 61, +convolution_pack8to4_gemm = 62, +crop = 63, +crop_pack1to4 = 64, +crop_pack1to8 = 65, +crop_pack4 = 66, +crop_pack4to1 = 67, +crop_pack4to8 = 68, +crop_pack8 = 69, +crop_pack8to1 = 70, +crop_pack8to4 = 71, +deconvolution = 72, +deconvolution_col2im = 73, +deconvolution_gemm = 74, +deconvolution_pack1to4 = 75, +deconvolution_pack1to4_gemm = 76, +deconvolution_pack1to8 = 77, +deconvolution_pack1to8_gemm = 78, +deconvolution_pack4 = 79, +deconvolution_pack4_col2im = 80, +deconvolution_pack4_gemm = 81, +deconvolution_pack4_gemm_cm_16_8_8 = 82, +deconvolution_pack4to1 = 83, +deconvolution_pack4to1_gemm = 84, +deconvolution_pack4to8 = 85, +deconvolution_pack4to8_gemm = 86, +deconvolution_pack8 = 87, +deconvolution_pack8_col2im = 88, +deconvolution_pack8_gemm = 89, +deconvolution_pack8to1 = 90, +deconvolution_pack8to1_gemm = 91, +deconvolution_pack8to4 = 92, +deconvolution_pack8to4_gemm = 93, +dropout = 94, +dropout_pack4 = 95, +dropout_pack8 = 96, +eltwise = 97, +eltwise_pack4 = 98, +eltwise_pack8 = 99, +elu = 100, +elu_pack4 = 101, +elu_pack8 = 102, +flatten = 103, +flatten_pack1to4 = 104, +flatten_pack1to8 = 105, +flatten_pack4 = 106, +flatten_pack4to8 = 107, +flatten_pack8 = 108, +innerproduct = 109, +innerproduct_gemm = 110, +innerproduct_gemm_wp1to4 = 111, +innerproduct_gemm_wp1to8 = 112, +innerproduct_gemm_wp4 = 113, +innerproduct_gemm_wp4to1 = 114, +innerproduct_gemm_wp4to8 = 115, +innerproduct_gemm_wp8 = 116, +innerproduct_gemm_wp8to1 = 117, +innerproduct_gemm_wp8to4 = 118, +innerproduct_pack1to4 = 119, +innerproduct_pack1to8 = 120, +innerproduct_pack4 = 121, +innerproduct_pack4to1 = 122, +innerproduct_pack4to8 = 123, +innerproduct_pack8 = 124, +innerproduct_pack8to1 = 125, +innerproduct_pack8to4 = 126, +innerproduct_reduce_sum8 = 127, +innerproduct_reduce_sum8_pack4 = 128, +innerproduct_reduce_sum8_pack8 = 129, +innerproduct_sum8 = 130, +innerproduct_sum8_pack1to4 = 131, +innerproduct_sum8_pack1to8 = 132, +innerproduct_sum8_pack4 = 133, +innerproduct_sum8_pack4to1 = 134, +innerproduct_sum8_pack4to8 = 135, +innerproduct_sum8_pack8 = 136, +innerproduct_sum8_pack8to1 = 137, +innerproduct_sum8_pack8to4 = 138, +lrn_norm = 139, +lrn_norm_across_channel_pack4 = 140, +lrn_norm_across_channel_pack8 = 141, +lrn_norm_within_channel_pack4 = 142, +lrn_norm_within_channel_pack8 = 143, +lrn_square_pad = 144, +lrn_square_pad_across_channel_pack4 = 145, +lrn_square_pad_across_channel_pack8 = 146, +lrn_square_pad_within_channel_pack4 = 147, +lrn_square_pad_within_channel_pack8 = 148, +pooling = 149, +pooling_adaptive = 150, +pooling_adaptive_pack4 = 151, +pooling_adaptive_pack8 = 152, +pooling_global = 153, +pooling_global_pack4 = 154, +pooling_global_pack8 = 155, +pooling_pack4 = 156, +pooling_pack8 = 157, +prelu = 158, +prelu_pack4 = 159, +prelu_pack8 = 160, +relu = 161, +relu_pack4 = 162, +relu_pack8 = 163, +reshape = 164, +reshape_pack1to4 = 165, +reshape_pack1to8 = 166, +reshape_pack4 = 167, +reshape_pack4to1 = 168, +reshape_pack4to8 = 169, +reshape_pack8 = 170, +reshape_pack8to1 = 171, +reshape_pack8to4 = 172, +scale = 173, +scale_pack4 = 174, +scale_pack8 = 175, +sigmoid = 176, +sigmoid_pack4 = 177, +sigmoid_pack8 = 178, +slice = 179, +slice_pack1to4 = 180, +slice_pack1to8 = 181, +slice_pack4 = 182, +slice_pack4to8 = 183, +slice_pack8 = 184, +softmax_div_sum = 185, +softmax_div_sum_pack4 = 186, +softmax_div_sum_pack8 = 187, +softmax_exp_sub_max = 188, +softmax_exp_sub_max_pack4 = 189, +softmax_exp_sub_max_pack8 = 190, +softmax_reduce_max = 191, +softmax_reduce_max_pack4 = 192, +softmax_reduce_max_pack8 = 193, +softmax_reduce_sum = 194, +softmax_reduce_sum_pack4 = 195, +softmax_reduce_sum_pack8 = 196, +tanh = 197, +tanh_pack4 = 198, +tanh_pack8 = 199, +binaryop = 200, +binaryop_broadcast = 201, +binaryop_broadcast_a1_pack4 = 202, +binaryop_broadcast_a1_pack8 = 203, +binaryop_broadcast_b1_pack4 = 204, +binaryop_broadcast_b1_pack8 = 205, +binaryop_broadcast_pack4 = 206, +binaryop_broadcast_pack8 = 207, +binaryop_pack4 = 208, +binaryop_pack8 = 209, +unaryop = 210, +unaryop_pack4 = 211, +unaryop_pack8 = 212, +convolutiondepthwise = 213, +convolutiondepthwise_group = 214, +convolutiondepthwise_group_pack1to4 = 215, +convolutiondepthwise_group_pack1to8 = 216, +convolutiondepthwise_group_pack4 = 217, +convolutiondepthwise_group_pack4to1 = 218, +convolutiondepthwise_group_pack4to8 = 219, +convolutiondepthwise_group_pack8 = 220, +convolutiondepthwise_group_pack8to1 = 221, +convolutiondepthwise_group_pack8to4 = 222, +convolutiondepthwise_pack4 = 223, +convolutiondepthwise_pack8 = 224, +padding = 225, +padding_3d = 226, +padding_3d_pack4 = 227, +padding_3d_pack8 = 228, +padding_pack1to4 = 229, +padding_pack1to8 = 230, +padding_pack4 = 231, +padding_pack4to1 = 232, +padding_pack4to8 = 233, +padding_pack8 = 234, +padding_pack8to1 = 235, +padding_pack8to4 = 236, +normalize_coeffs = 237, +normalize_coeffs_pack4 = 238, +normalize_coeffs_pack8 = 239, +normalize_norm = 240, +normalize_norm_pack4 = 241, +normalize_norm_pack8 = 242, +normalize_reduce_sum4_fp16_to_fp32 = 243, +normalize_reduce_sum4_fp16_to_fp32_pack4 = 244, +normalize_reduce_sum4_fp16_to_fp32_pack8 = 245, +normalize_reduce_sum4_fp32 = 246, +normalize_reduce_sum4_fp32_pack4 = 247, +normalize_reduce_sum4_fp32_pack8 = 248, +permute = 249, +permute_pack1to4 = 250, +permute_pack1to8 = 251, +permute_pack4 = 252, +permute_pack4to1 = 253, +permute_pack4to8 = 254, +permute_pack8 = 255, +permute_pack8to1 = 256, +permute_pack8to4 = 257, +priorbox = 258, +priorbox_mxnet = 259, +interp = 260, +interp_bicubic = 261, +interp_bicubic_coeffs = 262, +interp_bicubic_pack4 = 263, +interp_bicubic_pack8 = 264, +interp_pack4 = 265, +interp_pack8 = 266, +deconvolutiondepthwise = 267, +deconvolutiondepthwise_group = 268, +deconvolutiondepthwise_group_pack1to4 = 269, +deconvolutiondepthwise_group_pack1to8 = 270, +deconvolutiondepthwise_group_pack4 = 271, +deconvolutiondepthwise_group_pack4to1 = 272, +deconvolutiondepthwise_group_pack4to8 = 273, +deconvolutiondepthwise_group_pack8 = 274, +deconvolutiondepthwise_group_pack8to1 = 275, +deconvolutiondepthwise_group_pack8to4 = 276, +deconvolutiondepthwise_pack4 = 277, +deconvolutiondepthwise_pack8 = 278, +shufflechannel = 279, +shufflechannel_pack4 = 280, +shufflechannel_pack8 = 281, +instancenorm_coeffs = 282, +instancenorm_coeffs_pack4 = 283, +instancenorm_coeffs_pack8 = 284, +instancenorm_norm = 285, +instancenorm_norm_pack4 = 286, +instancenorm_norm_pack8 = 287, +instancenorm_reduce_mean = 288, +instancenorm_reduce_mean_pack4 = 289, +instancenorm_reduce_mean_pack8 = 290, +instancenorm_reduce_sum4_fp16_to_fp32 = 291, +instancenorm_reduce_sum4_fp16_to_fp32_pack4 = 292, +instancenorm_reduce_sum4_fp16_to_fp32_pack8 = 293, +instancenorm_reduce_sum4_fp32 = 294, +instancenorm_reduce_sum4_fp32_pack4 = 295, +instancenorm_reduce_sum4_fp32_pack8 = 296, +instancenorm_sub_mean_square = 297, +instancenorm_sub_mean_square_pack4 = 298, +instancenorm_sub_mean_square_pack8 = 299, +clip = 300, +clip_pack4 = 301, +clip_pack8 = 302, +reorg = 303, +reorg_pack1to4 = 304, +reorg_pack1to8 = 305, +reorg_pack4 = 306, +reorg_pack4to8 = 307, +reorg_pack8 = 308, +packing = 309, +packing_fp16_to_fp32 = 310, +packing_fp32_to_fp16 = 311, +packing_pack1to4 = 312, +packing_pack1to4_fp16_to_fp32 = 313, +packing_pack1to4_fp32_to_fp16 = 314, +packing_pack1to8 = 315, +packing_pack1to8_fp16_to_fp32 = 316, +packing_pack1to8_fp32_to_fp16 = 317, +packing_pack4 = 318, +packing_pack4_fp16_to_fp32 = 319, +packing_pack4_fp32_to_fp16 = 320, +packing_pack4to1 = 321, +packing_pack4to1_fp16_to_fp32 = 322, +packing_pack4to1_fp32_to_fp16 = 323, +packing_pack4to8 = 324, +packing_pack4to8_fp16_to_fp32 = 325, +packing_pack4to8_fp32_to_fp16 = 326, +packing_pack8 = 327, +packing_pack8_fp16_to_fp32 = 328, +packing_pack8_fp32_to_fp16 = 329, +packing_pack8to1 = 330, +packing_pack8to1_fp16_to_fp32 = 331, +packing_pack8to1_fp32_to_fp16 = 332, +packing_pack8to4 = 333, +packing_pack8to4_fp16_to_fp32 = 334, +packing_pack8to4_fp32_to_fp16 = 335, +cast_fp16_to_fp32 = 336, +cast_fp16_to_fp32_pack4 = 337, +cast_fp16_to_fp32_pack8 = 338, +cast_fp32_to_fp16 = 339, +cast_fp32_to_fp16_pack4 = 340, +cast_fp32_to_fp16_pack8 = 341, +hardsigmoid = 342, +hardsigmoid_pack4 = 343, +hardsigmoid_pack8 = 344, +hardswish = 345, +hardswish_pack4 = 346, +hardswish_pack8 = 347, +pixelshuffle = 348, +pixelshuffle_pack4 = 349, +pixelshuffle_pack4to1 = 350, +pixelshuffle_pack8 = 351, +pixelshuffle_pack8to1 = 352, +pixelshuffle_pack8to4 = 353, +deepcopy = 354, +deepcopy_pack4 = 355, +deepcopy_pack8 = 356, +mish = 357, +mish_pack4 = 358, +mish_pack8 = 359, +swish = 360, +swish_pack4 = 361, +swish_pack8 = 362, +convert_ycbcr = 363, +vulkan_activation = 364, + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/layer_type.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/layer_type.h new file mode 100644 index 0000000..511c714 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/layer_type.h @@ -0,0 +1,30 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_TYPE_H +#define NCNN_LAYER_TYPE_H + +namespace ncnn { + +namespace LayerType { +enum LayerType +{ +#include "layer_type_enum.h" + CustomBit = (1 << 8), +}; +} // namespace LayerType + +} // namespace ncnn + +#endif // NCNN_LAYER_TYPE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/layer_type_enum.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/layer_type_enum.h new file mode 100644 index 0000000..581d589 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/layer_type_enum.h @@ -0,0 +1,103 @@ +// Layer Type Enum header +// +// This file is auto-generated by cmake, don't edit it. + +AbsVal = 0, +ArgMax = 1, +BatchNorm = 2, +Bias = 3, +BNLL = 4, +Concat = 5, +Convolution = 6, +Crop = 7, +Deconvolution = 8, +Dropout = 9, +Eltwise = 10, +ELU = 11, +Embed = 12, +Exp = 13, +Flatten = 14, +InnerProduct = 15, +Input = 16, +Log = 17, +LRN = 18, +MemoryData = 19, +MVN = 20, +Pooling = 21, +Power = 22, +PReLU = 23, +Proposal = 24, +Reduction = 25, +ReLU = 26, +Reshape = 27, +ROIPooling = 28, +Scale = 29, +Sigmoid = 30, +Slice = 31, +Softmax = 32, +Split = 33, +SPP = 34, +TanH = 35, +Threshold = 36, +Tile = 37, +RNN = 38, +LSTM = 39, +BinaryOp = 40, +UnaryOp = 41, +ConvolutionDepthWise = 42, +Padding = 43, +Squeeze = 44, +ExpandDims = 45, +Normalize = 46, +Permute = 47, +PriorBox = 48, +DetectionOutput = 49, +Interp = 50, +DeconvolutionDepthWise = 51, +ShuffleChannel = 52, +InstanceNorm = 53, +Clip = 54, +Reorg = 55, +YoloDetectionOutput = 56, +Quantize = 57, +Dequantize = 58, +Yolov3DetectionOutput = 59, +PSROIPooling = 60, +ROIAlign = 61, +Packing = 62, +Requantize = 63, +Cast = 64, +HardSigmoid = 65, +SELU = 66, +HardSwish = 67, +Noop = 68, +PixelShuffle = 69, +DeepCopy = 70, +Mish = 71, +StatisticsPooling = 72, +Swish = 73, +Gemm = 74, +GroupNorm = 75, +LayerNorm = 76, +Softplus = 77, +GRU = 78, +MultiHeadAttention = 79, +GELU = 80, +Convolution1D = 81, +Pooling1D = 82, +ConvolutionDepthWise1D = 83, +Convolution3D = 84, +ConvolutionDepthWise3D = 85, +Pooling3D = 86, +MatMul = 87, +Deconvolution1D = 88, +DeconvolutionDepthWise1D = 89, +Deconvolution3D = 90, +DeconvolutionDepthWise3D = 91, +Einsum = 92, +DeformableConv2D = 93, +GLU = 94, +Fold = 95, +Unfold = 96, +GridSample = 97, + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/mat.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/mat.h new file mode 100644 index 0000000..c6f59ef --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/mat.h @@ -0,0 +1,1843 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_MAT_H +#define NCNN_MAT_H + +#include +#include +#if __ARM_NEON +#include +#endif +#if __SSE2__ +#include +#if __AVX__ +#include +#endif +#endif +#if __mips_msa +#include +#endif +#if __loongarch_sx +#include +#endif +#if __riscv_vector +#include +#include "cpu.h" // cpu_riscv_vlenb() +#endif + +#include "allocator.h" +#include "option.h" +#include "platform.h" + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#if NCNN_PIXEL +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#include +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API +#endif // NCNN_PIXEL + +namespace ncnn { + +#if NCNN_VULKAN +class VkMat; +class VkImageMat; +#endif // NCNN_VULKAN + +// the three dimension matrix +class NCNN_EXPORT Mat +{ +public: + // empty + Mat(); + // vec + Mat(int w, size_t elemsize = 4u, Allocator* allocator = 0); + // image + Mat(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0); + // dim + Mat(int w, int h, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // cube + Mat(int w, int h, int d, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // packed vec + Mat(int w, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed image + Mat(int w, int h, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed dim + Mat(int w, int h, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed cube + Mat(int w, int h, int d, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // copy + Mat(const Mat& m); + // external vec + Mat(int w, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external image + Mat(int w, int h, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external dim + Mat(int w, int h, int c, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external cube + Mat(int w, int h, int d, int c, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external packed vec + Mat(int w, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed image + Mat(int w, int h, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed dim + Mat(int w, int h, int c, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed cube + Mat(int w, int h, int d, int c, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // release + ~Mat(); + // assign + Mat& operator=(const Mat& m); + // set all + void fill(float v); + void fill(int v); +#if __ARM_NEON + void fill(float32x4_t _v); + void fill(uint16x4_t _v); + void fill(int32x4_t _v); + void fill(int32x4_t _v0, int32x4_t _v1); +#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC + void fill(float16x4_t _v); + void fill(float16x8_t _v); +#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +#endif // __ARM_NEON +#if __SSE2__ +#if __AVX__ +#if __AVX512F__ + void fill(__m512 _v); +#endif // __AVX512F__ + void fill(__m256 _v, int i = 0); +#endif // __AVX__ + void fill(__m128 _v); + void fill(__m128i _v); +#endif // __SSE2__ +#if __mips_msa + void fill(v4f32 _v); +#endif // __mips_msa +#if __loongarch_sx + void fill(__m128 _v); +#endif //__loongarch_sx +#if __riscv_vector + void fill(vfloat32m1_t _v); + void fill(vuint16m1_t _v); + void fill(vint8m1_t _v); +#if __riscv_zfh + void fill(vfloat16m1_t _v); +#endif // __riscv_zfh +#endif // __riscv_vector + template + void fill(T v); + // deep copy + Mat clone(Allocator* allocator = 0) const; + // deep copy from other mat, inplace + void clone_from(const ncnn::Mat& mat, Allocator* allocator = 0); + // reshape vec + Mat reshape(int w, Allocator* allocator = 0) const; + // reshape image + Mat reshape(int w, int h, Allocator* allocator = 0) const; + // reshape dim + Mat reshape(int w, int h, int c, Allocator* allocator = 0) const; + // reshape cube + Mat reshape(int w, int h, int d, int c, Allocator* allocator = 0) const; + // allocate vec + void create(int w, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate image + void create(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate dim + void create(int w, int h, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate like + void create_like(const Mat& m, Allocator* allocator = 0); +#if NCNN_VULKAN + // allocate like + void create_like(const VkMat& m, Allocator* allocator = 0); + // allocate like + void create_like(const VkImageMat& im, Allocator* allocator = 0); +#endif // NCNN_VULKAN + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // data reference + Mat channel(int c); + const Mat channel(int c) const; + Mat depth(int z); + const Mat depth(int z) const; + float* row(int y); + const float* row(int y) const; + template + T* row(int y); + template + const T* row(int y) const; + + // range reference + Mat channel_range(int c, int channels); + const Mat channel_range(int c, int channels) const; + Mat depth_range(int z, int depths); + const Mat depth_range(int z, int depths) const; + Mat row_range(int y, int rows); + const Mat row_range(int y, int rows) const; + Mat range(int x, int n); + const Mat range(int x, int n) const; + + // access raw data + template + operator T*(); + template + operator const T*() const; + + // convenient access float vec element + float& operator[](size_t i); + const float& operator[](size_t i) const; + +#if NCNN_PIXEL + enum PixelType + { + PIXEL_CONVERT_SHIFT = 16, + PIXEL_FORMAT_MASK = 0x0000ffff, + PIXEL_CONVERT_MASK = 0xffff0000, + + PIXEL_RGB = 1, + PIXEL_BGR = 2, + PIXEL_GRAY = 3, + PIXEL_RGBA = 4, + PIXEL_BGRA = 5, + + PIXEL_RGB2BGR = PIXEL_RGB | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2GRAY = PIXEL_RGB | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2RGBA = PIXEL_RGB | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2BGRA = PIXEL_RGB | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_BGR2RGB = PIXEL_BGR | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2GRAY = PIXEL_BGR | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2RGBA = PIXEL_BGR | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2BGRA = PIXEL_BGR | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_GRAY2RGB = PIXEL_GRAY | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2BGR = PIXEL_GRAY | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2RGBA = PIXEL_GRAY | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2BGRA = PIXEL_GRAY | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_RGBA2RGB = PIXEL_RGBA | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2BGR = PIXEL_RGBA | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2GRAY = PIXEL_RGBA | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2BGRA = PIXEL_RGBA | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_BGRA2RGB = PIXEL_BGRA | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2BGR = PIXEL_BGRA | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2GRAY = PIXEL_BGRA | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2RGBA = PIXEL_BGRA | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + }; + // convenient construct from pixel data + static Mat from_pixels(const unsigned char* pixels, int type, int w, int h, Allocator* allocator = 0); + // convenient construct from pixel data with stride(bytes-per-row) parameter + static Mat from_pixels(const unsigned char* pixels, int type, int w, int h, int stride, Allocator* allocator = 0); + // convenient construct from pixel data and resize to specific size + static Mat from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data and resize to specific size with stride(bytes-per-row) parameter + static Mat from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data roi + static Mat from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from pixel data roi with stride(bytes-per-row) parameter + static Mat from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from pixel data roi and resize to specific size + static Mat from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data roi and resize to specific size with stride(bytes-per-row) parameter + static Mat from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + + // convenient export to pixel data + void to_pixels(unsigned char* pixels, int type) const; + // convenient export to pixel data with stride(bytes-per-row) parameter + void to_pixels(unsigned char* pixels, int type, int stride) const; + // convenient export to pixel data and resize to specific size + void to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height) const; + // convenient export to pixel data and resize to specific size with stride(bytes-per-row) parameter + void to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height, int target_stride) const; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 + // convenient construct from android Bitmap + static Mat from_android_bitmap(JNIEnv* env, jobject bitmap, int type_to, Allocator* allocator = 0); + // convenient construct from android Bitmap and resize to specific size + static Mat from_android_bitmap_resize(JNIEnv* env, jobject bitmap, int type_to, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from android Bitmap roi + static Mat from_android_bitmap_roi(JNIEnv* env, jobject bitmap, int type_to, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from android Bitmap roi and resize to specific size + static Mat from_android_bitmap_roi_resize(JNIEnv* env, jobject bitmap, int type_to, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + // convenient export to android Bitmap and resize to the android Bitmap size + void to_android_bitmap(JNIEnv* env, jobject bitmap, int type_from) const; +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API +#endif // NCNN_PIXEL + + // substract channel-wise mean values, then multiply by normalize values, pass 0 to skip + void substract_mean_normalize(const float* mean_vals, const float* norm_vals); + + // convenient construct from half precision floating point data + static Mat from_float16(const unsigned short* data, int size); + + // pointer to the data + void* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + Allocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; + + size_t cstep; +}; + +#if NCNN_VULKAN + +// the three dimension matrix, vulkan version +class NCNN_EXPORT VkMat +{ +public: + // empty + VkMat(); + // vec + VkMat(int w, size_t elemsize, VkAllocator* allocator); + // image + VkMat(int w, int h, size_t elemsize, VkAllocator* allocator); + // dim + VkMat(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // cube + VkMat(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // packed vec + VkMat(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // packed image + VkMat(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // packed dim + VkMat(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // packed cube + VkMat(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // copy + VkMat(const VkMat& m); + // external vec + VkMat(int w, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external image + VkMat(int w, int h, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external dim + VkMat(int w, int h, int c, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external cube + VkMat(int w, int h, int d, int c, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external packed vec + VkMat(int w, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed image + VkMat(int w, int h, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed dim + VkMat(int w, int h, int c, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed cube + VkMat(int w, int h, int d, int c, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // release + ~VkMat(); + // assign + VkMat& operator=(const VkMat& m); + // allocate vec + void create(int w, size_t elemsize, VkAllocator* allocator); + // allocate image + void create(int w, int h, size_t elemsize, VkAllocator* allocator); + // allocate dim + void create(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate like + void create_like(const Mat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkMat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkImageMat& im, VkAllocator* allocator); + + // mapped + Mat mapped() const; + void* mapped_ptr() const; + + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // low-level reference + VkBuffer buffer() const; + size_t buffer_offset() const; + size_t buffer_capacity() const; + + // device buffer + VkBufferMemory* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + VkAllocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; + + size_t cstep; +}; + +class NCNN_EXPORT VkImageMat +{ +public: + // empty + VkImageMat(); + // vec + VkImageMat(int w, size_t elemsize, VkAllocator* allocator); + // image + VkImageMat(int w, int h, size_t elemsize, VkAllocator* allocator); + // dim + VkImageMat(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // cube + VkImageMat(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // packed vec + VkImageMat(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // packed image + VkImageMat(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // packed dim + VkImageMat(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // packed cube + VkImageMat(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // copy + VkImageMat(const VkImageMat& m); + // external vec + VkImageMat(int w, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external image + VkImageMat(int w, int h, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external dim + VkImageMat(int w, int h, int c, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external cube + VkImageMat(int w, int h, int d, int c, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external packed vec + VkImageMat(int w, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed image + VkImageMat(int w, int h, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed dim + VkImageMat(int w, int h, int c, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed cube + VkImageMat(int w, int h, int d, int c, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // release + ~VkImageMat(); + // assign + VkImageMat& operator=(const VkImageMat& m); + // allocate vec + void create(int w, size_t elemsize, VkAllocator* allocator); + // allocate image + void create(int w, int h, size_t elemsize, VkAllocator* allocator); + // allocate dim + void create(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate like + void create_like(const Mat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkMat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkImageMat& im, VkAllocator* allocator); + + // mapped + Mat mapped() const; + void* mapped_ptr() const; + + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // low-level reference + VkImage image() const; + VkImageView imageview() const; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 + // convenient construct from android hardware buffer + static VkImageMat from_android_hardware_buffer(VkAndroidHardwareBufferImageAllocator* allocator); +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + + // device image + VkImageMemory* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + VkAllocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; +}; + +// type for vulkan specialization constant and push constant +union vk_specialization_type +{ + int i; + float f; + uint32_t u32; +}; +union vk_constant_type +{ + int i; + float f; +}; +#endif // NCNN_VULKAN + +// misc function +#if NCNN_PIXEL +// convert yuv420sp(nv21) to rgb, the fast approximate version +NCNN_EXPORT void yuv420sp2rgb(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// convert yuv420sp(nv12) to rgb, the fast approximate version +NCNN_EXPORT void yuv420sp2rgb_nv12(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// convert yuv420sp(nv21) to rgb with half resize, the faster approximate version +NCNN_EXPORT void yuv420sp2rgb_half(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// image pixel bilinear resize +NCNN_EXPORT void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +// image pixel bilinear resize with stride(bytes-per-row) parameter +NCNN_EXPORT void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +// image pixel bilinear resize, convenient wrapper for yuv420sp(nv21/nv12) +NCNN_EXPORT void resize_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +#endif // NCNN_PIXEL +#if NCNN_PIXEL_ROTATE +// type is the from type, 6 means rotating from 6 to 1 +// +// 1 2 3 4 5 6 7 8 +// +// 888888 888888 88 88 8888888888 88 88 8888888888 +// 88 88 88 88 88 88 88 88 88 88 88 88 +// 8888 8888 8888 8888 88 8888888888 8888888888 88 +// 88 88 88 88 +// 88 88 888888 888888 +// +// ref http://sylvana.net/jpegcrop/exif_orientation.html +// image pixel kanna rotate +NCNN_EXPORT void kanna_rotate_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +// image pixel kanna rotate with stride(bytes-per-row) parameter +NCNN_EXPORT void kanna_rotate_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +// image pixel kanna rotate, convenient wrapper for yuv420sp(nv21/nv12) +NCNN_EXPORT void kanna_rotate_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +#endif // NCNN_PIXEL_ROTATE +#if NCNN_PIXEL_AFFINE +// resolve affine transform matrix from rotation angle, scale factor and x y offset +NCNN_EXPORT void get_rotation_matrix(float angle, float scale, float dx, float dy, float* tm); +// resolve affine transform matrix from two set of points, num_point must be >= 2 +NCNN_EXPORT void get_affine_transform(const float* points_from, const float* points_to, int num_point, float* tm); +// resolve the inversion affine transform matrix +NCNN_EXPORT void invert_affine_transform(const float* tm, float* tm_inv); +// image pixel bilinear warpaffine inverse transform, set -233 for transparent border color, the color RGBA is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +// image pixel bilinear warpaffine inverse transform with stride(bytes-per-row) parameter, set -233 for transparent border color, the color RGBA is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +// image pixel bilinear warpaffine, convenient wrapper for yuv420sp(nv21/nv12), set -233 for transparent border color, the color YUV_ is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +#endif // NCNN_PIXEL_AFFINE +#if NCNN_PIXEL_DRAWING +// draw rectangle, set thickness -1 for filled rectangle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_rectangle_c1(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c2(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c3(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c4(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw rectangle with stride(bytes-per-row) parameter, set thickness -1 for filled rectangle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_rectangle_c1(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c2(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c3(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c4(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw rectangle, convenient wrapper for yuv420sp(nv21/nv12), set thickness -1 for filled rectangle, the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_rectangle_yuv420sp(unsigned char* yuv420sp, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw circle, set thickness -1 for filled circle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_circle_c1(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c2(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c3(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c4(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +// draw circle with stride(bytes-per-row) parameter, set thickness -1 for filled circle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_circle_c1(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c2(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c3(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c4(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +// draw circle, convenient wrapper for yuv420sp(nv21/nv12), set thickness -1 for filled circle, the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_circle_yuv420sp(unsigned char* yuv420sp, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +// draw line, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_line_c1(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c2(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c3(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c4(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// draw line with stride(bytes-per-row) parameter, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_line_c1(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c2(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c3(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c4(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// draw line, convenient wrapper for yuv420sp(nv21/nv12), the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_line_yuv420sp(unsigned char* yuv420sp, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// resolve text bounding box size +NCNN_EXPORT void get_text_drawing_size(const char* text, int fontpixelsize, int* w, int* h); +// draw ascii printables and newline, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_text_c1(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c2(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c3(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c4(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +// draw ascii printables and newline with stride(bytes-per-row) parameter, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_text_c1(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c2(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c3(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c4(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +// draw ascii printables and newline, convenient wrapper for yuv420sp(nv21/nv12), the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_text_yuv420sp(unsigned char* yuv420sp, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +#endif // NCNN_PIXEL_DRAWING + +// type conversion +// convert float to half precision floating point +NCNN_EXPORT unsigned short float32_to_float16(float value); +// convert half precision floating point to float +NCNN_EXPORT float float16_to_float32(unsigned short value); +// convert float to brain half +NCNN_EXPORT NCNN_FORCEINLINE unsigned short float32_to_bfloat16(float value) +{ + // 16 : 16 + union + { + unsigned int u; + float f; + } tmp; + tmp.f = value; + return tmp.u >> 16; +} +// convert brain half to float +NCNN_EXPORT NCNN_FORCEINLINE float bfloat16_to_float32(unsigned short value) +{ + // 16 : 16 + union + { + unsigned int u; + float f; + } tmp; + tmp.u = value << 16; + return tmp.f; +} + +// mat process +enum BorderType +{ + BORDER_CONSTANT = 0, + BORDER_REPLICATE = 1, + BORDER_REFLECT = 2, + BORDER_TRANSPARENT = -233, +}; +NCNN_EXPORT void copy_make_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int type, float v, const Option& opt = Option()); +NCNN_EXPORT void copy_make_border_3d(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int front, int behind, int type, float v, const Option& opt = Option()); +NCNN_EXPORT void copy_cut_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, const Option& opt = Option()); +NCNN_EXPORT void copy_cut_border_3d(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int front, int behind, const Option& opt = Option()); +NCNN_EXPORT void resize_nearest(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void resize_bilinear(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void resize_bicubic(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void convert_packing(const Mat& src, Mat& dst, int elempack, const Option& opt = Option()); +NCNN_EXPORT void flatten(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float32_to_float16(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float16_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_int8_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float32_to_bfloat16(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_bfloat16_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void quantize_to_int8(const Mat& src, Mat& dst, const Mat& scale_data, const Option& opt = Option()); +NCNN_EXPORT void dequantize_from_int32(const Mat& src, Mat& dst, const Mat& scale_data, const Mat& bias_data, const Option& opt = Option()); +NCNN_EXPORT void requantize_from_int32_to_int8(const Mat& src, Mat& dst, const Mat& scale_in_data, const Mat& scale_out_data, const Mat& bias_data, int activation_type, const Mat& activation_params, const Option& opt = Option()); + +NCNN_FORCEINLINE Mat::Mat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ +} + +NCNN_FORCEINLINE Mat::Mat(int _w, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(const Mat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c), cstep(m.cstep) +{ + addref(); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = (size_t)w * h; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = (size_t)w * h; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::~Mat() +{ + release(); +} + +NCNN_FORCEINLINE void Mat::fill(float _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + + int i = 0; +#if __ARM_NEON + float32x4_t _c = vdupq_n_f32(_v); + for (; i + 3 < size; i += 4) + { + vst1q_f32(ptr, _c); + ptr += 4; + } +#endif // __ARM_NEON + for (; i < size; i++) + { + *ptr++ = _v; + } +} + +NCNN_FORCEINLINE void Mat::fill(int _v) +{ + int size = (int)total(); + int* ptr = (int*)data; + + int i = 0; +#if __ARM_NEON + int32x4_t _c = vdupq_n_s32(_v); + for (; i + 3 < size; i += 4) + { + vst1q_s32(ptr, _c); + ptr += 4; + } +#endif // __ARM_NEON + for (; i < size; i++) + { + *ptr++ = _v; + } +} + +#if __ARM_NEON +NCNN_FORCEINLINE void Mat::fill(float32x4_t _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + vst1q_f32(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(uint16x4_t _v) +{ + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + vst1_u16(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(int32x4_t _v) +{ + int size = (int)total(); + int* ptr = (int*)data; + for (int i = 0; i < size; i++) + { + vst1q_s32(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(int32x4_t _v0, int32x4_t _v1) +{ + int size = (int)total(); + int* ptr = (int*)data; + for (int i = 0; i < size; i++) + { + vst1q_s32(ptr, _v0); + vst1q_s32(ptr + 4, _v1); + ptr += 8; + } +} +#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +NCNN_FORCEINLINE void Mat::fill(float16x4_t _v) +{ + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vst1_f16(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(float16x8_t _v) +{ + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vst1q_f16(ptr, _v); + ptr += 8; + } +} +#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +#endif // __ARM_NEON + +#if __SSE2__ +#if __AVX__ +#if __AVX512F__ +NCNN_FORCEINLINE void Mat::fill(__m512 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm512_storeu_ps(ptr, _v); + ptr += 16; + } +} +#endif // __AVX512F__ +NCNN_FORCEINLINE void Mat::fill(__m256 _v, int _i) +{ + // old gcc cannot overload __m128 and __m256 type + // add a dummy int parameter for different mangled function symbol + (void)_i; + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm256_storeu_ps(ptr, _v); + ptr += 8; + } +} +#endif // __AVX__ +NCNN_FORCEINLINE void Mat::fill(__m128 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm_storeu_ps(ptr, _v); + ptr += 4; + } +} +NCNN_FORCEINLINE void Mat::fill(__m128i _v) +{ + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + _mm_store_si128((__m128i*)ptr, _v); + ptr += 8; + } +} +#endif // __SSE2__ + +#if __mips_msa +NCNN_FORCEINLINE void Mat::fill(v4f32 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + __msa_st_w((v4i32)_v, ptr, 0); + ptr += 4; + } +} +#endif // __mips_msa + +#if __loongarch_sx +NCNN_FORCEINLINE void Mat::fill(__m128 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + __lsx_vst(_v, ptr, 0); + ptr += 4; + } +} +#endif // __loongarch_sx +#if __riscv_vector +NCNN_FORCEINLINE void Mat::fill(vfloat32m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 4; + const size_t vl = vsetvl_e32m1(packn); + + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + vse32_v_f32m1(ptr, _v, vl); + ptr += packn; + } +} + +NCNN_FORCEINLINE void Mat::fill(vuint16m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 2; + const size_t vl = vsetvl_e16m1(packn); + + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + vse16_v_u16m1(ptr, _v, vl); + ptr += packn; + } +} + +NCNN_FORCEINLINE void Mat::fill(vint8m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 1; + const size_t vl = vsetvl_e8m1(packn); + + int size = (int)total(); + signed char* ptr = (signed char*)data; + for (int i = 0; i < size; i++) + { + vse8_v_i8m1(ptr, _v, vl); + ptr += packn; + } +} +#if __riscv_zfh +NCNN_FORCEINLINE void Mat::fill(vfloat16m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 2; + const size_t vl = vsetvl_e16m1(packn); + + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vse16_v_f16m1(ptr, _v, vl); + ptr += packn; + } +} +#endif // __riscv_zfh +#endif // __riscv_vector + +template +NCNN_FORCEINLINE void Mat::fill(T _v) +{ + int size = (int)total(); + T* ptr = (T*)data; + for (int i = 0; i < size; i++) + { + ptr[i] = _v; + } +} + +NCNN_FORCEINLINE Mat& Mat::operator=(const Mat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + cstep = m.cstep; + + return *this; +} + +NCNN_FORCEINLINE void Mat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void Mat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator) + allocator->fastFree(data); + else + fastFree(data); + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + cstep = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool Mat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t Mat::total() const +{ + return cstep * c; +} + +NCNN_FORCEINLINE int Mat::elembits() const +{ + return elempack ? static_cast(elemsize * 8) / elempack : 0; +} + +NCNN_FORCEINLINE Mat Mat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE Mat Mat::channel(int _c) +{ + Mat m(w, h, d, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims - 1; + if (dims == 4) + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::channel(int _c) const +{ + Mat m(w, h, d, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims - 1; + if (dims == 4) + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE Mat Mat::depth(int z) +{ + return Mat(w, h, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::depth(int z) const +{ + return Mat(w, h, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE float* Mat::row(int y) +{ + return (float*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +NCNN_FORCEINLINE const float* Mat::row(int y) const +{ + return (const float*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +template +NCNN_FORCEINLINE T* Mat::row(int y) +{ + return (T*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +template +NCNN_FORCEINLINE const T* Mat::row(int y) const +{ + return (const T*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +NCNN_FORCEINLINE Mat Mat::channel_range(int _c, int channels) +{ + Mat m(w, h, d, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::channel_range(int _c, int channels) const +{ + Mat m(w, h, d, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims; + return m; +} + +NCNN_FORCEINLINE Mat Mat::depth_range(int z, int depths) +{ + Mat m(w, h, depths, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::depth_range(int z, int depths) const +{ + Mat m(w, h, depths, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE Mat Mat::row_range(int y, int rows) +{ + return Mat(w, rows, (unsigned char*)data + (size_t)w * y * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::row_range(int y, int rows) const +{ + return Mat(w, rows, (unsigned char*)data + (size_t)w * y * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE Mat Mat::range(int x, int n) +{ + return Mat(n, (unsigned char*)data + x * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::range(int x, int n) const +{ + return Mat(n, (unsigned char*)data + x * elemsize, elemsize, elempack, allocator); +} + +template +NCNN_FORCEINLINE Mat::operator T*() +{ + return (T*)data; +} + +template +NCNN_FORCEINLINE Mat::operator const T*() const +{ + return (const T*)data; +} + +NCNN_FORCEINLINE float& Mat::operator[](size_t i) +{ + return ((float*)data)[i]; +} + +NCNN_FORCEINLINE const float& Mat::operator[](size_t i) const +{ + return ((const float*)data)[i]; +} + +#if NCNN_VULKAN + +NCNN_FORCEINLINE VkMat::VkMat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(const VkMat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c) +{ + addref(); + + cstep = m.cstep; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = w * h; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize(w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = w * h; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize(w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::~VkMat() +{ + release(); +} + +NCNN_FORCEINLINE VkMat& VkMat::operator=(const VkMat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + cstep = m.cstep; + + return *this; +} + +NCNN_FORCEINLINE Mat VkMat::mapped() const +{ + if (!allocator->mappable) + return Mat(); + + if (dims == 1) + return Mat(w, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 2) + return Mat(w, h, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 3) + return Mat(w, h, c, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 4) + return Mat(w, h, d, c, mapped_ptr(), elemsize, elempack, 0); + + return Mat(); +} + +NCNN_FORCEINLINE void* VkMat::mapped_ptr() const +{ + if (!allocator->mappable) + return 0; + + return (unsigned char*)data->mapped_ptr + data->offset; +} + +NCNN_FORCEINLINE void VkMat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void VkMat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator && data) + { + allocator->fastFree(data); + } + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + cstep = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool VkMat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t VkMat::total() const +{ + return cstep * c; +} + +NCNN_FORCEINLINE int VkMat::elembits() const +{ + return elempack ? static_cast(elemsize) * 8 / elempack : 0; +} + +NCNN_FORCEINLINE Mat VkMat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE VkBuffer VkMat::buffer() const +{ + return data->buffer; +} + +NCNN_FORCEINLINE size_t VkMat::buffer_offset() const +{ + return data->offset; +} + +NCNN_FORCEINLINE size_t VkMat::buffer_capacity() const +{ + return data->capacity; +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(const VkImageMat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c) +{ + addref(); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::~VkImageMat() +{ + release(); +} + +NCNN_FORCEINLINE VkImageMat& VkImageMat::operator=(const VkImageMat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + return *this; +} + +NCNN_FORCEINLINE Mat VkImageMat::mapped() const +{ + if (!allocator->mappable || !data->mapped_ptr) + return Mat(); + + if (dims == 1) + return Mat(w, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 2) + return Mat(w, h, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 3) + return Mat(w, h, c, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 4) + return Mat(w, h, d, c, mapped_ptr(), elemsize, elempack, 0); + + return Mat(); +} + +NCNN_FORCEINLINE void* VkImageMat::mapped_ptr() const +{ + if (!allocator->mappable || !data->mapped_ptr) + return 0; + + return (unsigned char*)data->mapped_ptr + data->bind_offset; +} + +NCNN_FORCEINLINE void VkImageMat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void VkImageMat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator && data) + { + allocator->fastFree(data); + } + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool VkImageMat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t VkImageMat::total() const +{ + return w * h * d * c; +} + +NCNN_FORCEINLINE int VkImageMat::elembits() const +{ + return elempack ? static_cast(elemsize) * 8 / elempack : 0; +} + +NCNN_FORCEINLINE Mat VkImageMat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE VkImage VkImageMat::image() const +{ + return data->image; +} + +NCNN_FORCEINLINE VkImageView VkImageMat::imageview() const +{ + return data->imageview; +} + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_MAT_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/modelbin.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/modelbin.h new file mode 100644 index 0000000..15d2b9c --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/modelbin.h @@ -0,0 +1,80 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_MODELBIN_H +#define NCNN_MODELBIN_H + +#include "mat.h" + +namespace ncnn { + +class DataReader; +class NCNN_EXPORT ModelBin +{ +public: + ModelBin(); + virtual ~ModelBin(); + // element type + // 0 = auto + // 1 = float32 + // 2 = float16 + // 3 = int8 + // load vec + virtual Mat load(int w, int type) const = 0; + // load image + virtual Mat load(int w, int h, int type) const; + // load dim + virtual Mat load(int w, int h, int c, int type) const; + // load cube + virtual Mat load(int w, int h, int d, int c, int type) const; +}; + +class ModelBinFromDataReaderPrivate; +class NCNN_EXPORT ModelBinFromDataReader : public ModelBin +{ +public: + explicit ModelBinFromDataReader(const DataReader& dr); + virtual ~ModelBinFromDataReader(); + + virtual Mat load(int w, int type) const; + +private: + ModelBinFromDataReader(const ModelBinFromDataReader&); + ModelBinFromDataReader& operator=(const ModelBinFromDataReader&); + +private: + ModelBinFromDataReaderPrivate* const d; +}; + +class ModelBinFromMatArrayPrivate; +class NCNN_EXPORT ModelBinFromMatArray : public ModelBin +{ +public: + // construct from weight blob array + explicit ModelBinFromMatArray(const Mat* weights); + virtual ~ModelBinFromMatArray(); + + virtual Mat load(int w, int type) const; + +private: + ModelBinFromMatArray(const ModelBinFromMatArray&); + ModelBinFromMatArray& operator=(const ModelBinFromMatArray&); + +private: + ModelBinFromMatArrayPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_MODELBIN_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/ncnn_export.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/ncnn_export.h new file mode 100644 index 0000000..e2f5fde --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/ncnn_export.h @@ -0,0 +1,42 @@ + +#ifndef NCNN_EXPORT_H +#define NCNN_EXPORT_H + +#ifdef NCNN_STATIC_DEFINE +# define NCNN_EXPORT +# define NCNN_NO_EXPORT +#else +# ifndef NCNN_EXPORT +# ifdef ncnn_EXPORTS + /* We are building this library */ +# define NCNN_EXPORT __attribute__((visibility("default"))) +# else + /* We are using this library */ +# define NCNN_EXPORT __attribute__((visibility("default"))) +# endif +# endif + +# ifndef NCNN_NO_EXPORT +# define NCNN_NO_EXPORT __attribute__((visibility("hidden"))) +# endif +#endif + +#ifndef NCNN_DEPRECATED +# define NCNN_DEPRECATED __attribute__ ((__deprecated__)) +#endif + +#ifndef NCNN_DEPRECATED_EXPORT +# define NCNN_DEPRECATED_EXPORT NCNN_EXPORT NCNN_DEPRECATED +#endif + +#ifndef NCNN_DEPRECATED_NO_EXPORT +# define NCNN_DEPRECATED_NO_EXPORT NCNN_NO_EXPORT NCNN_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef NCNN_NO_DEPRECATED +# define NCNN_NO_DEPRECATED +# endif +#endif + +#endif /* NCNN_EXPORT_H */ diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/net.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/net.h new file mode 100644 index 0000000..9407042 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/net.h @@ -0,0 +1,272 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_NET_H +#define NCNN_NET_H + +#include "blob.h" +#include "layer.h" +#include "mat.h" +#include "option.h" +#include "platform.h" + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +#if NCNN_VULKAN +class VkCompute; +#endif // NCNN_VULKAN +class DataReader; +class Extractor; +class NetPrivate; +class NCNN_EXPORT Net +{ +public: + // empty init + Net(); + // clear and destroy + virtual ~Net(); + +public: + // option can be changed before loading + Option opt; + +#if NCNN_VULKAN + // set gpu device by index + void set_vulkan_device(int device_index); + + // set gpu device by device handle, no owner transfer + void set_vulkan_device(const VulkanDevice* vkdev); + + const VulkanDevice* vulkan_device() const; +#endif // NCNN_VULKAN + +#if NCNN_STRING + // register custom layer by layer type name + // return 0 if success + int register_custom_layer(const char* type, layer_creator_func creator, layer_destroyer_func destroyer = 0, void* userdata = 0); + virtual int custom_layer_to_index(const char* type); +#endif // NCNN_STRING + // register custom layer by layer type + // return 0 if success + int register_custom_layer(int index, layer_creator_func creator, layer_destroyer_func destroyer = 0, void* userdata = 0); + +#if NCNN_STRING + int load_param(const DataReader& dr); +#endif // NCNN_STRING + + int load_param_bin(const DataReader& dr); + + int load_model(const DataReader& dr); + +#if NCNN_STDIO +#if NCNN_STRING + // load network structure from plain param file + // return 0 if success + int load_param(FILE* fp); + int load_param(const char* protopath); + int load_param_mem(const char* mem); +#endif // NCNN_STRING + // load network structure from binary param file + // return 0 if success + int load_param_bin(FILE* fp); + int load_param_bin(const char* protopath); + + // load network weight data from model file + // return 0 if success + int load_model(FILE* fp); + int load_model(const char* modelpath); +#endif // NCNN_STDIO + + // load network structure from external memory + // memory pointer must be 32-bit aligned + // return bytes consumed + int load_param(const unsigned char* mem); + + // reference network weight data from external memory + // weight data is not copied but referenced + // so external memory should be retained when used + // memory pointer must be 32-bit aligned + // return bytes consumed + int load_model(const unsigned char* mem); + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#if NCNN_STRING + // convenient load network structure from android asset plain param file + int load_param(AAsset* asset); + int load_param(AAssetManager* mgr, const char* assetpath); +#endif // NCNN_STRING + // convenient load network structure from android asset binary param file + int load_param_bin(AAsset* asset); + int load_param_bin(AAssetManager* mgr, const char* assetpath); + + // convenient load network weight data from android asset model file + int load_model(AAsset* asset); + int load_model(AAssetManager* mgr, const char* assetpath); +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + + // unload network structure and weight data + void clear(); + + // construct an Extractor from network + Extractor create_extractor() const; + + // get input/output indexes/names + const std::vector& input_indexes() const; + const std::vector& output_indexes() const; +#if NCNN_STRING + const std::vector& input_names() const; + const std::vector& output_names() const; +#endif + + const std::vector& blobs() const; + const std::vector& layers() const; + + std::vector& mutable_blobs(); + std::vector& mutable_layers(); + +protected: + friend class Extractor; +#if NCNN_STRING + int find_blob_index_by_name(const char* name) const; + int find_layer_index_by_name(const char* name) const; + virtual Layer* create_custom_layer(const char* type); +#endif // NCNN_STRING + virtual Layer* create_custom_layer(int index); + +private: + Net(const Net&); + Net& operator=(const Net&); + +private: + NetPrivate* const d; +}; + +class ExtractorPrivate; +class NCNN_EXPORT Extractor +{ +public: + virtual ~Extractor(); + + // copy + Extractor(const Extractor&); + + // assign + Extractor& operator=(const Extractor&); + + // clear blob mats and alloctors + void clear(); + + // enable light mode + // intermediate blob will be recycled when enabled + // enabled by default + void set_light_mode(bool enable); + + // set thread count for this extractor + // this will overwrite the global setting + // default count is system depended + void set_num_threads(int num_threads); + + // set blob memory allocator + void set_blob_allocator(Allocator* allocator); + + // set workspace memory allocator + void set_workspace_allocator(Allocator* allocator); + +#if NCNN_VULKAN + void set_vulkan_compute(bool enable); + + void set_blob_vkallocator(VkAllocator* allocator); + + void set_workspace_vkallocator(VkAllocator* allocator); + + void set_staging_vkallocator(VkAllocator* allocator); +#endif // NCNN_VULKAN + +#if NCNN_STRING + // set input by blob name + // return 0 if success + int input(const char* blob_name, const Mat& in); + + // get result by blob name + // return 0 if success + // type = 0, default + // type = 1, do not convert fp16/bf16 or / and packing + int extract(const char* blob_name, Mat& feat, int type = 0); +#endif // NCNN_STRING + + // set input by blob index + // return 0 if success + int input(int blob_index, const Mat& in); + + // get result by blob index + // return 0 if success + // type = 0, default + // type = 1, do not convert fp16/bf16 or / and packing + int extract(int blob_index, Mat& feat, int type = 0); + +#if NCNN_VULKAN +#if NCNN_STRING + // set input by blob name + // return 0 if success + int input(const char* blob_name, const VkMat& in); + + // get result by blob name + // return 0 if success + int extract(const char* blob_name, VkMat& feat, VkCompute& cmd); + + // set input by blob name + // return 0 if success + int input(const char* blob_name, const VkImageMat& in); + + // get result by blob name + // return 0 if success + int extract(const char* blob_name, VkImageMat& feat, VkCompute& cmd); +#endif // NCNN_STRING + + // set input by blob index + // return 0 if success + int input(int blob_index, const VkMat& in); + + // get result by blob index + // return 0 if success + int extract(int blob_index, VkMat& feat, VkCompute& cmd); + + // set input by blob index + // return 0 if success + int input(int blob_index, const VkImageMat& in); + + // get result by blob index + // return 0 if success + int extract(int blob_index, VkImageMat& feat, VkCompute& cmd); +#endif // NCNN_VULKAN + +protected: + friend Extractor Net::create_extractor() const; + Extractor(const Net* net, size_t blob_count); + +private: + ExtractorPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_NET_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/option.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/option.h new file mode 100644 index 0000000..3fda808 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/option.h @@ -0,0 +1,153 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_OPTION_H +#define NCNN_OPTION_H + +#include "platform.h" + +namespace ncnn { + +#if NCNN_VULKAN +class VkAllocator; +class PipelineCache; +#endif // NCNN_VULKAN + +class Allocator; +class NCNN_EXPORT Option +{ +public: + // default option + Option(); + +public: + // light mode + // intermediate blob will be recycled when enabled + // enabled by default + bool lightmode; + + // thread count + // default value is the one returned by get_cpu_count() + int num_threads; + + // blob memory allocator + Allocator* blob_allocator; + + // workspace memory allocator + Allocator* workspace_allocator; + +#if NCNN_VULKAN + // blob memory allocator + VkAllocator* blob_vkallocator; + + // workspace memory allocator + VkAllocator* workspace_vkallocator; + + // staging memory allocator + VkAllocator* staging_vkallocator; + + // pipeline cache + PipelineCache* pipeline_cache; +#endif // NCNN_VULKAN + + // the time openmp threads busy-wait for more work before going to sleep + // default value is 20ms to keep the cores enabled + // without too much extra power consumption afterwards + int openmp_blocktime; + + // enable winograd convolution optimization + // improve convolution 3x3 stride1 performance, may consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_winograd_convolution; + + // enable sgemm convolution optimization + // improve convolution 1x1 stride1 performance, may consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_sgemm_convolution; + + // enable quantized int8 inference + // use low-precision int8 path for quantized model + // changes should be applied before loading network structure and weight + // enabled by default + bool use_int8_inference; + + // enable vulkan compute + bool use_vulkan_compute; + + // enable bf16 data type for storage + // improve most operator performance on all arm devices, may consume more memory + bool use_bf16_storage; + + // enable options for gpu inference + bool use_fp16_packed; + bool use_fp16_storage; + bool use_fp16_arithmetic; + bool use_int8_packed; + bool use_int8_storage; + bool use_int8_arithmetic; + + // enable simd-friendly packed memory layout + // improve all operator performance on all arm devices, will consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_packing_layout; + + bool use_shader_pack8; + + // subgroup option + bool use_subgroup_basic; + bool use_subgroup_vote; + bool use_subgroup_ballot; + bool use_subgroup_shuffle; + + // turn on for adreno + bool use_image_storage; + bool use_tensor_storage; + + bool use_reserved_0; + + // enable DAZ(Denormals-Are-Zero) and FTZ(Flush-To-Zero) + // default value is 3 + // 0 = DAZ OFF, FTZ OFF + // 1 = DAZ ON , FTZ OFF + // 2 = DAZ OFF, FTZ ON + // 3 = DAZ ON, FTZ ON + int flush_denormals; + + bool use_local_pool_allocator; + + // enable local memory optimization for gpu inference + bool use_shader_local_memory; + + // enable cooperative matrix optimization for gpu inference + bool use_cooperative_matrix; + + // more fine-grained control of winograd convolution + bool use_winograd23_convolution; + bool use_winograd43_convolution; + bool use_winograd63_convolution; + + bool use_reserved_6; + bool use_reserved_7; + bool use_reserved_8; + bool use_reserved_9; + bool use_reserved_10; + bool use_reserved_11; +}; + +} // namespace ncnn + +#endif // NCNN_OPTION_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/paramdict.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/paramdict.h new file mode 100644 index 0000000..c2ef160 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/paramdict.h @@ -0,0 +1,73 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PARAMDICT_H +#define NCNN_PARAMDICT_H + +#include "mat.h" + +// at most 32 parameters +#define NCNN_MAX_PARAM_COUNT 32 + +namespace ncnn { + +class DataReader; +class Net; +class ParamDictPrivate; +class NCNN_EXPORT ParamDict +{ +public: + // empty + ParamDict(); + + virtual ~ParamDict(); + + // copy + ParamDict(const ParamDict&); + + // assign + ParamDict& operator=(const ParamDict&); + + // get type + int type(int id) const; + + // get int + int get(int id, int def) const; + // get float + float get(int id, float def) const; + // get array + Mat get(int id, const Mat& def) const; + + // set int + void set(int id, int i); + // set float + void set(int id, float f); + // set array + void set(int id, const Mat& v); + +protected: + friend class Net; + + void clear(); + + int load_param(const DataReader& dr); + int load_param_bin(const DataReader& dr); + +private: + ParamDictPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_PARAMDICT_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/pipeline.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/pipeline.h new file mode 100644 index 0000000..c284a14 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/pipeline.h @@ -0,0 +1,113 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PIPELINE_H +#define NCNN_PIPELINE_H + +#include "mat.h" +#include "platform.h" +#if NCNN_VULKAN +#include "gpu.h" + +#include +#endif // NCNN_VULKAN + +namespace ncnn { + +#if NCNN_VULKAN +class Option; +class PipelinePrivate; +class NCNN_EXPORT Pipeline +{ +public: + explicit Pipeline(const VulkanDevice* vkdev); + virtual ~Pipeline(); + +public: + void set_optimal_local_size_xyz(int w = 4, int h = 4, int c = 4); + void set_optimal_local_size_xyz(const Mat& local_size_xyz); + void set_local_size_xyz(int w, int h, int c); + + int create(const uint32_t* spv_data, size_t spv_data_size, const std::vector& specializations); + + int create(int shader_type_index, const Option& opt, const std::vector& specializations); + +public: + VkShaderModule shader_module() const; + VkDescriptorSetLayout descriptorset_layout() const; + VkPipelineLayout pipeline_layout() const; + VkPipeline pipeline() const; + VkDescriptorUpdateTemplateKHR descriptor_update_template() const; + + const ShaderInfo& shader_info() const; + + uint32_t local_size_x() const; + uint32_t local_size_y() const; + uint32_t local_size_z() const; + +protected: + void set_shader_module(VkShaderModule shader_module); + void set_descriptorset_layout(VkDescriptorSetLayout descriptorset_layout); + void set_pipeline_layout(VkPipelineLayout pipeline_layout); + void set_pipeline(VkPipeline pipeline); + void set_descriptor_update_template(VkDescriptorUpdateTemplateKHR descriptor_update_template); + + void set_shader_info(const ShaderInfo& shader_info); + +public: + const VulkanDevice* vkdev; + +private: + Pipeline(const Pipeline&); + Pipeline& operator=(const Pipeline&); + +private: + PipelinePrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class VkCompute; +class NCNN_EXPORT ImportAndroidHardwareBufferPipeline : private Pipeline +{ +public: + explicit ImportAndroidHardwareBufferPipeline(const VulkanDevice* vkdev); + virtual ~ImportAndroidHardwareBufferPipeline(); + + int create(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator, int type_to, int rotate_from, const Option& opt); + int create(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator, int type_to, int rotate_from, int target_width, int target_height, const Option& opt); + void destroy(); + + friend class VkCompute; + +protected: + int create_shader_module(const Option& opt); + int create_sampler(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator); + int create_descriptorset_layout(); + +public: + int type_to; + int rotate_from; + bool need_resize; + + VkSampler sampler; +}; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_PIPELINE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/pipelinecache.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/pipelinecache.h new file mode 100644 index 0000000..bb6b8fb --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/pipelinecache.h @@ -0,0 +1,85 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PIPELINECACHE_H +#define NCNN_PIPELINECACHE_H + +#include "platform.h" + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#include "mat.h" +#include "gpu.h" + +namespace ncnn { + +#if NCNN_VULKAN + +class VulkanDevice; +class PipelineCachePrivate; +class NCNN_EXPORT PipelineCache +{ +public: + explicit PipelineCache(const VulkanDevice* _vkdev); + + virtual ~PipelineCache(); + + void clear(); + + int get_pipeline(const uint32_t* spv_data, size_t spv_data_size, const std::vector& specializations, + uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* shader_module, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template, + ShaderInfo& shader_info) const; + + int get_pipeline(int shader_type_index, const Option& opt, const std::vector& specializations, + uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* shader_module, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template, + ShaderInfo& shader_info) const; + +protected: + int create_shader_module(int shader_type_index, const Option& opt, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* _shader_module, ShaderInfo& si) const; + + int new_pipeline(VkShaderModule shader_module, const ShaderInfo& shader_info, const std::vector& specializations, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template) const; + +protected: + const VulkanDevice* vkdev; + +private: + PipelineCache(const PipelineCache&); + PipelineCache& operator=(const PipelineCache&); + +private: + PipelineCachePrivate* const d; +}; + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_PIPELINECACHE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/platform.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/platform.h new file mode 100644 index 0000000..89f3243 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/platform.h @@ -0,0 +1,285 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PLATFORM_H +#define NCNN_PLATFORM_H + +#define NCNN_STDIO 1 +#define NCNN_STRING 1 +#define NCNN_SIMPLEOCV 0 +#define NCNN_SIMPLEOMP 0 +#define NCNN_SIMPLESTL 0 +#define NCNN_THREADS 1 +#define NCNN_BENCHMARK 0 +#define NCNN_C_API 1 +#define NCNN_PLATFORM_API 1 +#define NCNN_PIXEL 1 +#define NCNN_PIXEL_ROTATE 1 +#define NCNN_PIXEL_AFFINE 1 +#define NCNN_PIXEL_DRAWING 1 +#define NCNN_VULKAN 1 +#define NCNN_SYSTEM_GLSLANG 0 +#define NCNN_RUNTIME_CPU 1 +#define NCNN_AVX 1 +#define NCNN_XOP 1 +#define NCNN_FMA 1 +#define NCNN_F16C 1 +#define NCNN_AVX2 1 +#define NCNN_AVXVNNI 1 +#define NCNN_AVX512 1 +#define NCNN_AVX512VNNI 1 +#define NCNN_AVX512BF16 1 +#define NCNN_AVX512FP16 1 +#define NCNN_VFPV4 0 +#if __aarch64__ +#define NCNN_ARM82 0 +#define NCNN_ARM82DOT 0 +#define NCNN_ARM82FP16FML 0 +#define NCNN_ARM84BF16 0 +#define NCNN_ARM84I8MM 0 +#define NCNN_ARM86SVE 0 +#define NCNN_ARM86SVE2 0 +#define NCNN_ARM86SVEBF16 0 +#define NCNN_ARM86SVEI8MM 0 +#define NCNN_ARM86SVEF32MM 0 +#endif // __aarch64__ +#define NCNN_MSA 0 +#define NCNN_LSX 0 +#define NCNN_MMI 0 +#define NCNN_RVV 0 +#define NCNN_INT8 1 +#define NCNN_BF16 1 +#define NCNN_FORCE_INLINE 1 + +#define NCNN_VERSION_STRING "1.0.20221128" + +#include "ncnn_export.h" + +#ifdef __cplusplus + +#if NCNN_THREADS +#if (defined _WIN32 && !(defined __MINGW32__)) +#define WIN32_LEAN_AND_MEAN +#include +#include +#else +#include +#endif +#endif // NCNN_THREADS + +#if __ANDROID_API__ >= 26 +#define VK_USE_PLATFORM_ANDROID_KHR +#endif // __ANDROID_API__ >= 26 + +namespace ncnn { + +#if NCNN_THREADS +#if (defined _WIN32 && !(defined __MINGW32__)) +class NCNN_EXPORT Mutex +{ +public: + Mutex() { InitializeSRWLock(&srwlock); } + ~Mutex() {} + void lock() { AcquireSRWLockExclusive(&srwlock); } + void unlock() { ReleaseSRWLockExclusive(&srwlock); } +private: + friend class ConditionVariable; + // NOTE SRWLock is available from windows vista + SRWLOCK srwlock; +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() { InitializeConditionVariable(&condvar); } + ~ConditionVariable() {} + void wait(Mutex& mutex) { SleepConditionVariableSRW(&condvar, &mutex.srwlock, INFINITE, 0); } + void broadcast() { WakeAllConditionVariable(&condvar); } + void signal() { WakeConditionVariable(&condvar); } +private: + CONDITION_VARIABLE condvar; +}; + +static unsigned __stdcall start_wrapper(void* args); +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*start)(void*), void* args = 0) { _start = start; _args = args; handle = (HANDLE)_beginthreadex(0, 0, start_wrapper, this, 0, 0); } + ~Thread() {} + void join() { WaitForSingleObject(handle, INFINITE); CloseHandle(handle); } +private: + friend unsigned __stdcall start_wrapper(void* args) + { + Thread* t = (Thread*)args; + t->_start(t->_args); + return 0; + } + HANDLE handle; + void* (*_start)(void*); + void* _args; +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { key = TlsAlloc(); } + ~ThreadLocalStorage() { TlsFree(key); } + void set(void* value) { TlsSetValue(key, (LPVOID)value); } + void* get() { return (void*)TlsGetValue(key); } +private: + DWORD key; +}; +#else // (defined _WIN32 && !(defined __MINGW32__)) +class NCNN_EXPORT Mutex +{ +public: + Mutex() { pthread_mutex_init(&mutex, 0); } + ~Mutex() { pthread_mutex_destroy(&mutex); } + void lock() { pthread_mutex_lock(&mutex); } + void unlock() { pthread_mutex_unlock(&mutex); } +private: + friend class ConditionVariable; + pthread_mutex_t mutex; +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() { pthread_cond_init(&cond, 0); } + ~ConditionVariable() { pthread_cond_destroy(&cond); } + void wait(Mutex& mutex) { pthread_cond_wait(&cond, &mutex.mutex); } + void broadcast() { pthread_cond_broadcast(&cond); } + void signal() { pthread_cond_signal(&cond); } +private: + pthread_cond_t cond; +}; + +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*start)(void*), void* args = 0) { pthread_create(&t, 0, start, args); } + ~Thread() {} + void join() { pthread_join(t, 0); } +private: + pthread_t t; +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { pthread_key_create(&key, 0); } + ~ThreadLocalStorage() { pthread_key_delete(key); } + void set(void* value) { pthread_setspecific(key, value); } + void* get() { return pthread_getspecific(key); } +private: + pthread_key_t key; +}; +#endif // (defined _WIN32 && !(defined __MINGW32__)) +#else // NCNN_THREADS +class NCNN_EXPORT Mutex +{ +public: + Mutex() {} + ~Mutex() {} + void lock() {} + void unlock() {} +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() {} + ~ConditionVariable() {} + void wait(Mutex& /*mutex*/) {} + void broadcast() {} + void signal() {} +}; + +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*/*start*/)(void*), void* /*args*/ = 0) {} + ~Thread() {} + void join() {} +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { data = 0; } + ~ThreadLocalStorage() {} + void set(void* value) { data = value; } + void* get() { return data; } +private: + void* data; +}; +#endif // NCNN_THREADS + +class NCNN_EXPORT MutexLockGuard +{ +public: + MutexLockGuard(Mutex& _mutex) : mutex(_mutex) { mutex.lock(); } + ~MutexLockGuard() { mutex.unlock(); } +private: + Mutex& mutex; +}; + +} // namespace ncnn + +#if NCNN_SIMPLESTL +#include "simplestl.h" +#else +#include +#include +#include +#include +#endif + +#endif // __cplusplus + +#if NCNN_STDIO +#if NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#include +#define NCNN_LOGE(...) do { \ + fprintf(stderr, ##__VA_ARGS__); fprintf(stderr, "\n"); \ + __android_log_print(ANDROID_LOG_WARN, "ncnn", ##__VA_ARGS__); } while(0) +#else // NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#include +#define NCNN_LOGE(...) do { \ + fprintf(stderr, ##__VA_ARGS__); fprintf(stderr, "\n"); } while(0) +#endif // NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#else +#define NCNN_LOGE(...) +#endif + + +#if NCNN_FORCE_INLINE +#ifdef _MSC_VER + #define NCNN_FORCEINLINE __forceinline +#elif defined(__GNUC__) + #define NCNN_FORCEINLINE inline __attribute__((__always_inline__)) +#elif defined(__CLANG__) + #if __has_attribute(__always_inline__) + #define NCNN_FORCEINLINE inline __attribute__((__always_inline__)) + #else + #define NCNN_FORCEINLINE inline + #endif +#else + #define NCNN_FORCEINLINE inline +#endif +#else + #define NCNN_FORCEINLINE inline +#endif + +#endif // NCNN_PLATFORM_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/simpleocv.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/simpleocv.h new file mode 100644 index 0000000..55ede15 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/simpleocv.h @@ -0,0 +1,501 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEOCV_H +#define NCNN_SIMPLEOCV_H + +#include "platform.h" + +#if NCNN_SIMPLEOCV + +#include +#include +#include "allocator.h" +#include "mat.h" + +#if defined(_MSC_VER) || defined(__GNUC__) +#pragma push_macro("min") +#pragma push_macro("max") +#undef min +#undef max +#endif + +#ifndef NCNN_XADD +using ncnn::NCNN_XADD; +#endif + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; + +enum +{ + CV_LOAD_IMAGE_UNCHANGED = -1, + CV_LOAD_IMAGE_GRAYSCALE = 0, + CV_LOAD_IMAGE_COLOR = 1, +}; + +enum +{ + CV_IMWRITE_JPEG_QUALITY = 1 +}; + +// minimal opencv style data structure implementation +namespace cv { + +template +static inline _Tp saturate_cast(int v) +{ + return _Tp(v); +} +template<> +inline uchar saturate_cast(int v) +{ + return (uchar)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); +} + +template +struct Scalar_ +{ + Scalar_() + { + v[0] = 0; + v[1] = 0; + v[2] = 0; + v[3] = 0; + } + Scalar_(_Tp _v0) + { + v[0] = _v0; + v[1] = 0; + v[2] = 0; + v[3] = 0; + } + Scalar_(_Tp _v0, _Tp _v1, _Tp _v2) + { + v[0] = _v0; + v[1] = _v1; + v[2] = _v2; + v[3] = 0; + } + Scalar_(_Tp _v0, _Tp _v1, _Tp _v2, _Tp _v3) + { + v[0] = _v0; + v[1] = _v1; + v[2] = _v2; + v[3] = _v3; + } + + const _Tp operator[](const int i) const + { + return v[i]; + } + + _Tp operator[](const int i) + { + return v[i]; + } + + _Tp v[4]; +}; + +typedef Scalar_ Scalar; + +template +struct Point_ +{ + Point_() + : x(0), y(0) + { + } + Point_(_Tp _x, _Tp _y) + : x(_x), y(_y) + { + } + + template + operator Point_<_Tp2>() const + { + return Point_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y)); + } + + _Tp x; + _Tp y; +}; + +typedef Point_ Point; +typedef Point_ Point2f; + +template +struct Size_ +{ + Size_() + : width(0), height(0) + { + } + Size_(_Tp _w, _Tp _h) + : width(_w), height(_h) + { + } + + template + operator Size_<_Tp2>() const + { + return Size_<_Tp2>(saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); + } + + _Tp width; + _Tp height; +}; + +typedef Size_ Size; +typedef Size_ Size2f; + +template +struct Rect_ +{ + Rect_() + : x(0), y(0), width(0), height(0) + { + } + Rect_(_Tp _x, _Tp _y, _Tp _w, _Tp _h) + : x(_x), y(_y), width(_w), height(_h) + { + } + Rect_(Point_<_Tp> _p, Size_<_Tp> _size) + : x(_p.x), y(_p.y), width(_size.width), height(_size.height) + { + } + + template + operator Rect_<_Tp2>() const + { + return Rect_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y), saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); + } + + _Tp x; + _Tp y; + _Tp width; + _Tp height; + + // area + _Tp area() const + { + return width * height; + } +}; + +template +static inline Rect_<_Tp>& operator&=(Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + _Tp x1 = std::max(a.x, b.x), y1 = std::max(a.y, b.y); + a.width = std::min(a.x + a.width, b.x + b.width) - x1; + a.height = std::min(a.y + a.height, b.y + b.height) - y1; + a.x = x1; + a.y = y1; + if (a.width <= 0 || a.height <= 0) + a = Rect_<_Tp>(); + return a; +} + +template +static inline Rect_<_Tp>& operator|=(Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + _Tp x1 = std::min(a.x, b.x), y1 = std::min(a.y, b.y); + a.width = std::max(a.x + a.width, b.x + b.width) - x1; + a.height = std::max(a.y + a.height, b.y + b.height) - y1; + a.x = x1; + a.y = y1; + return a; +} + +template +static inline Rect_<_Tp> operator&(const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c &= b; +} + +template +static inline Rect_<_Tp> operator|(const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c |= b; +} + +typedef Rect_ Rect; +typedef Rect_ Rect2f; + +#define CV_8UC1 1 +#define CV_8UC3 3 +#define CV_8UC4 4 +#define CV_32FC1 4 + +struct NCNN_EXPORT Mat +{ + Mat() + : data(0), refcount(0), rows(0), cols(0), c(0) + { + } + + Mat(int _rows, int _cols, int flags) + : data(0), refcount(0) + { + create(_rows, _cols, flags); + } + + // copy + Mat(const Mat& m) + : data(m.data), refcount(m.refcount) + { + if (refcount) + NCNN_XADD(refcount, 1); + + rows = m.rows; + cols = m.cols; + c = m.c; + } + + Mat(int _rows, int _cols, int flags, void* _data) + : data((unsigned char*)_data), refcount(0) + { + rows = _rows; + cols = _cols; + c = flags; + } + + ~Mat() + { + release(); + } + + // assign + Mat& operator=(const Mat& m) + { + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + + rows = m.rows; + cols = m.cols; + c = m.c; + + return *this; + } + + Mat& operator=(const Scalar& s) + { + if (total() > 0) + { + uchar* p = data; + for (int i = 0; i < cols * rows; i++) + { + for (int j = 0; j < c; j++) + { + *p++ = s[j]; + } + } + } + + return *this; + } + + void create(int _rows, int _cols, int flags) + { + release(); + + rows = _rows; + cols = _cols; + c = flags; + + if (total() > 0) + { + // refcount address must be aligned, so we expand totalsize here + size_t totalsize = (total() + 3) >> 2 << 2; + data = (uchar*)ncnn::fastMalloc(totalsize + (int)sizeof(*refcount)); + refcount = (int*)(((uchar*)data) + totalsize); + *refcount = 1; + } + } + + void release() + { + if (refcount && NCNN_XADD(refcount, -1) == 1) + ncnn::fastFree(data); + + data = 0; + + rows = 0; + cols = 0; + c = 0; + + refcount = 0; + } + + Mat clone() const + { + if (empty()) + return Mat(); + + Mat m(rows, cols, c); + + if (total() > 0) + { + memcpy(m.data, data, total()); + } + + return m; + } + + bool empty() const + { + return data == 0 || total() == 0; + } + + int channels() const + { + return c; + } + + int type() const + { + return c; + } + + size_t total() const + { + return cols * rows * c; + } + + const uchar* ptr(int y) const + { + return data + y * cols * c; + } + + uchar* ptr(int y) + { + return data + y * cols * c; + } + + template + const _Tp* ptr(int y) const + { + return (const _Tp*)data + y * cols * c; + } + + template + _Tp* ptr(int y) + { + return (_Tp*)data + y * cols * c; + } + + // roi + Mat operator()(const Rect& roi) const + { + if (empty()) + return Mat(); + + Mat m(roi.height, roi.width, c); + + int sy = roi.y; + for (int y = 0; y < roi.height; y++) + { + const uchar* sptr = ptr(sy) + roi.x * c; + uchar* dptr = m.ptr(y); + memcpy(dptr, sptr, roi.width * c); + sy++; + } + + return m; + } + + uchar* data; + + // pointer to the reference counter; + // when points to user-allocated data, the pointer is NULL + int* refcount; + + int rows; + int cols; + + int c; +}; + +enum ImreadModes +{ + IMREAD_UNCHANGED = -1, + IMREAD_GRAYSCALE = 0, + IMREAD_COLOR = 1 +}; + +NCNN_EXPORT Mat imread(const std::string& path, int flags = IMREAD_COLOR); + +enum ImwriteFlags +{ + IMWRITE_JPEG_QUALITY = 1 +}; + +NCNN_EXPORT bool imwrite(const std::string& path, const Mat& m, const std::vector& params = std::vector()); + +NCNN_EXPORT void imshow(const std::string& name, const Mat& m); + +NCNN_EXPORT int waitKey(int delay = 0); + +#if NCNN_PIXEL +NCNN_EXPORT void resize(const Mat& src, Mat& dst, const Size& size, float sw = 0.f, float sh = 0.f, int flags = 0); +#endif // NCNN_PIXEL + +#if NCNN_PIXEL_DRAWING + +enum +{ + FILLED = -1 +}; + +NCNN_EXPORT void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void rectangle(Mat& img, Rect rec, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void circle(Mat& img, Point center, int radius, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void line(Mat& img, Point p0, Point p1, const Scalar& color, int thickness = 1); + +enum +{ + FONT_HERSHEY_SIMPLEX = 0 +}; + +NCNN_EXPORT void putText(Mat& img, const std::string& text, Point org, int fontFace, double fontScale, Scalar color, int thickness = 1); + +NCNN_EXPORT Size getTextSize(const std::string& text, int fontFace, double fontScale, int thickness, int* baseLine); + +#endif // NCNN_PIXEL_DRAWING + +} // namespace cv + +#if defined(_MSC_VER) || defined(__GNUC__) +#pragma pop_macro("min") +#pragma pop_macro("max") +#endif + +#endif // NCNN_SIMPLEOCV + +#endif // NCNN_SIMPLEOCV_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/simpleomp.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/simpleomp.h new file mode 100644 index 0000000..13e2452 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/simpleomp.h @@ -0,0 +1,53 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEOMP_H +#define NCNN_SIMPLEOMP_H + +#include "platform.h" + +#if NCNN_SIMPLEOMP + +#include + +// This minimal openmp runtime implementation only supports the llvm openmp abi +// and only supports #pragma omp parallel for num_threads(X) + +#ifdef __cplusplus +extern "C" { +#endif + +NCNN_EXPORT int omp_get_max_threads(); + +NCNN_EXPORT void omp_set_num_threads(int num_threads); + +NCNN_EXPORT int omp_get_dynamic(); + +NCNN_EXPORT void omp_set_dynamic(int dynamic); + +NCNN_EXPORT int omp_get_num_threads(); + +NCNN_EXPORT int omp_get_thread_num(); + +NCNN_EXPORT int kmp_get_blocktime(); + +NCNN_EXPORT void kmp_set_blocktime(int blocktime); + +#ifdef __cplusplus +} +#endif + +#endif // NCNN_SIMPLEOMP + +#endif // NCNN_SIMPLEOMP_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/simplestl.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/simplestl.h new file mode 100644 index 0000000..00ff468 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/simplestl.h @@ -0,0 +1,565 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLESTL_H +#define NCNN_SIMPLESTL_H + +#include +#include +#include + +#if !NCNN_SIMPLESTL + +#include + +#else + +// allocation functions +NCNN_EXPORT void* operator new(size_t size); +NCNN_EXPORT void* operator new[](size_t size); +// placement allocation functions +NCNN_EXPORT void* operator new(size_t size, void* ptr); +NCNN_EXPORT void* operator new[](size_t size, void* ptr); +// deallocation functions +NCNN_EXPORT void operator delete(void* ptr); +NCNN_EXPORT void operator delete[](void* ptr); +// deallocation functions since c++14 +#if __cplusplus >= 201402L +NCNN_EXPORT void operator delete(void* ptr, size_t sz); +NCNN_EXPORT void operator delete[](void* ptr, size_t sz); +#endif +// placement deallocation functions +NCNN_EXPORT void operator delete(void* ptr, void* voidptr2); +NCNN_EXPORT void operator delete[](void* ptr, void* voidptr2); + +#endif + +// minimal stl data structure implementation +namespace std { + +template +const T& max(const T& a, const T& b) +{ + return (a < b) ? b : a; +} + +template +const T& min(const T& a, const T& b) +{ + return (a > b) ? b : a; +} + +template +void swap(T& a, T& b) +{ + T temp(a); + a = b; + b = temp; +} + +template +struct pair +{ + pair() + : first(), second() + { + } + pair(const T1& t1, const T2& t2) + : first(t1), second(t2) + { + } + + T1 first; + T2 second; +}; + +template +bool operator==(const pair& x, const pair& y) +{ + return (x.first == y.first && x.second == y.second); +} +template +bool operator<(const pair& x, const pair& y) +{ + return x.first < y.first || (!(y.first < x.first) && x.second < y.second); +} +template +bool operator!=(const pair& x, const pair& y) +{ + return !(x == y); +} +template +bool operator>(const pair& x, const pair& y) +{ + return y < x; +} +template +bool operator<=(const pair& x, const pair& y) +{ + return !(y < x); +} +template +bool operator>=(const pair& x, const pair& y) +{ + return !(x < y); +} + +template +pair make_pair(const T1& t1, const T2& t2) +{ + return pair(t1, t2); +} + +template +struct node +{ + node* prev_; + node* next_; + T data_; + + node() + : prev_(0), next_(0), data_() + { + } + node(const T& t) + : prev_(0), next_(0), data_(t) + { + } +}; + +template +struct iter_list +{ + iter_list() + : curr_(0) + { + } + iter_list(node* n) + : curr_(n) + { + } + iter_list(const iter_list& i) + : curr_(i.curr_) + { + } + ~iter_list() + { + } + + iter_list& operator=(const iter_list& i) + { + curr_ = i.curr_; + return *this; + } + + T& operator*() + { + return curr_->data_; + } + T* operator->() + { + return &(curr_->data_); + } + + bool operator==(const iter_list& i) + { + return curr_ == i.curr_; + } + bool operator!=(const iter_list& i) + { + return curr_ != i.curr_; + } + + iter_list& operator++() + { + curr_ = curr_->next_; + return *this; + } + iter_list& operator--() + { + curr_ = curr_->prev_; + return *this; + } + + node* curr_; +}; + +template +struct list +{ + typedef iter_list iterator; + + list() + { + head_ = new node(); + tail_ = head_; + count_ = 0; + } + ~list() + { + clear(); + delete head_; + } + list(const list& l) + { + head_ = new node(); + tail_ = head_; + count_ = 0; + + for (iter_list i = l.begin(); i != l.end(); ++i) + { + push_back(*i); + } + } + + list& operator=(const list& l) + { + if (this == &l) + { + return *this; + } + clear(); + + for (iter_list i = l.begin(); i != l.end(); ++i) + { + push_back(*i); + } + return *this; + } + + void clear() + { + while (count_ > 0) + { + pop_front(); + } + } + + void pop_front() + { + if (count_ > 0) + { + head_ = head_->next_; + delete head_->prev_; + head_->prev_ = 0; + --count_; + } + } + + size_t size() const + { + return count_; + } + iter_list begin() const + { + return iter_list(head_); + } + iter_list end() const + { + return iter_list(tail_); + } + bool empty() const + { + return count_ == 0; + } + + void push_back(const T& t) + { + if (count_ == 0) + { + head_ = new node(t); + head_->prev_ = 0; + head_->next_ = tail_; + tail_->prev_ = head_; + count_ = 1; + } + else + { + node* temp = new node(t); + temp->prev_ = tail_->prev_; + temp->next_ = tail_; + tail_->prev_->next_ = temp; + tail_->prev_ = temp; + ++count_; + } + } + + iter_list erase(iter_list pos) + { + if (pos != end()) + { + node* temp = pos.curr_; + if (temp == head_) + { + ++pos; + temp->next_->prev_ = 0; + head_ = temp->next_; + } + else + { + --pos; + temp->next_->prev_ = temp->prev_; + temp->prev_->next_ = temp->next_; + ++pos; + } + delete temp; + --count_; + } + return pos; + } + +protected: + node* head_; + node* tail_; + size_t count_; +}; + +template +struct greater +{ + bool operator()(const T& x, const T& y) const + { + return (x > y); + } +}; + +template +struct less +{ + bool operator()(const T& x, const T& y) const + { + return (x < y); + } +}; + +template +void partial_sort(RandomAccessIter first, RandomAccessIter middle, RandomAccessIter last, Compare comp) +{ + // [TODO] heap sort should be used here, but we simply use bubble sort now + for (RandomAccessIter i = first; i < middle; ++i) + { + // bubble sort + for (RandomAccessIter j = last - 1; j > first; --j) + { + if (comp(*j, *(j - 1))) + { + swap(*j, *(j - 1)); + } + } + } +} + +template +struct vector +{ + vector() + : data_(0), size_(0), capacity_(0) + { + } + vector(const size_t new_size, const T& value = T()) + : data_(0), size_(0), capacity_(0) + { + resize(new_size, value); + } + ~vector() + { + clear(); + } + vector(const vector& v) + : data_(0), size_(0), capacity_(0) + { + resize(v.size()); + for (size_t i = 0; i < size_; i++) + { + data_[i] = v.data_[i]; + } + } + + vector& operator=(const vector& v) + { + if (this == &v) + { + return *this; + } + resize(0); + resize(v.size()); + for (size_t i = 0; i < size_; i++) + { + data_[i] = v.data_[i]; + } + return *this; + } + + void resize(const size_t new_size, const T& value = T()) + { + try_alloc(new_size); + if (new_size > size_) + { + for (size_t i = size_; i < new_size; i++) + { + new (&data_[i]) T(value); + } + } + else if (new_size < size_) + { + for (size_t i = new_size; i < size_; i++) + { + data_[i].~T(); + } + } + size_ = new_size; + } + + void clear() + { + for (size_t i = 0; i < size_; i++) + { + data_[i].~T(); + } + delete[](char*) data_; + data_ = 0; + size_ = 0; + capacity_ = 0; + } + + T* data() const + { + return data_; + } + size_t size() const + { + return size_; + } + T& operator[](size_t i) const + { + return data_[i]; + } + T* begin() const + { + return &data_[0]; + } + T* end() const + { + return &data_[size_]; + } + bool empty() const + { + return size_ == 0; + } + + void push_back(const T& t) + { + try_alloc(size_ + 1); + new (&data_[size_]) T(t); + size_++; + } + + void insert(T* pos, T* b, T* e) + { + vector* v = 0; + if (b >= begin() && b < end()) + { + //the same vector + v = new vector(*this); + b = v->begin() + (b - begin()); + e = v->begin() + (e - begin()); + } + size_t diff = pos - begin(); + try_alloc(size_ + (e - b)); + pos = begin() + diff; + memmove(pos + (e - b), pos, (end() - pos) * sizeof(T)); + size_t len = e - b; + size_ += len; + for (size_t i = 0; i < len; i++) + { + *pos = *b; + pos++; + b++; + } + delete v; + } + + T* erase(T* pos) + { + pos->~T(); + memmove(pos, pos + 1, (end() - pos - 1) * sizeof(T)); + size_--; + return pos; + } + +protected: + T* data_; + size_t size_; + size_t capacity_; + void try_alloc(size_t new_size) + { + if (new_size * 3 / 2 > capacity_ / 2) + { + capacity_ = new_size * 2; + T* new_data = (T*)new char[capacity_ * sizeof(T)]; + memset(static_cast(new_data), 0, capacity_ * sizeof(T)); + if (data_) + { + memmove(new_data, data_, sizeof(T) * size_); + delete[](char*) data_; + } + data_ = new_data; + } + } +}; + +struct NCNN_EXPORT string : public vector +{ + string() + { + } + string(const char* str) + { + size_t len = strlen(str); + resize(len); + memcpy(data_, str, len); + } + const char* c_str() const + { + return (const char*)data_; + } + bool operator==(const string& str2) const + { + return strcmp(data_, str2.data_) == 0; + } + bool operator==(const char* str2) const + { + return strcmp(data_, str2) == 0; + } + bool operator!=(const char* str2) const + { + return strcmp(data_, str2) != 0; + } + string& operator+=(const string& str1) + { + insert(end(), str1.begin(), str1.end()); + return *this; + } +}; + +inline string operator+(const string& str1, const string& str2) +{ + string str(str1); + str.insert(str.end(), str2.begin(), str2.end()); + return str; +} + +} // namespace std + +#endif // NCNN_SIMPLESTL_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/vulkan_header_fix.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/vulkan_header_fix.h new file mode 100644 index 0000000..e7a7e8e --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/include/ncnn/vulkan_header_fix.h @@ -0,0 +1,251 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_VULKAN_HEADER_FIX_H +#define NCNN_VULKAN_HEADER_FIX_H + +#include + +// This header contains new structure and function declearation to fix build with old vulkan sdk + +#if VK_HEADER_VERSION < 70 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES (VkStructureType)1000094000 +typedef enum VkSubgroupFeatureFlagBits +{ + VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001, + VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002, + VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004, + VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008, + VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010, + VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020, + VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040, + VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080, + VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 0x00000100, + VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubgroupFeatureFlagBits; +typedef VkFlags VkSubgroupFeatureFlags; +typedef struct VkPhysicalDeviceSubgroupProperties +{ + VkStructureType sType; + void* pNext; + uint32_t subgroupSize; + VkShaderStageFlags supportedStages; + VkSubgroupFeatureFlags supportedOperations; + VkBool32 quadOperationsInAllStages; +} VkPhysicalDeviceSubgroupProperties; +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES (VkStructureType)1000168000 +#define VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT (VkStructureType)1000168001 +typedef struct VkPhysicalDeviceMaintenance3Properties +{ + VkStructureType sType; + void* pNext; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceMaintenance3Properties; +typedef struct VkDescriptorSetLayoutSupport +{ + VkStructureType sType; + void* pNext; + VkBool32 supported; +} VkDescriptorSetLayoutSupport; +typedef VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; +typedef VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; +typedef void(VKAPI_PTR* PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); +#endif // VK_HEADER_VERSION < 70 + +#if VK_HEADER_VERSION < 80 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR (VkStructureType)1000177000 +typedef struct VkPhysicalDevice8BitStorageFeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; +} VkPhysicalDevice8BitStorageFeaturesKHR; +#define VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR (VkStructureType)1000109000 +#define VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR (VkStructureType)1000109001 +#define VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR (VkStructureType)1000109002 +#define VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR (VkStructureType)1000109003 +#define VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR (VkStructureType)1000109004 +#define VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR (VkStructureType)1000109005 +#define VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR (VkStructureType)1000109006 +typedef struct VkAttachmentDescription2KHR +{ + VkStructureType sType; + const void* pNext; + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription2KHR; +typedef struct VkAttachmentReference2KHR +{ + VkStructureType sType; + const void* pNext; + uint32_t attachment; + VkImageLayout layout; + VkImageAspectFlags aspectMask; +} VkAttachmentReference2KHR; +typedef struct VkSubpassDescription2KHR +{ + VkStructureType sType; + const void* pNext; + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t viewMask; + uint32_t inputAttachmentCount; + const VkAttachmentReference2KHR* pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference2KHR* pColorAttachments; + const VkAttachmentReference2KHR* pResolveAttachments; + const VkAttachmentReference2KHR* pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t* pPreserveAttachments; +} VkSubpassDescription2KHR; +typedef struct VkSubpassDependency2KHR +{ + VkStructureType sType; + const void* pNext; + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; + int32_t viewOffset; +} VkSubpassDependency2KHR; +typedef struct VkRenderPassCreateInfo2KHR +{ + VkStructureType sType; + const void* pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription2KHR* pAttachments; + uint32_t subpassCount; + const VkSubpassDescription2KHR* pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency2KHR* pDependencies; + uint32_t correlatedViewMaskCount; + const uint32_t* pCorrelatedViewMasks; +} VkRenderPassCreateInfo2KHR; +typedef struct VkSubpassBeginInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkSubpassContents contents; +} VkSubpassBeginInfoKHR; + +typedef struct VkSubpassEndInfoKHR +{ + VkStructureType sType; + const void* pNext; +} VkSubpassEndInfoKHR; +typedef VkResult(VKAPI_PTR* PFN_vkCreateRenderPass2KHR)(VkDevice device, const VkRenderPassCreateInfo2KHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void(VKAPI_PTR* PFN_vkCmdBeginRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfoKHR* pSubpassBeginInfo); +typedef void(VKAPI_PTR* PFN_vkCmdNextSubpass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfoKHR* pSubpassBeginInfo, const VkSubpassEndInfoKHR* pSubpassEndInfo); +typedef void(VKAPI_PTR* PFN_vkCmdEndRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassEndInfoKHR* pSubpassEndInfo); +#endif // VK_HEADER_VERSION < 80 + +#if VK_HEADER_VERSION < 95 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR (VkStructureType)1000082000 +typedef struct VkPhysicalDeviceFloat16Int8FeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; +} VkPhysicalDeviceFloat16Int8FeaturesKHR; +#endif // VK_HEADER_VERSION < 95 + +#if VK_HEADER_VERSION < 97 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT (VkStructureType)1000237000 +typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT +{ + VkStructureType sType; + void* pNext; + VkDeviceSize heapBudget[VK_MAX_MEMORY_HEAPS]; + VkDeviceSize heapUsage[VK_MAX_MEMORY_HEAPS]; +} VkPhysicalDeviceMemoryBudgetPropertiesEXT; +#endif // VK_HEADER_VERSION < 97 + +#if VK_HEADER_VERSION < 101 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV (VkStructureType)1000249000 +#define VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV (VkStructureType)1000249001 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV (VkStructureType)1000249002 +typedef enum VkComponentTypeNV +{ + VK_COMPONENT_TYPE_FLOAT16_NV = 0, + VK_COMPONENT_TYPE_FLOAT32_NV = 1, + VK_COMPONENT_TYPE_FLOAT64_NV = 2, + VK_COMPONENT_TYPE_SINT8_NV = 3, + VK_COMPONENT_TYPE_SINT16_NV = 4, + VK_COMPONENT_TYPE_SINT32_NV = 5, + VK_COMPONENT_TYPE_SINT64_NV = 6, + VK_COMPONENT_TYPE_UINT8_NV = 7, + VK_COMPONENT_TYPE_UINT16_NV = 8, + VK_COMPONENT_TYPE_UINT32_NV = 9, + VK_COMPONENT_TYPE_UINT64_NV = 10, + VK_COMPONENT_TYPE_BEGIN_RANGE_NV = VK_COMPONENT_TYPE_FLOAT16_NV, + VK_COMPONENT_TYPE_END_RANGE_NV = VK_COMPONENT_TYPE_UINT64_NV, + VK_COMPONENT_TYPE_RANGE_SIZE_NV = (VK_COMPONENT_TYPE_UINT64_NV - VK_COMPONENT_TYPE_FLOAT16_NV + 1), + VK_COMPONENT_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkComponentTypeNV; +typedef enum VkScopeNV +{ + VK_SCOPE_DEVICE_NV = 1, + VK_SCOPE_WORKGROUP_NV = 2, + VK_SCOPE_SUBGROUP_NV = 3, + VK_SCOPE_QUEUE_FAMILY_NV = 5, + VK_SCOPE_BEGIN_RANGE_NV = VK_SCOPE_DEVICE_NV, + VK_SCOPE_END_RANGE_NV = VK_SCOPE_QUEUE_FAMILY_NV, + VK_SCOPE_RANGE_SIZE_NV = (VK_SCOPE_QUEUE_FAMILY_NV - VK_SCOPE_DEVICE_NV + 1), + VK_SCOPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkScopeNV; +typedef struct VkCooperativeMatrixPropertiesNV +{ + VkStructureType sType; + void* pNext; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeNV AType; + VkComponentTypeNV BType; + VkComponentTypeNV CType; + VkComponentTypeNV DType; + VkScopeNV scope; +} VkCooperativeMatrixPropertiesNV; +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesNV +{ + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesNV; +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesNV +{ + VkStructureType sType; + void* pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesNV; +typedef VkResult(VKAPI_PTR* PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixPropertiesNV* pProperties); +#endif // VK_HEADER_VERSION < 101 + +#endif // NCNN_VULKAN_HEADER_FIX_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/lib/cmake/ncnn/ncnn-release.cmake b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/lib/cmake/ncnn/ncnn-release.cmake new file mode 100644 index 0000000..1fb8660 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/lib/cmake/ncnn/ncnn-release.cmake @@ -0,0 +1,19 @@ +#---------------------------------------------------------------- +# Generated CMake target import file for configuration "Release". +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "ncnn" for configuration "Release" +set_property(TARGET ncnn APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(ncnn PROPERTIES + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libncnn.so" + IMPORTED_SONAME_RELEASE "libncnn.so" + ) + +list(APPEND _cmake_import_check_targets ncnn ) +list(APPEND _cmake_import_check_files_for_ncnn "${_IMPORT_PREFIX}/lib/libncnn.so" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/lib/cmake/ncnn/ncnn.cmake b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/lib/cmake/ncnn/ncnn.cmake new file mode 100644 index 0000000..53b9fae --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/lib/cmake/ncnn/ncnn.cmake @@ -0,0 +1,109 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8) + message(FATAL_ERROR "CMake >= 2.8.0 required") +endif() +if(CMAKE_VERSION VERSION_LESS "2.8.3") + message(FATAL_ERROR "CMake >= 2.8.3 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.8.3...3.23) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_cmake_targets_defined "") +set(_cmake_targets_not_defined "") +set(_cmake_expected_targets "") +foreach(_cmake_expected_target IN ITEMS ncnn) + list(APPEND _cmake_expected_targets "${_cmake_expected_target}") + if(TARGET "${_cmake_expected_target}") + list(APPEND _cmake_targets_defined "${_cmake_expected_target}") + else() + list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") + endif() +endforeach() +unset(_cmake_expected_target) +if(_cmake_targets_defined STREQUAL _cmake_expected_targets) + unset(_cmake_targets_defined) + unset(_cmake_targets_not_defined) + unset(_cmake_expected_targets) + unset(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT _cmake_targets_defined STREQUAL "") + string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") + string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") +endif() +unset(_cmake_targets_defined) +unset(_cmake_targets_not_defined) +unset(_cmake_expected_targets) + + +# Compute the installation prefix relative to this file. +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +if(_IMPORT_PREFIX STREQUAL "/") + set(_IMPORT_PREFIX "") +endif() + +# Create imported target ncnn +add_library(ncnn SHARED IMPORTED) + +set_target_properties(ncnn PROPERTIES + INTERFACE_COMPILE_OPTIONS "-fno-rtti;-fno-exceptions" + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include/ncnn" + INTERFACE_LINK_LIBRARIES "-fopenmp;-static-openmp;-Wl,-wrap,__kmp_affinity_determine_capable;Threads::Threads;Vulkan::Vulkan;android;jnigraphics;log" + INTERFACE_POSITION_INDEPENDENT_CODE "ON" +) + +if(CMAKE_VERSION VERSION_LESS 2.8.12) + message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.") +endif() + +# Load information for each installed configuration. +file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/ncnn-*.cmake") +foreach(_cmake_config_file IN LISTS _cmake_config_files) + include("${_cmake_config_file}") +endforeach() +unset(_cmake_config_file) +unset(_cmake_config_files) + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(_cmake_target IN LISTS _cmake_import_check_targets) + foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}") + if(NOT EXISTS "${_cmake_file}") + message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file + \"${_cmake_file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + unset(_cmake_file) + unset("_cmake_import_check_files_for_${_cmake_target}") +endforeach() +unset(_cmake_target) +unset(_cmake_import_check_targets) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/lib/cmake/ncnn/ncnnConfig.cmake b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/lib/cmake/ncnn/ncnnConfig.cmake new file mode 100644 index 0000000..abb2dd6 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/lib/cmake/ncnn/ncnnConfig.cmake @@ -0,0 +1,42 @@ +set(NCNN_OPENMP ON) +set(NCNN_THREADS ON) +set(NCNN_VULKAN ON) +set(NCNN_SHARED_LIB ON) +set(NCNN_SYSTEM_GLSLANG OFF) + +if(NCNN_OPENMP) + find_package(OpenMP) +endif() + +if(NCNN_THREADS) + set(CMAKE_THREAD_PREFER_PTHREAD TRUE) + set(THREADS_PREFER_PTHREAD_FLAG TRUE) + find_package(Threads REQUIRED) +endif() + +if(NCNN_VULKAN) + find_package(Vulkan REQUIRED) + + if(NOT NCNN_SHARED_LIB) + if(NCNN_SYSTEM_GLSLANG) + find_package(glslang QUIET) + if(NOT glslang_FOUND) + set(GLSLANG_TARGET_DIR "") + include(${GLSLANG_TARGET_DIR}/OSDependentTargets.cmake) + include(${GLSLANG_TARGET_DIR}/OGLCompilerTargets.cmake) + if(EXISTS "${GLSLANG_TARGET_DIR}/HLSLTargets.cmake") + # hlsl support can be optional + include("${GLSLANG_TARGET_DIR}/HLSLTargets.cmake") + endif() + include(${GLSLANG_TARGET_DIR}/glslangTargets.cmake) + include(${GLSLANG_TARGET_DIR}/SPIRVTargets.cmake) + endif() + else() + set(glslang_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../lib/cmake/glslang") + find_package(glslang QUIET) + endif() + + endif() +endif() + +include(${CMAKE_CURRENT_LIST_DIR}/ncnn.cmake) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/lib/pkgconfig/ncnn.pc b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/lib/pkgconfig/ncnn.pc new file mode 100644 index 0000000..2ae00de --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86/lib/pkgconfig/ncnn.pc @@ -0,0 +1,11 @@ +prefix=${pcfiledir}/../.. +librarydir=${prefix}/lib +includedir=${prefix}/include + +Name: ncnn +Description: high-performance neural network inference framework optimized for the mobile platform +Version: 1.0.20221128 +URL: https://github.com/Tencent/ncnn +Libs: -L"${librarydir}" -lncnn +Cflags: -I"${includedir}" + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/allocator.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/allocator.h new file mode 100644 index 0000000..3a5ebca --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/allocator.h @@ -0,0 +1,448 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_ALLOCATOR_H +#define NCNN_ALLOCATOR_H + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include "platform.h" + +#include + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +#include +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +// the alignment of all the allocated buffers +#if NCNN_AVX512 +#define NCNN_MALLOC_ALIGN 64 +#elif NCNN_AVX +#define NCNN_MALLOC_ALIGN 32 +#else +#define NCNN_MALLOC_ALIGN 16 +#endif + +// we have some optimized kernels that may overread buffer a bit in loop +// it is common to interleave next-loop data load with arithmetic instructions +// allocating more bytes keeps us safe from SEGV_ACCERR failure +#define NCNN_MALLOC_OVERREAD 64 + +// Aligns a pointer to the specified number of bytes +// ptr Aligned pointer +// n Alignment size that must be a power of two +template +static NCNN_FORCEINLINE _Tp* alignPtr(_Tp* ptr, int n = (int)sizeof(_Tp)) +{ + return (_Tp*)(((size_t)ptr + n - 1) & -n); +} + +// Aligns a buffer size to the specified number of bytes +// The function returns the minimum number that is greater or equal to sz and is divisible by n +// sz Buffer size to align +// n Alignment size that must be a power of two +static NCNN_FORCEINLINE size_t alignSize(size_t sz, int n) +{ + return (sz + n - 1) & -n; +} + +static NCNN_FORCEINLINE void* fastMalloc(size_t size) +{ +#if _MSC_VER + return _aligned_malloc(size, NCNN_MALLOC_ALIGN); +#elif (defined(__unix__) || defined(__APPLE__)) && _POSIX_C_SOURCE >= 200112L || (__ANDROID__ && __ANDROID_API__ >= 17) + void* ptr = 0; + if (posix_memalign(&ptr, NCNN_MALLOC_ALIGN, size + NCNN_MALLOC_OVERREAD)) + ptr = 0; + return ptr; +#elif __ANDROID__ && __ANDROID_API__ < 17 + return memalign(NCNN_MALLOC_ALIGN, size + NCNN_MALLOC_OVERREAD); +#else + unsigned char* udata = (unsigned char*)malloc(size + sizeof(void*) + NCNN_MALLOC_ALIGN + NCNN_MALLOC_OVERREAD); + if (!udata) + return 0; + unsigned char** adata = alignPtr((unsigned char**)udata + 1, NCNN_MALLOC_ALIGN); + adata[-1] = udata; + return adata; +#endif +} + +static NCNN_FORCEINLINE void fastFree(void* ptr) +{ + if (ptr) + { +#if _MSC_VER + _aligned_free(ptr); +#elif (defined(__unix__) || defined(__APPLE__)) && _POSIX_C_SOURCE >= 200112L || (__ANDROID__ && __ANDROID_API__ >= 17) + free(ptr); +#elif __ANDROID__ && __ANDROID_API__ < 17 + free(ptr); +#else + unsigned char* udata = ((unsigned char**)ptr)[-1]; + free(udata); +#endif + } +} + +#if NCNN_THREADS +// exchange-add operation for atomic operations on reference counters +#if defined __riscv && !defined __riscv_atomic +// riscv target without A extension +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#elif defined __INTEL_COMPILER && !(defined WIN32 || defined _WIN32) +// atomic increment on the linux version of the Intel(tm) compiler +#define NCNN_XADD(addr, delta) (int)_InterlockedExchangeAdd(const_cast(reinterpret_cast(addr)), delta) +#elif defined __GNUC__ +#if defined __clang__ && __clang_major__ >= 3 && !defined __ANDROID__ && !defined __EMSCRIPTEN__ && !defined(__CUDACC__) +#ifdef __ATOMIC_ACQ_REL +#define NCNN_XADD(addr, delta) __c11_atomic_fetch_add((_Atomic(int)*)(addr), delta, __ATOMIC_ACQ_REL) +#else +#define NCNN_XADD(addr, delta) __atomic_fetch_add((_Atomic(int)*)(addr), delta, 4) +#endif +#else +#if defined __ATOMIC_ACQ_REL && !defined __clang__ +// version for gcc >= 4.7 +#define NCNN_XADD(addr, delta) (int)__atomic_fetch_add((unsigned*)(addr), (unsigned)(delta), __ATOMIC_ACQ_REL) +#else +#define NCNN_XADD(addr, delta) (int)__sync_fetch_and_add((unsigned*)(addr), (unsigned)(delta)) +#endif +#endif +#elif defined _MSC_VER && !defined RC_INVOKED +#define NCNN_XADD(addr, delta) (int)_InterlockedExchangeAdd((long volatile*)addr, delta) +#else +// thread-unsafe branch +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#endif +#else // NCNN_THREADS +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#endif // NCNN_THREADS + +class NCNN_EXPORT Allocator +{ +public: + virtual ~Allocator(); + virtual void* fastMalloc(size_t size) = 0; + virtual void fastFree(void* ptr) = 0; +}; + +class PoolAllocatorPrivate; +class NCNN_EXPORT PoolAllocator : public Allocator +{ +public: + PoolAllocator(); + ~PoolAllocator(); + + // ratio range 0 ~ 1 + // default cr = 0 + void set_size_compare_ratio(float scr); + + // budget drop threshold + // default threshold = 10 + void set_size_drop_threshold(size_t); + + // release all budgets immediately + void clear(); + + virtual void* fastMalloc(size_t size); + virtual void fastFree(void* ptr); + +private: + PoolAllocator(const PoolAllocator&); + PoolAllocator& operator=(const PoolAllocator&); + +private: + PoolAllocatorPrivate* const d; +}; + +class UnlockedPoolAllocatorPrivate; +class NCNN_EXPORT UnlockedPoolAllocator : public Allocator +{ +public: + UnlockedPoolAllocator(); + ~UnlockedPoolAllocator(); + + // ratio range 0 ~ 1 + // default cr = 0 + void set_size_compare_ratio(float scr); + + // budget drop threshold + // default threshold = 10 + void set_size_drop_threshold(size_t); + + // release all budgets immediately + void clear(); + + virtual void* fastMalloc(size_t size); + virtual void fastFree(void* ptr); + +private: + UnlockedPoolAllocator(const UnlockedPoolAllocator&); + UnlockedPoolAllocator& operator=(const UnlockedPoolAllocator&); + +private: + UnlockedPoolAllocatorPrivate* const d; +}; + +#if NCNN_VULKAN + +class VulkanDevice; + +class NCNN_EXPORT VkBufferMemory +{ +public: + VkBuffer buffer; + + // the base offset assigned by allocator + size_t offset; + size_t capacity; + + VkDeviceMemory memory; + void* mapped_ptr; + + // buffer state, modified by command functions internally + mutable VkAccessFlags access_flags; + mutable VkPipelineStageFlags stage_flags; + + // initialize and modified by mat + int refcount; +}; + +class NCNN_EXPORT VkImageMemory +{ +public: + VkImage image; + VkImageView imageview; + + // underlying info assigned by allocator + int width; + int height; + int depth; + VkFormat format; + + VkDeviceMemory memory; + void* mapped_ptr; + + // the base offset assigned by allocator + size_t bind_offset; + size_t bind_capacity; + + // image state, modified by command functions internally + mutable VkAccessFlags access_flags; + mutable VkImageLayout image_layout; + mutable VkPipelineStageFlags stage_flags; + + // in-execution state, modified by command functions internally + mutable int command_refcount; + + // initialize and modified by mat + int refcount; +}; + +class NCNN_EXPORT VkAllocator +{ +public: + explicit VkAllocator(const VulkanDevice* _vkdev); + virtual ~VkAllocator(); + + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size) = 0; + virtual void fastFree(VkBufferMemory* ptr) = 0; + virtual int flush(VkBufferMemory* ptr); + virtual int invalidate(VkBufferMemory* ptr); + + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack) = 0; + virtual void fastFree(VkImageMemory* ptr) = 0; + +public: + const VulkanDevice* vkdev; + uint32_t buffer_memory_type_index; + uint32_t image_memory_type_index; + uint32_t reserved_type_index; + bool mappable; + bool coherent; + +protected: + VkBuffer create_buffer(size_t size, VkBufferUsageFlags usage); + VkDeviceMemory allocate_memory(size_t size, uint32_t memory_type_index); + VkDeviceMemory allocate_dedicated_memory(size_t size, uint32_t memory_type_index, VkImage image, VkBuffer buffer); + + VkImage create_image(int width, int height, int depth, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage); + VkImageView create_imageview(VkImage image, VkFormat format); +}; + +class VkBlobAllocatorPrivate; +class NCNN_EXPORT VkBlobAllocator : public VkAllocator +{ +public: + explicit VkBlobAllocator(const VulkanDevice* vkdev, size_t preferred_block_size = 16 * 1024 * 1024); // 16M + virtual ~VkBlobAllocator(); + +public: + // release all budgets immediately + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkBlobAllocator(const VkBlobAllocator&); + VkBlobAllocator& operator=(const VkBlobAllocator&); + +private: + VkBlobAllocatorPrivate* const d; +}; + +class VkWeightAllocatorPrivate; +class NCNN_EXPORT VkWeightAllocator : public VkAllocator +{ +public: + explicit VkWeightAllocator(const VulkanDevice* vkdev, size_t preferred_block_size = 8 * 1024 * 1024); // 8M + virtual ~VkWeightAllocator(); + +public: + // release all blocks immediately + virtual void clear(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkWeightAllocator(const VkWeightAllocator&); + VkWeightAllocator& operator=(const VkWeightAllocator&); + +private: + VkWeightAllocatorPrivate* const d; +}; + +class VkStagingAllocatorPrivate; +class NCNN_EXPORT VkStagingAllocator : public VkAllocator +{ +public: + explicit VkStagingAllocator(const VulkanDevice* vkdev); + virtual ~VkStagingAllocator(); + +public: + // ratio range 0 ~ 1 + // default cr = 0.75 + void set_size_compare_ratio(float scr); + + // release all budgets immediately + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkStagingAllocator(const VkStagingAllocator&); + VkStagingAllocator& operator=(const VkStagingAllocator&); + +private: + VkStagingAllocatorPrivate* const d; +}; + +class VkWeightStagingAllocatorPrivate; +class NCNN_EXPORT VkWeightStagingAllocator : public VkAllocator +{ +public: + explicit VkWeightStagingAllocator(const VulkanDevice* vkdev); + virtual ~VkWeightStagingAllocator(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkWeightStagingAllocator(const VkWeightStagingAllocator&); + VkWeightStagingAllocator& operator=(const VkWeightStagingAllocator&); + +private: + VkWeightStagingAllocatorPrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class NCNN_EXPORT VkAndroidHardwareBufferImageAllocator : public VkAllocator +{ +public: + VkAndroidHardwareBufferImageAllocator(const VulkanDevice* _vkdev, AHardwareBuffer* _hb); + virtual ~VkAndroidHardwareBufferImageAllocator(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkAndroidHardwareBufferImageAllocator(const VkAndroidHardwareBufferImageAllocator&); + VkAndroidHardwareBufferImageAllocator& operator=(const VkAndroidHardwareBufferImageAllocator&); + +public: + int init(); + + int width() const; + int height() const; + uint64_t external_format() const; + +public: + AHardwareBuffer* hb; + AHardwareBuffer_Desc bufferDesc; + VkAndroidHardwareBufferFormatPropertiesANDROID bufferFormatProperties; + VkAndroidHardwareBufferPropertiesANDROID bufferProperties; + VkSamplerYcbcrConversionKHR samplerYcbcrConversion; +}; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_ALLOCATOR_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/benchmark.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/benchmark.h new file mode 100644 index 0000000..3d5c0cd --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/benchmark.h @@ -0,0 +1,36 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_BENCHMARK_H +#define NCNN_BENCHMARK_H + +#include "layer.h" +#include "mat.h" +#include "platform.h" + +namespace ncnn { + +// get now timestamp in ms +NCNN_EXPORT double get_current_time(); + +#if NCNN_BENCHMARK + +NCNN_EXPORT void benchmark(const Layer* layer, double start, double end); +NCNN_EXPORT void benchmark(const Layer* layer, const Mat& bottom_blob, Mat& top_blob, double start, double end); + +#endif // NCNN_BENCHMARK + +} // namespace ncnn + +#endif // NCNN_BENCHMARK_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/blob.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/blob.h new file mode 100644 index 0000000..c9f144f --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/blob.h @@ -0,0 +1,44 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_BLOB_H +#define NCNN_BLOB_H + +#include "mat.h" +#include "platform.h" + +namespace ncnn { + +class NCNN_EXPORT Blob +{ +public: + // empty + Blob(); + +public: +#if NCNN_STRING + // blob name + std::string name; +#endif // NCNN_STRING + // layer index which produce this blob as output + int producer; + // layer index which need this blob as input + int consumer; + // shape hint + Mat shape; +}; + +} // namespace ncnn + +#endif // NCNN_BLOB_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/c_api.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/c_api.h new file mode 100644 index 0000000..b7435f8 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/c_api.h @@ -0,0 +1,327 @@ +/* Tencent is pleased to support the open source community by making ncnn available. + * + * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef NCNN_C_API_H +#define NCNN_C_API_H + +#include "platform.h" + +#if NCNN_C_API + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +NCNN_EXPORT const char* ncnn_version(); + +/* allocator api */ +typedef struct __ncnn_allocator_t* ncnn_allocator_t; +struct NCNN_EXPORT __ncnn_allocator_t +{ + void* pthis; + + void* (*fast_malloc)(ncnn_allocator_t allocator, size_t size); + void (*fast_free)(ncnn_allocator_t allocator, void* ptr); +}; + +NCNN_EXPORT ncnn_allocator_t ncnn_allocator_create_pool_allocator(); +NCNN_EXPORT ncnn_allocator_t ncnn_allocator_create_unlocked_pool_allocator(); +NCNN_EXPORT void ncnn_allocator_destroy(ncnn_allocator_t allocator); + +/* option api */ +typedef struct __ncnn_option_t* ncnn_option_t; + +NCNN_EXPORT ncnn_option_t ncnn_option_create(); +NCNN_EXPORT void ncnn_option_destroy(ncnn_option_t opt); + +NCNN_EXPORT int ncnn_option_get_num_threads(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_num_threads(ncnn_option_t opt, int num_threads); + +NCNN_EXPORT int ncnn_option_get_use_local_pool_allocator(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_use_local_pool_allocator(ncnn_option_t opt, int use_local_pool_allocator); + +NCNN_EXPORT void ncnn_option_set_blob_allocator(ncnn_option_t opt, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_option_set_workspace_allocator(ncnn_option_t opt, ncnn_allocator_t allocator); + +NCNN_EXPORT int ncnn_option_get_use_vulkan_compute(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_use_vulkan_compute(ncnn_option_t opt, int use_vulkan_compute); + +/* mat api */ +typedef struct __ncnn_mat_t* ncnn_mat_t; + +NCNN_EXPORT ncnn_mat_t ncnn_mat_create(); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_1d(int w, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_2d(int w, int h, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_3d(int w, int h, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_4d(int w, int h, int d, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_1d(int w, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_2d(int w, int h, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_3d(int w, int h, int c, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_4d(int w, int h, int d, int c, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_1d_elem(int w, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_2d_elem(int w, int h, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_3d_elem(int w, int h, int c, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_4d_elem(int w, int h, int d, int c, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_1d_elem(int w, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_2d_elem(int w, int h, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_3d_elem(int w, int h, int c, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_4d_elem(int w, int h, int d, int c, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_mat_destroy(ncnn_mat_t mat); + +NCNN_EXPORT void ncnn_mat_fill_float(ncnn_mat_t mat, float v); + +NCNN_EXPORT ncnn_mat_t ncnn_mat_clone(const ncnn_mat_t mat, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_1d(const ncnn_mat_t mat, int w, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_2d(const ncnn_mat_t mat, int w, int h, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_3d(const ncnn_mat_t mat, int w, int h, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_4d(const ncnn_mat_t mat, int w, int h, int d, int c, ncnn_allocator_t allocator); + +NCNN_EXPORT int ncnn_mat_get_dims(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_w(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_h(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_d(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_c(const ncnn_mat_t mat); +NCNN_EXPORT size_t ncnn_mat_get_elemsize(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_elempack(const ncnn_mat_t mat); +NCNN_EXPORT size_t ncnn_mat_get_cstep(const ncnn_mat_t mat); +NCNN_EXPORT void* ncnn_mat_get_data(const ncnn_mat_t mat); + +NCNN_EXPORT void* ncnn_mat_get_channel_data(const ncnn_mat_t mat, int c); + +#if NCNN_PIXEL + +/* mat pixel api */ +#define NCNN_MAT_PIXEL_RGB 1 +#define NCNN_MAT_PIXEL_BGR 2 +#define NCNN_MAT_PIXEL_GRAY 3 +#define NCNN_MAT_PIXEL_RGBA 4 +#define NCNN_MAT_PIXEL_BGRA 5 +#define NCNN_MAT_PIXEL_X2Y(X, Y) (X | (Y << 16)) +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels(const unsigned char* pixels, int type, int w, int h, int stride, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, int target_width, int target_height, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_mat_to_pixels(const ncnn_mat_t mat, unsigned char* pixels, int type, int stride); +NCNN_EXPORT void ncnn_mat_to_pixels_resize(const ncnn_mat_t mat, unsigned char* pixels, int type, int target_width, int target_height, int target_stride); + +#endif /* NCNN_PIXEL */ + +NCNN_EXPORT void ncnn_mat_substract_mean_normalize(ncnn_mat_t mat, const float* mean_vals, const float* norm_vals); + +NCNN_EXPORT void ncnn_convert_packing(const ncnn_mat_t src, ncnn_mat_t* dst, int elempack, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_flatten(const ncnn_mat_t src, ncnn_mat_t* dst, const ncnn_option_t opt); + +/* blob api */ +typedef struct __ncnn_blob_t* ncnn_blob_t; + +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_blob_get_name(const ncnn_blob_t blob); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_blob_get_producer(const ncnn_blob_t blob); +NCNN_EXPORT int ncnn_blob_get_consumer(const ncnn_blob_t blob); + +NCNN_EXPORT void ncnn_blob_get_shape(const ncnn_blob_t blob, int* dims, int* w, int* h, int* c); + +/* paramdict api */ +typedef struct __ncnn_paramdict_t* ncnn_paramdict_t; + +NCNN_EXPORT ncnn_paramdict_t ncnn_paramdict_create(); +NCNN_EXPORT void ncnn_paramdict_destroy(ncnn_paramdict_t pd); + +NCNN_EXPORT int ncnn_paramdict_get_type(const ncnn_paramdict_t pd, int id); + +NCNN_EXPORT int ncnn_paramdict_get_int(const ncnn_paramdict_t pd, int id, int def); +NCNN_EXPORT float ncnn_paramdict_get_float(const ncnn_paramdict_t pd, int id, float def); +NCNN_EXPORT ncnn_mat_t ncnn_paramdict_get_array(const ncnn_paramdict_t pd, int id, const ncnn_mat_t def); + +NCNN_EXPORT void ncnn_paramdict_set_int(ncnn_paramdict_t pd, int id, int i); +NCNN_EXPORT void ncnn_paramdict_set_float(ncnn_paramdict_t pd, int id, float f); +NCNN_EXPORT void ncnn_paramdict_set_array(ncnn_paramdict_t pd, int id, const ncnn_mat_t v); + +/* datareader api */ +typedef struct __ncnn_datareader_t* ncnn_datareader_t; +struct NCNN_EXPORT __ncnn_datareader_t +{ + void* pthis; + +#if NCNN_STRING + int (*scan)(ncnn_datareader_t dr, const char* format, void* p); +#endif /* NCNN_STRING */ + size_t (*read)(ncnn_datareader_t dr, void* buf, size_t size); +}; + +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create(); +#if NCNN_STDIO +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create_from_stdio(FILE* fp); +#endif /* NCNN_STDIO */ +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create_from_memory(const unsigned char** mem); +NCNN_EXPORT void ncnn_datareader_destroy(ncnn_datareader_t dr); + +/* modelbin api */ +typedef struct __ncnn_modelbin_t* ncnn_modelbin_t; +struct NCNN_EXPORT __ncnn_modelbin_t +{ + void* pthis; + + ncnn_mat_t (*load_1d)(const ncnn_modelbin_t mb, int w, int type); + ncnn_mat_t (*load_2d)(const ncnn_modelbin_t mb, int w, int h, int type); + ncnn_mat_t (*load_3d)(const ncnn_modelbin_t mb, int w, int h, int c, int type); +}; + +NCNN_EXPORT ncnn_modelbin_t ncnn_modelbin_create_from_datareader(const ncnn_datareader_t dr); +NCNN_EXPORT ncnn_modelbin_t ncnn_modelbin_create_from_mat_array(const ncnn_mat_t* weights, int n); +NCNN_EXPORT void ncnn_modelbin_destroy(ncnn_modelbin_t mb); + +/* layer api */ +typedef struct __ncnn_layer_t* ncnn_layer_t; +struct NCNN_EXPORT __ncnn_layer_t +{ + void* pthis; + + int (*load_param)(ncnn_layer_t layer, const ncnn_paramdict_t pd); + int (*load_model)(ncnn_layer_t layer, const ncnn_modelbin_t mb); + + int (*create_pipeline)(ncnn_layer_t layer, const ncnn_option_t opt); + int (*destroy_pipeline)(ncnn_layer_t layer, const ncnn_option_t opt); + + int (*forward_1)(const ncnn_layer_t layer, const ncnn_mat_t bottom_blob, ncnn_mat_t* top_blob, const ncnn_option_t opt); + int (*forward_n)(const ncnn_layer_t layer, const ncnn_mat_t* bottom_blobs, int n, ncnn_mat_t* top_blobs, int n2, const ncnn_option_t opt); + + int (*forward_inplace_1)(const ncnn_layer_t layer, ncnn_mat_t bottom_top_blob, const ncnn_option_t opt); + int (*forward_inplace_n)(const ncnn_layer_t layer, ncnn_mat_t* bottom_top_blobs, int n, const ncnn_option_t opt); +}; + +NCNN_EXPORT ncnn_layer_t ncnn_layer_create(); +NCNN_EXPORT ncnn_layer_t ncnn_layer_create_by_typeindex(int typeindex); +#if NCNN_STRING +NCNN_EXPORT ncnn_layer_t ncnn_layer_create_by_type(const char* type); +#endif /* NCNN_STRING */ +NCNN_EXPORT void ncnn_layer_destroy(ncnn_layer_t layer); + +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_layer_get_name(const ncnn_layer_t layer); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_layer_get_typeindex(const ncnn_layer_t layer); +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_layer_get_type(const ncnn_layer_t layer); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_layer_get_one_blob_only(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_inplace(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_vulkan(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_packing(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_bf16_storage(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_fp16_storage(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_image_storage(const ncnn_layer_t layer); + +NCNN_EXPORT void ncnn_layer_set_one_blob_only(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_inplace(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_vulkan(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_packing(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_bf16_storage(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_fp16_storage(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_image_storage(ncnn_layer_t layer, int enable); + +NCNN_EXPORT int ncnn_layer_get_bottom_count(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_bottom(const ncnn_layer_t layer, int i); +NCNN_EXPORT int ncnn_layer_get_top_count(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_top(const ncnn_layer_t layer, int i); + +NCNN_EXPORT void ncnn_blob_get_bottom_shape(const ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c); +NCNN_EXPORT void ncnn_blob_get_top_shape(const ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c); + +/* layer factory function */ +typedef ncnn_layer_t (*ncnn_layer_creator_t)(void* userdata); +typedef void (*ncnn_layer_destroyer_t)(ncnn_layer_t layer, void* userdata); + +typedef struct __ncnn_net_custom_layer_factory_t* ncnn_net_custom_layer_factory_t; +struct __ncnn_net_custom_layer_factory_t +{ + ncnn_layer_creator_t creator; + ncnn_layer_destroyer_t destroyer; + void* userdata; + ncnn_net_custom_layer_factory_t next; +}; + +/* net api */ +typedef struct __ncnn_net_t* ncnn_net_t; +struct __ncnn_net_t +{ + void* pthis; + + ncnn_net_custom_layer_factory_t custom_layer_factory; +}; + +NCNN_EXPORT ncnn_net_t ncnn_net_create(); +NCNN_EXPORT void ncnn_net_destroy(ncnn_net_t net); + +NCNN_EXPORT ncnn_option_t ncnn_net_get_option(ncnn_net_t net); +NCNN_EXPORT void ncnn_net_set_option(ncnn_net_t net, ncnn_option_t opt); + +#if NCNN_STRING +NCNN_EXPORT void ncnn_net_register_custom_layer_by_type(ncnn_net_t net, const char* type, ncnn_layer_creator_t creator, ncnn_layer_destroyer_t destroyer, void* userdata); +#endif /* NCNN_STRING */ +NCNN_EXPORT void ncnn_net_register_custom_layer_by_typeindex(ncnn_net_t net, int typeindex, ncnn_layer_creator_t creator, ncnn_layer_destroyer_t destroyer, void* userdata); + +#if NCNN_STDIO +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param(ncnn_net_t net, const char* path); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_load_param_bin(ncnn_net_t net, const char* path); +NCNN_EXPORT int ncnn_net_load_model(ncnn_net_t net, const char* path); +#endif /* NCNN_STDIO */ + +#if NCNN_STDIO +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param_memory(ncnn_net_t net, const char* mem); +#endif /* NCNN_STRING */ +#endif /* NCNN_STDIO */ +NCNN_EXPORT int ncnn_net_load_param_bin_memory(ncnn_net_t net, const unsigned char* mem); +NCNN_EXPORT int ncnn_net_load_model_memory(ncnn_net_t net, const unsigned char* mem); + +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param_datareader(ncnn_net_t net, const ncnn_datareader_t dr); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_load_param_bin_datareader(ncnn_net_t net, const ncnn_datareader_t dr); +NCNN_EXPORT int ncnn_net_load_model_datareader(ncnn_net_t net, const ncnn_datareader_t dr); + +NCNN_EXPORT void ncnn_net_clear(ncnn_net_t net); + +/* extractor api */ +typedef struct __ncnn_extractor_t* ncnn_extractor_t; + +NCNN_EXPORT ncnn_extractor_t ncnn_extractor_create(ncnn_net_t net); +NCNN_EXPORT void ncnn_extractor_destroy(ncnn_extractor_t ex); + +NCNN_EXPORT void ncnn_extractor_set_option(ncnn_extractor_t ex, const ncnn_option_t opt); + +#if NCNN_STRING +NCNN_EXPORT int ncnn_extractor_input(ncnn_extractor_t ex, const char* name, const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_extractor_extract(ncnn_extractor_t ex, const char* name, ncnn_mat_t* mat); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_extractor_input_index(ncnn_extractor_t ex, int index, const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_extractor_extract_index(ncnn_extractor_t ex, int index, ncnn_mat_t* mat); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* NCNN_C_API */ + +#endif /* NCNN_C_API_H */ diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/command.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/command.h new file mode 100644 index 0000000..337d085 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/command.h @@ -0,0 +1,136 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_COMMAND_H +#define NCNN_COMMAND_H + +#include "platform.h" + +#if NCNN_VULKAN + +#include "mat.h" + +#include + +namespace ncnn { + +class Pipeline; +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class ImportAndroidHardwareBufferPipeline; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API +class VkComputePrivate; +class NCNN_EXPORT VkCompute +{ +public: + explicit VkCompute(const VulkanDevice* vkdev); + virtual ~VkCompute(); + +public: + void record_upload(const Mat& src, VkMat& dst, const Option& opt); + + void record_upload(const Mat& src, VkImageMat& dst, const Option& opt); + + void record_download(const VkMat& src, Mat& dst, const Option& opt); + + void record_download(const VkImageMat& src, Mat& dst, const Option& opt); + + void record_buffer_to_image(const VkMat& src, VkImageMat& dst, const Option& opt); + + void record_image_to_buffer(const VkImageMat& src, VkMat& dst, const Option& opt); + + void record_clone(const Mat& src, VkMat& dst, const Option& opt); + + void record_clone(const Mat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkMat& src, Mat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, Mat& dst, const Option& opt); + + void record_clone(const VkMat& src, VkMat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkMat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, VkMat& dst, const Option& opt); + + void record_pipeline(const Pipeline* pipeline, const std::vector& bindings, const std::vector& constants, const VkMat& dispatcher); + + void record_pipeline(const Pipeline* pipeline, const std::vector& bindings, const std::vector& constants, const VkImageMat& dispatcher); + + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const VkMat& dispatcher); + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const VkImageMat& dispatcher); + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const Mat& dispatcher); + +#if NCNN_BENCHMARK + void record_write_timestamp(uint32_t query); +#endif // NCNN_BENCHMARK + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 + void record_import_android_hardware_buffer(const ImportAndroidHardwareBufferPipeline* pipeline, const VkImageMat& src, const VkMat& dst); + + void record_import_android_hardware_buffer(const ImportAndroidHardwareBufferPipeline* pipeline, const VkImageMat& src, const VkImageMat& dst); +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + + int submit_and_wait(); + + int reset(); + +#if NCNN_BENCHMARK + int create_query_pool(uint32_t query_count); + + int get_query_pool_results(uint32_t first_query, uint32_t query_count, std::vector& results); +#endif // NCNN_BENCHMARK + +protected: + const VulkanDevice* vkdev; + + void barrier_readwrite(const VkMat& binding); + void barrier_readwrite(const VkImageMat& binding); + void barrier_readonly(const VkImageMat& binding); + +private: + VkComputePrivate* const d; +}; + +class VkTransferPrivate; +class NCNN_EXPORT VkTransfer +{ +public: + explicit VkTransfer(const VulkanDevice* vkdev); + virtual ~VkTransfer(); + +public: + void record_upload(const Mat& src, VkMat& dst, const Option& opt, bool flatten = true); + + void record_upload(const Mat& src, VkImageMat& dst, const Option& opt); + + int submit_and_wait(); + +protected: + const VulkanDevice* vkdev; + +private: + VkTransferPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_VULKAN + +#endif // NCNN_COMMAND_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/cpu.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/cpu.h new file mode 100644 index 0000000..0f748f3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/cpu.h @@ -0,0 +1,169 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_CPU_H +#define NCNN_CPU_H + +#include + +#if (defined _WIN32 && !(defined __MINGW32__)) +#define WIN32_LEAN_AND_MEAN +#include +#endif +#if defined __ANDROID__ || defined __linux__ +#include // cpu_set_t +#endif + +#include "platform.h" + +namespace ncnn { + +class NCNN_EXPORT CpuSet +{ +public: + CpuSet(); + void enable(int cpu); + void disable(int cpu); + void disable_all(); + bool is_enabled(int cpu) const; + int num_enabled() const; + +public: +#if (defined _WIN32 && !(defined __MINGW32__)) + ULONG_PTR mask; +#endif +#if defined __ANDROID__ || defined __linux__ + cpu_set_t cpu_set; +#endif +#if __APPLE__ + unsigned int policy; +#endif +}; + +// test optional cpu features +// edsp = armv7 edsp +NCNN_EXPORT int cpu_support_arm_edsp(); +// neon = armv7 neon or aarch64 asimd +NCNN_EXPORT int cpu_support_arm_neon(); +// vfpv4 = armv7 fp16 + fma +NCNN_EXPORT int cpu_support_arm_vfpv4(); +// asimdhp = aarch64 asimd half precision +NCNN_EXPORT int cpu_support_arm_asimdhp(); +// asimddp = aarch64 asimd dot product +NCNN_EXPORT int cpu_support_arm_asimddp(); +// asimdfhm = aarch64 asimd fhm +NCNN_EXPORT int cpu_support_arm_asimdfhm(); +// bf16 = aarch64 bf16 +NCNN_EXPORT int cpu_support_arm_bf16(); +// i8mm = aarch64 i8mm +NCNN_EXPORT int cpu_support_arm_i8mm(); +// sve = aarch64 sve +NCNN_EXPORT int cpu_support_arm_sve(); +// sve2 = aarch64 sve2 +NCNN_EXPORT int cpu_support_arm_sve2(); +// svebf16 = aarch64 svebf16 +NCNN_EXPORT int cpu_support_arm_svebf16(); +// svei8mm = aarch64 svei8mm +NCNN_EXPORT int cpu_support_arm_svei8mm(); +// svef32mm = aarch64 svef32mm +NCNN_EXPORT int cpu_support_arm_svef32mm(); + +// avx = x86 avx +NCNN_EXPORT int cpu_support_x86_avx(); +// fma = x86 fma +NCNN_EXPORT int cpu_support_x86_fma(); +// xop = x86 xop +NCNN_EXPORT int cpu_support_x86_xop(); +// f16c = x86 f16c +NCNN_EXPORT int cpu_support_x86_f16c(); +// avx2 = x86 avx2 + fma + f16c +NCNN_EXPORT int cpu_support_x86_avx2(); +// avx_vnni = x86 avx vnni +NCNN_EXPORT int cpu_support_x86_avx_vnni(); +// avx512 = x86 avx512f + avx512cd + avx512bw + avx512dq + avx512vl +NCNN_EXPORT int cpu_support_x86_avx512(); +// avx512_vnni = x86 avx512 vnni +NCNN_EXPORT int cpu_support_x86_avx512_vnni(); +// avx512_bf16 = x86 avx512 bf16 +NCNN_EXPORT int cpu_support_x86_avx512_bf16(); +// avx512_fp16 = x86 avx512 fp16 +NCNN_EXPORT int cpu_support_x86_avx512_fp16(); + +// lsx = loongarch lsx +NCNN_EXPORT int cpu_support_loongarch_lsx(); +// lasx = loongarch lasx +NCNN_EXPORT int cpu_support_loongarch_lasx(); + +// msa = mips mas +NCNN_EXPORT int cpu_support_mips_msa(); +// mmi = loongson mmi +NCNN_EXPORT int cpu_support_loongson_mmi(); + +// v = riscv vector +NCNN_EXPORT int cpu_support_riscv_v(); +// zfh = riscv half-precision float +NCNN_EXPORT int cpu_support_riscv_zfh(); +// vlenb = riscv vector length in bytes +NCNN_EXPORT int cpu_riscv_vlenb(); + +// cpu info +NCNN_EXPORT int get_cpu_count(); +NCNN_EXPORT int get_little_cpu_count(); +NCNN_EXPORT int get_big_cpu_count(); + +NCNN_EXPORT int get_physical_cpu_count(); +NCNN_EXPORT int get_physical_little_cpu_count(); +NCNN_EXPORT int get_physical_big_cpu_count(); + +// bind all threads on little clusters if powersave enabled +// affects HMP arch cpu like ARM big.LITTLE +// only implemented on android at the moment +// switching powersave is expensive and not thread-safe +// 0 = all cores enabled(default) +// 1 = only little clusters enabled +// 2 = only big clusters enabled +// return 0 if success for setter function +NCNN_EXPORT int get_cpu_powersave(); +NCNN_EXPORT int set_cpu_powersave(int powersave); + +// convenient wrapper +NCNN_EXPORT const CpuSet& get_cpu_thread_affinity_mask(int powersave); + +// set explicit thread affinity +NCNN_EXPORT int set_cpu_thread_affinity(const CpuSet& thread_affinity_mask); + +// misc function wrapper for openmp routines +NCNN_EXPORT int get_omp_num_threads(); +NCNN_EXPORT void set_omp_num_threads(int num_threads); + +NCNN_EXPORT int get_omp_dynamic(); +NCNN_EXPORT void set_omp_dynamic(int dynamic); + +NCNN_EXPORT int get_omp_thread_num(); + +NCNN_EXPORT int get_kmp_blocktime(); +NCNN_EXPORT void set_kmp_blocktime(int time_ms); + +// need to flush denormals on Intel Chipset. +// Other architectures such as ARM can be added as needed. +// 0 = DAZ OFF, FTZ OFF +// 1 = DAZ ON , FTZ OFF +// 2 = DAZ OFF, FTZ ON +// 3 = DAZ ON, FTZ ON +NCNN_EXPORT int get_flush_denormals(); +NCNN_EXPORT int set_flush_denormals(int flush_denormals); + +} // namespace ncnn + +#endif // NCNN_CPU_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/datareader.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/datareader.h new file mode 100644 index 0000000..ed2aba3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/datareader.h @@ -0,0 +1,122 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_DATAREADER_H +#define NCNN_DATAREADER_H + +#include "platform.h" +#if NCNN_STDIO +#include +#endif + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#endif +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +// data read wrapper +class NCNN_EXPORT DataReader +{ +public: + DataReader(); + virtual ~DataReader(); + +#if NCNN_STRING + // parse plain param text + // return 1 if scan success + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + + // read binary param and model data + // return bytes read + virtual size_t read(void* buf, size_t size) const; + + // get model data reference + // return bytes referenced + virtual size_t reference(size_t size, const void** buf) const; +}; + +#if NCNN_STDIO +class DataReaderFromStdioPrivate; +class NCNN_EXPORT DataReaderFromStdio : public DataReader +{ +public: + explicit DataReaderFromStdio(FILE* fp); + virtual ~DataReaderFromStdio(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + +private: + DataReaderFromStdio(const DataReaderFromStdio&); + DataReaderFromStdio& operator=(const DataReaderFromStdio&); + +private: + DataReaderFromStdioPrivate* const d; +}; +#endif // NCNN_STDIO + +class DataReaderFromMemoryPrivate; +class NCNN_EXPORT DataReaderFromMemory : public DataReader +{ +public: + explicit DataReaderFromMemory(const unsigned char*& mem); + virtual ~DataReaderFromMemory(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + virtual size_t reference(size_t size, const void** buf) const; + +private: + DataReaderFromMemory(const DataReaderFromMemory&); + DataReaderFromMemory& operator=(const DataReaderFromMemory&); + +private: + DataReaderFromMemoryPrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +class DataReaderFromAndroidAssetPrivate; +class NCNN_EXPORT DataReaderFromAndroidAsset : public DataReader +{ +public: + explicit DataReaderFromAndroidAsset(AAsset* asset); + virtual ~DataReaderFromAndroidAsset(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + +private: + DataReaderFromAndroidAsset(const DataReaderFromAndroidAsset&); + DataReaderFromAndroidAsset& operator=(const DataReaderFromAndroidAsset&); + +private: + DataReaderFromAndroidAssetPrivate* const d; +}; +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + +} // namespace ncnn + +#endif // NCNN_DATAREADER_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/gpu.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/gpu.h new file mode 100644 index 0000000..2ef4927 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/gpu.h @@ -0,0 +1,359 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_GPU_H +#define NCNN_GPU_H + +#include "platform.h" + +#if NCNN_VULKAN + +#include "mat.h" + +#include + +#include "vulkan_header_fix.h" + +namespace ncnn { + +// instance +NCNN_EXPORT int create_gpu_instance(); +NCNN_EXPORT void destroy_gpu_instance(); + +// instance extension capability +extern int support_VK_KHR_external_memory_capabilities; +extern int support_VK_KHR_get_physical_device_properties2; +extern int support_VK_KHR_get_surface_capabilities2; +extern int support_VK_KHR_surface; +extern int support_VK_EXT_debug_utils; +#if __ANDROID_API__ >= 26 +extern int support_VK_KHR_android_surface; +#endif // __ANDROID_API__ >= 26 + +// VK_KHR_external_memory_capabilities +extern PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR vkGetPhysicalDeviceExternalBufferPropertiesKHR; + +// VK_KHR_get_physical_device_properties2 +extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; +extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; +extern PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceImageFormatProperties2KHR vkGetPhysicalDeviceImageFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR; +extern PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR; +extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR vkGetPhysicalDeviceSparseImageFormatProperties2KHR; + +// VK_KHR_get_surface_capabilities2 +extern PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR; + +// VK_KHR_surface +extern PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; +extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; +extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; +extern PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; + +#if __ANDROID_API__ >= 26 +// VK_KHR_android_surface +extern PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; +#endif // __ANDROID_API__ >= 26 + +// VK_NV_cooperative_matrix +extern PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV vkGetPhysicalDeviceCooperativeMatrixPropertiesNV; + +// get info +NCNN_EXPORT int get_gpu_count(); +NCNN_EXPORT int get_default_gpu_index(); + +class GpuInfoPrivate; +class NCNN_EXPORT GpuInfo +{ +public: + explicit GpuInfo(); + virtual ~GpuInfo(); + + // vulkan physical device + VkPhysicalDevice physical_device() const; + + // memory properties + const VkPhysicalDeviceMemoryProperties& physical_device_memory_properties() const; + + // info + uint32_t api_version() const; + uint32_t driver_version() const; + uint32_t vendor_id() const; + uint32_t device_id() const; + const char* device_name() const; + uint8_t* pipeline_cache_uuid() const; + + // 0 = discrete gpu + // 1 = integrated gpu + // 2 = virtual gpu + // 3 = cpu + int type() const; + + // hardware limit + uint32_t max_shared_memory_size() const; + uint32_t max_workgroup_count_x() const; + uint32_t max_workgroup_count_y() const; + uint32_t max_workgroup_count_z() const; + uint32_t max_workgroup_invocations() const; + uint32_t max_workgroup_size_x() const; + uint32_t max_workgroup_size_y() const; + uint32_t max_workgroup_size_z() const; + size_t memory_map_alignment() const; + size_t buffer_offset_alignment() const; + size_t non_coherent_atom_size() const; + size_t buffer_image_granularity() const; + uint32_t max_image_dimension_1d() const; + uint32_t max_image_dimension_2d() const; + uint32_t max_image_dimension_3d() const; + float timestamp_period() const; + + // runtime + uint32_t compute_queue_family_index() const; + uint32_t graphics_queue_family_index() const; + uint32_t transfer_queue_family_index() const; + + uint32_t compute_queue_count() const; + uint32_t graphics_queue_count() const; + uint32_t transfer_queue_count() const; + + // property + bool unified_compute_transfer_queue() const; + + // subgroup + uint32_t subgroup_size() const; + bool support_subgroup_basic() const; + bool support_subgroup_vote() const; + bool support_subgroup_ballot() const; + bool support_subgroup_shuffle() const; + + // bug is not feature + bool bug_storage_buffer_no_l1() const; + bool bug_corrupted_online_pipeline_cache() const; + bool bug_buffer_image_load_zero() const; + + // but sometimes bug is a feature + bool bug_implicit_fp16_arithmetic() const; + + // fp16 and int8 feature + bool support_fp16_packed() const; + bool support_fp16_storage() const; + bool support_fp16_arithmetic() const; + bool support_int8_packed() const; + bool support_int8_storage() const; + bool support_int8_arithmetic() const; + + // ycbcr conversion feature + bool support_ycbcr_conversion() const; + + // cooperative matrix feature + bool support_cooperative_matrix() const; + bool support_cooperative_matrix_16_8_8() const; + + // extension capability + int support_VK_KHR_8bit_storage() const; + int support_VK_KHR_16bit_storage() const; + int support_VK_KHR_bind_memory2() const; + int support_VK_KHR_create_renderpass2() const; + int support_VK_KHR_dedicated_allocation() const; + int support_VK_KHR_descriptor_update_template() const; + int support_VK_KHR_external_memory() const; + int support_VK_KHR_get_memory_requirements2() const; + int support_VK_KHR_maintenance1() const; + int support_VK_KHR_maintenance2() const; + int support_VK_KHR_maintenance3() const; + int support_VK_KHR_multiview() const; + int support_VK_KHR_push_descriptor() const; + int support_VK_KHR_sampler_ycbcr_conversion() const; + int support_VK_KHR_shader_float16_int8() const; + int support_VK_KHR_shader_float_controls() const; + int support_VK_KHR_storage_buffer_storage_class() const; + int support_VK_KHR_swapchain() const; + int support_VK_EXT_descriptor_indexing() const; + int support_VK_EXT_memory_budget() const; + int support_VK_EXT_queue_family_foreign() const; +#if __ANDROID_API__ >= 26 + int support_VK_ANDROID_external_memory_android_hardware_buffer() const; +#endif // __ANDROID_API__ >= 26 + int support_VK_NV_cooperative_matrix() const; + +private: + GpuInfo(const GpuInfo&); + GpuInfo& operator=(const GpuInfo&); + +private: + friend int create_gpu_instance(); + GpuInfoPrivate* const d; +}; + +NCNN_EXPORT const GpuInfo& get_gpu_info(int device_index = get_default_gpu_index()); + +class VkAllocator; +class VkCompute; +class Option; +class PipelineCache; +class VulkanDevicePrivate; +class NCNN_EXPORT VulkanDevice +{ +public: + VulkanDevice(int device_index = get_default_gpu_index()); + ~VulkanDevice(); + + const GpuInfo& info; + + VkDevice vkdevice() const; + + VkShaderModule compile_shader_module(const uint32_t* spv_data, size_t spv_data_size) const; + + // with fixed workgroup size + VkShaderModule compile_shader_module(const uint32_t* spv_data, size_t spv_data_size, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z) const; + + // helper for creating pipeline + int create_descriptorset_layout(int binding_count, const int* binding_types, VkDescriptorSetLayout* descriptorset_layout) const; + int create_pipeline_layout(int push_constant_count, VkDescriptorSetLayout descriptorset_layout, VkPipelineLayout* pipeline_layout) const; + int create_pipeline(VkShaderModule shader_module, VkPipelineLayout pipeline_layout, const std::vector& specializations, VkPipeline* pipeline) const; + int create_descriptor_update_template(int binding_count, const int* binding_types, VkDescriptorSetLayout descriptorset_layout, VkPipelineLayout pipeline_layout, VkDescriptorUpdateTemplateKHR* descriptor_update_template) const; + + uint32_t find_memory_index(uint32_t memory_type_bits, VkFlags required, VkFlags preferred, VkFlags preferred_not) const; + bool is_mappable(uint32_t memory_type_index) const; + bool is_coherent(uint32_t memory_type_index) const; + + VkQueue acquire_queue(uint32_t queue_family_index) const; + void reclaim_queue(uint32_t queue_family_index, VkQueue queue) const; + + // allocator on this device + VkAllocator* acquire_blob_allocator() const; + void reclaim_blob_allocator(VkAllocator* allocator) const; + + VkAllocator* acquire_staging_allocator() const; + void reclaim_staging_allocator(VkAllocator* allocator) const; + + // immutable sampler for texelfetch + const VkSampler* immutable_texelfetch_sampler() const; + + // dummy buffer image + VkMat get_dummy_buffer() const; + VkImageMat get_dummy_image() const; + VkImageMat get_dummy_image_readonly() const; + + // pipeline cache on this device + const PipelineCache* get_pipeline_cache() const; + + // test image allocation + bool shape_support_image_storage(const Mat& shape) const; + + // current gpu heap memory budget in MB + uint32_t get_heap_budget() const; + + // utility operator + void convert_packing(const VkMat& src, VkMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkImageMat& src, VkImageMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkMat& src, VkImageMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkImageMat& src, VkMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + + // VK_KHR_bind_memory2 + PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; + PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; + + // VK_KHR_create_renderpass2 + PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; + PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; + PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; + + // VK_KHR_descriptor_update_template + PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; + PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; + PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; + + // VK_KHR_get_memory_requirements2 + PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; + PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; + PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; + + // VK_KHR_maintenance1 + PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; + + // VK_KHR_maintenance3 + PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; + + // VK_KHR_push_descriptor + PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; + PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; + + // VK_KHR_sampler_ycbcr_conversion + PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; + PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; + + // VK_KHR_swapchain + PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; + PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; + PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; + PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; + PFN_vkQueuePresentKHR vkQueuePresentKHR; + +#if __ANDROID_API__ >= 26 + // VK_ANDROID_external_memory_android_hardware_buffer + PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; + PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; +#endif // __ANDROID_API__ >= 26 + +protected: + // device extension + int init_device_extension(); + +private: + VulkanDevice(const VulkanDevice&); + VulkanDevice& operator=(const VulkanDevice&); + +private: + VulkanDevicePrivate* const d; +}; + +NCNN_EXPORT VulkanDevice* get_gpu_device(int device_index = get_default_gpu_index()); + +// online spirv compilation +NCNN_EXPORT int compile_spirv_module(const char* comp_string, const Option& opt, std::vector& spirv); +NCNN_EXPORT int compile_spirv_module(const char* comp_data, int comp_data_size, const Option& opt, std::vector& spirv); +NCNN_EXPORT int compile_spirv_module(int shader_type_index, const Option& opt, std::vector& spirv); + +// info from spirv +class NCNN_EXPORT ShaderInfo +{ +public: + int specialization_count; + int binding_count; + int push_constant_count; + + // 0 = null + // 1 = storage buffer + // 2 = storage image + // 3 = combined image sampler + int binding_types[16]; // 16 is large enough I think ... + + int reserved_0; + int reserved_1; + int reserved_2; + int reserved_3; +}; + +NCNN_EXPORT int resolve_shader_info(const uint32_t* spv_data, size_t spv_data_size, ShaderInfo& shader_info); + +} // namespace ncnn + +#endif // NCNN_VULKAN + +#endif // NCNN_GPU_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/layer.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/layer.h new file mode 100644 index 0000000..d02f65b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/layer.h @@ -0,0 +1,214 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_H +#define NCNN_LAYER_H + +#include "mat.h" +#include "modelbin.h" +#include "option.h" +#include "paramdict.h" +#include "platform.h" + +#include + +#if NCNN_VULKAN +#include "command.h" +#include "pipeline.h" + +#include +#endif // NCNN_VULKAN + +namespace ncnn { + +class NCNN_EXPORT Layer +{ +public: + // empty + Layer(); + // virtual destructor + virtual ~Layer(); + + // load layer specific parameter from parsed dict + // return 0 if success + virtual int load_param(const ParamDict& pd); + + // load layer specific weight data from model binary + // return 0 if success + virtual int load_model(const ModelBin& mb); + + // layer implementation specific setup + // return 0 if success + virtual int create_pipeline(const Option& opt); + + // layer implementation specific clean + // return 0 if success + virtual int destroy_pipeline(const Option& opt); + +public: + // one input and one output blob + bool one_blob_only; + + // support inplace inference + bool support_inplace; + + // support vulkan compute + bool support_vulkan; + + // accept input blob with packed storage + bool support_packing; + + // accept bf16 + bool support_bf16_storage; + + // accept fp16 + bool support_fp16_storage; + + // accept int8 + bool support_int8_storage; + + // shader image storage + bool support_image_storage; + + // shader tensor storage + bool support_tensor_storage; + + bool support_reserved_00; + + bool support_reserved_0; + bool support_reserved_1; + bool support_reserved_2; + bool support_reserved_3; + bool support_reserved_4; + bool support_reserved_5; + bool support_reserved_6; + bool support_reserved_7; + bool support_reserved_8; + bool support_reserved_9; + + // feature disabled set + int featmask; + +public: + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, const Option& opt) const; + virtual int forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, const Option& opt) const; + virtual int forward_inplace(Mat& bottom_top_blob, const Option& opt) const; + +#if NCNN_VULKAN +public: + // upload weight blob from host to device + virtual int upload_model(VkTransfer& cmd, const Option& opt); + +public: + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward_inplace(VkMat& bottom_top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward_inplace(VkImageMat& bottom_top_blob, VkCompute& cmd, const Option& opt) const; + +public: + // assigned immediately after creating this layer + const VulkanDevice* vkdev; +#endif // NCNN_VULKAN + +public: + // custom user data + void* userdata; + // layer type index + int typeindex; +#if NCNN_STRING + // layer type name + std::string type; + // layer name + std::string name; +#endif // NCNN_STRING + // blob index which this layer needs as input + std::vector bottoms; + // blob index which this layer produces as output + std::vector tops; + // shape hint + std::vector bottom_shapes; + std::vector top_shapes; +}; + +// layer factory function +typedef Layer* (*layer_creator_func)(void*); +typedef void (*layer_destroyer_func)(Layer*, void*); + +struct layer_registry_entry +{ +#if NCNN_STRING + // layer type name + const char* name; +#endif // NCNN_STRING + // layer factory entry + layer_creator_func creator; +}; + +struct custom_layer_registry_entry +{ +#if NCNN_STRING + // layer type name + const char* name; +#endif // NCNN_STRING + // layer factory entry + layer_creator_func creator; + layer_destroyer_func destroyer; + void* userdata; +}; + +#if NCNN_STRING +// get layer type from type name +NCNN_EXPORT int layer_to_index(const char* type); +// create layer from type name +NCNN_EXPORT Layer* create_layer(const char* type); +#endif // NCNN_STRING +// create layer from layer type +NCNN_EXPORT Layer* create_layer(int index); + +#define DEFINE_LAYER_CREATOR(name) \ + ::ncnn::Layer* name##_layer_creator(void* /*userdata*/) \ + { \ + return new name; \ + } + +#define DEFINE_LAYER_DESTROYER(name) \ + void name##_layer_destroyer(::ncnn::Layer* layer, void* /*userdata*/) \ + { \ + delete layer; \ + } + +} // namespace ncnn + +#endif // NCNN_LAYER_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/layer_shader_type.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/layer_shader_type.h new file mode 100644 index 0000000..c143e7d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/layer_shader_type.h @@ -0,0 +1,29 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_SHADER_TYPE_H +#define NCNN_LAYER_SHADER_TYPE_H + +namespace ncnn { + +namespace LayerShaderType { +enum LayerShaderType +{ +#include "layer_shader_type_enum.h" +}; +} // namespace LayerShaderType + +} // namespace ncnn + +#endif // NCNN_LAYER_SHADER_TYPE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/layer_shader_type_enum.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/layer_shader_type_enum.h new file mode 100644 index 0000000..f11cab9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/layer_shader_type_enum.h @@ -0,0 +1,370 @@ +// Layer Shader Enum header +// +// This file is auto-generated by cmake, don't edit it. + +absval = 0, +absval_pack4 = 1, +absval_pack8 = 2, +batchnorm = 3, +batchnorm_pack4 = 4, +batchnorm_pack8 = 5, +concat = 6, +concat_pack4 = 7, +concat_pack4to1 = 8, +concat_pack8 = 9, +concat_pack8to1 = 10, +concat_pack8to4 = 11, +convolution = 12, +convolution_1x1s1d1 = 13, +convolution_3x3s1d1_winograd23_transform_input = 14, +convolution_3x3s1d1_winograd23_transform_output = 15, +convolution_3x3s1d1_winograd43_transform_input = 16, +convolution_3x3s1d1_winograd43_transform_output = 17, +convolution_3x3s1d1_winograd_gemm = 18, +convolution_gemm = 19, +convolution_pack1to4 = 20, +convolution_pack1to4_1x1s1d1 = 21, +convolution_pack1to4_3x3s1d1_winograd_gemm = 22, +convolution_pack1to4_gemm = 23, +convolution_pack1to8 = 24, +convolution_pack1to8_1x1s1d1 = 25, +convolution_pack1to8_3x3s1d1_winograd_gemm = 26, +convolution_pack1to8_gemm = 27, +convolution_pack4 = 28, +convolution_pack4_1x1s1d1 = 29, +convolution_pack4_1x1s1d1_cm_16_8_8 = 30, +convolution_pack4_3x3s1d1_winograd23_transform_input = 31, +convolution_pack4_3x3s1d1_winograd23_transform_output = 32, +convolution_pack4_3x3s1d1_winograd43_transform_input = 33, +convolution_pack4_3x3s1d1_winograd43_transform_output = 34, +convolution_pack4_3x3s1d1_winograd_gemm = 35, +convolution_pack4_3x3s1d1_winograd_gemm_cm_16_8_8 = 36, +convolution_pack4_gemm = 37, +convolution_pack4_gemm_cm_16_8_8 = 38, +convolution_pack4to1 = 39, +convolution_pack4to1_1x1s1d1 = 40, +convolution_pack4to1_3x3s1d1_winograd_gemm = 41, +convolution_pack4to1_gemm = 42, +convolution_pack4to8 = 43, +convolution_pack4to8_1x1s1d1 = 44, +convolution_pack4to8_3x3s1d1_winograd_gemm = 45, +convolution_pack4to8_gemm = 46, +convolution_pack8 = 47, +convolution_pack8_1x1s1d1 = 48, +convolution_pack8_3x3s1d1_winograd23_transform_input = 49, +convolution_pack8_3x3s1d1_winograd23_transform_output = 50, +convolution_pack8_3x3s1d1_winograd43_transform_input = 51, +convolution_pack8_3x3s1d1_winograd43_transform_output = 52, +convolution_pack8_3x3s1d1_winograd_gemm = 53, +convolution_pack8_gemm = 54, +convolution_pack8to1 = 55, +convolution_pack8to1_1x1s1d1 = 56, +convolution_pack8to1_3x3s1d1_winograd_gemm = 57, +convolution_pack8to1_gemm = 58, +convolution_pack8to4 = 59, +convolution_pack8to4_1x1s1d1 = 60, +convolution_pack8to4_3x3s1d1_winograd_gemm = 61, +convolution_pack8to4_gemm = 62, +crop = 63, +crop_pack1to4 = 64, +crop_pack1to8 = 65, +crop_pack4 = 66, +crop_pack4to1 = 67, +crop_pack4to8 = 68, +crop_pack8 = 69, +crop_pack8to1 = 70, +crop_pack8to4 = 71, +deconvolution = 72, +deconvolution_col2im = 73, +deconvolution_gemm = 74, +deconvolution_pack1to4 = 75, +deconvolution_pack1to4_gemm = 76, +deconvolution_pack1to8 = 77, +deconvolution_pack1to8_gemm = 78, +deconvolution_pack4 = 79, +deconvolution_pack4_col2im = 80, +deconvolution_pack4_gemm = 81, +deconvolution_pack4_gemm_cm_16_8_8 = 82, +deconvolution_pack4to1 = 83, +deconvolution_pack4to1_gemm = 84, +deconvolution_pack4to8 = 85, +deconvolution_pack4to8_gemm = 86, +deconvolution_pack8 = 87, +deconvolution_pack8_col2im = 88, +deconvolution_pack8_gemm = 89, +deconvolution_pack8to1 = 90, +deconvolution_pack8to1_gemm = 91, +deconvolution_pack8to4 = 92, +deconvolution_pack8to4_gemm = 93, +dropout = 94, +dropout_pack4 = 95, +dropout_pack8 = 96, +eltwise = 97, +eltwise_pack4 = 98, +eltwise_pack8 = 99, +elu = 100, +elu_pack4 = 101, +elu_pack8 = 102, +flatten = 103, +flatten_pack1to4 = 104, +flatten_pack1to8 = 105, +flatten_pack4 = 106, +flatten_pack4to8 = 107, +flatten_pack8 = 108, +innerproduct = 109, +innerproduct_gemm = 110, +innerproduct_gemm_wp1to4 = 111, +innerproduct_gemm_wp1to8 = 112, +innerproduct_gemm_wp4 = 113, +innerproduct_gemm_wp4to1 = 114, +innerproduct_gemm_wp4to8 = 115, +innerproduct_gemm_wp8 = 116, +innerproduct_gemm_wp8to1 = 117, +innerproduct_gemm_wp8to4 = 118, +innerproduct_pack1to4 = 119, +innerproduct_pack1to8 = 120, +innerproduct_pack4 = 121, +innerproduct_pack4to1 = 122, +innerproduct_pack4to8 = 123, +innerproduct_pack8 = 124, +innerproduct_pack8to1 = 125, +innerproduct_pack8to4 = 126, +innerproduct_reduce_sum8 = 127, +innerproduct_reduce_sum8_pack4 = 128, +innerproduct_reduce_sum8_pack8 = 129, +innerproduct_sum8 = 130, +innerproduct_sum8_pack1to4 = 131, +innerproduct_sum8_pack1to8 = 132, +innerproduct_sum8_pack4 = 133, +innerproduct_sum8_pack4to1 = 134, +innerproduct_sum8_pack4to8 = 135, +innerproduct_sum8_pack8 = 136, +innerproduct_sum8_pack8to1 = 137, +innerproduct_sum8_pack8to4 = 138, +lrn_norm = 139, +lrn_norm_across_channel_pack4 = 140, +lrn_norm_across_channel_pack8 = 141, +lrn_norm_within_channel_pack4 = 142, +lrn_norm_within_channel_pack8 = 143, +lrn_square_pad = 144, +lrn_square_pad_across_channel_pack4 = 145, +lrn_square_pad_across_channel_pack8 = 146, +lrn_square_pad_within_channel_pack4 = 147, +lrn_square_pad_within_channel_pack8 = 148, +pooling = 149, +pooling_adaptive = 150, +pooling_adaptive_pack4 = 151, +pooling_adaptive_pack8 = 152, +pooling_global = 153, +pooling_global_pack4 = 154, +pooling_global_pack8 = 155, +pooling_pack4 = 156, +pooling_pack8 = 157, +prelu = 158, +prelu_pack4 = 159, +prelu_pack8 = 160, +relu = 161, +relu_pack4 = 162, +relu_pack8 = 163, +reshape = 164, +reshape_pack1to4 = 165, +reshape_pack1to8 = 166, +reshape_pack4 = 167, +reshape_pack4to1 = 168, +reshape_pack4to8 = 169, +reshape_pack8 = 170, +reshape_pack8to1 = 171, +reshape_pack8to4 = 172, +scale = 173, +scale_pack4 = 174, +scale_pack8 = 175, +sigmoid = 176, +sigmoid_pack4 = 177, +sigmoid_pack8 = 178, +slice = 179, +slice_pack1to4 = 180, +slice_pack1to8 = 181, +slice_pack4 = 182, +slice_pack4to8 = 183, +slice_pack8 = 184, +softmax_div_sum = 185, +softmax_div_sum_pack4 = 186, +softmax_div_sum_pack8 = 187, +softmax_exp_sub_max = 188, +softmax_exp_sub_max_pack4 = 189, +softmax_exp_sub_max_pack8 = 190, +softmax_reduce_max = 191, +softmax_reduce_max_pack4 = 192, +softmax_reduce_max_pack8 = 193, +softmax_reduce_sum = 194, +softmax_reduce_sum_pack4 = 195, +softmax_reduce_sum_pack8 = 196, +tanh = 197, +tanh_pack4 = 198, +tanh_pack8 = 199, +binaryop = 200, +binaryop_broadcast = 201, +binaryop_broadcast_a1_pack4 = 202, +binaryop_broadcast_a1_pack8 = 203, +binaryop_broadcast_b1_pack4 = 204, +binaryop_broadcast_b1_pack8 = 205, +binaryop_broadcast_pack4 = 206, +binaryop_broadcast_pack8 = 207, +binaryop_pack4 = 208, +binaryop_pack8 = 209, +unaryop = 210, +unaryop_pack4 = 211, +unaryop_pack8 = 212, +convolutiondepthwise = 213, +convolutiondepthwise_group = 214, +convolutiondepthwise_group_pack1to4 = 215, +convolutiondepthwise_group_pack1to8 = 216, +convolutiondepthwise_group_pack4 = 217, +convolutiondepthwise_group_pack4to1 = 218, +convolutiondepthwise_group_pack4to8 = 219, +convolutiondepthwise_group_pack8 = 220, +convolutiondepthwise_group_pack8to1 = 221, +convolutiondepthwise_group_pack8to4 = 222, +convolutiondepthwise_pack4 = 223, +convolutiondepthwise_pack8 = 224, +padding = 225, +padding_3d = 226, +padding_3d_pack4 = 227, +padding_3d_pack8 = 228, +padding_pack1to4 = 229, +padding_pack1to8 = 230, +padding_pack4 = 231, +padding_pack4to1 = 232, +padding_pack4to8 = 233, +padding_pack8 = 234, +padding_pack8to1 = 235, +padding_pack8to4 = 236, +normalize_coeffs = 237, +normalize_coeffs_pack4 = 238, +normalize_coeffs_pack8 = 239, +normalize_norm = 240, +normalize_norm_pack4 = 241, +normalize_norm_pack8 = 242, +normalize_reduce_sum4_fp16_to_fp32 = 243, +normalize_reduce_sum4_fp16_to_fp32_pack4 = 244, +normalize_reduce_sum4_fp16_to_fp32_pack8 = 245, +normalize_reduce_sum4_fp32 = 246, +normalize_reduce_sum4_fp32_pack4 = 247, +normalize_reduce_sum4_fp32_pack8 = 248, +permute = 249, +permute_pack1to4 = 250, +permute_pack1to8 = 251, +permute_pack4 = 252, +permute_pack4to1 = 253, +permute_pack4to8 = 254, +permute_pack8 = 255, +permute_pack8to1 = 256, +permute_pack8to4 = 257, +priorbox = 258, +priorbox_mxnet = 259, +interp = 260, +interp_bicubic = 261, +interp_bicubic_coeffs = 262, +interp_bicubic_pack4 = 263, +interp_bicubic_pack8 = 264, +interp_pack4 = 265, +interp_pack8 = 266, +deconvolutiondepthwise = 267, +deconvolutiondepthwise_group = 268, +deconvolutiondepthwise_group_pack1to4 = 269, +deconvolutiondepthwise_group_pack1to8 = 270, +deconvolutiondepthwise_group_pack4 = 271, +deconvolutiondepthwise_group_pack4to1 = 272, +deconvolutiondepthwise_group_pack4to8 = 273, +deconvolutiondepthwise_group_pack8 = 274, +deconvolutiondepthwise_group_pack8to1 = 275, +deconvolutiondepthwise_group_pack8to4 = 276, +deconvolutiondepthwise_pack4 = 277, +deconvolutiondepthwise_pack8 = 278, +shufflechannel = 279, +shufflechannel_pack4 = 280, +shufflechannel_pack8 = 281, +instancenorm_coeffs = 282, +instancenorm_coeffs_pack4 = 283, +instancenorm_coeffs_pack8 = 284, +instancenorm_norm = 285, +instancenorm_norm_pack4 = 286, +instancenorm_norm_pack8 = 287, +instancenorm_reduce_mean = 288, +instancenorm_reduce_mean_pack4 = 289, +instancenorm_reduce_mean_pack8 = 290, +instancenorm_reduce_sum4_fp16_to_fp32 = 291, +instancenorm_reduce_sum4_fp16_to_fp32_pack4 = 292, +instancenorm_reduce_sum4_fp16_to_fp32_pack8 = 293, +instancenorm_reduce_sum4_fp32 = 294, +instancenorm_reduce_sum4_fp32_pack4 = 295, +instancenorm_reduce_sum4_fp32_pack8 = 296, +instancenorm_sub_mean_square = 297, +instancenorm_sub_mean_square_pack4 = 298, +instancenorm_sub_mean_square_pack8 = 299, +clip = 300, +clip_pack4 = 301, +clip_pack8 = 302, +reorg = 303, +reorg_pack1to4 = 304, +reorg_pack1to8 = 305, +reorg_pack4 = 306, +reorg_pack4to8 = 307, +reorg_pack8 = 308, +packing = 309, +packing_fp16_to_fp32 = 310, +packing_fp32_to_fp16 = 311, +packing_pack1to4 = 312, +packing_pack1to4_fp16_to_fp32 = 313, +packing_pack1to4_fp32_to_fp16 = 314, +packing_pack1to8 = 315, +packing_pack1to8_fp16_to_fp32 = 316, +packing_pack1to8_fp32_to_fp16 = 317, +packing_pack4 = 318, +packing_pack4_fp16_to_fp32 = 319, +packing_pack4_fp32_to_fp16 = 320, +packing_pack4to1 = 321, +packing_pack4to1_fp16_to_fp32 = 322, +packing_pack4to1_fp32_to_fp16 = 323, +packing_pack4to8 = 324, +packing_pack4to8_fp16_to_fp32 = 325, +packing_pack4to8_fp32_to_fp16 = 326, +packing_pack8 = 327, +packing_pack8_fp16_to_fp32 = 328, +packing_pack8_fp32_to_fp16 = 329, +packing_pack8to1 = 330, +packing_pack8to1_fp16_to_fp32 = 331, +packing_pack8to1_fp32_to_fp16 = 332, +packing_pack8to4 = 333, +packing_pack8to4_fp16_to_fp32 = 334, +packing_pack8to4_fp32_to_fp16 = 335, +cast_fp16_to_fp32 = 336, +cast_fp16_to_fp32_pack4 = 337, +cast_fp16_to_fp32_pack8 = 338, +cast_fp32_to_fp16 = 339, +cast_fp32_to_fp16_pack4 = 340, +cast_fp32_to_fp16_pack8 = 341, +hardsigmoid = 342, +hardsigmoid_pack4 = 343, +hardsigmoid_pack8 = 344, +hardswish = 345, +hardswish_pack4 = 346, +hardswish_pack8 = 347, +pixelshuffle = 348, +pixelshuffle_pack4 = 349, +pixelshuffle_pack4to1 = 350, +pixelshuffle_pack8 = 351, +pixelshuffle_pack8to1 = 352, +pixelshuffle_pack8to4 = 353, +deepcopy = 354, +deepcopy_pack4 = 355, +deepcopy_pack8 = 356, +mish = 357, +mish_pack4 = 358, +mish_pack8 = 359, +swish = 360, +swish_pack4 = 361, +swish_pack8 = 362, +convert_ycbcr = 363, +vulkan_activation = 364, + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/layer_type.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/layer_type.h new file mode 100644 index 0000000..511c714 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/layer_type.h @@ -0,0 +1,30 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_TYPE_H +#define NCNN_LAYER_TYPE_H + +namespace ncnn { + +namespace LayerType { +enum LayerType +{ +#include "layer_type_enum.h" + CustomBit = (1 << 8), +}; +} // namespace LayerType + +} // namespace ncnn + +#endif // NCNN_LAYER_TYPE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/layer_type_enum.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/layer_type_enum.h new file mode 100644 index 0000000..581d589 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/layer_type_enum.h @@ -0,0 +1,103 @@ +// Layer Type Enum header +// +// This file is auto-generated by cmake, don't edit it. + +AbsVal = 0, +ArgMax = 1, +BatchNorm = 2, +Bias = 3, +BNLL = 4, +Concat = 5, +Convolution = 6, +Crop = 7, +Deconvolution = 8, +Dropout = 9, +Eltwise = 10, +ELU = 11, +Embed = 12, +Exp = 13, +Flatten = 14, +InnerProduct = 15, +Input = 16, +Log = 17, +LRN = 18, +MemoryData = 19, +MVN = 20, +Pooling = 21, +Power = 22, +PReLU = 23, +Proposal = 24, +Reduction = 25, +ReLU = 26, +Reshape = 27, +ROIPooling = 28, +Scale = 29, +Sigmoid = 30, +Slice = 31, +Softmax = 32, +Split = 33, +SPP = 34, +TanH = 35, +Threshold = 36, +Tile = 37, +RNN = 38, +LSTM = 39, +BinaryOp = 40, +UnaryOp = 41, +ConvolutionDepthWise = 42, +Padding = 43, +Squeeze = 44, +ExpandDims = 45, +Normalize = 46, +Permute = 47, +PriorBox = 48, +DetectionOutput = 49, +Interp = 50, +DeconvolutionDepthWise = 51, +ShuffleChannel = 52, +InstanceNorm = 53, +Clip = 54, +Reorg = 55, +YoloDetectionOutput = 56, +Quantize = 57, +Dequantize = 58, +Yolov3DetectionOutput = 59, +PSROIPooling = 60, +ROIAlign = 61, +Packing = 62, +Requantize = 63, +Cast = 64, +HardSigmoid = 65, +SELU = 66, +HardSwish = 67, +Noop = 68, +PixelShuffle = 69, +DeepCopy = 70, +Mish = 71, +StatisticsPooling = 72, +Swish = 73, +Gemm = 74, +GroupNorm = 75, +LayerNorm = 76, +Softplus = 77, +GRU = 78, +MultiHeadAttention = 79, +GELU = 80, +Convolution1D = 81, +Pooling1D = 82, +ConvolutionDepthWise1D = 83, +Convolution3D = 84, +ConvolutionDepthWise3D = 85, +Pooling3D = 86, +MatMul = 87, +Deconvolution1D = 88, +DeconvolutionDepthWise1D = 89, +Deconvolution3D = 90, +DeconvolutionDepthWise3D = 91, +Einsum = 92, +DeformableConv2D = 93, +GLU = 94, +Fold = 95, +Unfold = 96, +GridSample = 97, + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/mat.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/mat.h new file mode 100644 index 0000000..c6f59ef --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/mat.h @@ -0,0 +1,1843 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_MAT_H +#define NCNN_MAT_H + +#include +#include +#if __ARM_NEON +#include +#endif +#if __SSE2__ +#include +#if __AVX__ +#include +#endif +#endif +#if __mips_msa +#include +#endif +#if __loongarch_sx +#include +#endif +#if __riscv_vector +#include +#include "cpu.h" // cpu_riscv_vlenb() +#endif + +#include "allocator.h" +#include "option.h" +#include "platform.h" + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#if NCNN_PIXEL +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#include +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API +#endif // NCNN_PIXEL + +namespace ncnn { + +#if NCNN_VULKAN +class VkMat; +class VkImageMat; +#endif // NCNN_VULKAN + +// the three dimension matrix +class NCNN_EXPORT Mat +{ +public: + // empty + Mat(); + // vec + Mat(int w, size_t elemsize = 4u, Allocator* allocator = 0); + // image + Mat(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0); + // dim + Mat(int w, int h, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // cube + Mat(int w, int h, int d, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // packed vec + Mat(int w, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed image + Mat(int w, int h, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed dim + Mat(int w, int h, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed cube + Mat(int w, int h, int d, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // copy + Mat(const Mat& m); + // external vec + Mat(int w, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external image + Mat(int w, int h, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external dim + Mat(int w, int h, int c, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external cube + Mat(int w, int h, int d, int c, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external packed vec + Mat(int w, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed image + Mat(int w, int h, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed dim + Mat(int w, int h, int c, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed cube + Mat(int w, int h, int d, int c, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // release + ~Mat(); + // assign + Mat& operator=(const Mat& m); + // set all + void fill(float v); + void fill(int v); +#if __ARM_NEON + void fill(float32x4_t _v); + void fill(uint16x4_t _v); + void fill(int32x4_t _v); + void fill(int32x4_t _v0, int32x4_t _v1); +#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC + void fill(float16x4_t _v); + void fill(float16x8_t _v); +#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +#endif // __ARM_NEON +#if __SSE2__ +#if __AVX__ +#if __AVX512F__ + void fill(__m512 _v); +#endif // __AVX512F__ + void fill(__m256 _v, int i = 0); +#endif // __AVX__ + void fill(__m128 _v); + void fill(__m128i _v); +#endif // __SSE2__ +#if __mips_msa + void fill(v4f32 _v); +#endif // __mips_msa +#if __loongarch_sx + void fill(__m128 _v); +#endif //__loongarch_sx +#if __riscv_vector + void fill(vfloat32m1_t _v); + void fill(vuint16m1_t _v); + void fill(vint8m1_t _v); +#if __riscv_zfh + void fill(vfloat16m1_t _v); +#endif // __riscv_zfh +#endif // __riscv_vector + template + void fill(T v); + // deep copy + Mat clone(Allocator* allocator = 0) const; + // deep copy from other mat, inplace + void clone_from(const ncnn::Mat& mat, Allocator* allocator = 0); + // reshape vec + Mat reshape(int w, Allocator* allocator = 0) const; + // reshape image + Mat reshape(int w, int h, Allocator* allocator = 0) const; + // reshape dim + Mat reshape(int w, int h, int c, Allocator* allocator = 0) const; + // reshape cube + Mat reshape(int w, int h, int d, int c, Allocator* allocator = 0) const; + // allocate vec + void create(int w, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate image + void create(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate dim + void create(int w, int h, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate like + void create_like(const Mat& m, Allocator* allocator = 0); +#if NCNN_VULKAN + // allocate like + void create_like(const VkMat& m, Allocator* allocator = 0); + // allocate like + void create_like(const VkImageMat& im, Allocator* allocator = 0); +#endif // NCNN_VULKAN + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // data reference + Mat channel(int c); + const Mat channel(int c) const; + Mat depth(int z); + const Mat depth(int z) const; + float* row(int y); + const float* row(int y) const; + template + T* row(int y); + template + const T* row(int y) const; + + // range reference + Mat channel_range(int c, int channels); + const Mat channel_range(int c, int channels) const; + Mat depth_range(int z, int depths); + const Mat depth_range(int z, int depths) const; + Mat row_range(int y, int rows); + const Mat row_range(int y, int rows) const; + Mat range(int x, int n); + const Mat range(int x, int n) const; + + // access raw data + template + operator T*(); + template + operator const T*() const; + + // convenient access float vec element + float& operator[](size_t i); + const float& operator[](size_t i) const; + +#if NCNN_PIXEL + enum PixelType + { + PIXEL_CONVERT_SHIFT = 16, + PIXEL_FORMAT_MASK = 0x0000ffff, + PIXEL_CONVERT_MASK = 0xffff0000, + + PIXEL_RGB = 1, + PIXEL_BGR = 2, + PIXEL_GRAY = 3, + PIXEL_RGBA = 4, + PIXEL_BGRA = 5, + + PIXEL_RGB2BGR = PIXEL_RGB | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2GRAY = PIXEL_RGB | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2RGBA = PIXEL_RGB | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2BGRA = PIXEL_RGB | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_BGR2RGB = PIXEL_BGR | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2GRAY = PIXEL_BGR | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2RGBA = PIXEL_BGR | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2BGRA = PIXEL_BGR | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_GRAY2RGB = PIXEL_GRAY | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2BGR = PIXEL_GRAY | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2RGBA = PIXEL_GRAY | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2BGRA = PIXEL_GRAY | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_RGBA2RGB = PIXEL_RGBA | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2BGR = PIXEL_RGBA | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2GRAY = PIXEL_RGBA | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2BGRA = PIXEL_RGBA | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_BGRA2RGB = PIXEL_BGRA | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2BGR = PIXEL_BGRA | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2GRAY = PIXEL_BGRA | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2RGBA = PIXEL_BGRA | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + }; + // convenient construct from pixel data + static Mat from_pixels(const unsigned char* pixels, int type, int w, int h, Allocator* allocator = 0); + // convenient construct from pixel data with stride(bytes-per-row) parameter + static Mat from_pixels(const unsigned char* pixels, int type, int w, int h, int stride, Allocator* allocator = 0); + // convenient construct from pixel data and resize to specific size + static Mat from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data and resize to specific size with stride(bytes-per-row) parameter + static Mat from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data roi + static Mat from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from pixel data roi with stride(bytes-per-row) parameter + static Mat from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from pixel data roi and resize to specific size + static Mat from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data roi and resize to specific size with stride(bytes-per-row) parameter + static Mat from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + + // convenient export to pixel data + void to_pixels(unsigned char* pixels, int type) const; + // convenient export to pixel data with stride(bytes-per-row) parameter + void to_pixels(unsigned char* pixels, int type, int stride) const; + // convenient export to pixel data and resize to specific size + void to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height) const; + // convenient export to pixel data and resize to specific size with stride(bytes-per-row) parameter + void to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height, int target_stride) const; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 + // convenient construct from android Bitmap + static Mat from_android_bitmap(JNIEnv* env, jobject bitmap, int type_to, Allocator* allocator = 0); + // convenient construct from android Bitmap and resize to specific size + static Mat from_android_bitmap_resize(JNIEnv* env, jobject bitmap, int type_to, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from android Bitmap roi + static Mat from_android_bitmap_roi(JNIEnv* env, jobject bitmap, int type_to, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from android Bitmap roi and resize to specific size + static Mat from_android_bitmap_roi_resize(JNIEnv* env, jobject bitmap, int type_to, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + // convenient export to android Bitmap and resize to the android Bitmap size + void to_android_bitmap(JNIEnv* env, jobject bitmap, int type_from) const; +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API +#endif // NCNN_PIXEL + + // substract channel-wise mean values, then multiply by normalize values, pass 0 to skip + void substract_mean_normalize(const float* mean_vals, const float* norm_vals); + + // convenient construct from half precision floating point data + static Mat from_float16(const unsigned short* data, int size); + + // pointer to the data + void* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + Allocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; + + size_t cstep; +}; + +#if NCNN_VULKAN + +// the three dimension matrix, vulkan version +class NCNN_EXPORT VkMat +{ +public: + // empty + VkMat(); + // vec + VkMat(int w, size_t elemsize, VkAllocator* allocator); + // image + VkMat(int w, int h, size_t elemsize, VkAllocator* allocator); + // dim + VkMat(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // cube + VkMat(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // packed vec + VkMat(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // packed image + VkMat(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // packed dim + VkMat(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // packed cube + VkMat(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // copy + VkMat(const VkMat& m); + // external vec + VkMat(int w, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external image + VkMat(int w, int h, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external dim + VkMat(int w, int h, int c, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external cube + VkMat(int w, int h, int d, int c, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external packed vec + VkMat(int w, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed image + VkMat(int w, int h, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed dim + VkMat(int w, int h, int c, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed cube + VkMat(int w, int h, int d, int c, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // release + ~VkMat(); + // assign + VkMat& operator=(const VkMat& m); + // allocate vec + void create(int w, size_t elemsize, VkAllocator* allocator); + // allocate image + void create(int w, int h, size_t elemsize, VkAllocator* allocator); + // allocate dim + void create(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate like + void create_like(const Mat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkMat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkImageMat& im, VkAllocator* allocator); + + // mapped + Mat mapped() const; + void* mapped_ptr() const; + + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // low-level reference + VkBuffer buffer() const; + size_t buffer_offset() const; + size_t buffer_capacity() const; + + // device buffer + VkBufferMemory* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + VkAllocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; + + size_t cstep; +}; + +class NCNN_EXPORT VkImageMat +{ +public: + // empty + VkImageMat(); + // vec + VkImageMat(int w, size_t elemsize, VkAllocator* allocator); + // image + VkImageMat(int w, int h, size_t elemsize, VkAllocator* allocator); + // dim + VkImageMat(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // cube + VkImageMat(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // packed vec + VkImageMat(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // packed image + VkImageMat(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // packed dim + VkImageMat(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // packed cube + VkImageMat(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // copy + VkImageMat(const VkImageMat& m); + // external vec + VkImageMat(int w, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external image + VkImageMat(int w, int h, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external dim + VkImageMat(int w, int h, int c, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external cube + VkImageMat(int w, int h, int d, int c, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external packed vec + VkImageMat(int w, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed image + VkImageMat(int w, int h, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed dim + VkImageMat(int w, int h, int c, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed cube + VkImageMat(int w, int h, int d, int c, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // release + ~VkImageMat(); + // assign + VkImageMat& operator=(const VkImageMat& m); + // allocate vec + void create(int w, size_t elemsize, VkAllocator* allocator); + // allocate image + void create(int w, int h, size_t elemsize, VkAllocator* allocator); + // allocate dim + void create(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate like + void create_like(const Mat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkMat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkImageMat& im, VkAllocator* allocator); + + // mapped + Mat mapped() const; + void* mapped_ptr() const; + + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // low-level reference + VkImage image() const; + VkImageView imageview() const; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 + // convenient construct from android hardware buffer + static VkImageMat from_android_hardware_buffer(VkAndroidHardwareBufferImageAllocator* allocator); +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + + // device image + VkImageMemory* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + VkAllocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; +}; + +// type for vulkan specialization constant and push constant +union vk_specialization_type +{ + int i; + float f; + uint32_t u32; +}; +union vk_constant_type +{ + int i; + float f; +}; +#endif // NCNN_VULKAN + +// misc function +#if NCNN_PIXEL +// convert yuv420sp(nv21) to rgb, the fast approximate version +NCNN_EXPORT void yuv420sp2rgb(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// convert yuv420sp(nv12) to rgb, the fast approximate version +NCNN_EXPORT void yuv420sp2rgb_nv12(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// convert yuv420sp(nv21) to rgb with half resize, the faster approximate version +NCNN_EXPORT void yuv420sp2rgb_half(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// image pixel bilinear resize +NCNN_EXPORT void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +// image pixel bilinear resize with stride(bytes-per-row) parameter +NCNN_EXPORT void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +// image pixel bilinear resize, convenient wrapper for yuv420sp(nv21/nv12) +NCNN_EXPORT void resize_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +#endif // NCNN_PIXEL +#if NCNN_PIXEL_ROTATE +// type is the from type, 6 means rotating from 6 to 1 +// +// 1 2 3 4 5 6 7 8 +// +// 888888 888888 88 88 8888888888 88 88 8888888888 +// 88 88 88 88 88 88 88 88 88 88 88 88 +// 8888 8888 8888 8888 88 8888888888 8888888888 88 +// 88 88 88 88 +// 88 88 888888 888888 +// +// ref http://sylvana.net/jpegcrop/exif_orientation.html +// image pixel kanna rotate +NCNN_EXPORT void kanna_rotate_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +// image pixel kanna rotate with stride(bytes-per-row) parameter +NCNN_EXPORT void kanna_rotate_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +// image pixel kanna rotate, convenient wrapper for yuv420sp(nv21/nv12) +NCNN_EXPORT void kanna_rotate_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +#endif // NCNN_PIXEL_ROTATE +#if NCNN_PIXEL_AFFINE +// resolve affine transform matrix from rotation angle, scale factor and x y offset +NCNN_EXPORT void get_rotation_matrix(float angle, float scale, float dx, float dy, float* tm); +// resolve affine transform matrix from two set of points, num_point must be >= 2 +NCNN_EXPORT void get_affine_transform(const float* points_from, const float* points_to, int num_point, float* tm); +// resolve the inversion affine transform matrix +NCNN_EXPORT void invert_affine_transform(const float* tm, float* tm_inv); +// image pixel bilinear warpaffine inverse transform, set -233 for transparent border color, the color RGBA is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +// image pixel bilinear warpaffine inverse transform with stride(bytes-per-row) parameter, set -233 for transparent border color, the color RGBA is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +// image pixel bilinear warpaffine, convenient wrapper for yuv420sp(nv21/nv12), set -233 for transparent border color, the color YUV_ is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +#endif // NCNN_PIXEL_AFFINE +#if NCNN_PIXEL_DRAWING +// draw rectangle, set thickness -1 for filled rectangle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_rectangle_c1(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c2(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c3(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c4(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw rectangle with stride(bytes-per-row) parameter, set thickness -1 for filled rectangle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_rectangle_c1(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c2(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c3(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c4(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw rectangle, convenient wrapper for yuv420sp(nv21/nv12), set thickness -1 for filled rectangle, the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_rectangle_yuv420sp(unsigned char* yuv420sp, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw circle, set thickness -1 for filled circle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_circle_c1(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c2(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c3(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c4(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +// draw circle with stride(bytes-per-row) parameter, set thickness -1 for filled circle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_circle_c1(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c2(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c3(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c4(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +// draw circle, convenient wrapper for yuv420sp(nv21/nv12), set thickness -1 for filled circle, the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_circle_yuv420sp(unsigned char* yuv420sp, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +// draw line, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_line_c1(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c2(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c3(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c4(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// draw line with stride(bytes-per-row) parameter, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_line_c1(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c2(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c3(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c4(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// draw line, convenient wrapper for yuv420sp(nv21/nv12), the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_line_yuv420sp(unsigned char* yuv420sp, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// resolve text bounding box size +NCNN_EXPORT void get_text_drawing_size(const char* text, int fontpixelsize, int* w, int* h); +// draw ascii printables and newline, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_text_c1(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c2(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c3(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c4(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +// draw ascii printables and newline with stride(bytes-per-row) parameter, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_text_c1(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c2(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c3(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c4(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +// draw ascii printables and newline, convenient wrapper for yuv420sp(nv21/nv12), the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_text_yuv420sp(unsigned char* yuv420sp, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +#endif // NCNN_PIXEL_DRAWING + +// type conversion +// convert float to half precision floating point +NCNN_EXPORT unsigned short float32_to_float16(float value); +// convert half precision floating point to float +NCNN_EXPORT float float16_to_float32(unsigned short value); +// convert float to brain half +NCNN_EXPORT NCNN_FORCEINLINE unsigned short float32_to_bfloat16(float value) +{ + // 16 : 16 + union + { + unsigned int u; + float f; + } tmp; + tmp.f = value; + return tmp.u >> 16; +} +// convert brain half to float +NCNN_EXPORT NCNN_FORCEINLINE float bfloat16_to_float32(unsigned short value) +{ + // 16 : 16 + union + { + unsigned int u; + float f; + } tmp; + tmp.u = value << 16; + return tmp.f; +} + +// mat process +enum BorderType +{ + BORDER_CONSTANT = 0, + BORDER_REPLICATE = 1, + BORDER_REFLECT = 2, + BORDER_TRANSPARENT = -233, +}; +NCNN_EXPORT void copy_make_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int type, float v, const Option& opt = Option()); +NCNN_EXPORT void copy_make_border_3d(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int front, int behind, int type, float v, const Option& opt = Option()); +NCNN_EXPORT void copy_cut_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, const Option& opt = Option()); +NCNN_EXPORT void copy_cut_border_3d(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int front, int behind, const Option& opt = Option()); +NCNN_EXPORT void resize_nearest(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void resize_bilinear(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void resize_bicubic(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void convert_packing(const Mat& src, Mat& dst, int elempack, const Option& opt = Option()); +NCNN_EXPORT void flatten(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float32_to_float16(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float16_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_int8_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float32_to_bfloat16(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_bfloat16_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void quantize_to_int8(const Mat& src, Mat& dst, const Mat& scale_data, const Option& opt = Option()); +NCNN_EXPORT void dequantize_from_int32(const Mat& src, Mat& dst, const Mat& scale_data, const Mat& bias_data, const Option& opt = Option()); +NCNN_EXPORT void requantize_from_int32_to_int8(const Mat& src, Mat& dst, const Mat& scale_in_data, const Mat& scale_out_data, const Mat& bias_data, int activation_type, const Mat& activation_params, const Option& opt = Option()); + +NCNN_FORCEINLINE Mat::Mat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ +} + +NCNN_FORCEINLINE Mat::Mat(int _w, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(const Mat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c), cstep(m.cstep) +{ + addref(); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = (size_t)w * h; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = (size_t)w * h; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::~Mat() +{ + release(); +} + +NCNN_FORCEINLINE void Mat::fill(float _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + + int i = 0; +#if __ARM_NEON + float32x4_t _c = vdupq_n_f32(_v); + for (; i + 3 < size; i += 4) + { + vst1q_f32(ptr, _c); + ptr += 4; + } +#endif // __ARM_NEON + for (; i < size; i++) + { + *ptr++ = _v; + } +} + +NCNN_FORCEINLINE void Mat::fill(int _v) +{ + int size = (int)total(); + int* ptr = (int*)data; + + int i = 0; +#if __ARM_NEON + int32x4_t _c = vdupq_n_s32(_v); + for (; i + 3 < size; i += 4) + { + vst1q_s32(ptr, _c); + ptr += 4; + } +#endif // __ARM_NEON + for (; i < size; i++) + { + *ptr++ = _v; + } +} + +#if __ARM_NEON +NCNN_FORCEINLINE void Mat::fill(float32x4_t _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + vst1q_f32(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(uint16x4_t _v) +{ + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + vst1_u16(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(int32x4_t _v) +{ + int size = (int)total(); + int* ptr = (int*)data; + for (int i = 0; i < size; i++) + { + vst1q_s32(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(int32x4_t _v0, int32x4_t _v1) +{ + int size = (int)total(); + int* ptr = (int*)data; + for (int i = 0; i < size; i++) + { + vst1q_s32(ptr, _v0); + vst1q_s32(ptr + 4, _v1); + ptr += 8; + } +} +#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +NCNN_FORCEINLINE void Mat::fill(float16x4_t _v) +{ + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vst1_f16(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(float16x8_t _v) +{ + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vst1q_f16(ptr, _v); + ptr += 8; + } +} +#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +#endif // __ARM_NEON + +#if __SSE2__ +#if __AVX__ +#if __AVX512F__ +NCNN_FORCEINLINE void Mat::fill(__m512 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm512_storeu_ps(ptr, _v); + ptr += 16; + } +} +#endif // __AVX512F__ +NCNN_FORCEINLINE void Mat::fill(__m256 _v, int _i) +{ + // old gcc cannot overload __m128 and __m256 type + // add a dummy int parameter for different mangled function symbol + (void)_i; + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm256_storeu_ps(ptr, _v); + ptr += 8; + } +} +#endif // __AVX__ +NCNN_FORCEINLINE void Mat::fill(__m128 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm_storeu_ps(ptr, _v); + ptr += 4; + } +} +NCNN_FORCEINLINE void Mat::fill(__m128i _v) +{ + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + _mm_store_si128((__m128i*)ptr, _v); + ptr += 8; + } +} +#endif // __SSE2__ + +#if __mips_msa +NCNN_FORCEINLINE void Mat::fill(v4f32 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + __msa_st_w((v4i32)_v, ptr, 0); + ptr += 4; + } +} +#endif // __mips_msa + +#if __loongarch_sx +NCNN_FORCEINLINE void Mat::fill(__m128 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + __lsx_vst(_v, ptr, 0); + ptr += 4; + } +} +#endif // __loongarch_sx +#if __riscv_vector +NCNN_FORCEINLINE void Mat::fill(vfloat32m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 4; + const size_t vl = vsetvl_e32m1(packn); + + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + vse32_v_f32m1(ptr, _v, vl); + ptr += packn; + } +} + +NCNN_FORCEINLINE void Mat::fill(vuint16m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 2; + const size_t vl = vsetvl_e16m1(packn); + + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + vse16_v_u16m1(ptr, _v, vl); + ptr += packn; + } +} + +NCNN_FORCEINLINE void Mat::fill(vint8m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 1; + const size_t vl = vsetvl_e8m1(packn); + + int size = (int)total(); + signed char* ptr = (signed char*)data; + for (int i = 0; i < size; i++) + { + vse8_v_i8m1(ptr, _v, vl); + ptr += packn; + } +} +#if __riscv_zfh +NCNN_FORCEINLINE void Mat::fill(vfloat16m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 2; + const size_t vl = vsetvl_e16m1(packn); + + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vse16_v_f16m1(ptr, _v, vl); + ptr += packn; + } +} +#endif // __riscv_zfh +#endif // __riscv_vector + +template +NCNN_FORCEINLINE void Mat::fill(T _v) +{ + int size = (int)total(); + T* ptr = (T*)data; + for (int i = 0; i < size; i++) + { + ptr[i] = _v; + } +} + +NCNN_FORCEINLINE Mat& Mat::operator=(const Mat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + cstep = m.cstep; + + return *this; +} + +NCNN_FORCEINLINE void Mat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void Mat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator) + allocator->fastFree(data); + else + fastFree(data); + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + cstep = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool Mat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t Mat::total() const +{ + return cstep * c; +} + +NCNN_FORCEINLINE int Mat::elembits() const +{ + return elempack ? static_cast(elemsize * 8) / elempack : 0; +} + +NCNN_FORCEINLINE Mat Mat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE Mat Mat::channel(int _c) +{ + Mat m(w, h, d, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims - 1; + if (dims == 4) + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::channel(int _c) const +{ + Mat m(w, h, d, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims - 1; + if (dims == 4) + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE Mat Mat::depth(int z) +{ + return Mat(w, h, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::depth(int z) const +{ + return Mat(w, h, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE float* Mat::row(int y) +{ + return (float*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +NCNN_FORCEINLINE const float* Mat::row(int y) const +{ + return (const float*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +template +NCNN_FORCEINLINE T* Mat::row(int y) +{ + return (T*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +template +NCNN_FORCEINLINE const T* Mat::row(int y) const +{ + return (const T*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +NCNN_FORCEINLINE Mat Mat::channel_range(int _c, int channels) +{ + Mat m(w, h, d, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::channel_range(int _c, int channels) const +{ + Mat m(w, h, d, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims; + return m; +} + +NCNN_FORCEINLINE Mat Mat::depth_range(int z, int depths) +{ + Mat m(w, h, depths, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::depth_range(int z, int depths) const +{ + Mat m(w, h, depths, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE Mat Mat::row_range(int y, int rows) +{ + return Mat(w, rows, (unsigned char*)data + (size_t)w * y * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::row_range(int y, int rows) const +{ + return Mat(w, rows, (unsigned char*)data + (size_t)w * y * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE Mat Mat::range(int x, int n) +{ + return Mat(n, (unsigned char*)data + x * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::range(int x, int n) const +{ + return Mat(n, (unsigned char*)data + x * elemsize, elemsize, elempack, allocator); +} + +template +NCNN_FORCEINLINE Mat::operator T*() +{ + return (T*)data; +} + +template +NCNN_FORCEINLINE Mat::operator const T*() const +{ + return (const T*)data; +} + +NCNN_FORCEINLINE float& Mat::operator[](size_t i) +{ + return ((float*)data)[i]; +} + +NCNN_FORCEINLINE const float& Mat::operator[](size_t i) const +{ + return ((const float*)data)[i]; +} + +#if NCNN_VULKAN + +NCNN_FORCEINLINE VkMat::VkMat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(const VkMat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c) +{ + addref(); + + cstep = m.cstep; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = w * h; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize(w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = w * h; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize(w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::~VkMat() +{ + release(); +} + +NCNN_FORCEINLINE VkMat& VkMat::operator=(const VkMat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + cstep = m.cstep; + + return *this; +} + +NCNN_FORCEINLINE Mat VkMat::mapped() const +{ + if (!allocator->mappable) + return Mat(); + + if (dims == 1) + return Mat(w, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 2) + return Mat(w, h, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 3) + return Mat(w, h, c, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 4) + return Mat(w, h, d, c, mapped_ptr(), elemsize, elempack, 0); + + return Mat(); +} + +NCNN_FORCEINLINE void* VkMat::mapped_ptr() const +{ + if (!allocator->mappable) + return 0; + + return (unsigned char*)data->mapped_ptr + data->offset; +} + +NCNN_FORCEINLINE void VkMat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void VkMat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator && data) + { + allocator->fastFree(data); + } + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + cstep = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool VkMat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t VkMat::total() const +{ + return cstep * c; +} + +NCNN_FORCEINLINE int VkMat::elembits() const +{ + return elempack ? static_cast(elemsize) * 8 / elempack : 0; +} + +NCNN_FORCEINLINE Mat VkMat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE VkBuffer VkMat::buffer() const +{ + return data->buffer; +} + +NCNN_FORCEINLINE size_t VkMat::buffer_offset() const +{ + return data->offset; +} + +NCNN_FORCEINLINE size_t VkMat::buffer_capacity() const +{ + return data->capacity; +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(const VkImageMat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c) +{ + addref(); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::~VkImageMat() +{ + release(); +} + +NCNN_FORCEINLINE VkImageMat& VkImageMat::operator=(const VkImageMat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + return *this; +} + +NCNN_FORCEINLINE Mat VkImageMat::mapped() const +{ + if (!allocator->mappable || !data->mapped_ptr) + return Mat(); + + if (dims == 1) + return Mat(w, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 2) + return Mat(w, h, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 3) + return Mat(w, h, c, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 4) + return Mat(w, h, d, c, mapped_ptr(), elemsize, elempack, 0); + + return Mat(); +} + +NCNN_FORCEINLINE void* VkImageMat::mapped_ptr() const +{ + if (!allocator->mappable || !data->mapped_ptr) + return 0; + + return (unsigned char*)data->mapped_ptr + data->bind_offset; +} + +NCNN_FORCEINLINE void VkImageMat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void VkImageMat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator && data) + { + allocator->fastFree(data); + } + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool VkImageMat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t VkImageMat::total() const +{ + return w * h * d * c; +} + +NCNN_FORCEINLINE int VkImageMat::elembits() const +{ + return elempack ? static_cast(elemsize) * 8 / elempack : 0; +} + +NCNN_FORCEINLINE Mat VkImageMat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE VkImage VkImageMat::image() const +{ + return data->image; +} + +NCNN_FORCEINLINE VkImageView VkImageMat::imageview() const +{ + return data->imageview; +} + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_MAT_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/modelbin.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/modelbin.h new file mode 100644 index 0000000..15d2b9c --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/modelbin.h @@ -0,0 +1,80 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_MODELBIN_H +#define NCNN_MODELBIN_H + +#include "mat.h" + +namespace ncnn { + +class DataReader; +class NCNN_EXPORT ModelBin +{ +public: + ModelBin(); + virtual ~ModelBin(); + // element type + // 0 = auto + // 1 = float32 + // 2 = float16 + // 3 = int8 + // load vec + virtual Mat load(int w, int type) const = 0; + // load image + virtual Mat load(int w, int h, int type) const; + // load dim + virtual Mat load(int w, int h, int c, int type) const; + // load cube + virtual Mat load(int w, int h, int d, int c, int type) const; +}; + +class ModelBinFromDataReaderPrivate; +class NCNN_EXPORT ModelBinFromDataReader : public ModelBin +{ +public: + explicit ModelBinFromDataReader(const DataReader& dr); + virtual ~ModelBinFromDataReader(); + + virtual Mat load(int w, int type) const; + +private: + ModelBinFromDataReader(const ModelBinFromDataReader&); + ModelBinFromDataReader& operator=(const ModelBinFromDataReader&); + +private: + ModelBinFromDataReaderPrivate* const d; +}; + +class ModelBinFromMatArrayPrivate; +class NCNN_EXPORT ModelBinFromMatArray : public ModelBin +{ +public: + // construct from weight blob array + explicit ModelBinFromMatArray(const Mat* weights); + virtual ~ModelBinFromMatArray(); + + virtual Mat load(int w, int type) const; + +private: + ModelBinFromMatArray(const ModelBinFromMatArray&); + ModelBinFromMatArray& operator=(const ModelBinFromMatArray&); + +private: + ModelBinFromMatArrayPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_MODELBIN_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/ncnn_export.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/ncnn_export.h new file mode 100644 index 0000000..e2f5fde --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/ncnn_export.h @@ -0,0 +1,42 @@ + +#ifndef NCNN_EXPORT_H +#define NCNN_EXPORT_H + +#ifdef NCNN_STATIC_DEFINE +# define NCNN_EXPORT +# define NCNN_NO_EXPORT +#else +# ifndef NCNN_EXPORT +# ifdef ncnn_EXPORTS + /* We are building this library */ +# define NCNN_EXPORT __attribute__((visibility("default"))) +# else + /* We are using this library */ +# define NCNN_EXPORT __attribute__((visibility("default"))) +# endif +# endif + +# ifndef NCNN_NO_EXPORT +# define NCNN_NO_EXPORT __attribute__((visibility("hidden"))) +# endif +#endif + +#ifndef NCNN_DEPRECATED +# define NCNN_DEPRECATED __attribute__ ((__deprecated__)) +#endif + +#ifndef NCNN_DEPRECATED_EXPORT +# define NCNN_DEPRECATED_EXPORT NCNN_EXPORT NCNN_DEPRECATED +#endif + +#ifndef NCNN_DEPRECATED_NO_EXPORT +# define NCNN_DEPRECATED_NO_EXPORT NCNN_NO_EXPORT NCNN_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef NCNN_NO_DEPRECATED +# define NCNN_NO_DEPRECATED +# endif +#endif + +#endif /* NCNN_EXPORT_H */ diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/net.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/net.h new file mode 100644 index 0000000..9407042 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/net.h @@ -0,0 +1,272 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_NET_H +#define NCNN_NET_H + +#include "blob.h" +#include "layer.h" +#include "mat.h" +#include "option.h" +#include "platform.h" + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +#if NCNN_VULKAN +class VkCompute; +#endif // NCNN_VULKAN +class DataReader; +class Extractor; +class NetPrivate; +class NCNN_EXPORT Net +{ +public: + // empty init + Net(); + // clear and destroy + virtual ~Net(); + +public: + // option can be changed before loading + Option opt; + +#if NCNN_VULKAN + // set gpu device by index + void set_vulkan_device(int device_index); + + // set gpu device by device handle, no owner transfer + void set_vulkan_device(const VulkanDevice* vkdev); + + const VulkanDevice* vulkan_device() const; +#endif // NCNN_VULKAN + +#if NCNN_STRING + // register custom layer by layer type name + // return 0 if success + int register_custom_layer(const char* type, layer_creator_func creator, layer_destroyer_func destroyer = 0, void* userdata = 0); + virtual int custom_layer_to_index(const char* type); +#endif // NCNN_STRING + // register custom layer by layer type + // return 0 if success + int register_custom_layer(int index, layer_creator_func creator, layer_destroyer_func destroyer = 0, void* userdata = 0); + +#if NCNN_STRING + int load_param(const DataReader& dr); +#endif // NCNN_STRING + + int load_param_bin(const DataReader& dr); + + int load_model(const DataReader& dr); + +#if NCNN_STDIO +#if NCNN_STRING + // load network structure from plain param file + // return 0 if success + int load_param(FILE* fp); + int load_param(const char* protopath); + int load_param_mem(const char* mem); +#endif // NCNN_STRING + // load network structure from binary param file + // return 0 if success + int load_param_bin(FILE* fp); + int load_param_bin(const char* protopath); + + // load network weight data from model file + // return 0 if success + int load_model(FILE* fp); + int load_model(const char* modelpath); +#endif // NCNN_STDIO + + // load network structure from external memory + // memory pointer must be 32-bit aligned + // return bytes consumed + int load_param(const unsigned char* mem); + + // reference network weight data from external memory + // weight data is not copied but referenced + // so external memory should be retained when used + // memory pointer must be 32-bit aligned + // return bytes consumed + int load_model(const unsigned char* mem); + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#if NCNN_STRING + // convenient load network structure from android asset plain param file + int load_param(AAsset* asset); + int load_param(AAssetManager* mgr, const char* assetpath); +#endif // NCNN_STRING + // convenient load network structure from android asset binary param file + int load_param_bin(AAsset* asset); + int load_param_bin(AAssetManager* mgr, const char* assetpath); + + // convenient load network weight data from android asset model file + int load_model(AAsset* asset); + int load_model(AAssetManager* mgr, const char* assetpath); +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + + // unload network structure and weight data + void clear(); + + // construct an Extractor from network + Extractor create_extractor() const; + + // get input/output indexes/names + const std::vector& input_indexes() const; + const std::vector& output_indexes() const; +#if NCNN_STRING + const std::vector& input_names() const; + const std::vector& output_names() const; +#endif + + const std::vector& blobs() const; + const std::vector& layers() const; + + std::vector& mutable_blobs(); + std::vector& mutable_layers(); + +protected: + friend class Extractor; +#if NCNN_STRING + int find_blob_index_by_name(const char* name) const; + int find_layer_index_by_name(const char* name) const; + virtual Layer* create_custom_layer(const char* type); +#endif // NCNN_STRING + virtual Layer* create_custom_layer(int index); + +private: + Net(const Net&); + Net& operator=(const Net&); + +private: + NetPrivate* const d; +}; + +class ExtractorPrivate; +class NCNN_EXPORT Extractor +{ +public: + virtual ~Extractor(); + + // copy + Extractor(const Extractor&); + + // assign + Extractor& operator=(const Extractor&); + + // clear blob mats and alloctors + void clear(); + + // enable light mode + // intermediate blob will be recycled when enabled + // enabled by default + void set_light_mode(bool enable); + + // set thread count for this extractor + // this will overwrite the global setting + // default count is system depended + void set_num_threads(int num_threads); + + // set blob memory allocator + void set_blob_allocator(Allocator* allocator); + + // set workspace memory allocator + void set_workspace_allocator(Allocator* allocator); + +#if NCNN_VULKAN + void set_vulkan_compute(bool enable); + + void set_blob_vkallocator(VkAllocator* allocator); + + void set_workspace_vkallocator(VkAllocator* allocator); + + void set_staging_vkallocator(VkAllocator* allocator); +#endif // NCNN_VULKAN + +#if NCNN_STRING + // set input by blob name + // return 0 if success + int input(const char* blob_name, const Mat& in); + + // get result by blob name + // return 0 if success + // type = 0, default + // type = 1, do not convert fp16/bf16 or / and packing + int extract(const char* blob_name, Mat& feat, int type = 0); +#endif // NCNN_STRING + + // set input by blob index + // return 0 if success + int input(int blob_index, const Mat& in); + + // get result by blob index + // return 0 if success + // type = 0, default + // type = 1, do not convert fp16/bf16 or / and packing + int extract(int blob_index, Mat& feat, int type = 0); + +#if NCNN_VULKAN +#if NCNN_STRING + // set input by blob name + // return 0 if success + int input(const char* blob_name, const VkMat& in); + + // get result by blob name + // return 0 if success + int extract(const char* blob_name, VkMat& feat, VkCompute& cmd); + + // set input by blob name + // return 0 if success + int input(const char* blob_name, const VkImageMat& in); + + // get result by blob name + // return 0 if success + int extract(const char* blob_name, VkImageMat& feat, VkCompute& cmd); +#endif // NCNN_STRING + + // set input by blob index + // return 0 if success + int input(int blob_index, const VkMat& in); + + // get result by blob index + // return 0 if success + int extract(int blob_index, VkMat& feat, VkCompute& cmd); + + // set input by blob index + // return 0 if success + int input(int blob_index, const VkImageMat& in); + + // get result by blob index + // return 0 if success + int extract(int blob_index, VkImageMat& feat, VkCompute& cmd); +#endif // NCNN_VULKAN + +protected: + friend Extractor Net::create_extractor() const; + Extractor(const Net* net, size_t blob_count); + +private: + ExtractorPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_NET_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/option.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/option.h new file mode 100644 index 0000000..3fda808 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/option.h @@ -0,0 +1,153 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_OPTION_H +#define NCNN_OPTION_H + +#include "platform.h" + +namespace ncnn { + +#if NCNN_VULKAN +class VkAllocator; +class PipelineCache; +#endif // NCNN_VULKAN + +class Allocator; +class NCNN_EXPORT Option +{ +public: + // default option + Option(); + +public: + // light mode + // intermediate blob will be recycled when enabled + // enabled by default + bool lightmode; + + // thread count + // default value is the one returned by get_cpu_count() + int num_threads; + + // blob memory allocator + Allocator* blob_allocator; + + // workspace memory allocator + Allocator* workspace_allocator; + +#if NCNN_VULKAN + // blob memory allocator + VkAllocator* blob_vkallocator; + + // workspace memory allocator + VkAllocator* workspace_vkallocator; + + // staging memory allocator + VkAllocator* staging_vkallocator; + + // pipeline cache + PipelineCache* pipeline_cache; +#endif // NCNN_VULKAN + + // the time openmp threads busy-wait for more work before going to sleep + // default value is 20ms to keep the cores enabled + // without too much extra power consumption afterwards + int openmp_blocktime; + + // enable winograd convolution optimization + // improve convolution 3x3 stride1 performance, may consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_winograd_convolution; + + // enable sgemm convolution optimization + // improve convolution 1x1 stride1 performance, may consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_sgemm_convolution; + + // enable quantized int8 inference + // use low-precision int8 path for quantized model + // changes should be applied before loading network structure and weight + // enabled by default + bool use_int8_inference; + + // enable vulkan compute + bool use_vulkan_compute; + + // enable bf16 data type for storage + // improve most operator performance on all arm devices, may consume more memory + bool use_bf16_storage; + + // enable options for gpu inference + bool use_fp16_packed; + bool use_fp16_storage; + bool use_fp16_arithmetic; + bool use_int8_packed; + bool use_int8_storage; + bool use_int8_arithmetic; + + // enable simd-friendly packed memory layout + // improve all operator performance on all arm devices, will consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_packing_layout; + + bool use_shader_pack8; + + // subgroup option + bool use_subgroup_basic; + bool use_subgroup_vote; + bool use_subgroup_ballot; + bool use_subgroup_shuffle; + + // turn on for adreno + bool use_image_storage; + bool use_tensor_storage; + + bool use_reserved_0; + + // enable DAZ(Denormals-Are-Zero) and FTZ(Flush-To-Zero) + // default value is 3 + // 0 = DAZ OFF, FTZ OFF + // 1 = DAZ ON , FTZ OFF + // 2 = DAZ OFF, FTZ ON + // 3 = DAZ ON, FTZ ON + int flush_denormals; + + bool use_local_pool_allocator; + + // enable local memory optimization for gpu inference + bool use_shader_local_memory; + + // enable cooperative matrix optimization for gpu inference + bool use_cooperative_matrix; + + // more fine-grained control of winograd convolution + bool use_winograd23_convolution; + bool use_winograd43_convolution; + bool use_winograd63_convolution; + + bool use_reserved_6; + bool use_reserved_7; + bool use_reserved_8; + bool use_reserved_9; + bool use_reserved_10; + bool use_reserved_11; +}; + +} // namespace ncnn + +#endif // NCNN_OPTION_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/paramdict.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/paramdict.h new file mode 100644 index 0000000..c2ef160 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/paramdict.h @@ -0,0 +1,73 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PARAMDICT_H +#define NCNN_PARAMDICT_H + +#include "mat.h" + +// at most 32 parameters +#define NCNN_MAX_PARAM_COUNT 32 + +namespace ncnn { + +class DataReader; +class Net; +class ParamDictPrivate; +class NCNN_EXPORT ParamDict +{ +public: + // empty + ParamDict(); + + virtual ~ParamDict(); + + // copy + ParamDict(const ParamDict&); + + // assign + ParamDict& operator=(const ParamDict&); + + // get type + int type(int id) const; + + // get int + int get(int id, int def) const; + // get float + float get(int id, float def) const; + // get array + Mat get(int id, const Mat& def) const; + + // set int + void set(int id, int i); + // set float + void set(int id, float f); + // set array + void set(int id, const Mat& v); + +protected: + friend class Net; + + void clear(); + + int load_param(const DataReader& dr); + int load_param_bin(const DataReader& dr); + +private: + ParamDictPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_PARAMDICT_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/pipeline.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/pipeline.h new file mode 100644 index 0000000..c284a14 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/pipeline.h @@ -0,0 +1,113 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PIPELINE_H +#define NCNN_PIPELINE_H + +#include "mat.h" +#include "platform.h" +#if NCNN_VULKAN +#include "gpu.h" + +#include +#endif // NCNN_VULKAN + +namespace ncnn { + +#if NCNN_VULKAN +class Option; +class PipelinePrivate; +class NCNN_EXPORT Pipeline +{ +public: + explicit Pipeline(const VulkanDevice* vkdev); + virtual ~Pipeline(); + +public: + void set_optimal_local_size_xyz(int w = 4, int h = 4, int c = 4); + void set_optimal_local_size_xyz(const Mat& local_size_xyz); + void set_local_size_xyz(int w, int h, int c); + + int create(const uint32_t* spv_data, size_t spv_data_size, const std::vector& specializations); + + int create(int shader_type_index, const Option& opt, const std::vector& specializations); + +public: + VkShaderModule shader_module() const; + VkDescriptorSetLayout descriptorset_layout() const; + VkPipelineLayout pipeline_layout() const; + VkPipeline pipeline() const; + VkDescriptorUpdateTemplateKHR descriptor_update_template() const; + + const ShaderInfo& shader_info() const; + + uint32_t local_size_x() const; + uint32_t local_size_y() const; + uint32_t local_size_z() const; + +protected: + void set_shader_module(VkShaderModule shader_module); + void set_descriptorset_layout(VkDescriptorSetLayout descriptorset_layout); + void set_pipeline_layout(VkPipelineLayout pipeline_layout); + void set_pipeline(VkPipeline pipeline); + void set_descriptor_update_template(VkDescriptorUpdateTemplateKHR descriptor_update_template); + + void set_shader_info(const ShaderInfo& shader_info); + +public: + const VulkanDevice* vkdev; + +private: + Pipeline(const Pipeline&); + Pipeline& operator=(const Pipeline&); + +private: + PipelinePrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class VkCompute; +class NCNN_EXPORT ImportAndroidHardwareBufferPipeline : private Pipeline +{ +public: + explicit ImportAndroidHardwareBufferPipeline(const VulkanDevice* vkdev); + virtual ~ImportAndroidHardwareBufferPipeline(); + + int create(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator, int type_to, int rotate_from, const Option& opt); + int create(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator, int type_to, int rotate_from, int target_width, int target_height, const Option& opt); + void destroy(); + + friend class VkCompute; + +protected: + int create_shader_module(const Option& opt); + int create_sampler(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator); + int create_descriptorset_layout(); + +public: + int type_to; + int rotate_from; + bool need_resize; + + VkSampler sampler; +}; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_PIPELINE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/pipelinecache.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/pipelinecache.h new file mode 100644 index 0000000..bb6b8fb --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/pipelinecache.h @@ -0,0 +1,85 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PIPELINECACHE_H +#define NCNN_PIPELINECACHE_H + +#include "platform.h" + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#include "mat.h" +#include "gpu.h" + +namespace ncnn { + +#if NCNN_VULKAN + +class VulkanDevice; +class PipelineCachePrivate; +class NCNN_EXPORT PipelineCache +{ +public: + explicit PipelineCache(const VulkanDevice* _vkdev); + + virtual ~PipelineCache(); + + void clear(); + + int get_pipeline(const uint32_t* spv_data, size_t spv_data_size, const std::vector& specializations, + uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* shader_module, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template, + ShaderInfo& shader_info) const; + + int get_pipeline(int shader_type_index, const Option& opt, const std::vector& specializations, + uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* shader_module, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template, + ShaderInfo& shader_info) const; + +protected: + int create_shader_module(int shader_type_index, const Option& opt, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* _shader_module, ShaderInfo& si) const; + + int new_pipeline(VkShaderModule shader_module, const ShaderInfo& shader_info, const std::vector& specializations, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template) const; + +protected: + const VulkanDevice* vkdev; + +private: + PipelineCache(const PipelineCache&); + PipelineCache& operator=(const PipelineCache&); + +private: + PipelineCachePrivate* const d; +}; + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_PIPELINECACHE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/platform.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/platform.h new file mode 100644 index 0000000..89f3243 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/platform.h @@ -0,0 +1,285 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PLATFORM_H +#define NCNN_PLATFORM_H + +#define NCNN_STDIO 1 +#define NCNN_STRING 1 +#define NCNN_SIMPLEOCV 0 +#define NCNN_SIMPLEOMP 0 +#define NCNN_SIMPLESTL 0 +#define NCNN_THREADS 1 +#define NCNN_BENCHMARK 0 +#define NCNN_C_API 1 +#define NCNN_PLATFORM_API 1 +#define NCNN_PIXEL 1 +#define NCNN_PIXEL_ROTATE 1 +#define NCNN_PIXEL_AFFINE 1 +#define NCNN_PIXEL_DRAWING 1 +#define NCNN_VULKAN 1 +#define NCNN_SYSTEM_GLSLANG 0 +#define NCNN_RUNTIME_CPU 1 +#define NCNN_AVX 1 +#define NCNN_XOP 1 +#define NCNN_FMA 1 +#define NCNN_F16C 1 +#define NCNN_AVX2 1 +#define NCNN_AVXVNNI 1 +#define NCNN_AVX512 1 +#define NCNN_AVX512VNNI 1 +#define NCNN_AVX512BF16 1 +#define NCNN_AVX512FP16 1 +#define NCNN_VFPV4 0 +#if __aarch64__ +#define NCNN_ARM82 0 +#define NCNN_ARM82DOT 0 +#define NCNN_ARM82FP16FML 0 +#define NCNN_ARM84BF16 0 +#define NCNN_ARM84I8MM 0 +#define NCNN_ARM86SVE 0 +#define NCNN_ARM86SVE2 0 +#define NCNN_ARM86SVEBF16 0 +#define NCNN_ARM86SVEI8MM 0 +#define NCNN_ARM86SVEF32MM 0 +#endif // __aarch64__ +#define NCNN_MSA 0 +#define NCNN_LSX 0 +#define NCNN_MMI 0 +#define NCNN_RVV 0 +#define NCNN_INT8 1 +#define NCNN_BF16 1 +#define NCNN_FORCE_INLINE 1 + +#define NCNN_VERSION_STRING "1.0.20221128" + +#include "ncnn_export.h" + +#ifdef __cplusplus + +#if NCNN_THREADS +#if (defined _WIN32 && !(defined __MINGW32__)) +#define WIN32_LEAN_AND_MEAN +#include +#include +#else +#include +#endif +#endif // NCNN_THREADS + +#if __ANDROID_API__ >= 26 +#define VK_USE_PLATFORM_ANDROID_KHR +#endif // __ANDROID_API__ >= 26 + +namespace ncnn { + +#if NCNN_THREADS +#if (defined _WIN32 && !(defined __MINGW32__)) +class NCNN_EXPORT Mutex +{ +public: + Mutex() { InitializeSRWLock(&srwlock); } + ~Mutex() {} + void lock() { AcquireSRWLockExclusive(&srwlock); } + void unlock() { ReleaseSRWLockExclusive(&srwlock); } +private: + friend class ConditionVariable; + // NOTE SRWLock is available from windows vista + SRWLOCK srwlock; +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() { InitializeConditionVariable(&condvar); } + ~ConditionVariable() {} + void wait(Mutex& mutex) { SleepConditionVariableSRW(&condvar, &mutex.srwlock, INFINITE, 0); } + void broadcast() { WakeAllConditionVariable(&condvar); } + void signal() { WakeConditionVariable(&condvar); } +private: + CONDITION_VARIABLE condvar; +}; + +static unsigned __stdcall start_wrapper(void* args); +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*start)(void*), void* args = 0) { _start = start; _args = args; handle = (HANDLE)_beginthreadex(0, 0, start_wrapper, this, 0, 0); } + ~Thread() {} + void join() { WaitForSingleObject(handle, INFINITE); CloseHandle(handle); } +private: + friend unsigned __stdcall start_wrapper(void* args) + { + Thread* t = (Thread*)args; + t->_start(t->_args); + return 0; + } + HANDLE handle; + void* (*_start)(void*); + void* _args; +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { key = TlsAlloc(); } + ~ThreadLocalStorage() { TlsFree(key); } + void set(void* value) { TlsSetValue(key, (LPVOID)value); } + void* get() { return (void*)TlsGetValue(key); } +private: + DWORD key; +}; +#else // (defined _WIN32 && !(defined __MINGW32__)) +class NCNN_EXPORT Mutex +{ +public: + Mutex() { pthread_mutex_init(&mutex, 0); } + ~Mutex() { pthread_mutex_destroy(&mutex); } + void lock() { pthread_mutex_lock(&mutex); } + void unlock() { pthread_mutex_unlock(&mutex); } +private: + friend class ConditionVariable; + pthread_mutex_t mutex; +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() { pthread_cond_init(&cond, 0); } + ~ConditionVariable() { pthread_cond_destroy(&cond); } + void wait(Mutex& mutex) { pthread_cond_wait(&cond, &mutex.mutex); } + void broadcast() { pthread_cond_broadcast(&cond); } + void signal() { pthread_cond_signal(&cond); } +private: + pthread_cond_t cond; +}; + +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*start)(void*), void* args = 0) { pthread_create(&t, 0, start, args); } + ~Thread() {} + void join() { pthread_join(t, 0); } +private: + pthread_t t; +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { pthread_key_create(&key, 0); } + ~ThreadLocalStorage() { pthread_key_delete(key); } + void set(void* value) { pthread_setspecific(key, value); } + void* get() { return pthread_getspecific(key); } +private: + pthread_key_t key; +}; +#endif // (defined _WIN32 && !(defined __MINGW32__)) +#else // NCNN_THREADS +class NCNN_EXPORT Mutex +{ +public: + Mutex() {} + ~Mutex() {} + void lock() {} + void unlock() {} +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() {} + ~ConditionVariable() {} + void wait(Mutex& /*mutex*/) {} + void broadcast() {} + void signal() {} +}; + +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*/*start*/)(void*), void* /*args*/ = 0) {} + ~Thread() {} + void join() {} +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { data = 0; } + ~ThreadLocalStorage() {} + void set(void* value) { data = value; } + void* get() { return data; } +private: + void* data; +}; +#endif // NCNN_THREADS + +class NCNN_EXPORT MutexLockGuard +{ +public: + MutexLockGuard(Mutex& _mutex) : mutex(_mutex) { mutex.lock(); } + ~MutexLockGuard() { mutex.unlock(); } +private: + Mutex& mutex; +}; + +} // namespace ncnn + +#if NCNN_SIMPLESTL +#include "simplestl.h" +#else +#include +#include +#include +#include +#endif + +#endif // __cplusplus + +#if NCNN_STDIO +#if NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#include +#define NCNN_LOGE(...) do { \ + fprintf(stderr, ##__VA_ARGS__); fprintf(stderr, "\n"); \ + __android_log_print(ANDROID_LOG_WARN, "ncnn", ##__VA_ARGS__); } while(0) +#else // NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#include +#define NCNN_LOGE(...) do { \ + fprintf(stderr, ##__VA_ARGS__); fprintf(stderr, "\n"); } while(0) +#endif // NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#else +#define NCNN_LOGE(...) +#endif + + +#if NCNN_FORCE_INLINE +#ifdef _MSC_VER + #define NCNN_FORCEINLINE __forceinline +#elif defined(__GNUC__) + #define NCNN_FORCEINLINE inline __attribute__((__always_inline__)) +#elif defined(__CLANG__) + #if __has_attribute(__always_inline__) + #define NCNN_FORCEINLINE inline __attribute__((__always_inline__)) + #else + #define NCNN_FORCEINLINE inline + #endif +#else + #define NCNN_FORCEINLINE inline +#endif +#else + #define NCNN_FORCEINLINE inline +#endif + +#endif // NCNN_PLATFORM_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/simpleocv.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/simpleocv.h new file mode 100644 index 0000000..55ede15 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/simpleocv.h @@ -0,0 +1,501 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEOCV_H +#define NCNN_SIMPLEOCV_H + +#include "platform.h" + +#if NCNN_SIMPLEOCV + +#include +#include +#include "allocator.h" +#include "mat.h" + +#if defined(_MSC_VER) || defined(__GNUC__) +#pragma push_macro("min") +#pragma push_macro("max") +#undef min +#undef max +#endif + +#ifndef NCNN_XADD +using ncnn::NCNN_XADD; +#endif + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; + +enum +{ + CV_LOAD_IMAGE_UNCHANGED = -1, + CV_LOAD_IMAGE_GRAYSCALE = 0, + CV_LOAD_IMAGE_COLOR = 1, +}; + +enum +{ + CV_IMWRITE_JPEG_QUALITY = 1 +}; + +// minimal opencv style data structure implementation +namespace cv { + +template +static inline _Tp saturate_cast(int v) +{ + return _Tp(v); +} +template<> +inline uchar saturate_cast(int v) +{ + return (uchar)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); +} + +template +struct Scalar_ +{ + Scalar_() + { + v[0] = 0; + v[1] = 0; + v[2] = 0; + v[3] = 0; + } + Scalar_(_Tp _v0) + { + v[0] = _v0; + v[1] = 0; + v[2] = 0; + v[3] = 0; + } + Scalar_(_Tp _v0, _Tp _v1, _Tp _v2) + { + v[0] = _v0; + v[1] = _v1; + v[2] = _v2; + v[3] = 0; + } + Scalar_(_Tp _v0, _Tp _v1, _Tp _v2, _Tp _v3) + { + v[0] = _v0; + v[1] = _v1; + v[2] = _v2; + v[3] = _v3; + } + + const _Tp operator[](const int i) const + { + return v[i]; + } + + _Tp operator[](const int i) + { + return v[i]; + } + + _Tp v[4]; +}; + +typedef Scalar_ Scalar; + +template +struct Point_ +{ + Point_() + : x(0), y(0) + { + } + Point_(_Tp _x, _Tp _y) + : x(_x), y(_y) + { + } + + template + operator Point_<_Tp2>() const + { + return Point_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y)); + } + + _Tp x; + _Tp y; +}; + +typedef Point_ Point; +typedef Point_ Point2f; + +template +struct Size_ +{ + Size_() + : width(0), height(0) + { + } + Size_(_Tp _w, _Tp _h) + : width(_w), height(_h) + { + } + + template + operator Size_<_Tp2>() const + { + return Size_<_Tp2>(saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); + } + + _Tp width; + _Tp height; +}; + +typedef Size_ Size; +typedef Size_ Size2f; + +template +struct Rect_ +{ + Rect_() + : x(0), y(0), width(0), height(0) + { + } + Rect_(_Tp _x, _Tp _y, _Tp _w, _Tp _h) + : x(_x), y(_y), width(_w), height(_h) + { + } + Rect_(Point_<_Tp> _p, Size_<_Tp> _size) + : x(_p.x), y(_p.y), width(_size.width), height(_size.height) + { + } + + template + operator Rect_<_Tp2>() const + { + return Rect_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y), saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); + } + + _Tp x; + _Tp y; + _Tp width; + _Tp height; + + // area + _Tp area() const + { + return width * height; + } +}; + +template +static inline Rect_<_Tp>& operator&=(Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + _Tp x1 = std::max(a.x, b.x), y1 = std::max(a.y, b.y); + a.width = std::min(a.x + a.width, b.x + b.width) - x1; + a.height = std::min(a.y + a.height, b.y + b.height) - y1; + a.x = x1; + a.y = y1; + if (a.width <= 0 || a.height <= 0) + a = Rect_<_Tp>(); + return a; +} + +template +static inline Rect_<_Tp>& operator|=(Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + _Tp x1 = std::min(a.x, b.x), y1 = std::min(a.y, b.y); + a.width = std::max(a.x + a.width, b.x + b.width) - x1; + a.height = std::max(a.y + a.height, b.y + b.height) - y1; + a.x = x1; + a.y = y1; + return a; +} + +template +static inline Rect_<_Tp> operator&(const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c &= b; +} + +template +static inline Rect_<_Tp> operator|(const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c |= b; +} + +typedef Rect_ Rect; +typedef Rect_ Rect2f; + +#define CV_8UC1 1 +#define CV_8UC3 3 +#define CV_8UC4 4 +#define CV_32FC1 4 + +struct NCNN_EXPORT Mat +{ + Mat() + : data(0), refcount(0), rows(0), cols(0), c(0) + { + } + + Mat(int _rows, int _cols, int flags) + : data(0), refcount(0) + { + create(_rows, _cols, flags); + } + + // copy + Mat(const Mat& m) + : data(m.data), refcount(m.refcount) + { + if (refcount) + NCNN_XADD(refcount, 1); + + rows = m.rows; + cols = m.cols; + c = m.c; + } + + Mat(int _rows, int _cols, int flags, void* _data) + : data((unsigned char*)_data), refcount(0) + { + rows = _rows; + cols = _cols; + c = flags; + } + + ~Mat() + { + release(); + } + + // assign + Mat& operator=(const Mat& m) + { + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + + rows = m.rows; + cols = m.cols; + c = m.c; + + return *this; + } + + Mat& operator=(const Scalar& s) + { + if (total() > 0) + { + uchar* p = data; + for (int i = 0; i < cols * rows; i++) + { + for (int j = 0; j < c; j++) + { + *p++ = s[j]; + } + } + } + + return *this; + } + + void create(int _rows, int _cols, int flags) + { + release(); + + rows = _rows; + cols = _cols; + c = flags; + + if (total() > 0) + { + // refcount address must be aligned, so we expand totalsize here + size_t totalsize = (total() + 3) >> 2 << 2; + data = (uchar*)ncnn::fastMalloc(totalsize + (int)sizeof(*refcount)); + refcount = (int*)(((uchar*)data) + totalsize); + *refcount = 1; + } + } + + void release() + { + if (refcount && NCNN_XADD(refcount, -1) == 1) + ncnn::fastFree(data); + + data = 0; + + rows = 0; + cols = 0; + c = 0; + + refcount = 0; + } + + Mat clone() const + { + if (empty()) + return Mat(); + + Mat m(rows, cols, c); + + if (total() > 0) + { + memcpy(m.data, data, total()); + } + + return m; + } + + bool empty() const + { + return data == 0 || total() == 0; + } + + int channels() const + { + return c; + } + + int type() const + { + return c; + } + + size_t total() const + { + return cols * rows * c; + } + + const uchar* ptr(int y) const + { + return data + y * cols * c; + } + + uchar* ptr(int y) + { + return data + y * cols * c; + } + + template + const _Tp* ptr(int y) const + { + return (const _Tp*)data + y * cols * c; + } + + template + _Tp* ptr(int y) + { + return (_Tp*)data + y * cols * c; + } + + // roi + Mat operator()(const Rect& roi) const + { + if (empty()) + return Mat(); + + Mat m(roi.height, roi.width, c); + + int sy = roi.y; + for (int y = 0; y < roi.height; y++) + { + const uchar* sptr = ptr(sy) + roi.x * c; + uchar* dptr = m.ptr(y); + memcpy(dptr, sptr, roi.width * c); + sy++; + } + + return m; + } + + uchar* data; + + // pointer to the reference counter; + // when points to user-allocated data, the pointer is NULL + int* refcount; + + int rows; + int cols; + + int c; +}; + +enum ImreadModes +{ + IMREAD_UNCHANGED = -1, + IMREAD_GRAYSCALE = 0, + IMREAD_COLOR = 1 +}; + +NCNN_EXPORT Mat imread(const std::string& path, int flags = IMREAD_COLOR); + +enum ImwriteFlags +{ + IMWRITE_JPEG_QUALITY = 1 +}; + +NCNN_EXPORT bool imwrite(const std::string& path, const Mat& m, const std::vector& params = std::vector()); + +NCNN_EXPORT void imshow(const std::string& name, const Mat& m); + +NCNN_EXPORT int waitKey(int delay = 0); + +#if NCNN_PIXEL +NCNN_EXPORT void resize(const Mat& src, Mat& dst, const Size& size, float sw = 0.f, float sh = 0.f, int flags = 0); +#endif // NCNN_PIXEL + +#if NCNN_PIXEL_DRAWING + +enum +{ + FILLED = -1 +}; + +NCNN_EXPORT void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void rectangle(Mat& img, Rect rec, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void circle(Mat& img, Point center, int radius, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void line(Mat& img, Point p0, Point p1, const Scalar& color, int thickness = 1); + +enum +{ + FONT_HERSHEY_SIMPLEX = 0 +}; + +NCNN_EXPORT void putText(Mat& img, const std::string& text, Point org, int fontFace, double fontScale, Scalar color, int thickness = 1); + +NCNN_EXPORT Size getTextSize(const std::string& text, int fontFace, double fontScale, int thickness, int* baseLine); + +#endif // NCNN_PIXEL_DRAWING + +} // namespace cv + +#if defined(_MSC_VER) || defined(__GNUC__) +#pragma pop_macro("min") +#pragma pop_macro("max") +#endif + +#endif // NCNN_SIMPLEOCV + +#endif // NCNN_SIMPLEOCV_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/simpleomp.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/simpleomp.h new file mode 100644 index 0000000..13e2452 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/simpleomp.h @@ -0,0 +1,53 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEOMP_H +#define NCNN_SIMPLEOMP_H + +#include "platform.h" + +#if NCNN_SIMPLEOMP + +#include + +// This minimal openmp runtime implementation only supports the llvm openmp abi +// and only supports #pragma omp parallel for num_threads(X) + +#ifdef __cplusplus +extern "C" { +#endif + +NCNN_EXPORT int omp_get_max_threads(); + +NCNN_EXPORT void omp_set_num_threads(int num_threads); + +NCNN_EXPORT int omp_get_dynamic(); + +NCNN_EXPORT void omp_set_dynamic(int dynamic); + +NCNN_EXPORT int omp_get_num_threads(); + +NCNN_EXPORT int omp_get_thread_num(); + +NCNN_EXPORT int kmp_get_blocktime(); + +NCNN_EXPORT void kmp_set_blocktime(int blocktime); + +#ifdef __cplusplus +} +#endif + +#endif // NCNN_SIMPLEOMP + +#endif // NCNN_SIMPLEOMP_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/simplestl.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/simplestl.h new file mode 100644 index 0000000..00ff468 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/simplestl.h @@ -0,0 +1,565 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLESTL_H +#define NCNN_SIMPLESTL_H + +#include +#include +#include + +#if !NCNN_SIMPLESTL + +#include + +#else + +// allocation functions +NCNN_EXPORT void* operator new(size_t size); +NCNN_EXPORT void* operator new[](size_t size); +// placement allocation functions +NCNN_EXPORT void* operator new(size_t size, void* ptr); +NCNN_EXPORT void* operator new[](size_t size, void* ptr); +// deallocation functions +NCNN_EXPORT void operator delete(void* ptr); +NCNN_EXPORT void operator delete[](void* ptr); +// deallocation functions since c++14 +#if __cplusplus >= 201402L +NCNN_EXPORT void operator delete(void* ptr, size_t sz); +NCNN_EXPORT void operator delete[](void* ptr, size_t sz); +#endif +// placement deallocation functions +NCNN_EXPORT void operator delete(void* ptr, void* voidptr2); +NCNN_EXPORT void operator delete[](void* ptr, void* voidptr2); + +#endif + +// minimal stl data structure implementation +namespace std { + +template +const T& max(const T& a, const T& b) +{ + return (a < b) ? b : a; +} + +template +const T& min(const T& a, const T& b) +{ + return (a > b) ? b : a; +} + +template +void swap(T& a, T& b) +{ + T temp(a); + a = b; + b = temp; +} + +template +struct pair +{ + pair() + : first(), second() + { + } + pair(const T1& t1, const T2& t2) + : first(t1), second(t2) + { + } + + T1 first; + T2 second; +}; + +template +bool operator==(const pair& x, const pair& y) +{ + return (x.first == y.first && x.second == y.second); +} +template +bool operator<(const pair& x, const pair& y) +{ + return x.first < y.first || (!(y.first < x.first) && x.second < y.second); +} +template +bool operator!=(const pair& x, const pair& y) +{ + return !(x == y); +} +template +bool operator>(const pair& x, const pair& y) +{ + return y < x; +} +template +bool operator<=(const pair& x, const pair& y) +{ + return !(y < x); +} +template +bool operator>=(const pair& x, const pair& y) +{ + return !(x < y); +} + +template +pair make_pair(const T1& t1, const T2& t2) +{ + return pair(t1, t2); +} + +template +struct node +{ + node* prev_; + node* next_; + T data_; + + node() + : prev_(0), next_(0), data_() + { + } + node(const T& t) + : prev_(0), next_(0), data_(t) + { + } +}; + +template +struct iter_list +{ + iter_list() + : curr_(0) + { + } + iter_list(node* n) + : curr_(n) + { + } + iter_list(const iter_list& i) + : curr_(i.curr_) + { + } + ~iter_list() + { + } + + iter_list& operator=(const iter_list& i) + { + curr_ = i.curr_; + return *this; + } + + T& operator*() + { + return curr_->data_; + } + T* operator->() + { + return &(curr_->data_); + } + + bool operator==(const iter_list& i) + { + return curr_ == i.curr_; + } + bool operator!=(const iter_list& i) + { + return curr_ != i.curr_; + } + + iter_list& operator++() + { + curr_ = curr_->next_; + return *this; + } + iter_list& operator--() + { + curr_ = curr_->prev_; + return *this; + } + + node* curr_; +}; + +template +struct list +{ + typedef iter_list iterator; + + list() + { + head_ = new node(); + tail_ = head_; + count_ = 0; + } + ~list() + { + clear(); + delete head_; + } + list(const list& l) + { + head_ = new node(); + tail_ = head_; + count_ = 0; + + for (iter_list i = l.begin(); i != l.end(); ++i) + { + push_back(*i); + } + } + + list& operator=(const list& l) + { + if (this == &l) + { + return *this; + } + clear(); + + for (iter_list i = l.begin(); i != l.end(); ++i) + { + push_back(*i); + } + return *this; + } + + void clear() + { + while (count_ > 0) + { + pop_front(); + } + } + + void pop_front() + { + if (count_ > 0) + { + head_ = head_->next_; + delete head_->prev_; + head_->prev_ = 0; + --count_; + } + } + + size_t size() const + { + return count_; + } + iter_list begin() const + { + return iter_list(head_); + } + iter_list end() const + { + return iter_list(tail_); + } + bool empty() const + { + return count_ == 0; + } + + void push_back(const T& t) + { + if (count_ == 0) + { + head_ = new node(t); + head_->prev_ = 0; + head_->next_ = tail_; + tail_->prev_ = head_; + count_ = 1; + } + else + { + node* temp = new node(t); + temp->prev_ = tail_->prev_; + temp->next_ = tail_; + tail_->prev_->next_ = temp; + tail_->prev_ = temp; + ++count_; + } + } + + iter_list erase(iter_list pos) + { + if (pos != end()) + { + node* temp = pos.curr_; + if (temp == head_) + { + ++pos; + temp->next_->prev_ = 0; + head_ = temp->next_; + } + else + { + --pos; + temp->next_->prev_ = temp->prev_; + temp->prev_->next_ = temp->next_; + ++pos; + } + delete temp; + --count_; + } + return pos; + } + +protected: + node* head_; + node* tail_; + size_t count_; +}; + +template +struct greater +{ + bool operator()(const T& x, const T& y) const + { + return (x > y); + } +}; + +template +struct less +{ + bool operator()(const T& x, const T& y) const + { + return (x < y); + } +}; + +template +void partial_sort(RandomAccessIter first, RandomAccessIter middle, RandomAccessIter last, Compare comp) +{ + // [TODO] heap sort should be used here, but we simply use bubble sort now + for (RandomAccessIter i = first; i < middle; ++i) + { + // bubble sort + for (RandomAccessIter j = last - 1; j > first; --j) + { + if (comp(*j, *(j - 1))) + { + swap(*j, *(j - 1)); + } + } + } +} + +template +struct vector +{ + vector() + : data_(0), size_(0), capacity_(0) + { + } + vector(const size_t new_size, const T& value = T()) + : data_(0), size_(0), capacity_(0) + { + resize(new_size, value); + } + ~vector() + { + clear(); + } + vector(const vector& v) + : data_(0), size_(0), capacity_(0) + { + resize(v.size()); + for (size_t i = 0; i < size_; i++) + { + data_[i] = v.data_[i]; + } + } + + vector& operator=(const vector& v) + { + if (this == &v) + { + return *this; + } + resize(0); + resize(v.size()); + for (size_t i = 0; i < size_; i++) + { + data_[i] = v.data_[i]; + } + return *this; + } + + void resize(const size_t new_size, const T& value = T()) + { + try_alloc(new_size); + if (new_size > size_) + { + for (size_t i = size_; i < new_size; i++) + { + new (&data_[i]) T(value); + } + } + else if (new_size < size_) + { + for (size_t i = new_size; i < size_; i++) + { + data_[i].~T(); + } + } + size_ = new_size; + } + + void clear() + { + for (size_t i = 0; i < size_; i++) + { + data_[i].~T(); + } + delete[](char*) data_; + data_ = 0; + size_ = 0; + capacity_ = 0; + } + + T* data() const + { + return data_; + } + size_t size() const + { + return size_; + } + T& operator[](size_t i) const + { + return data_[i]; + } + T* begin() const + { + return &data_[0]; + } + T* end() const + { + return &data_[size_]; + } + bool empty() const + { + return size_ == 0; + } + + void push_back(const T& t) + { + try_alloc(size_ + 1); + new (&data_[size_]) T(t); + size_++; + } + + void insert(T* pos, T* b, T* e) + { + vector* v = 0; + if (b >= begin() && b < end()) + { + //the same vector + v = new vector(*this); + b = v->begin() + (b - begin()); + e = v->begin() + (e - begin()); + } + size_t diff = pos - begin(); + try_alloc(size_ + (e - b)); + pos = begin() + diff; + memmove(pos + (e - b), pos, (end() - pos) * sizeof(T)); + size_t len = e - b; + size_ += len; + for (size_t i = 0; i < len; i++) + { + *pos = *b; + pos++; + b++; + } + delete v; + } + + T* erase(T* pos) + { + pos->~T(); + memmove(pos, pos + 1, (end() - pos - 1) * sizeof(T)); + size_--; + return pos; + } + +protected: + T* data_; + size_t size_; + size_t capacity_; + void try_alloc(size_t new_size) + { + if (new_size * 3 / 2 > capacity_ / 2) + { + capacity_ = new_size * 2; + T* new_data = (T*)new char[capacity_ * sizeof(T)]; + memset(static_cast(new_data), 0, capacity_ * sizeof(T)); + if (data_) + { + memmove(new_data, data_, sizeof(T) * size_); + delete[](char*) data_; + } + data_ = new_data; + } + } +}; + +struct NCNN_EXPORT string : public vector +{ + string() + { + } + string(const char* str) + { + size_t len = strlen(str); + resize(len); + memcpy(data_, str, len); + } + const char* c_str() const + { + return (const char*)data_; + } + bool operator==(const string& str2) const + { + return strcmp(data_, str2.data_) == 0; + } + bool operator==(const char* str2) const + { + return strcmp(data_, str2) == 0; + } + bool operator!=(const char* str2) const + { + return strcmp(data_, str2) != 0; + } + string& operator+=(const string& str1) + { + insert(end(), str1.begin(), str1.end()); + return *this; + } +}; + +inline string operator+(const string& str1, const string& str2) +{ + string str(str1); + str.insert(str.end(), str2.begin(), str2.end()); + return str; +} + +} // namespace std + +#endif // NCNN_SIMPLESTL_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/vulkan_header_fix.h b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/vulkan_header_fix.h new file mode 100644 index 0000000..e7a7e8e --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/include/ncnn/vulkan_header_fix.h @@ -0,0 +1,251 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_VULKAN_HEADER_FIX_H +#define NCNN_VULKAN_HEADER_FIX_H + +#include + +// This header contains new structure and function declearation to fix build with old vulkan sdk + +#if VK_HEADER_VERSION < 70 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES (VkStructureType)1000094000 +typedef enum VkSubgroupFeatureFlagBits +{ + VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001, + VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002, + VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004, + VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008, + VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010, + VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020, + VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040, + VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080, + VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 0x00000100, + VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubgroupFeatureFlagBits; +typedef VkFlags VkSubgroupFeatureFlags; +typedef struct VkPhysicalDeviceSubgroupProperties +{ + VkStructureType sType; + void* pNext; + uint32_t subgroupSize; + VkShaderStageFlags supportedStages; + VkSubgroupFeatureFlags supportedOperations; + VkBool32 quadOperationsInAllStages; +} VkPhysicalDeviceSubgroupProperties; +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES (VkStructureType)1000168000 +#define VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT (VkStructureType)1000168001 +typedef struct VkPhysicalDeviceMaintenance3Properties +{ + VkStructureType sType; + void* pNext; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceMaintenance3Properties; +typedef struct VkDescriptorSetLayoutSupport +{ + VkStructureType sType; + void* pNext; + VkBool32 supported; +} VkDescriptorSetLayoutSupport; +typedef VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; +typedef VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; +typedef void(VKAPI_PTR* PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); +#endif // VK_HEADER_VERSION < 70 + +#if VK_HEADER_VERSION < 80 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR (VkStructureType)1000177000 +typedef struct VkPhysicalDevice8BitStorageFeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; +} VkPhysicalDevice8BitStorageFeaturesKHR; +#define VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR (VkStructureType)1000109000 +#define VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR (VkStructureType)1000109001 +#define VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR (VkStructureType)1000109002 +#define VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR (VkStructureType)1000109003 +#define VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR (VkStructureType)1000109004 +#define VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR (VkStructureType)1000109005 +#define VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR (VkStructureType)1000109006 +typedef struct VkAttachmentDescription2KHR +{ + VkStructureType sType; + const void* pNext; + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription2KHR; +typedef struct VkAttachmentReference2KHR +{ + VkStructureType sType; + const void* pNext; + uint32_t attachment; + VkImageLayout layout; + VkImageAspectFlags aspectMask; +} VkAttachmentReference2KHR; +typedef struct VkSubpassDescription2KHR +{ + VkStructureType sType; + const void* pNext; + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t viewMask; + uint32_t inputAttachmentCount; + const VkAttachmentReference2KHR* pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference2KHR* pColorAttachments; + const VkAttachmentReference2KHR* pResolveAttachments; + const VkAttachmentReference2KHR* pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t* pPreserveAttachments; +} VkSubpassDescription2KHR; +typedef struct VkSubpassDependency2KHR +{ + VkStructureType sType; + const void* pNext; + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; + int32_t viewOffset; +} VkSubpassDependency2KHR; +typedef struct VkRenderPassCreateInfo2KHR +{ + VkStructureType sType; + const void* pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription2KHR* pAttachments; + uint32_t subpassCount; + const VkSubpassDescription2KHR* pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency2KHR* pDependencies; + uint32_t correlatedViewMaskCount; + const uint32_t* pCorrelatedViewMasks; +} VkRenderPassCreateInfo2KHR; +typedef struct VkSubpassBeginInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkSubpassContents contents; +} VkSubpassBeginInfoKHR; + +typedef struct VkSubpassEndInfoKHR +{ + VkStructureType sType; + const void* pNext; +} VkSubpassEndInfoKHR; +typedef VkResult(VKAPI_PTR* PFN_vkCreateRenderPass2KHR)(VkDevice device, const VkRenderPassCreateInfo2KHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void(VKAPI_PTR* PFN_vkCmdBeginRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfoKHR* pSubpassBeginInfo); +typedef void(VKAPI_PTR* PFN_vkCmdNextSubpass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfoKHR* pSubpassBeginInfo, const VkSubpassEndInfoKHR* pSubpassEndInfo); +typedef void(VKAPI_PTR* PFN_vkCmdEndRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassEndInfoKHR* pSubpassEndInfo); +#endif // VK_HEADER_VERSION < 80 + +#if VK_HEADER_VERSION < 95 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR (VkStructureType)1000082000 +typedef struct VkPhysicalDeviceFloat16Int8FeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; +} VkPhysicalDeviceFloat16Int8FeaturesKHR; +#endif // VK_HEADER_VERSION < 95 + +#if VK_HEADER_VERSION < 97 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT (VkStructureType)1000237000 +typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT +{ + VkStructureType sType; + void* pNext; + VkDeviceSize heapBudget[VK_MAX_MEMORY_HEAPS]; + VkDeviceSize heapUsage[VK_MAX_MEMORY_HEAPS]; +} VkPhysicalDeviceMemoryBudgetPropertiesEXT; +#endif // VK_HEADER_VERSION < 97 + +#if VK_HEADER_VERSION < 101 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV (VkStructureType)1000249000 +#define VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV (VkStructureType)1000249001 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV (VkStructureType)1000249002 +typedef enum VkComponentTypeNV +{ + VK_COMPONENT_TYPE_FLOAT16_NV = 0, + VK_COMPONENT_TYPE_FLOAT32_NV = 1, + VK_COMPONENT_TYPE_FLOAT64_NV = 2, + VK_COMPONENT_TYPE_SINT8_NV = 3, + VK_COMPONENT_TYPE_SINT16_NV = 4, + VK_COMPONENT_TYPE_SINT32_NV = 5, + VK_COMPONENT_TYPE_SINT64_NV = 6, + VK_COMPONENT_TYPE_UINT8_NV = 7, + VK_COMPONENT_TYPE_UINT16_NV = 8, + VK_COMPONENT_TYPE_UINT32_NV = 9, + VK_COMPONENT_TYPE_UINT64_NV = 10, + VK_COMPONENT_TYPE_BEGIN_RANGE_NV = VK_COMPONENT_TYPE_FLOAT16_NV, + VK_COMPONENT_TYPE_END_RANGE_NV = VK_COMPONENT_TYPE_UINT64_NV, + VK_COMPONENT_TYPE_RANGE_SIZE_NV = (VK_COMPONENT_TYPE_UINT64_NV - VK_COMPONENT_TYPE_FLOAT16_NV + 1), + VK_COMPONENT_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkComponentTypeNV; +typedef enum VkScopeNV +{ + VK_SCOPE_DEVICE_NV = 1, + VK_SCOPE_WORKGROUP_NV = 2, + VK_SCOPE_SUBGROUP_NV = 3, + VK_SCOPE_QUEUE_FAMILY_NV = 5, + VK_SCOPE_BEGIN_RANGE_NV = VK_SCOPE_DEVICE_NV, + VK_SCOPE_END_RANGE_NV = VK_SCOPE_QUEUE_FAMILY_NV, + VK_SCOPE_RANGE_SIZE_NV = (VK_SCOPE_QUEUE_FAMILY_NV - VK_SCOPE_DEVICE_NV + 1), + VK_SCOPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkScopeNV; +typedef struct VkCooperativeMatrixPropertiesNV +{ + VkStructureType sType; + void* pNext; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeNV AType; + VkComponentTypeNV BType; + VkComponentTypeNV CType; + VkComponentTypeNV DType; + VkScopeNV scope; +} VkCooperativeMatrixPropertiesNV; +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesNV +{ + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesNV; +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesNV +{ + VkStructureType sType; + void* pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesNV; +typedef VkResult(VKAPI_PTR* PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixPropertiesNV* pProperties); +#endif // VK_HEADER_VERSION < 101 + +#endif // NCNN_VULKAN_HEADER_FIX_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/lib/cmake/ncnn/ncnn-release.cmake b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/lib/cmake/ncnn/ncnn-release.cmake new file mode 100644 index 0000000..1fb8660 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/lib/cmake/ncnn/ncnn-release.cmake @@ -0,0 +1,19 @@ +#---------------------------------------------------------------- +# Generated CMake target import file for configuration "Release". +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "ncnn" for configuration "Release" +set_property(TARGET ncnn APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(ncnn PROPERTIES + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libncnn.so" + IMPORTED_SONAME_RELEASE "libncnn.so" + ) + +list(APPEND _cmake_import_check_targets ncnn ) +list(APPEND _cmake_import_check_files_for_ncnn "${_IMPORT_PREFIX}/lib/libncnn.so" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/lib/cmake/ncnn/ncnn.cmake b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/lib/cmake/ncnn/ncnn.cmake new file mode 100644 index 0000000..53b9fae --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/lib/cmake/ncnn/ncnn.cmake @@ -0,0 +1,109 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8) + message(FATAL_ERROR "CMake >= 2.8.0 required") +endif() +if(CMAKE_VERSION VERSION_LESS "2.8.3") + message(FATAL_ERROR "CMake >= 2.8.3 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.8.3...3.23) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_cmake_targets_defined "") +set(_cmake_targets_not_defined "") +set(_cmake_expected_targets "") +foreach(_cmake_expected_target IN ITEMS ncnn) + list(APPEND _cmake_expected_targets "${_cmake_expected_target}") + if(TARGET "${_cmake_expected_target}") + list(APPEND _cmake_targets_defined "${_cmake_expected_target}") + else() + list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") + endif() +endforeach() +unset(_cmake_expected_target) +if(_cmake_targets_defined STREQUAL _cmake_expected_targets) + unset(_cmake_targets_defined) + unset(_cmake_targets_not_defined) + unset(_cmake_expected_targets) + unset(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT _cmake_targets_defined STREQUAL "") + string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") + string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") +endif() +unset(_cmake_targets_defined) +unset(_cmake_targets_not_defined) +unset(_cmake_expected_targets) + + +# Compute the installation prefix relative to this file. +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +if(_IMPORT_PREFIX STREQUAL "/") + set(_IMPORT_PREFIX "") +endif() + +# Create imported target ncnn +add_library(ncnn SHARED IMPORTED) + +set_target_properties(ncnn PROPERTIES + INTERFACE_COMPILE_OPTIONS "-fno-rtti;-fno-exceptions" + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include/ncnn" + INTERFACE_LINK_LIBRARIES "-fopenmp;-static-openmp;-Wl,-wrap,__kmp_affinity_determine_capable;Threads::Threads;Vulkan::Vulkan;android;jnigraphics;log" + INTERFACE_POSITION_INDEPENDENT_CODE "ON" +) + +if(CMAKE_VERSION VERSION_LESS 2.8.12) + message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.") +endif() + +# Load information for each installed configuration. +file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/ncnn-*.cmake") +foreach(_cmake_config_file IN LISTS _cmake_config_files) + include("${_cmake_config_file}") +endforeach() +unset(_cmake_config_file) +unset(_cmake_config_files) + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(_cmake_target IN LISTS _cmake_import_check_targets) + foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}") + if(NOT EXISTS "${_cmake_file}") + message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file + \"${_cmake_file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + unset(_cmake_file) + unset("_cmake_import_check_files_for_${_cmake_target}") +endforeach() +unset(_cmake_target) +unset(_cmake_import_check_targets) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/lib/cmake/ncnn/ncnnConfig.cmake b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/lib/cmake/ncnn/ncnnConfig.cmake new file mode 100644 index 0000000..abb2dd6 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/lib/cmake/ncnn/ncnnConfig.cmake @@ -0,0 +1,42 @@ +set(NCNN_OPENMP ON) +set(NCNN_THREADS ON) +set(NCNN_VULKAN ON) +set(NCNN_SHARED_LIB ON) +set(NCNN_SYSTEM_GLSLANG OFF) + +if(NCNN_OPENMP) + find_package(OpenMP) +endif() + +if(NCNN_THREADS) + set(CMAKE_THREAD_PREFER_PTHREAD TRUE) + set(THREADS_PREFER_PTHREAD_FLAG TRUE) + find_package(Threads REQUIRED) +endif() + +if(NCNN_VULKAN) + find_package(Vulkan REQUIRED) + + if(NOT NCNN_SHARED_LIB) + if(NCNN_SYSTEM_GLSLANG) + find_package(glslang QUIET) + if(NOT glslang_FOUND) + set(GLSLANG_TARGET_DIR "") + include(${GLSLANG_TARGET_DIR}/OSDependentTargets.cmake) + include(${GLSLANG_TARGET_DIR}/OGLCompilerTargets.cmake) + if(EXISTS "${GLSLANG_TARGET_DIR}/HLSLTargets.cmake") + # hlsl support can be optional + include("${GLSLANG_TARGET_DIR}/HLSLTargets.cmake") + endif() + include(${GLSLANG_TARGET_DIR}/glslangTargets.cmake) + include(${GLSLANG_TARGET_DIR}/SPIRVTargets.cmake) + endif() + else() + set(glslang_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../lib/cmake/glslang") + find_package(glslang QUIET) + endif() + + endif() +endif() + +include(${CMAKE_CURRENT_LIST_DIR}/ncnn.cmake) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/lib/pkgconfig/ncnn.pc b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/lib/pkgconfig/ncnn.pc new file mode 100644 index 0000000..2ae00de --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20221128-android-vulkan-shared/x86_64/lib/pkgconfig/ncnn.pc @@ -0,0 +1,11 @@ +prefix=${pcfiledir}/../.. +librarydir=${prefix}/lib +includedir=${prefix}/include + +Name: ncnn +Description: high-performance neural network inference framework optimized for the mobile platform +Version: 1.0.20221128 +URL: https://github.com/Tencent/ncnn +Libs: -L"${librarydir}" -lncnn +Cflags: -I"${includedir}" + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/allocator.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/allocator.h new file mode 100644 index 0000000..3a5ebca --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/allocator.h @@ -0,0 +1,448 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_ALLOCATOR_H +#define NCNN_ALLOCATOR_H + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include "platform.h" + +#include + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +#include +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +// the alignment of all the allocated buffers +#if NCNN_AVX512 +#define NCNN_MALLOC_ALIGN 64 +#elif NCNN_AVX +#define NCNN_MALLOC_ALIGN 32 +#else +#define NCNN_MALLOC_ALIGN 16 +#endif + +// we have some optimized kernels that may overread buffer a bit in loop +// it is common to interleave next-loop data load with arithmetic instructions +// allocating more bytes keeps us safe from SEGV_ACCERR failure +#define NCNN_MALLOC_OVERREAD 64 + +// Aligns a pointer to the specified number of bytes +// ptr Aligned pointer +// n Alignment size that must be a power of two +template +static NCNN_FORCEINLINE _Tp* alignPtr(_Tp* ptr, int n = (int)sizeof(_Tp)) +{ + return (_Tp*)(((size_t)ptr + n - 1) & -n); +} + +// Aligns a buffer size to the specified number of bytes +// The function returns the minimum number that is greater or equal to sz and is divisible by n +// sz Buffer size to align +// n Alignment size that must be a power of two +static NCNN_FORCEINLINE size_t alignSize(size_t sz, int n) +{ + return (sz + n - 1) & -n; +} + +static NCNN_FORCEINLINE void* fastMalloc(size_t size) +{ +#if _MSC_VER + return _aligned_malloc(size, NCNN_MALLOC_ALIGN); +#elif (defined(__unix__) || defined(__APPLE__)) && _POSIX_C_SOURCE >= 200112L || (__ANDROID__ && __ANDROID_API__ >= 17) + void* ptr = 0; + if (posix_memalign(&ptr, NCNN_MALLOC_ALIGN, size + NCNN_MALLOC_OVERREAD)) + ptr = 0; + return ptr; +#elif __ANDROID__ && __ANDROID_API__ < 17 + return memalign(NCNN_MALLOC_ALIGN, size + NCNN_MALLOC_OVERREAD); +#else + unsigned char* udata = (unsigned char*)malloc(size + sizeof(void*) + NCNN_MALLOC_ALIGN + NCNN_MALLOC_OVERREAD); + if (!udata) + return 0; + unsigned char** adata = alignPtr((unsigned char**)udata + 1, NCNN_MALLOC_ALIGN); + adata[-1] = udata; + return adata; +#endif +} + +static NCNN_FORCEINLINE void fastFree(void* ptr) +{ + if (ptr) + { +#if _MSC_VER + _aligned_free(ptr); +#elif (defined(__unix__) || defined(__APPLE__)) && _POSIX_C_SOURCE >= 200112L || (__ANDROID__ && __ANDROID_API__ >= 17) + free(ptr); +#elif __ANDROID__ && __ANDROID_API__ < 17 + free(ptr); +#else + unsigned char* udata = ((unsigned char**)ptr)[-1]; + free(udata); +#endif + } +} + +#if NCNN_THREADS +// exchange-add operation for atomic operations on reference counters +#if defined __riscv && !defined __riscv_atomic +// riscv target without A extension +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#elif defined __INTEL_COMPILER && !(defined WIN32 || defined _WIN32) +// atomic increment on the linux version of the Intel(tm) compiler +#define NCNN_XADD(addr, delta) (int)_InterlockedExchangeAdd(const_cast(reinterpret_cast(addr)), delta) +#elif defined __GNUC__ +#if defined __clang__ && __clang_major__ >= 3 && !defined __ANDROID__ && !defined __EMSCRIPTEN__ && !defined(__CUDACC__) +#ifdef __ATOMIC_ACQ_REL +#define NCNN_XADD(addr, delta) __c11_atomic_fetch_add((_Atomic(int)*)(addr), delta, __ATOMIC_ACQ_REL) +#else +#define NCNN_XADD(addr, delta) __atomic_fetch_add((_Atomic(int)*)(addr), delta, 4) +#endif +#else +#if defined __ATOMIC_ACQ_REL && !defined __clang__ +// version for gcc >= 4.7 +#define NCNN_XADD(addr, delta) (int)__atomic_fetch_add((unsigned*)(addr), (unsigned)(delta), __ATOMIC_ACQ_REL) +#else +#define NCNN_XADD(addr, delta) (int)__sync_fetch_and_add((unsigned*)(addr), (unsigned)(delta)) +#endif +#endif +#elif defined _MSC_VER && !defined RC_INVOKED +#define NCNN_XADD(addr, delta) (int)_InterlockedExchangeAdd((long volatile*)addr, delta) +#else +// thread-unsafe branch +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#endif +#else // NCNN_THREADS +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#endif // NCNN_THREADS + +class NCNN_EXPORT Allocator +{ +public: + virtual ~Allocator(); + virtual void* fastMalloc(size_t size) = 0; + virtual void fastFree(void* ptr) = 0; +}; + +class PoolAllocatorPrivate; +class NCNN_EXPORT PoolAllocator : public Allocator +{ +public: + PoolAllocator(); + ~PoolAllocator(); + + // ratio range 0 ~ 1 + // default cr = 0 + void set_size_compare_ratio(float scr); + + // budget drop threshold + // default threshold = 10 + void set_size_drop_threshold(size_t); + + // release all budgets immediately + void clear(); + + virtual void* fastMalloc(size_t size); + virtual void fastFree(void* ptr); + +private: + PoolAllocator(const PoolAllocator&); + PoolAllocator& operator=(const PoolAllocator&); + +private: + PoolAllocatorPrivate* const d; +}; + +class UnlockedPoolAllocatorPrivate; +class NCNN_EXPORT UnlockedPoolAllocator : public Allocator +{ +public: + UnlockedPoolAllocator(); + ~UnlockedPoolAllocator(); + + // ratio range 0 ~ 1 + // default cr = 0 + void set_size_compare_ratio(float scr); + + // budget drop threshold + // default threshold = 10 + void set_size_drop_threshold(size_t); + + // release all budgets immediately + void clear(); + + virtual void* fastMalloc(size_t size); + virtual void fastFree(void* ptr); + +private: + UnlockedPoolAllocator(const UnlockedPoolAllocator&); + UnlockedPoolAllocator& operator=(const UnlockedPoolAllocator&); + +private: + UnlockedPoolAllocatorPrivate* const d; +}; + +#if NCNN_VULKAN + +class VulkanDevice; + +class NCNN_EXPORT VkBufferMemory +{ +public: + VkBuffer buffer; + + // the base offset assigned by allocator + size_t offset; + size_t capacity; + + VkDeviceMemory memory; + void* mapped_ptr; + + // buffer state, modified by command functions internally + mutable VkAccessFlags access_flags; + mutable VkPipelineStageFlags stage_flags; + + // initialize and modified by mat + int refcount; +}; + +class NCNN_EXPORT VkImageMemory +{ +public: + VkImage image; + VkImageView imageview; + + // underlying info assigned by allocator + int width; + int height; + int depth; + VkFormat format; + + VkDeviceMemory memory; + void* mapped_ptr; + + // the base offset assigned by allocator + size_t bind_offset; + size_t bind_capacity; + + // image state, modified by command functions internally + mutable VkAccessFlags access_flags; + mutable VkImageLayout image_layout; + mutable VkPipelineStageFlags stage_flags; + + // in-execution state, modified by command functions internally + mutable int command_refcount; + + // initialize and modified by mat + int refcount; +}; + +class NCNN_EXPORT VkAllocator +{ +public: + explicit VkAllocator(const VulkanDevice* _vkdev); + virtual ~VkAllocator(); + + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size) = 0; + virtual void fastFree(VkBufferMemory* ptr) = 0; + virtual int flush(VkBufferMemory* ptr); + virtual int invalidate(VkBufferMemory* ptr); + + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack) = 0; + virtual void fastFree(VkImageMemory* ptr) = 0; + +public: + const VulkanDevice* vkdev; + uint32_t buffer_memory_type_index; + uint32_t image_memory_type_index; + uint32_t reserved_type_index; + bool mappable; + bool coherent; + +protected: + VkBuffer create_buffer(size_t size, VkBufferUsageFlags usage); + VkDeviceMemory allocate_memory(size_t size, uint32_t memory_type_index); + VkDeviceMemory allocate_dedicated_memory(size_t size, uint32_t memory_type_index, VkImage image, VkBuffer buffer); + + VkImage create_image(int width, int height, int depth, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage); + VkImageView create_imageview(VkImage image, VkFormat format); +}; + +class VkBlobAllocatorPrivate; +class NCNN_EXPORT VkBlobAllocator : public VkAllocator +{ +public: + explicit VkBlobAllocator(const VulkanDevice* vkdev, size_t preferred_block_size = 16 * 1024 * 1024); // 16M + virtual ~VkBlobAllocator(); + +public: + // release all budgets immediately + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkBlobAllocator(const VkBlobAllocator&); + VkBlobAllocator& operator=(const VkBlobAllocator&); + +private: + VkBlobAllocatorPrivate* const d; +}; + +class VkWeightAllocatorPrivate; +class NCNN_EXPORT VkWeightAllocator : public VkAllocator +{ +public: + explicit VkWeightAllocator(const VulkanDevice* vkdev, size_t preferred_block_size = 8 * 1024 * 1024); // 8M + virtual ~VkWeightAllocator(); + +public: + // release all blocks immediately + virtual void clear(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkWeightAllocator(const VkWeightAllocator&); + VkWeightAllocator& operator=(const VkWeightAllocator&); + +private: + VkWeightAllocatorPrivate* const d; +}; + +class VkStagingAllocatorPrivate; +class NCNN_EXPORT VkStagingAllocator : public VkAllocator +{ +public: + explicit VkStagingAllocator(const VulkanDevice* vkdev); + virtual ~VkStagingAllocator(); + +public: + // ratio range 0 ~ 1 + // default cr = 0.75 + void set_size_compare_ratio(float scr); + + // release all budgets immediately + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkStagingAllocator(const VkStagingAllocator&); + VkStagingAllocator& operator=(const VkStagingAllocator&); + +private: + VkStagingAllocatorPrivate* const d; +}; + +class VkWeightStagingAllocatorPrivate; +class NCNN_EXPORT VkWeightStagingAllocator : public VkAllocator +{ +public: + explicit VkWeightStagingAllocator(const VulkanDevice* vkdev); + virtual ~VkWeightStagingAllocator(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkWeightStagingAllocator(const VkWeightStagingAllocator&); + VkWeightStagingAllocator& operator=(const VkWeightStagingAllocator&); + +private: + VkWeightStagingAllocatorPrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class NCNN_EXPORT VkAndroidHardwareBufferImageAllocator : public VkAllocator +{ +public: + VkAndroidHardwareBufferImageAllocator(const VulkanDevice* _vkdev, AHardwareBuffer* _hb); + virtual ~VkAndroidHardwareBufferImageAllocator(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkAndroidHardwareBufferImageAllocator(const VkAndroidHardwareBufferImageAllocator&); + VkAndroidHardwareBufferImageAllocator& operator=(const VkAndroidHardwareBufferImageAllocator&); + +public: + int init(); + + int width() const; + int height() const; + uint64_t external_format() const; + +public: + AHardwareBuffer* hb; + AHardwareBuffer_Desc bufferDesc; + VkAndroidHardwareBufferFormatPropertiesANDROID bufferFormatProperties; + VkAndroidHardwareBufferPropertiesANDROID bufferProperties; + VkSamplerYcbcrConversionKHR samplerYcbcrConversion; +}; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_ALLOCATOR_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/benchmark.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/benchmark.h new file mode 100644 index 0000000..ed42c1a --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/benchmark.h @@ -0,0 +1,39 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_BENCHMARK_H +#define NCNN_BENCHMARK_H + +#include "layer.h" +#include "mat.h" +#include "platform.h" + +namespace ncnn { + +// get now timestamp in ms +NCNN_EXPORT double get_current_time(); + +// sleep milliseconds +NCNN_EXPORT void sleep(unsigned long long int milliseconds = 1000); + +#if NCNN_BENCHMARK + +NCNN_EXPORT void benchmark(const Layer* layer, double start, double end); +NCNN_EXPORT void benchmark(const Layer* layer, const Mat& bottom_blob, Mat& top_blob, double start, double end); + +#endif // NCNN_BENCHMARK + +} // namespace ncnn + +#endif // NCNN_BENCHMARK_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/blob.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/blob.h new file mode 100644 index 0000000..c9f144f --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/blob.h @@ -0,0 +1,44 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_BLOB_H +#define NCNN_BLOB_H + +#include "mat.h" +#include "platform.h" + +namespace ncnn { + +class NCNN_EXPORT Blob +{ +public: + // empty + Blob(); + +public: +#if NCNN_STRING + // blob name + std::string name; +#endif // NCNN_STRING + // layer index which produce this blob as output + int producer; + // layer index which need this blob as input + int consumer; + // shape hint + Mat shape; +}; + +} // namespace ncnn + +#endif // NCNN_BLOB_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/c_api.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/c_api.h new file mode 100644 index 0000000..31d5b6d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/c_api.h @@ -0,0 +1,347 @@ +/* Tencent is pleased to support the open source community by making ncnn available. + * + * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef NCNN_C_API_H +#define NCNN_C_API_H + +#include "platform.h" + +#if NCNN_C_API + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +NCNN_EXPORT const char* ncnn_version(); + +/* allocator api */ +typedef struct __ncnn_allocator_t* ncnn_allocator_t; +struct NCNN_EXPORT __ncnn_allocator_t +{ + void* pthis; + + void* (*fast_malloc)(ncnn_allocator_t allocator, size_t size); + void (*fast_free)(ncnn_allocator_t allocator, void* ptr); +}; + +NCNN_EXPORT ncnn_allocator_t ncnn_allocator_create_pool_allocator(); +NCNN_EXPORT ncnn_allocator_t ncnn_allocator_create_unlocked_pool_allocator(); +NCNN_EXPORT void ncnn_allocator_destroy(ncnn_allocator_t allocator); + +/* option api */ +typedef struct __ncnn_option_t* ncnn_option_t; + +NCNN_EXPORT ncnn_option_t ncnn_option_create(); +NCNN_EXPORT void ncnn_option_destroy(ncnn_option_t opt); + +NCNN_EXPORT int ncnn_option_get_num_threads(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_num_threads(ncnn_option_t opt, int num_threads); + +NCNN_EXPORT int ncnn_option_get_use_local_pool_allocator(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_use_local_pool_allocator(ncnn_option_t opt, int use_local_pool_allocator); + +NCNN_EXPORT void ncnn_option_set_blob_allocator(ncnn_option_t opt, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_option_set_workspace_allocator(ncnn_option_t opt, ncnn_allocator_t allocator); + +NCNN_EXPORT int ncnn_option_get_use_vulkan_compute(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_use_vulkan_compute(ncnn_option_t opt, int use_vulkan_compute); + +/* mat api */ +typedef struct __ncnn_mat_t* ncnn_mat_t; + +NCNN_EXPORT ncnn_mat_t ncnn_mat_create(); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_1d(int w, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_2d(int w, int h, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_3d(int w, int h, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_4d(int w, int h, int d, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_1d(int w, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_2d(int w, int h, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_3d(int w, int h, int c, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_4d(int w, int h, int d, int c, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_1d_elem(int w, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_2d_elem(int w, int h, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_3d_elem(int w, int h, int c, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_4d_elem(int w, int h, int d, int c, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_1d_elem(int w, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_2d_elem(int w, int h, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_3d_elem(int w, int h, int c, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_4d_elem(int w, int h, int d, int c, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_mat_destroy(ncnn_mat_t mat); + +NCNN_EXPORT void ncnn_mat_fill_float(ncnn_mat_t mat, float v); + +NCNN_EXPORT ncnn_mat_t ncnn_mat_clone(const ncnn_mat_t mat, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_1d(const ncnn_mat_t mat, int w, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_2d(const ncnn_mat_t mat, int w, int h, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_3d(const ncnn_mat_t mat, int w, int h, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_4d(const ncnn_mat_t mat, int w, int h, int d, int c, ncnn_allocator_t allocator); + +NCNN_EXPORT int ncnn_mat_get_dims(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_w(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_h(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_d(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_c(const ncnn_mat_t mat); +NCNN_EXPORT size_t ncnn_mat_get_elemsize(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_elempack(const ncnn_mat_t mat); +NCNN_EXPORT size_t ncnn_mat_get_cstep(const ncnn_mat_t mat); +NCNN_EXPORT void* ncnn_mat_get_data(const ncnn_mat_t mat); + +NCNN_EXPORT void* ncnn_mat_get_channel_data(const ncnn_mat_t mat, int c); + +#if NCNN_PIXEL + +/* mat pixel api */ +#define NCNN_MAT_PIXEL_RGB 1 +#define NCNN_MAT_PIXEL_BGR 2 +#define NCNN_MAT_PIXEL_GRAY 3 +#define NCNN_MAT_PIXEL_RGBA 4 +#define NCNN_MAT_PIXEL_BGRA 5 +#define NCNN_MAT_PIXEL_X2Y(X, Y) (X | (Y << 16)) +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels(const unsigned char* pixels, int type, int w, int h, int stride, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, int target_width, int target_height, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_mat_to_pixels(const ncnn_mat_t mat, unsigned char* pixels, int type, int stride); +NCNN_EXPORT void ncnn_mat_to_pixels_resize(const ncnn_mat_t mat, unsigned char* pixels, int type, int target_width, int target_height, int target_stride); + +#endif /* NCNN_PIXEL */ + +NCNN_EXPORT void ncnn_mat_substract_mean_normalize(ncnn_mat_t mat, const float* mean_vals, const float* norm_vals); + +NCNN_EXPORT void ncnn_convert_packing(const ncnn_mat_t src, ncnn_mat_t* dst, int elempack, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_flatten(const ncnn_mat_t src, ncnn_mat_t* dst, const ncnn_option_t opt); + +/* blob api */ +typedef struct __ncnn_blob_t* ncnn_blob_t; + +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_blob_get_name(const ncnn_blob_t blob); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_blob_get_producer(const ncnn_blob_t blob); +NCNN_EXPORT int ncnn_blob_get_consumer(const ncnn_blob_t blob); + +NCNN_EXPORT void ncnn_blob_get_shape(const ncnn_blob_t blob, int* dims, int* w, int* h, int* c); + +/* paramdict api */ +typedef struct __ncnn_paramdict_t* ncnn_paramdict_t; + +NCNN_EXPORT ncnn_paramdict_t ncnn_paramdict_create(); +NCNN_EXPORT void ncnn_paramdict_destroy(ncnn_paramdict_t pd); + +NCNN_EXPORT int ncnn_paramdict_get_type(const ncnn_paramdict_t pd, int id); + +NCNN_EXPORT int ncnn_paramdict_get_int(const ncnn_paramdict_t pd, int id, int def); +NCNN_EXPORT float ncnn_paramdict_get_float(const ncnn_paramdict_t pd, int id, float def); +NCNN_EXPORT ncnn_mat_t ncnn_paramdict_get_array(const ncnn_paramdict_t pd, int id, const ncnn_mat_t def); + +NCNN_EXPORT void ncnn_paramdict_set_int(ncnn_paramdict_t pd, int id, int i); +NCNN_EXPORT void ncnn_paramdict_set_float(ncnn_paramdict_t pd, int id, float f); +NCNN_EXPORT void ncnn_paramdict_set_array(ncnn_paramdict_t pd, int id, const ncnn_mat_t v); + +/* datareader api */ +typedef struct __ncnn_datareader_t* ncnn_datareader_t; +struct NCNN_EXPORT __ncnn_datareader_t +{ + void* pthis; + +#if NCNN_STRING + int (*scan)(ncnn_datareader_t dr, const char* format, void* p); +#endif /* NCNN_STRING */ + size_t (*read)(ncnn_datareader_t dr, void* buf, size_t size); +}; + +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create(); +#if NCNN_STDIO +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create_from_stdio(FILE* fp); +#endif /* NCNN_STDIO */ +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create_from_memory(const unsigned char** mem); +NCNN_EXPORT void ncnn_datareader_destroy(ncnn_datareader_t dr); + +/* modelbin api */ +typedef struct __ncnn_modelbin_t* ncnn_modelbin_t; +struct NCNN_EXPORT __ncnn_modelbin_t +{ + void* pthis; + + ncnn_mat_t (*load_1d)(const ncnn_modelbin_t mb, int w, int type); + ncnn_mat_t (*load_2d)(const ncnn_modelbin_t mb, int w, int h, int type); + ncnn_mat_t (*load_3d)(const ncnn_modelbin_t mb, int w, int h, int c, int type); +}; + +NCNN_EXPORT ncnn_modelbin_t ncnn_modelbin_create_from_datareader(const ncnn_datareader_t dr); +NCNN_EXPORT ncnn_modelbin_t ncnn_modelbin_create_from_mat_array(const ncnn_mat_t* weights, int n); +NCNN_EXPORT void ncnn_modelbin_destroy(ncnn_modelbin_t mb); + +/* layer api */ +typedef struct __ncnn_layer_t* ncnn_layer_t; +struct NCNN_EXPORT __ncnn_layer_t +{ + void* pthis; + + int (*load_param)(ncnn_layer_t layer, const ncnn_paramdict_t pd); + int (*load_model)(ncnn_layer_t layer, const ncnn_modelbin_t mb); + + int (*create_pipeline)(ncnn_layer_t layer, const ncnn_option_t opt); + int (*destroy_pipeline)(ncnn_layer_t layer, const ncnn_option_t opt); + + int (*forward_1)(const ncnn_layer_t layer, const ncnn_mat_t bottom_blob, ncnn_mat_t* top_blob, const ncnn_option_t opt); + int (*forward_n)(const ncnn_layer_t layer, const ncnn_mat_t* bottom_blobs, int n, ncnn_mat_t* top_blobs, int n2, const ncnn_option_t opt); + + int (*forward_inplace_1)(const ncnn_layer_t layer, ncnn_mat_t bottom_top_blob, const ncnn_option_t opt); + int (*forward_inplace_n)(const ncnn_layer_t layer, ncnn_mat_t* bottom_top_blobs, int n, const ncnn_option_t opt); +}; + +NCNN_EXPORT ncnn_layer_t ncnn_layer_create(); +NCNN_EXPORT ncnn_layer_t ncnn_layer_create_by_typeindex(int typeindex); +#if NCNN_STRING +NCNN_EXPORT ncnn_layer_t ncnn_layer_create_by_type(const char* type); +NCNN_EXPORT int ncnn_layer_type_to_index(const char* type); +#endif /* NCNN_STRING */ +NCNN_EXPORT void ncnn_layer_destroy(ncnn_layer_t layer); + +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_layer_get_name(const ncnn_layer_t layer); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_layer_get_typeindex(const ncnn_layer_t layer); +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_layer_get_type(const ncnn_layer_t layer); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_layer_get_one_blob_only(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_inplace(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_vulkan(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_packing(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_bf16_storage(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_fp16_storage(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_image_storage(const ncnn_layer_t layer); + +NCNN_EXPORT void ncnn_layer_set_one_blob_only(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_inplace(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_vulkan(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_packing(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_bf16_storage(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_fp16_storage(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_image_storage(ncnn_layer_t layer, int enable); + +NCNN_EXPORT int ncnn_layer_get_bottom_count(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_bottom(const ncnn_layer_t layer, int i); +NCNN_EXPORT int ncnn_layer_get_top_count(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_top(const ncnn_layer_t layer, int i); + +NCNN_EXPORT void ncnn_blob_get_bottom_shape(const ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c); +NCNN_EXPORT void ncnn_blob_get_top_shape(const ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c); + +/* layer factory function */ +typedef ncnn_layer_t (*ncnn_layer_creator_t)(void* userdata); +typedef void (*ncnn_layer_destroyer_t)(ncnn_layer_t layer, void* userdata); + +typedef struct __ncnn_net_custom_layer_factory_t* ncnn_net_custom_layer_factory_t; +struct __ncnn_net_custom_layer_factory_t +{ + ncnn_layer_creator_t creator; + ncnn_layer_destroyer_t destroyer; + void* userdata; + ncnn_net_custom_layer_factory_t next; +}; + +/* net api */ +typedef struct __ncnn_net_t* ncnn_net_t; +struct __ncnn_net_t +{ + void* pthis; + + ncnn_net_custom_layer_factory_t custom_layer_factory; +}; + +NCNN_EXPORT ncnn_net_t ncnn_net_create(); +NCNN_EXPORT void ncnn_net_destroy(ncnn_net_t net); + +NCNN_EXPORT ncnn_option_t ncnn_net_get_option(ncnn_net_t net); +NCNN_EXPORT void ncnn_net_set_option(ncnn_net_t net, ncnn_option_t opt); + +#if NCNN_STRING +NCNN_EXPORT void ncnn_net_register_custom_layer_by_type(ncnn_net_t net, const char* type, ncnn_layer_creator_t creator, ncnn_layer_destroyer_t destroyer, void* userdata); +#endif /* NCNN_STRING */ +NCNN_EXPORT void ncnn_net_register_custom_layer_by_typeindex(ncnn_net_t net, int typeindex, ncnn_layer_creator_t creator, ncnn_layer_destroyer_t destroyer, void* userdata); + +#if NCNN_STDIO +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param(ncnn_net_t net, const char* path); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_load_param_bin(ncnn_net_t net, const char* path); +NCNN_EXPORT int ncnn_net_load_model(ncnn_net_t net, const char* path); +#endif /* NCNN_STDIO */ + +#if NCNN_STDIO +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param_memory(ncnn_net_t net, const char* mem); +#endif /* NCNN_STRING */ +#endif /* NCNN_STDIO */ +NCNN_EXPORT int ncnn_net_load_param_bin_memory(ncnn_net_t net, const unsigned char* mem); +NCNN_EXPORT int ncnn_net_load_model_memory(ncnn_net_t net, const unsigned char* mem); + +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param_datareader(ncnn_net_t net, const ncnn_datareader_t dr); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_load_param_bin_datareader(ncnn_net_t net, const ncnn_datareader_t dr); +NCNN_EXPORT int ncnn_net_load_model_datareader(ncnn_net_t net, const ncnn_datareader_t dr); + +NCNN_EXPORT void ncnn_net_clear(ncnn_net_t net); + +NCNN_EXPORT int ncnn_net_get_input_count(const ncnn_net_t net); +NCNN_EXPORT int ncnn_net_get_output_count(const ncnn_net_t net); +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_net_get_input_name(const ncnn_net_t net, int i); +NCNN_EXPORT const char* ncnn_net_get_output_name(const ncnn_net_t net, int i); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_get_input_index(const ncnn_net_t net, int i); +NCNN_EXPORT int ncnn_net_get_output_index(const ncnn_net_t net, int i); + +/* extractor api */ +typedef struct __ncnn_extractor_t* ncnn_extractor_t; + +NCNN_EXPORT ncnn_extractor_t ncnn_extractor_create(ncnn_net_t net); +NCNN_EXPORT void ncnn_extractor_destroy(ncnn_extractor_t ex); + +NCNN_EXPORT void ncnn_extractor_set_option(ncnn_extractor_t ex, const ncnn_option_t opt); + +#if NCNN_STRING +NCNN_EXPORT int ncnn_extractor_input(ncnn_extractor_t ex, const char* name, const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_extractor_extract(ncnn_extractor_t ex, const char* name, ncnn_mat_t* mat); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_extractor_input_index(ncnn_extractor_t ex, int index, const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_extractor_extract_index(ncnn_extractor_t ex, int index, ncnn_mat_t* mat); + +/* mat process api */ +#define NCNN_BORDER_CONSTANT 0 +#define NCNN_BORDER_REPLICATE 1 +#define NCNN_BORDER_REFLECT 2 +#define NCNN_BORDER_TRANSPARENT -233 +NCNN_EXPORT void ncnn_copy_make_border(const ncnn_mat_t src, ncnn_mat_t dst, int top, int bottom, int left, int right, int type, float v, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_copy_make_border_3d(const ncnn_mat_t src, ncnn_mat_t dst, int top, int bottom, int left, int right, int front, int behind, int type, float v, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_copy_cut_border(const ncnn_mat_t src, ncnn_mat_t dst, int top, int bottom, int left, int right, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_copy_cut_border_3d(const ncnn_mat_t src, ncnn_mat_t dst, int top, int bottom, int left, int right, int front, int behind, const ncnn_option_t opt); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* NCNN_C_API */ + +#endif /* NCNN_C_API_H */ diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/command.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/command.h new file mode 100644 index 0000000..337d085 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/command.h @@ -0,0 +1,136 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_COMMAND_H +#define NCNN_COMMAND_H + +#include "platform.h" + +#if NCNN_VULKAN + +#include "mat.h" + +#include + +namespace ncnn { + +class Pipeline; +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class ImportAndroidHardwareBufferPipeline; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API +class VkComputePrivate; +class NCNN_EXPORT VkCompute +{ +public: + explicit VkCompute(const VulkanDevice* vkdev); + virtual ~VkCompute(); + +public: + void record_upload(const Mat& src, VkMat& dst, const Option& opt); + + void record_upload(const Mat& src, VkImageMat& dst, const Option& opt); + + void record_download(const VkMat& src, Mat& dst, const Option& opt); + + void record_download(const VkImageMat& src, Mat& dst, const Option& opt); + + void record_buffer_to_image(const VkMat& src, VkImageMat& dst, const Option& opt); + + void record_image_to_buffer(const VkImageMat& src, VkMat& dst, const Option& opt); + + void record_clone(const Mat& src, VkMat& dst, const Option& opt); + + void record_clone(const Mat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkMat& src, Mat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, Mat& dst, const Option& opt); + + void record_clone(const VkMat& src, VkMat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkMat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, VkMat& dst, const Option& opt); + + void record_pipeline(const Pipeline* pipeline, const std::vector& bindings, const std::vector& constants, const VkMat& dispatcher); + + void record_pipeline(const Pipeline* pipeline, const std::vector& bindings, const std::vector& constants, const VkImageMat& dispatcher); + + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const VkMat& dispatcher); + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const VkImageMat& dispatcher); + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const Mat& dispatcher); + +#if NCNN_BENCHMARK + void record_write_timestamp(uint32_t query); +#endif // NCNN_BENCHMARK + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 + void record_import_android_hardware_buffer(const ImportAndroidHardwareBufferPipeline* pipeline, const VkImageMat& src, const VkMat& dst); + + void record_import_android_hardware_buffer(const ImportAndroidHardwareBufferPipeline* pipeline, const VkImageMat& src, const VkImageMat& dst); +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + + int submit_and_wait(); + + int reset(); + +#if NCNN_BENCHMARK + int create_query_pool(uint32_t query_count); + + int get_query_pool_results(uint32_t first_query, uint32_t query_count, std::vector& results); +#endif // NCNN_BENCHMARK + +protected: + const VulkanDevice* vkdev; + + void barrier_readwrite(const VkMat& binding); + void barrier_readwrite(const VkImageMat& binding); + void barrier_readonly(const VkImageMat& binding); + +private: + VkComputePrivate* const d; +}; + +class VkTransferPrivate; +class NCNN_EXPORT VkTransfer +{ +public: + explicit VkTransfer(const VulkanDevice* vkdev); + virtual ~VkTransfer(); + +public: + void record_upload(const Mat& src, VkMat& dst, const Option& opt, bool flatten = true); + + void record_upload(const Mat& src, VkImageMat& dst, const Option& opt); + + int submit_and_wait(); + +protected: + const VulkanDevice* vkdev; + +private: + VkTransferPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_VULKAN + +#endif // NCNN_COMMAND_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/cpu.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/cpu.h new file mode 100644 index 0000000..7d6bfce --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/cpu.h @@ -0,0 +1,178 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_CPU_H +#define NCNN_CPU_H + +#include + +#if (defined _WIN32 && !(defined __MINGW32__)) +#define WIN32_LEAN_AND_MEAN +#include +#endif +#if defined __ANDROID__ || defined __linux__ +#include // cpu_set_t +#endif + +#include "platform.h" + +namespace ncnn { + +class NCNN_EXPORT CpuSet +{ +public: + CpuSet(); + void enable(int cpu); + void disable(int cpu); + void disable_all(); + bool is_enabled(int cpu) const; + int num_enabled() const; + +public: +#if (defined _WIN32 && !(defined __MINGW32__)) + ULONG_PTR mask; +#endif +#if defined __ANDROID__ || defined __linux__ + cpu_set_t cpu_set; +#endif +#if __APPLE__ + unsigned int policy; +#endif +}; + +// test optional cpu features +// edsp = armv7 edsp +NCNN_EXPORT int cpu_support_arm_edsp(); +// neon = armv7 neon or aarch64 asimd +NCNN_EXPORT int cpu_support_arm_neon(); +// vfpv4 = armv7 fp16 + fma +NCNN_EXPORT int cpu_support_arm_vfpv4(); +// asimdhp = aarch64 asimd half precision +NCNN_EXPORT int cpu_support_arm_asimdhp(); +// cpuid = aarch64 cpuid info +NCNN_EXPORT int cpu_support_arm_cpuid(); +// asimddp = aarch64 asimd dot product +NCNN_EXPORT int cpu_support_arm_asimddp(); +// asimdfhm = aarch64 asimd fhm +NCNN_EXPORT int cpu_support_arm_asimdfhm(); +// bf16 = aarch64 bf16 +NCNN_EXPORT int cpu_support_arm_bf16(); +// i8mm = aarch64 i8mm +NCNN_EXPORT int cpu_support_arm_i8mm(); +// sve = aarch64 sve +NCNN_EXPORT int cpu_support_arm_sve(); +// sve2 = aarch64 sve2 +NCNN_EXPORT int cpu_support_arm_sve2(); +// svebf16 = aarch64 svebf16 +NCNN_EXPORT int cpu_support_arm_svebf16(); +// svei8mm = aarch64 svei8mm +NCNN_EXPORT int cpu_support_arm_svei8mm(); +// svef32mm = aarch64 svef32mm +NCNN_EXPORT int cpu_support_arm_svef32mm(); + +// avx = x86 avx +NCNN_EXPORT int cpu_support_x86_avx(); +// fma = x86 fma +NCNN_EXPORT int cpu_support_x86_fma(); +// xop = x86 xop +NCNN_EXPORT int cpu_support_x86_xop(); +// f16c = x86 f16c +NCNN_EXPORT int cpu_support_x86_f16c(); +// avx2 = x86 avx2 + fma + f16c +NCNN_EXPORT int cpu_support_x86_avx2(); +// avx_vnni = x86 avx vnni +NCNN_EXPORT int cpu_support_x86_avx_vnni(); +// avx512 = x86 avx512f + avx512cd + avx512bw + avx512dq + avx512vl +NCNN_EXPORT int cpu_support_x86_avx512(); +// avx512_vnni = x86 avx512 vnni +NCNN_EXPORT int cpu_support_x86_avx512_vnni(); +// avx512_bf16 = x86 avx512 bf16 +NCNN_EXPORT int cpu_support_x86_avx512_bf16(); +// avx512_fp16 = x86 avx512 fp16 +NCNN_EXPORT int cpu_support_x86_avx512_fp16(); + +// lsx = loongarch lsx +NCNN_EXPORT int cpu_support_loongarch_lsx(); +// lasx = loongarch lasx +NCNN_EXPORT int cpu_support_loongarch_lasx(); + +// msa = mips mas +NCNN_EXPORT int cpu_support_mips_msa(); +// mmi = loongson mmi +NCNN_EXPORT int cpu_support_loongson_mmi(); + +// v = riscv vector +NCNN_EXPORT int cpu_support_riscv_v(); +// zfh = riscv half-precision float +NCNN_EXPORT int cpu_support_riscv_zfh(); +// vlenb = riscv vector length in bytes +NCNN_EXPORT int cpu_riscv_vlenb(); + +// cpu info +NCNN_EXPORT int get_cpu_count(); +NCNN_EXPORT int get_little_cpu_count(); +NCNN_EXPORT int get_big_cpu_count(); + +NCNN_EXPORT int get_physical_cpu_count(); +NCNN_EXPORT int get_physical_little_cpu_count(); +NCNN_EXPORT int get_physical_big_cpu_count(); + +// cpu l2 varies from 64k to 1M, but l3 can be zero +NCNN_EXPORT int get_cpu_level2_cache_size(); +NCNN_EXPORT int get_cpu_level3_cache_size(); + +// bind all threads on little clusters if powersave enabled +// affects HMP arch cpu like ARM big.LITTLE +// only implemented on android at the moment +// switching powersave is expensive and not thread-safe +// 0 = all cores enabled(default) +// 1 = only little clusters enabled +// 2 = only big clusters enabled +// return 0 if success for setter function +NCNN_EXPORT int get_cpu_powersave(); +NCNN_EXPORT int set_cpu_powersave(int powersave); + +// convenient wrapper +NCNN_EXPORT const CpuSet& get_cpu_thread_affinity_mask(int powersave); + +// set explicit thread affinity +NCNN_EXPORT int set_cpu_thread_affinity(const CpuSet& thread_affinity_mask); + +// runtime thread affinity info +NCNN_EXPORT int is_current_thread_running_on_a53_a55(); + +// misc function wrapper for openmp routines +NCNN_EXPORT int get_omp_num_threads(); +NCNN_EXPORT void set_omp_num_threads(int num_threads); + +NCNN_EXPORT int get_omp_dynamic(); +NCNN_EXPORT void set_omp_dynamic(int dynamic); + +NCNN_EXPORT int get_omp_thread_num(); + +NCNN_EXPORT int get_kmp_blocktime(); +NCNN_EXPORT void set_kmp_blocktime(int time_ms); + +// need to flush denormals on Intel Chipset. +// Other architectures such as ARM can be added as needed. +// 0 = DAZ OFF, FTZ OFF +// 1 = DAZ ON , FTZ OFF +// 2 = DAZ OFF, FTZ ON +// 3 = DAZ ON, FTZ ON +NCNN_EXPORT int get_flush_denormals(); +NCNN_EXPORT int set_flush_denormals(int flush_denormals); + +} // namespace ncnn + +#endif // NCNN_CPU_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/datareader.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/datareader.h new file mode 100644 index 0000000..ed2aba3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/datareader.h @@ -0,0 +1,122 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_DATAREADER_H +#define NCNN_DATAREADER_H + +#include "platform.h" +#if NCNN_STDIO +#include +#endif + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#endif +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +// data read wrapper +class NCNN_EXPORT DataReader +{ +public: + DataReader(); + virtual ~DataReader(); + +#if NCNN_STRING + // parse plain param text + // return 1 if scan success + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + + // read binary param and model data + // return bytes read + virtual size_t read(void* buf, size_t size) const; + + // get model data reference + // return bytes referenced + virtual size_t reference(size_t size, const void** buf) const; +}; + +#if NCNN_STDIO +class DataReaderFromStdioPrivate; +class NCNN_EXPORT DataReaderFromStdio : public DataReader +{ +public: + explicit DataReaderFromStdio(FILE* fp); + virtual ~DataReaderFromStdio(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + +private: + DataReaderFromStdio(const DataReaderFromStdio&); + DataReaderFromStdio& operator=(const DataReaderFromStdio&); + +private: + DataReaderFromStdioPrivate* const d; +}; +#endif // NCNN_STDIO + +class DataReaderFromMemoryPrivate; +class NCNN_EXPORT DataReaderFromMemory : public DataReader +{ +public: + explicit DataReaderFromMemory(const unsigned char*& mem); + virtual ~DataReaderFromMemory(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + virtual size_t reference(size_t size, const void** buf) const; + +private: + DataReaderFromMemory(const DataReaderFromMemory&); + DataReaderFromMemory& operator=(const DataReaderFromMemory&); + +private: + DataReaderFromMemoryPrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +class DataReaderFromAndroidAssetPrivate; +class NCNN_EXPORT DataReaderFromAndroidAsset : public DataReader +{ +public: + explicit DataReaderFromAndroidAsset(AAsset* asset); + virtual ~DataReaderFromAndroidAsset(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + +private: + DataReaderFromAndroidAsset(const DataReaderFromAndroidAsset&); + DataReaderFromAndroidAsset& operator=(const DataReaderFromAndroidAsset&); + +private: + DataReaderFromAndroidAssetPrivate* const d; +}; +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + +} // namespace ncnn + +#endif // NCNN_DATAREADER_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/gpu.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/gpu.h new file mode 100644 index 0000000..1eff228 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/gpu.h @@ -0,0 +1,392 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_GPU_H +#define NCNN_GPU_H + +#include "platform.h" + +#if NCNN_VULKAN + +#include "mat.h" + +#include + +#include "vulkan_header_fix.h" + +namespace ncnn { + +// instance + +// Create VkInstance and initialize some objects that need to be calculated by GPU +// Creates a VkInstance object, Checks the extended attributes supported by the Vulkan instance concerned, +// Initializes, and creates Vulkan validation layers (if ENABLE_VALIDATION_LAYER is enabled), +// Iterates over all supported physical devices, etc. +NCNN_EXPORT int create_gpu_instance(); + +// Get global VkInstance variable +// Must be called after create_gpu_instance() and before destroy_gpu_instance() +NCNN_EXPORT VkInstance get_gpu_instance(); + +// Destroy VkInstance object and free the memory of the associated object +// Usually called in the destructor of the main program exit +NCNN_EXPORT void destroy_gpu_instance(); + +// instance extension capability +extern int support_VK_KHR_external_memory_capabilities; +extern int support_VK_KHR_get_physical_device_properties2; +extern int support_VK_KHR_get_surface_capabilities2; +extern int support_VK_KHR_surface; +extern int support_VK_EXT_debug_utils; +extern int support_VK_EXT_validation_features; +extern int support_VK_EXT_validation_flags; +#if __ANDROID_API__ >= 26 +extern int support_VK_KHR_android_surface; +#endif // __ANDROID_API__ >= 26 + +// VK_KHR_cooperative_matrix +extern PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR; + +// VK_KHR_external_memory_capabilities +extern PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR vkGetPhysicalDeviceExternalBufferPropertiesKHR; + +// VK_KHR_get_physical_device_properties2 +extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; +extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; +extern PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceImageFormatProperties2KHR vkGetPhysicalDeviceImageFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR; +extern PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR; +extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR vkGetPhysicalDeviceSparseImageFormatProperties2KHR; + +// VK_KHR_get_surface_capabilities2 +extern PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR; + +// VK_KHR_surface +extern PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; +extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; +extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; +extern PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; + +#if __ANDROID_API__ >= 26 +// VK_KHR_android_surface +extern PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; +#endif // __ANDROID_API__ >= 26 + +// VK_NV_cooperative_matrix +extern PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV vkGetPhysicalDeviceCooperativeMatrixPropertiesNV; + +// get info +NCNN_EXPORT int get_gpu_count(); +NCNN_EXPORT int get_default_gpu_index(); + +class GpuInfoPrivate; +class NCNN_EXPORT GpuInfo +{ +public: + explicit GpuInfo(); + virtual ~GpuInfo(); + + // vulkan physical device + VkPhysicalDevice physical_device() const; + + // memory properties + const VkPhysicalDeviceMemoryProperties& physical_device_memory_properties() const; + + // info + uint32_t api_version() const; + uint32_t driver_version() const; + uint32_t vendor_id() const; + uint32_t device_id() const; + const char* device_name() const; + uint8_t* pipeline_cache_uuid() const; + + // 0 = discrete gpu + // 1 = integrated gpu + // 2 = virtual gpu + // 3 = cpu + int type() const; + + // hardware limit + uint32_t max_shared_memory_size() const; + uint32_t max_workgroup_count_x() const; + uint32_t max_workgroup_count_y() const; + uint32_t max_workgroup_count_z() const; + uint32_t max_workgroup_invocations() const; + uint32_t max_workgroup_size_x() const; + uint32_t max_workgroup_size_y() const; + uint32_t max_workgroup_size_z() const; + size_t memory_map_alignment() const; + size_t buffer_offset_alignment() const; + size_t non_coherent_atom_size() const; + size_t buffer_image_granularity() const; + uint32_t max_image_dimension_1d() const; + uint32_t max_image_dimension_2d() const; + uint32_t max_image_dimension_3d() const; + float timestamp_period() const; + + // runtime + uint32_t compute_queue_family_index() const; + uint32_t graphics_queue_family_index() const; + uint32_t transfer_queue_family_index() const; + + uint32_t compute_queue_count() const; + uint32_t graphics_queue_count() const; + uint32_t transfer_queue_count() const; + + // property + bool unified_compute_transfer_queue() const; + + // subgroup + uint32_t subgroup_size() const; + bool support_subgroup_basic() const; + bool support_subgroup_vote() const; + bool support_subgroup_ballot() const; + bool support_subgroup_shuffle() const; + + // bug is not feature + bool bug_storage_buffer_no_l1() const; + bool bug_corrupted_online_pipeline_cache() const; + bool bug_buffer_image_load_zero() const; + + // but sometimes bug is a feature + bool bug_implicit_fp16_arithmetic() const; + + // fp16 and int8 feature + bool support_fp16_packed() const; + bool support_fp16_storage() const; + bool support_fp16_arithmetic() const; + bool support_int8_packed() const; + bool support_int8_storage() const; + bool support_int8_arithmetic() const; + + // ycbcr conversion feature + bool support_ycbcr_conversion() const; + + // cooperative matrix feature + bool support_cooperative_matrix() const; + bool support_cooperative_matrix_16_8_8() const; + bool support_cooperative_matrix_16_8_16() const; + bool support_cooperative_matrix_16_16_16() const; + + // extension capability + int support_VK_KHR_8bit_storage() const; + int support_VK_KHR_16bit_storage() const; + int support_VK_KHR_bind_memory2() const; + int support_VK_KHR_buffer_device_address() const; + int support_VK_KHR_create_renderpass2() const; + int support_VK_KHR_cooperative_matrix() const; + int support_VK_KHR_dedicated_allocation() const; + int support_VK_KHR_descriptor_update_template() const; + int support_VK_KHR_external_memory() const; + int support_VK_KHR_get_memory_requirements2() const; + int support_VK_KHR_maintenance1() const; + int support_VK_KHR_maintenance2() const; + int support_VK_KHR_maintenance3() const; + int support_VK_KHR_multiview() const; + int support_VK_KHR_portability_subset() const; + int support_VK_KHR_push_descriptor() const; + int support_VK_KHR_sampler_ycbcr_conversion() const; + int support_VK_KHR_shader_float16_int8() const; + int support_VK_KHR_shader_float_controls() const; + int support_VK_KHR_storage_buffer_storage_class() const; + int support_VK_KHR_swapchain() const; + int support_VK_EXT_buffer_device_address() const; + int support_VK_EXT_descriptor_indexing() const; + int support_VK_EXT_memory_budget() const; + int support_VK_EXT_memory_priority() const; + int support_VK_EXT_queue_family_foreign() const; + int support_VK_AMD_device_coherent_memory() const; +#if __ANDROID_API__ >= 26 + int support_VK_ANDROID_external_memory_android_hardware_buffer() const; +#endif // __ANDROID_API__ >= 26 + int support_VK_NV_cooperative_matrix() const; + +private: + GpuInfo(const GpuInfo&); + GpuInfo& operator=(const GpuInfo&); + +private: + friend int create_gpu_instance(); + GpuInfoPrivate* const d; +}; + +NCNN_EXPORT const GpuInfo& get_gpu_info(int device_index = get_default_gpu_index()); + +class VkAllocator; +class VkCompute; +class Option; +class PipelineCache; +class VulkanDevicePrivate; +class NCNN_EXPORT VulkanDevice +{ +public: + VulkanDevice(int device_index = get_default_gpu_index()); + ~VulkanDevice(); + + const GpuInfo& info; + + VkDevice vkdevice() const; + + VkShaderModule compile_shader_module(const uint32_t* spv_data, size_t spv_data_size) const; + + // with fixed workgroup size + VkShaderModule compile_shader_module(const uint32_t* spv_data, size_t spv_data_size, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z) const; + + // helper for creating pipeline + int create_descriptorset_layout(int binding_count, const int* binding_types, VkDescriptorSetLayout* descriptorset_layout) const; + int create_pipeline_layout(int push_constant_count, VkDescriptorSetLayout descriptorset_layout, VkPipelineLayout* pipeline_layout) const; + int create_pipeline(VkShaderModule shader_module, VkPipelineLayout pipeline_layout, const std::vector& specializations, VkPipeline* pipeline) const; + int create_descriptor_update_template(int binding_count, const int* binding_types, VkDescriptorSetLayout descriptorset_layout, VkPipelineLayout pipeline_layout, VkDescriptorUpdateTemplateKHR* descriptor_update_template) const; + + uint32_t find_memory_index(uint32_t memory_type_bits, VkFlags required, VkFlags preferred, VkFlags preferred_not) const; + bool is_mappable(uint32_t memory_type_index) const; + bool is_coherent(uint32_t memory_type_index) const; + + VkQueue acquire_queue(uint32_t queue_family_index) const; + void reclaim_queue(uint32_t queue_family_index, VkQueue queue) const; + + // allocator on this device + VkAllocator* acquire_blob_allocator() const; + void reclaim_blob_allocator(VkAllocator* allocator) const; + + VkAllocator* acquire_staging_allocator() const; + void reclaim_staging_allocator(VkAllocator* allocator) const; + + // immutable sampler for texelfetch + const VkSampler* immutable_texelfetch_sampler() const; + + // dummy buffer image + VkMat get_dummy_buffer() const; + VkImageMat get_dummy_image() const; + VkImageMat get_dummy_image_readonly() const; + + // pipeline cache on this device + const PipelineCache* get_pipeline_cache() const; + + // test image allocation + bool shape_support_image_storage(const Mat& shape) const; + + // current gpu heap memory budget in MB + uint32_t get_heap_budget() const; + + // utility operator + void convert_packing(const VkMat& src, VkMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkImageMat& src, VkImageMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkMat& src, VkImageMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkImageMat& src, VkMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + + // VK_KHR_bind_memory2 + PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; + PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; + + // VK_KHR_buffer_device_address + PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR; + PFN_vkGetBufferOpaqueCaptureAddressKHR vkGetBufferOpaqueCaptureAddressKHR; + PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR vkGetDeviceMemoryOpaqueCaptureAddressKHR; + + // VK_KHR_create_renderpass2 + PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; + PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; + PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; + + // VK_KHR_descriptor_update_template + PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; + PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; + PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; + + // VK_KHR_get_memory_requirements2 + PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; + PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; + PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; + + // VK_KHR_maintenance1 + PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; + + // VK_KHR_maintenance3 + PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; + + // VK_KHR_push_descriptor + PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; + PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; + + // VK_KHR_sampler_ycbcr_conversion + PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; + PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; + + // VK_KHR_swapchain + PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; + PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; + PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; + PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; + PFN_vkQueuePresentKHR vkQueuePresentKHR; + + // VK_EXT_buffer_device_address + PFN_vkGetBufferDeviceAddressEXT vkGetBufferDeviceAddressEXT; + +#if __ANDROID_API__ >= 26 + // VK_ANDROID_external_memory_android_hardware_buffer + PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; + PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; +#endif // __ANDROID_API__ >= 26 + +protected: + // device extension + int init_device_extension(); + +private: + VulkanDevice(const VulkanDevice&); + VulkanDevice& operator=(const VulkanDevice&); + +private: + VulkanDevicePrivate* const d; +}; + +NCNN_EXPORT VulkanDevice* get_gpu_device(int device_index = get_default_gpu_index()); + +// online spirv compilation +NCNN_EXPORT int compile_spirv_module(const char* comp_string, const Option& opt, std::vector& spirv); +NCNN_EXPORT int compile_spirv_module(const char* comp_data, int comp_data_size, const Option& opt, std::vector& spirv); +NCNN_EXPORT int compile_spirv_module(int shader_type_index, const Option& opt, std::vector& spirv); + +// info from spirv +class NCNN_EXPORT ShaderInfo +{ +public: + int specialization_count; + int binding_count; + int push_constant_count; + + // 0 = null + // 1 = storage buffer + // 2 = storage image + // 3 = combined image sampler + int binding_types[16]; // 16 is large enough I think ... + + int reserved_0; + int reserved_1; + int reserved_2; + int reserved_3; +}; + +NCNN_EXPORT int resolve_shader_info(const uint32_t* spv_data, size_t spv_data_size, ShaderInfo& shader_info); + +} // namespace ncnn + +#endif // NCNN_VULKAN + +#endif // NCNN_GPU_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/layer.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/layer.h new file mode 100644 index 0000000..f0418a9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/layer.h @@ -0,0 +1,222 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_H +#define NCNN_LAYER_H + +#include "mat.h" +#include "modelbin.h" +#include "option.h" +#include "paramdict.h" +#include "platform.h" + +#if NCNN_VULKAN +#include "command.h" +#include "pipeline.h" + +#include +#endif // NCNN_VULKAN + +namespace ncnn { + +class NCNN_EXPORT Layer +{ +public: + // empty + Layer(); + // virtual destructor + virtual ~Layer(); + + // load layer specific parameter from parsed dict + // return 0 if success + virtual int load_param(const ParamDict& pd); + + // load layer specific weight data from model binary + // return 0 if success + virtual int load_model(const ModelBin& mb); + + // layer implementation specific setup + // return 0 if success + virtual int create_pipeline(const Option& opt); + + // layer implementation specific clean + // return 0 if success + virtual int destroy_pipeline(const Option& opt); + +public: + // one input and one output blob + bool one_blob_only; + + // support inplace inference + bool support_inplace; + + // support vulkan compute + bool support_vulkan; + + // accept input blob with packed storage + bool support_packing; + + // accept bf16 + bool support_bf16_storage; + + // accept fp16 + bool support_fp16_storage; + + // accept int8 + bool support_int8_storage; + + // shader image storage + bool support_image_storage; + + // shader tensor storage + bool support_tensor_storage; + + bool support_reserved_00; + + bool support_reserved_0; + bool support_reserved_1; + bool support_reserved_2; + bool support_reserved_3; + bool support_reserved_4; + bool support_reserved_5; + bool support_reserved_6; + bool support_reserved_7; + bool support_reserved_8; + bool support_reserved_9; + + // feature disabled set + int featmask; + +public: + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, const Option& opt) const; + virtual int forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, const Option& opt) const; + virtual int forward_inplace(Mat& bottom_top_blob, const Option& opt) const; + +#if NCNN_VULKAN +public: + // upload weight blob from host to device + virtual int upload_model(VkTransfer& cmd, const Option& opt); + +public: + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward_inplace(VkMat& bottom_top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward_inplace(VkImageMat& bottom_top_blob, VkCompute& cmd, const Option& opt) const; + +public: + // assigned immediately after creating this layer + const VulkanDevice* vkdev; +#endif // NCNN_VULKAN + +public: + // custom user data + void* userdata; + // layer type index + int typeindex; +#if NCNN_STRING + // layer type name + std::string type; + // layer name + std::string name; +#endif // NCNN_STRING + // blob index which this layer needs as input + std::vector bottoms; + // blob index which this layer produces as output + std::vector tops; + // shape hint + std::vector bottom_shapes; + std::vector top_shapes; +}; + +// layer factory function +typedef Layer* (*layer_creator_func)(void*); +typedef void (*layer_destroyer_func)(Layer*, void*); + +struct layer_registry_entry +{ +#if NCNN_STRING + // layer type name + const char* name; +#endif // NCNN_STRING + // layer factory entry + layer_creator_func creator; +}; + +struct custom_layer_registry_entry +{ +#if NCNN_STRING + // layer type name + const char* name; +#endif // NCNN_STRING + // layer factory entry + layer_creator_func creator; + layer_destroyer_func destroyer; + void* userdata; +}; + +struct overwrite_builtin_layer_registry_entry +{ + // layer type index + int typeindex; + // layer factory entry + layer_creator_func creator; + layer_destroyer_func destroyer; + void* userdata; +}; + +#if NCNN_STRING +// get layer type from type name +NCNN_EXPORT int layer_to_index(const char* type); +// create layer from type name +NCNN_EXPORT Layer* create_layer(const char* type); +#endif // NCNN_STRING +// create layer from layer type +NCNN_EXPORT Layer* create_layer(int index); + +#define DEFINE_LAYER_CREATOR(name) \ + ::ncnn::Layer* name##_layer_creator(void* /*userdata*/) \ + { \ + return new name; \ + } + +#define DEFINE_LAYER_DESTROYER(name) \ + void name##_layer_destroyer(::ncnn::Layer* layer, void* /*userdata*/) \ + { \ + delete layer; \ + } + +} // namespace ncnn + +#endif // NCNN_LAYER_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/layer_shader_type.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/layer_shader_type.h new file mode 100644 index 0000000..c143e7d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/layer_shader_type.h @@ -0,0 +1,29 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_SHADER_TYPE_H +#define NCNN_LAYER_SHADER_TYPE_H + +namespace ncnn { + +namespace LayerShaderType { +enum LayerShaderType +{ +#include "layer_shader_type_enum.h" +}; +} // namespace LayerShaderType + +} // namespace ncnn + +#endif // NCNN_LAYER_SHADER_TYPE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/layer_shader_type_enum.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/layer_shader_type_enum.h new file mode 100644 index 0000000..aac8803 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/layer_shader_type_enum.h @@ -0,0 +1,5 @@ +// Layer Shader Enum header +// +// This file is auto-generated by cmake, don't edit it. + + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/layer_type.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/layer_type.h new file mode 100644 index 0000000..511c714 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/layer_type.h @@ -0,0 +1,30 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_TYPE_H +#define NCNN_LAYER_TYPE_H + +namespace ncnn { + +namespace LayerType { +enum LayerType +{ +#include "layer_type_enum.h" + CustomBit = (1 << 8), +}; +} // namespace LayerType + +} // namespace ncnn + +#endif // NCNN_LAYER_TYPE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/layer_type_enum.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/layer_type_enum.h new file mode 100644 index 0000000..97153ed --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/layer_type_enum.h @@ -0,0 +1,109 @@ +// Layer Type Enum header +// +// This file is auto-generated by cmake, don't edit it. + +AbsVal = 0, +ArgMax = 1, +BatchNorm = 2, +Bias = 3, +BNLL = 4, +Concat = 5, +Convolution = 6, +Crop = 7, +Deconvolution = 8, +Dropout = 9, +Eltwise = 10, +ELU = 11, +Embed = 12, +Exp = 13, +Flatten = 14, +InnerProduct = 15, +Input = 16, +Log = 17, +LRN = 18, +MemoryData = 19, +MVN = 20, +Pooling = 21, +Power = 22, +PReLU = 23, +Proposal = 24, +Reduction = 25, +ReLU = 26, +Reshape = 27, +ROIPooling = 28, +Scale = 29, +Sigmoid = 30, +Slice = 31, +Softmax = 32, +Split = 33, +SPP = 34, +TanH = 35, +Threshold = 36, +Tile = 37, +RNN = 38, +LSTM = 39, +BinaryOp = 40, +UnaryOp = 41, +ConvolutionDepthWise = 42, +Padding = 43, +Squeeze = 44, +ExpandDims = 45, +Normalize = 46, +Permute = 47, +PriorBox = 48, +DetectionOutput = 49, +Interp = 50, +DeconvolutionDepthWise = 51, +ShuffleChannel = 52, +InstanceNorm = 53, +Clip = 54, +Reorg = 55, +YoloDetectionOutput = 56, +Quantize = 57, +Dequantize = 58, +Yolov3DetectionOutput = 59, +PSROIPooling = 60, +ROIAlign = 61, +Packing = 62, +Requantize = 63, +Cast = 64, +HardSigmoid = 65, +SELU = 66, +HardSwish = 67, +Noop = 68, +PixelShuffle = 69, +DeepCopy = 70, +Mish = 71, +StatisticsPooling = 72, +Swish = 73, +Gemm = 74, +GroupNorm = 75, +LayerNorm = 76, +Softplus = 77, +GRU = 78, +MultiHeadAttention = 79, +GELU = 80, +Convolution1D = 81, +Pooling1D = 82, +ConvolutionDepthWise1D = 83, +Convolution3D = 84, +ConvolutionDepthWise3D = 85, +Pooling3D = 86, +MatMul = 87, +Deconvolution1D = 88, +DeconvolutionDepthWise1D = 89, +Deconvolution3D = 90, +DeconvolutionDepthWise3D = 91, +Einsum = 92, +DeformableConv2D = 93, +GLU = 94, +Fold = 95, +Unfold = 96, +GridSample = 97, +CumulativeSum = 98, +CopyTo = 99, +Erf = 100, +Diag = 101, +CELU = 102, +Shrink = 103, + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/mat.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/mat.h new file mode 100644 index 0000000..c6f59ef --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/mat.h @@ -0,0 +1,1843 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_MAT_H +#define NCNN_MAT_H + +#include +#include +#if __ARM_NEON +#include +#endif +#if __SSE2__ +#include +#if __AVX__ +#include +#endif +#endif +#if __mips_msa +#include +#endif +#if __loongarch_sx +#include +#endif +#if __riscv_vector +#include +#include "cpu.h" // cpu_riscv_vlenb() +#endif + +#include "allocator.h" +#include "option.h" +#include "platform.h" + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#if NCNN_PIXEL +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#include +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API +#endif // NCNN_PIXEL + +namespace ncnn { + +#if NCNN_VULKAN +class VkMat; +class VkImageMat; +#endif // NCNN_VULKAN + +// the three dimension matrix +class NCNN_EXPORT Mat +{ +public: + // empty + Mat(); + // vec + Mat(int w, size_t elemsize = 4u, Allocator* allocator = 0); + // image + Mat(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0); + // dim + Mat(int w, int h, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // cube + Mat(int w, int h, int d, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // packed vec + Mat(int w, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed image + Mat(int w, int h, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed dim + Mat(int w, int h, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed cube + Mat(int w, int h, int d, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // copy + Mat(const Mat& m); + // external vec + Mat(int w, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external image + Mat(int w, int h, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external dim + Mat(int w, int h, int c, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external cube + Mat(int w, int h, int d, int c, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external packed vec + Mat(int w, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed image + Mat(int w, int h, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed dim + Mat(int w, int h, int c, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed cube + Mat(int w, int h, int d, int c, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // release + ~Mat(); + // assign + Mat& operator=(const Mat& m); + // set all + void fill(float v); + void fill(int v); +#if __ARM_NEON + void fill(float32x4_t _v); + void fill(uint16x4_t _v); + void fill(int32x4_t _v); + void fill(int32x4_t _v0, int32x4_t _v1); +#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC + void fill(float16x4_t _v); + void fill(float16x8_t _v); +#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +#endif // __ARM_NEON +#if __SSE2__ +#if __AVX__ +#if __AVX512F__ + void fill(__m512 _v); +#endif // __AVX512F__ + void fill(__m256 _v, int i = 0); +#endif // __AVX__ + void fill(__m128 _v); + void fill(__m128i _v); +#endif // __SSE2__ +#if __mips_msa + void fill(v4f32 _v); +#endif // __mips_msa +#if __loongarch_sx + void fill(__m128 _v); +#endif //__loongarch_sx +#if __riscv_vector + void fill(vfloat32m1_t _v); + void fill(vuint16m1_t _v); + void fill(vint8m1_t _v); +#if __riscv_zfh + void fill(vfloat16m1_t _v); +#endif // __riscv_zfh +#endif // __riscv_vector + template + void fill(T v); + // deep copy + Mat clone(Allocator* allocator = 0) const; + // deep copy from other mat, inplace + void clone_from(const ncnn::Mat& mat, Allocator* allocator = 0); + // reshape vec + Mat reshape(int w, Allocator* allocator = 0) const; + // reshape image + Mat reshape(int w, int h, Allocator* allocator = 0) const; + // reshape dim + Mat reshape(int w, int h, int c, Allocator* allocator = 0) const; + // reshape cube + Mat reshape(int w, int h, int d, int c, Allocator* allocator = 0) const; + // allocate vec + void create(int w, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate image + void create(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate dim + void create(int w, int h, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate like + void create_like(const Mat& m, Allocator* allocator = 0); +#if NCNN_VULKAN + // allocate like + void create_like(const VkMat& m, Allocator* allocator = 0); + // allocate like + void create_like(const VkImageMat& im, Allocator* allocator = 0); +#endif // NCNN_VULKAN + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // data reference + Mat channel(int c); + const Mat channel(int c) const; + Mat depth(int z); + const Mat depth(int z) const; + float* row(int y); + const float* row(int y) const; + template + T* row(int y); + template + const T* row(int y) const; + + // range reference + Mat channel_range(int c, int channels); + const Mat channel_range(int c, int channels) const; + Mat depth_range(int z, int depths); + const Mat depth_range(int z, int depths) const; + Mat row_range(int y, int rows); + const Mat row_range(int y, int rows) const; + Mat range(int x, int n); + const Mat range(int x, int n) const; + + // access raw data + template + operator T*(); + template + operator const T*() const; + + // convenient access float vec element + float& operator[](size_t i); + const float& operator[](size_t i) const; + +#if NCNN_PIXEL + enum PixelType + { + PIXEL_CONVERT_SHIFT = 16, + PIXEL_FORMAT_MASK = 0x0000ffff, + PIXEL_CONVERT_MASK = 0xffff0000, + + PIXEL_RGB = 1, + PIXEL_BGR = 2, + PIXEL_GRAY = 3, + PIXEL_RGBA = 4, + PIXEL_BGRA = 5, + + PIXEL_RGB2BGR = PIXEL_RGB | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2GRAY = PIXEL_RGB | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2RGBA = PIXEL_RGB | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2BGRA = PIXEL_RGB | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_BGR2RGB = PIXEL_BGR | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2GRAY = PIXEL_BGR | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2RGBA = PIXEL_BGR | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2BGRA = PIXEL_BGR | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_GRAY2RGB = PIXEL_GRAY | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2BGR = PIXEL_GRAY | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2RGBA = PIXEL_GRAY | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2BGRA = PIXEL_GRAY | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_RGBA2RGB = PIXEL_RGBA | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2BGR = PIXEL_RGBA | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2GRAY = PIXEL_RGBA | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2BGRA = PIXEL_RGBA | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_BGRA2RGB = PIXEL_BGRA | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2BGR = PIXEL_BGRA | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2GRAY = PIXEL_BGRA | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2RGBA = PIXEL_BGRA | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + }; + // convenient construct from pixel data + static Mat from_pixels(const unsigned char* pixels, int type, int w, int h, Allocator* allocator = 0); + // convenient construct from pixel data with stride(bytes-per-row) parameter + static Mat from_pixels(const unsigned char* pixels, int type, int w, int h, int stride, Allocator* allocator = 0); + // convenient construct from pixel data and resize to specific size + static Mat from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data and resize to specific size with stride(bytes-per-row) parameter + static Mat from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data roi + static Mat from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from pixel data roi with stride(bytes-per-row) parameter + static Mat from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from pixel data roi and resize to specific size + static Mat from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data roi and resize to specific size with stride(bytes-per-row) parameter + static Mat from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + + // convenient export to pixel data + void to_pixels(unsigned char* pixels, int type) const; + // convenient export to pixel data with stride(bytes-per-row) parameter + void to_pixels(unsigned char* pixels, int type, int stride) const; + // convenient export to pixel data and resize to specific size + void to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height) const; + // convenient export to pixel data and resize to specific size with stride(bytes-per-row) parameter + void to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height, int target_stride) const; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 + // convenient construct from android Bitmap + static Mat from_android_bitmap(JNIEnv* env, jobject bitmap, int type_to, Allocator* allocator = 0); + // convenient construct from android Bitmap and resize to specific size + static Mat from_android_bitmap_resize(JNIEnv* env, jobject bitmap, int type_to, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from android Bitmap roi + static Mat from_android_bitmap_roi(JNIEnv* env, jobject bitmap, int type_to, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from android Bitmap roi and resize to specific size + static Mat from_android_bitmap_roi_resize(JNIEnv* env, jobject bitmap, int type_to, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + // convenient export to android Bitmap and resize to the android Bitmap size + void to_android_bitmap(JNIEnv* env, jobject bitmap, int type_from) const; +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API +#endif // NCNN_PIXEL + + // substract channel-wise mean values, then multiply by normalize values, pass 0 to skip + void substract_mean_normalize(const float* mean_vals, const float* norm_vals); + + // convenient construct from half precision floating point data + static Mat from_float16(const unsigned short* data, int size); + + // pointer to the data + void* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + Allocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; + + size_t cstep; +}; + +#if NCNN_VULKAN + +// the three dimension matrix, vulkan version +class NCNN_EXPORT VkMat +{ +public: + // empty + VkMat(); + // vec + VkMat(int w, size_t elemsize, VkAllocator* allocator); + // image + VkMat(int w, int h, size_t elemsize, VkAllocator* allocator); + // dim + VkMat(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // cube + VkMat(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // packed vec + VkMat(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // packed image + VkMat(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // packed dim + VkMat(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // packed cube + VkMat(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // copy + VkMat(const VkMat& m); + // external vec + VkMat(int w, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external image + VkMat(int w, int h, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external dim + VkMat(int w, int h, int c, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external cube + VkMat(int w, int h, int d, int c, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external packed vec + VkMat(int w, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed image + VkMat(int w, int h, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed dim + VkMat(int w, int h, int c, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed cube + VkMat(int w, int h, int d, int c, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // release + ~VkMat(); + // assign + VkMat& operator=(const VkMat& m); + // allocate vec + void create(int w, size_t elemsize, VkAllocator* allocator); + // allocate image + void create(int w, int h, size_t elemsize, VkAllocator* allocator); + // allocate dim + void create(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate like + void create_like(const Mat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkMat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkImageMat& im, VkAllocator* allocator); + + // mapped + Mat mapped() const; + void* mapped_ptr() const; + + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // low-level reference + VkBuffer buffer() const; + size_t buffer_offset() const; + size_t buffer_capacity() const; + + // device buffer + VkBufferMemory* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + VkAllocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; + + size_t cstep; +}; + +class NCNN_EXPORT VkImageMat +{ +public: + // empty + VkImageMat(); + // vec + VkImageMat(int w, size_t elemsize, VkAllocator* allocator); + // image + VkImageMat(int w, int h, size_t elemsize, VkAllocator* allocator); + // dim + VkImageMat(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // cube + VkImageMat(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // packed vec + VkImageMat(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // packed image + VkImageMat(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // packed dim + VkImageMat(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // packed cube + VkImageMat(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // copy + VkImageMat(const VkImageMat& m); + // external vec + VkImageMat(int w, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external image + VkImageMat(int w, int h, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external dim + VkImageMat(int w, int h, int c, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external cube + VkImageMat(int w, int h, int d, int c, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external packed vec + VkImageMat(int w, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed image + VkImageMat(int w, int h, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed dim + VkImageMat(int w, int h, int c, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed cube + VkImageMat(int w, int h, int d, int c, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // release + ~VkImageMat(); + // assign + VkImageMat& operator=(const VkImageMat& m); + // allocate vec + void create(int w, size_t elemsize, VkAllocator* allocator); + // allocate image + void create(int w, int h, size_t elemsize, VkAllocator* allocator); + // allocate dim + void create(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate like + void create_like(const Mat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkMat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkImageMat& im, VkAllocator* allocator); + + // mapped + Mat mapped() const; + void* mapped_ptr() const; + + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // low-level reference + VkImage image() const; + VkImageView imageview() const; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 + // convenient construct from android hardware buffer + static VkImageMat from_android_hardware_buffer(VkAndroidHardwareBufferImageAllocator* allocator); +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + + // device image + VkImageMemory* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + VkAllocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; +}; + +// type for vulkan specialization constant and push constant +union vk_specialization_type +{ + int i; + float f; + uint32_t u32; +}; +union vk_constant_type +{ + int i; + float f; +}; +#endif // NCNN_VULKAN + +// misc function +#if NCNN_PIXEL +// convert yuv420sp(nv21) to rgb, the fast approximate version +NCNN_EXPORT void yuv420sp2rgb(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// convert yuv420sp(nv12) to rgb, the fast approximate version +NCNN_EXPORT void yuv420sp2rgb_nv12(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// convert yuv420sp(nv21) to rgb with half resize, the faster approximate version +NCNN_EXPORT void yuv420sp2rgb_half(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// image pixel bilinear resize +NCNN_EXPORT void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +// image pixel bilinear resize with stride(bytes-per-row) parameter +NCNN_EXPORT void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +// image pixel bilinear resize, convenient wrapper for yuv420sp(nv21/nv12) +NCNN_EXPORT void resize_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +#endif // NCNN_PIXEL +#if NCNN_PIXEL_ROTATE +// type is the from type, 6 means rotating from 6 to 1 +// +// 1 2 3 4 5 6 7 8 +// +// 888888 888888 88 88 8888888888 88 88 8888888888 +// 88 88 88 88 88 88 88 88 88 88 88 88 +// 8888 8888 8888 8888 88 8888888888 8888888888 88 +// 88 88 88 88 +// 88 88 888888 888888 +// +// ref http://sylvana.net/jpegcrop/exif_orientation.html +// image pixel kanna rotate +NCNN_EXPORT void kanna_rotate_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +// image pixel kanna rotate with stride(bytes-per-row) parameter +NCNN_EXPORT void kanna_rotate_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +// image pixel kanna rotate, convenient wrapper for yuv420sp(nv21/nv12) +NCNN_EXPORT void kanna_rotate_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +#endif // NCNN_PIXEL_ROTATE +#if NCNN_PIXEL_AFFINE +// resolve affine transform matrix from rotation angle, scale factor and x y offset +NCNN_EXPORT void get_rotation_matrix(float angle, float scale, float dx, float dy, float* tm); +// resolve affine transform matrix from two set of points, num_point must be >= 2 +NCNN_EXPORT void get_affine_transform(const float* points_from, const float* points_to, int num_point, float* tm); +// resolve the inversion affine transform matrix +NCNN_EXPORT void invert_affine_transform(const float* tm, float* tm_inv); +// image pixel bilinear warpaffine inverse transform, set -233 for transparent border color, the color RGBA is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +// image pixel bilinear warpaffine inverse transform with stride(bytes-per-row) parameter, set -233 for transparent border color, the color RGBA is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +// image pixel bilinear warpaffine, convenient wrapper for yuv420sp(nv21/nv12), set -233 for transparent border color, the color YUV_ is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +#endif // NCNN_PIXEL_AFFINE +#if NCNN_PIXEL_DRAWING +// draw rectangle, set thickness -1 for filled rectangle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_rectangle_c1(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c2(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c3(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c4(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw rectangle with stride(bytes-per-row) parameter, set thickness -1 for filled rectangle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_rectangle_c1(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c2(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c3(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c4(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw rectangle, convenient wrapper for yuv420sp(nv21/nv12), set thickness -1 for filled rectangle, the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_rectangle_yuv420sp(unsigned char* yuv420sp, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw circle, set thickness -1 for filled circle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_circle_c1(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c2(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c3(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c4(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +// draw circle with stride(bytes-per-row) parameter, set thickness -1 for filled circle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_circle_c1(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c2(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c3(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c4(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +// draw circle, convenient wrapper for yuv420sp(nv21/nv12), set thickness -1 for filled circle, the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_circle_yuv420sp(unsigned char* yuv420sp, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +// draw line, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_line_c1(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c2(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c3(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c4(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// draw line with stride(bytes-per-row) parameter, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_line_c1(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c2(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c3(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c4(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// draw line, convenient wrapper for yuv420sp(nv21/nv12), the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_line_yuv420sp(unsigned char* yuv420sp, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// resolve text bounding box size +NCNN_EXPORT void get_text_drawing_size(const char* text, int fontpixelsize, int* w, int* h); +// draw ascii printables and newline, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_text_c1(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c2(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c3(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c4(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +// draw ascii printables and newline with stride(bytes-per-row) parameter, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_text_c1(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c2(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c3(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c4(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +// draw ascii printables and newline, convenient wrapper for yuv420sp(nv21/nv12), the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_text_yuv420sp(unsigned char* yuv420sp, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +#endif // NCNN_PIXEL_DRAWING + +// type conversion +// convert float to half precision floating point +NCNN_EXPORT unsigned short float32_to_float16(float value); +// convert half precision floating point to float +NCNN_EXPORT float float16_to_float32(unsigned short value); +// convert float to brain half +NCNN_EXPORT NCNN_FORCEINLINE unsigned short float32_to_bfloat16(float value) +{ + // 16 : 16 + union + { + unsigned int u; + float f; + } tmp; + tmp.f = value; + return tmp.u >> 16; +} +// convert brain half to float +NCNN_EXPORT NCNN_FORCEINLINE float bfloat16_to_float32(unsigned short value) +{ + // 16 : 16 + union + { + unsigned int u; + float f; + } tmp; + tmp.u = value << 16; + return tmp.f; +} + +// mat process +enum BorderType +{ + BORDER_CONSTANT = 0, + BORDER_REPLICATE = 1, + BORDER_REFLECT = 2, + BORDER_TRANSPARENT = -233, +}; +NCNN_EXPORT void copy_make_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int type, float v, const Option& opt = Option()); +NCNN_EXPORT void copy_make_border_3d(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int front, int behind, int type, float v, const Option& opt = Option()); +NCNN_EXPORT void copy_cut_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, const Option& opt = Option()); +NCNN_EXPORT void copy_cut_border_3d(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int front, int behind, const Option& opt = Option()); +NCNN_EXPORT void resize_nearest(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void resize_bilinear(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void resize_bicubic(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void convert_packing(const Mat& src, Mat& dst, int elempack, const Option& opt = Option()); +NCNN_EXPORT void flatten(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float32_to_float16(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float16_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_int8_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float32_to_bfloat16(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_bfloat16_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void quantize_to_int8(const Mat& src, Mat& dst, const Mat& scale_data, const Option& opt = Option()); +NCNN_EXPORT void dequantize_from_int32(const Mat& src, Mat& dst, const Mat& scale_data, const Mat& bias_data, const Option& opt = Option()); +NCNN_EXPORT void requantize_from_int32_to_int8(const Mat& src, Mat& dst, const Mat& scale_in_data, const Mat& scale_out_data, const Mat& bias_data, int activation_type, const Mat& activation_params, const Option& opt = Option()); + +NCNN_FORCEINLINE Mat::Mat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ +} + +NCNN_FORCEINLINE Mat::Mat(int _w, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(const Mat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c), cstep(m.cstep) +{ + addref(); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = (size_t)w * h; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = (size_t)w * h; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::~Mat() +{ + release(); +} + +NCNN_FORCEINLINE void Mat::fill(float _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + + int i = 0; +#if __ARM_NEON + float32x4_t _c = vdupq_n_f32(_v); + for (; i + 3 < size; i += 4) + { + vst1q_f32(ptr, _c); + ptr += 4; + } +#endif // __ARM_NEON + for (; i < size; i++) + { + *ptr++ = _v; + } +} + +NCNN_FORCEINLINE void Mat::fill(int _v) +{ + int size = (int)total(); + int* ptr = (int*)data; + + int i = 0; +#if __ARM_NEON + int32x4_t _c = vdupq_n_s32(_v); + for (; i + 3 < size; i += 4) + { + vst1q_s32(ptr, _c); + ptr += 4; + } +#endif // __ARM_NEON + for (; i < size; i++) + { + *ptr++ = _v; + } +} + +#if __ARM_NEON +NCNN_FORCEINLINE void Mat::fill(float32x4_t _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + vst1q_f32(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(uint16x4_t _v) +{ + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + vst1_u16(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(int32x4_t _v) +{ + int size = (int)total(); + int* ptr = (int*)data; + for (int i = 0; i < size; i++) + { + vst1q_s32(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(int32x4_t _v0, int32x4_t _v1) +{ + int size = (int)total(); + int* ptr = (int*)data; + for (int i = 0; i < size; i++) + { + vst1q_s32(ptr, _v0); + vst1q_s32(ptr + 4, _v1); + ptr += 8; + } +} +#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +NCNN_FORCEINLINE void Mat::fill(float16x4_t _v) +{ + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vst1_f16(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(float16x8_t _v) +{ + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vst1q_f16(ptr, _v); + ptr += 8; + } +} +#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +#endif // __ARM_NEON + +#if __SSE2__ +#if __AVX__ +#if __AVX512F__ +NCNN_FORCEINLINE void Mat::fill(__m512 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm512_storeu_ps(ptr, _v); + ptr += 16; + } +} +#endif // __AVX512F__ +NCNN_FORCEINLINE void Mat::fill(__m256 _v, int _i) +{ + // old gcc cannot overload __m128 and __m256 type + // add a dummy int parameter for different mangled function symbol + (void)_i; + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm256_storeu_ps(ptr, _v); + ptr += 8; + } +} +#endif // __AVX__ +NCNN_FORCEINLINE void Mat::fill(__m128 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm_storeu_ps(ptr, _v); + ptr += 4; + } +} +NCNN_FORCEINLINE void Mat::fill(__m128i _v) +{ + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + _mm_store_si128((__m128i*)ptr, _v); + ptr += 8; + } +} +#endif // __SSE2__ + +#if __mips_msa +NCNN_FORCEINLINE void Mat::fill(v4f32 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + __msa_st_w((v4i32)_v, ptr, 0); + ptr += 4; + } +} +#endif // __mips_msa + +#if __loongarch_sx +NCNN_FORCEINLINE void Mat::fill(__m128 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + __lsx_vst(_v, ptr, 0); + ptr += 4; + } +} +#endif // __loongarch_sx +#if __riscv_vector +NCNN_FORCEINLINE void Mat::fill(vfloat32m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 4; + const size_t vl = vsetvl_e32m1(packn); + + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + vse32_v_f32m1(ptr, _v, vl); + ptr += packn; + } +} + +NCNN_FORCEINLINE void Mat::fill(vuint16m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 2; + const size_t vl = vsetvl_e16m1(packn); + + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + vse16_v_u16m1(ptr, _v, vl); + ptr += packn; + } +} + +NCNN_FORCEINLINE void Mat::fill(vint8m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 1; + const size_t vl = vsetvl_e8m1(packn); + + int size = (int)total(); + signed char* ptr = (signed char*)data; + for (int i = 0; i < size; i++) + { + vse8_v_i8m1(ptr, _v, vl); + ptr += packn; + } +} +#if __riscv_zfh +NCNN_FORCEINLINE void Mat::fill(vfloat16m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 2; + const size_t vl = vsetvl_e16m1(packn); + + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vse16_v_f16m1(ptr, _v, vl); + ptr += packn; + } +} +#endif // __riscv_zfh +#endif // __riscv_vector + +template +NCNN_FORCEINLINE void Mat::fill(T _v) +{ + int size = (int)total(); + T* ptr = (T*)data; + for (int i = 0; i < size; i++) + { + ptr[i] = _v; + } +} + +NCNN_FORCEINLINE Mat& Mat::operator=(const Mat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + cstep = m.cstep; + + return *this; +} + +NCNN_FORCEINLINE void Mat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void Mat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator) + allocator->fastFree(data); + else + fastFree(data); + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + cstep = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool Mat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t Mat::total() const +{ + return cstep * c; +} + +NCNN_FORCEINLINE int Mat::elembits() const +{ + return elempack ? static_cast(elemsize * 8) / elempack : 0; +} + +NCNN_FORCEINLINE Mat Mat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE Mat Mat::channel(int _c) +{ + Mat m(w, h, d, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims - 1; + if (dims == 4) + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::channel(int _c) const +{ + Mat m(w, h, d, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims - 1; + if (dims == 4) + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE Mat Mat::depth(int z) +{ + return Mat(w, h, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::depth(int z) const +{ + return Mat(w, h, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE float* Mat::row(int y) +{ + return (float*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +NCNN_FORCEINLINE const float* Mat::row(int y) const +{ + return (const float*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +template +NCNN_FORCEINLINE T* Mat::row(int y) +{ + return (T*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +template +NCNN_FORCEINLINE const T* Mat::row(int y) const +{ + return (const T*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +NCNN_FORCEINLINE Mat Mat::channel_range(int _c, int channels) +{ + Mat m(w, h, d, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::channel_range(int _c, int channels) const +{ + Mat m(w, h, d, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims; + return m; +} + +NCNN_FORCEINLINE Mat Mat::depth_range(int z, int depths) +{ + Mat m(w, h, depths, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::depth_range(int z, int depths) const +{ + Mat m(w, h, depths, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE Mat Mat::row_range(int y, int rows) +{ + return Mat(w, rows, (unsigned char*)data + (size_t)w * y * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::row_range(int y, int rows) const +{ + return Mat(w, rows, (unsigned char*)data + (size_t)w * y * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE Mat Mat::range(int x, int n) +{ + return Mat(n, (unsigned char*)data + x * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::range(int x, int n) const +{ + return Mat(n, (unsigned char*)data + x * elemsize, elemsize, elempack, allocator); +} + +template +NCNN_FORCEINLINE Mat::operator T*() +{ + return (T*)data; +} + +template +NCNN_FORCEINLINE Mat::operator const T*() const +{ + return (const T*)data; +} + +NCNN_FORCEINLINE float& Mat::operator[](size_t i) +{ + return ((float*)data)[i]; +} + +NCNN_FORCEINLINE const float& Mat::operator[](size_t i) const +{ + return ((const float*)data)[i]; +} + +#if NCNN_VULKAN + +NCNN_FORCEINLINE VkMat::VkMat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(const VkMat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c) +{ + addref(); + + cstep = m.cstep; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = w * h; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize(w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = w * h; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize(w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::~VkMat() +{ + release(); +} + +NCNN_FORCEINLINE VkMat& VkMat::operator=(const VkMat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + cstep = m.cstep; + + return *this; +} + +NCNN_FORCEINLINE Mat VkMat::mapped() const +{ + if (!allocator->mappable) + return Mat(); + + if (dims == 1) + return Mat(w, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 2) + return Mat(w, h, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 3) + return Mat(w, h, c, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 4) + return Mat(w, h, d, c, mapped_ptr(), elemsize, elempack, 0); + + return Mat(); +} + +NCNN_FORCEINLINE void* VkMat::mapped_ptr() const +{ + if (!allocator->mappable) + return 0; + + return (unsigned char*)data->mapped_ptr + data->offset; +} + +NCNN_FORCEINLINE void VkMat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void VkMat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator && data) + { + allocator->fastFree(data); + } + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + cstep = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool VkMat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t VkMat::total() const +{ + return cstep * c; +} + +NCNN_FORCEINLINE int VkMat::elembits() const +{ + return elempack ? static_cast(elemsize) * 8 / elempack : 0; +} + +NCNN_FORCEINLINE Mat VkMat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE VkBuffer VkMat::buffer() const +{ + return data->buffer; +} + +NCNN_FORCEINLINE size_t VkMat::buffer_offset() const +{ + return data->offset; +} + +NCNN_FORCEINLINE size_t VkMat::buffer_capacity() const +{ + return data->capacity; +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(const VkImageMat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c) +{ + addref(); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::~VkImageMat() +{ + release(); +} + +NCNN_FORCEINLINE VkImageMat& VkImageMat::operator=(const VkImageMat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + return *this; +} + +NCNN_FORCEINLINE Mat VkImageMat::mapped() const +{ + if (!allocator->mappable || !data->mapped_ptr) + return Mat(); + + if (dims == 1) + return Mat(w, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 2) + return Mat(w, h, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 3) + return Mat(w, h, c, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 4) + return Mat(w, h, d, c, mapped_ptr(), elemsize, elempack, 0); + + return Mat(); +} + +NCNN_FORCEINLINE void* VkImageMat::mapped_ptr() const +{ + if (!allocator->mappable || !data->mapped_ptr) + return 0; + + return (unsigned char*)data->mapped_ptr + data->bind_offset; +} + +NCNN_FORCEINLINE void VkImageMat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void VkImageMat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator && data) + { + allocator->fastFree(data); + } + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool VkImageMat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t VkImageMat::total() const +{ + return w * h * d * c; +} + +NCNN_FORCEINLINE int VkImageMat::elembits() const +{ + return elempack ? static_cast(elemsize) * 8 / elempack : 0; +} + +NCNN_FORCEINLINE Mat VkImageMat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE VkImage VkImageMat::image() const +{ + return data->image; +} + +NCNN_FORCEINLINE VkImageView VkImageMat::imageview() const +{ + return data->imageview; +} + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_MAT_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/modelbin.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/modelbin.h new file mode 100644 index 0000000..aada5f6 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/modelbin.h @@ -0,0 +1,80 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_MODELBIN_H +#define NCNN_MODELBIN_H + +#include "mat.h" + +namespace ncnn { + +class DataReader; +class NCNN_EXPORT ModelBin +{ +public: + ModelBin(); + virtual ~ModelBin(); + // element type + // 0 = auto + // 1 = float32 + // 2 = float16 + // 3 = int8 + // load vec + virtual Mat load(int w, int type) const; + // load image + virtual Mat load(int w, int h, int type) const; + // load dim + virtual Mat load(int w, int h, int c, int type) const; + // load cube + virtual Mat load(int w, int h, int d, int c, int type) const; +}; + +class ModelBinFromDataReaderPrivate; +class NCNN_EXPORT ModelBinFromDataReader : public ModelBin +{ +public: + explicit ModelBinFromDataReader(const DataReader& dr); + virtual ~ModelBinFromDataReader(); + + virtual Mat load(int w, int type) const; + +private: + ModelBinFromDataReader(const ModelBinFromDataReader&); + ModelBinFromDataReader& operator=(const ModelBinFromDataReader&); + +private: + ModelBinFromDataReaderPrivate* const d; +}; + +class ModelBinFromMatArrayPrivate; +class NCNN_EXPORT ModelBinFromMatArray : public ModelBin +{ +public: + // construct from weight blob array + explicit ModelBinFromMatArray(const Mat* weights); + virtual ~ModelBinFromMatArray(); + + virtual Mat load(int w, int type) const; + +private: + ModelBinFromMatArray(const ModelBinFromMatArray&); + ModelBinFromMatArray& operator=(const ModelBinFromMatArray&); + +private: + ModelBinFromMatArrayPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_MODELBIN_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/ncnn_export.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/ncnn_export.h new file mode 100644 index 0000000..e2f5fde --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/ncnn_export.h @@ -0,0 +1,42 @@ + +#ifndef NCNN_EXPORT_H +#define NCNN_EXPORT_H + +#ifdef NCNN_STATIC_DEFINE +# define NCNN_EXPORT +# define NCNN_NO_EXPORT +#else +# ifndef NCNN_EXPORT +# ifdef ncnn_EXPORTS + /* We are building this library */ +# define NCNN_EXPORT __attribute__((visibility("default"))) +# else + /* We are using this library */ +# define NCNN_EXPORT __attribute__((visibility("default"))) +# endif +# endif + +# ifndef NCNN_NO_EXPORT +# define NCNN_NO_EXPORT __attribute__((visibility("hidden"))) +# endif +#endif + +#ifndef NCNN_DEPRECATED +# define NCNN_DEPRECATED __attribute__ ((__deprecated__)) +#endif + +#ifndef NCNN_DEPRECATED_EXPORT +# define NCNN_DEPRECATED_EXPORT NCNN_EXPORT NCNN_DEPRECATED +#endif + +#ifndef NCNN_DEPRECATED_NO_EXPORT +# define NCNN_DEPRECATED_NO_EXPORT NCNN_NO_EXPORT NCNN_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef NCNN_NO_DEPRECATED +# define NCNN_NO_DEPRECATED +# endif +#endif + +#endif /* NCNN_EXPORT_H */ diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/net.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/net.h new file mode 100644 index 0000000..98e3ec3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/net.h @@ -0,0 +1,274 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_NET_H +#define NCNN_NET_H + +#include "blob.h" +#include "layer.h" +#include "mat.h" +#include "option.h" +#include "platform.h" + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +#if NCNN_VULKAN +class VkCompute; +#endif // NCNN_VULKAN +class DataReader; +class Extractor; +class NetPrivate; +class NCNN_EXPORT Net +{ +public: + // empty init + Net(); + // clear and destroy + virtual ~Net(); + +public: + // option can be changed before loading + Option opt; + +#if NCNN_VULKAN + // set gpu device by index + void set_vulkan_device(int device_index); + + // set gpu device by device handle, no owner transfer + void set_vulkan_device(const VulkanDevice* vkdev); + + const VulkanDevice* vulkan_device() const; +#endif // NCNN_VULKAN + +#if NCNN_STRING + // register custom layer or overwrite built-in layer by layer type name + // return 0 if success + int register_custom_layer(const char* type, layer_creator_func creator, layer_destroyer_func destroyer = 0, void* userdata = 0); + virtual int custom_layer_to_index(const char* type); +#endif // NCNN_STRING + // register custom layer or overwrite built-in layer by layer type + // return 0 if success + int register_custom_layer(int index, layer_creator_func creator, layer_destroyer_func destroyer = 0, void* userdata = 0); + +#if NCNN_STRING + int load_param(const DataReader& dr); +#endif // NCNN_STRING + + int load_param_bin(const DataReader& dr); + + int load_model(const DataReader& dr); + +#if NCNN_STDIO +#if NCNN_STRING + // load network structure from plain param file + // return 0 if success + int load_param(FILE* fp); + int load_param(const char* protopath); + int load_param_mem(const char* mem); +#endif // NCNN_STRING + // load network structure from binary param file + // return 0 if success + int load_param_bin(FILE* fp); + int load_param_bin(const char* protopath); + + // load network weight data from model file + // return 0 if success + int load_model(FILE* fp); + int load_model(const char* modelpath); +#endif // NCNN_STDIO + + // load network structure from external memory + // memory pointer must be 32-bit aligned + // return bytes consumed + int load_param(const unsigned char* mem); + + // reference network weight data from external memory + // weight data is not copied but referenced + // so external memory should be retained when used + // memory pointer must be 32-bit aligned + // return bytes consumed + int load_model(const unsigned char* mem); + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#if NCNN_STRING + // convenient load network structure from android asset plain param file + int load_param(AAsset* asset); + int load_param(AAssetManager* mgr, const char* assetpath); +#endif // NCNN_STRING + // convenient load network structure from android asset binary param file + int load_param_bin(AAsset* asset); + int load_param_bin(AAssetManager* mgr, const char* assetpath); + + // convenient load network weight data from android asset model file + int load_model(AAsset* asset); + int load_model(AAssetManager* mgr, const char* assetpath); +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + + // unload network structure and weight data + void clear(); + + // construct an Extractor from network + Extractor create_extractor() const; + + // get input/output indexes/names + const std::vector& input_indexes() const; + const std::vector& output_indexes() const; +#if NCNN_STRING + const std::vector& input_names() const; + const std::vector& output_names() const; +#endif + + const std::vector& blobs() const; + const std::vector& layers() const; + + std::vector& mutable_blobs(); + std::vector& mutable_layers(); + +protected: + friend class Extractor; +#if NCNN_STRING + int find_blob_index_by_name(const char* name) const; + int find_layer_index_by_name(const char* name) const; + virtual Layer* create_custom_layer(const char* type); + virtual Layer* create_overwrite_builtin_layer(const char* type); +#endif // NCNN_STRING + virtual Layer* create_custom_layer(int index); + virtual Layer* create_overwrite_builtin_layer(int typeindex); + +private: + Net(const Net&); + Net& operator=(const Net&); + +private: + NetPrivate* const d; +}; + +class ExtractorPrivate; +class NCNN_EXPORT Extractor +{ +public: + virtual ~Extractor(); + + // copy + Extractor(const Extractor&); + + // assign + Extractor& operator=(const Extractor&); + + // clear blob mats and alloctors + void clear(); + + // enable light mode + // intermediate blob will be recycled when enabled + // enabled by default + void set_light_mode(bool enable); + + // set thread count for this extractor + // this will overwrite the global setting + // default count is system depended + void set_num_threads(int num_threads); + + // set blob memory allocator + void set_blob_allocator(Allocator* allocator); + + // set workspace memory allocator + void set_workspace_allocator(Allocator* allocator); + +#if NCNN_VULKAN + void set_vulkan_compute(bool enable); + + void set_blob_vkallocator(VkAllocator* allocator); + + void set_workspace_vkallocator(VkAllocator* allocator); + + void set_staging_vkallocator(VkAllocator* allocator); +#endif // NCNN_VULKAN + +#if NCNN_STRING + // set input by blob name + // return 0 if success + int input(const char* blob_name, const Mat& in); + + // get result by blob name + // return 0 if success + // type = 0, default + // type = 1, do not convert fp16/bf16 or / and packing + int extract(const char* blob_name, Mat& feat, int type = 0); +#endif // NCNN_STRING + + // set input by blob index + // return 0 if success + int input(int blob_index, const Mat& in); + + // get result by blob index + // return 0 if success + // type = 0, default + // type = 1, do not convert fp16/bf16 or / and packing + int extract(int blob_index, Mat& feat, int type = 0); + +#if NCNN_VULKAN +#if NCNN_STRING + // set input by blob name + // return 0 if success + int input(const char* blob_name, const VkMat& in); + + // get result by blob name + // return 0 if success + int extract(const char* blob_name, VkMat& feat, VkCompute& cmd); + + // set input by blob name + // return 0 if success + int input(const char* blob_name, const VkImageMat& in); + + // get result by blob name + // return 0 if success + int extract(const char* blob_name, VkImageMat& feat, VkCompute& cmd); +#endif // NCNN_STRING + + // set input by blob index + // return 0 if success + int input(int blob_index, const VkMat& in); + + // get result by blob index + // return 0 if success + int extract(int blob_index, VkMat& feat, VkCompute& cmd); + + // set input by blob index + // return 0 if success + int input(int blob_index, const VkImageMat& in); + + // get result by blob index + // return 0 if success + int extract(int blob_index, VkImageMat& feat, VkCompute& cmd); +#endif // NCNN_VULKAN + +protected: + friend Extractor Net::create_extractor() const; + Extractor(const Net* net, size_t blob_count); + +private: + ExtractorPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_NET_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/option.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/option.h new file mode 100644 index 0000000..7d0cc60 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/option.h @@ -0,0 +1,156 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_OPTION_H +#define NCNN_OPTION_H + +#include "platform.h" + +namespace ncnn { + +#if NCNN_VULKAN +class VkAllocator; +class PipelineCache; +#endif // NCNN_VULKAN + +class Allocator; +class NCNN_EXPORT Option +{ +public: + // default option + Option(); + +public: + // light mode + // intermediate blob will be recycled when enabled + // enabled by default + bool lightmode; + + // thread count + // default value is the one returned by get_cpu_count() + int num_threads; + + // blob memory allocator + Allocator* blob_allocator; + + // workspace memory allocator + Allocator* workspace_allocator; + +#if NCNN_VULKAN + // blob memory allocator + VkAllocator* blob_vkallocator; + + // workspace memory allocator + VkAllocator* workspace_vkallocator; + + // staging memory allocator + VkAllocator* staging_vkallocator; + + // pipeline cache + PipelineCache* pipeline_cache; +#endif // NCNN_VULKAN + + // the time openmp threads busy-wait for more work before going to sleep + // default value is 20ms to keep the cores enabled + // without too much extra power consumption afterwards + int openmp_blocktime; + + // enable winograd convolution optimization + // improve convolution 3x3 stride1 performance, may consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_winograd_convolution; + + // enable sgemm convolution optimization + // improve convolution 1x1 stride1 performance, may consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_sgemm_convolution; + + // enable quantized int8 inference + // use low-precision int8 path for quantized model + // changes should be applied before loading network structure and weight + // enabled by default + bool use_int8_inference; + + // enable vulkan compute + bool use_vulkan_compute; + + // enable bf16 data type for storage + // improve most operator performance on all arm devices, may consume more memory + bool use_bf16_storage; + + // enable options for gpu inference + bool use_fp16_packed; + bool use_fp16_storage; + bool use_fp16_arithmetic; + bool use_int8_packed; + bool use_int8_storage; + bool use_int8_arithmetic; + + // enable simd-friendly packed memory layout + // improve all operator performance on all arm devices, will consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_packing_layout; + + bool use_shader_pack8; + + // subgroup option + bool use_subgroup_basic; + bool use_subgroup_vote; + bool use_subgroup_ballot; + bool use_subgroup_shuffle; + + // turn on for adreno + bool use_image_storage; + bool use_tensor_storage; + + bool use_reserved_0; + + // enable DAZ(Denormals-Are-Zero) and FTZ(Flush-To-Zero) + // default value is 3 + // 0 = DAZ OFF, FTZ OFF + // 1 = DAZ ON , FTZ OFF + // 2 = DAZ OFF, FTZ ON + // 3 = DAZ ON, FTZ ON + int flush_denormals; + + bool use_local_pool_allocator; + + // enable local memory optimization for gpu inference + bool use_shader_local_memory; + + // enable cooperative matrix optimization for gpu inference + bool use_cooperative_matrix; + + // more fine-grained control of winograd convolution + bool use_winograd23_convolution; + bool use_winograd43_convolution; + bool use_winograd63_convolution; + + // this option is turned on for A53/A55 automatically + // but you can force this on/off if you wish + bool use_a53_a55_optimized_kernel; + + bool use_reserved_7; + bool use_reserved_8; + bool use_reserved_9; + bool use_reserved_10; + bool use_reserved_11; +}; + +} // namespace ncnn + +#endif // NCNN_OPTION_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/paramdict.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/paramdict.h new file mode 100644 index 0000000..c2ef160 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/paramdict.h @@ -0,0 +1,73 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PARAMDICT_H +#define NCNN_PARAMDICT_H + +#include "mat.h" + +// at most 32 parameters +#define NCNN_MAX_PARAM_COUNT 32 + +namespace ncnn { + +class DataReader; +class Net; +class ParamDictPrivate; +class NCNN_EXPORT ParamDict +{ +public: + // empty + ParamDict(); + + virtual ~ParamDict(); + + // copy + ParamDict(const ParamDict&); + + // assign + ParamDict& operator=(const ParamDict&); + + // get type + int type(int id) const; + + // get int + int get(int id, int def) const; + // get float + float get(int id, float def) const; + // get array + Mat get(int id, const Mat& def) const; + + // set int + void set(int id, int i); + // set float + void set(int id, float f); + // set array + void set(int id, const Mat& v); + +protected: + friend class Net; + + void clear(); + + int load_param(const DataReader& dr); + int load_param_bin(const DataReader& dr); + +private: + ParamDictPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_PARAMDICT_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/pipeline.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/pipeline.h new file mode 100644 index 0000000..c284a14 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/pipeline.h @@ -0,0 +1,113 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PIPELINE_H +#define NCNN_PIPELINE_H + +#include "mat.h" +#include "platform.h" +#if NCNN_VULKAN +#include "gpu.h" + +#include +#endif // NCNN_VULKAN + +namespace ncnn { + +#if NCNN_VULKAN +class Option; +class PipelinePrivate; +class NCNN_EXPORT Pipeline +{ +public: + explicit Pipeline(const VulkanDevice* vkdev); + virtual ~Pipeline(); + +public: + void set_optimal_local_size_xyz(int w = 4, int h = 4, int c = 4); + void set_optimal_local_size_xyz(const Mat& local_size_xyz); + void set_local_size_xyz(int w, int h, int c); + + int create(const uint32_t* spv_data, size_t spv_data_size, const std::vector& specializations); + + int create(int shader_type_index, const Option& opt, const std::vector& specializations); + +public: + VkShaderModule shader_module() const; + VkDescriptorSetLayout descriptorset_layout() const; + VkPipelineLayout pipeline_layout() const; + VkPipeline pipeline() const; + VkDescriptorUpdateTemplateKHR descriptor_update_template() const; + + const ShaderInfo& shader_info() const; + + uint32_t local_size_x() const; + uint32_t local_size_y() const; + uint32_t local_size_z() const; + +protected: + void set_shader_module(VkShaderModule shader_module); + void set_descriptorset_layout(VkDescriptorSetLayout descriptorset_layout); + void set_pipeline_layout(VkPipelineLayout pipeline_layout); + void set_pipeline(VkPipeline pipeline); + void set_descriptor_update_template(VkDescriptorUpdateTemplateKHR descriptor_update_template); + + void set_shader_info(const ShaderInfo& shader_info); + +public: + const VulkanDevice* vkdev; + +private: + Pipeline(const Pipeline&); + Pipeline& operator=(const Pipeline&); + +private: + PipelinePrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class VkCompute; +class NCNN_EXPORT ImportAndroidHardwareBufferPipeline : private Pipeline +{ +public: + explicit ImportAndroidHardwareBufferPipeline(const VulkanDevice* vkdev); + virtual ~ImportAndroidHardwareBufferPipeline(); + + int create(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator, int type_to, int rotate_from, const Option& opt); + int create(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator, int type_to, int rotate_from, int target_width, int target_height, const Option& opt); + void destroy(); + + friend class VkCompute; + +protected: + int create_shader_module(const Option& opt); + int create_sampler(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator); + int create_descriptorset_layout(); + +public: + int type_to; + int rotate_from; + bool need_resize; + + VkSampler sampler; +}; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_PIPELINE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/pipelinecache.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/pipelinecache.h new file mode 100644 index 0000000..bb6b8fb --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/pipelinecache.h @@ -0,0 +1,85 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PIPELINECACHE_H +#define NCNN_PIPELINECACHE_H + +#include "platform.h" + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#include "mat.h" +#include "gpu.h" + +namespace ncnn { + +#if NCNN_VULKAN + +class VulkanDevice; +class PipelineCachePrivate; +class NCNN_EXPORT PipelineCache +{ +public: + explicit PipelineCache(const VulkanDevice* _vkdev); + + virtual ~PipelineCache(); + + void clear(); + + int get_pipeline(const uint32_t* spv_data, size_t spv_data_size, const std::vector& specializations, + uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* shader_module, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template, + ShaderInfo& shader_info) const; + + int get_pipeline(int shader_type_index, const Option& opt, const std::vector& specializations, + uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* shader_module, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template, + ShaderInfo& shader_info) const; + +protected: + int create_shader_module(int shader_type_index, const Option& opt, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* _shader_module, ShaderInfo& si) const; + + int new_pipeline(VkShaderModule shader_module, const ShaderInfo& shader_info, const std::vector& specializations, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template) const; + +protected: + const VulkanDevice* vkdev; + +private: + PipelineCache(const PipelineCache&); + PipelineCache& operator=(const PipelineCache&); + +private: + PipelineCachePrivate* const d; +}; + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_PIPELINECACHE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/platform.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/platform.h new file mode 100644 index 0000000..8c46058 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/platform.h @@ -0,0 +1,293 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PLATFORM_H +#define NCNN_PLATFORM_H + +#define NCNN_STDIO 1 +#define NCNN_STRING 1 +#define NCNN_SIMPLEOCV 0 +#define NCNN_SIMPLEOMP 0 +#define NCNN_SIMPLESTL 0 +#define NCNN_SIMPLEMATH 0 +#define NCNN_THREADS 1 +#define NCNN_BENCHMARK 0 +#define NCNN_C_API 1 +#define NCNN_PLATFORM_API 1 +#define NCNN_PIXEL 1 +#define NCNN_PIXEL_ROTATE 1 +#define NCNN_PIXEL_AFFINE 1 +#define NCNN_PIXEL_DRAWING 1 +#define NCNN_VULKAN 0 +#define NCNN_SYSTEM_GLSLANG 0 +#define NCNN_RUNTIME_CPU 1 +#define NCNN_GNU_INLINE_ASM 1 +#define NCNN_AVX 0 +#define NCNN_XOP 0 +#define NCNN_FMA 0 +#define NCNN_F16C 0 +#define NCNN_AVX2 0 +#define NCNN_AVXVNNI 0 +#define NCNN_AVX512 0 +#define NCNN_AVX512VNNI 0 +#define NCNN_AVX512BF16 0 +#define NCNN_AVX512FP16 0 +#define NCNN_VFPV4 1 +#define NCNN_ARM82 1 +#define NCNN_ARM82DOT 1 +#define NCNN_ARM82FP16FML 1 +#define NCNN_ARM84BF16 1 +#define NCNN_ARM84I8MM 1 +#define NCNN_ARM86SVE 1 +#define NCNN_ARM86SVE2 1 +#define NCNN_ARM86SVEBF16 1 +#define NCNN_ARM86SVEI8MM 1 +#define NCNN_ARM86SVEF32MM 1 +#define NCNN_MSA 0 +#define NCNN_LSX 0 +#define NCNN_MMI 0 +#define NCNN_RVV 0 +#define NCNN_INT8 1 +#define NCNN_BF16 1 +#define NCNN_FORCE_INLINE 1 + +#define NCNN_VERSION_STRING "1.0.20231027" + +#include "ncnn_export.h" + +#ifdef __cplusplus + +#if NCNN_THREADS +#if (defined _WIN32 && !(defined __MINGW32__)) +#define WIN32_LEAN_AND_MEAN +#include +#include +#else +#include +#endif +#endif // NCNN_THREADS + +#if __ANDROID_API__ >= 26 +#define VK_USE_PLATFORM_ANDROID_KHR +#endif // __ANDROID_API__ >= 26 + +namespace ncnn { + +#if NCNN_THREADS +#if (defined _WIN32 && !(defined __MINGW32__)) +class NCNN_EXPORT Mutex +{ +public: + Mutex() { InitializeSRWLock(&srwlock); } + ~Mutex() {} + void lock() { AcquireSRWLockExclusive(&srwlock); } + void unlock() { ReleaseSRWLockExclusive(&srwlock); } +private: + friend class ConditionVariable; + // NOTE SRWLock is available from windows vista + SRWLOCK srwlock; +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() { InitializeConditionVariable(&condvar); } + ~ConditionVariable() {} + void wait(Mutex& mutex) { SleepConditionVariableSRW(&condvar, &mutex.srwlock, INFINITE, 0); } + void broadcast() { WakeAllConditionVariable(&condvar); } + void signal() { WakeConditionVariable(&condvar); } +private: + CONDITION_VARIABLE condvar; +}; + +static unsigned __stdcall start_wrapper(void* args); +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*start)(void*), void* args = 0) { _start = start; _args = args; handle = (HANDLE)_beginthreadex(0, 0, start_wrapper, this, 0, 0); } + ~Thread() {} + void join() { WaitForSingleObject(handle, INFINITE); CloseHandle(handle); } +private: + friend unsigned __stdcall start_wrapper(void* args) + { + Thread* t = (Thread*)args; + t->_start(t->_args); + return 0; + } + HANDLE handle; + void* (*_start)(void*); + void* _args; +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { key = TlsAlloc(); } + ~ThreadLocalStorage() { TlsFree(key); } + void set(void* value) { TlsSetValue(key, (LPVOID)value); } + void* get() { return (void*)TlsGetValue(key); } +private: + DWORD key; +}; +#else // (defined _WIN32 && !(defined __MINGW32__)) +class NCNN_EXPORT Mutex +{ +public: + Mutex() { pthread_mutex_init(&mutex, 0); } + ~Mutex() { pthread_mutex_destroy(&mutex); } + void lock() { pthread_mutex_lock(&mutex); } + void unlock() { pthread_mutex_unlock(&mutex); } +private: + friend class ConditionVariable; + pthread_mutex_t mutex; +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() { pthread_cond_init(&cond, 0); } + ~ConditionVariable() { pthread_cond_destroy(&cond); } + void wait(Mutex& mutex) { pthread_cond_wait(&cond, &mutex.mutex); } + void broadcast() { pthread_cond_broadcast(&cond); } + void signal() { pthread_cond_signal(&cond); } +private: + pthread_cond_t cond; +}; + +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*start)(void*), void* args = 0) { pthread_create(&t, 0, start, args); } + ~Thread() {} + void join() { pthread_join(t, 0); } +private: + pthread_t t; +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { pthread_key_create(&key, 0); } + ~ThreadLocalStorage() { pthread_key_delete(key); } + void set(void* value) { pthread_setspecific(key, value); } + void* get() { return pthread_getspecific(key); } +private: + pthread_key_t key; +}; +#endif // (defined _WIN32 && !(defined __MINGW32__)) +#else // NCNN_THREADS +class NCNN_EXPORT Mutex +{ +public: + Mutex() {} + ~Mutex() {} + void lock() {} + void unlock() {} +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() {} + ~ConditionVariable() {} + void wait(Mutex& /*mutex*/) {} + void broadcast() {} + void signal() {} +}; + +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*/*start*/)(void*), void* /*args*/ = 0) {} + ~Thread() {} + void join() {} +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { data = 0; } + ~ThreadLocalStorage() {} + void set(void* value) { data = value; } + void* get() { return data; } +private: + void* data; +}; +#endif // NCNN_THREADS + +class NCNN_EXPORT MutexLockGuard +{ +public: + MutexLockGuard(Mutex& _mutex) : mutex(_mutex) { mutex.lock(); } + ~MutexLockGuard() { mutex.unlock(); } +private: + Mutex& mutex; +}; + +} // namespace ncnn + +#if NCNN_SIMPLESTL +#include "simplestl.h" +#else +#include +#include +#include +#include +#endif + +// simplemath +#if NCNN_SIMPLEMATH +#include "simplemath.h" +#else +#include +#include +#endif + +#endif // __cplusplus + +#if NCNN_STDIO +#if NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#include +#define NCNN_LOGE(...) do { \ + fprintf(stderr, ##__VA_ARGS__); fprintf(stderr, "\n"); \ + __android_log_print(ANDROID_LOG_WARN, "ncnn", ##__VA_ARGS__); } while(0) +#else // NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#include +#define NCNN_LOGE(...) do { \ + fprintf(stderr, ##__VA_ARGS__); fprintf(stderr, "\n"); } while(0) +#endif // NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#else +#define NCNN_LOGE(...) +#endif + + +#if NCNN_FORCE_INLINE +#ifdef _MSC_VER + #define NCNN_FORCEINLINE __forceinline +#elif defined(__GNUC__) + #define NCNN_FORCEINLINE inline __attribute__((__always_inline__)) +#elif defined(__CLANG__) + #if __has_attribute(__always_inline__) + #define NCNN_FORCEINLINE inline __attribute__((__always_inline__)) + #else + #define NCNN_FORCEINLINE inline + #endif +#else + #define NCNN_FORCEINLINE inline +#endif +#else + #define NCNN_FORCEINLINE inline +#endif + +#endif // NCNN_PLATFORM_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/simplemath.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/simplemath.h new file mode 100644 index 0000000..fd7fa69 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/simplemath.h @@ -0,0 +1,102 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEMATH_H +#define NCNN_SIMPLEMATH_H + +#include "platform.h" + +#if NCNN_SIMPLEMATH + +#ifdef __cplusplus +extern "C" { +#endif +/* +* ==================================================== +* discrete functions +* ==================================================== +*/ +NCNN_EXPORT float fabs(float); +NCNN_EXPORT float fabsf(float); +NCNN_EXPORT float fmod(float, float); +NCNN_EXPORT float floor(float); +NCNN_EXPORT float floorf(float); +NCNN_EXPORT float round(float); +NCNN_EXPORT float roundf(float); +NCNN_EXPORT float ceil(float); +NCNN_EXPORT float ceilf(float); +NCNN_EXPORT float fmaxf(float, float); +NCNN_EXPORT float truncf(float); +NCNN_EXPORT float frac(float); +/* +* ==================================================== +* trigonometric functions +* ==================================================== +*/ +NCNN_EXPORT float sinf(float); +NCNN_EXPORT float cosf(float); +NCNN_EXPORT float tanf(float); +NCNN_EXPORT float asinf(float); +NCNN_EXPORT float acosf(float); +NCNN_EXPORT float atanf(float); +NCNN_EXPORT float atan2f(float, float); +NCNN_EXPORT float tanhf(float); + +/* +* ==================================================== +* power functions +* ==================================================== +*/ +NCNN_EXPORT float sqrtf(float); +NCNN_EXPORT float sqrt(float); +NCNN_EXPORT float powf(float, float); + +/* +* ==================================================== +* exponential and logarithm functions +* ==================================================== +*/ +NCNN_EXPORT float expf(float); +NCNN_EXPORT float frexp(float, int*); +NCNN_EXPORT float logf(float); +NCNN_EXPORT float log(float); +NCNN_EXPORT float log10f(float); + +/* +* ==================================================== +* probability functions +* ==================================================== +*/ +NCNN_EXPORT float erf(float); +NCNN_EXPORT float erfcf(float); + +/* +* ==================================================== +* other functions +* ==================================================== +*/ +NCNN_EXPORT int msb(unsigned int); +NCNN_EXPORT float fmaf(float, float, float); +NCNN_EXPORT float copysignf(float, float); +NCNN_EXPORT void fesetround(int); +NCNN_EXPORT int fegetround(); +NCNN_EXPORT float nearbyintf(float); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // NCNN_SIMPLEMATH + +#endif // NCNN_SIMPLEMATH_H \ No newline at end of file diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/simpleocv.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/simpleocv.h new file mode 100644 index 0000000..54b22d9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/simpleocv.h @@ -0,0 +1,503 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEOCV_H +#define NCNN_SIMPLEOCV_H + +#include "platform.h" + +#if NCNN_SIMPLEOCV + +#include +#include +#include "allocator.h" +#include "mat.h" + +#if defined(_MSC_VER) || defined(__GNUC__) +#pragma push_macro("min") +#pragma push_macro("max") +#undef min +#undef max +#endif + +#ifndef NCNN_XADD +using ncnn::NCNN_XADD; +#endif + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; + +enum +{ + CV_LOAD_IMAGE_UNCHANGED = -1, + CV_LOAD_IMAGE_GRAYSCALE = 0, + CV_LOAD_IMAGE_COLOR = 1, +}; + +enum +{ + CV_IMWRITE_JPEG_QUALITY = 1 +}; + +// minimal opencv style data structure implementation +namespace cv { + +template +static inline _Tp saturate_cast(int v) +{ + return _Tp(v); +} +template<> +inline uchar saturate_cast(int v) +{ + return (uchar)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); +} + +template +struct Scalar_ +{ + Scalar_() + { + v[0] = 0; + v[1] = 0; + v[2] = 0; + v[3] = 0; + } + Scalar_(_Tp _v0) + { + v[0] = _v0; + v[1] = 0; + v[2] = 0; + v[3] = 0; + } + Scalar_(_Tp _v0, _Tp _v1, _Tp _v2) + { + v[0] = _v0; + v[1] = _v1; + v[2] = _v2; + v[3] = 0; + } + Scalar_(_Tp _v0, _Tp _v1, _Tp _v2, _Tp _v3) + { + v[0] = _v0; + v[1] = _v1; + v[2] = _v2; + v[3] = _v3; + } + + const _Tp operator[](const int i) const + { + return v[i]; + } + + _Tp operator[](const int i) + { + return v[i]; + } + + _Tp v[4]; +}; + +typedef Scalar_ Scalar; + +template +struct Point_ +{ + Point_() + : x(0), y(0) + { + } + Point_(_Tp _x, _Tp _y) + : x(_x), y(_y) + { + } + + template + operator Point_<_Tp2>() const + { + return Point_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y)); + } + + _Tp x; + _Tp y; +}; + +typedef Point_ Point; +typedef Point_ Point2f; + +template +struct Size_ +{ + Size_() + : width(0), height(0) + { + } + Size_(_Tp _w, _Tp _h) + : width(_w), height(_h) + { + } + + template + operator Size_<_Tp2>() const + { + return Size_<_Tp2>(saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); + } + + _Tp width; + _Tp height; +}; + +typedef Size_ Size; +typedef Size_ Size2f; + +template +struct Rect_ +{ + Rect_() + : x(0), y(0), width(0), height(0) + { + } + Rect_(_Tp _x, _Tp _y, _Tp _w, _Tp _h) + : x(_x), y(_y), width(_w), height(_h) + { + } + Rect_(Point_<_Tp> _p, Size_<_Tp> _size) + : x(_p.x), y(_p.y), width(_size.width), height(_size.height) + { + } + + template + operator Rect_<_Tp2>() const + { + return Rect_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y), saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); + } + + _Tp x; + _Tp y; + _Tp width; + _Tp height; + + // area + _Tp area() const + { + return width * height; + } +}; + +template +static inline Rect_<_Tp>& operator&=(Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + _Tp x1 = std::max(a.x, b.x), y1 = std::max(a.y, b.y); + a.width = std::min(a.x + a.width, b.x + b.width) - x1; + a.height = std::min(a.y + a.height, b.y + b.height) - y1; + a.x = x1; + a.y = y1; + if (a.width <= 0 || a.height <= 0) + a = Rect_<_Tp>(); + return a; +} + +template +static inline Rect_<_Tp>& operator|=(Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + _Tp x1 = std::min(a.x, b.x), y1 = std::min(a.y, b.y); + a.width = std::max(a.x + a.width, b.x + b.width) - x1; + a.height = std::max(a.y + a.height, b.y + b.height) - y1; + a.x = x1; + a.y = y1; + return a; +} + +template +static inline Rect_<_Tp> operator&(const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c &= b; +} + +template +static inline Rect_<_Tp> operator|(const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c |= b; +} + +typedef Rect_ Rect; +typedef Rect_ Rect2f; + +#define CV_8UC1 1 +#define CV_8UC3 3 +#define CV_8UC4 4 +#define CV_32FC1 4 + +struct NCNN_EXPORT Mat +{ + Mat() + : data(0), refcount(0), rows(0), cols(0), c(0) + { + } + + Mat(int _rows, int _cols, int flags) + : data(0), refcount(0) + { + create(_rows, _cols, flags); + } + + // copy + Mat(const Mat& m) + : data(m.data), refcount(m.refcount) + { + if (refcount) + NCNN_XADD(refcount, 1); + + rows = m.rows; + cols = m.cols; + c = m.c; + } + + Mat(int _rows, int _cols, int flags, void* _data) + : data((unsigned char*)_data), refcount(0) + { + rows = _rows; + cols = _cols; + c = flags; + } + + ~Mat() + { + release(); + } + + // assign + Mat& operator=(const Mat& m) + { + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + + rows = m.rows; + cols = m.cols; + c = m.c; + + return *this; + } + + Mat& operator=(const Scalar& s) + { + if (total() > 0) + { + uchar* p = data; + for (int i = 0; i < cols * rows; i++) + { + for (int j = 0; j < c; j++) + { + *p++ = s[j]; + } + } + } + + return *this; + } + + void create(int _rows, int _cols, int flags) + { + release(); + + rows = _rows; + cols = _cols; + c = flags; + + if (total() > 0) + { + // refcount address must be aligned, so we expand totalsize here + size_t totalsize = (total() + 3) >> 2 << 2; + data = (uchar*)ncnn::fastMalloc(totalsize + (int)sizeof(*refcount)); + refcount = (int*)(((uchar*)data) + totalsize); + *refcount = 1; + } + } + + void release() + { + if (refcount && NCNN_XADD(refcount, -1) == 1) + ncnn::fastFree(data); + + data = 0; + + rows = 0; + cols = 0; + c = 0; + + refcount = 0; + } + + Mat clone() const + { + if (empty()) + return Mat(); + + Mat m(rows, cols, c); + + if (total() > 0) + { + memcpy(m.data, data, total()); + } + + return m; + } + + bool empty() const + { + return data == 0 || total() == 0; + } + + int channels() const + { + return c; + } + + int type() const + { + return c; + } + + size_t total() const + { + return cols * rows * c; + } + + const uchar* ptr(int y) const + { + return data + y * cols * c; + } + + uchar* ptr(int y) + { + return data + y * cols * c; + } + + template + const _Tp* ptr(int y) const + { + return (const _Tp*)data + y * cols * c; + } + + template + _Tp* ptr(int y) + { + return (_Tp*)data + y * cols * c; + } + + // roi + Mat operator()(const Rect& roi) const + { + if (empty()) + return Mat(); + + Mat m(roi.height, roi.width, c); + + int sy = roi.y; + for (int y = 0; y < roi.height; y++) + { + const uchar* sptr = ptr(sy) + roi.x * c; + uchar* dptr = m.ptr(y); + memcpy(dptr, sptr, roi.width * c); + sy++; + } + + return m; + } + + uchar* data; + + // pointer to the reference counter; + // when points to user-allocated data, the pointer is NULL + int* refcount; + + int rows; + int cols; + + int c; +}; + +enum ImreadModes +{ + IMREAD_UNCHANGED = -1, + IMREAD_GRAYSCALE = 0, + IMREAD_COLOR = 1 +}; + +NCNN_EXPORT Mat imread(const std::string& path, int flags = IMREAD_COLOR); + +NCNN_EXPORT Mat imdecode(const std::vector& buf, int flags = IMREAD_COLOR); + +enum ImwriteFlags +{ + IMWRITE_JPEG_QUALITY = 1 +}; + +NCNN_EXPORT bool imwrite(const std::string& path, const Mat& m, const std::vector& params = std::vector()); + +NCNN_EXPORT void imshow(const std::string& name, const Mat& m); + +NCNN_EXPORT int waitKey(int delay = 0); + +#if NCNN_PIXEL +NCNN_EXPORT void resize(const Mat& src, Mat& dst, const Size& size, float sw = 0.f, float sh = 0.f, int flags = 0); +#endif // NCNN_PIXEL + +#if NCNN_PIXEL_DRAWING + +enum +{ + FILLED = -1 +}; + +NCNN_EXPORT void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void rectangle(Mat& img, Rect rec, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void circle(Mat& img, Point center, int radius, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void line(Mat& img, Point p0, Point p1, const Scalar& color, int thickness = 1); + +enum +{ + FONT_HERSHEY_SIMPLEX = 0 +}; + +NCNN_EXPORT void putText(Mat& img, const std::string& text, Point org, int fontFace, double fontScale, Scalar color, int thickness = 1); + +NCNN_EXPORT Size getTextSize(const std::string& text, int fontFace, double fontScale, int thickness, int* baseLine); + +#endif // NCNN_PIXEL_DRAWING + +} // namespace cv + +#if defined(_MSC_VER) || defined(__GNUC__) +#pragma pop_macro("min") +#pragma pop_macro("max") +#endif + +#endif // NCNN_SIMPLEOCV + +#endif // NCNN_SIMPLEOCV_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/simpleomp.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/simpleomp.h new file mode 100644 index 0000000..13e2452 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/simpleomp.h @@ -0,0 +1,53 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEOMP_H +#define NCNN_SIMPLEOMP_H + +#include "platform.h" + +#if NCNN_SIMPLEOMP + +#include + +// This minimal openmp runtime implementation only supports the llvm openmp abi +// and only supports #pragma omp parallel for num_threads(X) + +#ifdef __cplusplus +extern "C" { +#endif + +NCNN_EXPORT int omp_get_max_threads(); + +NCNN_EXPORT void omp_set_num_threads(int num_threads); + +NCNN_EXPORT int omp_get_dynamic(); + +NCNN_EXPORT void omp_set_dynamic(int dynamic); + +NCNN_EXPORT int omp_get_num_threads(); + +NCNN_EXPORT int omp_get_thread_num(); + +NCNN_EXPORT int kmp_get_blocktime(); + +NCNN_EXPORT void kmp_set_blocktime(int blocktime); + +#ifdef __cplusplus +} +#endif + +#endif // NCNN_SIMPLEOMP + +#endif // NCNN_SIMPLEOMP_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/simplestl.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/simplestl.h new file mode 100644 index 0000000..00ff468 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/simplestl.h @@ -0,0 +1,565 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLESTL_H +#define NCNN_SIMPLESTL_H + +#include +#include +#include + +#if !NCNN_SIMPLESTL + +#include + +#else + +// allocation functions +NCNN_EXPORT void* operator new(size_t size); +NCNN_EXPORT void* operator new[](size_t size); +// placement allocation functions +NCNN_EXPORT void* operator new(size_t size, void* ptr); +NCNN_EXPORT void* operator new[](size_t size, void* ptr); +// deallocation functions +NCNN_EXPORT void operator delete(void* ptr); +NCNN_EXPORT void operator delete[](void* ptr); +// deallocation functions since c++14 +#if __cplusplus >= 201402L +NCNN_EXPORT void operator delete(void* ptr, size_t sz); +NCNN_EXPORT void operator delete[](void* ptr, size_t sz); +#endif +// placement deallocation functions +NCNN_EXPORT void operator delete(void* ptr, void* voidptr2); +NCNN_EXPORT void operator delete[](void* ptr, void* voidptr2); + +#endif + +// minimal stl data structure implementation +namespace std { + +template +const T& max(const T& a, const T& b) +{ + return (a < b) ? b : a; +} + +template +const T& min(const T& a, const T& b) +{ + return (a > b) ? b : a; +} + +template +void swap(T& a, T& b) +{ + T temp(a); + a = b; + b = temp; +} + +template +struct pair +{ + pair() + : first(), second() + { + } + pair(const T1& t1, const T2& t2) + : first(t1), second(t2) + { + } + + T1 first; + T2 second; +}; + +template +bool operator==(const pair& x, const pair& y) +{ + return (x.first == y.first && x.second == y.second); +} +template +bool operator<(const pair& x, const pair& y) +{ + return x.first < y.first || (!(y.first < x.first) && x.second < y.second); +} +template +bool operator!=(const pair& x, const pair& y) +{ + return !(x == y); +} +template +bool operator>(const pair& x, const pair& y) +{ + return y < x; +} +template +bool operator<=(const pair& x, const pair& y) +{ + return !(y < x); +} +template +bool operator>=(const pair& x, const pair& y) +{ + return !(x < y); +} + +template +pair make_pair(const T1& t1, const T2& t2) +{ + return pair(t1, t2); +} + +template +struct node +{ + node* prev_; + node* next_; + T data_; + + node() + : prev_(0), next_(0), data_() + { + } + node(const T& t) + : prev_(0), next_(0), data_(t) + { + } +}; + +template +struct iter_list +{ + iter_list() + : curr_(0) + { + } + iter_list(node* n) + : curr_(n) + { + } + iter_list(const iter_list& i) + : curr_(i.curr_) + { + } + ~iter_list() + { + } + + iter_list& operator=(const iter_list& i) + { + curr_ = i.curr_; + return *this; + } + + T& operator*() + { + return curr_->data_; + } + T* operator->() + { + return &(curr_->data_); + } + + bool operator==(const iter_list& i) + { + return curr_ == i.curr_; + } + bool operator!=(const iter_list& i) + { + return curr_ != i.curr_; + } + + iter_list& operator++() + { + curr_ = curr_->next_; + return *this; + } + iter_list& operator--() + { + curr_ = curr_->prev_; + return *this; + } + + node* curr_; +}; + +template +struct list +{ + typedef iter_list iterator; + + list() + { + head_ = new node(); + tail_ = head_; + count_ = 0; + } + ~list() + { + clear(); + delete head_; + } + list(const list& l) + { + head_ = new node(); + tail_ = head_; + count_ = 0; + + for (iter_list i = l.begin(); i != l.end(); ++i) + { + push_back(*i); + } + } + + list& operator=(const list& l) + { + if (this == &l) + { + return *this; + } + clear(); + + for (iter_list i = l.begin(); i != l.end(); ++i) + { + push_back(*i); + } + return *this; + } + + void clear() + { + while (count_ > 0) + { + pop_front(); + } + } + + void pop_front() + { + if (count_ > 0) + { + head_ = head_->next_; + delete head_->prev_; + head_->prev_ = 0; + --count_; + } + } + + size_t size() const + { + return count_; + } + iter_list begin() const + { + return iter_list(head_); + } + iter_list end() const + { + return iter_list(tail_); + } + bool empty() const + { + return count_ == 0; + } + + void push_back(const T& t) + { + if (count_ == 0) + { + head_ = new node(t); + head_->prev_ = 0; + head_->next_ = tail_; + tail_->prev_ = head_; + count_ = 1; + } + else + { + node* temp = new node(t); + temp->prev_ = tail_->prev_; + temp->next_ = tail_; + tail_->prev_->next_ = temp; + tail_->prev_ = temp; + ++count_; + } + } + + iter_list erase(iter_list pos) + { + if (pos != end()) + { + node* temp = pos.curr_; + if (temp == head_) + { + ++pos; + temp->next_->prev_ = 0; + head_ = temp->next_; + } + else + { + --pos; + temp->next_->prev_ = temp->prev_; + temp->prev_->next_ = temp->next_; + ++pos; + } + delete temp; + --count_; + } + return pos; + } + +protected: + node* head_; + node* tail_; + size_t count_; +}; + +template +struct greater +{ + bool operator()(const T& x, const T& y) const + { + return (x > y); + } +}; + +template +struct less +{ + bool operator()(const T& x, const T& y) const + { + return (x < y); + } +}; + +template +void partial_sort(RandomAccessIter first, RandomAccessIter middle, RandomAccessIter last, Compare comp) +{ + // [TODO] heap sort should be used here, but we simply use bubble sort now + for (RandomAccessIter i = first; i < middle; ++i) + { + // bubble sort + for (RandomAccessIter j = last - 1; j > first; --j) + { + if (comp(*j, *(j - 1))) + { + swap(*j, *(j - 1)); + } + } + } +} + +template +struct vector +{ + vector() + : data_(0), size_(0), capacity_(0) + { + } + vector(const size_t new_size, const T& value = T()) + : data_(0), size_(0), capacity_(0) + { + resize(new_size, value); + } + ~vector() + { + clear(); + } + vector(const vector& v) + : data_(0), size_(0), capacity_(0) + { + resize(v.size()); + for (size_t i = 0; i < size_; i++) + { + data_[i] = v.data_[i]; + } + } + + vector& operator=(const vector& v) + { + if (this == &v) + { + return *this; + } + resize(0); + resize(v.size()); + for (size_t i = 0; i < size_; i++) + { + data_[i] = v.data_[i]; + } + return *this; + } + + void resize(const size_t new_size, const T& value = T()) + { + try_alloc(new_size); + if (new_size > size_) + { + for (size_t i = size_; i < new_size; i++) + { + new (&data_[i]) T(value); + } + } + else if (new_size < size_) + { + for (size_t i = new_size; i < size_; i++) + { + data_[i].~T(); + } + } + size_ = new_size; + } + + void clear() + { + for (size_t i = 0; i < size_; i++) + { + data_[i].~T(); + } + delete[](char*) data_; + data_ = 0; + size_ = 0; + capacity_ = 0; + } + + T* data() const + { + return data_; + } + size_t size() const + { + return size_; + } + T& operator[](size_t i) const + { + return data_[i]; + } + T* begin() const + { + return &data_[0]; + } + T* end() const + { + return &data_[size_]; + } + bool empty() const + { + return size_ == 0; + } + + void push_back(const T& t) + { + try_alloc(size_ + 1); + new (&data_[size_]) T(t); + size_++; + } + + void insert(T* pos, T* b, T* e) + { + vector* v = 0; + if (b >= begin() && b < end()) + { + //the same vector + v = new vector(*this); + b = v->begin() + (b - begin()); + e = v->begin() + (e - begin()); + } + size_t diff = pos - begin(); + try_alloc(size_ + (e - b)); + pos = begin() + diff; + memmove(pos + (e - b), pos, (end() - pos) * sizeof(T)); + size_t len = e - b; + size_ += len; + for (size_t i = 0; i < len; i++) + { + *pos = *b; + pos++; + b++; + } + delete v; + } + + T* erase(T* pos) + { + pos->~T(); + memmove(pos, pos + 1, (end() - pos - 1) * sizeof(T)); + size_--; + return pos; + } + +protected: + T* data_; + size_t size_; + size_t capacity_; + void try_alloc(size_t new_size) + { + if (new_size * 3 / 2 > capacity_ / 2) + { + capacity_ = new_size * 2; + T* new_data = (T*)new char[capacity_ * sizeof(T)]; + memset(static_cast(new_data), 0, capacity_ * sizeof(T)); + if (data_) + { + memmove(new_data, data_, sizeof(T) * size_); + delete[](char*) data_; + } + data_ = new_data; + } + } +}; + +struct NCNN_EXPORT string : public vector +{ + string() + { + } + string(const char* str) + { + size_t len = strlen(str); + resize(len); + memcpy(data_, str, len); + } + const char* c_str() const + { + return (const char*)data_; + } + bool operator==(const string& str2) const + { + return strcmp(data_, str2.data_) == 0; + } + bool operator==(const char* str2) const + { + return strcmp(data_, str2) == 0; + } + bool operator!=(const char* str2) const + { + return strcmp(data_, str2) != 0; + } + string& operator+=(const string& str1) + { + insert(end(), str1.begin(), str1.end()); + return *this; + } +}; + +inline string operator+(const string& str1, const string& str2) +{ + string str(str1); + str.insert(str.end(), str2.begin(), str2.end()); + return str; +} + +} // namespace std + +#endif // NCNN_SIMPLESTL_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/vulkan_header_fix.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/vulkan_header_fix.h new file mode 100644 index 0000000..0a5ea9b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/include/ncnn/vulkan_header_fix.h @@ -0,0 +1,449 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_VULKAN_HEADER_FIX_H +#define NCNN_VULKAN_HEADER_FIX_H + +#include + +// This header contains new structure and function declearation to fix build with old vulkan sdk + +#if VK_HEADER_VERSION < 70 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES (VkStructureType)1000094000 +typedef enum VkSubgroupFeatureFlagBits +{ + VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001, + VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002, + VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004, + VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008, + VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010, + VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020, + VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040, + VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080, + VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 0x00000100, + VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubgroupFeatureFlagBits; +typedef VkFlags VkSubgroupFeatureFlags; +typedef struct VkPhysicalDeviceSubgroupProperties +{ + VkStructureType sType; + void* pNext; + uint32_t subgroupSize; + VkShaderStageFlags supportedStages; + VkSubgroupFeatureFlags supportedOperations; + VkBool32 quadOperationsInAllStages; +} VkPhysicalDeviceSubgroupProperties; +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES (VkStructureType)1000168000 +#define VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT (VkStructureType)1000168001 +typedef struct VkPhysicalDeviceMaintenance3Properties +{ + VkStructureType sType; + void* pNext; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceMaintenance3Properties; +typedef struct VkDescriptorSetLayoutSupport +{ + VkStructureType sType; + void* pNext; + VkBool32 supported; +} VkDescriptorSetLayoutSupport; +typedef VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; +typedef VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; +typedef void(VKAPI_PTR* PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); +#endif // VK_HEADER_VERSION < 70 + +#if VK_HEADER_VERSION < 80 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR (VkStructureType)1000177000 +typedef struct VkPhysicalDevice8BitStorageFeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; +} VkPhysicalDevice8BitStorageFeaturesKHR; +#define VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR (VkStructureType)1000109000 +#define VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR (VkStructureType)1000109001 +#define VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR (VkStructureType)1000109002 +#define VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR (VkStructureType)1000109003 +#define VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR (VkStructureType)1000109004 +#define VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR (VkStructureType)1000109005 +#define VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR (VkStructureType)1000109006 +typedef struct VkAttachmentDescription2KHR +{ + VkStructureType sType; + const void* pNext; + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription2KHR; +typedef struct VkAttachmentReference2KHR +{ + VkStructureType sType; + const void* pNext; + uint32_t attachment; + VkImageLayout layout; + VkImageAspectFlags aspectMask; +} VkAttachmentReference2KHR; +typedef struct VkSubpassDescription2KHR +{ + VkStructureType sType; + const void* pNext; + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t viewMask; + uint32_t inputAttachmentCount; + const VkAttachmentReference2KHR* pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference2KHR* pColorAttachments; + const VkAttachmentReference2KHR* pResolveAttachments; + const VkAttachmentReference2KHR* pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t* pPreserveAttachments; +} VkSubpassDescription2KHR; +typedef struct VkSubpassDependency2KHR +{ + VkStructureType sType; + const void* pNext; + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; + int32_t viewOffset; +} VkSubpassDependency2KHR; +typedef struct VkRenderPassCreateInfo2KHR +{ + VkStructureType sType; + const void* pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription2KHR* pAttachments; + uint32_t subpassCount; + const VkSubpassDescription2KHR* pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency2KHR* pDependencies; + uint32_t correlatedViewMaskCount; + const uint32_t* pCorrelatedViewMasks; +} VkRenderPassCreateInfo2KHR; +typedef struct VkSubpassBeginInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkSubpassContents contents; +} VkSubpassBeginInfoKHR; + +typedef struct VkSubpassEndInfoKHR +{ + VkStructureType sType; + const void* pNext; +} VkSubpassEndInfoKHR; +typedef VkResult(VKAPI_PTR* PFN_vkCreateRenderPass2KHR)(VkDevice device, const VkRenderPassCreateInfo2KHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void(VKAPI_PTR* PFN_vkCmdBeginRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfoKHR* pSubpassBeginInfo); +typedef void(VKAPI_PTR* PFN_vkCmdNextSubpass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfoKHR* pSubpassBeginInfo, const VkSubpassEndInfoKHR* pSubpassEndInfo); +typedef void(VKAPI_PTR* PFN_vkCmdEndRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassEndInfoKHR* pSubpassEndInfo); +#endif // VK_HEADER_VERSION < 80 + +#if VK_HEADER_VERSION < 95 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR (VkStructureType)1000082000 +typedef struct VkPhysicalDeviceFloat16Int8FeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; +} VkPhysicalDeviceFloat16Int8FeaturesKHR; +#endif // VK_HEADER_VERSION < 95 + +#if VK_HEADER_VERSION < 97 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT (VkStructureType)1000237000 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT (VkStructureType)1000238000 +#define VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT (VkStructureType)1000238001 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT (VkStructureType)1000244000 +#define VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_EXT (VkStructureType)1000244001 +#define VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT (VkStructureType)1000244002 +#define VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT (VkStructureType)1000247000 +#define VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT (VkBufferCreateFlagBits)0x00020000 +#define VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT (VkBufferUsageFlagBits)0x00020000 +typedef uint64_t VkDeviceAddress; +typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT +{ + VkStructureType sType; + void* pNext; + VkDeviceSize heapBudget[VK_MAX_MEMORY_HEAPS]; + VkDeviceSize heapUsage[VK_MAX_MEMORY_HEAPS]; +} VkPhysicalDeviceMemoryBudgetPropertiesEXT; +typedef struct VkPhysicalDeviceMemoryPriorityFeaturesEXT +{ + VkStructureType sType; + void* pNext; + VkBool32 memoryPriority; +} VkPhysicalDeviceMemoryPriorityFeaturesEXT; +typedef struct VkMemoryPriorityAllocateInfoEXT +{ + VkStructureType sType; + const void* pNext; + float priority; +} VkMemoryPriorityAllocateInfoEXT; +typedef struct VkPhysicalDeviceBufferAddressFeaturesEXT +{ + VkStructureType sType; + void* pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferAddressFeaturesEXT; +typedef struct VkBufferDeviceAddressInfoEXT +{ + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferDeviceAddressInfoEXT; +typedef struct VkBufferDeviceAddressCreateInfoEXT +{ + VkStructureType sType; + const void* pNext; + VkDeviceSize deviceAddress; +} VkBufferDeviceAddressCreateInfoEXT; +typedef VkDeviceAddress(VKAPI_PTR* PFN_vkGetBufferDeviceAddressEXT)(VkDevice device, const VkBufferDeviceAddressInfoEXT* pInfo); +typedef enum VkValidationFeatureEnableEXT +{ + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT = 0, + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT = 1, + VK_VALIDATION_FEATURE_ENABLE_BEGIN_RANGE_EXT = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT, + VK_VALIDATION_FEATURE_ENABLE_END_RANGE_EXT = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT, + VK_VALIDATION_FEATURE_ENABLE_RANGE_SIZE_EXT = (VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT - VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT + 1), + VK_VALIDATION_FEATURE_ENABLE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationFeatureEnableEXT; +typedef enum VkValidationFeatureDisableEXT +{ + VK_VALIDATION_FEATURE_DISABLE_ALL_EXT = 0, + VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT = 1, + VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT = 2, + VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT = 3, + VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT = 4, + VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT = 5, + VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT = 6, + VK_VALIDATION_FEATURE_DISABLE_BEGIN_RANGE_EXT = VK_VALIDATION_FEATURE_DISABLE_ALL_EXT, + VK_VALIDATION_FEATURE_DISABLE_END_RANGE_EXT = VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT, + VK_VALIDATION_FEATURE_DISABLE_RANGE_SIZE_EXT = (VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT - VK_VALIDATION_FEATURE_DISABLE_ALL_EXT + 1), + VK_VALIDATION_FEATURE_DISABLE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationFeatureDisableEXT; +typedef struct VkValidationFeaturesEXT +{ + VkStructureType sType; + const void* pNext; + uint32_t enabledValidationFeatureCount; + const VkValidationFeatureEnableEXT* pEnabledValidationFeatures; + uint32_t disabledValidationFeatureCount; + const VkValidationFeatureDisableEXT* pDisabledValidationFeatures; +} VkValidationFeaturesEXT; +#endif // VK_HEADER_VERSION < 97 + +#if VK_HEADER_VERSION < 101 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV (VkStructureType)1000249000 +#define VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV (VkStructureType)1000249001 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV (VkStructureType)1000249002 +typedef enum VkComponentTypeNV +{ + VK_COMPONENT_TYPE_FLOAT16_NV = 0, + VK_COMPONENT_TYPE_FLOAT32_NV = 1, + VK_COMPONENT_TYPE_FLOAT64_NV = 2, + VK_COMPONENT_TYPE_SINT8_NV = 3, + VK_COMPONENT_TYPE_SINT16_NV = 4, + VK_COMPONENT_TYPE_SINT32_NV = 5, + VK_COMPONENT_TYPE_SINT64_NV = 6, + VK_COMPONENT_TYPE_UINT8_NV = 7, + VK_COMPONENT_TYPE_UINT16_NV = 8, + VK_COMPONENT_TYPE_UINT32_NV = 9, + VK_COMPONENT_TYPE_UINT64_NV = 10, + VK_COMPONENT_TYPE_BEGIN_RANGE_NV = VK_COMPONENT_TYPE_FLOAT16_NV, + VK_COMPONENT_TYPE_END_RANGE_NV = VK_COMPONENT_TYPE_UINT64_NV, + VK_COMPONENT_TYPE_RANGE_SIZE_NV = (VK_COMPONENT_TYPE_UINT64_NV - VK_COMPONENT_TYPE_FLOAT16_NV + 1), + VK_COMPONENT_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkComponentTypeNV; +typedef enum VkScopeNV +{ + VK_SCOPE_DEVICE_NV = 1, + VK_SCOPE_WORKGROUP_NV = 2, + VK_SCOPE_SUBGROUP_NV = 3, + VK_SCOPE_QUEUE_FAMILY_NV = 5, + VK_SCOPE_BEGIN_RANGE_NV = VK_SCOPE_DEVICE_NV, + VK_SCOPE_END_RANGE_NV = VK_SCOPE_QUEUE_FAMILY_NV, + VK_SCOPE_RANGE_SIZE_NV = (VK_SCOPE_QUEUE_FAMILY_NV - VK_SCOPE_DEVICE_NV + 1), + VK_SCOPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkScopeNV; +typedef struct VkCooperativeMatrixPropertiesNV +{ + VkStructureType sType; + void* pNext; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeNV AType; + VkComponentTypeNV BType; + VkComponentTypeNV CType; + VkComponentTypeNV DType; + VkScopeNV scope; +} VkCooperativeMatrixPropertiesNV; +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesNV +{ + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesNV; +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesNV +{ + VkStructureType sType; + void* pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesNV; +typedef VkResult(VKAPI_PTR* PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixPropertiesNV* pProperties); +#endif // VK_HEADER_VERSION < 101 + +#if VK_HEADER_VERSION < 121 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD (VkStructureType)1000229000 +#define VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD (VkMemoryPropertyFlagBits)0x00000040 +#define VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD (VkMemoryPropertyFlagBits)0x00000040 +typedef struct VkPhysicalDeviceCoherentMemoryFeaturesAMD +{ + VkStructureType sType; + void* pNext; + VkBool32 deviceCoherentMemory; +} VkPhysicalDeviceCoherentMemoryFeaturesAMD; +#endif // VK_HEADER_VERSION < 121 + +#if VK_HEADER_VERSION < 129 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR (VkStructureType)1000257000 +#define VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR (VkStructureType)1000244001 +#define VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO_KHR (VkStructureType)1000257002 +#define VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO_KHR (VkStructureType)1000257003 +#define VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO_KHR (VkStructureType)1000257004 +#define VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR (VkBufferCreateFlagBits)0x00020000 +#define VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR (VkBufferUsageFlagBits)0x00020000 +#define VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR (VkMemoryAllocateFlagBits)0x00000002 +#define VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR (VkMemoryAllocateFlagBits)0x00000004 +typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferDeviceAddressFeaturesKHR; +typedef struct VkBufferDeviceAddressInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferDeviceAddressInfoKHR; +typedef struct VkBufferOpaqueCaptureAddressCreateInfoKHR +{ + VkStructureType sType; + const void* pNext; + uint64_t opaqueCaptureAddress; +} VkBufferOpaqueCaptureAddressCreateInfoKHR; +typedef struct VkMemoryOpaqueCaptureAddressAllocateInfoKHR +{ + VkStructureType sType; + const void* pNext; + uint64_t opaqueCaptureAddress; +} VkMemoryOpaqueCaptureAddressAllocateInfoKHR; +typedef struct VkDeviceMemoryOpaqueCaptureAddressInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; +} VkDeviceMemoryOpaqueCaptureAddressInfoKHR; +typedef VkDeviceAddress(VKAPI_PTR* PFN_vkGetBufferDeviceAddressKHR)(VkDevice device, const VkBufferDeviceAddressInfoKHR* pInfo); +typedef uint64_t(VKAPI_PTR* PFN_vkGetBufferOpaqueCaptureAddressKHR)(VkDevice device, const VkBufferDeviceAddressInfoKHR* pInfo); +typedef uint64_t(VKAPI_PTR* PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR)(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfoKHR* pInfo); +#endif // VK_HEADER_VERSION < 129 + +#if VK_HEADER_VERSION < 208 +typedef enum VkInstanceCreateFlagBits +{ + VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR = 0x00000001, + VK_INSTANCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkInstanceCreateFlagBits; +#endif // VK_HEADER_VERSION < 208 + +#if VK_HEADER_VERSION < 255 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR (VkStructureType)1000506000 +#define VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_KHR (VkStructureType)1000506001 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR (VkStructureType)1000506002 +typedef enum VkComponentTypeKHR +{ + VK_COMPONENT_TYPE_FLOAT16_KHR = 0, + VK_COMPONENT_TYPE_FLOAT32_KHR = 1, + VK_COMPONENT_TYPE_FLOAT64_KHR = 2, + VK_COMPONENT_TYPE_SINT8_KHR = 3, + VK_COMPONENT_TYPE_SINT16_KHR = 4, + VK_COMPONENT_TYPE_SINT32_KHR = 5, + VK_COMPONENT_TYPE_SINT64_KHR = 6, + VK_COMPONENT_TYPE_UINT8_KHR = 7, + VK_COMPONENT_TYPE_UINT16_KHR = 8, + VK_COMPONENT_TYPE_UINT32_KHR = 9, + VK_COMPONENT_TYPE_UINT64_KHR = 10, + VK_COMPONENT_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkComponentTypeKHR; +typedef enum VkScopeKHR +{ + VK_SCOPE_DEVICE_KHR = 1, + VK_SCOPE_WORKGROUP_KHR = 2, + VK_SCOPE_SUBGROUP_KHR = 3, + VK_SCOPE_QUEUE_FAMILY_KHR = 5, + VK_SCOPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkScopeKHR; +typedef struct VkCooperativeMatrixPropertiesKHR +{ + VkStructureType sType; + void* pNext; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeKHR AType; + VkComponentTypeKHR BType; + VkComponentTypeKHR CType; + VkComponentTypeKHR ResultType; + VkBool32 saturatingAccumulation; + VkScopeKHR scope; +} VkCooperativeMatrixPropertiesKHR; +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesKHR; +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesKHR +{ + VkStructureType sType; + void* pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesKHR; +typedef VkResult(VKAPI_PTR* PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixPropertiesKHR* pProperties); +#endif // VK_HEADER_VERSION < 255 + +#endif // NCNN_VULKAN_HEADER_FIX_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/lib/cmake/ncnn/ncnn-release.cmake b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/lib/cmake/ncnn/ncnn-release.cmake new file mode 100644 index 0000000..1fb8660 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/lib/cmake/ncnn/ncnn-release.cmake @@ -0,0 +1,19 @@ +#---------------------------------------------------------------- +# Generated CMake target import file for configuration "Release". +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "ncnn" for configuration "Release" +set_property(TARGET ncnn APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(ncnn PROPERTIES + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libncnn.so" + IMPORTED_SONAME_RELEASE "libncnn.so" + ) + +list(APPEND _cmake_import_check_targets ncnn ) +list(APPEND _cmake_import_check_files_for_ncnn "${_IMPORT_PREFIX}/lib/libncnn.so" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/lib/cmake/ncnn/ncnn.cmake b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/lib/cmake/ncnn/ncnn.cmake new file mode 100644 index 0000000..6726e95 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/lib/cmake/ncnn/ncnn.cmake @@ -0,0 +1,109 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8) + message(FATAL_ERROR "CMake >= 2.8.0 required") +endif() +if(CMAKE_VERSION VERSION_LESS "2.8.3") + message(FATAL_ERROR "CMake >= 2.8.3 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.8.3...3.25) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_cmake_targets_defined "") +set(_cmake_targets_not_defined "") +set(_cmake_expected_targets "") +foreach(_cmake_expected_target IN ITEMS ncnn) + list(APPEND _cmake_expected_targets "${_cmake_expected_target}") + if(TARGET "${_cmake_expected_target}") + list(APPEND _cmake_targets_defined "${_cmake_expected_target}") + else() + list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") + endif() +endforeach() +unset(_cmake_expected_target) +if(_cmake_targets_defined STREQUAL _cmake_expected_targets) + unset(_cmake_targets_defined) + unset(_cmake_targets_not_defined) + unset(_cmake_expected_targets) + unset(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT _cmake_targets_defined STREQUAL "") + string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") + string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") +endif() +unset(_cmake_targets_defined) +unset(_cmake_targets_not_defined) +unset(_cmake_expected_targets) + + +# Compute the installation prefix relative to this file. +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +if(_IMPORT_PREFIX STREQUAL "/") + set(_IMPORT_PREFIX "") +endif() + +# Create imported target ncnn +add_library(ncnn SHARED IMPORTED) + +set_target_properties(ncnn PROPERTIES + INTERFACE_COMPILE_OPTIONS "-fno-rtti;-fno-exceptions" + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include/ncnn" + INTERFACE_LINK_LIBRARIES "-fopenmp;-static-openmp;-Wl,-wrap,__kmp_affinity_determine_capable;Threads::Threads;android;jnigraphics;log" + INTERFACE_POSITION_INDEPENDENT_CODE "ON" +) + +if(CMAKE_VERSION VERSION_LESS 2.8.12) + message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.") +endif() + +# Load information for each installed configuration. +file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/ncnn-*.cmake") +foreach(_cmake_config_file IN LISTS _cmake_config_files) + include("${_cmake_config_file}") +endforeach() +unset(_cmake_config_file) +unset(_cmake_config_files) + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(_cmake_target IN LISTS _cmake_import_check_targets) + foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}") + if(NOT EXISTS "${_cmake_file}") + message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file + \"${_cmake_file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + unset(_cmake_file) + unset("_cmake_import_check_files_for_${_cmake_target}") +endforeach() +unset(_cmake_target) +unset(_cmake_import_check_targets) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/lib/cmake/ncnn/ncnnConfig.cmake b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/lib/cmake/ncnn/ncnnConfig.cmake new file mode 100644 index 0000000..d3ac286 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/lib/cmake/ncnn/ncnnConfig.cmake @@ -0,0 +1,42 @@ +set(NCNN_OPENMP ON) +set(NCNN_THREADS ON) +set(NCNN_VULKAN OFF) +set(NCNN_SHARED_LIB ON) +set(NCNN_SYSTEM_GLSLANG OFF) + +if(NCNN_OPENMP) + find_package(OpenMP) +endif() + +if(NCNN_THREADS) + set(CMAKE_THREAD_PREFER_PTHREAD TRUE) + set(THREADS_PREFER_PTHREAD_FLAG TRUE) + find_package(Threads REQUIRED) +endif() + +if(NCNN_VULKAN) + find_package(Vulkan REQUIRED) + + if(NOT NCNN_SHARED_LIB) + if(NCNN_SYSTEM_GLSLANG) + find_package(glslang QUIET) + if(NOT glslang_FOUND) + set(GLSLANG_TARGET_DIR "") + include(${GLSLANG_TARGET_DIR}/OSDependentTargets.cmake) + include(${GLSLANG_TARGET_DIR}/OGLCompilerTargets.cmake) + if(EXISTS "${GLSLANG_TARGET_DIR}/HLSLTargets.cmake") + # hlsl support can be optional + include("${GLSLANG_TARGET_DIR}/HLSLTargets.cmake") + endif() + include(${GLSLANG_TARGET_DIR}/glslangTargets.cmake) + include(${GLSLANG_TARGET_DIR}/SPIRVTargets.cmake) + endif() + else() + set(glslang_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../lib/cmake/glslang") + find_package(glslang QUIET) + endif() + + endif() +endif() + +include(${CMAKE_CURRENT_LIST_DIR}/ncnn.cmake) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/lib/pkgconfig/ncnn.pc b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/lib/pkgconfig/ncnn.pc new file mode 100644 index 0000000..4e80236 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/arm64-v8a/lib/pkgconfig/ncnn.pc @@ -0,0 +1,11 @@ +prefix=${pcfiledir}/../.. +librarydir=${prefix}/lib +includedir=${prefix}/include + +Name: ncnn +Description: high-performance neural network inference framework optimized for the mobile platform +Version: 1.0.20231027 +URL: https://github.com/Tencent/ncnn +Libs: -L"${librarydir}" -lncnn +Cflags: -I"${includedir}" + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/allocator.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/allocator.h new file mode 100644 index 0000000..3a5ebca --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/allocator.h @@ -0,0 +1,448 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_ALLOCATOR_H +#define NCNN_ALLOCATOR_H + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include "platform.h" + +#include + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +#include +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +// the alignment of all the allocated buffers +#if NCNN_AVX512 +#define NCNN_MALLOC_ALIGN 64 +#elif NCNN_AVX +#define NCNN_MALLOC_ALIGN 32 +#else +#define NCNN_MALLOC_ALIGN 16 +#endif + +// we have some optimized kernels that may overread buffer a bit in loop +// it is common to interleave next-loop data load with arithmetic instructions +// allocating more bytes keeps us safe from SEGV_ACCERR failure +#define NCNN_MALLOC_OVERREAD 64 + +// Aligns a pointer to the specified number of bytes +// ptr Aligned pointer +// n Alignment size that must be a power of two +template +static NCNN_FORCEINLINE _Tp* alignPtr(_Tp* ptr, int n = (int)sizeof(_Tp)) +{ + return (_Tp*)(((size_t)ptr + n - 1) & -n); +} + +// Aligns a buffer size to the specified number of bytes +// The function returns the minimum number that is greater or equal to sz and is divisible by n +// sz Buffer size to align +// n Alignment size that must be a power of two +static NCNN_FORCEINLINE size_t alignSize(size_t sz, int n) +{ + return (sz + n - 1) & -n; +} + +static NCNN_FORCEINLINE void* fastMalloc(size_t size) +{ +#if _MSC_VER + return _aligned_malloc(size, NCNN_MALLOC_ALIGN); +#elif (defined(__unix__) || defined(__APPLE__)) && _POSIX_C_SOURCE >= 200112L || (__ANDROID__ && __ANDROID_API__ >= 17) + void* ptr = 0; + if (posix_memalign(&ptr, NCNN_MALLOC_ALIGN, size + NCNN_MALLOC_OVERREAD)) + ptr = 0; + return ptr; +#elif __ANDROID__ && __ANDROID_API__ < 17 + return memalign(NCNN_MALLOC_ALIGN, size + NCNN_MALLOC_OVERREAD); +#else + unsigned char* udata = (unsigned char*)malloc(size + sizeof(void*) + NCNN_MALLOC_ALIGN + NCNN_MALLOC_OVERREAD); + if (!udata) + return 0; + unsigned char** adata = alignPtr((unsigned char**)udata + 1, NCNN_MALLOC_ALIGN); + adata[-1] = udata; + return adata; +#endif +} + +static NCNN_FORCEINLINE void fastFree(void* ptr) +{ + if (ptr) + { +#if _MSC_VER + _aligned_free(ptr); +#elif (defined(__unix__) || defined(__APPLE__)) && _POSIX_C_SOURCE >= 200112L || (__ANDROID__ && __ANDROID_API__ >= 17) + free(ptr); +#elif __ANDROID__ && __ANDROID_API__ < 17 + free(ptr); +#else + unsigned char* udata = ((unsigned char**)ptr)[-1]; + free(udata); +#endif + } +} + +#if NCNN_THREADS +// exchange-add operation for atomic operations on reference counters +#if defined __riscv && !defined __riscv_atomic +// riscv target without A extension +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#elif defined __INTEL_COMPILER && !(defined WIN32 || defined _WIN32) +// atomic increment on the linux version of the Intel(tm) compiler +#define NCNN_XADD(addr, delta) (int)_InterlockedExchangeAdd(const_cast(reinterpret_cast(addr)), delta) +#elif defined __GNUC__ +#if defined __clang__ && __clang_major__ >= 3 && !defined __ANDROID__ && !defined __EMSCRIPTEN__ && !defined(__CUDACC__) +#ifdef __ATOMIC_ACQ_REL +#define NCNN_XADD(addr, delta) __c11_atomic_fetch_add((_Atomic(int)*)(addr), delta, __ATOMIC_ACQ_REL) +#else +#define NCNN_XADD(addr, delta) __atomic_fetch_add((_Atomic(int)*)(addr), delta, 4) +#endif +#else +#if defined __ATOMIC_ACQ_REL && !defined __clang__ +// version for gcc >= 4.7 +#define NCNN_XADD(addr, delta) (int)__atomic_fetch_add((unsigned*)(addr), (unsigned)(delta), __ATOMIC_ACQ_REL) +#else +#define NCNN_XADD(addr, delta) (int)__sync_fetch_and_add((unsigned*)(addr), (unsigned)(delta)) +#endif +#endif +#elif defined _MSC_VER && !defined RC_INVOKED +#define NCNN_XADD(addr, delta) (int)_InterlockedExchangeAdd((long volatile*)addr, delta) +#else +// thread-unsafe branch +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#endif +#else // NCNN_THREADS +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#endif // NCNN_THREADS + +class NCNN_EXPORT Allocator +{ +public: + virtual ~Allocator(); + virtual void* fastMalloc(size_t size) = 0; + virtual void fastFree(void* ptr) = 0; +}; + +class PoolAllocatorPrivate; +class NCNN_EXPORT PoolAllocator : public Allocator +{ +public: + PoolAllocator(); + ~PoolAllocator(); + + // ratio range 0 ~ 1 + // default cr = 0 + void set_size_compare_ratio(float scr); + + // budget drop threshold + // default threshold = 10 + void set_size_drop_threshold(size_t); + + // release all budgets immediately + void clear(); + + virtual void* fastMalloc(size_t size); + virtual void fastFree(void* ptr); + +private: + PoolAllocator(const PoolAllocator&); + PoolAllocator& operator=(const PoolAllocator&); + +private: + PoolAllocatorPrivate* const d; +}; + +class UnlockedPoolAllocatorPrivate; +class NCNN_EXPORT UnlockedPoolAllocator : public Allocator +{ +public: + UnlockedPoolAllocator(); + ~UnlockedPoolAllocator(); + + // ratio range 0 ~ 1 + // default cr = 0 + void set_size_compare_ratio(float scr); + + // budget drop threshold + // default threshold = 10 + void set_size_drop_threshold(size_t); + + // release all budgets immediately + void clear(); + + virtual void* fastMalloc(size_t size); + virtual void fastFree(void* ptr); + +private: + UnlockedPoolAllocator(const UnlockedPoolAllocator&); + UnlockedPoolAllocator& operator=(const UnlockedPoolAllocator&); + +private: + UnlockedPoolAllocatorPrivate* const d; +}; + +#if NCNN_VULKAN + +class VulkanDevice; + +class NCNN_EXPORT VkBufferMemory +{ +public: + VkBuffer buffer; + + // the base offset assigned by allocator + size_t offset; + size_t capacity; + + VkDeviceMemory memory; + void* mapped_ptr; + + // buffer state, modified by command functions internally + mutable VkAccessFlags access_flags; + mutable VkPipelineStageFlags stage_flags; + + // initialize and modified by mat + int refcount; +}; + +class NCNN_EXPORT VkImageMemory +{ +public: + VkImage image; + VkImageView imageview; + + // underlying info assigned by allocator + int width; + int height; + int depth; + VkFormat format; + + VkDeviceMemory memory; + void* mapped_ptr; + + // the base offset assigned by allocator + size_t bind_offset; + size_t bind_capacity; + + // image state, modified by command functions internally + mutable VkAccessFlags access_flags; + mutable VkImageLayout image_layout; + mutable VkPipelineStageFlags stage_flags; + + // in-execution state, modified by command functions internally + mutable int command_refcount; + + // initialize and modified by mat + int refcount; +}; + +class NCNN_EXPORT VkAllocator +{ +public: + explicit VkAllocator(const VulkanDevice* _vkdev); + virtual ~VkAllocator(); + + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size) = 0; + virtual void fastFree(VkBufferMemory* ptr) = 0; + virtual int flush(VkBufferMemory* ptr); + virtual int invalidate(VkBufferMemory* ptr); + + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack) = 0; + virtual void fastFree(VkImageMemory* ptr) = 0; + +public: + const VulkanDevice* vkdev; + uint32_t buffer_memory_type_index; + uint32_t image_memory_type_index; + uint32_t reserved_type_index; + bool mappable; + bool coherent; + +protected: + VkBuffer create_buffer(size_t size, VkBufferUsageFlags usage); + VkDeviceMemory allocate_memory(size_t size, uint32_t memory_type_index); + VkDeviceMemory allocate_dedicated_memory(size_t size, uint32_t memory_type_index, VkImage image, VkBuffer buffer); + + VkImage create_image(int width, int height, int depth, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage); + VkImageView create_imageview(VkImage image, VkFormat format); +}; + +class VkBlobAllocatorPrivate; +class NCNN_EXPORT VkBlobAllocator : public VkAllocator +{ +public: + explicit VkBlobAllocator(const VulkanDevice* vkdev, size_t preferred_block_size = 16 * 1024 * 1024); // 16M + virtual ~VkBlobAllocator(); + +public: + // release all budgets immediately + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkBlobAllocator(const VkBlobAllocator&); + VkBlobAllocator& operator=(const VkBlobAllocator&); + +private: + VkBlobAllocatorPrivate* const d; +}; + +class VkWeightAllocatorPrivate; +class NCNN_EXPORT VkWeightAllocator : public VkAllocator +{ +public: + explicit VkWeightAllocator(const VulkanDevice* vkdev, size_t preferred_block_size = 8 * 1024 * 1024); // 8M + virtual ~VkWeightAllocator(); + +public: + // release all blocks immediately + virtual void clear(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkWeightAllocator(const VkWeightAllocator&); + VkWeightAllocator& operator=(const VkWeightAllocator&); + +private: + VkWeightAllocatorPrivate* const d; +}; + +class VkStagingAllocatorPrivate; +class NCNN_EXPORT VkStagingAllocator : public VkAllocator +{ +public: + explicit VkStagingAllocator(const VulkanDevice* vkdev); + virtual ~VkStagingAllocator(); + +public: + // ratio range 0 ~ 1 + // default cr = 0.75 + void set_size_compare_ratio(float scr); + + // release all budgets immediately + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkStagingAllocator(const VkStagingAllocator&); + VkStagingAllocator& operator=(const VkStagingAllocator&); + +private: + VkStagingAllocatorPrivate* const d; +}; + +class VkWeightStagingAllocatorPrivate; +class NCNN_EXPORT VkWeightStagingAllocator : public VkAllocator +{ +public: + explicit VkWeightStagingAllocator(const VulkanDevice* vkdev); + virtual ~VkWeightStagingAllocator(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkWeightStagingAllocator(const VkWeightStagingAllocator&); + VkWeightStagingAllocator& operator=(const VkWeightStagingAllocator&); + +private: + VkWeightStagingAllocatorPrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class NCNN_EXPORT VkAndroidHardwareBufferImageAllocator : public VkAllocator +{ +public: + VkAndroidHardwareBufferImageAllocator(const VulkanDevice* _vkdev, AHardwareBuffer* _hb); + virtual ~VkAndroidHardwareBufferImageAllocator(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkAndroidHardwareBufferImageAllocator(const VkAndroidHardwareBufferImageAllocator&); + VkAndroidHardwareBufferImageAllocator& operator=(const VkAndroidHardwareBufferImageAllocator&); + +public: + int init(); + + int width() const; + int height() const; + uint64_t external_format() const; + +public: + AHardwareBuffer* hb; + AHardwareBuffer_Desc bufferDesc; + VkAndroidHardwareBufferFormatPropertiesANDROID bufferFormatProperties; + VkAndroidHardwareBufferPropertiesANDROID bufferProperties; + VkSamplerYcbcrConversionKHR samplerYcbcrConversion; +}; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_ALLOCATOR_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/benchmark.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/benchmark.h new file mode 100644 index 0000000..ed42c1a --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/benchmark.h @@ -0,0 +1,39 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_BENCHMARK_H +#define NCNN_BENCHMARK_H + +#include "layer.h" +#include "mat.h" +#include "platform.h" + +namespace ncnn { + +// get now timestamp in ms +NCNN_EXPORT double get_current_time(); + +// sleep milliseconds +NCNN_EXPORT void sleep(unsigned long long int milliseconds = 1000); + +#if NCNN_BENCHMARK + +NCNN_EXPORT void benchmark(const Layer* layer, double start, double end); +NCNN_EXPORT void benchmark(const Layer* layer, const Mat& bottom_blob, Mat& top_blob, double start, double end); + +#endif // NCNN_BENCHMARK + +} // namespace ncnn + +#endif // NCNN_BENCHMARK_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/blob.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/blob.h new file mode 100644 index 0000000..c9f144f --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/blob.h @@ -0,0 +1,44 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_BLOB_H +#define NCNN_BLOB_H + +#include "mat.h" +#include "platform.h" + +namespace ncnn { + +class NCNN_EXPORT Blob +{ +public: + // empty + Blob(); + +public: +#if NCNN_STRING + // blob name + std::string name; +#endif // NCNN_STRING + // layer index which produce this blob as output + int producer; + // layer index which need this blob as input + int consumer; + // shape hint + Mat shape; +}; + +} // namespace ncnn + +#endif // NCNN_BLOB_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/c_api.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/c_api.h new file mode 100644 index 0000000..31d5b6d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/c_api.h @@ -0,0 +1,347 @@ +/* Tencent is pleased to support the open source community by making ncnn available. + * + * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef NCNN_C_API_H +#define NCNN_C_API_H + +#include "platform.h" + +#if NCNN_C_API + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +NCNN_EXPORT const char* ncnn_version(); + +/* allocator api */ +typedef struct __ncnn_allocator_t* ncnn_allocator_t; +struct NCNN_EXPORT __ncnn_allocator_t +{ + void* pthis; + + void* (*fast_malloc)(ncnn_allocator_t allocator, size_t size); + void (*fast_free)(ncnn_allocator_t allocator, void* ptr); +}; + +NCNN_EXPORT ncnn_allocator_t ncnn_allocator_create_pool_allocator(); +NCNN_EXPORT ncnn_allocator_t ncnn_allocator_create_unlocked_pool_allocator(); +NCNN_EXPORT void ncnn_allocator_destroy(ncnn_allocator_t allocator); + +/* option api */ +typedef struct __ncnn_option_t* ncnn_option_t; + +NCNN_EXPORT ncnn_option_t ncnn_option_create(); +NCNN_EXPORT void ncnn_option_destroy(ncnn_option_t opt); + +NCNN_EXPORT int ncnn_option_get_num_threads(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_num_threads(ncnn_option_t opt, int num_threads); + +NCNN_EXPORT int ncnn_option_get_use_local_pool_allocator(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_use_local_pool_allocator(ncnn_option_t opt, int use_local_pool_allocator); + +NCNN_EXPORT void ncnn_option_set_blob_allocator(ncnn_option_t opt, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_option_set_workspace_allocator(ncnn_option_t opt, ncnn_allocator_t allocator); + +NCNN_EXPORT int ncnn_option_get_use_vulkan_compute(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_use_vulkan_compute(ncnn_option_t opt, int use_vulkan_compute); + +/* mat api */ +typedef struct __ncnn_mat_t* ncnn_mat_t; + +NCNN_EXPORT ncnn_mat_t ncnn_mat_create(); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_1d(int w, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_2d(int w, int h, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_3d(int w, int h, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_4d(int w, int h, int d, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_1d(int w, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_2d(int w, int h, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_3d(int w, int h, int c, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_4d(int w, int h, int d, int c, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_1d_elem(int w, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_2d_elem(int w, int h, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_3d_elem(int w, int h, int c, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_4d_elem(int w, int h, int d, int c, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_1d_elem(int w, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_2d_elem(int w, int h, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_3d_elem(int w, int h, int c, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_4d_elem(int w, int h, int d, int c, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_mat_destroy(ncnn_mat_t mat); + +NCNN_EXPORT void ncnn_mat_fill_float(ncnn_mat_t mat, float v); + +NCNN_EXPORT ncnn_mat_t ncnn_mat_clone(const ncnn_mat_t mat, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_1d(const ncnn_mat_t mat, int w, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_2d(const ncnn_mat_t mat, int w, int h, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_3d(const ncnn_mat_t mat, int w, int h, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_4d(const ncnn_mat_t mat, int w, int h, int d, int c, ncnn_allocator_t allocator); + +NCNN_EXPORT int ncnn_mat_get_dims(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_w(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_h(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_d(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_c(const ncnn_mat_t mat); +NCNN_EXPORT size_t ncnn_mat_get_elemsize(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_elempack(const ncnn_mat_t mat); +NCNN_EXPORT size_t ncnn_mat_get_cstep(const ncnn_mat_t mat); +NCNN_EXPORT void* ncnn_mat_get_data(const ncnn_mat_t mat); + +NCNN_EXPORT void* ncnn_mat_get_channel_data(const ncnn_mat_t mat, int c); + +#if NCNN_PIXEL + +/* mat pixel api */ +#define NCNN_MAT_PIXEL_RGB 1 +#define NCNN_MAT_PIXEL_BGR 2 +#define NCNN_MAT_PIXEL_GRAY 3 +#define NCNN_MAT_PIXEL_RGBA 4 +#define NCNN_MAT_PIXEL_BGRA 5 +#define NCNN_MAT_PIXEL_X2Y(X, Y) (X | (Y << 16)) +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels(const unsigned char* pixels, int type, int w, int h, int stride, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, int target_width, int target_height, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_mat_to_pixels(const ncnn_mat_t mat, unsigned char* pixels, int type, int stride); +NCNN_EXPORT void ncnn_mat_to_pixels_resize(const ncnn_mat_t mat, unsigned char* pixels, int type, int target_width, int target_height, int target_stride); + +#endif /* NCNN_PIXEL */ + +NCNN_EXPORT void ncnn_mat_substract_mean_normalize(ncnn_mat_t mat, const float* mean_vals, const float* norm_vals); + +NCNN_EXPORT void ncnn_convert_packing(const ncnn_mat_t src, ncnn_mat_t* dst, int elempack, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_flatten(const ncnn_mat_t src, ncnn_mat_t* dst, const ncnn_option_t opt); + +/* blob api */ +typedef struct __ncnn_blob_t* ncnn_blob_t; + +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_blob_get_name(const ncnn_blob_t blob); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_blob_get_producer(const ncnn_blob_t blob); +NCNN_EXPORT int ncnn_blob_get_consumer(const ncnn_blob_t blob); + +NCNN_EXPORT void ncnn_blob_get_shape(const ncnn_blob_t blob, int* dims, int* w, int* h, int* c); + +/* paramdict api */ +typedef struct __ncnn_paramdict_t* ncnn_paramdict_t; + +NCNN_EXPORT ncnn_paramdict_t ncnn_paramdict_create(); +NCNN_EXPORT void ncnn_paramdict_destroy(ncnn_paramdict_t pd); + +NCNN_EXPORT int ncnn_paramdict_get_type(const ncnn_paramdict_t pd, int id); + +NCNN_EXPORT int ncnn_paramdict_get_int(const ncnn_paramdict_t pd, int id, int def); +NCNN_EXPORT float ncnn_paramdict_get_float(const ncnn_paramdict_t pd, int id, float def); +NCNN_EXPORT ncnn_mat_t ncnn_paramdict_get_array(const ncnn_paramdict_t pd, int id, const ncnn_mat_t def); + +NCNN_EXPORT void ncnn_paramdict_set_int(ncnn_paramdict_t pd, int id, int i); +NCNN_EXPORT void ncnn_paramdict_set_float(ncnn_paramdict_t pd, int id, float f); +NCNN_EXPORT void ncnn_paramdict_set_array(ncnn_paramdict_t pd, int id, const ncnn_mat_t v); + +/* datareader api */ +typedef struct __ncnn_datareader_t* ncnn_datareader_t; +struct NCNN_EXPORT __ncnn_datareader_t +{ + void* pthis; + +#if NCNN_STRING + int (*scan)(ncnn_datareader_t dr, const char* format, void* p); +#endif /* NCNN_STRING */ + size_t (*read)(ncnn_datareader_t dr, void* buf, size_t size); +}; + +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create(); +#if NCNN_STDIO +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create_from_stdio(FILE* fp); +#endif /* NCNN_STDIO */ +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create_from_memory(const unsigned char** mem); +NCNN_EXPORT void ncnn_datareader_destroy(ncnn_datareader_t dr); + +/* modelbin api */ +typedef struct __ncnn_modelbin_t* ncnn_modelbin_t; +struct NCNN_EXPORT __ncnn_modelbin_t +{ + void* pthis; + + ncnn_mat_t (*load_1d)(const ncnn_modelbin_t mb, int w, int type); + ncnn_mat_t (*load_2d)(const ncnn_modelbin_t mb, int w, int h, int type); + ncnn_mat_t (*load_3d)(const ncnn_modelbin_t mb, int w, int h, int c, int type); +}; + +NCNN_EXPORT ncnn_modelbin_t ncnn_modelbin_create_from_datareader(const ncnn_datareader_t dr); +NCNN_EXPORT ncnn_modelbin_t ncnn_modelbin_create_from_mat_array(const ncnn_mat_t* weights, int n); +NCNN_EXPORT void ncnn_modelbin_destroy(ncnn_modelbin_t mb); + +/* layer api */ +typedef struct __ncnn_layer_t* ncnn_layer_t; +struct NCNN_EXPORT __ncnn_layer_t +{ + void* pthis; + + int (*load_param)(ncnn_layer_t layer, const ncnn_paramdict_t pd); + int (*load_model)(ncnn_layer_t layer, const ncnn_modelbin_t mb); + + int (*create_pipeline)(ncnn_layer_t layer, const ncnn_option_t opt); + int (*destroy_pipeline)(ncnn_layer_t layer, const ncnn_option_t opt); + + int (*forward_1)(const ncnn_layer_t layer, const ncnn_mat_t bottom_blob, ncnn_mat_t* top_blob, const ncnn_option_t opt); + int (*forward_n)(const ncnn_layer_t layer, const ncnn_mat_t* bottom_blobs, int n, ncnn_mat_t* top_blobs, int n2, const ncnn_option_t opt); + + int (*forward_inplace_1)(const ncnn_layer_t layer, ncnn_mat_t bottom_top_blob, const ncnn_option_t opt); + int (*forward_inplace_n)(const ncnn_layer_t layer, ncnn_mat_t* bottom_top_blobs, int n, const ncnn_option_t opt); +}; + +NCNN_EXPORT ncnn_layer_t ncnn_layer_create(); +NCNN_EXPORT ncnn_layer_t ncnn_layer_create_by_typeindex(int typeindex); +#if NCNN_STRING +NCNN_EXPORT ncnn_layer_t ncnn_layer_create_by_type(const char* type); +NCNN_EXPORT int ncnn_layer_type_to_index(const char* type); +#endif /* NCNN_STRING */ +NCNN_EXPORT void ncnn_layer_destroy(ncnn_layer_t layer); + +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_layer_get_name(const ncnn_layer_t layer); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_layer_get_typeindex(const ncnn_layer_t layer); +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_layer_get_type(const ncnn_layer_t layer); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_layer_get_one_blob_only(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_inplace(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_vulkan(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_packing(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_bf16_storage(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_fp16_storage(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_image_storage(const ncnn_layer_t layer); + +NCNN_EXPORT void ncnn_layer_set_one_blob_only(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_inplace(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_vulkan(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_packing(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_bf16_storage(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_fp16_storage(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_image_storage(ncnn_layer_t layer, int enable); + +NCNN_EXPORT int ncnn_layer_get_bottom_count(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_bottom(const ncnn_layer_t layer, int i); +NCNN_EXPORT int ncnn_layer_get_top_count(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_top(const ncnn_layer_t layer, int i); + +NCNN_EXPORT void ncnn_blob_get_bottom_shape(const ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c); +NCNN_EXPORT void ncnn_blob_get_top_shape(const ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c); + +/* layer factory function */ +typedef ncnn_layer_t (*ncnn_layer_creator_t)(void* userdata); +typedef void (*ncnn_layer_destroyer_t)(ncnn_layer_t layer, void* userdata); + +typedef struct __ncnn_net_custom_layer_factory_t* ncnn_net_custom_layer_factory_t; +struct __ncnn_net_custom_layer_factory_t +{ + ncnn_layer_creator_t creator; + ncnn_layer_destroyer_t destroyer; + void* userdata; + ncnn_net_custom_layer_factory_t next; +}; + +/* net api */ +typedef struct __ncnn_net_t* ncnn_net_t; +struct __ncnn_net_t +{ + void* pthis; + + ncnn_net_custom_layer_factory_t custom_layer_factory; +}; + +NCNN_EXPORT ncnn_net_t ncnn_net_create(); +NCNN_EXPORT void ncnn_net_destroy(ncnn_net_t net); + +NCNN_EXPORT ncnn_option_t ncnn_net_get_option(ncnn_net_t net); +NCNN_EXPORT void ncnn_net_set_option(ncnn_net_t net, ncnn_option_t opt); + +#if NCNN_STRING +NCNN_EXPORT void ncnn_net_register_custom_layer_by_type(ncnn_net_t net, const char* type, ncnn_layer_creator_t creator, ncnn_layer_destroyer_t destroyer, void* userdata); +#endif /* NCNN_STRING */ +NCNN_EXPORT void ncnn_net_register_custom_layer_by_typeindex(ncnn_net_t net, int typeindex, ncnn_layer_creator_t creator, ncnn_layer_destroyer_t destroyer, void* userdata); + +#if NCNN_STDIO +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param(ncnn_net_t net, const char* path); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_load_param_bin(ncnn_net_t net, const char* path); +NCNN_EXPORT int ncnn_net_load_model(ncnn_net_t net, const char* path); +#endif /* NCNN_STDIO */ + +#if NCNN_STDIO +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param_memory(ncnn_net_t net, const char* mem); +#endif /* NCNN_STRING */ +#endif /* NCNN_STDIO */ +NCNN_EXPORT int ncnn_net_load_param_bin_memory(ncnn_net_t net, const unsigned char* mem); +NCNN_EXPORT int ncnn_net_load_model_memory(ncnn_net_t net, const unsigned char* mem); + +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param_datareader(ncnn_net_t net, const ncnn_datareader_t dr); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_load_param_bin_datareader(ncnn_net_t net, const ncnn_datareader_t dr); +NCNN_EXPORT int ncnn_net_load_model_datareader(ncnn_net_t net, const ncnn_datareader_t dr); + +NCNN_EXPORT void ncnn_net_clear(ncnn_net_t net); + +NCNN_EXPORT int ncnn_net_get_input_count(const ncnn_net_t net); +NCNN_EXPORT int ncnn_net_get_output_count(const ncnn_net_t net); +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_net_get_input_name(const ncnn_net_t net, int i); +NCNN_EXPORT const char* ncnn_net_get_output_name(const ncnn_net_t net, int i); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_get_input_index(const ncnn_net_t net, int i); +NCNN_EXPORT int ncnn_net_get_output_index(const ncnn_net_t net, int i); + +/* extractor api */ +typedef struct __ncnn_extractor_t* ncnn_extractor_t; + +NCNN_EXPORT ncnn_extractor_t ncnn_extractor_create(ncnn_net_t net); +NCNN_EXPORT void ncnn_extractor_destroy(ncnn_extractor_t ex); + +NCNN_EXPORT void ncnn_extractor_set_option(ncnn_extractor_t ex, const ncnn_option_t opt); + +#if NCNN_STRING +NCNN_EXPORT int ncnn_extractor_input(ncnn_extractor_t ex, const char* name, const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_extractor_extract(ncnn_extractor_t ex, const char* name, ncnn_mat_t* mat); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_extractor_input_index(ncnn_extractor_t ex, int index, const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_extractor_extract_index(ncnn_extractor_t ex, int index, ncnn_mat_t* mat); + +/* mat process api */ +#define NCNN_BORDER_CONSTANT 0 +#define NCNN_BORDER_REPLICATE 1 +#define NCNN_BORDER_REFLECT 2 +#define NCNN_BORDER_TRANSPARENT -233 +NCNN_EXPORT void ncnn_copy_make_border(const ncnn_mat_t src, ncnn_mat_t dst, int top, int bottom, int left, int right, int type, float v, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_copy_make_border_3d(const ncnn_mat_t src, ncnn_mat_t dst, int top, int bottom, int left, int right, int front, int behind, int type, float v, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_copy_cut_border(const ncnn_mat_t src, ncnn_mat_t dst, int top, int bottom, int left, int right, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_copy_cut_border_3d(const ncnn_mat_t src, ncnn_mat_t dst, int top, int bottom, int left, int right, int front, int behind, const ncnn_option_t opt); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* NCNN_C_API */ + +#endif /* NCNN_C_API_H */ diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/command.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/command.h new file mode 100644 index 0000000..337d085 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/command.h @@ -0,0 +1,136 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_COMMAND_H +#define NCNN_COMMAND_H + +#include "platform.h" + +#if NCNN_VULKAN + +#include "mat.h" + +#include + +namespace ncnn { + +class Pipeline; +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class ImportAndroidHardwareBufferPipeline; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API +class VkComputePrivate; +class NCNN_EXPORT VkCompute +{ +public: + explicit VkCompute(const VulkanDevice* vkdev); + virtual ~VkCompute(); + +public: + void record_upload(const Mat& src, VkMat& dst, const Option& opt); + + void record_upload(const Mat& src, VkImageMat& dst, const Option& opt); + + void record_download(const VkMat& src, Mat& dst, const Option& opt); + + void record_download(const VkImageMat& src, Mat& dst, const Option& opt); + + void record_buffer_to_image(const VkMat& src, VkImageMat& dst, const Option& opt); + + void record_image_to_buffer(const VkImageMat& src, VkMat& dst, const Option& opt); + + void record_clone(const Mat& src, VkMat& dst, const Option& opt); + + void record_clone(const Mat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkMat& src, Mat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, Mat& dst, const Option& opt); + + void record_clone(const VkMat& src, VkMat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkMat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, VkMat& dst, const Option& opt); + + void record_pipeline(const Pipeline* pipeline, const std::vector& bindings, const std::vector& constants, const VkMat& dispatcher); + + void record_pipeline(const Pipeline* pipeline, const std::vector& bindings, const std::vector& constants, const VkImageMat& dispatcher); + + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const VkMat& dispatcher); + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const VkImageMat& dispatcher); + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const Mat& dispatcher); + +#if NCNN_BENCHMARK + void record_write_timestamp(uint32_t query); +#endif // NCNN_BENCHMARK + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 + void record_import_android_hardware_buffer(const ImportAndroidHardwareBufferPipeline* pipeline, const VkImageMat& src, const VkMat& dst); + + void record_import_android_hardware_buffer(const ImportAndroidHardwareBufferPipeline* pipeline, const VkImageMat& src, const VkImageMat& dst); +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + + int submit_and_wait(); + + int reset(); + +#if NCNN_BENCHMARK + int create_query_pool(uint32_t query_count); + + int get_query_pool_results(uint32_t first_query, uint32_t query_count, std::vector& results); +#endif // NCNN_BENCHMARK + +protected: + const VulkanDevice* vkdev; + + void barrier_readwrite(const VkMat& binding); + void barrier_readwrite(const VkImageMat& binding); + void barrier_readonly(const VkImageMat& binding); + +private: + VkComputePrivate* const d; +}; + +class VkTransferPrivate; +class NCNN_EXPORT VkTransfer +{ +public: + explicit VkTransfer(const VulkanDevice* vkdev); + virtual ~VkTransfer(); + +public: + void record_upload(const Mat& src, VkMat& dst, const Option& opt, bool flatten = true); + + void record_upload(const Mat& src, VkImageMat& dst, const Option& opt); + + int submit_and_wait(); + +protected: + const VulkanDevice* vkdev; + +private: + VkTransferPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_VULKAN + +#endif // NCNN_COMMAND_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/cpu.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/cpu.h new file mode 100644 index 0000000..7d6bfce --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/cpu.h @@ -0,0 +1,178 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_CPU_H +#define NCNN_CPU_H + +#include + +#if (defined _WIN32 && !(defined __MINGW32__)) +#define WIN32_LEAN_AND_MEAN +#include +#endif +#if defined __ANDROID__ || defined __linux__ +#include // cpu_set_t +#endif + +#include "platform.h" + +namespace ncnn { + +class NCNN_EXPORT CpuSet +{ +public: + CpuSet(); + void enable(int cpu); + void disable(int cpu); + void disable_all(); + bool is_enabled(int cpu) const; + int num_enabled() const; + +public: +#if (defined _WIN32 && !(defined __MINGW32__)) + ULONG_PTR mask; +#endif +#if defined __ANDROID__ || defined __linux__ + cpu_set_t cpu_set; +#endif +#if __APPLE__ + unsigned int policy; +#endif +}; + +// test optional cpu features +// edsp = armv7 edsp +NCNN_EXPORT int cpu_support_arm_edsp(); +// neon = armv7 neon or aarch64 asimd +NCNN_EXPORT int cpu_support_arm_neon(); +// vfpv4 = armv7 fp16 + fma +NCNN_EXPORT int cpu_support_arm_vfpv4(); +// asimdhp = aarch64 asimd half precision +NCNN_EXPORT int cpu_support_arm_asimdhp(); +// cpuid = aarch64 cpuid info +NCNN_EXPORT int cpu_support_arm_cpuid(); +// asimddp = aarch64 asimd dot product +NCNN_EXPORT int cpu_support_arm_asimddp(); +// asimdfhm = aarch64 asimd fhm +NCNN_EXPORT int cpu_support_arm_asimdfhm(); +// bf16 = aarch64 bf16 +NCNN_EXPORT int cpu_support_arm_bf16(); +// i8mm = aarch64 i8mm +NCNN_EXPORT int cpu_support_arm_i8mm(); +// sve = aarch64 sve +NCNN_EXPORT int cpu_support_arm_sve(); +// sve2 = aarch64 sve2 +NCNN_EXPORT int cpu_support_arm_sve2(); +// svebf16 = aarch64 svebf16 +NCNN_EXPORT int cpu_support_arm_svebf16(); +// svei8mm = aarch64 svei8mm +NCNN_EXPORT int cpu_support_arm_svei8mm(); +// svef32mm = aarch64 svef32mm +NCNN_EXPORT int cpu_support_arm_svef32mm(); + +// avx = x86 avx +NCNN_EXPORT int cpu_support_x86_avx(); +// fma = x86 fma +NCNN_EXPORT int cpu_support_x86_fma(); +// xop = x86 xop +NCNN_EXPORT int cpu_support_x86_xop(); +// f16c = x86 f16c +NCNN_EXPORT int cpu_support_x86_f16c(); +// avx2 = x86 avx2 + fma + f16c +NCNN_EXPORT int cpu_support_x86_avx2(); +// avx_vnni = x86 avx vnni +NCNN_EXPORT int cpu_support_x86_avx_vnni(); +// avx512 = x86 avx512f + avx512cd + avx512bw + avx512dq + avx512vl +NCNN_EXPORT int cpu_support_x86_avx512(); +// avx512_vnni = x86 avx512 vnni +NCNN_EXPORT int cpu_support_x86_avx512_vnni(); +// avx512_bf16 = x86 avx512 bf16 +NCNN_EXPORT int cpu_support_x86_avx512_bf16(); +// avx512_fp16 = x86 avx512 fp16 +NCNN_EXPORT int cpu_support_x86_avx512_fp16(); + +// lsx = loongarch lsx +NCNN_EXPORT int cpu_support_loongarch_lsx(); +// lasx = loongarch lasx +NCNN_EXPORT int cpu_support_loongarch_lasx(); + +// msa = mips mas +NCNN_EXPORT int cpu_support_mips_msa(); +// mmi = loongson mmi +NCNN_EXPORT int cpu_support_loongson_mmi(); + +// v = riscv vector +NCNN_EXPORT int cpu_support_riscv_v(); +// zfh = riscv half-precision float +NCNN_EXPORT int cpu_support_riscv_zfh(); +// vlenb = riscv vector length in bytes +NCNN_EXPORT int cpu_riscv_vlenb(); + +// cpu info +NCNN_EXPORT int get_cpu_count(); +NCNN_EXPORT int get_little_cpu_count(); +NCNN_EXPORT int get_big_cpu_count(); + +NCNN_EXPORT int get_physical_cpu_count(); +NCNN_EXPORT int get_physical_little_cpu_count(); +NCNN_EXPORT int get_physical_big_cpu_count(); + +// cpu l2 varies from 64k to 1M, but l3 can be zero +NCNN_EXPORT int get_cpu_level2_cache_size(); +NCNN_EXPORT int get_cpu_level3_cache_size(); + +// bind all threads on little clusters if powersave enabled +// affects HMP arch cpu like ARM big.LITTLE +// only implemented on android at the moment +// switching powersave is expensive and not thread-safe +// 0 = all cores enabled(default) +// 1 = only little clusters enabled +// 2 = only big clusters enabled +// return 0 if success for setter function +NCNN_EXPORT int get_cpu_powersave(); +NCNN_EXPORT int set_cpu_powersave(int powersave); + +// convenient wrapper +NCNN_EXPORT const CpuSet& get_cpu_thread_affinity_mask(int powersave); + +// set explicit thread affinity +NCNN_EXPORT int set_cpu_thread_affinity(const CpuSet& thread_affinity_mask); + +// runtime thread affinity info +NCNN_EXPORT int is_current_thread_running_on_a53_a55(); + +// misc function wrapper for openmp routines +NCNN_EXPORT int get_omp_num_threads(); +NCNN_EXPORT void set_omp_num_threads(int num_threads); + +NCNN_EXPORT int get_omp_dynamic(); +NCNN_EXPORT void set_omp_dynamic(int dynamic); + +NCNN_EXPORT int get_omp_thread_num(); + +NCNN_EXPORT int get_kmp_blocktime(); +NCNN_EXPORT void set_kmp_blocktime(int time_ms); + +// need to flush denormals on Intel Chipset. +// Other architectures such as ARM can be added as needed. +// 0 = DAZ OFF, FTZ OFF +// 1 = DAZ ON , FTZ OFF +// 2 = DAZ OFF, FTZ ON +// 3 = DAZ ON, FTZ ON +NCNN_EXPORT int get_flush_denormals(); +NCNN_EXPORT int set_flush_denormals(int flush_denormals); + +} // namespace ncnn + +#endif // NCNN_CPU_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/datareader.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/datareader.h new file mode 100644 index 0000000..ed2aba3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/datareader.h @@ -0,0 +1,122 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_DATAREADER_H +#define NCNN_DATAREADER_H + +#include "platform.h" +#if NCNN_STDIO +#include +#endif + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#endif +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +// data read wrapper +class NCNN_EXPORT DataReader +{ +public: + DataReader(); + virtual ~DataReader(); + +#if NCNN_STRING + // parse plain param text + // return 1 if scan success + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + + // read binary param and model data + // return bytes read + virtual size_t read(void* buf, size_t size) const; + + // get model data reference + // return bytes referenced + virtual size_t reference(size_t size, const void** buf) const; +}; + +#if NCNN_STDIO +class DataReaderFromStdioPrivate; +class NCNN_EXPORT DataReaderFromStdio : public DataReader +{ +public: + explicit DataReaderFromStdio(FILE* fp); + virtual ~DataReaderFromStdio(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + +private: + DataReaderFromStdio(const DataReaderFromStdio&); + DataReaderFromStdio& operator=(const DataReaderFromStdio&); + +private: + DataReaderFromStdioPrivate* const d; +}; +#endif // NCNN_STDIO + +class DataReaderFromMemoryPrivate; +class NCNN_EXPORT DataReaderFromMemory : public DataReader +{ +public: + explicit DataReaderFromMemory(const unsigned char*& mem); + virtual ~DataReaderFromMemory(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + virtual size_t reference(size_t size, const void** buf) const; + +private: + DataReaderFromMemory(const DataReaderFromMemory&); + DataReaderFromMemory& operator=(const DataReaderFromMemory&); + +private: + DataReaderFromMemoryPrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +class DataReaderFromAndroidAssetPrivate; +class NCNN_EXPORT DataReaderFromAndroidAsset : public DataReader +{ +public: + explicit DataReaderFromAndroidAsset(AAsset* asset); + virtual ~DataReaderFromAndroidAsset(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + +private: + DataReaderFromAndroidAsset(const DataReaderFromAndroidAsset&); + DataReaderFromAndroidAsset& operator=(const DataReaderFromAndroidAsset&); + +private: + DataReaderFromAndroidAssetPrivate* const d; +}; +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + +} // namespace ncnn + +#endif // NCNN_DATAREADER_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/gpu.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/gpu.h new file mode 100644 index 0000000..1eff228 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/gpu.h @@ -0,0 +1,392 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_GPU_H +#define NCNN_GPU_H + +#include "platform.h" + +#if NCNN_VULKAN + +#include "mat.h" + +#include + +#include "vulkan_header_fix.h" + +namespace ncnn { + +// instance + +// Create VkInstance and initialize some objects that need to be calculated by GPU +// Creates a VkInstance object, Checks the extended attributes supported by the Vulkan instance concerned, +// Initializes, and creates Vulkan validation layers (if ENABLE_VALIDATION_LAYER is enabled), +// Iterates over all supported physical devices, etc. +NCNN_EXPORT int create_gpu_instance(); + +// Get global VkInstance variable +// Must be called after create_gpu_instance() and before destroy_gpu_instance() +NCNN_EXPORT VkInstance get_gpu_instance(); + +// Destroy VkInstance object and free the memory of the associated object +// Usually called in the destructor of the main program exit +NCNN_EXPORT void destroy_gpu_instance(); + +// instance extension capability +extern int support_VK_KHR_external_memory_capabilities; +extern int support_VK_KHR_get_physical_device_properties2; +extern int support_VK_KHR_get_surface_capabilities2; +extern int support_VK_KHR_surface; +extern int support_VK_EXT_debug_utils; +extern int support_VK_EXT_validation_features; +extern int support_VK_EXT_validation_flags; +#if __ANDROID_API__ >= 26 +extern int support_VK_KHR_android_surface; +#endif // __ANDROID_API__ >= 26 + +// VK_KHR_cooperative_matrix +extern PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR; + +// VK_KHR_external_memory_capabilities +extern PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR vkGetPhysicalDeviceExternalBufferPropertiesKHR; + +// VK_KHR_get_physical_device_properties2 +extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; +extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; +extern PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceImageFormatProperties2KHR vkGetPhysicalDeviceImageFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR; +extern PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR; +extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR vkGetPhysicalDeviceSparseImageFormatProperties2KHR; + +// VK_KHR_get_surface_capabilities2 +extern PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR; + +// VK_KHR_surface +extern PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; +extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; +extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; +extern PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; + +#if __ANDROID_API__ >= 26 +// VK_KHR_android_surface +extern PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; +#endif // __ANDROID_API__ >= 26 + +// VK_NV_cooperative_matrix +extern PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV vkGetPhysicalDeviceCooperativeMatrixPropertiesNV; + +// get info +NCNN_EXPORT int get_gpu_count(); +NCNN_EXPORT int get_default_gpu_index(); + +class GpuInfoPrivate; +class NCNN_EXPORT GpuInfo +{ +public: + explicit GpuInfo(); + virtual ~GpuInfo(); + + // vulkan physical device + VkPhysicalDevice physical_device() const; + + // memory properties + const VkPhysicalDeviceMemoryProperties& physical_device_memory_properties() const; + + // info + uint32_t api_version() const; + uint32_t driver_version() const; + uint32_t vendor_id() const; + uint32_t device_id() const; + const char* device_name() const; + uint8_t* pipeline_cache_uuid() const; + + // 0 = discrete gpu + // 1 = integrated gpu + // 2 = virtual gpu + // 3 = cpu + int type() const; + + // hardware limit + uint32_t max_shared_memory_size() const; + uint32_t max_workgroup_count_x() const; + uint32_t max_workgroup_count_y() const; + uint32_t max_workgroup_count_z() const; + uint32_t max_workgroup_invocations() const; + uint32_t max_workgroup_size_x() const; + uint32_t max_workgroup_size_y() const; + uint32_t max_workgroup_size_z() const; + size_t memory_map_alignment() const; + size_t buffer_offset_alignment() const; + size_t non_coherent_atom_size() const; + size_t buffer_image_granularity() const; + uint32_t max_image_dimension_1d() const; + uint32_t max_image_dimension_2d() const; + uint32_t max_image_dimension_3d() const; + float timestamp_period() const; + + // runtime + uint32_t compute_queue_family_index() const; + uint32_t graphics_queue_family_index() const; + uint32_t transfer_queue_family_index() const; + + uint32_t compute_queue_count() const; + uint32_t graphics_queue_count() const; + uint32_t transfer_queue_count() const; + + // property + bool unified_compute_transfer_queue() const; + + // subgroup + uint32_t subgroup_size() const; + bool support_subgroup_basic() const; + bool support_subgroup_vote() const; + bool support_subgroup_ballot() const; + bool support_subgroup_shuffle() const; + + // bug is not feature + bool bug_storage_buffer_no_l1() const; + bool bug_corrupted_online_pipeline_cache() const; + bool bug_buffer_image_load_zero() const; + + // but sometimes bug is a feature + bool bug_implicit_fp16_arithmetic() const; + + // fp16 and int8 feature + bool support_fp16_packed() const; + bool support_fp16_storage() const; + bool support_fp16_arithmetic() const; + bool support_int8_packed() const; + bool support_int8_storage() const; + bool support_int8_arithmetic() const; + + // ycbcr conversion feature + bool support_ycbcr_conversion() const; + + // cooperative matrix feature + bool support_cooperative_matrix() const; + bool support_cooperative_matrix_16_8_8() const; + bool support_cooperative_matrix_16_8_16() const; + bool support_cooperative_matrix_16_16_16() const; + + // extension capability + int support_VK_KHR_8bit_storage() const; + int support_VK_KHR_16bit_storage() const; + int support_VK_KHR_bind_memory2() const; + int support_VK_KHR_buffer_device_address() const; + int support_VK_KHR_create_renderpass2() const; + int support_VK_KHR_cooperative_matrix() const; + int support_VK_KHR_dedicated_allocation() const; + int support_VK_KHR_descriptor_update_template() const; + int support_VK_KHR_external_memory() const; + int support_VK_KHR_get_memory_requirements2() const; + int support_VK_KHR_maintenance1() const; + int support_VK_KHR_maintenance2() const; + int support_VK_KHR_maintenance3() const; + int support_VK_KHR_multiview() const; + int support_VK_KHR_portability_subset() const; + int support_VK_KHR_push_descriptor() const; + int support_VK_KHR_sampler_ycbcr_conversion() const; + int support_VK_KHR_shader_float16_int8() const; + int support_VK_KHR_shader_float_controls() const; + int support_VK_KHR_storage_buffer_storage_class() const; + int support_VK_KHR_swapchain() const; + int support_VK_EXT_buffer_device_address() const; + int support_VK_EXT_descriptor_indexing() const; + int support_VK_EXT_memory_budget() const; + int support_VK_EXT_memory_priority() const; + int support_VK_EXT_queue_family_foreign() const; + int support_VK_AMD_device_coherent_memory() const; +#if __ANDROID_API__ >= 26 + int support_VK_ANDROID_external_memory_android_hardware_buffer() const; +#endif // __ANDROID_API__ >= 26 + int support_VK_NV_cooperative_matrix() const; + +private: + GpuInfo(const GpuInfo&); + GpuInfo& operator=(const GpuInfo&); + +private: + friend int create_gpu_instance(); + GpuInfoPrivate* const d; +}; + +NCNN_EXPORT const GpuInfo& get_gpu_info(int device_index = get_default_gpu_index()); + +class VkAllocator; +class VkCompute; +class Option; +class PipelineCache; +class VulkanDevicePrivate; +class NCNN_EXPORT VulkanDevice +{ +public: + VulkanDevice(int device_index = get_default_gpu_index()); + ~VulkanDevice(); + + const GpuInfo& info; + + VkDevice vkdevice() const; + + VkShaderModule compile_shader_module(const uint32_t* spv_data, size_t spv_data_size) const; + + // with fixed workgroup size + VkShaderModule compile_shader_module(const uint32_t* spv_data, size_t spv_data_size, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z) const; + + // helper for creating pipeline + int create_descriptorset_layout(int binding_count, const int* binding_types, VkDescriptorSetLayout* descriptorset_layout) const; + int create_pipeline_layout(int push_constant_count, VkDescriptorSetLayout descriptorset_layout, VkPipelineLayout* pipeline_layout) const; + int create_pipeline(VkShaderModule shader_module, VkPipelineLayout pipeline_layout, const std::vector& specializations, VkPipeline* pipeline) const; + int create_descriptor_update_template(int binding_count, const int* binding_types, VkDescriptorSetLayout descriptorset_layout, VkPipelineLayout pipeline_layout, VkDescriptorUpdateTemplateKHR* descriptor_update_template) const; + + uint32_t find_memory_index(uint32_t memory_type_bits, VkFlags required, VkFlags preferred, VkFlags preferred_not) const; + bool is_mappable(uint32_t memory_type_index) const; + bool is_coherent(uint32_t memory_type_index) const; + + VkQueue acquire_queue(uint32_t queue_family_index) const; + void reclaim_queue(uint32_t queue_family_index, VkQueue queue) const; + + // allocator on this device + VkAllocator* acquire_blob_allocator() const; + void reclaim_blob_allocator(VkAllocator* allocator) const; + + VkAllocator* acquire_staging_allocator() const; + void reclaim_staging_allocator(VkAllocator* allocator) const; + + // immutable sampler for texelfetch + const VkSampler* immutable_texelfetch_sampler() const; + + // dummy buffer image + VkMat get_dummy_buffer() const; + VkImageMat get_dummy_image() const; + VkImageMat get_dummy_image_readonly() const; + + // pipeline cache on this device + const PipelineCache* get_pipeline_cache() const; + + // test image allocation + bool shape_support_image_storage(const Mat& shape) const; + + // current gpu heap memory budget in MB + uint32_t get_heap_budget() const; + + // utility operator + void convert_packing(const VkMat& src, VkMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkImageMat& src, VkImageMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkMat& src, VkImageMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkImageMat& src, VkMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + + // VK_KHR_bind_memory2 + PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; + PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; + + // VK_KHR_buffer_device_address + PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR; + PFN_vkGetBufferOpaqueCaptureAddressKHR vkGetBufferOpaqueCaptureAddressKHR; + PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR vkGetDeviceMemoryOpaqueCaptureAddressKHR; + + // VK_KHR_create_renderpass2 + PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; + PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; + PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; + + // VK_KHR_descriptor_update_template + PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; + PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; + PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; + + // VK_KHR_get_memory_requirements2 + PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; + PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; + PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; + + // VK_KHR_maintenance1 + PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; + + // VK_KHR_maintenance3 + PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; + + // VK_KHR_push_descriptor + PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; + PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; + + // VK_KHR_sampler_ycbcr_conversion + PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; + PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; + + // VK_KHR_swapchain + PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; + PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; + PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; + PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; + PFN_vkQueuePresentKHR vkQueuePresentKHR; + + // VK_EXT_buffer_device_address + PFN_vkGetBufferDeviceAddressEXT vkGetBufferDeviceAddressEXT; + +#if __ANDROID_API__ >= 26 + // VK_ANDROID_external_memory_android_hardware_buffer + PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; + PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; +#endif // __ANDROID_API__ >= 26 + +protected: + // device extension + int init_device_extension(); + +private: + VulkanDevice(const VulkanDevice&); + VulkanDevice& operator=(const VulkanDevice&); + +private: + VulkanDevicePrivate* const d; +}; + +NCNN_EXPORT VulkanDevice* get_gpu_device(int device_index = get_default_gpu_index()); + +// online spirv compilation +NCNN_EXPORT int compile_spirv_module(const char* comp_string, const Option& opt, std::vector& spirv); +NCNN_EXPORT int compile_spirv_module(const char* comp_data, int comp_data_size, const Option& opt, std::vector& spirv); +NCNN_EXPORT int compile_spirv_module(int shader_type_index, const Option& opt, std::vector& spirv); + +// info from spirv +class NCNN_EXPORT ShaderInfo +{ +public: + int specialization_count; + int binding_count; + int push_constant_count; + + // 0 = null + // 1 = storage buffer + // 2 = storage image + // 3 = combined image sampler + int binding_types[16]; // 16 is large enough I think ... + + int reserved_0; + int reserved_1; + int reserved_2; + int reserved_3; +}; + +NCNN_EXPORT int resolve_shader_info(const uint32_t* spv_data, size_t spv_data_size, ShaderInfo& shader_info); + +} // namespace ncnn + +#endif // NCNN_VULKAN + +#endif // NCNN_GPU_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/layer.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/layer.h new file mode 100644 index 0000000..f0418a9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/layer.h @@ -0,0 +1,222 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_H +#define NCNN_LAYER_H + +#include "mat.h" +#include "modelbin.h" +#include "option.h" +#include "paramdict.h" +#include "platform.h" + +#if NCNN_VULKAN +#include "command.h" +#include "pipeline.h" + +#include +#endif // NCNN_VULKAN + +namespace ncnn { + +class NCNN_EXPORT Layer +{ +public: + // empty + Layer(); + // virtual destructor + virtual ~Layer(); + + // load layer specific parameter from parsed dict + // return 0 if success + virtual int load_param(const ParamDict& pd); + + // load layer specific weight data from model binary + // return 0 if success + virtual int load_model(const ModelBin& mb); + + // layer implementation specific setup + // return 0 if success + virtual int create_pipeline(const Option& opt); + + // layer implementation specific clean + // return 0 if success + virtual int destroy_pipeline(const Option& opt); + +public: + // one input and one output blob + bool one_blob_only; + + // support inplace inference + bool support_inplace; + + // support vulkan compute + bool support_vulkan; + + // accept input blob with packed storage + bool support_packing; + + // accept bf16 + bool support_bf16_storage; + + // accept fp16 + bool support_fp16_storage; + + // accept int8 + bool support_int8_storage; + + // shader image storage + bool support_image_storage; + + // shader tensor storage + bool support_tensor_storage; + + bool support_reserved_00; + + bool support_reserved_0; + bool support_reserved_1; + bool support_reserved_2; + bool support_reserved_3; + bool support_reserved_4; + bool support_reserved_5; + bool support_reserved_6; + bool support_reserved_7; + bool support_reserved_8; + bool support_reserved_9; + + // feature disabled set + int featmask; + +public: + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, const Option& opt) const; + virtual int forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, const Option& opt) const; + virtual int forward_inplace(Mat& bottom_top_blob, const Option& opt) const; + +#if NCNN_VULKAN +public: + // upload weight blob from host to device + virtual int upload_model(VkTransfer& cmd, const Option& opt); + +public: + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward_inplace(VkMat& bottom_top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward_inplace(VkImageMat& bottom_top_blob, VkCompute& cmd, const Option& opt) const; + +public: + // assigned immediately after creating this layer + const VulkanDevice* vkdev; +#endif // NCNN_VULKAN + +public: + // custom user data + void* userdata; + // layer type index + int typeindex; +#if NCNN_STRING + // layer type name + std::string type; + // layer name + std::string name; +#endif // NCNN_STRING + // blob index which this layer needs as input + std::vector bottoms; + // blob index which this layer produces as output + std::vector tops; + // shape hint + std::vector bottom_shapes; + std::vector top_shapes; +}; + +// layer factory function +typedef Layer* (*layer_creator_func)(void*); +typedef void (*layer_destroyer_func)(Layer*, void*); + +struct layer_registry_entry +{ +#if NCNN_STRING + // layer type name + const char* name; +#endif // NCNN_STRING + // layer factory entry + layer_creator_func creator; +}; + +struct custom_layer_registry_entry +{ +#if NCNN_STRING + // layer type name + const char* name; +#endif // NCNN_STRING + // layer factory entry + layer_creator_func creator; + layer_destroyer_func destroyer; + void* userdata; +}; + +struct overwrite_builtin_layer_registry_entry +{ + // layer type index + int typeindex; + // layer factory entry + layer_creator_func creator; + layer_destroyer_func destroyer; + void* userdata; +}; + +#if NCNN_STRING +// get layer type from type name +NCNN_EXPORT int layer_to_index(const char* type); +// create layer from type name +NCNN_EXPORT Layer* create_layer(const char* type); +#endif // NCNN_STRING +// create layer from layer type +NCNN_EXPORT Layer* create_layer(int index); + +#define DEFINE_LAYER_CREATOR(name) \ + ::ncnn::Layer* name##_layer_creator(void* /*userdata*/) \ + { \ + return new name; \ + } + +#define DEFINE_LAYER_DESTROYER(name) \ + void name##_layer_destroyer(::ncnn::Layer* layer, void* /*userdata*/) \ + { \ + delete layer; \ + } + +} // namespace ncnn + +#endif // NCNN_LAYER_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/layer_shader_type.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/layer_shader_type.h new file mode 100644 index 0000000..c143e7d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/layer_shader_type.h @@ -0,0 +1,29 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_SHADER_TYPE_H +#define NCNN_LAYER_SHADER_TYPE_H + +namespace ncnn { + +namespace LayerShaderType { +enum LayerShaderType +{ +#include "layer_shader_type_enum.h" +}; +} // namespace LayerShaderType + +} // namespace ncnn + +#endif // NCNN_LAYER_SHADER_TYPE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/layer_shader_type_enum.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/layer_shader_type_enum.h new file mode 100644 index 0000000..aac8803 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/layer_shader_type_enum.h @@ -0,0 +1,5 @@ +// Layer Shader Enum header +// +// This file is auto-generated by cmake, don't edit it. + + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/layer_type.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/layer_type.h new file mode 100644 index 0000000..511c714 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/layer_type.h @@ -0,0 +1,30 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_TYPE_H +#define NCNN_LAYER_TYPE_H + +namespace ncnn { + +namespace LayerType { +enum LayerType +{ +#include "layer_type_enum.h" + CustomBit = (1 << 8), +}; +} // namespace LayerType + +} // namespace ncnn + +#endif // NCNN_LAYER_TYPE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/layer_type_enum.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/layer_type_enum.h new file mode 100644 index 0000000..97153ed --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/layer_type_enum.h @@ -0,0 +1,109 @@ +// Layer Type Enum header +// +// This file is auto-generated by cmake, don't edit it. + +AbsVal = 0, +ArgMax = 1, +BatchNorm = 2, +Bias = 3, +BNLL = 4, +Concat = 5, +Convolution = 6, +Crop = 7, +Deconvolution = 8, +Dropout = 9, +Eltwise = 10, +ELU = 11, +Embed = 12, +Exp = 13, +Flatten = 14, +InnerProduct = 15, +Input = 16, +Log = 17, +LRN = 18, +MemoryData = 19, +MVN = 20, +Pooling = 21, +Power = 22, +PReLU = 23, +Proposal = 24, +Reduction = 25, +ReLU = 26, +Reshape = 27, +ROIPooling = 28, +Scale = 29, +Sigmoid = 30, +Slice = 31, +Softmax = 32, +Split = 33, +SPP = 34, +TanH = 35, +Threshold = 36, +Tile = 37, +RNN = 38, +LSTM = 39, +BinaryOp = 40, +UnaryOp = 41, +ConvolutionDepthWise = 42, +Padding = 43, +Squeeze = 44, +ExpandDims = 45, +Normalize = 46, +Permute = 47, +PriorBox = 48, +DetectionOutput = 49, +Interp = 50, +DeconvolutionDepthWise = 51, +ShuffleChannel = 52, +InstanceNorm = 53, +Clip = 54, +Reorg = 55, +YoloDetectionOutput = 56, +Quantize = 57, +Dequantize = 58, +Yolov3DetectionOutput = 59, +PSROIPooling = 60, +ROIAlign = 61, +Packing = 62, +Requantize = 63, +Cast = 64, +HardSigmoid = 65, +SELU = 66, +HardSwish = 67, +Noop = 68, +PixelShuffle = 69, +DeepCopy = 70, +Mish = 71, +StatisticsPooling = 72, +Swish = 73, +Gemm = 74, +GroupNorm = 75, +LayerNorm = 76, +Softplus = 77, +GRU = 78, +MultiHeadAttention = 79, +GELU = 80, +Convolution1D = 81, +Pooling1D = 82, +ConvolutionDepthWise1D = 83, +Convolution3D = 84, +ConvolutionDepthWise3D = 85, +Pooling3D = 86, +MatMul = 87, +Deconvolution1D = 88, +DeconvolutionDepthWise1D = 89, +Deconvolution3D = 90, +DeconvolutionDepthWise3D = 91, +Einsum = 92, +DeformableConv2D = 93, +GLU = 94, +Fold = 95, +Unfold = 96, +GridSample = 97, +CumulativeSum = 98, +CopyTo = 99, +Erf = 100, +Diag = 101, +CELU = 102, +Shrink = 103, + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/mat.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/mat.h new file mode 100644 index 0000000..c6f59ef --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/mat.h @@ -0,0 +1,1843 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_MAT_H +#define NCNN_MAT_H + +#include +#include +#if __ARM_NEON +#include +#endif +#if __SSE2__ +#include +#if __AVX__ +#include +#endif +#endif +#if __mips_msa +#include +#endif +#if __loongarch_sx +#include +#endif +#if __riscv_vector +#include +#include "cpu.h" // cpu_riscv_vlenb() +#endif + +#include "allocator.h" +#include "option.h" +#include "platform.h" + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#if NCNN_PIXEL +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#include +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API +#endif // NCNN_PIXEL + +namespace ncnn { + +#if NCNN_VULKAN +class VkMat; +class VkImageMat; +#endif // NCNN_VULKAN + +// the three dimension matrix +class NCNN_EXPORT Mat +{ +public: + // empty + Mat(); + // vec + Mat(int w, size_t elemsize = 4u, Allocator* allocator = 0); + // image + Mat(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0); + // dim + Mat(int w, int h, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // cube + Mat(int w, int h, int d, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // packed vec + Mat(int w, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed image + Mat(int w, int h, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed dim + Mat(int w, int h, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed cube + Mat(int w, int h, int d, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // copy + Mat(const Mat& m); + // external vec + Mat(int w, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external image + Mat(int w, int h, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external dim + Mat(int w, int h, int c, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external cube + Mat(int w, int h, int d, int c, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external packed vec + Mat(int w, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed image + Mat(int w, int h, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed dim + Mat(int w, int h, int c, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed cube + Mat(int w, int h, int d, int c, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // release + ~Mat(); + // assign + Mat& operator=(const Mat& m); + // set all + void fill(float v); + void fill(int v); +#if __ARM_NEON + void fill(float32x4_t _v); + void fill(uint16x4_t _v); + void fill(int32x4_t _v); + void fill(int32x4_t _v0, int32x4_t _v1); +#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC + void fill(float16x4_t _v); + void fill(float16x8_t _v); +#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +#endif // __ARM_NEON +#if __SSE2__ +#if __AVX__ +#if __AVX512F__ + void fill(__m512 _v); +#endif // __AVX512F__ + void fill(__m256 _v, int i = 0); +#endif // __AVX__ + void fill(__m128 _v); + void fill(__m128i _v); +#endif // __SSE2__ +#if __mips_msa + void fill(v4f32 _v); +#endif // __mips_msa +#if __loongarch_sx + void fill(__m128 _v); +#endif //__loongarch_sx +#if __riscv_vector + void fill(vfloat32m1_t _v); + void fill(vuint16m1_t _v); + void fill(vint8m1_t _v); +#if __riscv_zfh + void fill(vfloat16m1_t _v); +#endif // __riscv_zfh +#endif // __riscv_vector + template + void fill(T v); + // deep copy + Mat clone(Allocator* allocator = 0) const; + // deep copy from other mat, inplace + void clone_from(const ncnn::Mat& mat, Allocator* allocator = 0); + // reshape vec + Mat reshape(int w, Allocator* allocator = 0) const; + // reshape image + Mat reshape(int w, int h, Allocator* allocator = 0) const; + // reshape dim + Mat reshape(int w, int h, int c, Allocator* allocator = 0) const; + // reshape cube + Mat reshape(int w, int h, int d, int c, Allocator* allocator = 0) const; + // allocate vec + void create(int w, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate image + void create(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate dim + void create(int w, int h, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate like + void create_like(const Mat& m, Allocator* allocator = 0); +#if NCNN_VULKAN + // allocate like + void create_like(const VkMat& m, Allocator* allocator = 0); + // allocate like + void create_like(const VkImageMat& im, Allocator* allocator = 0); +#endif // NCNN_VULKAN + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // data reference + Mat channel(int c); + const Mat channel(int c) const; + Mat depth(int z); + const Mat depth(int z) const; + float* row(int y); + const float* row(int y) const; + template + T* row(int y); + template + const T* row(int y) const; + + // range reference + Mat channel_range(int c, int channels); + const Mat channel_range(int c, int channels) const; + Mat depth_range(int z, int depths); + const Mat depth_range(int z, int depths) const; + Mat row_range(int y, int rows); + const Mat row_range(int y, int rows) const; + Mat range(int x, int n); + const Mat range(int x, int n) const; + + // access raw data + template + operator T*(); + template + operator const T*() const; + + // convenient access float vec element + float& operator[](size_t i); + const float& operator[](size_t i) const; + +#if NCNN_PIXEL + enum PixelType + { + PIXEL_CONVERT_SHIFT = 16, + PIXEL_FORMAT_MASK = 0x0000ffff, + PIXEL_CONVERT_MASK = 0xffff0000, + + PIXEL_RGB = 1, + PIXEL_BGR = 2, + PIXEL_GRAY = 3, + PIXEL_RGBA = 4, + PIXEL_BGRA = 5, + + PIXEL_RGB2BGR = PIXEL_RGB | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2GRAY = PIXEL_RGB | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2RGBA = PIXEL_RGB | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2BGRA = PIXEL_RGB | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_BGR2RGB = PIXEL_BGR | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2GRAY = PIXEL_BGR | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2RGBA = PIXEL_BGR | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2BGRA = PIXEL_BGR | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_GRAY2RGB = PIXEL_GRAY | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2BGR = PIXEL_GRAY | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2RGBA = PIXEL_GRAY | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2BGRA = PIXEL_GRAY | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_RGBA2RGB = PIXEL_RGBA | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2BGR = PIXEL_RGBA | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2GRAY = PIXEL_RGBA | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2BGRA = PIXEL_RGBA | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_BGRA2RGB = PIXEL_BGRA | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2BGR = PIXEL_BGRA | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2GRAY = PIXEL_BGRA | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2RGBA = PIXEL_BGRA | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + }; + // convenient construct from pixel data + static Mat from_pixels(const unsigned char* pixels, int type, int w, int h, Allocator* allocator = 0); + // convenient construct from pixel data with stride(bytes-per-row) parameter + static Mat from_pixels(const unsigned char* pixels, int type, int w, int h, int stride, Allocator* allocator = 0); + // convenient construct from pixel data and resize to specific size + static Mat from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data and resize to specific size with stride(bytes-per-row) parameter + static Mat from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data roi + static Mat from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from pixel data roi with stride(bytes-per-row) parameter + static Mat from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from pixel data roi and resize to specific size + static Mat from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data roi and resize to specific size with stride(bytes-per-row) parameter + static Mat from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + + // convenient export to pixel data + void to_pixels(unsigned char* pixels, int type) const; + // convenient export to pixel data with stride(bytes-per-row) parameter + void to_pixels(unsigned char* pixels, int type, int stride) const; + // convenient export to pixel data and resize to specific size + void to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height) const; + // convenient export to pixel data and resize to specific size with stride(bytes-per-row) parameter + void to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height, int target_stride) const; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 + // convenient construct from android Bitmap + static Mat from_android_bitmap(JNIEnv* env, jobject bitmap, int type_to, Allocator* allocator = 0); + // convenient construct from android Bitmap and resize to specific size + static Mat from_android_bitmap_resize(JNIEnv* env, jobject bitmap, int type_to, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from android Bitmap roi + static Mat from_android_bitmap_roi(JNIEnv* env, jobject bitmap, int type_to, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from android Bitmap roi and resize to specific size + static Mat from_android_bitmap_roi_resize(JNIEnv* env, jobject bitmap, int type_to, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + // convenient export to android Bitmap and resize to the android Bitmap size + void to_android_bitmap(JNIEnv* env, jobject bitmap, int type_from) const; +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API +#endif // NCNN_PIXEL + + // substract channel-wise mean values, then multiply by normalize values, pass 0 to skip + void substract_mean_normalize(const float* mean_vals, const float* norm_vals); + + // convenient construct from half precision floating point data + static Mat from_float16(const unsigned short* data, int size); + + // pointer to the data + void* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + Allocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; + + size_t cstep; +}; + +#if NCNN_VULKAN + +// the three dimension matrix, vulkan version +class NCNN_EXPORT VkMat +{ +public: + // empty + VkMat(); + // vec + VkMat(int w, size_t elemsize, VkAllocator* allocator); + // image + VkMat(int w, int h, size_t elemsize, VkAllocator* allocator); + // dim + VkMat(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // cube + VkMat(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // packed vec + VkMat(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // packed image + VkMat(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // packed dim + VkMat(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // packed cube + VkMat(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // copy + VkMat(const VkMat& m); + // external vec + VkMat(int w, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external image + VkMat(int w, int h, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external dim + VkMat(int w, int h, int c, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external cube + VkMat(int w, int h, int d, int c, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external packed vec + VkMat(int w, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed image + VkMat(int w, int h, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed dim + VkMat(int w, int h, int c, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed cube + VkMat(int w, int h, int d, int c, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // release + ~VkMat(); + // assign + VkMat& operator=(const VkMat& m); + // allocate vec + void create(int w, size_t elemsize, VkAllocator* allocator); + // allocate image + void create(int w, int h, size_t elemsize, VkAllocator* allocator); + // allocate dim + void create(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate like + void create_like(const Mat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkMat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkImageMat& im, VkAllocator* allocator); + + // mapped + Mat mapped() const; + void* mapped_ptr() const; + + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // low-level reference + VkBuffer buffer() const; + size_t buffer_offset() const; + size_t buffer_capacity() const; + + // device buffer + VkBufferMemory* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + VkAllocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; + + size_t cstep; +}; + +class NCNN_EXPORT VkImageMat +{ +public: + // empty + VkImageMat(); + // vec + VkImageMat(int w, size_t elemsize, VkAllocator* allocator); + // image + VkImageMat(int w, int h, size_t elemsize, VkAllocator* allocator); + // dim + VkImageMat(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // cube + VkImageMat(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // packed vec + VkImageMat(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // packed image + VkImageMat(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // packed dim + VkImageMat(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // packed cube + VkImageMat(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // copy + VkImageMat(const VkImageMat& m); + // external vec + VkImageMat(int w, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external image + VkImageMat(int w, int h, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external dim + VkImageMat(int w, int h, int c, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external cube + VkImageMat(int w, int h, int d, int c, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external packed vec + VkImageMat(int w, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed image + VkImageMat(int w, int h, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed dim + VkImageMat(int w, int h, int c, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed cube + VkImageMat(int w, int h, int d, int c, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // release + ~VkImageMat(); + // assign + VkImageMat& operator=(const VkImageMat& m); + // allocate vec + void create(int w, size_t elemsize, VkAllocator* allocator); + // allocate image + void create(int w, int h, size_t elemsize, VkAllocator* allocator); + // allocate dim + void create(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate like + void create_like(const Mat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkMat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkImageMat& im, VkAllocator* allocator); + + // mapped + Mat mapped() const; + void* mapped_ptr() const; + + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // low-level reference + VkImage image() const; + VkImageView imageview() const; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 + // convenient construct from android hardware buffer + static VkImageMat from_android_hardware_buffer(VkAndroidHardwareBufferImageAllocator* allocator); +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + + // device image + VkImageMemory* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + VkAllocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; +}; + +// type for vulkan specialization constant and push constant +union vk_specialization_type +{ + int i; + float f; + uint32_t u32; +}; +union vk_constant_type +{ + int i; + float f; +}; +#endif // NCNN_VULKAN + +// misc function +#if NCNN_PIXEL +// convert yuv420sp(nv21) to rgb, the fast approximate version +NCNN_EXPORT void yuv420sp2rgb(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// convert yuv420sp(nv12) to rgb, the fast approximate version +NCNN_EXPORT void yuv420sp2rgb_nv12(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// convert yuv420sp(nv21) to rgb with half resize, the faster approximate version +NCNN_EXPORT void yuv420sp2rgb_half(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// image pixel bilinear resize +NCNN_EXPORT void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +// image pixel bilinear resize with stride(bytes-per-row) parameter +NCNN_EXPORT void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +// image pixel bilinear resize, convenient wrapper for yuv420sp(nv21/nv12) +NCNN_EXPORT void resize_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +#endif // NCNN_PIXEL +#if NCNN_PIXEL_ROTATE +// type is the from type, 6 means rotating from 6 to 1 +// +// 1 2 3 4 5 6 7 8 +// +// 888888 888888 88 88 8888888888 88 88 8888888888 +// 88 88 88 88 88 88 88 88 88 88 88 88 +// 8888 8888 8888 8888 88 8888888888 8888888888 88 +// 88 88 88 88 +// 88 88 888888 888888 +// +// ref http://sylvana.net/jpegcrop/exif_orientation.html +// image pixel kanna rotate +NCNN_EXPORT void kanna_rotate_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +// image pixel kanna rotate with stride(bytes-per-row) parameter +NCNN_EXPORT void kanna_rotate_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +// image pixel kanna rotate, convenient wrapper for yuv420sp(nv21/nv12) +NCNN_EXPORT void kanna_rotate_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +#endif // NCNN_PIXEL_ROTATE +#if NCNN_PIXEL_AFFINE +// resolve affine transform matrix from rotation angle, scale factor and x y offset +NCNN_EXPORT void get_rotation_matrix(float angle, float scale, float dx, float dy, float* tm); +// resolve affine transform matrix from two set of points, num_point must be >= 2 +NCNN_EXPORT void get_affine_transform(const float* points_from, const float* points_to, int num_point, float* tm); +// resolve the inversion affine transform matrix +NCNN_EXPORT void invert_affine_transform(const float* tm, float* tm_inv); +// image pixel bilinear warpaffine inverse transform, set -233 for transparent border color, the color RGBA is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +// image pixel bilinear warpaffine inverse transform with stride(bytes-per-row) parameter, set -233 for transparent border color, the color RGBA is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +// image pixel bilinear warpaffine, convenient wrapper for yuv420sp(nv21/nv12), set -233 for transparent border color, the color YUV_ is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +#endif // NCNN_PIXEL_AFFINE +#if NCNN_PIXEL_DRAWING +// draw rectangle, set thickness -1 for filled rectangle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_rectangle_c1(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c2(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c3(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c4(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw rectangle with stride(bytes-per-row) parameter, set thickness -1 for filled rectangle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_rectangle_c1(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c2(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c3(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c4(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw rectangle, convenient wrapper for yuv420sp(nv21/nv12), set thickness -1 for filled rectangle, the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_rectangle_yuv420sp(unsigned char* yuv420sp, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw circle, set thickness -1 for filled circle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_circle_c1(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c2(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c3(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c4(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +// draw circle with stride(bytes-per-row) parameter, set thickness -1 for filled circle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_circle_c1(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c2(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c3(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c4(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +// draw circle, convenient wrapper for yuv420sp(nv21/nv12), set thickness -1 for filled circle, the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_circle_yuv420sp(unsigned char* yuv420sp, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +// draw line, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_line_c1(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c2(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c3(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c4(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// draw line with stride(bytes-per-row) parameter, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_line_c1(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c2(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c3(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c4(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// draw line, convenient wrapper for yuv420sp(nv21/nv12), the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_line_yuv420sp(unsigned char* yuv420sp, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// resolve text bounding box size +NCNN_EXPORT void get_text_drawing_size(const char* text, int fontpixelsize, int* w, int* h); +// draw ascii printables and newline, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_text_c1(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c2(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c3(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c4(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +// draw ascii printables and newline with stride(bytes-per-row) parameter, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_text_c1(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c2(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c3(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c4(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +// draw ascii printables and newline, convenient wrapper for yuv420sp(nv21/nv12), the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_text_yuv420sp(unsigned char* yuv420sp, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +#endif // NCNN_PIXEL_DRAWING + +// type conversion +// convert float to half precision floating point +NCNN_EXPORT unsigned short float32_to_float16(float value); +// convert half precision floating point to float +NCNN_EXPORT float float16_to_float32(unsigned short value); +// convert float to brain half +NCNN_EXPORT NCNN_FORCEINLINE unsigned short float32_to_bfloat16(float value) +{ + // 16 : 16 + union + { + unsigned int u; + float f; + } tmp; + tmp.f = value; + return tmp.u >> 16; +} +// convert brain half to float +NCNN_EXPORT NCNN_FORCEINLINE float bfloat16_to_float32(unsigned short value) +{ + // 16 : 16 + union + { + unsigned int u; + float f; + } tmp; + tmp.u = value << 16; + return tmp.f; +} + +// mat process +enum BorderType +{ + BORDER_CONSTANT = 0, + BORDER_REPLICATE = 1, + BORDER_REFLECT = 2, + BORDER_TRANSPARENT = -233, +}; +NCNN_EXPORT void copy_make_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int type, float v, const Option& opt = Option()); +NCNN_EXPORT void copy_make_border_3d(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int front, int behind, int type, float v, const Option& opt = Option()); +NCNN_EXPORT void copy_cut_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, const Option& opt = Option()); +NCNN_EXPORT void copy_cut_border_3d(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int front, int behind, const Option& opt = Option()); +NCNN_EXPORT void resize_nearest(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void resize_bilinear(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void resize_bicubic(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void convert_packing(const Mat& src, Mat& dst, int elempack, const Option& opt = Option()); +NCNN_EXPORT void flatten(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float32_to_float16(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float16_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_int8_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float32_to_bfloat16(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_bfloat16_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void quantize_to_int8(const Mat& src, Mat& dst, const Mat& scale_data, const Option& opt = Option()); +NCNN_EXPORT void dequantize_from_int32(const Mat& src, Mat& dst, const Mat& scale_data, const Mat& bias_data, const Option& opt = Option()); +NCNN_EXPORT void requantize_from_int32_to_int8(const Mat& src, Mat& dst, const Mat& scale_in_data, const Mat& scale_out_data, const Mat& bias_data, int activation_type, const Mat& activation_params, const Option& opt = Option()); + +NCNN_FORCEINLINE Mat::Mat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ +} + +NCNN_FORCEINLINE Mat::Mat(int _w, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(const Mat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c), cstep(m.cstep) +{ + addref(); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = (size_t)w * h; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = (size_t)w * h; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::~Mat() +{ + release(); +} + +NCNN_FORCEINLINE void Mat::fill(float _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + + int i = 0; +#if __ARM_NEON + float32x4_t _c = vdupq_n_f32(_v); + for (; i + 3 < size; i += 4) + { + vst1q_f32(ptr, _c); + ptr += 4; + } +#endif // __ARM_NEON + for (; i < size; i++) + { + *ptr++ = _v; + } +} + +NCNN_FORCEINLINE void Mat::fill(int _v) +{ + int size = (int)total(); + int* ptr = (int*)data; + + int i = 0; +#if __ARM_NEON + int32x4_t _c = vdupq_n_s32(_v); + for (; i + 3 < size; i += 4) + { + vst1q_s32(ptr, _c); + ptr += 4; + } +#endif // __ARM_NEON + for (; i < size; i++) + { + *ptr++ = _v; + } +} + +#if __ARM_NEON +NCNN_FORCEINLINE void Mat::fill(float32x4_t _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + vst1q_f32(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(uint16x4_t _v) +{ + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + vst1_u16(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(int32x4_t _v) +{ + int size = (int)total(); + int* ptr = (int*)data; + for (int i = 0; i < size; i++) + { + vst1q_s32(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(int32x4_t _v0, int32x4_t _v1) +{ + int size = (int)total(); + int* ptr = (int*)data; + for (int i = 0; i < size; i++) + { + vst1q_s32(ptr, _v0); + vst1q_s32(ptr + 4, _v1); + ptr += 8; + } +} +#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +NCNN_FORCEINLINE void Mat::fill(float16x4_t _v) +{ + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vst1_f16(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(float16x8_t _v) +{ + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vst1q_f16(ptr, _v); + ptr += 8; + } +} +#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +#endif // __ARM_NEON + +#if __SSE2__ +#if __AVX__ +#if __AVX512F__ +NCNN_FORCEINLINE void Mat::fill(__m512 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm512_storeu_ps(ptr, _v); + ptr += 16; + } +} +#endif // __AVX512F__ +NCNN_FORCEINLINE void Mat::fill(__m256 _v, int _i) +{ + // old gcc cannot overload __m128 and __m256 type + // add a dummy int parameter for different mangled function symbol + (void)_i; + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm256_storeu_ps(ptr, _v); + ptr += 8; + } +} +#endif // __AVX__ +NCNN_FORCEINLINE void Mat::fill(__m128 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm_storeu_ps(ptr, _v); + ptr += 4; + } +} +NCNN_FORCEINLINE void Mat::fill(__m128i _v) +{ + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + _mm_store_si128((__m128i*)ptr, _v); + ptr += 8; + } +} +#endif // __SSE2__ + +#if __mips_msa +NCNN_FORCEINLINE void Mat::fill(v4f32 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + __msa_st_w((v4i32)_v, ptr, 0); + ptr += 4; + } +} +#endif // __mips_msa + +#if __loongarch_sx +NCNN_FORCEINLINE void Mat::fill(__m128 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + __lsx_vst(_v, ptr, 0); + ptr += 4; + } +} +#endif // __loongarch_sx +#if __riscv_vector +NCNN_FORCEINLINE void Mat::fill(vfloat32m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 4; + const size_t vl = vsetvl_e32m1(packn); + + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + vse32_v_f32m1(ptr, _v, vl); + ptr += packn; + } +} + +NCNN_FORCEINLINE void Mat::fill(vuint16m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 2; + const size_t vl = vsetvl_e16m1(packn); + + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + vse16_v_u16m1(ptr, _v, vl); + ptr += packn; + } +} + +NCNN_FORCEINLINE void Mat::fill(vint8m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 1; + const size_t vl = vsetvl_e8m1(packn); + + int size = (int)total(); + signed char* ptr = (signed char*)data; + for (int i = 0; i < size; i++) + { + vse8_v_i8m1(ptr, _v, vl); + ptr += packn; + } +} +#if __riscv_zfh +NCNN_FORCEINLINE void Mat::fill(vfloat16m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 2; + const size_t vl = vsetvl_e16m1(packn); + + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vse16_v_f16m1(ptr, _v, vl); + ptr += packn; + } +} +#endif // __riscv_zfh +#endif // __riscv_vector + +template +NCNN_FORCEINLINE void Mat::fill(T _v) +{ + int size = (int)total(); + T* ptr = (T*)data; + for (int i = 0; i < size; i++) + { + ptr[i] = _v; + } +} + +NCNN_FORCEINLINE Mat& Mat::operator=(const Mat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + cstep = m.cstep; + + return *this; +} + +NCNN_FORCEINLINE void Mat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void Mat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator) + allocator->fastFree(data); + else + fastFree(data); + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + cstep = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool Mat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t Mat::total() const +{ + return cstep * c; +} + +NCNN_FORCEINLINE int Mat::elembits() const +{ + return elempack ? static_cast(elemsize * 8) / elempack : 0; +} + +NCNN_FORCEINLINE Mat Mat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE Mat Mat::channel(int _c) +{ + Mat m(w, h, d, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims - 1; + if (dims == 4) + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::channel(int _c) const +{ + Mat m(w, h, d, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims - 1; + if (dims == 4) + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE Mat Mat::depth(int z) +{ + return Mat(w, h, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::depth(int z) const +{ + return Mat(w, h, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE float* Mat::row(int y) +{ + return (float*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +NCNN_FORCEINLINE const float* Mat::row(int y) const +{ + return (const float*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +template +NCNN_FORCEINLINE T* Mat::row(int y) +{ + return (T*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +template +NCNN_FORCEINLINE const T* Mat::row(int y) const +{ + return (const T*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +NCNN_FORCEINLINE Mat Mat::channel_range(int _c, int channels) +{ + Mat m(w, h, d, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::channel_range(int _c, int channels) const +{ + Mat m(w, h, d, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims; + return m; +} + +NCNN_FORCEINLINE Mat Mat::depth_range(int z, int depths) +{ + Mat m(w, h, depths, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::depth_range(int z, int depths) const +{ + Mat m(w, h, depths, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE Mat Mat::row_range(int y, int rows) +{ + return Mat(w, rows, (unsigned char*)data + (size_t)w * y * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::row_range(int y, int rows) const +{ + return Mat(w, rows, (unsigned char*)data + (size_t)w * y * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE Mat Mat::range(int x, int n) +{ + return Mat(n, (unsigned char*)data + x * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::range(int x, int n) const +{ + return Mat(n, (unsigned char*)data + x * elemsize, elemsize, elempack, allocator); +} + +template +NCNN_FORCEINLINE Mat::operator T*() +{ + return (T*)data; +} + +template +NCNN_FORCEINLINE Mat::operator const T*() const +{ + return (const T*)data; +} + +NCNN_FORCEINLINE float& Mat::operator[](size_t i) +{ + return ((float*)data)[i]; +} + +NCNN_FORCEINLINE const float& Mat::operator[](size_t i) const +{ + return ((const float*)data)[i]; +} + +#if NCNN_VULKAN + +NCNN_FORCEINLINE VkMat::VkMat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(const VkMat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c) +{ + addref(); + + cstep = m.cstep; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = w * h; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize(w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = w * h; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize(w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::~VkMat() +{ + release(); +} + +NCNN_FORCEINLINE VkMat& VkMat::operator=(const VkMat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + cstep = m.cstep; + + return *this; +} + +NCNN_FORCEINLINE Mat VkMat::mapped() const +{ + if (!allocator->mappable) + return Mat(); + + if (dims == 1) + return Mat(w, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 2) + return Mat(w, h, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 3) + return Mat(w, h, c, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 4) + return Mat(w, h, d, c, mapped_ptr(), elemsize, elempack, 0); + + return Mat(); +} + +NCNN_FORCEINLINE void* VkMat::mapped_ptr() const +{ + if (!allocator->mappable) + return 0; + + return (unsigned char*)data->mapped_ptr + data->offset; +} + +NCNN_FORCEINLINE void VkMat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void VkMat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator && data) + { + allocator->fastFree(data); + } + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + cstep = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool VkMat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t VkMat::total() const +{ + return cstep * c; +} + +NCNN_FORCEINLINE int VkMat::elembits() const +{ + return elempack ? static_cast(elemsize) * 8 / elempack : 0; +} + +NCNN_FORCEINLINE Mat VkMat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE VkBuffer VkMat::buffer() const +{ + return data->buffer; +} + +NCNN_FORCEINLINE size_t VkMat::buffer_offset() const +{ + return data->offset; +} + +NCNN_FORCEINLINE size_t VkMat::buffer_capacity() const +{ + return data->capacity; +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(const VkImageMat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c) +{ + addref(); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::~VkImageMat() +{ + release(); +} + +NCNN_FORCEINLINE VkImageMat& VkImageMat::operator=(const VkImageMat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + return *this; +} + +NCNN_FORCEINLINE Mat VkImageMat::mapped() const +{ + if (!allocator->mappable || !data->mapped_ptr) + return Mat(); + + if (dims == 1) + return Mat(w, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 2) + return Mat(w, h, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 3) + return Mat(w, h, c, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 4) + return Mat(w, h, d, c, mapped_ptr(), elemsize, elempack, 0); + + return Mat(); +} + +NCNN_FORCEINLINE void* VkImageMat::mapped_ptr() const +{ + if (!allocator->mappable || !data->mapped_ptr) + return 0; + + return (unsigned char*)data->mapped_ptr + data->bind_offset; +} + +NCNN_FORCEINLINE void VkImageMat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void VkImageMat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator && data) + { + allocator->fastFree(data); + } + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool VkImageMat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t VkImageMat::total() const +{ + return w * h * d * c; +} + +NCNN_FORCEINLINE int VkImageMat::elembits() const +{ + return elempack ? static_cast(elemsize) * 8 / elempack : 0; +} + +NCNN_FORCEINLINE Mat VkImageMat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE VkImage VkImageMat::image() const +{ + return data->image; +} + +NCNN_FORCEINLINE VkImageView VkImageMat::imageview() const +{ + return data->imageview; +} + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_MAT_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/modelbin.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/modelbin.h new file mode 100644 index 0000000..aada5f6 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/modelbin.h @@ -0,0 +1,80 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_MODELBIN_H +#define NCNN_MODELBIN_H + +#include "mat.h" + +namespace ncnn { + +class DataReader; +class NCNN_EXPORT ModelBin +{ +public: + ModelBin(); + virtual ~ModelBin(); + // element type + // 0 = auto + // 1 = float32 + // 2 = float16 + // 3 = int8 + // load vec + virtual Mat load(int w, int type) const; + // load image + virtual Mat load(int w, int h, int type) const; + // load dim + virtual Mat load(int w, int h, int c, int type) const; + // load cube + virtual Mat load(int w, int h, int d, int c, int type) const; +}; + +class ModelBinFromDataReaderPrivate; +class NCNN_EXPORT ModelBinFromDataReader : public ModelBin +{ +public: + explicit ModelBinFromDataReader(const DataReader& dr); + virtual ~ModelBinFromDataReader(); + + virtual Mat load(int w, int type) const; + +private: + ModelBinFromDataReader(const ModelBinFromDataReader&); + ModelBinFromDataReader& operator=(const ModelBinFromDataReader&); + +private: + ModelBinFromDataReaderPrivate* const d; +}; + +class ModelBinFromMatArrayPrivate; +class NCNN_EXPORT ModelBinFromMatArray : public ModelBin +{ +public: + // construct from weight blob array + explicit ModelBinFromMatArray(const Mat* weights); + virtual ~ModelBinFromMatArray(); + + virtual Mat load(int w, int type) const; + +private: + ModelBinFromMatArray(const ModelBinFromMatArray&); + ModelBinFromMatArray& operator=(const ModelBinFromMatArray&); + +private: + ModelBinFromMatArrayPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_MODELBIN_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/ncnn_export.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/ncnn_export.h new file mode 100644 index 0000000..e2f5fde --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/ncnn_export.h @@ -0,0 +1,42 @@ + +#ifndef NCNN_EXPORT_H +#define NCNN_EXPORT_H + +#ifdef NCNN_STATIC_DEFINE +# define NCNN_EXPORT +# define NCNN_NO_EXPORT +#else +# ifndef NCNN_EXPORT +# ifdef ncnn_EXPORTS + /* We are building this library */ +# define NCNN_EXPORT __attribute__((visibility("default"))) +# else + /* We are using this library */ +# define NCNN_EXPORT __attribute__((visibility("default"))) +# endif +# endif + +# ifndef NCNN_NO_EXPORT +# define NCNN_NO_EXPORT __attribute__((visibility("hidden"))) +# endif +#endif + +#ifndef NCNN_DEPRECATED +# define NCNN_DEPRECATED __attribute__ ((__deprecated__)) +#endif + +#ifndef NCNN_DEPRECATED_EXPORT +# define NCNN_DEPRECATED_EXPORT NCNN_EXPORT NCNN_DEPRECATED +#endif + +#ifndef NCNN_DEPRECATED_NO_EXPORT +# define NCNN_DEPRECATED_NO_EXPORT NCNN_NO_EXPORT NCNN_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef NCNN_NO_DEPRECATED +# define NCNN_NO_DEPRECATED +# endif +#endif + +#endif /* NCNN_EXPORT_H */ diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/net.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/net.h new file mode 100644 index 0000000..98e3ec3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/net.h @@ -0,0 +1,274 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_NET_H +#define NCNN_NET_H + +#include "blob.h" +#include "layer.h" +#include "mat.h" +#include "option.h" +#include "platform.h" + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +#if NCNN_VULKAN +class VkCompute; +#endif // NCNN_VULKAN +class DataReader; +class Extractor; +class NetPrivate; +class NCNN_EXPORT Net +{ +public: + // empty init + Net(); + // clear and destroy + virtual ~Net(); + +public: + // option can be changed before loading + Option opt; + +#if NCNN_VULKAN + // set gpu device by index + void set_vulkan_device(int device_index); + + // set gpu device by device handle, no owner transfer + void set_vulkan_device(const VulkanDevice* vkdev); + + const VulkanDevice* vulkan_device() const; +#endif // NCNN_VULKAN + +#if NCNN_STRING + // register custom layer or overwrite built-in layer by layer type name + // return 0 if success + int register_custom_layer(const char* type, layer_creator_func creator, layer_destroyer_func destroyer = 0, void* userdata = 0); + virtual int custom_layer_to_index(const char* type); +#endif // NCNN_STRING + // register custom layer or overwrite built-in layer by layer type + // return 0 if success + int register_custom_layer(int index, layer_creator_func creator, layer_destroyer_func destroyer = 0, void* userdata = 0); + +#if NCNN_STRING + int load_param(const DataReader& dr); +#endif // NCNN_STRING + + int load_param_bin(const DataReader& dr); + + int load_model(const DataReader& dr); + +#if NCNN_STDIO +#if NCNN_STRING + // load network structure from plain param file + // return 0 if success + int load_param(FILE* fp); + int load_param(const char* protopath); + int load_param_mem(const char* mem); +#endif // NCNN_STRING + // load network structure from binary param file + // return 0 if success + int load_param_bin(FILE* fp); + int load_param_bin(const char* protopath); + + // load network weight data from model file + // return 0 if success + int load_model(FILE* fp); + int load_model(const char* modelpath); +#endif // NCNN_STDIO + + // load network structure from external memory + // memory pointer must be 32-bit aligned + // return bytes consumed + int load_param(const unsigned char* mem); + + // reference network weight data from external memory + // weight data is not copied but referenced + // so external memory should be retained when used + // memory pointer must be 32-bit aligned + // return bytes consumed + int load_model(const unsigned char* mem); + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#if NCNN_STRING + // convenient load network structure from android asset plain param file + int load_param(AAsset* asset); + int load_param(AAssetManager* mgr, const char* assetpath); +#endif // NCNN_STRING + // convenient load network structure from android asset binary param file + int load_param_bin(AAsset* asset); + int load_param_bin(AAssetManager* mgr, const char* assetpath); + + // convenient load network weight data from android asset model file + int load_model(AAsset* asset); + int load_model(AAssetManager* mgr, const char* assetpath); +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + + // unload network structure and weight data + void clear(); + + // construct an Extractor from network + Extractor create_extractor() const; + + // get input/output indexes/names + const std::vector& input_indexes() const; + const std::vector& output_indexes() const; +#if NCNN_STRING + const std::vector& input_names() const; + const std::vector& output_names() const; +#endif + + const std::vector& blobs() const; + const std::vector& layers() const; + + std::vector& mutable_blobs(); + std::vector& mutable_layers(); + +protected: + friend class Extractor; +#if NCNN_STRING + int find_blob_index_by_name(const char* name) const; + int find_layer_index_by_name(const char* name) const; + virtual Layer* create_custom_layer(const char* type); + virtual Layer* create_overwrite_builtin_layer(const char* type); +#endif // NCNN_STRING + virtual Layer* create_custom_layer(int index); + virtual Layer* create_overwrite_builtin_layer(int typeindex); + +private: + Net(const Net&); + Net& operator=(const Net&); + +private: + NetPrivate* const d; +}; + +class ExtractorPrivate; +class NCNN_EXPORT Extractor +{ +public: + virtual ~Extractor(); + + // copy + Extractor(const Extractor&); + + // assign + Extractor& operator=(const Extractor&); + + // clear blob mats and alloctors + void clear(); + + // enable light mode + // intermediate blob will be recycled when enabled + // enabled by default + void set_light_mode(bool enable); + + // set thread count for this extractor + // this will overwrite the global setting + // default count is system depended + void set_num_threads(int num_threads); + + // set blob memory allocator + void set_blob_allocator(Allocator* allocator); + + // set workspace memory allocator + void set_workspace_allocator(Allocator* allocator); + +#if NCNN_VULKAN + void set_vulkan_compute(bool enable); + + void set_blob_vkallocator(VkAllocator* allocator); + + void set_workspace_vkallocator(VkAllocator* allocator); + + void set_staging_vkallocator(VkAllocator* allocator); +#endif // NCNN_VULKAN + +#if NCNN_STRING + // set input by blob name + // return 0 if success + int input(const char* blob_name, const Mat& in); + + // get result by blob name + // return 0 if success + // type = 0, default + // type = 1, do not convert fp16/bf16 or / and packing + int extract(const char* blob_name, Mat& feat, int type = 0); +#endif // NCNN_STRING + + // set input by blob index + // return 0 if success + int input(int blob_index, const Mat& in); + + // get result by blob index + // return 0 if success + // type = 0, default + // type = 1, do not convert fp16/bf16 or / and packing + int extract(int blob_index, Mat& feat, int type = 0); + +#if NCNN_VULKAN +#if NCNN_STRING + // set input by blob name + // return 0 if success + int input(const char* blob_name, const VkMat& in); + + // get result by blob name + // return 0 if success + int extract(const char* blob_name, VkMat& feat, VkCompute& cmd); + + // set input by blob name + // return 0 if success + int input(const char* blob_name, const VkImageMat& in); + + // get result by blob name + // return 0 if success + int extract(const char* blob_name, VkImageMat& feat, VkCompute& cmd); +#endif // NCNN_STRING + + // set input by blob index + // return 0 if success + int input(int blob_index, const VkMat& in); + + // get result by blob index + // return 0 if success + int extract(int blob_index, VkMat& feat, VkCompute& cmd); + + // set input by blob index + // return 0 if success + int input(int blob_index, const VkImageMat& in); + + // get result by blob index + // return 0 if success + int extract(int blob_index, VkImageMat& feat, VkCompute& cmd); +#endif // NCNN_VULKAN + +protected: + friend Extractor Net::create_extractor() const; + Extractor(const Net* net, size_t blob_count); + +private: + ExtractorPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_NET_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/option.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/option.h new file mode 100644 index 0000000..7d0cc60 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/option.h @@ -0,0 +1,156 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_OPTION_H +#define NCNN_OPTION_H + +#include "platform.h" + +namespace ncnn { + +#if NCNN_VULKAN +class VkAllocator; +class PipelineCache; +#endif // NCNN_VULKAN + +class Allocator; +class NCNN_EXPORT Option +{ +public: + // default option + Option(); + +public: + // light mode + // intermediate blob will be recycled when enabled + // enabled by default + bool lightmode; + + // thread count + // default value is the one returned by get_cpu_count() + int num_threads; + + // blob memory allocator + Allocator* blob_allocator; + + // workspace memory allocator + Allocator* workspace_allocator; + +#if NCNN_VULKAN + // blob memory allocator + VkAllocator* blob_vkallocator; + + // workspace memory allocator + VkAllocator* workspace_vkallocator; + + // staging memory allocator + VkAllocator* staging_vkallocator; + + // pipeline cache + PipelineCache* pipeline_cache; +#endif // NCNN_VULKAN + + // the time openmp threads busy-wait for more work before going to sleep + // default value is 20ms to keep the cores enabled + // without too much extra power consumption afterwards + int openmp_blocktime; + + // enable winograd convolution optimization + // improve convolution 3x3 stride1 performance, may consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_winograd_convolution; + + // enable sgemm convolution optimization + // improve convolution 1x1 stride1 performance, may consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_sgemm_convolution; + + // enable quantized int8 inference + // use low-precision int8 path for quantized model + // changes should be applied before loading network structure and weight + // enabled by default + bool use_int8_inference; + + // enable vulkan compute + bool use_vulkan_compute; + + // enable bf16 data type for storage + // improve most operator performance on all arm devices, may consume more memory + bool use_bf16_storage; + + // enable options for gpu inference + bool use_fp16_packed; + bool use_fp16_storage; + bool use_fp16_arithmetic; + bool use_int8_packed; + bool use_int8_storage; + bool use_int8_arithmetic; + + // enable simd-friendly packed memory layout + // improve all operator performance on all arm devices, will consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_packing_layout; + + bool use_shader_pack8; + + // subgroup option + bool use_subgroup_basic; + bool use_subgroup_vote; + bool use_subgroup_ballot; + bool use_subgroup_shuffle; + + // turn on for adreno + bool use_image_storage; + bool use_tensor_storage; + + bool use_reserved_0; + + // enable DAZ(Denormals-Are-Zero) and FTZ(Flush-To-Zero) + // default value is 3 + // 0 = DAZ OFF, FTZ OFF + // 1 = DAZ ON , FTZ OFF + // 2 = DAZ OFF, FTZ ON + // 3 = DAZ ON, FTZ ON + int flush_denormals; + + bool use_local_pool_allocator; + + // enable local memory optimization for gpu inference + bool use_shader_local_memory; + + // enable cooperative matrix optimization for gpu inference + bool use_cooperative_matrix; + + // more fine-grained control of winograd convolution + bool use_winograd23_convolution; + bool use_winograd43_convolution; + bool use_winograd63_convolution; + + // this option is turned on for A53/A55 automatically + // but you can force this on/off if you wish + bool use_a53_a55_optimized_kernel; + + bool use_reserved_7; + bool use_reserved_8; + bool use_reserved_9; + bool use_reserved_10; + bool use_reserved_11; +}; + +} // namespace ncnn + +#endif // NCNN_OPTION_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/paramdict.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/paramdict.h new file mode 100644 index 0000000..c2ef160 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/paramdict.h @@ -0,0 +1,73 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PARAMDICT_H +#define NCNN_PARAMDICT_H + +#include "mat.h" + +// at most 32 parameters +#define NCNN_MAX_PARAM_COUNT 32 + +namespace ncnn { + +class DataReader; +class Net; +class ParamDictPrivate; +class NCNN_EXPORT ParamDict +{ +public: + // empty + ParamDict(); + + virtual ~ParamDict(); + + // copy + ParamDict(const ParamDict&); + + // assign + ParamDict& operator=(const ParamDict&); + + // get type + int type(int id) const; + + // get int + int get(int id, int def) const; + // get float + float get(int id, float def) const; + // get array + Mat get(int id, const Mat& def) const; + + // set int + void set(int id, int i); + // set float + void set(int id, float f); + // set array + void set(int id, const Mat& v); + +protected: + friend class Net; + + void clear(); + + int load_param(const DataReader& dr); + int load_param_bin(const DataReader& dr); + +private: + ParamDictPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_PARAMDICT_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/pipeline.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/pipeline.h new file mode 100644 index 0000000..c284a14 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/pipeline.h @@ -0,0 +1,113 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PIPELINE_H +#define NCNN_PIPELINE_H + +#include "mat.h" +#include "platform.h" +#if NCNN_VULKAN +#include "gpu.h" + +#include +#endif // NCNN_VULKAN + +namespace ncnn { + +#if NCNN_VULKAN +class Option; +class PipelinePrivate; +class NCNN_EXPORT Pipeline +{ +public: + explicit Pipeline(const VulkanDevice* vkdev); + virtual ~Pipeline(); + +public: + void set_optimal_local_size_xyz(int w = 4, int h = 4, int c = 4); + void set_optimal_local_size_xyz(const Mat& local_size_xyz); + void set_local_size_xyz(int w, int h, int c); + + int create(const uint32_t* spv_data, size_t spv_data_size, const std::vector& specializations); + + int create(int shader_type_index, const Option& opt, const std::vector& specializations); + +public: + VkShaderModule shader_module() const; + VkDescriptorSetLayout descriptorset_layout() const; + VkPipelineLayout pipeline_layout() const; + VkPipeline pipeline() const; + VkDescriptorUpdateTemplateKHR descriptor_update_template() const; + + const ShaderInfo& shader_info() const; + + uint32_t local_size_x() const; + uint32_t local_size_y() const; + uint32_t local_size_z() const; + +protected: + void set_shader_module(VkShaderModule shader_module); + void set_descriptorset_layout(VkDescriptorSetLayout descriptorset_layout); + void set_pipeline_layout(VkPipelineLayout pipeline_layout); + void set_pipeline(VkPipeline pipeline); + void set_descriptor_update_template(VkDescriptorUpdateTemplateKHR descriptor_update_template); + + void set_shader_info(const ShaderInfo& shader_info); + +public: + const VulkanDevice* vkdev; + +private: + Pipeline(const Pipeline&); + Pipeline& operator=(const Pipeline&); + +private: + PipelinePrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class VkCompute; +class NCNN_EXPORT ImportAndroidHardwareBufferPipeline : private Pipeline +{ +public: + explicit ImportAndroidHardwareBufferPipeline(const VulkanDevice* vkdev); + virtual ~ImportAndroidHardwareBufferPipeline(); + + int create(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator, int type_to, int rotate_from, const Option& opt); + int create(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator, int type_to, int rotate_from, int target_width, int target_height, const Option& opt); + void destroy(); + + friend class VkCompute; + +protected: + int create_shader_module(const Option& opt); + int create_sampler(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator); + int create_descriptorset_layout(); + +public: + int type_to; + int rotate_from; + bool need_resize; + + VkSampler sampler; +}; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_PIPELINE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/pipelinecache.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/pipelinecache.h new file mode 100644 index 0000000..bb6b8fb --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/pipelinecache.h @@ -0,0 +1,85 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PIPELINECACHE_H +#define NCNN_PIPELINECACHE_H + +#include "platform.h" + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#include "mat.h" +#include "gpu.h" + +namespace ncnn { + +#if NCNN_VULKAN + +class VulkanDevice; +class PipelineCachePrivate; +class NCNN_EXPORT PipelineCache +{ +public: + explicit PipelineCache(const VulkanDevice* _vkdev); + + virtual ~PipelineCache(); + + void clear(); + + int get_pipeline(const uint32_t* spv_data, size_t spv_data_size, const std::vector& specializations, + uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* shader_module, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template, + ShaderInfo& shader_info) const; + + int get_pipeline(int shader_type_index, const Option& opt, const std::vector& specializations, + uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* shader_module, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template, + ShaderInfo& shader_info) const; + +protected: + int create_shader_module(int shader_type_index, const Option& opt, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* _shader_module, ShaderInfo& si) const; + + int new_pipeline(VkShaderModule shader_module, const ShaderInfo& shader_info, const std::vector& specializations, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template) const; + +protected: + const VulkanDevice* vkdev; + +private: + PipelineCache(const PipelineCache&); + PipelineCache& operator=(const PipelineCache&); + +private: + PipelineCachePrivate* const d; +}; + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_PIPELINECACHE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/platform.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/platform.h new file mode 100644 index 0000000..46dc3b0 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/platform.h @@ -0,0 +1,293 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PLATFORM_H +#define NCNN_PLATFORM_H + +#define NCNN_STDIO 1 +#define NCNN_STRING 1 +#define NCNN_SIMPLEOCV 0 +#define NCNN_SIMPLEOMP 0 +#define NCNN_SIMPLESTL 0 +#define NCNN_SIMPLEMATH 0 +#define NCNN_THREADS 1 +#define NCNN_BENCHMARK 0 +#define NCNN_C_API 1 +#define NCNN_PLATFORM_API 1 +#define NCNN_PIXEL 1 +#define NCNN_PIXEL_ROTATE 1 +#define NCNN_PIXEL_AFFINE 1 +#define NCNN_PIXEL_DRAWING 1 +#define NCNN_VULKAN 0 +#define NCNN_SYSTEM_GLSLANG 0 +#define NCNN_RUNTIME_CPU 1 +#define NCNN_GNU_INLINE_ASM 1 +#define NCNN_AVX 0 +#define NCNN_XOP 0 +#define NCNN_FMA 0 +#define NCNN_F16C 0 +#define NCNN_AVX2 0 +#define NCNN_AVXVNNI 0 +#define NCNN_AVX512 0 +#define NCNN_AVX512VNNI 0 +#define NCNN_AVX512BF16 0 +#define NCNN_AVX512FP16 0 +#define NCNN_VFPV4 1 +#define NCNN_ARM82 0 +#define NCNN_ARM82DOT 0 +#define NCNN_ARM82FP16FML 0 +#define NCNN_ARM84BF16 0 +#define NCNN_ARM84I8MM 0 +#define NCNN_ARM86SVE 0 +#define NCNN_ARM86SVE2 0 +#define NCNN_ARM86SVEBF16 0 +#define NCNN_ARM86SVEI8MM 0 +#define NCNN_ARM86SVEF32MM 0 +#define NCNN_MSA 0 +#define NCNN_LSX 0 +#define NCNN_MMI 0 +#define NCNN_RVV 0 +#define NCNN_INT8 1 +#define NCNN_BF16 1 +#define NCNN_FORCE_INLINE 1 + +#define NCNN_VERSION_STRING "1.0.20231027" + +#include "ncnn_export.h" + +#ifdef __cplusplus + +#if NCNN_THREADS +#if (defined _WIN32 && !(defined __MINGW32__)) +#define WIN32_LEAN_AND_MEAN +#include +#include +#else +#include +#endif +#endif // NCNN_THREADS + +#if __ANDROID_API__ >= 26 +#define VK_USE_PLATFORM_ANDROID_KHR +#endif // __ANDROID_API__ >= 26 + +namespace ncnn { + +#if NCNN_THREADS +#if (defined _WIN32 && !(defined __MINGW32__)) +class NCNN_EXPORT Mutex +{ +public: + Mutex() { InitializeSRWLock(&srwlock); } + ~Mutex() {} + void lock() { AcquireSRWLockExclusive(&srwlock); } + void unlock() { ReleaseSRWLockExclusive(&srwlock); } +private: + friend class ConditionVariable; + // NOTE SRWLock is available from windows vista + SRWLOCK srwlock; +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() { InitializeConditionVariable(&condvar); } + ~ConditionVariable() {} + void wait(Mutex& mutex) { SleepConditionVariableSRW(&condvar, &mutex.srwlock, INFINITE, 0); } + void broadcast() { WakeAllConditionVariable(&condvar); } + void signal() { WakeConditionVariable(&condvar); } +private: + CONDITION_VARIABLE condvar; +}; + +static unsigned __stdcall start_wrapper(void* args); +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*start)(void*), void* args = 0) { _start = start; _args = args; handle = (HANDLE)_beginthreadex(0, 0, start_wrapper, this, 0, 0); } + ~Thread() {} + void join() { WaitForSingleObject(handle, INFINITE); CloseHandle(handle); } +private: + friend unsigned __stdcall start_wrapper(void* args) + { + Thread* t = (Thread*)args; + t->_start(t->_args); + return 0; + } + HANDLE handle; + void* (*_start)(void*); + void* _args; +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { key = TlsAlloc(); } + ~ThreadLocalStorage() { TlsFree(key); } + void set(void* value) { TlsSetValue(key, (LPVOID)value); } + void* get() { return (void*)TlsGetValue(key); } +private: + DWORD key; +}; +#else // (defined _WIN32 && !(defined __MINGW32__)) +class NCNN_EXPORT Mutex +{ +public: + Mutex() { pthread_mutex_init(&mutex, 0); } + ~Mutex() { pthread_mutex_destroy(&mutex); } + void lock() { pthread_mutex_lock(&mutex); } + void unlock() { pthread_mutex_unlock(&mutex); } +private: + friend class ConditionVariable; + pthread_mutex_t mutex; +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() { pthread_cond_init(&cond, 0); } + ~ConditionVariable() { pthread_cond_destroy(&cond); } + void wait(Mutex& mutex) { pthread_cond_wait(&cond, &mutex.mutex); } + void broadcast() { pthread_cond_broadcast(&cond); } + void signal() { pthread_cond_signal(&cond); } +private: + pthread_cond_t cond; +}; + +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*start)(void*), void* args = 0) { pthread_create(&t, 0, start, args); } + ~Thread() {} + void join() { pthread_join(t, 0); } +private: + pthread_t t; +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { pthread_key_create(&key, 0); } + ~ThreadLocalStorage() { pthread_key_delete(key); } + void set(void* value) { pthread_setspecific(key, value); } + void* get() { return pthread_getspecific(key); } +private: + pthread_key_t key; +}; +#endif // (defined _WIN32 && !(defined __MINGW32__)) +#else // NCNN_THREADS +class NCNN_EXPORT Mutex +{ +public: + Mutex() {} + ~Mutex() {} + void lock() {} + void unlock() {} +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() {} + ~ConditionVariable() {} + void wait(Mutex& /*mutex*/) {} + void broadcast() {} + void signal() {} +}; + +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*/*start*/)(void*), void* /*args*/ = 0) {} + ~Thread() {} + void join() {} +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { data = 0; } + ~ThreadLocalStorage() {} + void set(void* value) { data = value; } + void* get() { return data; } +private: + void* data; +}; +#endif // NCNN_THREADS + +class NCNN_EXPORT MutexLockGuard +{ +public: + MutexLockGuard(Mutex& _mutex) : mutex(_mutex) { mutex.lock(); } + ~MutexLockGuard() { mutex.unlock(); } +private: + Mutex& mutex; +}; + +} // namespace ncnn + +#if NCNN_SIMPLESTL +#include "simplestl.h" +#else +#include +#include +#include +#include +#endif + +// simplemath +#if NCNN_SIMPLEMATH +#include "simplemath.h" +#else +#include +#include +#endif + +#endif // __cplusplus + +#if NCNN_STDIO +#if NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#include +#define NCNN_LOGE(...) do { \ + fprintf(stderr, ##__VA_ARGS__); fprintf(stderr, "\n"); \ + __android_log_print(ANDROID_LOG_WARN, "ncnn", ##__VA_ARGS__); } while(0) +#else // NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#include +#define NCNN_LOGE(...) do { \ + fprintf(stderr, ##__VA_ARGS__); fprintf(stderr, "\n"); } while(0) +#endif // NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#else +#define NCNN_LOGE(...) +#endif + + +#if NCNN_FORCE_INLINE +#ifdef _MSC_VER + #define NCNN_FORCEINLINE __forceinline +#elif defined(__GNUC__) + #define NCNN_FORCEINLINE inline __attribute__((__always_inline__)) +#elif defined(__CLANG__) + #if __has_attribute(__always_inline__) + #define NCNN_FORCEINLINE inline __attribute__((__always_inline__)) + #else + #define NCNN_FORCEINLINE inline + #endif +#else + #define NCNN_FORCEINLINE inline +#endif +#else + #define NCNN_FORCEINLINE inline +#endif + +#endif // NCNN_PLATFORM_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/simplemath.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/simplemath.h new file mode 100644 index 0000000..fd7fa69 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/simplemath.h @@ -0,0 +1,102 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEMATH_H +#define NCNN_SIMPLEMATH_H + +#include "platform.h" + +#if NCNN_SIMPLEMATH + +#ifdef __cplusplus +extern "C" { +#endif +/* +* ==================================================== +* discrete functions +* ==================================================== +*/ +NCNN_EXPORT float fabs(float); +NCNN_EXPORT float fabsf(float); +NCNN_EXPORT float fmod(float, float); +NCNN_EXPORT float floor(float); +NCNN_EXPORT float floorf(float); +NCNN_EXPORT float round(float); +NCNN_EXPORT float roundf(float); +NCNN_EXPORT float ceil(float); +NCNN_EXPORT float ceilf(float); +NCNN_EXPORT float fmaxf(float, float); +NCNN_EXPORT float truncf(float); +NCNN_EXPORT float frac(float); +/* +* ==================================================== +* trigonometric functions +* ==================================================== +*/ +NCNN_EXPORT float sinf(float); +NCNN_EXPORT float cosf(float); +NCNN_EXPORT float tanf(float); +NCNN_EXPORT float asinf(float); +NCNN_EXPORT float acosf(float); +NCNN_EXPORT float atanf(float); +NCNN_EXPORT float atan2f(float, float); +NCNN_EXPORT float tanhf(float); + +/* +* ==================================================== +* power functions +* ==================================================== +*/ +NCNN_EXPORT float sqrtf(float); +NCNN_EXPORT float sqrt(float); +NCNN_EXPORT float powf(float, float); + +/* +* ==================================================== +* exponential and logarithm functions +* ==================================================== +*/ +NCNN_EXPORT float expf(float); +NCNN_EXPORT float frexp(float, int*); +NCNN_EXPORT float logf(float); +NCNN_EXPORT float log(float); +NCNN_EXPORT float log10f(float); + +/* +* ==================================================== +* probability functions +* ==================================================== +*/ +NCNN_EXPORT float erf(float); +NCNN_EXPORT float erfcf(float); + +/* +* ==================================================== +* other functions +* ==================================================== +*/ +NCNN_EXPORT int msb(unsigned int); +NCNN_EXPORT float fmaf(float, float, float); +NCNN_EXPORT float copysignf(float, float); +NCNN_EXPORT void fesetround(int); +NCNN_EXPORT int fegetround(); +NCNN_EXPORT float nearbyintf(float); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // NCNN_SIMPLEMATH + +#endif // NCNN_SIMPLEMATH_H \ No newline at end of file diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/simpleocv.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/simpleocv.h new file mode 100644 index 0000000..54b22d9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/simpleocv.h @@ -0,0 +1,503 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEOCV_H +#define NCNN_SIMPLEOCV_H + +#include "platform.h" + +#if NCNN_SIMPLEOCV + +#include +#include +#include "allocator.h" +#include "mat.h" + +#if defined(_MSC_VER) || defined(__GNUC__) +#pragma push_macro("min") +#pragma push_macro("max") +#undef min +#undef max +#endif + +#ifndef NCNN_XADD +using ncnn::NCNN_XADD; +#endif + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; + +enum +{ + CV_LOAD_IMAGE_UNCHANGED = -1, + CV_LOAD_IMAGE_GRAYSCALE = 0, + CV_LOAD_IMAGE_COLOR = 1, +}; + +enum +{ + CV_IMWRITE_JPEG_QUALITY = 1 +}; + +// minimal opencv style data structure implementation +namespace cv { + +template +static inline _Tp saturate_cast(int v) +{ + return _Tp(v); +} +template<> +inline uchar saturate_cast(int v) +{ + return (uchar)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); +} + +template +struct Scalar_ +{ + Scalar_() + { + v[0] = 0; + v[1] = 0; + v[2] = 0; + v[3] = 0; + } + Scalar_(_Tp _v0) + { + v[0] = _v0; + v[1] = 0; + v[2] = 0; + v[3] = 0; + } + Scalar_(_Tp _v0, _Tp _v1, _Tp _v2) + { + v[0] = _v0; + v[1] = _v1; + v[2] = _v2; + v[3] = 0; + } + Scalar_(_Tp _v0, _Tp _v1, _Tp _v2, _Tp _v3) + { + v[0] = _v0; + v[1] = _v1; + v[2] = _v2; + v[3] = _v3; + } + + const _Tp operator[](const int i) const + { + return v[i]; + } + + _Tp operator[](const int i) + { + return v[i]; + } + + _Tp v[4]; +}; + +typedef Scalar_ Scalar; + +template +struct Point_ +{ + Point_() + : x(0), y(0) + { + } + Point_(_Tp _x, _Tp _y) + : x(_x), y(_y) + { + } + + template + operator Point_<_Tp2>() const + { + return Point_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y)); + } + + _Tp x; + _Tp y; +}; + +typedef Point_ Point; +typedef Point_ Point2f; + +template +struct Size_ +{ + Size_() + : width(0), height(0) + { + } + Size_(_Tp _w, _Tp _h) + : width(_w), height(_h) + { + } + + template + operator Size_<_Tp2>() const + { + return Size_<_Tp2>(saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); + } + + _Tp width; + _Tp height; +}; + +typedef Size_ Size; +typedef Size_ Size2f; + +template +struct Rect_ +{ + Rect_() + : x(0), y(0), width(0), height(0) + { + } + Rect_(_Tp _x, _Tp _y, _Tp _w, _Tp _h) + : x(_x), y(_y), width(_w), height(_h) + { + } + Rect_(Point_<_Tp> _p, Size_<_Tp> _size) + : x(_p.x), y(_p.y), width(_size.width), height(_size.height) + { + } + + template + operator Rect_<_Tp2>() const + { + return Rect_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y), saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); + } + + _Tp x; + _Tp y; + _Tp width; + _Tp height; + + // area + _Tp area() const + { + return width * height; + } +}; + +template +static inline Rect_<_Tp>& operator&=(Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + _Tp x1 = std::max(a.x, b.x), y1 = std::max(a.y, b.y); + a.width = std::min(a.x + a.width, b.x + b.width) - x1; + a.height = std::min(a.y + a.height, b.y + b.height) - y1; + a.x = x1; + a.y = y1; + if (a.width <= 0 || a.height <= 0) + a = Rect_<_Tp>(); + return a; +} + +template +static inline Rect_<_Tp>& operator|=(Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + _Tp x1 = std::min(a.x, b.x), y1 = std::min(a.y, b.y); + a.width = std::max(a.x + a.width, b.x + b.width) - x1; + a.height = std::max(a.y + a.height, b.y + b.height) - y1; + a.x = x1; + a.y = y1; + return a; +} + +template +static inline Rect_<_Tp> operator&(const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c &= b; +} + +template +static inline Rect_<_Tp> operator|(const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c |= b; +} + +typedef Rect_ Rect; +typedef Rect_ Rect2f; + +#define CV_8UC1 1 +#define CV_8UC3 3 +#define CV_8UC4 4 +#define CV_32FC1 4 + +struct NCNN_EXPORT Mat +{ + Mat() + : data(0), refcount(0), rows(0), cols(0), c(0) + { + } + + Mat(int _rows, int _cols, int flags) + : data(0), refcount(0) + { + create(_rows, _cols, flags); + } + + // copy + Mat(const Mat& m) + : data(m.data), refcount(m.refcount) + { + if (refcount) + NCNN_XADD(refcount, 1); + + rows = m.rows; + cols = m.cols; + c = m.c; + } + + Mat(int _rows, int _cols, int flags, void* _data) + : data((unsigned char*)_data), refcount(0) + { + rows = _rows; + cols = _cols; + c = flags; + } + + ~Mat() + { + release(); + } + + // assign + Mat& operator=(const Mat& m) + { + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + + rows = m.rows; + cols = m.cols; + c = m.c; + + return *this; + } + + Mat& operator=(const Scalar& s) + { + if (total() > 0) + { + uchar* p = data; + for (int i = 0; i < cols * rows; i++) + { + for (int j = 0; j < c; j++) + { + *p++ = s[j]; + } + } + } + + return *this; + } + + void create(int _rows, int _cols, int flags) + { + release(); + + rows = _rows; + cols = _cols; + c = flags; + + if (total() > 0) + { + // refcount address must be aligned, so we expand totalsize here + size_t totalsize = (total() + 3) >> 2 << 2; + data = (uchar*)ncnn::fastMalloc(totalsize + (int)sizeof(*refcount)); + refcount = (int*)(((uchar*)data) + totalsize); + *refcount = 1; + } + } + + void release() + { + if (refcount && NCNN_XADD(refcount, -1) == 1) + ncnn::fastFree(data); + + data = 0; + + rows = 0; + cols = 0; + c = 0; + + refcount = 0; + } + + Mat clone() const + { + if (empty()) + return Mat(); + + Mat m(rows, cols, c); + + if (total() > 0) + { + memcpy(m.data, data, total()); + } + + return m; + } + + bool empty() const + { + return data == 0 || total() == 0; + } + + int channels() const + { + return c; + } + + int type() const + { + return c; + } + + size_t total() const + { + return cols * rows * c; + } + + const uchar* ptr(int y) const + { + return data + y * cols * c; + } + + uchar* ptr(int y) + { + return data + y * cols * c; + } + + template + const _Tp* ptr(int y) const + { + return (const _Tp*)data + y * cols * c; + } + + template + _Tp* ptr(int y) + { + return (_Tp*)data + y * cols * c; + } + + // roi + Mat operator()(const Rect& roi) const + { + if (empty()) + return Mat(); + + Mat m(roi.height, roi.width, c); + + int sy = roi.y; + for (int y = 0; y < roi.height; y++) + { + const uchar* sptr = ptr(sy) + roi.x * c; + uchar* dptr = m.ptr(y); + memcpy(dptr, sptr, roi.width * c); + sy++; + } + + return m; + } + + uchar* data; + + // pointer to the reference counter; + // when points to user-allocated data, the pointer is NULL + int* refcount; + + int rows; + int cols; + + int c; +}; + +enum ImreadModes +{ + IMREAD_UNCHANGED = -1, + IMREAD_GRAYSCALE = 0, + IMREAD_COLOR = 1 +}; + +NCNN_EXPORT Mat imread(const std::string& path, int flags = IMREAD_COLOR); + +NCNN_EXPORT Mat imdecode(const std::vector& buf, int flags = IMREAD_COLOR); + +enum ImwriteFlags +{ + IMWRITE_JPEG_QUALITY = 1 +}; + +NCNN_EXPORT bool imwrite(const std::string& path, const Mat& m, const std::vector& params = std::vector()); + +NCNN_EXPORT void imshow(const std::string& name, const Mat& m); + +NCNN_EXPORT int waitKey(int delay = 0); + +#if NCNN_PIXEL +NCNN_EXPORT void resize(const Mat& src, Mat& dst, const Size& size, float sw = 0.f, float sh = 0.f, int flags = 0); +#endif // NCNN_PIXEL + +#if NCNN_PIXEL_DRAWING + +enum +{ + FILLED = -1 +}; + +NCNN_EXPORT void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void rectangle(Mat& img, Rect rec, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void circle(Mat& img, Point center, int radius, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void line(Mat& img, Point p0, Point p1, const Scalar& color, int thickness = 1); + +enum +{ + FONT_HERSHEY_SIMPLEX = 0 +}; + +NCNN_EXPORT void putText(Mat& img, const std::string& text, Point org, int fontFace, double fontScale, Scalar color, int thickness = 1); + +NCNN_EXPORT Size getTextSize(const std::string& text, int fontFace, double fontScale, int thickness, int* baseLine); + +#endif // NCNN_PIXEL_DRAWING + +} // namespace cv + +#if defined(_MSC_VER) || defined(__GNUC__) +#pragma pop_macro("min") +#pragma pop_macro("max") +#endif + +#endif // NCNN_SIMPLEOCV + +#endif // NCNN_SIMPLEOCV_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/simpleomp.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/simpleomp.h new file mode 100644 index 0000000..13e2452 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/simpleomp.h @@ -0,0 +1,53 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEOMP_H +#define NCNN_SIMPLEOMP_H + +#include "platform.h" + +#if NCNN_SIMPLEOMP + +#include + +// This minimal openmp runtime implementation only supports the llvm openmp abi +// and only supports #pragma omp parallel for num_threads(X) + +#ifdef __cplusplus +extern "C" { +#endif + +NCNN_EXPORT int omp_get_max_threads(); + +NCNN_EXPORT void omp_set_num_threads(int num_threads); + +NCNN_EXPORT int omp_get_dynamic(); + +NCNN_EXPORT void omp_set_dynamic(int dynamic); + +NCNN_EXPORT int omp_get_num_threads(); + +NCNN_EXPORT int omp_get_thread_num(); + +NCNN_EXPORT int kmp_get_blocktime(); + +NCNN_EXPORT void kmp_set_blocktime(int blocktime); + +#ifdef __cplusplus +} +#endif + +#endif // NCNN_SIMPLEOMP + +#endif // NCNN_SIMPLEOMP_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/simplestl.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/simplestl.h new file mode 100644 index 0000000..00ff468 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/simplestl.h @@ -0,0 +1,565 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLESTL_H +#define NCNN_SIMPLESTL_H + +#include +#include +#include + +#if !NCNN_SIMPLESTL + +#include + +#else + +// allocation functions +NCNN_EXPORT void* operator new(size_t size); +NCNN_EXPORT void* operator new[](size_t size); +// placement allocation functions +NCNN_EXPORT void* operator new(size_t size, void* ptr); +NCNN_EXPORT void* operator new[](size_t size, void* ptr); +// deallocation functions +NCNN_EXPORT void operator delete(void* ptr); +NCNN_EXPORT void operator delete[](void* ptr); +// deallocation functions since c++14 +#if __cplusplus >= 201402L +NCNN_EXPORT void operator delete(void* ptr, size_t sz); +NCNN_EXPORT void operator delete[](void* ptr, size_t sz); +#endif +// placement deallocation functions +NCNN_EXPORT void operator delete(void* ptr, void* voidptr2); +NCNN_EXPORT void operator delete[](void* ptr, void* voidptr2); + +#endif + +// minimal stl data structure implementation +namespace std { + +template +const T& max(const T& a, const T& b) +{ + return (a < b) ? b : a; +} + +template +const T& min(const T& a, const T& b) +{ + return (a > b) ? b : a; +} + +template +void swap(T& a, T& b) +{ + T temp(a); + a = b; + b = temp; +} + +template +struct pair +{ + pair() + : first(), second() + { + } + pair(const T1& t1, const T2& t2) + : first(t1), second(t2) + { + } + + T1 first; + T2 second; +}; + +template +bool operator==(const pair& x, const pair& y) +{ + return (x.first == y.first && x.second == y.second); +} +template +bool operator<(const pair& x, const pair& y) +{ + return x.first < y.first || (!(y.first < x.first) && x.second < y.second); +} +template +bool operator!=(const pair& x, const pair& y) +{ + return !(x == y); +} +template +bool operator>(const pair& x, const pair& y) +{ + return y < x; +} +template +bool operator<=(const pair& x, const pair& y) +{ + return !(y < x); +} +template +bool operator>=(const pair& x, const pair& y) +{ + return !(x < y); +} + +template +pair make_pair(const T1& t1, const T2& t2) +{ + return pair(t1, t2); +} + +template +struct node +{ + node* prev_; + node* next_; + T data_; + + node() + : prev_(0), next_(0), data_() + { + } + node(const T& t) + : prev_(0), next_(0), data_(t) + { + } +}; + +template +struct iter_list +{ + iter_list() + : curr_(0) + { + } + iter_list(node* n) + : curr_(n) + { + } + iter_list(const iter_list& i) + : curr_(i.curr_) + { + } + ~iter_list() + { + } + + iter_list& operator=(const iter_list& i) + { + curr_ = i.curr_; + return *this; + } + + T& operator*() + { + return curr_->data_; + } + T* operator->() + { + return &(curr_->data_); + } + + bool operator==(const iter_list& i) + { + return curr_ == i.curr_; + } + bool operator!=(const iter_list& i) + { + return curr_ != i.curr_; + } + + iter_list& operator++() + { + curr_ = curr_->next_; + return *this; + } + iter_list& operator--() + { + curr_ = curr_->prev_; + return *this; + } + + node* curr_; +}; + +template +struct list +{ + typedef iter_list iterator; + + list() + { + head_ = new node(); + tail_ = head_; + count_ = 0; + } + ~list() + { + clear(); + delete head_; + } + list(const list& l) + { + head_ = new node(); + tail_ = head_; + count_ = 0; + + for (iter_list i = l.begin(); i != l.end(); ++i) + { + push_back(*i); + } + } + + list& operator=(const list& l) + { + if (this == &l) + { + return *this; + } + clear(); + + for (iter_list i = l.begin(); i != l.end(); ++i) + { + push_back(*i); + } + return *this; + } + + void clear() + { + while (count_ > 0) + { + pop_front(); + } + } + + void pop_front() + { + if (count_ > 0) + { + head_ = head_->next_; + delete head_->prev_; + head_->prev_ = 0; + --count_; + } + } + + size_t size() const + { + return count_; + } + iter_list begin() const + { + return iter_list(head_); + } + iter_list end() const + { + return iter_list(tail_); + } + bool empty() const + { + return count_ == 0; + } + + void push_back(const T& t) + { + if (count_ == 0) + { + head_ = new node(t); + head_->prev_ = 0; + head_->next_ = tail_; + tail_->prev_ = head_; + count_ = 1; + } + else + { + node* temp = new node(t); + temp->prev_ = tail_->prev_; + temp->next_ = tail_; + tail_->prev_->next_ = temp; + tail_->prev_ = temp; + ++count_; + } + } + + iter_list erase(iter_list pos) + { + if (pos != end()) + { + node* temp = pos.curr_; + if (temp == head_) + { + ++pos; + temp->next_->prev_ = 0; + head_ = temp->next_; + } + else + { + --pos; + temp->next_->prev_ = temp->prev_; + temp->prev_->next_ = temp->next_; + ++pos; + } + delete temp; + --count_; + } + return pos; + } + +protected: + node* head_; + node* tail_; + size_t count_; +}; + +template +struct greater +{ + bool operator()(const T& x, const T& y) const + { + return (x > y); + } +}; + +template +struct less +{ + bool operator()(const T& x, const T& y) const + { + return (x < y); + } +}; + +template +void partial_sort(RandomAccessIter first, RandomAccessIter middle, RandomAccessIter last, Compare comp) +{ + // [TODO] heap sort should be used here, but we simply use bubble sort now + for (RandomAccessIter i = first; i < middle; ++i) + { + // bubble sort + for (RandomAccessIter j = last - 1; j > first; --j) + { + if (comp(*j, *(j - 1))) + { + swap(*j, *(j - 1)); + } + } + } +} + +template +struct vector +{ + vector() + : data_(0), size_(0), capacity_(0) + { + } + vector(const size_t new_size, const T& value = T()) + : data_(0), size_(0), capacity_(0) + { + resize(new_size, value); + } + ~vector() + { + clear(); + } + vector(const vector& v) + : data_(0), size_(0), capacity_(0) + { + resize(v.size()); + for (size_t i = 0; i < size_; i++) + { + data_[i] = v.data_[i]; + } + } + + vector& operator=(const vector& v) + { + if (this == &v) + { + return *this; + } + resize(0); + resize(v.size()); + for (size_t i = 0; i < size_; i++) + { + data_[i] = v.data_[i]; + } + return *this; + } + + void resize(const size_t new_size, const T& value = T()) + { + try_alloc(new_size); + if (new_size > size_) + { + for (size_t i = size_; i < new_size; i++) + { + new (&data_[i]) T(value); + } + } + else if (new_size < size_) + { + for (size_t i = new_size; i < size_; i++) + { + data_[i].~T(); + } + } + size_ = new_size; + } + + void clear() + { + for (size_t i = 0; i < size_; i++) + { + data_[i].~T(); + } + delete[](char*) data_; + data_ = 0; + size_ = 0; + capacity_ = 0; + } + + T* data() const + { + return data_; + } + size_t size() const + { + return size_; + } + T& operator[](size_t i) const + { + return data_[i]; + } + T* begin() const + { + return &data_[0]; + } + T* end() const + { + return &data_[size_]; + } + bool empty() const + { + return size_ == 0; + } + + void push_back(const T& t) + { + try_alloc(size_ + 1); + new (&data_[size_]) T(t); + size_++; + } + + void insert(T* pos, T* b, T* e) + { + vector* v = 0; + if (b >= begin() && b < end()) + { + //the same vector + v = new vector(*this); + b = v->begin() + (b - begin()); + e = v->begin() + (e - begin()); + } + size_t diff = pos - begin(); + try_alloc(size_ + (e - b)); + pos = begin() + diff; + memmove(pos + (e - b), pos, (end() - pos) * sizeof(T)); + size_t len = e - b; + size_ += len; + for (size_t i = 0; i < len; i++) + { + *pos = *b; + pos++; + b++; + } + delete v; + } + + T* erase(T* pos) + { + pos->~T(); + memmove(pos, pos + 1, (end() - pos - 1) * sizeof(T)); + size_--; + return pos; + } + +protected: + T* data_; + size_t size_; + size_t capacity_; + void try_alloc(size_t new_size) + { + if (new_size * 3 / 2 > capacity_ / 2) + { + capacity_ = new_size * 2; + T* new_data = (T*)new char[capacity_ * sizeof(T)]; + memset(static_cast(new_data), 0, capacity_ * sizeof(T)); + if (data_) + { + memmove(new_data, data_, sizeof(T) * size_); + delete[](char*) data_; + } + data_ = new_data; + } + } +}; + +struct NCNN_EXPORT string : public vector +{ + string() + { + } + string(const char* str) + { + size_t len = strlen(str); + resize(len); + memcpy(data_, str, len); + } + const char* c_str() const + { + return (const char*)data_; + } + bool operator==(const string& str2) const + { + return strcmp(data_, str2.data_) == 0; + } + bool operator==(const char* str2) const + { + return strcmp(data_, str2) == 0; + } + bool operator!=(const char* str2) const + { + return strcmp(data_, str2) != 0; + } + string& operator+=(const string& str1) + { + insert(end(), str1.begin(), str1.end()); + return *this; + } +}; + +inline string operator+(const string& str1, const string& str2) +{ + string str(str1); + str.insert(str.end(), str2.begin(), str2.end()); + return str; +} + +} // namespace std + +#endif // NCNN_SIMPLESTL_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/vulkan_header_fix.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/vulkan_header_fix.h new file mode 100644 index 0000000..0a5ea9b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/include/ncnn/vulkan_header_fix.h @@ -0,0 +1,449 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_VULKAN_HEADER_FIX_H +#define NCNN_VULKAN_HEADER_FIX_H + +#include + +// This header contains new structure and function declearation to fix build with old vulkan sdk + +#if VK_HEADER_VERSION < 70 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES (VkStructureType)1000094000 +typedef enum VkSubgroupFeatureFlagBits +{ + VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001, + VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002, + VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004, + VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008, + VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010, + VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020, + VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040, + VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080, + VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 0x00000100, + VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubgroupFeatureFlagBits; +typedef VkFlags VkSubgroupFeatureFlags; +typedef struct VkPhysicalDeviceSubgroupProperties +{ + VkStructureType sType; + void* pNext; + uint32_t subgroupSize; + VkShaderStageFlags supportedStages; + VkSubgroupFeatureFlags supportedOperations; + VkBool32 quadOperationsInAllStages; +} VkPhysicalDeviceSubgroupProperties; +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES (VkStructureType)1000168000 +#define VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT (VkStructureType)1000168001 +typedef struct VkPhysicalDeviceMaintenance3Properties +{ + VkStructureType sType; + void* pNext; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceMaintenance3Properties; +typedef struct VkDescriptorSetLayoutSupport +{ + VkStructureType sType; + void* pNext; + VkBool32 supported; +} VkDescriptorSetLayoutSupport; +typedef VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; +typedef VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; +typedef void(VKAPI_PTR* PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); +#endif // VK_HEADER_VERSION < 70 + +#if VK_HEADER_VERSION < 80 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR (VkStructureType)1000177000 +typedef struct VkPhysicalDevice8BitStorageFeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; +} VkPhysicalDevice8BitStorageFeaturesKHR; +#define VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR (VkStructureType)1000109000 +#define VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR (VkStructureType)1000109001 +#define VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR (VkStructureType)1000109002 +#define VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR (VkStructureType)1000109003 +#define VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR (VkStructureType)1000109004 +#define VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR (VkStructureType)1000109005 +#define VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR (VkStructureType)1000109006 +typedef struct VkAttachmentDescription2KHR +{ + VkStructureType sType; + const void* pNext; + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription2KHR; +typedef struct VkAttachmentReference2KHR +{ + VkStructureType sType; + const void* pNext; + uint32_t attachment; + VkImageLayout layout; + VkImageAspectFlags aspectMask; +} VkAttachmentReference2KHR; +typedef struct VkSubpassDescription2KHR +{ + VkStructureType sType; + const void* pNext; + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t viewMask; + uint32_t inputAttachmentCount; + const VkAttachmentReference2KHR* pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference2KHR* pColorAttachments; + const VkAttachmentReference2KHR* pResolveAttachments; + const VkAttachmentReference2KHR* pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t* pPreserveAttachments; +} VkSubpassDescription2KHR; +typedef struct VkSubpassDependency2KHR +{ + VkStructureType sType; + const void* pNext; + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; + int32_t viewOffset; +} VkSubpassDependency2KHR; +typedef struct VkRenderPassCreateInfo2KHR +{ + VkStructureType sType; + const void* pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription2KHR* pAttachments; + uint32_t subpassCount; + const VkSubpassDescription2KHR* pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency2KHR* pDependencies; + uint32_t correlatedViewMaskCount; + const uint32_t* pCorrelatedViewMasks; +} VkRenderPassCreateInfo2KHR; +typedef struct VkSubpassBeginInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkSubpassContents contents; +} VkSubpassBeginInfoKHR; + +typedef struct VkSubpassEndInfoKHR +{ + VkStructureType sType; + const void* pNext; +} VkSubpassEndInfoKHR; +typedef VkResult(VKAPI_PTR* PFN_vkCreateRenderPass2KHR)(VkDevice device, const VkRenderPassCreateInfo2KHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void(VKAPI_PTR* PFN_vkCmdBeginRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfoKHR* pSubpassBeginInfo); +typedef void(VKAPI_PTR* PFN_vkCmdNextSubpass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfoKHR* pSubpassBeginInfo, const VkSubpassEndInfoKHR* pSubpassEndInfo); +typedef void(VKAPI_PTR* PFN_vkCmdEndRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassEndInfoKHR* pSubpassEndInfo); +#endif // VK_HEADER_VERSION < 80 + +#if VK_HEADER_VERSION < 95 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR (VkStructureType)1000082000 +typedef struct VkPhysicalDeviceFloat16Int8FeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; +} VkPhysicalDeviceFloat16Int8FeaturesKHR; +#endif // VK_HEADER_VERSION < 95 + +#if VK_HEADER_VERSION < 97 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT (VkStructureType)1000237000 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT (VkStructureType)1000238000 +#define VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT (VkStructureType)1000238001 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT (VkStructureType)1000244000 +#define VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_EXT (VkStructureType)1000244001 +#define VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT (VkStructureType)1000244002 +#define VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT (VkStructureType)1000247000 +#define VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT (VkBufferCreateFlagBits)0x00020000 +#define VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT (VkBufferUsageFlagBits)0x00020000 +typedef uint64_t VkDeviceAddress; +typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT +{ + VkStructureType sType; + void* pNext; + VkDeviceSize heapBudget[VK_MAX_MEMORY_HEAPS]; + VkDeviceSize heapUsage[VK_MAX_MEMORY_HEAPS]; +} VkPhysicalDeviceMemoryBudgetPropertiesEXT; +typedef struct VkPhysicalDeviceMemoryPriorityFeaturesEXT +{ + VkStructureType sType; + void* pNext; + VkBool32 memoryPriority; +} VkPhysicalDeviceMemoryPriorityFeaturesEXT; +typedef struct VkMemoryPriorityAllocateInfoEXT +{ + VkStructureType sType; + const void* pNext; + float priority; +} VkMemoryPriorityAllocateInfoEXT; +typedef struct VkPhysicalDeviceBufferAddressFeaturesEXT +{ + VkStructureType sType; + void* pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferAddressFeaturesEXT; +typedef struct VkBufferDeviceAddressInfoEXT +{ + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferDeviceAddressInfoEXT; +typedef struct VkBufferDeviceAddressCreateInfoEXT +{ + VkStructureType sType; + const void* pNext; + VkDeviceSize deviceAddress; +} VkBufferDeviceAddressCreateInfoEXT; +typedef VkDeviceAddress(VKAPI_PTR* PFN_vkGetBufferDeviceAddressEXT)(VkDevice device, const VkBufferDeviceAddressInfoEXT* pInfo); +typedef enum VkValidationFeatureEnableEXT +{ + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT = 0, + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT = 1, + VK_VALIDATION_FEATURE_ENABLE_BEGIN_RANGE_EXT = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT, + VK_VALIDATION_FEATURE_ENABLE_END_RANGE_EXT = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT, + VK_VALIDATION_FEATURE_ENABLE_RANGE_SIZE_EXT = (VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT - VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT + 1), + VK_VALIDATION_FEATURE_ENABLE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationFeatureEnableEXT; +typedef enum VkValidationFeatureDisableEXT +{ + VK_VALIDATION_FEATURE_DISABLE_ALL_EXT = 0, + VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT = 1, + VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT = 2, + VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT = 3, + VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT = 4, + VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT = 5, + VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT = 6, + VK_VALIDATION_FEATURE_DISABLE_BEGIN_RANGE_EXT = VK_VALIDATION_FEATURE_DISABLE_ALL_EXT, + VK_VALIDATION_FEATURE_DISABLE_END_RANGE_EXT = VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT, + VK_VALIDATION_FEATURE_DISABLE_RANGE_SIZE_EXT = (VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT - VK_VALIDATION_FEATURE_DISABLE_ALL_EXT + 1), + VK_VALIDATION_FEATURE_DISABLE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationFeatureDisableEXT; +typedef struct VkValidationFeaturesEXT +{ + VkStructureType sType; + const void* pNext; + uint32_t enabledValidationFeatureCount; + const VkValidationFeatureEnableEXT* pEnabledValidationFeatures; + uint32_t disabledValidationFeatureCount; + const VkValidationFeatureDisableEXT* pDisabledValidationFeatures; +} VkValidationFeaturesEXT; +#endif // VK_HEADER_VERSION < 97 + +#if VK_HEADER_VERSION < 101 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV (VkStructureType)1000249000 +#define VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV (VkStructureType)1000249001 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV (VkStructureType)1000249002 +typedef enum VkComponentTypeNV +{ + VK_COMPONENT_TYPE_FLOAT16_NV = 0, + VK_COMPONENT_TYPE_FLOAT32_NV = 1, + VK_COMPONENT_TYPE_FLOAT64_NV = 2, + VK_COMPONENT_TYPE_SINT8_NV = 3, + VK_COMPONENT_TYPE_SINT16_NV = 4, + VK_COMPONENT_TYPE_SINT32_NV = 5, + VK_COMPONENT_TYPE_SINT64_NV = 6, + VK_COMPONENT_TYPE_UINT8_NV = 7, + VK_COMPONENT_TYPE_UINT16_NV = 8, + VK_COMPONENT_TYPE_UINT32_NV = 9, + VK_COMPONENT_TYPE_UINT64_NV = 10, + VK_COMPONENT_TYPE_BEGIN_RANGE_NV = VK_COMPONENT_TYPE_FLOAT16_NV, + VK_COMPONENT_TYPE_END_RANGE_NV = VK_COMPONENT_TYPE_UINT64_NV, + VK_COMPONENT_TYPE_RANGE_SIZE_NV = (VK_COMPONENT_TYPE_UINT64_NV - VK_COMPONENT_TYPE_FLOAT16_NV + 1), + VK_COMPONENT_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkComponentTypeNV; +typedef enum VkScopeNV +{ + VK_SCOPE_DEVICE_NV = 1, + VK_SCOPE_WORKGROUP_NV = 2, + VK_SCOPE_SUBGROUP_NV = 3, + VK_SCOPE_QUEUE_FAMILY_NV = 5, + VK_SCOPE_BEGIN_RANGE_NV = VK_SCOPE_DEVICE_NV, + VK_SCOPE_END_RANGE_NV = VK_SCOPE_QUEUE_FAMILY_NV, + VK_SCOPE_RANGE_SIZE_NV = (VK_SCOPE_QUEUE_FAMILY_NV - VK_SCOPE_DEVICE_NV + 1), + VK_SCOPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkScopeNV; +typedef struct VkCooperativeMatrixPropertiesNV +{ + VkStructureType sType; + void* pNext; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeNV AType; + VkComponentTypeNV BType; + VkComponentTypeNV CType; + VkComponentTypeNV DType; + VkScopeNV scope; +} VkCooperativeMatrixPropertiesNV; +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesNV +{ + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesNV; +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesNV +{ + VkStructureType sType; + void* pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesNV; +typedef VkResult(VKAPI_PTR* PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixPropertiesNV* pProperties); +#endif // VK_HEADER_VERSION < 101 + +#if VK_HEADER_VERSION < 121 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD (VkStructureType)1000229000 +#define VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD (VkMemoryPropertyFlagBits)0x00000040 +#define VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD (VkMemoryPropertyFlagBits)0x00000040 +typedef struct VkPhysicalDeviceCoherentMemoryFeaturesAMD +{ + VkStructureType sType; + void* pNext; + VkBool32 deviceCoherentMemory; +} VkPhysicalDeviceCoherentMemoryFeaturesAMD; +#endif // VK_HEADER_VERSION < 121 + +#if VK_HEADER_VERSION < 129 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR (VkStructureType)1000257000 +#define VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR (VkStructureType)1000244001 +#define VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO_KHR (VkStructureType)1000257002 +#define VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO_KHR (VkStructureType)1000257003 +#define VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO_KHR (VkStructureType)1000257004 +#define VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR (VkBufferCreateFlagBits)0x00020000 +#define VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR (VkBufferUsageFlagBits)0x00020000 +#define VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR (VkMemoryAllocateFlagBits)0x00000002 +#define VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR (VkMemoryAllocateFlagBits)0x00000004 +typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferDeviceAddressFeaturesKHR; +typedef struct VkBufferDeviceAddressInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferDeviceAddressInfoKHR; +typedef struct VkBufferOpaqueCaptureAddressCreateInfoKHR +{ + VkStructureType sType; + const void* pNext; + uint64_t opaqueCaptureAddress; +} VkBufferOpaqueCaptureAddressCreateInfoKHR; +typedef struct VkMemoryOpaqueCaptureAddressAllocateInfoKHR +{ + VkStructureType sType; + const void* pNext; + uint64_t opaqueCaptureAddress; +} VkMemoryOpaqueCaptureAddressAllocateInfoKHR; +typedef struct VkDeviceMemoryOpaqueCaptureAddressInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; +} VkDeviceMemoryOpaqueCaptureAddressInfoKHR; +typedef VkDeviceAddress(VKAPI_PTR* PFN_vkGetBufferDeviceAddressKHR)(VkDevice device, const VkBufferDeviceAddressInfoKHR* pInfo); +typedef uint64_t(VKAPI_PTR* PFN_vkGetBufferOpaqueCaptureAddressKHR)(VkDevice device, const VkBufferDeviceAddressInfoKHR* pInfo); +typedef uint64_t(VKAPI_PTR* PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR)(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfoKHR* pInfo); +#endif // VK_HEADER_VERSION < 129 + +#if VK_HEADER_VERSION < 208 +typedef enum VkInstanceCreateFlagBits +{ + VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR = 0x00000001, + VK_INSTANCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkInstanceCreateFlagBits; +#endif // VK_HEADER_VERSION < 208 + +#if VK_HEADER_VERSION < 255 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR (VkStructureType)1000506000 +#define VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_KHR (VkStructureType)1000506001 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR (VkStructureType)1000506002 +typedef enum VkComponentTypeKHR +{ + VK_COMPONENT_TYPE_FLOAT16_KHR = 0, + VK_COMPONENT_TYPE_FLOAT32_KHR = 1, + VK_COMPONENT_TYPE_FLOAT64_KHR = 2, + VK_COMPONENT_TYPE_SINT8_KHR = 3, + VK_COMPONENT_TYPE_SINT16_KHR = 4, + VK_COMPONENT_TYPE_SINT32_KHR = 5, + VK_COMPONENT_TYPE_SINT64_KHR = 6, + VK_COMPONENT_TYPE_UINT8_KHR = 7, + VK_COMPONENT_TYPE_UINT16_KHR = 8, + VK_COMPONENT_TYPE_UINT32_KHR = 9, + VK_COMPONENT_TYPE_UINT64_KHR = 10, + VK_COMPONENT_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkComponentTypeKHR; +typedef enum VkScopeKHR +{ + VK_SCOPE_DEVICE_KHR = 1, + VK_SCOPE_WORKGROUP_KHR = 2, + VK_SCOPE_SUBGROUP_KHR = 3, + VK_SCOPE_QUEUE_FAMILY_KHR = 5, + VK_SCOPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkScopeKHR; +typedef struct VkCooperativeMatrixPropertiesKHR +{ + VkStructureType sType; + void* pNext; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeKHR AType; + VkComponentTypeKHR BType; + VkComponentTypeKHR CType; + VkComponentTypeKHR ResultType; + VkBool32 saturatingAccumulation; + VkScopeKHR scope; +} VkCooperativeMatrixPropertiesKHR; +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesKHR; +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesKHR +{ + VkStructureType sType; + void* pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesKHR; +typedef VkResult(VKAPI_PTR* PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixPropertiesKHR* pProperties); +#endif // VK_HEADER_VERSION < 255 + +#endif // NCNN_VULKAN_HEADER_FIX_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/lib/cmake/ncnn/ncnn-release.cmake b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/lib/cmake/ncnn/ncnn-release.cmake new file mode 100644 index 0000000..1fb8660 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/lib/cmake/ncnn/ncnn-release.cmake @@ -0,0 +1,19 @@ +#---------------------------------------------------------------- +# Generated CMake target import file for configuration "Release". +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "ncnn" for configuration "Release" +set_property(TARGET ncnn APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(ncnn PROPERTIES + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libncnn.so" + IMPORTED_SONAME_RELEASE "libncnn.so" + ) + +list(APPEND _cmake_import_check_targets ncnn ) +list(APPEND _cmake_import_check_files_for_ncnn "${_IMPORT_PREFIX}/lib/libncnn.so" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/lib/cmake/ncnn/ncnn.cmake b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/lib/cmake/ncnn/ncnn.cmake new file mode 100644 index 0000000..6726e95 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/lib/cmake/ncnn/ncnn.cmake @@ -0,0 +1,109 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8) + message(FATAL_ERROR "CMake >= 2.8.0 required") +endif() +if(CMAKE_VERSION VERSION_LESS "2.8.3") + message(FATAL_ERROR "CMake >= 2.8.3 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.8.3...3.25) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_cmake_targets_defined "") +set(_cmake_targets_not_defined "") +set(_cmake_expected_targets "") +foreach(_cmake_expected_target IN ITEMS ncnn) + list(APPEND _cmake_expected_targets "${_cmake_expected_target}") + if(TARGET "${_cmake_expected_target}") + list(APPEND _cmake_targets_defined "${_cmake_expected_target}") + else() + list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") + endif() +endforeach() +unset(_cmake_expected_target) +if(_cmake_targets_defined STREQUAL _cmake_expected_targets) + unset(_cmake_targets_defined) + unset(_cmake_targets_not_defined) + unset(_cmake_expected_targets) + unset(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT _cmake_targets_defined STREQUAL "") + string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") + string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") +endif() +unset(_cmake_targets_defined) +unset(_cmake_targets_not_defined) +unset(_cmake_expected_targets) + + +# Compute the installation prefix relative to this file. +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +if(_IMPORT_PREFIX STREQUAL "/") + set(_IMPORT_PREFIX "") +endif() + +# Create imported target ncnn +add_library(ncnn SHARED IMPORTED) + +set_target_properties(ncnn PROPERTIES + INTERFACE_COMPILE_OPTIONS "-fno-rtti;-fno-exceptions" + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include/ncnn" + INTERFACE_LINK_LIBRARIES "-fopenmp;-static-openmp;-Wl,-wrap,__kmp_affinity_determine_capable;Threads::Threads;android;jnigraphics;log" + INTERFACE_POSITION_INDEPENDENT_CODE "ON" +) + +if(CMAKE_VERSION VERSION_LESS 2.8.12) + message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.") +endif() + +# Load information for each installed configuration. +file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/ncnn-*.cmake") +foreach(_cmake_config_file IN LISTS _cmake_config_files) + include("${_cmake_config_file}") +endforeach() +unset(_cmake_config_file) +unset(_cmake_config_files) + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(_cmake_target IN LISTS _cmake_import_check_targets) + foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}") + if(NOT EXISTS "${_cmake_file}") + message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file + \"${_cmake_file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + unset(_cmake_file) + unset("_cmake_import_check_files_for_${_cmake_target}") +endforeach() +unset(_cmake_target) +unset(_cmake_import_check_targets) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/lib/cmake/ncnn/ncnnConfig.cmake b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/lib/cmake/ncnn/ncnnConfig.cmake new file mode 100644 index 0000000..d3ac286 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/lib/cmake/ncnn/ncnnConfig.cmake @@ -0,0 +1,42 @@ +set(NCNN_OPENMP ON) +set(NCNN_THREADS ON) +set(NCNN_VULKAN OFF) +set(NCNN_SHARED_LIB ON) +set(NCNN_SYSTEM_GLSLANG OFF) + +if(NCNN_OPENMP) + find_package(OpenMP) +endif() + +if(NCNN_THREADS) + set(CMAKE_THREAD_PREFER_PTHREAD TRUE) + set(THREADS_PREFER_PTHREAD_FLAG TRUE) + find_package(Threads REQUIRED) +endif() + +if(NCNN_VULKAN) + find_package(Vulkan REQUIRED) + + if(NOT NCNN_SHARED_LIB) + if(NCNN_SYSTEM_GLSLANG) + find_package(glslang QUIET) + if(NOT glslang_FOUND) + set(GLSLANG_TARGET_DIR "") + include(${GLSLANG_TARGET_DIR}/OSDependentTargets.cmake) + include(${GLSLANG_TARGET_DIR}/OGLCompilerTargets.cmake) + if(EXISTS "${GLSLANG_TARGET_DIR}/HLSLTargets.cmake") + # hlsl support can be optional + include("${GLSLANG_TARGET_DIR}/HLSLTargets.cmake") + endif() + include(${GLSLANG_TARGET_DIR}/glslangTargets.cmake) + include(${GLSLANG_TARGET_DIR}/SPIRVTargets.cmake) + endif() + else() + set(glslang_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../lib/cmake/glslang") + find_package(glslang QUIET) + endif() + + endif() +endif() + +include(${CMAKE_CURRENT_LIST_DIR}/ncnn.cmake) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/lib/pkgconfig/ncnn.pc b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/lib/pkgconfig/ncnn.pc new file mode 100644 index 0000000..4e80236 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/armeabi-v7a/lib/pkgconfig/ncnn.pc @@ -0,0 +1,11 @@ +prefix=${pcfiledir}/../.. +librarydir=${prefix}/lib +includedir=${prefix}/include + +Name: ncnn +Description: high-performance neural network inference framework optimized for the mobile platform +Version: 1.0.20231027 +URL: https://github.com/Tencent/ncnn +Libs: -L"${librarydir}" -lncnn +Cflags: -I"${includedir}" + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/allocator.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/allocator.h new file mode 100644 index 0000000..3a5ebca --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/allocator.h @@ -0,0 +1,448 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_ALLOCATOR_H +#define NCNN_ALLOCATOR_H + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include "platform.h" + +#include + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +#include +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +// the alignment of all the allocated buffers +#if NCNN_AVX512 +#define NCNN_MALLOC_ALIGN 64 +#elif NCNN_AVX +#define NCNN_MALLOC_ALIGN 32 +#else +#define NCNN_MALLOC_ALIGN 16 +#endif + +// we have some optimized kernels that may overread buffer a bit in loop +// it is common to interleave next-loop data load with arithmetic instructions +// allocating more bytes keeps us safe from SEGV_ACCERR failure +#define NCNN_MALLOC_OVERREAD 64 + +// Aligns a pointer to the specified number of bytes +// ptr Aligned pointer +// n Alignment size that must be a power of two +template +static NCNN_FORCEINLINE _Tp* alignPtr(_Tp* ptr, int n = (int)sizeof(_Tp)) +{ + return (_Tp*)(((size_t)ptr + n - 1) & -n); +} + +// Aligns a buffer size to the specified number of bytes +// The function returns the minimum number that is greater or equal to sz and is divisible by n +// sz Buffer size to align +// n Alignment size that must be a power of two +static NCNN_FORCEINLINE size_t alignSize(size_t sz, int n) +{ + return (sz + n - 1) & -n; +} + +static NCNN_FORCEINLINE void* fastMalloc(size_t size) +{ +#if _MSC_VER + return _aligned_malloc(size, NCNN_MALLOC_ALIGN); +#elif (defined(__unix__) || defined(__APPLE__)) && _POSIX_C_SOURCE >= 200112L || (__ANDROID__ && __ANDROID_API__ >= 17) + void* ptr = 0; + if (posix_memalign(&ptr, NCNN_MALLOC_ALIGN, size + NCNN_MALLOC_OVERREAD)) + ptr = 0; + return ptr; +#elif __ANDROID__ && __ANDROID_API__ < 17 + return memalign(NCNN_MALLOC_ALIGN, size + NCNN_MALLOC_OVERREAD); +#else + unsigned char* udata = (unsigned char*)malloc(size + sizeof(void*) + NCNN_MALLOC_ALIGN + NCNN_MALLOC_OVERREAD); + if (!udata) + return 0; + unsigned char** adata = alignPtr((unsigned char**)udata + 1, NCNN_MALLOC_ALIGN); + adata[-1] = udata; + return adata; +#endif +} + +static NCNN_FORCEINLINE void fastFree(void* ptr) +{ + if (ptr) + { +#if _MSC_VER + _aligned_free(ptr); +#elif (defined(__unix__) || defined(__APPLE__)) && _POSIX_C_SOURCE >= 200112L || (__ANDROID__ && __ANDROID_API__ >= 17) + free(ptr); +#elif __ANDROID__ && __ANDROID_API__ < 17 + free(ptr); +#else + unsigned char* udata = ((unsigned char**)ptr)[-1]; + free(udata); +#endif + } +} + +#if NCNN_THREADS +// exchange-add operation for atomic operations on reference counters +#if defined __riscv && !defined __riscv_atomic +// riscv target without A extension +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#elif defined __INTEL_COMPILER && !(defined WIN32 || defined _WIN32) +// atomic increment on the linux version of the Intel(tm) compiler +#define NCNN_XADD(addr, delta) (int)_InterlockedExchangeAdd(const_cast(reinterpret_cast(addr)), delta) +#elif defined __GNUC__ +#if defined __clang__ && __clang_major__ >= 3 && !defined __ANDROID__ && !defined __EMSCRIPTEN__ && !defined(__CUDACC__) +#ifdef __ATOMIC_ACQ_REL +#define NCNN_XADD(addr, delta) __c11_atomic_fetch_add((_Atomic(int)*)(addr), delta, __ATOMIC_ACQ_REL) +#else +#define NCNN_XADD(addr, delta) __atomic_fetch_add((_Atomic(int)*)(addr), delta, 4) +#endif +#else +#if defined __ATOMIC_ACQ_REL && !defined __clang__ +// version for gcc >= 4.7 +#define NCNN_XADD(addr, delta) (int)__atomic_fetch_add((unsigned*)(addr), (unsigned)(delta), __ATOMIC_ACQ_REL) +#else +#define NCNN_XADD(addr, delta) (int)__sync_fetch_and_add((unsigned*)(addr), (unsigned)(delta)) +#endif +#endif +#elif defined _MSC_VER && !defined RC_INVOKED +#define NCNN_XADD(addr, delta) (int)_InterlockedExchangeAdd((long volatile*)addr, delta) +#else +// thread-unsafe branch +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#endif +#else // NCNN_THREADS +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#endif // NCNN_THREADS + +class NCNN_EXPORT Allocator +{ +public: + virtual ~Allocator(); + virtual void* fastMalloc(size_t size) = 0; + virtual void fastFree(void* ptr) = 0; +}; + +class PoolAllocatorPrivate; +class NCNN_EXPORT PoolAllocator : public Allocator +{ +public: + PoolAllocator(); + ~PoolAllocator(); + + // ratio range 0 ~ 1 + // default cr = 0 + void set_size_compare_ratio(float scr); + + // budget drop threshold + // default threshold = 10 + void set_size_drop_threshold(size_t); + + // release all budgets immediately + void clear(); + + virtual void* fastMalloc(size_t size); + virtual void fastFree(void* ptr); + +private: + PoolAllocator(const PoolAllocator&); + PoolAllocator& operator=(const PoolAllocator&); + +private: + PoolAllocatorPrivate* const d; +}; + +class UnlockedPoolAllocatorPrivate; +class NCNN_EXPORT UnlockedPoolAllocator : public Allocator +{ +public: + UnlockedPoolAllocator(); + ~UnlockedPoolAllocator(); + + // ratio range 0 ~ 1 + // default cr = 0 + void set_size_compare_ratio(float scr); + + // budget drop threshold + // default threshold = 10 + void set_size_drop_threshold(size_t); + + // release all budgets immediately + void clear(); + + virtual void* fastMalloc(size_t size); + virtual void fastFree(void* ptr); + +private: + UnlockedPoolAllocator(const UnlockedPoolAllocator&); + UnlockedPoolAllocator& operator=(const UnlockedPoolAllocator&); + +private: + UnlockedPoolAllocatorPrivate* const d; +}; + +#if NCNN_VULKAN + +class VulkanDevice; + +class NCNN_EXPORT VkBufferMemory +{ +public: + VkBuffer buffer; + + // the base offset assigned by allocator + size_t offset; + size_t capacity; + + VkDeviceMemory memory; + void* mapped_ptr; + + // buffer state, modified by command functions internally + mutable VkAccessFlags access_flags; + mutable VkPipelineStageFlags stage_flags; + + // initialize and modified by mat + int refcount; +}; + +class NCNN_EXPORT VkImageMemory +{ +public: + VkImage image; + VkImageView imageview; + + // underlying info assigned by allocator + int width; + int height; + int depth; + VkFormat format; + + VkDeviceMemory memory; + void* mapped_ptr; + + // the base offset assigned by allocator + size_t bind_offset; + size_t bind_capacity; + + // image state, modified by command functions internally + mutable VkAccessFlags access_flags; + mutable VkImageLayout image_layout; + mutable VkPipelineStageFlags stage_flags; + + // in-execution state, modified by command functions internally + mutable int command_refcount; + + // initialize and modified by mat + int refcount; +}; + +class NCNN_EXPORT VkAllocator +{ +public: + explicit VkAllocator(const VulkanDevice* _vkdev); + virtual ~VkAllocator(); + + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size) = 0; + virtual void fastFree(VkBufferMemory* ptr) = 0; + virtual int flush(VkBufferMemory* ptr); + virtual int invalidate(VkBufferMemory* ptr); + + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack) = 0; + virtual void fastFree(VkImageMemory* ptr) = 0; + +public: + const VulkanDevice* vkdev; + uint32_t buffer_memory_type_index; + uint32_t image_memory_type_index; + uint32_t reserved_type_index; + bool mappable; + bool coherent; + +protected: + VkBuffer create_buffer(size_t size, VkBufferUsageFlags usage); + VkDeviceMemory allocate_memory(size_t size, uint32_t memory_type_index); + VkDeviceMemory allocate_dedicated_memory(size_t size, uint32_t memory_type_index, VkImage image, VkBuffer buffer); + + VkImage create_image(int width, int height, int depth, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage); + VkImageView create_imageview(VkImage image, VkFormat format); +}; + +class VkBlobAllocatorPrivate; +class NCNN_EXPORT VkBlobAllocator : public VkAllocator +{ +public: + explicit VkBlobAllocator(const VulkanDevice* vkdev, size_t preferred_block_size = 16 * 1024 * 1024); // 16M + virtual ~VkBlobAllocator(); + +public: + // release all budgets immediately + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkBlobAllocator(const VkBlobAllocator&); + VkBlobAllocator& operator=(const VkBlobAllocator&); + +private: + VkBlobAllocatorPrivate* const d; +}; + +class VkWeightAllocatorPrivate; +class NCNN_EXPORT VkWeightAllocator : public VkAllocator +{ +public: + explicit VkWeightAllocator(const VulkanDevice* vkdev, size_t preferred_block_size = 8 * 1024 * 1024); // 8M + virtual ~VkWeightAllocator(); + +public: + // release all blocks immediately + virtual void clear(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkWeightAllocator(const VkWeightAllocator&); + VkWeightAllocator& operator=(const VkWeightAllocator&); + +private: + VkWeightAllocatorPrivate* const d; +}; + +class VkStagingAllocatorPrivate; +class NCNN_EXPORT VkStagingAllocator : public VkAllocator +{ +public: + explicit VkStagingAllocator(const VulkanDevice* vkdev); + virtual ~VkStagingAllocator(); + +public: + // ratio range 0 ~ 1 + // default cr = 0.75 + void set_size_compare_ratio(float scr); + + // release all budgets immediately + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkStagingAllocator(const VkStagingAllocator&); + VkStagingAllocator& operator=(const VkStagingAllocator&); + +private: + VkStagingAllocatorPrivate* const d; +}; + +class VkWeightStagingAllocatorPrivate; +class NCNN_EXPORT VkWeightStagingAllocator : public VkAllocator +{ +public: + explicit VkWeightStagingAllocator(const VulkanDevice* vkdev); + virtual ~VkWeightStagingAllocator(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkWeightStagingAllocator(const VkWeightStagingAllocator&); + VkWeightStagingAllocator& operator=(const VkWeightStagingAllocator&); + +private: + VkWeightStagingAllocatorPrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class NCNN_EXPORT VkAndroidHardwareBufferImageAllocator : public VkAllocator +{ +public: + VkAndroidHardwareBufferImageAllocator(const VulkanDevice* _vkdev, AHardwareBuffer* _hb); + virtual ~VkAndroidHardwareBufferImageAllocator(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkAndroidHardwareBufferImageAllocator(const VkAndroidHardwareBufferImageAllocator&); + VkAndroidHardwareBufferImageAllocator& operator=(const VkAndroidHardwareBufferImageAllocator&); + +public: + int init(); + + int width() const; + int height() const; + uint64_t external_format() const; + +public: + AHardwareBuffer* hb; + AHardwareBuffer_Desc bufferDesc; + VkAndroidHardwareBufferFormatPropertiesANDROID bufferFormatProperties; + VkAndroidHardwareBufferPropertiesANDROID bufferProperties; + VkSamplerYcbcrConversionKHR samplerYcbcrConversion; +}; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_ALLOCATOR_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/benchmark.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/benchmark.h new file mode 100644 index 0000000..ed42c1a --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/benchmark.h @@ -0,0 +1,39 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_BENCHMARK_H +#define NCNN_BENCHMARK_H + +#include "layer.h" +#include "mat.h" +#include "platform.h" + +namespace ncnn { + +// get now timestamp in ms +NCNN_EXPORT double get_current_time(); + +// sleep milliseconds +NCNN_EXPORT void sleep(unsigned long long int milliseconds = 1000); + +#if NCNN_BENCHMARK + +NCNN_EXPORT void benchmark(const Layer* layer, double start, double end); +NCNN_EXPORT void benchmark(const Layer* layer, const Mat& bottom_blob, Mat& top_blob, double start, double end); + +#endif // NCNN_BENCHMARK + +} // namespace ncnn + +#endif // NCNN_BENCHMARK_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/blob.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/blob.h new file mode 100644 index 0000000..c9f144f --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/blob.h @@ -0,0 +1,44 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_BLOB_H +#define NCNN_BLOB_H + +#include "mat.h" +#include "platform.h" + +namespace ncnn { + +class NCNN_EXPORT Blob +{ +public: + // empty + Blob(); + +public: +#if NCNN_STRING + // blob name + std::string name; +#endif // NCNN_STRING + // layer index which produce this blob as output + int producer; + // layer index which need this blob as input + int consumer; + // shape hint + Mat shape; +}; + +} // namespace ncnn + +#endif // NCNN_BLOB_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/c_api.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/c_api.h new file mode 100644 index 0000000..31d5b6d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/c_api.h @@ -0,0 +1,347 @@ +/* Tencent is pleased to support the open source community by making ncnn available. + * + * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef NCNN_C_API_H +#define NCNN_C_API_H + +#include "platform.h" + +#if NCNN_C_API + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +NCNN_EXPORT const char* ncnn_version(); + +/* allocator api */ +typedef struct __ncnn_allocator_t* ncnn_allocator_t; +struct NCNN_EXPORT __ncnn_allocator_t +{ + void* pthis; + + void* (*fast_malloc)(ncnn_allocator_t allocator, size_t size); + void (*fast_free)(ncnn_allocator_t allocator, void* ptr); +}; + +NCNN_EXPORT ncnn_allocator_t ncnn_allocator_create_pool_allocator(); +NCNN_EXPORT ncnn_allocator_t ncnn_allocator_create_unlocked_pool_allocator(); +NCNN_EXPORT void ncnn_allocator_destroy(ncnn_allocator_t allocator); + +/* option api */ +typedef struct __ncnn_option_t* ncnn_option_t; + +NCNN_EXPORT ncnn_option_t ncnn_option_create(); +NCNN_EXPORT void ncnn_option_destroy(ncnn_option_t opt); + +NCNN_EXPORT int ncnn_option_get_num_threads(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_num_threads(ncnn_option_t opt, int num_threads); + +NCNN_EXPORT int ncnn_option_get_use_local_pool_allocator(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_use_local_pool_allocator(ncnn_option_t opt, int use_local_pool_allocator); + +NCNN_EXPORT void ncnn_option_set_blob_allocator(ncnn_option_t opt, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_option_set_workspace_allocator(ncnn_option_t opt, ncnn_allocator_t allocator); + +NCNN_EXPORT int ncnn_option_get_use_vulkan_compute(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_use_vulkan_compute(ncnn_option_t opt, int use_vulkan_compute); + +/* mat api */ +typedef struct __ncnn_mat_t* ncnn_mat_t; + +NCNN_EXPORT ncnn_mat_t ncnn_mat_create(); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_1d(int w, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_2d(int w, int h, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_3d(int w, int h, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_4d(int w, int h, int d, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_1d(int w, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_2d(int w, int h, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_3d(int w, int h, int c, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_4d(int w, int h, int d, int c, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_1d_elem(int w, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_2d_elem(int w, int h, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_3d_elem(int w, int h, int c, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_4d_elem(int w, int h, int d, int c, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_1d_elem(int w, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_2d_elem(int w, int h, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_3d_elem(int w, int h, int c, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_4d_elem(int w, int h, int d, int c, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_mat_destroy(ncnn_mat_t mat); + +NCNN_EXPORT void ncnn_mat_fill_float(ncnn_mat_t mat, float v); + +NCNN_EXPORT ncnn_mat_t ncnn_mat_clone(const ncnn_mat_t mat, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_1d(const ncnn_mat_t mat, int w, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_2d(const ncnn_mat_t mat, int w, int h, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_3d(const ncnn_mat_t mat, int w, int h, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_4d(const ncnn_mat_t mat, int w, int h, int d, int c, ncnn_allocator_t allocator); + +NCNN_EXPORT int ncnn_mat_get_dims(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_w(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_h(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_d(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_c(const ncnn_mat_t mat); +NCNN_EXPORT size_t ncnn_mat_get_elemsize(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_elempack(const ncnn_mat_t mat); +NCNN_EXPORT size_t ncnn_mat_get_cstep(const ncnn_mat_t mat); +NCNN_EXPORT void* ncnn_mat_get_data(const ncnn_mat_t mat); + +NCNN_EXPORT void* ncnn_mat_get_channel_data(const ncnn_mat_t mat, int c); + +#if NCNN_PIXEL + +/* mat pixel api */ +#define NCNN_MAT_PIXEL_RGB 1 +#define NCNN_MAT_PIXEL_BGR 2 +#define NCNN_MAT_PIXEL_GRAY 3 +#define NCNN_MAT_PIXEL_RGBA 4 +#define NCNN_MAT_PIXEL_BGRA 5 +#define NCNN_MAT_PIXEL_X2Y(X, Y) (X | (Y << 16)) +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels(const unsigned char* pixels, int type, int w, int h, int stride, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, int target_width, int target_height, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_mat_to_pixels(const ncnn_mat_t mat, unsigned char* pixels, int type, int stride); +NCNN_EXPORT void ncnn_mat_to_pixels_resize(const ncnn_mat_t mat, unsigned char* pixels, int type, int target_width, int target_height, int target_stride); + +#endif /* NCNN_PIXEL */ + +NCNN_EXPORT void ncnn_mat_substract_mean_normalize(ncnn_mat_t mat, const float* mean_vals, const float* norm_vals); + +NCNN_EXPORT void ncnn_convert_packing(const ncnn_mat_t src, ncnn_mat_t* dst, int elempack, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_flatten(const ncnn_mat_t src, ncnn_mat_t* dst, const ncnn_option_t opt); + +/* blob api */ +typedef struct __ncnn_blob_t* ncnn_blob_t; + +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_blob_get_name(const ncnn_blob_t blob); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_blob_get_producer(const ncnn_blob_t blob); +NCNN_EXPORT int ncnn_blob_get_consumer(const ncnn_blob_t blob); + +NCNN_EXPORT void ncnn_blob_get_shape(const ncnn_blob_t blob, int* dims, int* w, int* h, int* c); + +/* paramdict api */ +typedef struct __ncnn_paramdict_t* ncnn_paramdict_t; + +NCNN_EXPORT ncnn_paramdict_t ncnn_paramdict_create(); +NCNN_EXPORT void ncnn_paramdict_destroy(ncnn_paramdict_t pd); + +NCNN_EXPORT int ncnn_paramdict_get_type(const ncnn_paramdict_t pd, int id); + +NCNN_EXPORT int ncnn_paramdict_get_int(const ncnn_paramdict_t pd, int id, int def); +NCNN_EXPORT float ncnn_paramdict_get_float(const ncnn_paramdict_t pd, int id, float def); +NCNN_EXPORT ncnn_mat_t ncnn_paramdict_get_array(const ncnn_paramdict_t pd, int id, const ncnn_mat_t def); + +NCNN_EXPORT void ncnn_paramdict_set_int(ncnn_paramdict_t pd, int id, int i); +NCNN_EXPORT void ncnn_paramdict_set_float(ncnn_paramdict_t pd, int id, float f); +NCNN_EXPORT void ncnn_paramdict_set_array(ncnn_paramdict_t pd, int id, const ncnn_mat_t v); + +/* datareader api */ +typedef struct __ncnn_datareader_t* ncnn_datareader_t; +struct NCNN_EXPORT __ncnn_datareader_t +{ + void* pthis; + +#if NCNN_STRING + int (*scan)(ncnn_datareader_t dr, const char* format, void* p); +#endif /* NCNN_STRING */ + size_t (*read)(ncnn_datareader_t dr, void* buf, size_t size); +}; + +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create(); +#if NCNN_STDIO +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create_from_stdio(FILE* fp); +#endif /* NCNN_STDIO */ +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create_from_memory(const unsigned char** mem); +NCNN_EXPORT void ncnn_datareader_destroy(ncnn_datareader_t dr); + +/* modelbin api */ +typedef struct __ncnn_modelbin_t* ncnn_modelbin_t; +struct NCNN_EXPORT __ncnn_modelbin_t +{ + void* pthis; + + ncnn_mat_t (*load_1d)(const ncnn_modelbin_t mb, int w, int type); + ncnn_mat_t (*load_2d)(const ncnn_modelbin_t mb, int w, int h, int type); + ncnn_mat_t (*load_3d)(const ncnn_modelbin_t mb, int w, int h, int c, int type); +}; + +NCNN_EXPORT ncnn_modelbin_t ncnn_modelbin_create_from_datareader(const ncnn_datareader_t dr); +NCNN_EXPORT ncnn_modelbin_t ncnn_modelbin_create_from_mat_array(const ncnn_mat_t* weights, int n); +NCNN_EXPORT void ncnn_modelbin_destroy(ncnn_modelbin_t mb); + +/* layer api */ +typedef struct __ncnn_layer_t* ncnn_layer_t; +struct NCNN_EXPORT __ncnn_layer_t +{ + void* pthis; + + int (*load_param)(ncnn_layer_t layer, const ncnn_paramdict_t pd); + int (*load_model)(ncnn_layer_t layer, const ncnn_modelbin_t mb); + + int (*create_pipeline)(ncnn_layer_t layer, const ncnn_option_t opt); + int (*destroy_pipeline)(ncnn_layer_t layer, const ncnn_option_t opt); + + int (*forward_1)(const ncnn_layer_t layer, const ncnn_mat_t bottom_blob, ncnn_mat_t* top_blob, const ncnn_option_t opt); + int (*forward_n)(const ncnn_layer_t layer, const ncnn_mat_t* bottom_blobs, int n, ncnn_mat_t* top_blobs, int n2, const ncnn_option_t opt); + + int (*forward_inplace_1)(const ncnn_layer_t layer, ncnn_mat_t bottom_top_blob, const ncnn_option_t opt); + int (*forward_inplace_n)(const ncnn_layer_t layer, ncnn_mat_t* bottom_top_blobs, int n, const ncnn_option_t opt); +}; + +NCNN_EXPORT ncnn_layer_t ncnn_layer_create(); +NCNN_EXPORT ncnn_layer_t ncnn_layer_create_by_typeindex(int typeindex); +#if NCNN_STRING +NCNN_EXPORT ncnn_layer_t ncnn_layer_create_by_type(const char* type); +NCNN_EXPORT int ncnn_layer_type_to_index(const char* type); +#endif /* NCNN_STRING */ +NCNN_EXPORT void ncnn_layer_destroy(ncnn_layer_t layer); + +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_layer_get_name(const ncnn_layer_t layer); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_layer_get_typeindex(const ncnn_layer_t layer); +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_layer_get_type(const ncnn_layer_t layer); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_layer_get_one_blob_only(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_inplace(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_vulkan(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_packing(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_bf16_storage(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_fp16_storage(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_image_storage(const ncnn_layer_t layer); + +NCNN_EXPORT void ncnn_layer_set_one_blob_only(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_inplace(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_vulkan(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_packing(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_bf16_storage(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_fp16_storage(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_image_storage(ncnn_layer_t layer, int enable); + +NCNN_EXPORT int ncnn_layer_get_bottom_count(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_bottom(const ncnn_layer_t layer, int i); +NCNN_EXPORT int ncnn_layer_get_top_count(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_top(const ncnn_layer_t layer, int i); + +NCNN_EXPORT void ncnn_blob_get_bottom_shape(const ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c); +NCNN_EXPORT void ncnn_blob_get_top_shape(const ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c); + +/* layer factory function */ +typedef ncnn_layer_t (*ncnn_layer_creator_t)(void* userdata); +typedef void (*ncnn_layer_destroyer_t)(ncnn_layer_t layer, void* userdata); + +typedef struct __ncnn_net_custom_layer_factory_t* ncnn_net_custom_layer_factory_t; +struct __ncnn_net_custom_layer_factory_t +{ + ncnn_layer_creator_t creator; + ncnn_layer_destroyer_t destroyer; + void* userdata; + ncnn_net_custom_layer_factory_t next; +}; + +/* net api */ +typedef struct __ncnn_net_t* ncnn_net_t; +struct __ncnn_net_t +{ + void* pthis; + + ncnn_net_custom_layer_factory_t custom_layer_factory; +}; + +NCNN_EXPORT ncnn_net_t ncnn_net_create(); +NCNN_EXPORT void ncnn_net_destroy(ncnn_net_t net); + +NCNN_EXPORT ncnn_option_t ncnn_net_get_option(ncnn_net_t net); +NCNN_EXPORT void ncnn_net_set_option(ncnn_net_t net, ncnn_option_t opt); + +#if NCNN_STRING +NCNN_EXPORT void ncnn_net_register_custom_layer_by_type(ncnn_net_t net, const char* type, ncnn_layer_creator_t creator, ncnn_layer_destroyer_t destroyer, void* userdata); +#endif /* NCNN_STRING */ +NCNN_EXPORT void ncnn_net_register_custom_layer_by_typeindex(ncnn_net_t net, int typeindex, ncnn_layer_creator_t creator, ncnn_layer_destroyer_t destroyer, void* userdata); + +#if NCNN_STDIO +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param(ncnn_net_t net, const char* path); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_load_param_bin(ncnn_net_t net, const char* path); +NCNN_EXPORT int ncnn_net_load_model(ncnn_net_t net, const char* path); +#endif /* NCNN_STDIO */ + +#if NCNN_STDIO +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param_memory(ncnn_net_t net, const char* mem); +#endif /* NCNN_STRING */ +#endif /* NCNN_STDIO */ +NCNN_EXPORT int ncnn_net_load_param_bin_memory(ncnn_net_t net, const unsigned char* mem); +NCNN_EXPORT int ncnn_net_load_model_memory(ncnn_net_t net, const unsigned char* mem); + +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param_datareader(ncnn_net_t net, const ncnn_datareader_t dr); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_load_param_bin_datareader(ncnn_net_t net, const ncnn_datareader_t dr); +NCNN_EXPORT int ncnn_net_load_model_datareader(ncnn_net_t net, const ncnn_datareader_t dr); + +NCNN_EXPORT void ncnn_net_clear(ncnn_net_t net); + +NCNN_EXPORT int ncnn_net_get_input_count(const ncnn_net_t net); +NCNN_EXPORT int ncnn_net_get_output_count(const ncnn_net_t net); +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_net_get_input_name(const ncnn_net_t net, int i); +NCNN_EXPORT const char* ncnn_net_get_output_name(const ncnn_net_t net, int i); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_get_input_index(const ncnn_net_t net, int i); +NCNN_EXPORT int ncnn_net_get_output_index(const ncnn_net_t net, int i); + +/* extractor api */ +typedef struct __ncnn_extractor_t* ncnn_extractor_t; + +NCNN_EXPORT ncnn_extractor_t ncnn_extractor_create(ncnn_net_t net); +NCNN_EXPORT void ncnn_extractor_destroy(ncnn_extractor_t ex); + +NCNN_EXPORT void ncnn_extractor_set_option(ncnn_extractor_t ex, const ncnn_option_t opt); + +#if NCNN_STRING +NCNN_EXPORT int ncnn_extractor_input(ncnn_extractor_t ex, const char* name, const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_extractor_extract(ncnn_extractor_t ex, const char* name, ncnn_mat_t* mat); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_extractor_input_index(ncnn_extractor_t ex, int index, const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_extractor_extract_index(ncnn_extractor_t ex, int index, ncnn_mat_t* mat); + +/* mat process api */ +#define NCNN_BORDER_CONSTANT 0 +#define NCNN_BORDER_REPLICATE 1 +#define NCNN_BORDER_REFLECT 2 +#define NCNN_BORDER_TRANSPARENT -233 +NCNN_EXPORT void ncnn_copy_make_border(const ncnn_mat_t src, ncnn_mat_t dst, int top, int bottom, int left, int right, int type, float v, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_copy_make_border_3d(const ncnn_mat_t src, ncnn_mat_t dst, int top, int bottom, int left, int right, int front, int behind, int type, float v, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_copy_cut_border(const ncnn_mat_t src, ncnn_mat_t dst, int top, int bottom, int left, int right, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_copy_cut_border_3d(const ncnn_mat_t src, ncnn_mat_t dst, int top, int bottom, int left, int right, int front, int behind, const ncnn_option_t opt); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* NCNN_C_API */ + +#endif /* NCNN_C_API_H */ diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/command.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/command.h new file mode 100644 index 0000000..337d085 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/command.h @@ -0,0 +1,136 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_COMMAND_H +#define NCNN_COMMAND_H + +#include "platform.h" + +#if NCNN_VULKAN + +#include "mat.h" + +#include + +namespace ncnn { + +class Pipeline; +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class ImportAndroidHardwareBufferPipeline; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API +class VkComputePrivate; +class NCNN_EXPORT VkCompute +{ +public: + explicit VkCompute(const VulkanDevice* vkdev); + virtual ~VkCompute(); + +public: + void record_upload(const Mat& src, VkMat& dst, const Option& opt); + + void record_upload(const Mat& src, VkImageMat& dst, const Option& opt); + + void record_download(const VkMat& src, Mat& dst, const Option& opt); + + void record_download(const VkImageMat& src, Mat& dst, const Option& opt); + + void record_buffer_to_image(const VkMat& src, VkImageMat& dst, const Option& opt); + + void record_image_to_buffer(const VkImageMat& src, VkMat& dst, const Option& opt); + + void record_clone(const Mat& src, VkMat& dst, const Option& opt); + + void record_clone(const Mat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkMat& src, Mat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, Mat& dst, const Option& opt); + + void record_clone(const VkMat& src, VkMat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkMat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, VkMat& dst, const Option& opt); + + void record_pipeline(const Pipeline* pipeline, const std::vector& bindings, const std::vector& constants, const VkMat& dispatcher); + + void record_pipeline(const Pipeline* pipeline, const std::vector& bindings, const std::vector& constants, const VkImageMat& dispatcher); + + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const VkMat& dispatcher); + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const VkImageMat& dispatcher); + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const Mat& dispatcher); + +#if NCNN_BENCHMARK + void record_write_timestamp(uint32_t query); +#endif // NCNN_BENCHMARK + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 + void record_import_android_hardware_buffer(const ImportAndroidHardwareBufferPipeline* pipeline, const VkImageMat& src, const VkMat& dst); + + void record_import_android_hardware_buffer(const ImportAndroidHardwareBufferPipeline* pipeline, const VkImageMat& src, const VkImageMat& dst); +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + + int submit_and_wait(); + + int reset(); + +#if NCNN_BENCHMARK + int create_query_pool(uint32_t query_count); + + int get_query_pool_results(uint32_t first_query, uint32_t query_count, std::vector& results); +#endif // NCNN_BENCHMARK + +protected: + const VulkanDevice* vkdev; + + void barrier_readwrite(const VkMat& binding); + void barrier_readwrite(const VkImageMat& binding); + void barrier_readonly(const VkImageMat& binding); + +private: + VkComputePrivate* const d; +}; + +class VkTransferPrivate; +class NCNN_EXPORT VkTransfer +{ +public: + explicit VkTransfer(const VulkanDevice* vkdev); + virtual ~VkTransfer(); + +public: + void record_upload(const Mat& src, VkMat& dst, const Option& opt, bool flatten = true); + + void record_upload(const Mat& src, VkImageMat& dst, const Option& opt); + + int submit_and_wait(); + +protected: + const VulkanDevice* vkdev; + +private: + VkTransferPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_VULKAN + +#endif // NCNN_COMMAND_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/cpu.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/cpu.h new file mode 100644 index 0000000..7d6bfce --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/cpu.h @@ -0,0 +1,178 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_CPU_H +#define NCNN_CPU_H + +#include + +#if (defined _WIN32 && !(defined __MINGW32__)) +#define WIN32_LEAN_AND_MEAN +#include +#endif +#if defined __ANDROID__ || defined __linux__ +#include // cpu_set_t +#endif + +#include "platform.h" + +namespace ncnn { + +class NCNN_EXPORT CpuSet +{ +public: + CpuSet(); + void enable(int cpu); + void disable(int cpu); + void disable_all(); + bool is_enabled(int cpu) const; + int num_enabled() const; + +public: +#if (defined _WIN32 && !(defined __MINGW32__)) + ULONG_PTR mask; +#endif +#if defined __ANDROID__ || defined __linux__ + cpu_set_t cpu_set; +#endif +#if __APPLE__ + unsigned int policy; +#endif +}; + +// test optional cpu features +// edsp = armv7 edsp +NCNN_EXPORT int cpu_support_arm_edsp(); +// neon = armv7 neon or aarch64 asimd +NCNN_EXPORT int cpu_support_arm_neon(); +// vfpv4 = armv7 fp16 + fma +NCNN_EXPORT int cpu_support_arm_vfpv4(); +// asimdhp = aarch64 asimd half precision +NCNN_EXPORT int cpu_support_arm_asimdhp(); +// cpuid = aarch64 cpuid info +NCNN_EXPORT int cpu_support_arm_cpuid(); +// asimddp = aarch64 asimd dot product +NCNN_EXPORT int cpu_support_arm_asimddp(); +// asimdfhm = aarch64 asimd fhm +NCNN_EXPORT int cpu_support_arm_asimdfhm(); +// bf16 = aarch64 bf16 +NCNN_EXPORT int cpu_support_arm_bf16(); +// i8mm = aarch64 i8mm +NCNN_EXPORT int cpu_support_arm_i8mm(); +// sve = aarch64 sve +NCNN_EXPORT int cpu_support_arm_sve(); +// sve2 = aarch64 sve2 +NCNN_EXPORT int cpu_support_arm_sve2(); +// svebf16 = aarch64 svebf16 +NCNN_EXPORT int cpu_support_arm_svebf16(); +// svei8mm = aarch64 svei8mm +NCNN_EXPORT int cpu_support_arm_svei8mm(); +// svef32mm = aarch64 svef32mm +NCNN_EXPORT int cpu_support_arm_svef32mm(); + +// avx = x86 avx +NCNN_EXPORT int cpu_support_x86_avx(); +// fma = x86 fma +NCNN_EXPORT int cpu_support_x86_fma(); +// xop = x86 xop +NCNN_EXPORT int cpu_support_x86_xop(); +// f16c = x86 f16c +NCNN_EXPORT int cpu_support_x86_f16c(); +// avx2 = x86 avx2 + fma + f16c +NCNN_EXPORT int cpu_support_x86_avx2(); +// avx_vnni = x86 avx vnni +NCNN_EXPORT int cpu_support_x86_avx_vnni(); +// avx512 = x86 avx512f + avx512cd + avx512bw + avx512dq + avx512vl +NCNN_EXPORT int cpu_support_x86_avx512(); +// avx512_vnni = x86 avx512 vnni +NCNN_EXPORT int cpu_support_x86_avx512_vnni(); +// avx512_bf16 = x86 avx512 bf16 +NCNN_EXPORT int cpu_support_x86_avx512_bf16(); +// avx512_fp16 = x86 avx512 fp16 +NCNN_EXPORT int cpu_support_x86_avx512_fp16(); + +// lsx = loongarch lsx +NCNN_EXPORT int cpu_support_loongarch_lsx(); +// lasx = loongarch lasx +NCNN_EXPORT int cpu_support_loongarch_lasx(); + +// msa = mips mas +NCNN_EXPORT int cpu_support_mips_msa(); +// mmi = loongson mmi +NCNN_EXPORT int cpu_support_loongson_mmi(); + +// v = riscv vector +NCNN_EXPORT int cpu_support_riscv_v(); +// zfh = riscv half-precision float +NCNN_EXPORT int cpu_support_riscv_zfh(); +// vlenb = riscv vector length in bytes +NCNN_EXPORT int cpu_riscv_vlenb(); + +// cpu info +NCNN_EXPORT int get_cpu_count(); +NCNN_EXPORT int get_little_cpu_count(); +NCNN_EXPORT int get_big_cpu_count(); + +NCNN_EXPORT int get_physical_cpu_count(); +NCNN_EXPORT int get_physical_little_cpu_count(); +NCNN_EXPORT int get_physical_big_cpu_count(); + +// cpu l2 varies from 64k to 1M, but l3 can be zero +NCNN_EXPORT int get_cpu_level2_cache_size(); +NCNN_EXPORT int get_cpu_level3_cache_size(); + +// bind all threads on little clusters if powersave enabled +// affects HMP arch cpu like ARM big.LITTLE +// only implemented on android at the moment +// switching powersave is expensive and not thread-safe +// 0 = all cores enabled(default) +// 1 = only little clusters enabled +// 2 = only big clusters enabled +// return 0 if success for setter function +NCNN_EXPORT int get_cpu_powersave(); +NCNN_EXPORT int set_cpu_powersave(int powersave); + +// convenient wrapper +NCNN_EXPORT const CpuSet& get_cpu_thread_affinity_mask(int powersave); + +// set explicit thread affinity +NCNN_EXPORT int set_cpu_thread_affinity(const CpuSet& thread_affinity_mask); + +// runtime thread affinity info +NCNN_EXPORT int is_current_thread_running_on_a53_a55(); + +// misc function wrapper for openmp routines +NCNN_EXPORT int get_omp_num_threads(); +NCNN_EXPORT void set_omp_num_threads(int num_threads); + +NCNN_EXPORT int get_omp_dynamic(); +NCNN_EXPORT void set_omp_dynamic(int dynamic); + +NCNN_EXPORT int get_omp_thread_num(); + +NCNN_EXPORT int get_kmp_blocktime(); +NCNN_EXPORT void set_kmp_blocktime(int time_ms); + +// need to flush denormals on Intel Chipset. +// Other architectures such as ARM can be added as needed. +// 0 = DAZ OFF, FTZ OFF +// 1 = DAZ ON , FTZ OFF +// 2 = DAZ OFF, FTZ ON +// 3 = DAZ ON, FTZ ON +NCNN_EXPORT int get_flush_denormals(); +NCNN_EXPORT int set_flush_denormals(int flush_denormals); + +} // namespace ncnn + +#endif // NCNN_CPU_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/datareader.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/datareader.h new file mode 100644 index 0000000..ed2aba3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/datareader.h @@ -0,0 +1,122 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_DATAREADER_H +#define NCNN_DATAREADER_H + +#include "platform.h" +#if NCNN_STDIO +#include +#endif + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#endif +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +// data read wrapper +class NCNN_EXPORT DataReader +{ +public: + DataReader(); + virtual ~DataReader(); + +#if NCNN_STRING + // parse plain param text + // return 1 if scan success + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + + // read binary param and model data + // return bytes read + virtual size_t read(void* buf, size_t size) const; + + // get model data reference + // return bytes referenced + virtual size_t reference(size_t size, const void** buf) const; +}; + +#if NCNN_STDIO +class DataReaderFromStdioPrivate; +class NCNN_EXPORT DataReaderFromStdio : public DataReader +{ +public: + explicit DataReaderFromStdio(FILE* fp); + virtual ~DataReaderFromStdio(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + +private: + DataReaderFromStdio(const DataReaderFromStdio&); + DataReaderFromStdio& operator=(const DataReaderFromStdio&); + +private: + DataReaderFromStdioPrivate* const d; +}; +#endif // NCNN_STDIO + +class DataReaderFromMemoryPrivate; +class NCNN_EXPORT DataReaderFromMemory : public DataReader +{ +public: + explicit DataReaderFromMemory(const unsigned char*& mem); + virtual ~DataReaderFromMemory(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + virtual size_t reference(size_t size, const void** buf) const; + +private: + DataReaderFromMemory(const DataReaderFromMemory&); + DataReaderFromMemory& operator=(const DataReaderFromMemory&); + +private: + DataReaderFromMemoryPrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +class DataReaderFromAndroidAssetPrivate; +class NCNN_EXPORT DataReaderFromAndroidAsset : public DataReader +{ +public: + explicit DataReaderFromAndroidAsset(AAsset* asset); + virtual ~DataReaderFromAndroidAsset(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + +private: + DataReaderFromAndroidAsset(const DataReaderFromAndroidAsset&); + DataReaderFromAndroidAsset& operator=(const DataReaderFromAndroidAsset&); + +private: + DataReaderFromAndroidAssetPrivate* const d; +}; +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + +} // namespace ncnn + +#endif // NCNN_DATAREADER_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/gpu.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/gpu.h new file mode 100644 index 0000000..1eff228 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/gpu.h @@ -0,0 +1,392 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_GPU_H +#define NCNN_GPU_H + +#include "platform.h" + +#if NCNN_VULKAN + +#include "mat.h" + +#include + +#include "vulkan_header_fix.h" + +namespace ncnn { + +// instance + +// Create VkInstance and initialize some objects that need to be calculated by GPU +// Creates a VkInstance object, Checks the extended attributes supported by the Vulkan instance concerned, +// Initializes, and creates Vulkan validation layers (if ENABLE_VALIDATION_LAYER is enabled), +// Iterates over all supported physical devices, etc. +NCNN_EXPORT int create_gpu_instance(); + +// Get global VkInstance variable +// Must be called after create_gpu_instance() and before destroy_gpu_instance() +NCNN_EXPORT VkInstance get_gpu_instance(); + +// Destroy VkInstance object and free the memory of the associated object +// Usually called in the destructor of the main program exit +NCNN_EXPORT void destroy_gpu_instance(); + +// instance extension capability +extern int support_VK_KHR_external_memory_capabilities; +extern int support_VK_KHR_get_physical_device_properties2; +extern int support_VK_KHR_get_surface_capabilities2; +extern int support_VK_KHR_surface; +extern int support_VK_EXT_debug_utils; +extern int support_VK_EXT_validation_features; +extern int support_VK_EXT_validation_flags; +#if __ANDROID_API__ >= 26 +extern int support_VK_KHR_android_surface; +#endif // __ANDROID_API__ >= 26 + +// VK_KHR_cooperative_matrix +extern PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR; + +// VK_KHR_external_memory_capabilities +extern PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR vkGetPhysicalDeviceExternalBufferPropertiesKHR; + +// VK_KHR_get_physical_device_properties2 +extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; +extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; +extern PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceImageFormatProperties2KHR vkGetPhysicalDeviceImageFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR; +extern PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR; +extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR vkGetPhysicalDeviceSparseImageFormatProperties2KHR; + +// VK_KHR_get_surface_capabilities2 +extern PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR; + +// VK_KHR_surface +extern PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; +extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; +extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; +extern PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; + +#if __ANDROID_API__ >= 26 +// VK_KHR_android_surface +extern PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; +#endif // __ANDROID_API__ >= 26 + +// VK_NV_cooperative_matrix +extern PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV vkGetPhysicalDeviceCooperativeMatrixPropertiesNV; + +// get info +NCNN_EXPORT int get_gpu_count(); +NCNN_EXPORT int get_default_gpu_index(); + +class GpuInfoPrivate; +class NCNN_EXPORT GpuInfo +{ +public: + explicit GpuInfo(); + virtual ~GpuInfo(); + + // vulkan physical device + VkPhysicalDevice physical_device() const; + + // memory properties + const VkPhysicalDeviceMemoryProperties& physical_device_memory_properties() const; + + // info + uint32_t api_version() const; + uint32_t driver_version() const; + uint32_t vendor_id() const; + uint32_t device_id() const; + const char* device_name() const; + uint8_t* pipeline_cache_uuid() const; + + // 0 = discrete gpu + // 1 = integrated gpu + // 2 = virtual gpu + // 3 = cpu + int type() const; + + // hardware limit + uint32_t max_shared_memory_size() const; + uint32_t max_workgroup_count_x() const; + uint32_t max_workgroup_count_y() const; + uint32_t max_workgroup_count_z() const; + uint32_t max_workgroup_invocations() const; + uint32_t max_workgroup_size_x() const; + uint32_t max_workgroup_size_y() const; + uint32_t max_workgroup_size_z() const; + size_t memory_map_alignment() const; + size_t buffer_offset_alignment() const; + size_t non_coherent_atom_size() const; + size_t buffer_image_granularity() const; + uint32_t max_image_dimension_1d() const; + uint32_t max_image_dimension_2d() const; + uint32_t max_image_dimension_3d() const; + float timestamp_period() const; + + // runtime + uint32_t compute_queue_family_index() const; + uint32_t graphics_queue_family_index() const; + uint32_t transfer_queue_family_index() const; + + uint32_t compute_queue_count() const; + uint32_t graphics_queue_count() const; + uint32_t transfer_queue_count() const; + + // property + bool unified_compute_transfer_queue() const; + + // subgroup + uint32_t subgroup_size() const; + bool support_subgroup_basic() const; + bool support_subgroup_vote() const; + bool support_subgroup_ballot() const; + bool support_subgroup_shuffle() const; + + // bug is not feature + bool bug_storage_buffer_no_l1() const; + bool bug_corrupted_online_pipeline_cache() const; + bool bug_buffer_image_load_zero() const; + + // but sometimes bug is a feature + bool bug_implicit_fp16_arithmetic() const; + + // fp16 and int8 feature + bool support_fp16_packed() const; + bool support_fp16_storage() const; + bool support_fp16_arithmetic() const; + bool support_int8_packed() const; + bool support_int8_storage() const; + bool support_int8_arithmetic() const; + + // ycbcr conversion feature + bool support_ycbcr_conversion() const; + + // cooperative matrix feature + bool support_cooperative_matrix() const; + bool support_cooperative_matrix_16_8_8() const; + bool support_cooperative_matrix_16_8_16() const; + bool support_cooperative_matrix_16_16_16() const; + + // extension capability + int support_VK_KHR_8bit_storage() const; + int support_VK_KHR_16bit_storage() const; + int support_VK_KHR_bind_memory2() const; + int support_VK_KHR_buffer_device_address() const; + int support_VK_KHR_create_renderpass2() const; + int support_VK_KHR_cooperative_matrix() const; + int support_VK_KHR_dedicated_allocation() const; + int support_VK_KHR_descriptor_update_template() const; + int support_VK_KHR_external_memory() const; + int support_VK_KHR_get_memory_requirements2() const; + int support_VK_KHR_maintenance1() const; + int support_VK_KHR_maintenance2() const; + int support_VK_KHR_maintenance3() const; + int support_VK_KHR_multiview() const; + int support_VK_KHR_portability_subset() const; + int support_VK_KHR_push_descriptor() const; + int support_VK_KHR_sampler_ycbcr_conversion() const; + int support_VK_KHR_shader_float16_int8() const; + int support_VK_KHR_shader_float_controls() const; + int support_VK_KHR_storage_buffer_storage_class() const; + int support_VK_KHR_swapchain() const; + int support_VK_EXT_buffer_device_address() const; + int support_VK_EXT_descriptor_indexing() const; + int support_VK_EXT_memory_budget() const; + int support_VK_EXT_memory_priority() const; + int support_VK_EXT_queue_family_foreign() const; + int support_VK_AMD_device_coherent_memory() const; +#if __ANDROID_API__ >= 26 + int support_VK_ANDROID_external_memory_android_hardware_buffer() const; +#endif // __ANDROID_API__ >= 26 + int support_VK_NV_cooperative_matrix() const; + +private: + GpuInfo(const GpuInfo&); + GpuInfo& operator=(const GpuInfo&); + +private: + friend int create_gpu_instance(); + GpuInfoPrivate* const d; +}; + +NCNN_EXPORT const GpuInfo& get_gpu_info(int device_index = get_default_gpu_index()); + +class VkAllocator; +class VkCompute; +class Option; +class PipelineCache; +class VulkanDevicePrivate; +class NCNN_EXPORT VulkanDevice +{ +public: + VulkanDevice(int device_index = get_default_gpu_index()); + ~VulkanDevice(); + + const GpuInfo& info; + + VkDevice vkdevice() const; + + VkShaderModule compile_shader_module(const uint32_t* spv_data, size_t spv_data_size) const; + + // with fixed workgroup size + VkShaderModule compile_shader_module(const uint32_t* spv_data, size_t spv_data_size, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z) const; + + // helper for creating pipeline + int create_descriptorset_layout(int binding_count, const int* binding_types, VkDescriptorSetLayout* descriptorset_layout) const; + int create_pipeline_layout(int push_constant_count, VkDescriptorSetLayout descriptorset_layout, VkPipelineLayout* pipeline_layout) const; + int create_pipeline(VkShaderModule shader_module, VkPipelineLayout pipeline_layout, const std::vector& specializations, VkPipeline* pipeline) const; + int create_descriptor_update_template(int binding_count, const int* binding_types, VkDescriptorSetLayout descriptorset_layout, VkPipelineLayout pipeline_layout, VkDescriptorUpdateTemplateKHR* descriptor_update_template) const; + + uint32_t find_memory_index(uint32_t memory_type_bits, VkFlags required, VkFlags preferred, VkFlags preferred_not) const; + bool is_mappable(uint32_t memory_type_index) const; + bool is_coherent(uint32_t memory_type_index) const; + + VkQueue acquire_queue(uint32_t queue_family_index) const; + void reclaim_queue(uint32_t queue_family_index, VkQueue queue) const; + + // allocator on this device + VkAllocator* acquire_blob_allocator() const; + void reclaim_blob_allocator(VkAllocator* allocator) const; + + VkAllocator* acquire_staging_allocator() const; + void reclaim_staging_allocator(VkAllocator* allocator) const; + + // immutable sampler for texelfetch + const VkSampler* immutable_texelfetch_sampler() const; + + // dummy buffer image + VkMat get_dummy_buffer() const; + VkImageMat get_dummy_image() const; + VkImageMat get_dummy_image_readonly() const; + + // pipeline cache on this device + const PipelineCache* get_pipeline_cache() const; + + // test image allocation + bool shape_support_image_storage(const Mat& shape) const; + + // current gpu heap memory budget in MB + uint32_t get_heap_budget() const; + + // utility operator + void convert_packing(const VkMat& src, VkMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkImageMat& src, VkImageMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkMat& src, VkImageMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkImageMat& src, VkMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + + // VK_KHR_bind_memory2 + PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; + PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; + + // VK_KHR_buffer_device_address + PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR; + PFN_vkGetBufferOpaqueCaptureAddressKHR vkGetBufferOpaqueCaptureAddressKHR; + PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR vkGetDeviceMemoryOpaqueCaptureAddressKHR; + + // VK_KHR_create_renderpass2 + PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; + PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; + PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; + + // VK_KHR_descriptor_update_template + PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; + PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; + PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; + + // VK_KHR_get_memory_requirements2 + PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; + PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; + PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; + + // VK_KHR_maintenance1 + PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; + + // VK_KHR_maintenance3 + PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; + + // VK_KHR_push_descriptor + PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; + PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; + + // VK_KHR_sampler_ycbcr_conversion + PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; + PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; + + // VK_KHR_swapchain + PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; + PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; + PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; + PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; + PFN_vkQueuePresentKHR vkQueuePresentKHR; + + // VK_EXT_buffer_device_address + PFN_vkGetBufferDeviceAddressEXT vkGetBufferDeviceAddressEXT; + +#if __ANDROID_API__ >= 26 + // VK_ANDROID_external_memory_android_hardware_buffer + PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; + PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; +#endif // __ANDROID_API__ >= 26 + +protected: + // device extension + int init_device_extension(); + +private: + VulkanDevice(const VulkanDevice&); + VulkanDevice& operator=(const VulkanDevice&); + +private: + VulkanDevicePrivate* const d; +}; + +NCNN_EXPORT VulkanDevice* get_gpu_device(int device_index = get_default_gpu_index()); + +// online spirv compilation +NCNN_EXPORT int compile_spirv_module(const char* comp_string, const Option& opt, std::vector& spirv); +NCNN_EXPORT int compile_spirv_module(const char* comp_data, int comp_data_size, const Option& opt, std::vector& spirv); +NCNN_EXPORT int compile_spirv_module(int shader_type_index, const Option& opt, std::vector& spirv); + +// info from spirv +class NCNN_EXPORT ShaderInfo +{ +public: + int specialization_count; + int binding_count; + int push_constant_count; + + // 0 = null + // 1 = storage buffer + // 2 = storage image + // 3 = combined image sampler + int binding_types[16]; // 16 is large enough I think ... + + int reserved_0; + int reserved_1; + int reserved_2; + int reserved_3; +}; + +NCNN_EXPORT int resolve_shader_info(const uint32_t* spv_data, size_t spv_data_size, ShaderInfo& shader_info); + +} // namespace ncnn + +#endif // NCNN_VULKAN + +#endif // NCNN_GPU_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/layer.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/layer.h new file mode 100644 index 0000000..f0418a9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/layer.h @@ -0,0 +1,222 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_H +#define NCNN_LAYER_H + +#include "mat.h" +#include "modelbin.h" +#include "option.h" +#include "paramdict.h" +#include "platform.h" + +#if NCNN_VULKAN +#include "command.h" +#include "pipeline.h" + +#include +#endif // NCNN_VULKAN + +namespace ncnn { + +class NCNN_EXPORT Layer +{ +public: + // empty + Layer(); + // virtual destructor + virtual ~Layer(); + + // load layer specific parameter from parsed dict + // return 0 if success + virtual int load_param(const ParamDict& pd); + + // load layer specific weight data from model binary + // return 0 if success + virtual int load_model(const ModelBin& mb); + + // layer implementation specific setup + // return 0 if success + virtual int create_pipeline(const Option& opt); + + // layer implementation specific clean + // return 0 if success + virtual int destroy_pipeline(const Option& opt); + +public: + // one input and one output blob + bool one_blob_only; + + // support inplace inference + bool support_inplace; + + // support vulkan compute + bool support_vulkan; + + // accept input blob with packed storage + bool support_packing; + + // accept bf16 + bool support_bf16_storage; + + // accept fp16 + bool support_fp16_storage; + + // accept int8 + bool support_int8_storage; + + // shader image storage + bool support_image_storage; + + // shader tensor storage + bool support_tensor_storage; + + bool support_reserved_00; + + bool support_reserved_0; + bool support_reserved_1; + bool support_reserved_2; + bool support_reserved_3; + bool support_reserved_4; + bool support_reserved_5; + bool support_reserved_6; + bool support_reserved_7; + bool support_reserved_8; + bool support_reserved_9; + + // feature disabled set + int featmask; + +public: + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, const Option& opt) const; + virtual int forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, const Option& opt) const; + virtual int forward_inplace(Mat& bottom_top_blob, const Option& opt) const; + +#if NCNN_VULKAN +public: + // upload weight blob from host to device + virtual int upload_model(VkTransfer& cmd, const Option& opt); + +public: + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward_inplace(VkMat& bottom_top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward_inplace(VkImageMat& bottom_top_blob, VkCompute& cmd, const Option& opt) const; + +public: + // assigned immediately after creating this layer + const VulkanDevice* vkdev; +#endif // NCNN_VULKAN + +public: + // custom user data + void* userdata; + // layer type index + int typeindex; +#if NCNN_STRING + // layer type name + std::string type; + // layer name + std::string name; +#endif // NCNN_STRING + // blob index which this layer needs as input + std::vector bottoms; + // blob index which this layer produces as output + std::vector tops; + // shape hint + std::vector bottom_shapes; + std::vector top_shapes; +}; + +// layer factory function +typedef Layer* (*layer_creator_func)(void*); +typedef void (*layer_destroyer_func)(Layer*, void*); + +struct layer_registry_entry +{ +#if NCNN_STRING + // layer type name + const char* name; +#endif // NCNN_STRING + // layer factory entry + layer_creator_func creator; +}; + +struct custom_layer_registry_entry +{ +#if NCNN_STRING + // layer type name + const char* name; +#endif // NCNN_STRING + // layer factory entry + layer_creator_func creator; + layer_destroyer_func destroyer; + void* userdata; +}; + +struct overwrite_builtin_layer_registry_entry +{ + // layer type index + int typeindex; + // layer factory entry + layer_creator_func creator; + layer_destroyer_func destroyer; + void* userdata; +}; + +#if NCNN_STRING +// get layer type from type name +NCNN_EXPORT int layer_to_index(const char* type); +// create layer from type name +NCNN_EXPORT Layer* create_layer(const char* type); +#endif // NCNN_STRING +// create layer from layer type +NCNN_EXPORT Layer* create_layer(int index); + +#define DEFINE_LAYER_CREATOR(name) \ + ::ncnn::Layer* name##_layer_creator(void* /*userdata*/) \ + { \ + return new name; \ + } + +#define DEFINE_LAYER_DESTROYER(name) \ + void name##_layer_destroyer(::ncnn::Layer* layer, void* /*userdata*/) \ + { \ + delete layer; \ + } + +} // namespace ncnn + +#endif // NCNN_LAYER_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/layer_shader_type.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/layer_shader_type.h new file mode 100644 index 0000000..c143e7d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/layer_shader_type.h @@ -0,0 +1,29 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_SHADER_TYPE_H +#define NCNN_LAYER_SHADER_TYPE_H + +namespace ncnn { + +namespace LayerShaderType { +enum LayerShaderType +{ +#include "layer_shader_type_enum.h" +}; +} // namespace LayerShaderType + +} // namespace ncnn + +#endif // NCNN_LAYER_SHADER_TYPE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/layer_shader_type_enum.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/layer_shader_type_enum.h new file mode 100644 index 0000000..aac8803 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/layer_shader_type_enum.h @@ -0,0 +1,5 @@ +// Layer Shader Enum header +// +// This file is auto-generated by cmake, don't edit it. + + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/layer_type.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/layer_type.h new file mode 100644 index 0000000..511c714 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/layer_type.h @@ -0,0 +1,30 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_TYPE_H +#define NCNN_LAYER_TYPE_H + +namespace ncnn { + +namespace LayerType { +enum LayerType +{ +#include "layer_type_enum.h" + CustomBit = (1 << 8), +}; +} // namespace LayerType + +} // namespace ncnn + +#endif // NCNN_LAYER_TYPE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/layer_type_enum.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/layer_type_enum.h new file mode 100644 index 0000000..97153ed --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/layer_type_enum.h @@ -0,0 +1,109 @@ +// Layer Type Enum header +// +// This file is auto-generated by cmake, don't edit it. + +AbsVal = 0, +ArgMax = 1, +BatchNorm = 2, +Bias = 3, +BNLL = 4, +Concat = 5, +Convolution = 6, +Crop = 7, +Deconvolution = 8, +Dropout = 9, +Eltwise = 10, +ELU = 11, +Embed = 12, +Exp = 13, +Flatten = 14, +InnerProduct = 15, +Input = 16, +Log = 17, +LRN = 18, +MemoryData = 19, +MVN = 20, +Pooling = 21, +Power = 22, +PReLU = 23, +Proposal = 24, +Reduction = 25, +ReLU = 26, +Reshape = 27, +ROIPooling = 28, +Scale = 29, +Sigmoid = 30, +Slice = 31, +Softmax = 32, +Split = 33, +SPP = 34, +TanH = 35, +Threshold = 36, +Tile = 37, +RNN = 38, +LSTM = 39, +BinaryOp = 40, +UnaryOp = 41, +ConvolutionDepthWise = 42, +Padding = 43, +Squeeze = 44, +ExpandDims = 45, +Normalize = 46, +Permute = 47, +PriorBox = 48, +DetectionOutput = 49, +Interp = 50, +DeconvolutionDepthWise = 51, +ShuffleChannel = 52, +InstanceNorm = 53, +Clip = 54, +Reorg = 55, +YoloDetectionOutput = 56, +Quantize = 57, +Dequantize = 58, +Yolov3DetectionOutput = 59, +PSROIPooling = 60, +ROIAlign = 61, +Packing = 62, +Requantize = 63, +Cast = 64, +HardSigmoid = 65, +SELU = 66, +HardSwish = 67, +Noop = 68, +PixelShuffle = 69, +DeepCopy = 70, +Mish = 71, +StatisticsPooling = 72, +Swish = 73, +Gemm = 74, +GroupNorm = 75, +LayerNorm = 76, +Softplus = 77, +GRU = 78, +MultiHeadAttention = 79, +GELU = 80, +Convolution1D = 81, +Pooling1D = 82, +ConvolutionDepthWise1D = 83, +Convolution3D = 84, +ConvolutionDepthWise3D = 85, +Pooling3D = 86, +MatMul = 87, +Deconvolution1D = 88, +DeconvolutionDepthWise1D = 89, +Deconvolution3D = 90, +DeconvolutionDepthWise3D = 91, +Einsum = 92, +DeformableConv2D = 93, +GLU = 94, +Fold = 95, +Unfold = 96, +GridSample = 97, +CumulativeSum = 98, +CopyTo = 99, +Erf = 100, +Diag = 101, +CELU = 102, +Shrink = 103, + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/mat.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/mat.h new file mode 100644 index 0000000..c6f59ef --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/mat.h @@ -0,0 +1,1843 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_MAT_H +#define NCNN_MAT_H + +#include +#include +#if __ARM_NEON +#include +#endif +#if __SSE2__ +#include +#if __AVX__ +#include +#endif +#endif +#if __mips_msa +#include +#endif +#if __loongarch_sx +#include +#endif +#if __riscv_vector +#include +#include "cpu.h" // cpu_riscv_vlenb() +#endif + +#include "allocator.h" +#include "option.h" +#include "platform.h" + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#if NCNN_PIXEL +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#include +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API +#endif // NCNN_PIXEL + +namespace ncnn { + +#if NCNN_VULKAN +class VkMat; +class VkImageMat; +#endif // NCNN_VULKAN + +// the three dimension matrix +class NCNN_EXPORT Mat +{ +public: + // empty + Mat(); + // vec + Mat(int w, size_t elemsize = 4u, Allocator* allocator = 0); + // image + Mat(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0); + // dim + Mat(int w, int h, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // cube + Mat(int w, int h, int d, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // packed vec + Mat(int w, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed image + Mat(int w, int h, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed dim + Mat(int w, int h, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed cube + Mat(int w, int h, int d, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // copy + Mat(const Mat& m); + // external vec + Mat(int w, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external image + Mat(int w, int h, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external dim + Mat(int w, int h, int c, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external cube + Mat(int w, int h, int d, int c, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external packed vec + Mat(int w, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed image + Mat(int w, int h, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed dim + Mat(int w, int h, int c, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed cube + Mat(int w, int h, int d, int c, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // release + ~Mat(); + // assign + Mat& operator=(const Mat& m); + // set all + void fill(float v); + void fill(int v); +#if __ARM_NEON + void fill(float32x4_t _v); + void fill(uint16x4_t _v); + void fill(int32x4_t _v); + void fill(int32x4_t _v0, int32x4_t _v1); +#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC + void fill(float16x4_t _v); + void fill(float16x8_t _v); +#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +#endif // __ARM_NEON +#if __SSE2__ +#if __AVX__ +#if __AVX512F__ + void fill(__m512 _v); +#endif // __AVX512F__ + void fill(__m256 _v, int i = 0); +#endif // __AVX__ + void fill(__m128 _v); + void fill(__m128i _v); +#endif // __SSE2__ +#if __mips_msa + void fill(v4f32 _v); +#endif // __mips_msa +#if __loongarch_sx + void fill(__m128 _v); +#endif //__loongarch_sx +#if __riscv_vector + void fill(vfloat32m1_t _v); + void fill(vuint16m1_t _v); + void fill(vint8m1_t _v); +#if __riscv_zfh + void fill(vfloat16m1_t _v); +#endif // __riscv_zfh +#endif // __riscv_vector + template + void fill(T v); + // deep copy + Mat clone(Allocator* allocator = 0) const; + // deep copy from other mat, inplace + void clone_from(const ncnn::Mat& mat, Allocator* allocator = 0); + // reshape vec + Mat reshape(int w, Allocator* allocator = 0) const; + // reshape image + Mat reshape(int w, int h, Allocator* allocator = 0) const; + // reshape dim + Mat reshape(int w, int h, int c, Allocator* allocator = 0) const; + // reshape cube + Mat reshape(int w, int h, int d, int c, Allocator* allocator = 0) const; + // allocate vec + void create(int w, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate image + void create(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate dim + void create(int w, int h, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate like + void create_like(const Mat& m, Allocator* allocator = 0); +#if NCNN_VULKAN + // allocate like + void create_like(const VkMat& m, Allocator* allocator = 0); + // allocate like + void create_like(const VkImageMat& im, Allocator* allocator = 0); +#endif // NCNN_VULKAN + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // data reference + Mat channel(int c); + const Mat channel(int c) const; + Mat depth(int z); + const Mat depth(int z) const; + float* row(int y); + const float* row(int y) const; + template + T* row(int y); + template + const T* row(int y) const; + + // range reference + Mat channel_range(int c, int channels); + const Mat channel_range(int c, int channels) const; + Mat depth_range(int z, int depths); + const Mat depth_range(int z, int depths) const; + Mat row_range(int y, int rows); + const Mat row_range(int y, int rows) const; + Mat range(int x, int n); + const Mat range(int x, int n) const; + + // access raw data + template + operator T*(); + template + operator const T*() const; + + // convenient access float vec element + float& operator[](size_t i); + const float& operator[](size_t i) const; + +#if NCNN_PIXEL + enum PixelType + { + PIXEL_CONVERT_SHIFT = 16, + PIXEL_FORMAT_MASK = 0x0000ffff, + PIXEL_CONVERT_MASK = 0xffff0000, + + PIXEL_RGB = 1, + PIXEL_BGR = 2, + PIXEL_GRAY = 3, + PIXEL_RGBA = 4, + PIXEL_BGRA = 5, + + PIXEL_RGB2BGR = PIXEL_RGB | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2GRAY = PIXEL_RGB | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2RGBA = PIXEL_RGB | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2BGRA = PIXEL_RGB | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_BGR2RGB = PIXEL_BGR | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2GRAY = PIXEL_BGR | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2RGBA = PIXEL_BGR | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2BGRA = PIXEL_BGR | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_GRAY2RGB = PIXEL_GRAY | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2BGR = PIXEL_GRAY | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2RGBA = PIXEL_GRAY | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2BGRA = PIXEL_GRAY | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_RGBA2RGB = PIXEL_RGBA | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2BGR = PIXEL_RGBA | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2GRAY = PIXEL_RGBA | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2BGRA = PIXEL_RGBA | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_BGRA2RGB = PIXEL_BGRA | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2BGR = PIXEL_BGRA | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2GRAY = PIXEL_BGRA | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2RGBA = PIXEL_BGRA | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + }; + // convenient construct from pixel data + static Mat from_pixels(const unsigned char* pixels, int type, int w, int h, Allocator* allocator = 0); + // convenient construct from pixel data with stride(bytes-per-row) parameter + static Mat from_pixels(const unsigned char* pixels, int type, int w, int h, int stride, Allocator* allocator = 0); + // convenient construct from pixel data and resize to specific size + static Mat from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data and resize to specific size with stride(bytes-per-row) parameter + static Mat from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data roi + static Mat from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from pixel data roi with stride(bytes-per-row) parameter + static Mat from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from pixel data roi and resize to specific size + static Mat from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data roi and resize to specific size with stride(bytes-per-row) parameter + static Mat from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + + // convenient export to pixel data + void to_pixels(unsigned char* pixels, int type) const; + // convenient export to pixel data with stride(bytes-per-row) parameter + void to_pixels(unsigned char* pixels, int type, int stride) const; + // convenient export to pixel data and resize to specific size + void to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height) const; + // convenient export to pixel data and resize to specific size with stride(bytes-per-row) parameter + void to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height, int target_stride) const; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 + // convenient construct from android Bitmap + static Mat from_android_bitmap(JNIEnv* env, jobject bitmap, int type_to, Allocator* allocator = 0); + // convenient construct from android Bitmap and resize to specific size + static Mat from_android_bitmap_resize(JNIEnv* env, jobject bitmap, int type_to, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from android Bitmap roi + static Mat from_android_bitmap_roi(JNIEnv* env, jobject bitmap, int type_to, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from android Bitmap roi and resize to specific size + static Mat from_android_bitmap_roi_resize(JNIEnv* env, jobject bitmap, int type_to, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + // convenient export to android Bitmap and resize to the android Bitmap size + void to_android_bitmap(JNIEnv* env, jobject bitmap, int type_from) const; +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API +#endif // NCNN_PIXEL + + // substract channel-wise mean values, then multiply by normalize values, pass 0 to skip + void substract_mean_normalize(const float* mean_vals, const float* norm_vals); + + // convenient construct from half precision floating point data + static Mat from_float16(const unsigned short* data, int size); + + // pointer to the data + void* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + Allocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; + + size_t cstep; +}; + +#if NCNN_VULKAN + +// the three dimension matrix, vulkan version +class NCNN_EXPORT VkMat +{ +public: + // empty + VkMat(); + // vec + VkMat(int w, size_t elemsize, VkAllocator* allocator); + // image + VkMat(int w, int h, size_t elemsize, VkAllocator* allocator); + // dim + VkMat(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // cube + VkMat(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // packed vec + VkMat(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // packed image + VkMat(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // packed dim + VkMat(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // packed cube + VkMat(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // copy + VkMat(const VkMat& m); + // external vec + VkMat(int w, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external image + VkMat(int w, int h, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external dim + VkMat(int w, int h, int c, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external cube + VkMat(int w, int h, int d, int c, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external packed vec + VkMat(int w, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed image + VkMat(int w, int h, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed dim + VkMat(int w, int h, int c, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed cube + VkMat(int w, int h, int d, int c, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // release + ~VkMat(); + // assign + VkMat& operator=(const VkMat& m); + // allocate vec + void create(int w, size_t elemsize, VkAllocator* allocator); + // allocate image + void create(int w, int h, size_t elemsize, VkAllocator* allocator); + // allocate dim + void create(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate like + void create_like(const Mat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkMat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkImageMat& im, VkAllocator* allocator); + + // mapped + Mat mapped() const; + void* mapped_ptr() const; + + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // low-level reference + VkBuffer buffer() const; + size_t buffer_offset() const; + size_t buffer_capacity() const; + + // device buffer + VkBufferMemory* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + VkAllocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; + + size_t cstep; +}; + +class NCNN_EXPORT VkImageMat +{ +public: + // empty + VkImageMat(); + // vec + VkImageMat(int w, size_t elemsize, VkAllocator* allocator); + // image + VkImageMat(int w, int h, size_t elemsize, VkAllocator* allocator); + // dim + VkImageMat(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // cube + VkImageMat(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // packed vec + VkImageMat(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // packed image + VkImageMat(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // packed dim + VkImageMat(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // packed cube + VkImageMat(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // copy + VkImageMat(const VkImageMat& m); + // external vec + VkImageMat(int w, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external image + VkImageMat(int w, int h, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external dim + VkImageMat(int w, int h, int c, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external cube + VkImageMat(int w, int h, int d, int c, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external packed vec + VkImageMat(int w, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed image + VkImageMat(int w, int h, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed dim + VkImageMat(int w, int h, int c, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed cube + VkImageMat(int w, int h, int d, int c, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // release + ~VkImageMat(); + // assign + VkImageMat& operator=(const VkImageMat& m); + // allocate vec + void create(int w, size_t elemsize, VkAllocator* allocator); + // allocate image + void create(int w, int h, size_t elemsize, VkAllocator* allocator); + // allocate dim + void create(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate like + void create_like(const Mat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkMat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkImageMat& im, VkAllocator* allocator); + + // mapped + Mat mapped() const; + void* mapped_ptr() const; + + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // low-level reference + VkImage image() const; + VkImageView imageview() const; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 + // convenient construct from android hardware buffer + static VkImageMat from_android_hardware_buffer(VkAndroidHardwareBufferImageAllocator* allocator); +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + + // device image + VkImageMemory* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + VkAllocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; +}; + +// type for vulkan specialization constant and push constant +union vk_specialization_type +{ + int i; + float f; + uint32_t u32; +}; +union vk_constant_type +{ + int i; + float f; +}; +#endif // NCNN_VULKAN + +// misc function +#if NCNN_PIXEL +// convert yuv420sp(nv21) to rgb, the fast approximate version +NCNN_EXPORT void yuv420sp2rgb(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// convert yuv420sp(nv12) to rgb, the fast approximate version +NCNN_EXPORT void yuv420sp2rgb_nv12(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// convert yuv420sp(nv21) to rgb with half resize, the faster approximate version +NCNN_EXPORT void yuv420sp2rgb_half(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// image pixel bilinear resize +NCNN_EXPORT void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +// image pixel bilinear resize with stride(bytes-per-row) parameter +NCNN_EXPORT void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +// image pixel bilinear resize, convenient wrapper for yuv420sp(nv21/nv12) +NCNN_EXPORT void resize_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +#endif // NCNN_PIXEL +#if NCNN_PIXEL_ROTATE +// type is the from type, 6 means rotating from 6 to 1 +// +// 1 2 3 4 5 6 7 8 +// +// 888888 888888 88 88 8888888888 88 88 8888888888 +// 88 88 88 88 88 88 88 88 88 88 88 88 +// 8888 8888 8888 8888 88 8888888888 8888888888 88 +// 88 88 88 88 +// 88 88 888888 888888 +// +// ref http://sylvana.net/jpegcrop/exif_orientation.html +// image pixel kanna rotate +NCNN_EXPORT void kanna_rotate_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +// image pixel kanna rotate with stride(bytes-per-row) parameter +NCNN_EXPORT void kanna_rotate_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +// image pixel kanna rotate, convenient wrapper for yuv420sp(nv21/nv12) +NCNN_EXPORT void kanna_rotate_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +#endif // NCNN_PIXEL_ROTATE +#if NCNN_PIXEL_AFFINE +// resolve affine transform matrix from rotation angle, scale factor and x y offset +NCNN_EXPORT void get_rotation_matrix(float angle, float scale, float dx, float dy, float* tm); +// resolve affine transform matrix from two set of points, num_point must be >= 2 +NCNN_EXPORT void get_affine_transform(const float* points_from, const float* points_to, int num_point, float* tm); +// resolve the inversion affine transform matrix +NCNN_EXPORT void invert_affine_transform(const float* tm, float* tm_inv); +// image pixel bilinear warpaffine inverse transform, set -233 for transparent border color, the color RGBA is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +// image pixel bilinear warpaffine inverse transform with stride(bytes-per-row) parameter, set -233 for transparent border color, the color RGBA is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +// image pixel bilinear warpaffine, convenient wrapper for yuv420sp(nv21/nv12), set -233 for transparent border color, the color YUV_ is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +#endif // NCNN_PIXEL_AFFINE +#if NCNN_PIXEL_DRAWING +// draw rectangle, set thickness -1 for filled rectangle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_rectangle_c1(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c2(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c3(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c4(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw rectangle with stride(bytes-per-row) parameter, set thickness -1 for filled rectangle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_rectangle_c1(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c2(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c3(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c4(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw rectangle, convenient wrapper for yuv420sp(nv21/nv12), set thickness -1 for filled rectangle, the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_rectangle_yuv420sp(unsigned char* yuv420sp, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw circle, set thickness -1 for filled circle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_circle_c1(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c2(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c3(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c4(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +// draw circle with stride(bytes-per-row) parameter, set thickness -1 for filled circle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_circle_c1(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c2(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c3(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c4(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +// draw circle, convenient wrapper for yuv420sp(nv21/nv12), set thickness -1 for filled circle, the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_circle_yuv420sp(unsigned char* yuv420sp, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +// draw line, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_line_c1(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c2(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c3(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c4(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// draw line with stride(bytes-per-row) parameter, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_line_c1(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c2(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c3(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c4(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// draw line, convenient wrapper for yuv420sp(nv21/nv12), the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_line_yuv420sp(unsigned char* yuv420sp, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// resolve text bounding box size +NCNN_EXPORT void get_text_drawing_size(const char* text, int fontpixelsize, int* w, int* h); +// draw ascii printables and newline, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_text_c1(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c2(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c3(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c4(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +// draw ascii printables and newline with stride(bytes-per-row) parameter, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_text_c1(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c2(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c3(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c4(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +// draw ascii printables and newline, convenient wrapper for yuv420sp(nv21/nv12), the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_text_yuv420sp(unsigned char* yuv420sp, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +#endif // NCNN_PIXEL_DRAWING + +// type conversion +// convert float to half precision floating point +NCNN_EXPORT unsigned short float32_to_float16(float value); +// convert half precision floating point to float +NCNN_EXPORT float float16_to_float32(unsigned short value); +// convert float to brain half +NCNN_EXPORT NCNN_FORCEINLINE unsigned short float32_to_bfloat16(float value) +{ + // 16 : 16 + union + { + unsigned int u; + float f; + } tmp; + tmp.f = value; + return tmp.u >> 16; +} +// convert brain half to float +NCNN_EXPORT NCNN_FORCEINLINE float bfloat16_to_float32(unsigned short value) +{ + // 16 : 16 + union + { + unsigned int u; + float f; + } tmp; + tmp.u = value << 16; + return tmp.f; +} + +// mat process +enum BorderType +{ + BORDER_CONSTANT = 0, + BORDER_REPLICATE = 1, + BORDER_REFLECT = 2, + BORDER_TRANSPARENT = -233, +}; +NCNN_EXPORT void copy_make_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int type, float v, const Option& opt = Option()); +NCNN_EXPORT void copy_make_border_3d(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int front, int behind, int type, float v, const Option& opt = Option()); +NCNN_EXPORT void copy_cut_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, const Option& opt = Option()); +NCNN_EXPORT void copy_cut_border_3d(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int front, int behind, const Option& opt = Option()); +NCNN_EXPORT void resize_nearest(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void resize_bilinear(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void resize_bicubic(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void convert_packing(const Mat& src, Mat& dst, int elempack, const Option& opt = Option()); +NCNN_EXPORT void flatten(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float32_to_float16(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float16_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_int8_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float32_to_bfloat16(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_bfloat16_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void quantize_to_int8(const Mat& src, Mat& dst, const Mat& scale_data, const Option& opt = Option()); +NCNN_EXPORT void dequantize_from_int32(const Mat& src, Mat& dst, const Mat& scale_data, const Mat& bias_data, const Option& opt = Option()); +NCNN_EXPORT void requantize_from_int32_to_int8(const Mat& src, Mat& dst, const Mat& scale_in_data, const Mat& scale_out_data, const Mat& bias_data, int activation_type, const Mat& activation_params, const Option& opt = Option()); + +NCNN_FORCEINLINE Mat::Mat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ +} + +NCNN_FORCEINLINE Mat::Mat(int _w, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(const Mat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c), cstep(m.cstep) +{ + addref(); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = (size_t)w * h; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = (size_t)w * h; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::~Mat() +{ + release(); +} + +NCNN_FORCEINLINE void Mat::fill(float _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + + int i = 0; +#if __ARM_NEON + float32x4_t _c = vdupq_n_f32(_v); + for (; i + 3 < size; i += 4) + { + vst1q_f32(ptr, _c); + ptr += 4; + } +#endif // __ARM_NEON + for (; i < size; i++) + { + *ptr++ = _v; + } +} + +NCNN_FORCEINLINE void Mat::fill(int _v) +{ + int size = (int)total(); + int* ptr = (int*)data; + + int i = 0; +#if __ARM_NEON + int32x4_t _c = vdupq_n_s32(_v); + for (; i + 3 < size; i += 4) + { + vst1q_s32(ptr, _c); + ptr += 4; + } +#endif // __ARM_NEON + for (; i < size; i++) + { + *ptr++ = _v; + } +} + +#if __ARM_NEON +NCNN_FORCEINLINE void Mat::fill(float32x4_t _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + vst1q_f32(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(uint16x4_t _v) +{ + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + vst1_u16(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(int32x4_t _v) +{ + int size = (int)total(); + int* ptr = (int*)data; + for (int i = 0; i < size; i++) + { + vst1q_s32(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(int32x4_t _v0, int32x4_t _v1) +{ + int size = (int)total(); + int* ptr = (int*)data; + for (int i = 0; i < size; i++) + { + vst1q_s32(ptr, _v0); + vst1q_s32(ptr + 4, _v1); + ptr += 8; + } +} +#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +NCNN_FORCEINLINE void Mat::fill(float16x4_t _v) +{ + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vst1_f16(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(float16x8_t _v) +{ + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vst1q_f16(ptr, _v); + ptr += 8; + } +} +#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +#endif // __ARM_NEON + +#if __SSE2__ +#if __AVX__ +#if __AVX512F__ +NCNN_FORCEINLINE void Mat::fill(__m512 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm512_storeu_ps(ptr, _v); + ptr += 16; + } +} +#endif // __AVX512F__ +NCNN_FORCEINLINE void Mat::fill(__m256 _v, int _i) +{ + // old gcc cannot overload __m128 and __m256 type + // add a dummy int parameter for different mangled function symbol + (void)_i; + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm256_storeu_ps(ptr, _v); + ptr += 8; + } +} +#endif // __AVX__ +NCNN_FORCEINLINE void Mat::fill(__m128 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm_storeu_ps(ptr, _v); + ptr += 4; + } +} +NCNN_FORCEINLINE void Mat::fill(__m128i _v) +{ + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + _mm_store_si128((__m128i*)ptr, _v); + ptr += 8; + } +} +#endif // __SSE2__ + +#if __mips_msa +NCNN_FORCEINLINE void Mat::fill(v4f32 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + __msa_st_w((v4i32)_v, ptr, 0); + ptr += 4; + } +} +#endif // __mips_msa + +#if __loongarch_sx +NCNN_FORCEINLINE void Mat::fill(__m128 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + __lsx_vst(_v, ptr, 0); + ptr += 4; + } +} +#endif // __loongarch_sx +#if __riscv_vector +NCNN_FORCEINLINE void Mat::fill(vfloat32m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 4; + const size_t vl = vsetvl_e32m1(packn); + + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + vse32_v_f32m1(ptr, _v, vl); + ptr += packn; + } +} + +NCNN_FORCEINLINE void Mat::fill(vuint16m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 2; + const size_t vl = vsetvl_e16m1(packn); + + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + vse16_v_u16m1(ptr, _v, vl); + ptr += packn; + } +} + +NCNN_FORCEINLINE void Mat::fill(vint8m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 1; + const size_t vl = vsetvl_e8m1(packn); + + int size = (int)total(); + signed char* ptr = (signed char*)data; + for (int i = 0; i < size; i++) + { + vse8_v_i8m1(ptr, _v, vl); + ptr += packn; + } +} +#if __riscv_zfh +NCNN_FORCEINLINE void Mat::fill(vfloat16m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 2; + const size_t vl = vsetvl_e16m1(packn); + + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vse16_v_f16m1(ptr, _v, vl); + ptr += packn; + } +} +#endif // __riscv_zfh +#endif // __riscv_vector + +template +NCNN_FORCEINLINE void Mat::fill(T _v) +{ + int size = (int)total(); + T* ptr = (T*)data; + for (int i = 0; i < size; i++) + { + ptr[i] = _v; + } +} + +NCNN_FORCEINLINE Mat& Mat::operator=(const Mat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + cstep = m.cstep; + + return *this; +} + +NCNN_FORCEINLINE void Mat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void Mat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator) + allocator->fastFree(data); + else + fastFree(data); + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + cstep = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool Mat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t Mat::total() const +{ + return cstep * c; +} + +NCNN_FORCEINLINE int Mat::elembits() const +{ + return elempack ? static_cast(elemsize * 8) / elempack : 0; +} + +NCNN_FORCEINLINE Mat Mat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE Mat Mat::channel(int _c) +{ + Mat m(w, h, d, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims - 1; + if (dims == 4) + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::channel(int _c) const +{ + Mat m(w, h, d, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims - 1; + if (dims == 4) + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE Mat Mat::depth(int z) +{ + return Mat(w, h, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::depth(int z) const +{ + return Mat(w, h, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE float* Mat::row(int y) +{ + return (float*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +NCNN_FORCEINLINE const float* Mat::row(int y) const +{ + return (const float*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +template +NCNN_FORCEINLINE T* Mat::row(int y) +{ + return (T*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +template +NCNN_FORCEINLINE const T* Mat::row(int y) const +{ + return (const T*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +NCNN_FORCEINLINE Mat Mat::channel_range(int _c, int channels) +{ + Mat m(w, h, d, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::channel_range(int _c, int channels) const +{ + Mat m(w, h, d, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims; + return m; +} + +NCNN_FORCEINLINE Mat Mat::depth_range(int z, int depths) +{ + Mat m(w, h, depths, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::depth_range(int z, int depths) const +{ + Mat m(w, h, depths, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE Mat Mat::row_range(int y, int rows) +{ + return Mat(w, rows, (unsigned char*)data + (size_t)w * y * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::row_range(int y, int rows) const +{ + return Mat(w, rows, (unsigned char*)data + (size_t)w * y * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE Mat Mat::range(int x, int n) +{ + return Mat(n, (unsigned char*)data + x * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::range(int x, int n) const +{ + return Mat(n, (unsigned char*)data + x * elemsize, elemsize, elempack, allocator); +} + +template +NCNN_FORCEINLINE Mat::operator T*() +{ + return (T*)data; +} + +template +NCNN_FORCEINLINE Mat::operator const T*() const +{ + return (const T*)data; +} + +NCNN_FORCEINLINE float& Mat::operator[](size_t i) +{ + return ((float*)data)[i]; +} + +NCNN_FORCEINLINE const float& Mat::operator[](size_t i) const +{ + return ((const float*)data)[i]; +} + +#if NCNN_VULKAN + +NCNN_FORCEINLINE VkMat::VkMat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(const VkMat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c) +{ + addref(); + + cstep = m.cstep; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = w * h; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize(w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = w * h; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize(w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::~VkMat() +{ + release(); +} + +NCNN_FORCEINLINE VkMat& VkMat::operator=(const VkMat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + cstep = m.cstep; + + return *this; +} + +NCNN_FORCEINLINE Mat VkMat::mapped() const +{ + if (!allocator->mappable) + return Mat(); + + if (dims == 1) + return Mat(w, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 2) + return Mat(w, h, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 3) + return Mat(w, h, c, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 4) + return Mat(w, h, d, c, mapped_ptr(), elemsize, elempack, 0); + + return Mat(); +} + +NCNN_FORCEINLINE void* VkMat::mapped_ptr() const +{ + if (!allocator->mappable) + return 0; + + return (unsigned char*)data->mapped_ptr + data->offset; +} + +NCNN_FORCEINLINE void VkMat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void VkMat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator && data) + { + allocator->fastFree(data); + } + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + cstep = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool VkMat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t VkMat::total() const +{ + return cstep * c; +} + +NCNN_FORCEINLINE int VkMat::elembits() const +{ + return elempack ? static_cast(elemsize) * 8 / elempack : 0; +} + +NCNN_FORCEINLINE Mat VkMat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE VkBuffer VkMat::buffer() const +{ + return data->buffer; +} + +NCNN_FORCEINLINE size_t VkMat::buffer_offset() const +{ + return data->offset; +} + +NCNN_FORCEINLINE size_t VkMat::buffer_capacity() const +{ + return data->capacity; +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(const VkImageMat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c) +{ + addref(); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::~VkImageMat() +{ + release(); +} + +NCNN_FORCEINLINE VkImageMat& VkImageMat::operator=(const VkImageMat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + return *this; +} + +NCNN_FORCEINLINE Mat VkImageMat::mapped() const +{ + if (!allocator->mappable || !data->mapped_ptr) + return Mat(); + + if (dims == 1) + return Mat(w, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 2) + return Mat(w, h, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 3) + return Mat(w, h, c, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 4) + return Mat(w, h, d, c, mapped_ptr(), elemsize, elempack, 0); + + return Mat(); +} + +NCNN_FORCEINLINE void* VkImageMat::mapped_ptr() const +{ + if (!allocator->mappable || !data->mapped_ptr) + return 0; + + return (unsigned char*)data->mapped_ptr + data->bind_offset; +} + +NCNN_FORCEINLINE void VkImageMat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void VkImageMat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator && data) + { + allocator->fastFree(data); + } + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool VkImageMat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t VkImageMat::total() const +{ + return w * h * d * c; +} + +NCNN_FORCEINLINE int VkImageMat::elembits() const +{ + return elempack ? static_cast(elemsize) * 8 / elempack : 0; +} + +NCNN_FORCEINLINE Mat VkImageMat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE VkImage VkImageMat::image() const +{ + return data->image; +} + +NCNN_FORCEINLINE VkImageView VkImageMat::imageview() const +{ + return data->imageview; +} + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_MAT_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/modelbin.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/modelbin.h new file mode 100644 index 0000000..aada5f6 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/modelbin.h @@ -0,0 +1,80 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_MODELBIN_H +#define NCNN_MODELBIN_H + +#include "mat.h" + +namespace ncnn { + +class DataReader; +class NCNN_EXPORT ModelBin +{ +public: + ModelBin(); + virtual ~ModelBin(); + // element type + // 0 = auto + // 1 = float32 + // 2 = float16 + // 3 = int8 + // load vec + virtual Mat load(int w, int type) const; + // load image + virtual Mat load(int w, int h, int type) const; + // load dim + virtual Mat load(int w, int h, int c, int type) const; + // load cube + virtual Mat load(int w, int h, int d, int c, int type) const; +}; + +class ModelBinFromDataReaderPrivate; +class NCNN_EXPORT ModelBinFromDataReader : public ModelBin +{ +public: + explicit ModelBinFromDataReader(const DataReader& dr); + virtual ~ModelBinFromDataReader(); + + virtual Mat load(int w, int type) const; + +private: + ModelBinFromDataReader(const ModelBinFromDataReader&); + ModelBinFromDataReader& operator=(const ModelBinFromDataReader&); + +private: + ModelBinFromDataReaderPrivate* const d; +}; + +class ModelBinFromMatArrayPrivate; +class NCNN_EXPORT ModelBinFromMatArray : public ModelBin +{ +public: + // construct from weight blob array + explicit ModelBinFromMatArray(const Mat* weights); + virtual ~ModelBinFromMatArray(); + + virtual Mat load(int w, int type) const; + +private: + ModelBinFromMatArray(const ModelBinFromMatArray&); + ModelBinFromMatArray& operator=(const ModelBinFromMatArray&); + +private: + ModelBinFromMatArrayPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_MODELBIN_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/ncnn_export.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/ncnn_export.h new file mode 100644 index 0000000..e2f5fde --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/ncnn_export.h @@ -0,0 +1,42 @@ + +#ifndef NCNN_EXPORT_H +#define NCNN_EXPORT_H + +#ifdef NCNN_STATIC_DEFINE +# define NCNN_EXPORT +# define NCNN_NO_EXPORT +#else +# ifndef NCNN_EXPORT +# ifdef ncnn_EXPORTS + /* We are building this library */ +# define NCNN_EXPORT __attribute__((visibility("default"))) +# else + /* We are using this library */ +# define NCNN_EXPORT __attribute__((visibility("default"))) +# endif +# endif + +# ifndef NCNN_NO_EXPORT +# define NCNN_NO_EXPORT __attribute__((visibility("hidden"))) +# endif +#endif + +#ifndef NCNN_DEPRECATED +# define NCNN_DEPRECATED __attribute__ ((__deprecated__)) +#endif + +#ifndef NCNN_DEPRECATED_EXPORT +# define NCNN_DEPRECATED_EXPORT NCNN_EXPORT NCNN_DEPRECATED +#endif + +#ifndef NCNN_DEPRECATED_NO_EXPORT +# define NCNN_DEPRECATED_NO_EXPORT NCNN_NO_EXPORT NCNN_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef NCNN_NO_DEPRECATED +# define NCNN_NO_DEPRECATED +# endif +#endif + +#endif /* NCNN_EXPORT_H */ diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/net.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/net.h new file mode 100644 index 0000000..98e3ec3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/net.h @@ -0,0 +1,274 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_NET_H +#define NCNN_NET_H + +#include "blob.h" +#include "layer.h" +#include "mat.h" +#include "option.h" +#include "platform.h" + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +#if NCNN_VULKAN +class VkCompute; +#endif // NCNN_VULKAN +class DataReader; +class Extractor; +class NetPrivate; +class NCNN_EXPORT Net +{ +public: + // empty init + Net(); + // clear and destroy + virtual ~Net(); + +public: + // option can be changed before loading + Option opt; + +#if NCNN_VULKAN + // set gpu device by index + void set_vulkan_device(int device_index); + + // set gpu device by device handle, no owner transfer + void set_vulkan_device(const VulkanDevice* vkdev); + + const VulkanDevice* vulkan_device() const; +#endif // NCNN_VULKAN + +#if NCNN_STRING + // register custom layer or overwrite built-in layer by layer type name + // return 0 if success + int register_custom_layer(const char* type, layer_creator_func creator, layer_destroyer_func destroyer = 0, void* userdata = 0); + virtual int custom_layer_to_index(const char* type); +#endif // NCNN_STRING + // register custom layer or overwrite built-in layer by layer type + // return 0 if success + int register_custom_layer(int index, layer_creator_func creator, layer_destroyer_func destroyer = 0, void* userdata = 0); + +#if NCNN_STRING + int load_param(const DataReader& dr); +#endif // NCNN_STRING + + int load_param_bin(const DataReader& dr); + + int load_model(const DataReader& dr); + +#if NCNN_STDIO +#if NCNN_STRING + // load network structure from plain param file + // return 0 if success + int load_param(FILE* fp); + int load_param(const char* protopath); + int load_param_mem(const char* mem); +#endif // NCNN_STRING + // load network structure from binary param file + // return 0 if success + int load_param_bin(FILE* fp); + int load_param_bin(const char* protopath); + + // load network weight data from model file + // return 0 if success + int load_model(FILE* fp); + int load_model(const char* modelpath); +#endif // NCNN_STDIO + + // load network structure from external memory + // memory pointer must be 32-bit aligned + // return bytes consumed + int load_param(const unsigned char* mem); + + // reference network weight data from external memory + // weight data is not copied but referenced + // so external memory should be retained when used + // memory pointer must be 32-bit aligned + // return bytes consumed + int load_model(const unsigned char* mem); + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#if NCNN_STRING + // convenient load network structure from android asset plain param file + int load_param(AAsset* asset); + int load_param(AAssetManager* mgr, const char* assetpath); +#endif // NCNN_STRING + // convenient load network structure from android asset binary param file + int load_param_bin(AAsset* asset); + int load_param_bin(AAssetManager* mgr, const char* assetpath); + + // convenient load network weight data from android asset model file + int load_model(AAsset* asset); + int load_model(AAssetManager* mgr, const char* assetpath); +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + + // unload network structure and weight data + void clear(); + + // construct an Extractor from network + Extractor create_extractor() const; + + // get input/output indexes/names + const std::vector& input_indexes() const; + const std::vector& output_indexes() const; +#if NCNN_STRING + const std::vector& input_names() const; + const std::vector& output_names() const; +#endif + + const std::vector& blobs() const; + const std::vector& layers() const; + + std::vector& mutable_blobs(); + std::vector& mutable_layers(); + +protected: + friend class Extractor; +#if NCNN_STRING + int find_blob_index_by_name(const char* name) const; + int find_layer_index_by_name(const char* name) const; + virtual Layer* create_custom_layer(const char* type); + virtual Layer* create_overwrite_builtin_layer(const char* type); +#endif // NCNN_STRING + virtual Layer* create_custom_layer(int index); + virtual Layer* create_overwrite_builtin_layer(int typeindex); + +private: + Net(const Net&); + Net& operator=(const Net&); + +private: + NetPrivate* const d; +}; + +class ExtractorPrivate; +class NCNN_EXPORT Extractor +{ +public: + virtual ~Extractor(); + + // copy + Extractor(const Extractor&); + + // assign + Extractor& operator=(const Extractor&); + + // clear blob mats and alloctors + void clear(); + + // enable light mode + // intermediate blob will be recycled when enabled + // enabled by default + void set_light_mode(bool enable); + + // set thread count for this extractor + // this will overwrite the global setting + // default count is system depended + void set_num_threads(int num_threads); + + // set blob memory allocator + void set_blob_allocator(Allocator* allocator); + + // set workspace memory allocator + void set_workspace_allocator(Allocator* allocator); + +#if NCNN_VULKAN + void set_vulkan_compute(bool enable); + + void set_blob_vkallocator(VkAllocator* allocator); + + void set_workspace_vkallocator(VkAllocator* allocator); + + void set_staging_vkallocator(VkAllocator* allocator); +#endif // NCNN_VULKAN + +#if NCNN_STRING + // set input by blob name + // return 0 if success + int input(const char* blob_name, const Mat& in); + + // get result by blob name + // return 0 if success + // type = 0, default + // type = 1, do not convert fp16/bf16 or / and packing + int extract(const char* blob_name, Mat& feat, int type = 0); +#endif // NCNN_STRING + + // set input by blob index + // return 0 if success + int input(int blob_index, const Mat& in); + + // get result by blob index + // return 0 if success + // type = 0, default + // type = 1, do not convert fp16/bf16 or / and packing + int extract(int blob_index, Mat& feat, int type = 0); + +#if NCNN_VULKAN +#if NCNN_STRING + // set input by blob name + // return 0 if success + int input(const char* blob_name, const VkMat& in); + + // get result by blob name + // return 0 if success + int extract(const char* blob_name, VkMat& feat, VkCompute& cmd); + + // set input by blob name + // return 0 if success + int input(const char* blob_name, const VkImageMat& in); + + // get result by blob name + // return 0 if success + int extract(const char* blob_name, VkImageMat& feat, VkCompute& cmd); +#endif // NCNN_STRING + + // set input by blob index + // return 0 if success + int input(int blob_index, const VkMat& in); + + // get result by blob index + // return 0 if success + int extract(int blob_index, VkMat& feat, VkCompute& cmd); + + // set input by blob index + // return 0 if success + int input(int blob_index, const VkImageMat& in); + + // get result by blob index + // return 0 if success + int extract(int blob_index, VkImageMat& feat, VkCompute& cmd); +#endif // NCNN_VULKAN + +protected: + friend Extractor Net::create_extractor() const; + Extractor(const Net* net, size_t blob_count); + +private: + ExtractorPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_NET_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/option.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/option.h new file mode 100644 index 0000000..7d0cc60 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/option.h @@ -0,0 +1,156 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_OPTION_H +#define NCNN_OPTION_H + +#include "platform.h" + +namespace ncnn { + +#if NCNN_VULKAN +class VkAllocator; +class PipelineCache; +#endif // NCNN_VULKAN + +class Allocator; +class NCNN_EXPORT Option +{ +public: + // default option + Option(); + +public: + // light mode + // intermediate blob will be recycled when enabled + // enabled by default + bool lightmode; + + // thread count + // default value is the one returned by get_cpu_count() + int num_threads; + + // blob memory allocator + Allocator* blob_allocator; + + // workspace memory allocator + Allocator* workspace_allocator; + +#if NCNN_VULKAN + // blob memory allocator + VkAllocator* blob_vkallocator; + + // workspace memory allocator + VkAllocator* workspace_vkallocator; + + // staging memory allocator + VkAllocator* staging_vkallocator; + + // pipeline cache + PipelineCache* pipeline_cache; +#endif // NCNN_VULKAN + + // the time openmp threads busy-wait for more work before going to sleep + // default value is 20ms to keep the cores enabled + // without too much extra power consumption afterwards + int openmp_blocktime; + + // enable winograd convolution optimization + // improve convolution 3x3 stride1 performance, may consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_winograd_convolution; + + // enable sgemm convolution optimization + // improve convolution 1x1 stride1 performance, may consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_sgemm_convolution; + + // enable quantized int8 inference + // use low-precision int8 path for quantized model + // changes should be applied before loading network structure and weight + // enabled by default + bool use_int8_inference; + + // enable vulkan compute + bool use_vulkan_compute; + + // enable bf16 data type for storage + // improve most operator performance on all arm devices, may consume more memory + bool use_bf16_storage; + + // enable options for gpu inference + bool use_fp16_packed; + bool use_fp16_storage; + bool use_fp16_arithmetic; + bool use_int8_packed; + bool use_int8_storage; + bool use_int8_arithmetic; + + // enable simd-friendly packed memory layout + // improve all operator performance on all arm devices, will consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_packing_layout; + + bool use_shader_pack8; + + // subgroup option + bool use_subgroup_basic; + bool use_subgroup_vote; + bool use_subgroup_ballot; + bool use_subgroup_shuffle; + + // turn on for adreno + bool use_image_storage; + bool use_tensor_storage; + + bool use_reserved_0; + + // enable DAZ(Denormals-Are-Zero) and FTZ(Flush-To-Zero) + // default value is 3 + // 0 = DAZ OFF, FTZ OFF + // 1 = DAZ ON , FTZ OFF + // 2 = DAZ OFF, FTZ ON + // 3 = DAZ ON, FTZ ON + int flush_denormals; + + bool use_local_pool_allocator; + + // enable local memory optimization for gpu inference + bool use_shader_local_memory; + + // enable cooperative matrix optimization for gpu inference + bool use_cooperative_matrix; + + // more fine-grained control of winograd convolution + bool use_winograd23_convolution; + bool use_winograd43_convolution; + bool use_winograd63_convolution; + + // this option is turned on for A53/A55 automatically + // but you can force this on/off if you wish + bool use_a53_a55_optimized_kernel; + + bool use_reserved_7; + bool use_reserved_8; + bool use_reserved_9; + bool use_reserved_10; + bool use_reserved_11; +}; + +} // namespace ncnn + +#endif // NCNN_OPTION_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/paramdict.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/paramdict.h new file mode 100644 index 0000000..c2ef160 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/paramdict.h @@ -0,0 +1,73 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PARAMDICT_H +#define NCNN_PARAMDICT_H + +#include "mat.h" + +// at most 32 parameters +#define NCNN_MAX_PARAM_COUNT 32 + +namespace ncnn { + +class DataReader; +class Net; +class ParamDictPrivate; +class NCNN_EXPORT ParamDict +{ +public: + // empty + ParamDict(); + + virtual ~ParamDict(); + + // copy + ParamDict(const ParamDict&); + + // assign + ParamDict& operator=(const ParamDict&); + + // get type + int type(int id) const; + + // get int + int get(int id, int def) const; + // get float + float get(int id, float def) const; + // get array + Mat get(int id, const Mat& def) const; + + // set int + void set(int id, int i); + // set float + void set(int id, float f); + // set array + void set(int id, const Mat& v); + +protected: + friend class Net; + + void clear(); + + int load_param(const DataReader& dr); + int load_param_bin(const DataReader& dr); + +private: + ParamDictPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_PARAMDICT_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/pipeline.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/pipeline.h new file mode 100644 index 0000000..c284a14 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/pipeline.h @@ -0,0 +1,113 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PIPELINE_H +#define NCNN_PIPELINE_H + +#include "mat.h" +#include "platform.h" +#if NCNN_VULKAN +#include "gpu.h" + +#include +#endif // NCNN_VULKAN + +namespace ncnn { + +#if NCNN_VULKAN +class Option; +class PipelinePrivate; +class NCNN_EXPORT Pipeline +{ +public: + explicit Pipeline(const VulkanDevice* vkdev); + virtual ~Pipeline(); + +public: + void set_optimal_local_size_xyz(int w = 4, int h = 4, int c = 4); + void set_optimal_local_size_xyz(const Mat& local_size_xyz); + void set_local_size_xyz(int w, int h, int c); + + int create(const uint32_t* spv_data, size_t spv_data_size, const std::vector& specializations); + + int create(int shader_type_index, const Option& opt, const std::vector& specializations); + +public: + VkShaderModule shader_module() const; + VkDescriptorSetLayout descriptorset_layout() const; + VkPipelineLayout pipeline_layout() const; + VkPipeline pipeline() const; + VkDescriptorUpdateTemplateKHR descriptor_update_template() const; + + const ShaderInfo& shader_info() const; + + uint32_t local_size_x() const; + uint32_t local_size_y() const; + uint32_t local_size_z() const; + +protected: + void set_shader_module(VkShaderModule shader_module); + void set_descriptorset_layout(VkDescriptorSetLayout descriptorset_layout); + void set_pipeline_layout(VkPipelineLayout pipeline_layout); + void set_pipeline(VkPipeline pipeline); + void set_descriptor_update_template(VkDescriptorUpdateTemplateKHR descriptor_update_template); + + void set_shader_info(const ShaderInfo& shader_info); + +public: + const VulkanDevice* vkdev; + +private: + Pipeline(const Pipeline&); + Pipeline& operator=(const Pipeline&); + +private: + PipelinePrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class VkCompute; +class NCNN_EXPORT ImportAndroidHardwareBufferPipeline : private Pipeline +{ +public: + explicit ImportAndroidHardwareBufferPipeline(const VulkanDevice* vkdev); + virtual ~ImportAndroidHardwareBufferPipeline(); + + int create(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator, int type_to, int rotate_from, const Option& opt); + int create(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator, int type_to, int rotate_from, int target_width, int target_height, const Option& opt); + void destroy(); + + friend class VkCompute; + +protected: + int create_shader_module(const Option& opt); + int create_sampler(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator); + int create_descriptorset_layout(); + +public: + int type_to; + int rotate_from; + bool need_resize; + + VkSampler sampler; +}; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_PIPELINE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/pipelinecache.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/pipelinecache.h new file mode 100644 index 0000000..bb6b8fb --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/pipelinecache.h @@ -0,0 +1,85 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PIPELINECACHE_H +#define NCNN_PIPELINECACHE_H + +#include "platform.h" + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#include "mat.h" +#include "gpu.h" + +namespace ncnn { + +#if NCNN_VULKAN + +class VulkanDevice; +class PipelineCachePrivate; +class NCNN_EXPORT PipelineCache +{ +public: + explicit PipelineCache(const VulkanDevice* _vkdev); + + virtual ~PipelineCache(); + + void clear(); + + int get_pipeline(const uint32_t* spv_data, size_t spv_data_size, const std::vector& specializations, + uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* shader_module, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template, + ShaderInfo& shader_info) const; + + int get_pipeline(int shader_type_index, const Option& opt, const std::vector& specializations, + uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* shader_module, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template, + ShaderInfo& shader_info) const; + +protected: + int create_shader_module(int shader_type_index, const Option& opt, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* _shader_module, ShaderInfo& si) const; + + int new_pipeline(VkShaderModule shader_module, const ShaderInfo& shader_info, const std::vector& specializations, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template) const; + +protected: + const VulkanDevice* vkdev; + +private: + PipelineCache(const PipelineCache&); + PipelineCache& operator=(const PipelineCache&); + +private: + PipelineCachePrivate* const d; +}; + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_PIPELINECACHE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/platform.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/platform.h new file mode 100644 index 0000000..b5f4337 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/platform.h @@ -0,0 +1,293 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PLATFORM_H +#define NCNN_PLATFORM_H + +#define NCNN_STDIO 1 +#define NCNN_STRING 1 +#define NCNN_SIMPLEOCV 0 +#define NCNN_SIMPLEOMP 0 +#define NCNN_SIMPLESTL 0 +#define NCNN_SIMPLEMATH 0 +#define NCNN_THREADS 1 +#define NCNN_BENCHMARK 0 +#define NCNN_C_API 1 +#define NCNN_PLATFORM_API 1 +#define NCNN_PIXEL 1 +#define NCNN_PIXEL_ROTATE 1 +#define NCNN_PIXEL_AFFINE 1 +#define NCNN_PIXEL_DRAWING 1 +#define NCNN_VULKAN 0 +#define NCNN_SYSTEM_GLSLANG 0 +#define NCNN_RUNTIME_CPU 1 +#define NCNN_GNU_INLINE_ASM 1 +#define NCNN_AVX 1 +#define NCNN_XOP 1 +#define NCNN_FMA 1 +#define NCNN_F16C 1 +#define NCNN_AVX2 1 +#define NCNN_AVXVNNI 1 +#define NCNN_AVX512 1 +#define NCNN_AVX512VNNI 1 +#define NCNN_AVX512BF16 1 +#define NCNN_AVX512FP16 1 +#define NCNN_VFPV4 0 +#define NCNN_ARM82 0 +#define NCNN_ARM82DOT 0 +#define NCNN_ARM82FP16FML 0 +#define NCNN_ARM84BF16 0 +#define NCNN_ARM84I8MM 0 +#define NCNN_ARM86SVE 0 +#define NCNN_ARM86SVE2 0 +#define NCNN_ARM86SVEBF16 0 +#define NCNN_ARM86SVEI8MM 0 +#define NCNN_ARM86SVEF32MM 0 +#define NCNN_MSA 0 +#define NCNN_LSX 0 +#define NCNN_MMI 0 +#define NCNN_RVV 0 +#define NCNN_INT8 1 +#define NCNN_BF16 1 +#define NCNN_FORCE_INLINE 1 + +#define NCNN_VERSION_STRING "1.0.20231027" + +#include "ncnn_export.h" + +#ifdef __cplusplus + +#if NCNN_THREADS +#if (defined _WIN32 && !(defined __MINGW32__)) +#define WIN32_LEAN_AND_MEAN +#include +#include +#else +#include +#endif +#endif // NCNN_THREADS + +#if __ANDROID_API__ >= 26 +#define VK_USE_PLATFORM_ANDROID_KHR +#endif // __ANDROID_API__ >= 26 + +namespace ncnn { + +#if NCNN_THREADS +#if (defined _WIN32 && !(defined __MINGW32__)) +class NCNN_EXPORT Mutex +{ +public: + Mutex() { InitializeSRWLock(&srwlock); } + ~Mutex() {} + void lock() { AcquireSRWLockExclusive(&srwlock); } + void unlock() { ReleaseSRWLockExclusive(&srwlock); } +private: + friend class ConditionVariable; + // NOTE SRWLock is available from windows vista + SRWLOCK srwlock; +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() { InitializeConditionVariable(&condvar); } + ~ConditionVariable() {} + void wait(Mutex& mutex) { SleepConditionVariableSRW(&condvar, &mutex.srwlock, INFINITE, 0); } + void broadcast() { WakeAllConditionVariable(&condvar); } + void signal() { WakeConditionVariable(&condvar); } +private: + CONDITION_VARIABLE condvar; +}; + +static unsigned __stdcall start_wrapper(void* args); +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*start)(void*), void* args = 0) { _start = start; _args = args; handle = (HANDLE)_beginthreadex(0, 0, start_wrapper, this, 0, 0); } + ~Thread() {} + void join() { WaitForSingleObject(handle, INFINITE); CloseHandle(handle); } +private: + friend unsigned __stdcall start_wrapper(void* args) + { + Thread* t = (Thread*)args; + t->_start(t->_args); + return 0; + } + HANDLE handle; + void* (*_start)(void*); + void* _args; +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { key = TlsAlloc(); } + ~ThreadLocalStorage() { TlsFree(key); } + void set(void* value) { TlsSetValue(key, (LPVOID)value); } + void* get() { return (void*)TlsGetValue(key); } +private: + DWORD key; +}; +#else // (defined _WIN32 && !(defined __MINGW32__)) +class NCNN_EXPORT Mutex +{ +public: + Mutex() { pthread_mutex_init(&mutex, 0); } + ~Mutex() { pthread_mutex_destroy(&mutex); } + void lock() { pthread_mutex_lock(&mutex); } + void unlock() { pthread_mutex_unlock(&mutex); } +private: + friend class ConditionVariable; + pthread_mutex_t mutex; +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() { pthread_cond_init(&cond, 0); } + ~ConditionVariable() { pthread_cond_destroy(&cond); } + void wait(Mutex& mutex) { pthread_cond_wait(&cond, &mutex.mutex); } + void broadcast() { pthread_cond_broadcast(&cond); } + void signal() { pthread_cond_signal(&cond); } +private: + pthread_cond_t cond; +}; + +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*start)(void*), void* args = 0) { pthread_create(&t, 0, start, args); } + ~Thread() {} + void join() { pthread_join(t, 0); } +private: + pthread_t t; +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { pthread_key_create(&key, 0); } + ~ThreadLocalStorage() { pthread_key_delete(key); } + void set(void* value) { pthread_setspecific(key, value); } + void* get() { return pthread_getspecific(key); } +private: + pthread_key_t key; +}; +#endif // (defined _WIN32 && !(defined __MINGW32__)) +#else // NCNN_THREADS +class NCNN_EXPORT Mutex +{ +public: + Mutex() {} + ~Mutex() {} + void lock() {} + void unlock() {} +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() {} + ~ConditionVariable() {} + void wait(Mutex& /*mutex*/) {} + void broadcast() {} + void signal() {} +}; + +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*/*start*/)(void*), void* /*args*/ = 0) {} + ~Thread() {} + void join() {} +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { data = 0; } + ~ThreadLocalStorage() {} + void set(void* value) { data = value; } + void* get() { return data; } +private: + void* data; +}; +#endif // NCNN_THREADS + +class NCNN_EXPORT MutexLockGuard +{ +public: + MutexLockGuard(Mutex& _mutex) : mutex(_mutex) { mutex.lock(); } + ~MutexLockGuard() { mutex.unlock(); } +private: + Mutex& mutex; +}; + +} // namespace ncnn + +#if NCNN_SIMPLESTL +#include "simplestl.h" +#else +#include +#include +#include +#include +#endif + +// simplemath +#if NCNN_SIMPLEMATH +#include "simplemath.h" +#else +#include +#include +#endif + +#endif // __cplusplus + +#if NCNN_STDIO +#if NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#include +#define NCNN_LOGE(...) do { \ + fprintf(stderr, ##__VA_ARGS__); fprintf(stderr, "\n"); \ + __android_log_print(ANDROID_LOG_WARN, "ncnn", ##__VA_ARGS__); } while(0) +#else // NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#include +#define NCNN_LOGE(...) do { \ + fprintf(stderr, ##__VA_ARGS__); fprintf(stderr, "\n"); } while(0) +#endif // NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#else +#define NCNN_LOGE(...) +#endif + + +#if NCNN_FORCE_INLINE +#ifdef _MSC_VER + #define NCNN_FORCEINLINE __forceinline +#elif defined(__GNUC__) + #define NCNN_FORCEINLINE inline __attribute__((__always_inline__)) +#elif defined(__CLANG__) + #if __has_attribute(__always_inline__) + #define NCNN_FORCEINLINE inline __attribute__((__always_inline__)) + #else + #define NCNN_FORCEINLINE inline + #endif +#else + #define NCNN_FORCEINLINE inline +#endif +#else + #define NCNN_FORCEINLINE inline +#endif + +#endif // NCNN_PLATFORM_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/simplemath.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/simplemath.h new file mode 100644 index 0000000..fd7fa69 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/simplemath.h @@ -0,0 +1,102 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEMATH_H +#define NCNN_SIMPLEMATH_H + +#include "platform.h" + +#if NCNN_SIMPLEMATH + +#ifdef __cplusplus +extern "C" { +#endif +/* +* ==================================================== +* discrete functions +* ==================================================== +*/ +NCNN_EXPORT float fabs(float); +NCNN_EXPORT float fabsf(float); +NCNN_EXPORT float fmod(float, float); +NCNN_EXPORT float floor(float); +NCNN_EXPORT float floorf(float); +NCNN_EXPORT float round(float); +NCNN_EXPORT float roundf(float); +NCNN_EXPORT float ceil(float); +NCNN_EXPORT float ceilf(float); +NCNN_EXPORT float fmaxf(float, float); +NCNN_EXPORT float truncf(float); +NCNN_EXPORT float frac(float); +/* +* ==================================================== +* trigonometric functions +* ==================================================== +*/ +NCNN_EXPORT float sinf(float); +NCNN_EXPORT float cosf(float); +NCNN_EXPORT float tanf(float); +NCNN_EXPORT float asinf(float); +NCNN_EXPORT float acosf(float); +NCNN_EXPORT float atanf(float); +NCNN_EXPORT float atan2f(float, float); +NCNN_EXPORT float tanhf(float); + +/* +* ==================================================== +* power functions +* ==================================================== +*/ +NCNN_EXPORT float sqrtf(float); +NCNN_EXPORT float sqrt(float); +NCNN_EXPORT float powf(float, float); + +/* +* ==================================================== +* exponential and logarithm functions +* ==================================================== +*/ +NCNN_EXPORT float expf(float); +NCNN_EXPORT float frexp(float, int*); +NCNN_EXPORT float logf(float); +NCNN_EXPORT float log(float); +NCNN_EXPORT float log10f(float); + +/* +* ==================================================== +* probability functions +* ==================================================== +*/ +NCNN_EXPORT float erf(float); +NCNN_EXPORT float erfcf(float); + +/* +* ==================================================== +* other functions +* ==================================================== +*/ +NCNN_EXPORT int msb(unsigned int); +NCNN_EXPORT float fmaf(float, float, float); +NCNN_EXPORT float copysignf(float, float); +NCNN_EXPORT void fesetround(int); +NCNN_EXPORT int fegetround(); +NCNN_EXPORT float nearbyintf(float); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // NCNN_SIMPLEMATH + +#endif // NCNN_SIMPLEMATH_H \ No newline at end of file diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/simpleocv.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/simpleocv.h new file mode 100644 index 0000000..54b22d9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/simpleocv.h @@ -0,0 +1,503 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEOCV_H +#define NCNN_SIMPLEOCV_H + +#include "platform.h" + +#if NCNN_SIMPLEOCV + +#include +#include +#include "allocator.h" +#include "mat.h" + +#if defined(_MSC_VER) || defined(__GNUC__) +#pragma push_macro("min") +#pragma push_macro("max") +#undef min +#undef max +#endif + +#ifndef NCNN_XADD +using ncnn::NCNN_XADD; +#endif + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; + +enum +{ + CV_LOAD_IMAGE_UNCHANGED = -1, + CV_LOAD_IMAGE_GRAYSCALE = 0, + CV_LOAD_IMAGE_COLOR = 1, +}; + +enum +{ + CV_IMWRITE_JPEG_QUALITY = 1 +}; + +// minimal opencv style data structure implementation +namespace cv { + +template +static inline _Tp saturate_cast(int v) +{ + return _Tp(v); +} +template<> +inline uchar saturate_cast(int v) +{ + return (uchar)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); +} + +template +struct Scalar_ +{ + Scalar_() + { + v[0] = 0; + v[1] = 0; + v[2] = 0; + v[3] = 0; + } + Scalar_(_Tp _v0) + { + v[0] = _v0; + v[1] = 0; + v[2] = 0; + v[3] = 0; + } + Scalar_(_Tp _v0, _Tp _v1, _Tp _v2) + { + v[0] = _v0; + v[1] = _v1; + v[2] = _v2; + v[3] = 0; + } + Scalar_(_Tp _v0, _Tp _v1, _Tp _v2, _Tp _v3) + { + v[0] = _v0; + v[1] = _v1; + v[2] = _v2; + v[3] = _v3; + } + + const _Tp operator[](const int i) const + { + return v[i]; + } + + _Tp operator[](const int i) + { + return v[i]; + } + + _Tp v[4]; +}; + +typedef Scalar_ Scalar; + +template +struct Point_ +{ + Point_() + : x(0), y(0) + { + } + Point_(_Tp _x, _Tp _y) + : x(_x), y(_y) + { + } + + template + operator Point_<_Tp2>() const + { + return Point_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y)); + } + + _Tp x; + _Tp y; +}; + +typedef Point_ Point; +typedef Point_ Point2f; + +template +struct Size_ +{ + Size_() + : width(0), height(0) + { + } + Size_(_Tp _w, _Tp _h) + : width(_w), height(_h) + { + } + + template + operator Size_<_Tp2>() const + { + return Size_<_Tp2>(saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); + } + + _Tp width; + _Tp height; +}; + +typedef Size_ Size; +typedef Size_ Size2f; + +template +struct Rect_ +{ + Rect_() + : x(0), y(0), width(0), height(0) + { + } + Rect_(_Tp _x, _Tp _y, _Tp _w, _Tp _h) + : x(_x), y(_y), width(_w), height(_h) + { + } + Rect_(Point_<_Tp> _p, Size_<_Tp> _size) + : x(_p.x), y(_p.y), width(_size.width), height(_size.height) + { + } + + template + operator Rect_<_Tp2>() const + { + return Rect_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y), saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); + } + + _Tp x; + _Tp y; + _Tp width; + _Tp height; + + // area + _Tp area() const + { + return width * height; + } +}; + +template +static inline Rect_<_Tp>& operator&=(Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + _Tp x1 = std::max(a.x, b.x), y1 = std::max(a.y, b.y); + a.width = std::min(a.x + a.width, b.x + b.width) - x1; + a.height = std::min(a.y + a.height, b.y + b.height) - y1; + a.x = x1; + a.y = y1; + if (a.width <= 0 || a.height <= 0) + a = Rect_<_Tp>(); + return a; +} + +template +static inline Rect_<_Tp>& operator|=(Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + _Tp x1 = std::min(a.x, b.x), y1 = std::min(a.y, b.y); + a.width = std::max(a.x + a.width, b.x + b.width) - x1; + a.height = std::max(a.y + a.height, b.y + b.height) - y1; + a.x = x1; + a.y = y1; + return a; +} + +template +static inline Rect_<_Tp> operator&(const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c &= b; +} + +template +static inline Rect_<_Tp> operator|(const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c |= b; +} + +typedef Rect_ Rect; +typedef Rect_ Rect2f; + +#define CV_8UC1 1 +#define CV_8UC3 3 +#define CV_8UC4 4 +#define CV_32FC1 4 + +struct NCNN_EXPORT Mat +{ + Mat() + : data(0), refcount(0), rows(0), cols(0), c(0) + { + } + + Mat(int _rows, int _cols, int flags) + : data(0), refcount(0) + { + create(_rows, _cols, flags); + } + + // copy + Mat(const Mat& m) + : data(m.data), refcount(m.refcount) + { + if (refcount) + NCNN_XADD(refcount, 1); + + rows = m.rows; + cols = m.cols; + c = m.c; + } + + Mat(int _rows, int _cols, int flags, void* _data) + : data((unsigned char*)_data), refcount(0) + { + rows = _rows; + cols = _cols; + c = flags; + } + + ~Mat() + { + release(); + } + + // assign + Mat& operator=(const Mat& m) + { + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + + rows = m.rows; + cols = m.cols; + c = m.c; + + return *this; + } + + Mat& operator=(const Scalar& s) + { + if (total() > 0) + { + uchar* p = data; + for (int i = 0; i < cols * rows; i++) + { + for (int j = 0; j < c; j++) + { + *p++ = s[j]; + } + } + } + + return *this; + } + + void create(int _rows, int _cols, int flags) + { + release(); + + rows = _rows; + cols = _cols; + c = flags; + + if (total() > 0) + { + // refcount address must be aligned, so we expand totalsize here + size_t totalsize = (total() + 3) >> 2 << 2; + data = (uchar*)ncnn::fastMalloc(totalsize + (int)sizeof(*refcount)); + refcount = (int*)(((uchar*)data) + totalsize); + *refcount = 1; + } + } + + void release() + { + if (refcount && NCNN_XADD(refcount, -1) == 1) + ncnn::fastFree(data); + + data = 0; + + rows = 0; + cols = 0; + c = 0; + + refcount = 0; + } + + Mat clone() const + { + if (empty()) + return Mat(); + + Mat m(rows, cols, c); + + if (total() > 0) + { + memcpy(m.data, data, total()); + } + + return m; + } + + bool empty() const + { + return data == 0 || total() == 0; + } + + int channels() const + { + return c; + } + + int type() const + { + return c; + } + + size_t total() const + { + return cols * rows * c; + } + + const uchar* ptr(int y) const + { + return data + y * cols * c; + } + + uchar* ptr(int y) + { + return data + y * cols * c; + } + + template + const _Tp* ptr(int y) const + { + return (const _Tp*)data + y * cols * c; + } + + template + _Tp* ptr(int y) + { + return (_Tp*)data + y * cols * c; + } + + // roi + Mat operator()(const Rect& roi) const + { + if (empty()) + return Mat(); + + Mat m(roi.height, roi.width, c); + + int sy = roi.y; + for (int y = 0; y < roi.height; y++) + { + const uchar* sptr = ptr(sy) + roi.x * c; + uchar* dptr = m.ptr(y); + memcpy(dptr, sptr, roi.width * c); + sy++; + } + + return m; + } + + uchar* data; + + // pointer to the reference counter; + // when points to user-allocated data, the pointer is NULL + int* refcount; + + int rows; + int cols; + + int c; +}; + +enum ImreadModes +{ + IMREAD_UNCHANGED = -1, + IMREAD_GRAYSCALE = 0, + IMREAD_COLOR = 1 +}; + +NCNN_EXPORT Mat imread(const std::string& path, int flags = IMREAD_COLOR); + +NCNN_EXPORT Mat imdecode(const std::vector& buf, int flags = IMREAD_COLOR); + +enum ImwriteFlags +{ + IMWRITE_JPEG_QUALITY = 1 +}; + +NCNN_EXPORT bool imwrite(const std::string& path, const Mat& m, const std::vector& params = std::vector()); + +NCNN_EXPORT void imshow(const std::string& name, const Mat& m); + +NCNN_EXPORT int waitKey(int delay = 0); + +#if NCNN_PIXEL +NCNN_EXPORT void resize(const Mat& src, Mat& dst, const Size& size, float sw = 0.f, float sh = 0.f, int flags = 0); +#endif // NCNN_PIXEL + +#if NCNN_PIXEL_DRAWING + +enum +{ + FILLED = -1 +}; + +NCNN_EXPORT void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void rectangle(Mat& img, Rect rec, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void circle(Mat& img, Point center, int radius, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void line(Mat& img, Point p0, Point p1, const Scalar& color, int thickness = 1); + +enum +{ + FONT_HERSHEY_SIMPLEX = 0 +}; + +NCNN_EXPORT void putText(Mat& img, const std::string& text, Point org, int fontFace, double fontScale, Scalar color, int thickness = 1); + +NCNN_EXPORT Size getTextSize(const std::string& text, int fontFace, double fontScale, int thickness, int* baseLine); + +#endif // NCNN_PIXEL_DRAWING + +} // namespace cv + +#if defined(_MSC_VER) || defined(__GNUC__) +#pragma pop_macro("min") +#pragma pop_macro("max") +#endif + +#endif // NCNN_SIMPLEOCV + +#endif // NCNN_SIMPLEOCV_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/simpleomp.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/simpleomp.h new file mode 100644 index 0000000..13e2452 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/simpleomp.h @@ -0,0 +1,53 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEOMP_H +#define NCNN_SIMPLEOMP_H + +#include "platform.h" + +#if NCNN_SIMPLEOMP + +#include + +// This minimal openmp runtime implementation only supports the llvm openmp abi +// and only supports #pragma omp parallel for num_threads(X) + +#ifdef __cplusplus +extern "C" { +#endif + +NCNN_EXPORT int omp_get_max_threads(); + +NCNN_EXPORT void omp_set_num_threads(int num_threads); + +NCNN_EXPORT int omp_get_dynamic(); + +NCNN_EXPORT void omp_set_dynamic(int dynamic); + +NCNN_EXPORT int omp_get_num_threads(); + +NCNN_EXPORT int omp_get_thread_num(); + +NCNN_EXPORT int kmp_get_blocktime(); + +NCNN_EXPORT void kmp_set_blocktime(int blocktime); + +#ifdef __cplusplus +} +#endif + +#endif // NCNN_SIMPLEOMP + +#endif // NCNN_SIMPLEOMP_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/simplestl.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/simplestl.h new file mode 100644 index 0000000..00ff468 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/simplestl.h @@ -0,0 +1,565 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLESTL_H +#define NCNN_SIMPLESTL_H + +#include +#include +#include + +#if !NCNN_SIMPLESTL + +#include + +#else + +// allocation functions +NCNN_EXPORT void* operator new(size_t size); +NCNN_EXPORT void* operator new[](size_t size); +// placement allocation functions +NCNN_EXPORT void* operator new(size_t size, void* ptr); +NCNN_EXPORT void* operator new[](size_t size, void* ptr); +// deallocation functions +NCNN_EXPORT void operator delete(void* ptr); +NCNN_EXPORT void operator delete[](void* ptr); +// deallocation functions since c++14 +#if __cplusplus >= 201402L +NCNN_EXPORT void operator delete(void* ptr, size_t sz); +NCNN_EXPORT void operator delete[](void* ptr, size_t sz); +#endif +// placement deallocation functions +NCNN_EXPORT void operator delete(void* ptr, void* voidptr2); +NCNN_EXPORT void operator delete[](void* ptr, void* voidptr2); + +#endif + +// minimal stl data structure implementation +namespace std { + +template +const T& max(const T& a, const T& b) +{ + return (a < b) ? b : a; +} + +template +const T& min(const T& a, const T& b) +{ + return (a > b) ? b : a; +} + +template +void swap(T& a, T& b) +{ + T temp(a); + a = b; + b = temp; +} + +template +struct pair +{ + pair() + : first(), second() + { + } + pair(const T1& t1, const T2& t2) + : first(t1), second(t2) + { + } + + T1 first; + T2 second; +}; + +template +bool operator==(const pair& x, const pair& y) +{ + return (x.first == y.first && x.second == y.second); +} +template +bool operator<(const pair& x, const pair& y) +{ + return x.first < y.first || (!(y.first < x.first) && x.second < y.second); +} +template +bool operator!=(const pair& x, const pair& y) +{ + return !(x == y); +} +template +bool operator>(const pair& x, const pair& y) +{ + return y < x; +} +template +bool operator<=(const pair& x, const pair& y) +{ + return !(y < x); +} +template +bool operator>=(const pair& x, const pair& y) +{ + return !(x < y); +} + +template +pair make_pair(const T1& t1, const T2& t2) +{ + return pair(t1, t2); +} + +template +struct node +{ + node* prev_; + node* next_; + T data_; + + node() + : prev_(0), next_(0), data_() + { + } + node(const T& t) + : prev_(0), next_(0), data_(t) + { + } +}; + +template +struct iter_list +{ + iter_list() + : curr_(0) + { + } + iter_list(node* n) + : curr_(n) + { + } + iter_list(const iter_list& i) + : curr_(i.curr_) + { + } + ~iter_list() + { + } + + iter_list& operator=(const iter_list& i) + { + curr_ = i.curr_; + return *this; + } + + T& operator*() + { + return curr_->data_; + } + T* operator->() + { + return &(curr_->data_); + } + + bool operator==(const iter_list& i) + { + return curr_ == i.curr_; + } + bool operator!=(const iter_list& i) + { + return curr_ != i.curr_; + } + + iter_list& operator++() + { + curr_ = curr_->next_; + return *this; + } + iter_list& operator--() + { + curr_ = curr_->prev_; + return *this; + } + + node* curr_; +}; + +template +struct list +{ + typedef iter_list iterator; + + list() + { + head_ = new node(); + tail_ = head_; + count_ = 0; + } + ~list() + { + clear(); + delete head_; + } + list(const list& l) + { + head_ = new node(); + tail_ = head_; + count_ = 0; + + for (iter_list i = l.begin(); i != l.end(); ++i) + { + push_back(*i); + } + } + + list& operator=(const list& l) + { + if (this == &l) + { + return *this; + } + clear(); + + for (iter_list i = l.begin(); i != l.end(); ++i) + { + push_back(*i); + } + return *this; + } + + void clear() + { + while (count_ > 0) + { + pop_front(); + } + } + + void pop_front() + { + if (count_ > 0) + { + head_ = head_->next_; + delete head_->prev_; + head_->prev_ = 0; + --count_; + } + } + + size_t size() const + { + return count_; + } + iter_list begin() const + { + return iter_list(head_); + } + iter_list end() const + { + return iter_list(tail_); + } + bool empty() const + { + return count_ == 0; + } + + void push_back(const T& t) + { + if (count_ == 0) + { + head_ = new node(t); + head_->prev_ = 0; + head_->next_ = tail_; + tail_->prev_ = head_; + count_ = 1; + } + else + { + node* temp = new node(t); + temp->prev_ = tail_->prev_; + temp->next_ = tail_; + tail_->prev_->next_ = temp; + tail_->prev_ = temp; + ++count_; + } + } + + iter_list erase(iter_list pos) + { + if (pos != end()) + { + node* temp = pos.curr_; + if (temp == head_) + { + ++pos; + temp->next_->prev_ = 0; + head_ = temp->next_; + } + else + { + --pos; + temp->next_->prev_ = temp->prev_; + temp->prev_->next_ = temp->next_; + ++pos; + } + delete temp; + --count_; + } + return pos; + } + +protected: + node* head_; + node* tail_; + size_t count_; +}; + +template +struct greater +{ + bool operator()(const T& x, const T& y) const + { + return (x > y); + } +}; + +template +struct less +{ + bool operator()(const T& x, const T& y) const + { + return (x < y); + } +}; + +template +void partial_sort(RandomAccessIter first, RandomAccessIter middle, RandomAccessIter last, Compare comp) +{ + // [TODO] heap sort should be used here, but we simply use bubble sort now + for (RandomAccessIter i = first; i < middle; ++i) + { + // bubble sort + for (RandomAccessIter j = last - 1; j > first; --j) + { + if (comp(*j, *(j - 1))) + { + swap(*j, *(j - 1)); + } + } + } +} + +template +struct vector +{ + vector() + : data_(0), size_(0), capacity_(0) + { + } + vector(const size_t new_size, const T& value = T()) + : data_(0), size_(0), capacity_(0) + { + resize(new_size, value); + } + ~vector() + { + clear(); + } + vector(const vector& v) + : data_(0), size_(0), capacity_(0) + { + resize(v.size()); + for (size_t i = 0; i < size_; i++) + { + data_[i] = v.data_[i]; + } + } + + vector& operator=(const vector& v) + { + if (this == &v) + { + return *this; + } + resize(0); + resize(v.size()); + for (size_t i = 0; i < size_; i++) + { + data_[i] = v.data_[i]; + } + return *this; + } + + void resize(const size_t new_size, const T& value = T()) + { + try_alloc(new_size); + if (new_size > size_) + { + for (size_t i = size_; i < new_size; i++) + { + new (&data_[i]) T(value); + } + } + else if (new_size < size_) + { + for (size_t i = new_size; i < size_; i++) + { + data_[i].~T(); + } + } + size_ = new_size; + } + + void clear() + { + for (size_t i = 0; i < size_; i++) + { + data_[i].~T(); + } + delete[](char*) data_; + data_ = 0; + size_ = 0; + capacity_ = 0; + } + + T* data() const + { + return data_; + } + size_t size() const + { + return size_; + } + T& operator[](size_t i) const + { + return data_[i]; + } + T* begin() const + { + return &data_[0]; + } + T* end() const + { + return &data_[size_]; + } + bool empty() const + { + return size_ == 0; + } + + void push_back(const T& t) + { + try_alloc(size_ + 1); + new (&data_[size_]) T(t); + size_++; + } + + void insert(T* pos, T* b, T* e) + { + vector* v = 0; + if (b >= begin() && b < end()) + { + //the same vector + v = new vector(*this); + b = v->begin() + (b - begin()); + e = v->begin() + (e - begin()); + } + size_t diff = pos - begin(); + try_alloc(size_ + (e - b)); + pos = begin() + diff; + memmove(pos + (e - b), pos, (end() - pos) * sizeof(T)); + size_t len = e - b; + size_ += len; + for (size_t i = 0; i < len; i++) + { + *pos = *b; + pos++; + b++; + } + delete v; + } + + T* erase(T* pos) + { + pos->~T(); + memmove(pos, pos + 1, (end() - pos - 1) * sizeof(T)); + size_--; + return pos; + } + +protected: + T* data_; + size_t size_; + size_t capacity_; + void try_alloc(size_t new_size) + { + if (new_size * 3 / 2 > capacity_ / 2) + { + capacity_ = new_size * 2; + T* new_data = (T*)new char[capacity_ * sizeof(T)]; + memset(static_cast(new_data), 0, capacity_ * sizeof(T)); + if (data_) + { + memmove(new_data, data_, sizeof(T) * size_); + delete[](char*) data_; + } + data_ = new_data; + } + } +}; + +struct NCNN_EXPORT string : public vector +{ + string() + { + } + string(const char* str) + { + size_t len = strlen(str); + resize(len); + memcpy(data_, str, len); + } + const char* c_str() const + { + return (const char*)data_; + } + bool operator==(const string& str2) const + { + return strcmp(data_, str2.data_) == 0; + } + bool operator==(const char* str2) const + { + return strcmp(data_, str2) == 0; + } + bool operator!=(const char* str2) const + { + return strcmp(data_, str2) != 0; + } + string& operator+=(const string& str1) + { + insert(end(), str1.begin(), str1.end()); + return *this; + } +}; + +inline string operator+(const string& str1, const string& str2) +{ + string str(str1); + str.insert(str.end(), str2.begin(), str2.end()); + return str; +} + +} // namespace std + +#endif // NCNN_SIMPLESTL_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/vulkan_header_fix.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/vulkan_header_fix.h new file mode 100644 index 0000000..0a5ea9b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/include/ncnn/vulkan_header_fix.h @@ -0,0 +1,449 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_VULKAN_HEADER_FIX_H +#define NCNN_VULKAN_HEADER_FIX_H + +#include + +// This header contains new structure and function declearation to fix build with old vulkan sdk + +#if VK_HEADER_VERSION < 70 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES (VkStructureType)1000094000 +typedef enum VkSubgroupFeatureFlagBits +{ + VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001, + VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002, + VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004, + VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008, + VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010, + VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020, + VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040, + VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080, + VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 0x00000100, + VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubgroupFeatureFlagBits; +typedef VkFlags VkSubgroupFeatureFlags; +typedef struct VkPhysicalDeviceSubgroupProperties +{ + VkStructureType sType; + void* pNext; + uint32_t subgroupSize; + VkShaderStageFlags supportedStages; + VkSubgroupFeatureFlags supportedOperations; + VkBool32 quadOperationsInAllStages; +} VkPhysicalDeviceSubgroupProperties; +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES (VkStructureType)1000168000 +#define VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT (VkStructureType)1000168001 +typedef struct VkPhysicalDeviceMaintenance3Properties +{ + VkStructureType sType; + void* pNext; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceMaintenance3Properties; +typedef struct VkDescriptorSetLayoutSupport +{ + VkStructureType sType; + void* pNext; + VkBool32 supported; +} VkDescriptorSetLayoutSupport; +typedef VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; +typedef VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; +typedef void(VKAPI_PTR* PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); +#endif // VK_HEADER_VERSION < 70 + +#if VK_HEADER_VERSION < 80 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR (VkStructureType)1000177000 +typedef struct VkPhysicalDevice8BitStorageFeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; +} VkPhysicalDevice8BitStorageFeaturesKHR; +#define VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR (VkStructureType)1000109000 +#define VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR (VkStructureType)1000109001 +#define VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR (VkStructureType)1000109002 +#define VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR (VkStructureType)1000109003 +#define VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR (VkStructureType)1000109004 +#define VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR (VkStructureType)1000109005 +#define VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR (VkStructureType)1000109006 +typedef struct VkAttachmentDescription2KHR +{ + VkStructureType sType; + const void* pNext; + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription2KHR; +typedef struct VkAttachmentReference2KHR +{ + VkStructureType sType; + const void* pNext; + uint32_t attachment; + VkImageLayout layout; + VkImageAspectFlags aspectMask; +} VkAttachmentReference2KHR; +typedef struct VkSubpassDescription2KHR +{ + VkStructureType sType; + const void* pNext; + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t viewMask; + uint32_t inputAttachmentCount; + const VkAttachmentReference2KHR* pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference2KHR* pColorAttachments; + const VkAttachmentReference2KHR* pResolveAttachments; + const VkAttachmentReference2KHR* pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t* pPreserveAttachments; +} VkSubpassDescription2KHR; +typedef struct VkSubpassDependency2KHR +{ + VkStructureType sType; + const void* pNext; + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; + int32_t viewOffset; +} VkSubpassDependency2KHR; +typedef struct VkRenderPassCreateInfo2KHR +{ + VkStructureType sType; + const void* pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription2KHR* pAttachments; + uint32_t subpassCount; + const VkSubpassDescription2KHR* pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency2KHR* pDependencies; + uint32_t correlatedViewMaskCount; + const uint32_t* pCorrelatedViewMasks; +} VkRenderPassCreateInfo2KHR; +typedef struct VkSubpassBeginInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkSubpassContents contents; +} VkSubpassBeginInfoKHR; + +typedef struct VkSubpassEndInfoKHR +{ + VkStructureType sType; + const void* pNext; +} VkSubpassEndInfoKHR; +typedef VkResult(VKAPI_PTR* PFN_vkCreateRenderPass2KHR)(VkDevice device, const VkRenderPassCreateInfo2KHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void(VKAPI_PTR* PFN_vkCmdBeginRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfoKHR* pSubpassBeginInfo); +typedef void(VKAPI_PTR* PFN_vkCmdNextSubpass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfoKHR* pSubpassBeginInfo, const VkSubpassEndInfoKHR* pSubpassEndInfo); +typedef void(VKAPI_PTR* PFN_vkCmdEndRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassEndInfoKHR* pSubpassEndInfo); +#endif // VK_HEADER_VERSION < 80 + +#if VK_HEADER_VERSION < 95 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR (VkStructureType)1000082000 +typedef struct VkPhysicalDeviceFloat16Int8FeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; +} VkPhysicalDeviceFloat16Int8FeaturesKHR; +#endif // VK_HEADER_VERSION < 95 + +#if VK_HEADER_VERSION < 97 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT (VkStructureType)1000237000 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT (VkStructureType)1000238000 +#define VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT (VkStructureType)1000238001 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT (VkStructureType)1000244000 +#define VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_EXT (VkStructureType)1000244001 +#define VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT (VkStructureType)1000244002 +#define VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT (VkStructureType)1000247000 +#define VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT (VkBufferCreateFlagBits)0x00020000 +#define VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT (VkBufferUsageFlagBits)0x00020000 +typedef uint64_t VkDeviceAddress; +typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT +{ + VkStructureType sType; + void* pNext; + VkDeviceSize heapBudget[VK_MAX_MEMORY_HEAPS]; + VkDeviceSize heapUsage[VK_MAX_MEMORY_HEAPS]; +} VkPhysicalDeviceMemoryBudgetPropertiesEXT; +typedef struct VkPhysicalDeviceMemoryPriorityFeaturesEXT +{ + VkStructureType sType; + void* pNext; + VkBool32 memoryPriority; +} VkPhysicalDeviceMemoryPriorityFeaturesEXT; +typedef struct VkMemoryPriorityAllocateInfoEXT +{ + VkStructureType sType; + const void* pNext; + float priority; +} VkMemoryPriorityAllocateInfoEXT; +typedef struct VkPhysicalDeviceBufferAddressFeaturesEXT +{ + VkStructureType sType; + void* pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferAddressFeaturesEXT; +typedef struct VkBufferDeviceAddressInfoEXT +{ + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferDeviceAddressInfoEXT; +typedef struct VkBufferDeviceAddressCreateInfoEXT +{ + VkStructureType sType; + const void* pNext; + VkDeviceSize deviceAddress; +} VkBufferDeviceAddressCreateInfoEXT; +typedef VkDeviceAddress(VKAPI_PTR* PFN_vkGetBufferDeviceAddressEXT)(VkDevice device, const VkBufferDeviceAddressInfoEXT* pInfo); +typedef enum VkValidationFeatureEnableEXT +{ + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT = 0, + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT = 1, + VK_VALIDATION_FEATURE_ENABLE_BEGIN_RANGE_EXT = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT, + VK_VALIDATION_FEATURE_ENABLE_END_RANGE_EXT = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT, + VK_VALIDATION_FEATURE_ENABLE_RANGE_SIZE_EXT = (VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT - VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT + 1), + VK_VALIDATION_FEATURE_ENABLE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationFeatureEnableEXT; +typedef enum VkValidationFeatureDisableEXT +{ + VK_VALIDATION_FEATURE_DISABLE_ALL_EXT = 0, + VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT = 1, + VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT = 2, + VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT = 3, + VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT = 4, + VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT = 5, + VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT = 6, + VK_VALIDATION_FEATURE_DISABLE_BEGIN_RANGE_EXT = VK_VALIDATION_FEATURE_DISABLE_ALL_EXT, + VK_VALIDATION_FEATURE_DISABLE_END_RANGE_EXT = VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT, + VK_VALIDATION_FEATURE_DISABLE_RANGE_SIZE_EXT = (VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT - VK_VALIDATION_FEATURE_DISABLE_ALL_EXT + 1), + VK_VALIDATION_FEATURE_DISABLE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationFeatureDisableEXT; +typedef struct VkValidationFeaturesEXT +{ + VkStructureType sType; + const void* pNext; + uint32_t enabledValidationFeatureCount; + const VkValidationFeatureEnableEXT* pEnabledValidationFeatures; + uint32_t disabledValidationFeatureCount; + const VkValidationFeatureDisableEXT* pDisabledValidationFeatures; +} VkValidationFeaturesEXT; +#endif // VK_HEADER_VERSION < 97 + +#if VK_HEADER_VERSION < 101 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV (VkStructureType)1000249000 +#define VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV (VkStructureType)1000249001 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV (VkStructureType)1000249002 +typedef enum VkComponentTypeNV +{ + VK_COMPONENT_TYPE_FLOAT16_NV = 0, + VK_COMPONENT_TYPE_FLOAT32_NV = 1, + VK_COMPONENT_TYPE_FLOAT64_NV = 2, + VK_COMPONENT_TYPE_SINT8_NV = 3, + VK_COMPONENT_TYPE_SINT16_NV = 4, + VK_COMPONENT_TYPE_SINT32_NV = 5, + VK_COMPONENT_TYPE_SINT64_NV = 6, + VK_COMPONENT_TYPE_UINT8_NV = 7, + VK_COMPONENT_TYPE_UINT16_NV = 8, + VK_COMPONENT_TYPE_UINT32_NV = 9, + VK_COMPONENT_TYPE_UINT64_NV = 10, + VK_COMPONENT_TYPE_BEGIN_RANGE_NV = VK_COMPONENT_TYPE_FLOAT16_NV, + VK_COMPONENT_TYPE_END_RANGE_NV = VK_COMPONENT_TYPE_UINT64_NV, + VK_COMPONENT_TYPE_RANGE_SIZE_NV = (VK_COMPONENT_TYPE_UINT64_NV - VK_COMPONENT_TYPE_FLOAT16_NV + 1), + VK_COMPONENT_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkComponentTypeNV; +typedef enum VkScopeNV +{ + VK_SCOPE_DEVICE_NV = 1, + VK_SCOPE_WORKGROUP_NV = 2, + VK_SCOPE_SUBGROUP_NV = 3, + VK_SCOPE_QUEUE_FAMILY_NV = 5, + VK_SCOPE_BEGIN_RANGE_NV = VK_SCOPE_DEVICE_NV, + VK_SCOPE_END_RANGE_NV = VK_SCOPE_QUEUE_FAMILY_NV, + VK_SCOPE_RANGE_SIZE_NV = (VK_SCOPE_QUEUE_FAMILY_NV - VK_SCOPE_DEVICE_NV + 1), + VK_SCOPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkScopeNV; +typedef struct VkCooperativeMatrixPropertiesNV +{ + VkStructureType sType; + void* pNext; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeNV AType; + VkComponentTypeNV BType; + VkComponentTypeNV CType; + VkComponentTypeNV DType; + VkScopeNV scope; +} VkCooperativeMatrixPropertiesNV; +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesNV +{ + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesNV; +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesNV +{ + VkStructureType sType; + void* pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesNV; +typedef VkResult(VKAPI_PTR* PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixPropertiesNV* pProperties); +#endif // VK_HEADER_VERSION < 101 + +#if VK_HEADER_VERSION < 121 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD (VkStructureType)1000229000 +#define VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD (VkMemoryPropertyFlagBits)0x00000040 +#define VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD (VkMemoryPropertyFlagBits)0x00000040 +typedef struct VkPhysicalDeviceCoherentMemoryFeaturesAMD +{ + VkStructureType sType; + void* pNext; + VkBool32 deviceCoherentMemory; +} VkPhysicalDeviceCoherentMemoryFeaturesAMD; +#endif // VK_HEADER_VERSION < 121 + +#if VK_HEADER_VERSION < 129 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR (VkStructureType)1000257000 +#define VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR (VkStructureType)1000244001 +#define VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO_KHR (VkStructureType)1000257002 +#define VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO_KHR (VkStructureType)1000257003 +#define VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO_KHR (VkStructureType)1000257004 +#define VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR (VkBufferCreateFlagBits)0x00020000 +#define VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR (VkBufferUsageFlagBits)0x00020000 +#define VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR (VkMemoryAllocateFlagBits)0x00000002 +#define VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR (VkMemoryAllocateFlagBits)0x00000004 +typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferDeviceAddressFeaturesKHR; +typedef struct VkBufferDeviceAddressInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferDeviceAddressInfoKHR; +typedef struct VkBufferOpaqueCaptureAddressCreateInfoKHR +{ + VkStructureType sType; + const void* pNext; + uint64_t opaqueCaptureAddress; +} VkBufferOpaqueCaptureAddressCreateInfoKHR; +typedef struct VkMemoryOpaqueCaptureAddressAllocateInfoKHR +{ + VkStructureType sType; + const void* pNext; + uint64_t opaqueCaptureAddress; +} VkMemoryOpaqueCaptureAddressAllocateInfoKHR; +typedef struct VkDeviceMemoryOpaqueCaptureAddressInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; +} VkDeviceMemoryOpaqueCaptureAddressInfoKHR; +typedef VkDeviceAddress(VKAPI_PTR* PFN_vkGetBufferDeviceAddressKHR)(VkDevice device, const VkBufferDeviceAddressInfoKHR* pInfo); +typedef uint64_t(VKAPI_PTR* PFN_vkGetBufferOpaqueCaptureAddressKHR)(VkDevice device, const VkBufferDeviceAddressInfoKHR* pInfo); +typedef uint64_t(VKAPI_PTR* PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR)(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfoKHR* pInfo); +#endif // VK_HEADER_VERSION < 129 + +#if VK_HEADER_VERSION < 208 +typedef enum VkInstanceCreateFlagBits +{ + VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR = 0x00000001, + VK_INSTANCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkInstanceCreateFlagBits; +#endif // VK_HEADER_VERSION < 208 + +#if VK_HEADER_VERSION < 255 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR (VkStructureType)1000506000 +#define VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_KHR (VkStructureType)1000506001 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR (VkStructureType)1000506002 +typedef enum VkComponentTypeKHR +{ + VK_COMPONENT_TYPE_FLOAT16_KHR = 0, + VK_COMPONENT_TYPE_FLOAT32_KHR = 1, + VK_COMPONENT_TYPE_FLOAT64_KHR = 2, + VK_COMPONENT_TYPE_SINT8_KHR = 3, + VK_COMPONENT_TYPE_SINT16_KHR = 4, + VK_COMPONENT_TYPE_SINT32_KHR = 5, + VK_COMPONENT_TYPE_SINT64_KHR = 6, + VK_COMPONENT_TYPE_UINT8_KHR = 7, + VK_COMPONENT_TYPE_UINT16_KHR = 8, + VK_COMPONENT_TYPE_UINT32_KHR = 9, + VK_COMPONENT_TYPE_UINT64_KHR = 10, + VK_COMPONENT_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkComponentTypeKHR; +typedef enum VkScopeKHR +{ + VK_SCOPE_DEVICE_KHR = 1, + VK_SCOPE_WORKGROUP_KHR = 2, + VK_SCOPE_SUBGROUP_KHR = 3, + VK_SCOPE_QUEUE_FAMILY_KHR = 5, + VK_SCOPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkScopeKHR; +typedef struct VkCooperativeMatrixPropertiesKHR +{ + VkStructureType sType; + void* pNext; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeKHR AType; + VkComponentTypeKHR BType; + VkComponentTypeKHR CType; + VkComponentTypeKHR ResultType; + VkBool32 saturatingAccumulation; + VkScopeKHR scope; +} VkCooperativeMatrixPropertiesKHR; +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesKHR; +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesKHR +{ + VkStructureType sType; + void* pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesKHR; +typedef VkResult(VKAPI_PTR* PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixPropertiesKHR* pProperties); +#endif // VK_HEADER_VERSION < 255 + +#endif // NCNN_VULKAN_HEADER_FIX_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/lib/cmake/ncnn/ncnn-release.cmake b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/lib/cmake/ncnn/ncnn-release.cmake new file mode 100644 index 0000000..1fb8660 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/lib/cmake/ncnn/ncnn-release.cmake @@ -0,0 +1,19 @@ +#---------------------------------------------------------------- +# Generated CMake target import file for configuration "Release". +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "ncnn" for configuration "Release" +set_property(TARGET ncnn APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(ncnn PROPERTIES + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libncnn.so" + IMPORTED_SONAME_RELEASE "libncnn.so" + ) + +list(APPEND _cmake_import_check_targets ncnn ) +list(APPEND _cmake_import_check_files_for_ncnn "${_IMPORT_PREFIX}/lib/libncnn.so" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/lib/cmake/ncnn/ncnn.cmake b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/lib/cmake/ncnn/ncnn.cmake new file mode 100644 index 0000000..6726e95 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/lib/cmake/ncnn/ncnn.cmake @@ -0,0 +1,109 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8) + message(FATAL_ERROR "CMake >= 2.8.0 required") +endif() +if(CMAKE_VERSION VERSION_LESS "2.8.3") + message(FATAL_ERROR "CMake >= 2.8.3 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.8.3...3.25) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_cmake_targets_defined "") +set(_cmake_targets_not_defined "") +set(_cmake_expected_targets "") +foreach(_cmake_expected_target IN ITEMS ncnn) + list(APPEND _cmake_expected_targets "${_cmake_expected_target}") + if(TARGET "${_cmake_expected_target}") + list(APPEND _cmake_targets_defined "${_cmake_expected_target}") + else() + list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") + endif() +endforeach() +unset(_cmake_expected_target) +if(_cmake_targets_defined STREQUAL _cmake_expected_targets) + unset(_cmake_targets_defined) + unset(_cmake_targets_not_defined) + unset(_cmake_expected_targets) + unset(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT _cmake_targets_defined STREQUAL "") + string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") + string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") +endif() +unset(_cmake_targets_defined) +unset(_cmake_targets_not_defined) +unset(_cmake_expected_targets) + + +# Compute the installation prefix relative to this file. +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +if(_IMPORT_PREFIX STREQUAL "/") + set(_IMPORT_PREFIX "") +endif() + +# Create imported target ncnn +add_library(ncnn SHARED IMPORTED) + +set_target_properties(ncnn PROPERTIES + INTERFACE_COMPILE_OPTIONS "-fno-rtti;-fno-exceptions" + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include/ncnn" + INTERFACE_LINK_LIBRARIES "-fopenmp;-static-openmp;-Wl,-wrap,__kmp_affinity_determine_capable;Threads::Threads;android;jnigraphics;log" + INTERFACE_POSITION_INDEPENDENT_CODE "ON" +) + +if(CMAKE_VERSION VERSION_LESS 2.8.12) + message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.") +endif() + +# Load information for each installed configuration. +file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/ncnn-*.cmake") +foreach(_cmake_config_file IN LISTS _cmake_config_files) + include("${_cmake_config_file}") +endforeach() +unset(_cmake_config_file) +unset(_cmake_config_files) + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(_cmake_target IN LISTS _cmake_import_check_targets) + foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}") + if(NOT EXISTS "${_cmake_file}") + message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file + \"${_cmake_file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + unset(_cmake_file) + unset("_cmake_import_check_files_for_${_cmake_target}") +endforeach() +unset(_cmake_target) +unset(_cmake_import_check_targets) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/lib/cmake/ncnn/ncnnConfig.cmake b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/lib/cmake/ncnn/ncnnConfig.cmake new file mode 100644 index 0000000..d3ac286 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/lib/cmake/ncnn/ncnnConfig.cmake @@ -0,0 +1,42 @@ +set(NCNN_OPENMP ON) +set(NCNN_THREADS ON) +set(NCNN_VULKAN OFF) +set(NCNN_SHARED_LIB ON) +set(NCNN_SYSTEM_GLSLANG OFF) + +if(NCNN_OPENMP) + find_package(OpenMP) +endif() + +if(NCNN_THREADS) + set(CMAKE_THREAD_PREFER_PTHREAD TRUE) + set(THREADS_PREFER_PTHREAD_FLAG TRUE) + find_package(Threads REQUIRED) +endif() + +if(NCNN_VULKAN) + find_package(Vulkan REQUIRED) + + if(NOT NCNN_SHARED_LIB) + if(NCNN_SYSTEM_GLSLANG) + find_package(glslang QUIET) + if(NOT glslang_FOUND) + set(GLSLANG_TARGET_DIR "") + include(${GLSLANG_TARGET_DIR}/OSDependentTargets.cmake) + include(${GLSLANG_TARGET_DIR}/OGLCompilerTargets.cmake) + if(EXISTS "${GLSLANG_TARGET_DIR}/HLSLTargets.cmake") + # hlsl support can be optional + include("${GLSLANG_TARGET_DIR}/HLSLTargets.cmake") + endif() + include(${GLSLANG_TARGET_DIR}/glslangTargets.cmake) + include(${GLSLANG_TARGET_DIR}/SPIRVTargets.cmake) + endif() + else() + set(glslang_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../lib/cmake/glslang") + find_package(glslang QUIET) + endif() + + endif() +endif() + +include(${CMAKE_CURRENT_LIST_DIR}/ncnn.cmake) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/lib/pkgconfig/ncnn.pc b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/lib/pkgconfig/ncnn.pc new file mode 100644 index 0000000..4e80236 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86/lib/pkgconfig/ncnn.pc @@ -0,0 +1,11 @@ +prefix=${pcfiledir}/../.. +librarydir=${prefix}/lib +includedir=${prefix}/include + +Name: ncnn +Description: high-performance neural network inference framework optimized for the mobile platform +Version: 1.0.20231027 +URL: https://github.com/Tencent/ncnn +Libs: -L"${librarydir}" -lncnn +Cflags: -I"${includedir}" + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/allocator.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/allocator.h new file mode 100644 index 0000000..3a5ebca --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/allocator.h @@ -0,0 +1,448 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_ALLOCATOR_H +#define NCNN_ALLOCATOR_H + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include "platform.h" + +#include + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +#include +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +// the alignment of all the allocated buffers +#if NCNN_AVX512 +#define NCNN_MALLOC_ALIGN 64 +#elif NCNN_AVX +#define NCNN_MALLOC_ALIGN 32 +#else +#define NCNN_MALLOC_ALIGN 16 +#endif + +// we have some optimized kernels that may overread buffer a bit in loop +// it is common to interleave next-loop data load with arithmetic instructions +// allocating more bytes keeps us safe from SEGV_ACCERR failure +#define NCNN_MALLOC_OVERREAD 64 + +// Aligns a pointer to the specified number of bytes +// ptr Aligned pointer +// n Alignment size that must be a power of two +template +static NCNN_FORCEINLINE _Tp* alignPtr(_Tp* ptr, int n = (int)sizeof(_Tp)) +{ + return (_Tp*)(((size_t)ptr + n - 1) & -n); +} + +// Aligns a buffer size to the specified number of bytes +// The function returns the minimum number that is greater or equal to sz and is divisible by n +// sz Buffer size to align +// n Alignment size that must be a power of two +static NCNN_FORCEINLINE size_t alignSize(size_t sz, int n) +{ + return (sz + n - 1) & -n; +} + +static NCNN_FORCEINLINE void* fastMalloc(size_t size) +{ +#if _MSC_VER + return _aligned_malloc(size, NCNN_MALLOC_ALIGN); +#elif (defined(__unix__) || defined(__APPLE__)) && _POSIX_C_SOURCE >= 200112L || (__ANDROID__ && __ANDROID_API__ >= 17) + void* ptr = 0; + if (posix_memalign(&ptr, NCNN_MALLOC_ALIGN, size + NCNN_MALLOC_OVERREAD)) + ptr = 0; + return ptr; +#elif __ANDROID__ && __ANDROID_API__ < 17 + return memalign(NCNN_MALLOC_ALIGN, size + NCNN_MALLOC_OVERREAD); +#else + unsigned char* udata = (unsigned char*)malloc(size + sizeof(void*) + NCNN_MALLOC_ALIGN + NCNN_MALLOC_OVERREAD); + if (!udata) + return 0; + unsigned char** adata = alignPtr((unsigned char**)udata + 1, NCNN_MALLOC_ALIGN); + adata[-1] = udata; + return adata; +#endif +} + +static NCNN_FORCEINLINE void fastFree(void* ptr) +{ + if (ptr) + { +#if _MSC_VER + _aligned_free(ptr); +#elif (defined(__unix__) || defined(__APPLE__)) && _POSIX_C_SOURCE >= 200112L || (__ANDROID__ && __ANDROID_API__ >= 17) + free(ptr); +#elif __ANDROID__ && __ANDROID_API__ < 17 + free(ptr); +#else + unsigned char* udata = ((unsigned char**)ptr)[-1]; + free(udata); +#endif + } +} + +#if NCNN_THREADS +// exchange-add operation for atomic operations on reference counters +#if defined __riscv && !defined __riscv_atomic +// riscv target without A extension +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#elif defined __INTEL_COMPILER && !(defined WIN32 || defined _WIN32) +// atomic increment on the linux version of the Intel(tm) compiler +#define NCNN_XADD(addr, delta) (int)_InterlockedExchangeAdd(const_cast(reinterpret_cast(addr)), delta) +#elif defined __GNUC__ +#if defined __clang__ && __clang_major__ >= 3 && !defined __ANDROID__ && !defined __EMSCRIPTEN__ && !defined(__CUDACC__) +#ifdef __ATOMIC_ACQ_REL +#define NCNN_XADD(addr, delta) __c11_atomic_fetch_add((_Atomic(int)*)(addr), delta, __ATOMIC_ACQ_REL) +#else +#define NCNN_XADD(addr, delta) __atomic_fetch_add((_Atomic(int)*)(addr), delta, 4) +#endif +#else +#if defined __ATOMIC_ACQ_REL && !defined __clang__ +// version for gcc >= 4.7 +#define NCNN_XADD(addr, delta) (int)__atomic_fetch_add((unsigned*)(addr), (unsigned)(delta), __ATOMIC_ACQ_REL) +#else +#define NCNN_XADD(addr, delta) (int)__sync_fetch_and_add((unsigned*)(addr), (unsigned)(delta)) +#endif +#endif +#elif defined _MSC_VER && !defined RC_INVOKED +#define NCNN_XADD(addr, delta) (int)_InterlockedExchangeAdd((long volatile*)addr, delta) +#else +// thread-unsafe branch +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#endif +#else // NCNN_THREADS +static NCNN_FORCEINLINE int NCNN_XADD(int* addr, int delta) +{ + int tmp = *addr; + *addr += delta; + return tmp; +} +#endif // NCNN_THREADS + +class NCNN_EXPORT Allocator +{ +public: + virtual ~Allocator(); + virtual void* fastMalloc(size_t size) = 0; + virtual void fastFree(void* ptr) = 0; +}; + +class PoolAllocatorPrivate; +class NCNN_EXPORT PoolAllocator : public Allocator +{ +public: + PoolAllocator(); + ~PoolAllocator(); + + // ratio range 0 ~ 1 + // default cr = 0 + void set_size_compare_ratio(float scr); + + // budget drop threshold + // default threshold = 10 + void set_size_drop_threshold(size_t); + + // release all budgets immediately + void clear(); + + virtual void* fastMalloc(size_t size); + virtual void fastFree(void* ptr); + +private: + PoolAllocator(const PoolAllocator&); + PoolAllocator& operator=(const PoolAllocator&); + +private: + PoolAllocatorPrivate* const d; +}; + +class UnlockedPoolAllocatorPrivate; +class NCNN_EXPORT UnlockedPoolAllocator : public Allocator +{ +public: + UnlockedPoolAllocator(); + ~UnlockedPoolAllocator(); + + // ratio range 0 ~ 1 + // default cr = 0 + void set_size_compare_ratio(float scr); + + // budget drop threshold + // default threshold = 10 + void set_size_drop_threshold(size_t); + + // release all budgets immediately + void clear(); + + virtual void* fastMalloc(size_t size); + virtual void fastFree(void* ptr); + +private: + UnlockedPoolAllocator(const UnlockedPoolAllocator&); + UnlockedPoolAllocator& operator=(const UnlockedPoolAllocator&); + +private: + UnlockedPoolAllocatorPrivate* const d; +}; + +#if NCNN_VULKAN + +class VulkanDevice; + +class NCNN_EXPORT VkBufferMemory +{ +public: + VkBuffer buffer; + + // the base offset assigned by allocator + size_t offset; + size_t capacity; + + VkDeviceMemory memory; + void* mapped_ptr; + + // buffer state, modified by command functions internally + mutable VkAccessFlags access_flags; + mutable VkPipelineStageFlags stage_flags; + + // initialize and modified by mat + int refcount; +}; + +class NCNN_EXPORT VkImageMemory +{ +public: + VkImage image; + VkImageView imageview; + + // underlying info assigned by allocator + int width; + int height; + int depth; + VkFormat format; + + VkDeviceMemory memory; + void* mapped_ptr; + + // the base offset assigned by allocator + size_t bind_offset; + size_t bind_capacity; + + // image state, modified by command functions internally + mutable VkAccessFlags access_flags; + mutable VkImageLayout image_layout; + mutable VkPipelineStageFlags stage_flags; + + // in-execution state, modified by command functions internally + mutable int command_refcount; + + // initialize and modified by mat + int refcount; +}; + +class NCNN_EXPORT VkAllocator +{ +public: + explicit VkAllocator(const VulkanDevice* _vkdev); + virtual ~VkAllocator(); + + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size) = 0; + virtual void fastFree(VkBufferMemory* ptr) = 0; + virtual int flush(VkBufferMemory* ptr); + virtual int invalidate(VkBufferMemory* ptr); + + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack) = 0; + virtual void fastFree(VkImageMemory* ptr) = 0; + +public: + const VulkanDevice* vkdev; + uint32_t buffer_memory_type_index; + uint32_t image_memory_type_index; + uint32_t reserved_type_index; + bool mappable; + bool coherent; + +protected: + VkBuffer create_buffer(size_t size, VkBufferUsageFlags usage); + VkDeviceMemory allocate_memory(size_t size, uint32_t memory_type_index); + VkDeviceMemory allocate_dedicated_memory(size_t size, uint32_t memory_type_index, VkImage image, VkBuffer buffer); + + VkImage create_image(int width, int height, int depth, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage); + VkImageView create_imageview(VkImage image, VkFormat format); +}; + +class VkBlobAllocatorPrivate; +class NCNN_EXPORT VkBlobAllocator : public VkAllocator +{ +public: + explicit VkBlobAllocator(const VulkanDevice* vkdev, size_t preferred_block_size = 16 * 1024 * 1024); // 16M + virtual ~VkBlobAllocator(); + +public: + // release all budgets immediately + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkBlobAllocator(const VkBlobAllocator&); + VkBlobAllocator& operator=(const VkBlobAllocator&); + +private: + VkBlobAllocatorPrivate* const d; +}; + +class VkWeightAllocatorPrivate; +class NCNN_EXPORT VkWeightAllocator : public VkAllocator +{ +public: + explicit VkWeightAllocator(const VulkanDevice* vkdev, size_t preferred_block_size = 8 * 1024 * 1024); // 8M + virtual ~VkWeightAllocator(); + +public: + // release all blocks immediately + virtual void clear(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkWeightAllocator(const VkWeightAllocator&); + VkWeightAllocator& operator=(const VkWeightAllocator&); + +private: + VkWeightAllocatorPrivate* const d; +}; + +class VkStagingAllocatorPrivate; +class NCNN_EXPORT VkStagingAllocator : public VkAllocator +{ +public: + explicit VkStagingAllocator(const VulkanDevice* vkdev); + virtual ~VkStagingAllocator(); + +public: + // ratio range 0 ~ 1 + // default cr = 0.75 + void set_size_compare_ratio(float scr); + + // release all budgets immediately + virtual void clear(); + + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkStagingAllocator(const VkStagingAllocator&); + VkStagingAllocator& operator=(const VkStagingAllocator&); + +private: + VkStagingAllocatorPrivate* const d; +}; + +class VkWeightStagingAllocatorPrivate; +class NCNN_EXPORT VkWeightStagingAllocator : public VkAllocator +{ +public: + explicit VkWeightStagingAllocator(const VulkanDevice* vkdev); + virtual ~VkWeightStagingAllocator(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkWeightStagingAllocator(const VkWeightStagingAllocator&); + VkWeightStagingAllocator& operator=(const VkWeightStagingAllocator&); + +private: + VkWeightStagingAllocatorPrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class NCNN_EXPORT VkAndroidHardwareBufferImageAllocator : public VkAllocator +{ +public: + VkAndroidHardwareBufferImageAllocator(const VulkanDevice* _vkdev, AHardwareBuffer* _hb); + virtual ~VkAndroidHardwareBufferImageAllocator(); + +public: + virtual VkBufferMemory* fastMalloc(size_t size); + virtual void fastFree(VkBufferMemory* ptr); + virtual VkImageMemory* fastMalloc(int w, int h, int c, size_t elemsize, int elempack); + virtual void fastFree(VkImageMemory* ptr); + +private: + VkAndroidHardwareBufferImageAllocator(const VkAndroidHardwareBufferImageAllocator&); + VkAndroidHardwareBufferImageAllocator& operator=(const VkAndroidHardwareBufferImageAllocator&); + +public: + int init(); + + int width() const; + int height() const; + uint64_t external_format() const; + +public: + AHardwareBuffer* hb; + AHardwareBuffer_Desc bufferDesc; + VkAndroidHardwareBufferFormatPropertiesANDROID bufferFormatProperties; + VkAndroidHardwareBufferPropertiesANDROID bufferProperties; + VkSamplerYcbcrConversionKHR samplerYcbcrConversion; +}; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_ALLOCATOR_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/benchmark.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/benchmark.h new file mode 100644 index 0000000..ed42c1a --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/benchmark.h @@ -0,0 +1,39 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_BENCHMARK_H +#define NCNN_BENCHMARK_H + +#include "layer.h" +#include "mat.h" +#include "platform.h" + +namespace ncnn { + +// get now timestamp in ms +NCNN_EXPORT double get_current_time(); + +// sleep milliseconds +NCNN_EXPORT void sleep(unsigned long long int milliseconds = 1000); + +#if NCNN_BENCHMARK + +NCNN_EXPORT void benchmark(const Layer* layer, double start, double end); +NCNN_EXPORT void benchmark(const Layer* layer, const Mat& bottom_blob, Mat& top_blob, double start, double end); + +#endif // NCNN_BENCHMARK + +} // namespace ncnn + +#endif // NCNN_BENCHMARK_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/blob.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/blob.h new file mode 100644 index 0000000..c9f144f --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/blob.h @@ -0,0 +1,44 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_BLOB_H +#define NCNN_BLOB_H + +#include "mat.h" +#include "platform.h" + +namespace ncnn { + +class NCNN_EXPORT Blob +{ +public: + // empty + Blob(); + +public: +#if NCNN_STRING + // blob name + std::string name; +#endif // NCNN_STRING + // layer index which produce this blob as output + int producer; + // layer index which need this blob as input + int consumer; + // shape hint + Mat shape; +}; + +} // namespace ncnn + +#endif // NCNN_BLOB_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/c_api.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/c_api.h new file mode 100644 index 0000000..31d5b6d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/c_api.h @@ -0,0 +1,347 @@ +/* Tencent is pleased to support the open source community by making ncnn available. + * + * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +#ifndef NCNN_C_API_H +#define NCNN_C_API_H + +#include "platform.h" + +#if NCNN_C_API + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +NCNN_EXPORT const char* ncnn_version(); + +/* allocator api */ +typedef struct __ncnn_allocator_t* ncnn_allocator_t; +struct NCNN_EXPORT __ncnn_allocator_t +{ + void* pthis; + + void* (*fast_malloc)(ncnn_allocator_t allocator, size_t size); + void (*fast_free)(ncnn_allocator_t allocator, void* ptr); +}; + +NCNN_EXPORT ncnn_allocator_t ncnn_allocator_create_pool_allocator(); +NCNN_EXPORT ncnn_allocator_t ncnn_allocator_create_unlocked_pool_allocator(); +NCNN_EXPORT void ncnn_allocator_destroy(ncnn_allocator_t allocator); + +/* option api */ +typedef struct __ncnn_option_t* ncnn_option_t; + +NCNN_EXPORT ncnn_option_t ncnn_option_create(); +NCNN_EXPORT void ncnn_option_destroy(ncnn_option_t opt); + +NCNN_EXPORT int ncnn_option_get_num_threads(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_num_threads(ncnn_option_t opt, int num_threads); + +NCNN_EXPORT int ncnn_option_get_use_local_pool_allocator(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_use_local_pool_allocator(ncnn_option_t opt, int use_local_pool_allocator); + +NCNN_EXPORT void ncnn_option_set_blob_allocator(ncnn_option_t opt, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_option_set_workspace_allocator(ncnn_option_t opt, ncnn_allocator_t allocator); + +NCNN_EXPORT int ncnn_option_get_use_vulkan_compute(const ncnn_option_t opt); +NCNN_EXPORT void ncnn_option_set_use_vulkan_compute(ncnn_option_t opt, int use_vulkan_compute); + +/* mat api */ +typedef struct __ncnn_mat_t* ncnn_mat_t; + +NCNN_EXPORT ncnn_mat_t ncnn_mat_create(); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_1d(int w, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_2d(int w, int h, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_3d(int w, int h, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_4d(int w, int h, int d, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_1d(int w, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_2d(int w, int h, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_3d(int w, int h, int c, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_4d(int w, int h, int d, int c, void* data, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_1d_elem(int w, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_2d_elem(int w, int h, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_3d_elem(int w, int h, int c, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_4d_elem(int w, int h, int d, int c, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_1d_elem(int w, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_2d_elem(int w, int h, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_3d_elem(int w, int h, int c, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_create_external_4d_elem(int w, int h, int d, int c, void* data, size_t elemsize, int elempack, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_mat_destroy(ncnn_mat_t mat); + +NCNN_EXPORT void ncnn_mat_fill_float(ncnn_mat_t mat, float v); + +NCNN_EXPORT ncnn_mat_t ncnn_mat_clone(const ncnn_mat_t mat, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_1d(const ncnn_mat_t mat, int w, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_2d(const ncnn_mat_t mat, int w, int h, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_3d(const ncnn_mat_t mat, int w, int h, int c, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_reshape_4d(const ncnn_mat_t mat, int w, int h, int d, int c, ncnn_allocator_t allocator); + +NCNN_EXPORT int ncnn_mat_get_dims(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_w(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_h(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_d(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_c(const ncnn_mat_t mat); +NCNN_EXPORT size_t ncnn_mat_get_elemsize(const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_mat_get_elempack(const ncnn_mat_t mat); +NCNN_EXPORT size_t ncnn_mat_get_cstep(const ncnn_mat_t mat); +NCNN_EXPORT void* ncnn_mat_get_data(const ncnn_mat_t mat); + +NCNN_EXPORT void* ncnn_mat_get_channel_data(const ncnn_mat_t mat, int c); + +#if NCNN_PIXEL + +/* mat pixel api */ +#define NCNN_MAT_PIXEL_RGB 1 +#define NCNN_MAT_PIXEL_BGR 2 +#define NCNN_MAT_PIXEL_GRAY 3 +#define NCNN_MAT_PIXEL_RGBA 4 +#define NCNN_MAT_PIXEL_BGRA 5 +#define NCNN_MAT_PIXEL_X2Y(X, Y) (X | (Y << 16)) +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels(const unsigned char* pixels, int type, int w, int h, int stride, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, ncnn_allocator_t allocator); +NCNN_EXPORT ncnn_mat_t ncnn_mat_from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, int target_width, int target_height, ncnn_allocator_t allocator); +NCNN_EXPORT void ncnn_mat_to_pixels(const ncnn_mat_t mat, unsigned char* pixels, int type, int stride); +NCNN_EXPORT void ncnn_mat_to_pixels_resize(const ncnn_mat_t mat, unsigned char* pixels, int type, int target_width, int target_height, int target_stride); + +#endif /* NCNN_PIXEL */ + +NCNN_EXPORT void ncnn_mat_substract_mean_normalize(ncnn_mat_t mat, const float* mean_vals, const float* norm_vals); + +NCNN_EXPORT void ncnn_convert_packing(const ncnn_mat_t src, ncnn_mat_t* dst, int elempack, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_flatten(const ncnn_mat_t src, ncnn_mat_t* dst, const ncnn_option_t opt); + +/* blob api */ +typedef struct __ncnn_blob_t* ncnn_blob_t; + +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_blob_get_name(const ncnn_blob_t blob); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_blob_get_producer(const ncnn_blob_t blob); +NCNN_EXPORT int ncnn_blob_get_consumer(const ncnn_blob_t blob); + +NCNN_EXPORT void ncnn_blob_get_shape(const ncnn_blob_t blob, int* dims, int* w, int* h, int* c); + +/* paramdict api */ +typedef struct __ncnn_paramdict_t* ncnn_paramdict_t; + +NCNN_EXPORT ncnn_paramdict_t ncnn_paramdict_create(); +NCNN_EXPORT void ncnn_paramdict_destroy(ncnn_paramdict_t pd); + +NCNN_EXPORT int ncnn_paramdict_get_type(const ncnn_paramdict_t pd, int id); + +NCNN_EXPORT int ncnn_paramdict_get_int(const ncnn_paramdict_t pd, int id, int def); +NCNN_EXPORT float ncnn_paramdict_get_float(const ncnn_paramdict_t pd, int id, float def); +NCNN_EXPORT ncnn_mat_t ncnn_paramdict_get_array(const ncnn_paramdict_t pd, int id, const ncnn_mat_t def); + +NCNN_EXPORT void ncnn_paramdict_set_int(ncnn_paramdict_t pd, int id, int i); +NCNN_EXPORT void ncnn_paramdict_set_float(ncnn_paramdict_t pd, int id, float f); +NCNN_EXPORT void ncnn_paramdict_set_array(ncnn_paramdict_t pd, int id, const ncnn_mat_t v); + +/* datareader api */ +typedef struct __ncnn_datareader_t* ncnn_datareader_t; +struct NCNN_EXPORT __ncnn_datareader_t +{ + void* pthis; + +#if NCNN_STRING + int (*scan)(ncnn_datareader_t dr, const char* format, void* p); +#endif /* NCNN_STRING */ + size_t (*read)(ncnn_datareader_t dr, void* buf, size_t size); +}; + +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create(); +#if NCNN_STDIO +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create_from_stdio(FILE* fp); +#endif /* NCNN_STDIO */ +NCNN_EXPORT ncnn_datareader_t ncnn_datareader_create_from_memory(const unsigned char** mem); +NCNN_EXPORT void ncnn_datareader_destroy(ncnn_datareader_t dr); + +/* modelbin api */ +typedef struct __ncnn_modelbin_t* ncnn_modelbin_t; +struct NCNN_EXPORT __ncnn_modelbin_t +{ + void* pthis; + + ncnn_mat_t (*load_1d)(const ncnn_modelbin_t mb, int w, int type); + ncnn_mat_t (*load_2d)(const ncnn_modelbin_t mb, int w, int h, int type); + ncnn_mat_t (*load_3d)(const ncnn_modelbin_t mb, int w, int h, int c, int type); +}; + +NCNN_EXPORT ncnn_modelbin_t ncnn_modelbin_create_from_datareader(const ncnn_datareader_t dr); +NCNN_EXPORT ncnn_modelbin_t ncnn_modelbin_create_from_mat_array(const ncnn_mat_t* weights, int n); +NCNN_EXPORT void ncnn_modelbin_destroy(ncnn_modelbin_t mb); + +/* layer api */ +typedef struct __ncnn_layer_t* ncnn_layer_t; +struct NCNN_EXPORT __ncnn_layer_t +{ + void* pthis; + + int (*load_param)(ncnn_layer_t layer, const ncnn_paramdict_t pd); + int (*load_model)(ncnn_layer_t layer, const ncnn_modelbin_t mb); + + int (*create_pipeline)(ncnn_layer_t layer, const ncnn_option_t opt); + int (*destroy_pipeline)(ncnn_layer_t layer, const ncnn_option_t opt); + + int (*forward_1)(const ncnn_layer_t layer, const ncnn_mat_t bottom_blob, ncnn_mat_t* top_blob, const ncnn_option_t opt); + int (*forward_n)(const ncnn_layer_t layer, const ncnn_mat_t* bottom_blobs, int n, ncnn_mat_t* top_blobs, int n2, const ncnn_option_t opt); + + int (*forward_inplace_1)(const ncnn_layer_t layer, ncnn_mat_t bottom_top_blob, const ncnn_option_t opt); + int (*forward_inplace_n)(const ncnn_layer_t layer, ncnn_mat_t* bottom_top_blobs, int n, const ncnn_option_t opt); +}; + +NCNN_EXPORT ncnn_layer_t ncnn_layer_create(); +NCNN_EXPORT ncnn_layer_t ncnn_layer_create_by_typeindex(int typeindex); +#if NCNN_STRING +NCNN_EXPORT ncnn_layer_t ncnn_layer_create_by_type(const char* type); +NCNN_EXPORT int ncnn_layer_type_to_index(const char* type); +#endif /* NCNN_STRING */ +NCNN_EXPORT void ncnn_layer_destroy(ncnn_layer_t layer); + +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_layer_get_name(const ncnn_layer_t layer); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_layer_get_typeindex(const ncnn_layer_t layer); +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_layer_get_type(const ncnn_layer_t layer); +#endif /* NCNN_STRING */ + +NCNN_EXPORT int ncnn_layer_get_one_blob_only(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_inplace(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_vulkan(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_packing(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_bf16_storage(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_fp16_storage(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_support_image_storage(const ncnn_layer_t layer); + +NCNN_EXPORT void ncnn_layer_set_one_blob_only(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_inplace(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_vulkan(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_packing(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_bf16_storage(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_fp16_storage(ncnn_layer_t layer, int enable); +NCNN_EXPORT void ncnn_layer_set_support_image_storage(ncnn_layer_t layer, int enable); + +NCNN_EXPORT int ncnn_layer_get_bottom_count(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_bottom(const ncnn_layer_t layer, int i); +NCNN_EXPORT int ncnn_layer_get_top_count(const ncnn_layer_t layer); +NCNN_EXPORT int ncnn_layer_get_top(const ncnn_layer_t layer, int i); + +NCNN_EXPORT void ncnn_blob_get_bottom_shape(const ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c); +NCNN_EXPORT void ncnn_blob_get_top_shape(const ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c); + +/* layer factory function */ +typedef ncnn_layer_t (*ncnn_layer_creator_t)(void* userdata); +typedef void (*ncnn_layer_destroyer_t)(ncnn_layer_t layer, void* userdata); + +typedef struct __ncnn_net_custom_layer_factory_t* ncnn_net_custom_layer_factory_t; +struct __ncnn_net_custom_layer_factory_t +{ + ncnn_layer_creator_t creator; + ncnn_layer_destroyer_t destroyer; + void* userdata; + ncnn_net_custom_layer_factory_t next; +}; + +/* net api */ +typedef struct __ncnn_net_t* ncnn_net_t; +struct __ncnn_net_t +{ + void* pthis; + + ncnn_net_custom_layer_factory_t custom_layer_factory; +}; + +NCNN_EXPORT ncnn_net_t ncnn_net_create(); +NCNN_EXPORT void ncnn_net_destroy(ncnn_net_t net); + +NCNN_EXPORT ncnn_option_t ncnn_net_get_option(ncnn_net_t net); +NCNN_EXPORT void ncnn_net_set_option(ncnn_net_t net, ncnn_option_t opt); + +#if NCNN_STRING +NCNN_EXPORT void ncnn_net_register_custom_layer_by_type(ncnn_net_t net, const char* type, ncnn_layer_creator_t creator, ncnn_layer_destroyer_t destroyer, void* userdata); +#endif /* NCNN_STRING */ +NCNN_EXPORT void ncnn_net_register_custom_layer_by_typeindex(ncnn_net_t net, int typeindex, ncnn_layer_creator_t creator, ncnn_layer_destroyer_t destroyer, void* userdata); + +#if NCNN_STDIO +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param(ncnn_net_t net, const char* path); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_load_param_bin(ncnn_net_t net, const char* path); +NCNN_EXPORT int ncnn_net_load_model(ncnn_net_t net, const char* path); +#endif /* NCNN_STDIO */ + +#if NCNN_STDIO +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param_memory(ncnn_net_t net, const char* mem); +#endif /* NCNN_STRING */ +#endif /* NCNN_STDIO */ +NCNN_EXPORT int ncnn_net_load_param_bin_memory(ncnn_net_t net, const unsigned char* mem); +NCNN_EXPORT int ncnn_net_load_model_memory(ncnn_net_t net, const unsigned char* mem); + +#if NCNN_STRING +NCNN_EXPORT int ncnn_net_load_param_datareader(ncnn_net_t net, const ncnn_datareader_t dr); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_load_param_bin_datareader(ncnn_net_t net, const ncnn_datareader_t dr); +NCNN_EXPORT int ncnn_net_load_model_datareader(ncnn_net_t net, const ncnn_datareader_t dr); + +NCNN_EXPORT void ncnn_net_clear(ncnn_net_t net); + +NCNN_EXPORT int ncnn_net_get_input_count(const ncnn_net_t net); +NCNN_EXPORT int ncnn_net_get_output_count(const ncnn_net_t net); +#if NCNN_STRING +NCNN_EXPORT const char* ncnn_net_get_input_name(const ncnn_net_t net, int i); +NCNN_EXPORT const char* ncnn_net_get_output_name(const ncnn_net_t net, int i); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_net_get_input_index(const ncnn_net_t net, int i); +NCNN_EXPORT int ncnn_net_get_output_index(const ncnn_net_t net, int i); + +/* extractor api */ +typedef struct __ncnn_extractor_t* ncnn_extractor_t; + +NCNN_EXPORT ncnn_extractor_t ncnn_extractor_create(ncnn_net_t net); +NCNN_EXPORT void ncnn_extractor_destroy(ncnn_extractor_t ex); + +NCNN_EXPORT void ncnn_extractor_set_option(ncnn_extractor_t ex, const ncnn_option_t opt); + +#if NCNN_STRING +NCNN_EXPORT int ncnn_extractor_input(ncnn_extractor_t ex, const char* name, const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_extractor_extract(ncnn_extractor_t ex, const char* name, ncnn_mat_t* mat); +#endif /* NCNN_STRING */ +NCNN_EXPORT int ncnn_extractor_input_index(ncnn_extractor_t ex, int index, const ncnn_mat_t mat); +NCNN_EXPORT int ncnn_extractor_extract_index(ncnn_extractor_t ex, int index, ncnn_mat_t* mat); + +/* mat process api */ +#define NCNN_BORDER_CONSTANT 0 +#define NCNN_BORDER_REPLICATE 1 +#define NCNN_BORDER_REFLECT 2 +#define NCNN_BORDER_TRANSPARENT -233 +NCNN_EXPORT void ncnn_copy_make_border(const ncnn_mat_t src, ncnn_mat_t dst, int top, int bottom, int left, int right, int type, float v, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_copy_make_border_3d(const ncnn_mat_t src, ncnn_mat_t dst, int top, int bottom, int left, int right, int front, int behind, int type, float v, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_copy_cut_border(const ncnn_mat_t src, ncnn_mat_t dst, int top, int bottom, int left, int right, const ncnn_option_t opt); +NCNN_EXPORT void ncnn_copy_cut_border_3d(const ncnn_mat_t src, ncnn_mat_t dst, int top, int bottom, int left, int right, int front, int behind, const ncnn_option_t opt); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* NCNN_C_API */ + +#endif /* NCNN_C_API_H */ diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/command.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/command.h new file mode 100644 index 0000000..337d085 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/command.h @@ -0,0 +1,136 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_COMMAND_H +#define NCNN_COMMAND_H + +#include "platform.h" + +#if NCNN_VULKAN + +#include "mat.h" + +#include + +namespace ncnn { + +class Pipeline; +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class ImportAndroidHardwareBufferPipeline; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API +class VkComputePrivate; +class NCNN_EXPORT VkCompute +{ +public: + explicit VkCompute(const VulkanDevice* vkdev); + virtual ~VkCompute(); + +public: + void record_upload(const Mat& src, VkMat& dst, const Option& opt); + + void record_upload(const Mat& src, VkImageMat& dst, const Option& opt); + + void record_download(const VkMat& src, Mat& dst, const Option& opt); + + void record_download(const VkImageMat& src, Mat& dst, const Option& opt); + + void record_buffer_to_image(const VkMat& src, VkImageMat& dst, const Option& opt); + + void record_image_to_buffer(const VkImageMat& src, VkMat& dst, const Option& opt); + + void record_clone(const Mat& src, VkMat& dst, const Option& opt); + + void record_clone(const Mat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkMat& src, Mat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, Mat& dst, const Option& opt); + + void record_clone(const VkMat& src, VkMat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkMat& src, VkImageMat& dst, const Option& opt); + + void record_clone(const VkImageMat& src, VkMat& dst, const Option& opt); + + void record_pipeline(const Pipeline* pipeline, const std::vector& bindings, const std::vector& constants, const VkMat& dispatcher); + + void record_pipeline(const Pipeline* pipeline, const std::vector& bindings, const std::vector& constants, const VkImageMat& dispatcher); + + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const VkMat& dispatcher); + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const VkImageMat& dispatcher); + void record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const Mat& dispatcher); + +#if NCNN_BENCHMARK + void record_write_timestamp(uint32_t query); +#endif // NCNN_BENCHMARK + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 + void record_import_android_hardware_buffer(const ImportAndroidHardwareBufferPipeline* pipeline, const VkImageMat& src, const VkMat& dst); + + void record_import_android_hardware_buffer(const ImportAndroidHardwareBufferPipeline* pipeline, const VkImageMat& src, const VkImageMat& dst); +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + + int submit_and_wait(); + + int reset(); + +#if NCNN_BENCHMARK + int create_query_pool(uint32_t query_count); + + int get_query_pool_results(uint32_t first_query, uint32_t query_count, std::vector& results); +#endif // NCNN_BENCHMARK + +protected: + const VulkanDevice* vkdev; + + void barrier_readwrite(const VkMat& binding); + void barrier_readwrite(const VkImageMat& binding); + void barrier_readonly(const VkImageMat& binding); + +private: + VkComputePrivate* const d; +}; + +class VkTransferPrivate; +class NCNN_EXPORT VkTransfer +{ +public: + explicit VkTransfer(const VulkanDevice* vkdev); + virtual ~VkTransfer(); + +public: + void record_upload(const Mat& src, VkMat& dst, const Option& opt, bool flatten = true); + + void record_upload(const Mat& src, VkImageMat& dst, const Option& opt); + + int submit_and_wait(); + +protected: + const VulkanDevice* vkdev; + +private: + VkTransferPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_VULKAN + +#endif // NCNN_COMMAND_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/cpu.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/cpu.h new file mode 100644 index 0000000..7d6bfce --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/cpu.h @@ -0,0 +1,178 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_CPU_H +#define NCNN_CPU_H + +#include + +#if (defined _WIN32 && !(defined __MINGW32__)) +#define WIN32_LEAN_AND_MEAN +#include +#endif +#if defined __ANDROID__ || defined __linux__ +#include // cpu_set_t +#endif + +#include "platform.h" + +namespace ncnn { + +class NCNN_EXPORT CpuSet +{ +public: + CpuSet(); + void enable(int cpu); + void disable(int cpu); + void disable_all(); + bool is_enabled(int cpu) const; + int num_enabled() const; + +public: +#if (defined _WIN32 && !(defined __MINGW32__)) + ULONG_PTR mask; +#endif +#if defined __ANDROID__ || defined __linux__ + cpu_set_t cpu_set; +#endif +#if __APPLE__ + unsigned int policy; +#endif +}; + +// test optional cpu features +// edsp = armv7 edsp +NCNN_EXPORT int cpu_support_arm_edsp(); +// neon = armv7 neon or aarch64 asimd +NCNN_EXPORT int cpu_support_arm_neon(); +// vfpv4 = armv7 fp16 + fma +NCNN_EXPORT int cpu_support_arm_vfpv4(); +// asimdhp = aarch64 asimd half precision +NCNN_EXPORT int cpu_support_arm_asimdhp(); +// cpuid = aarch64 cpuid info +NCNN_EXPORT int cpu_support_arm_cpuid(); +// asimddp = aarch64 asimd dot product +NCNN_EXPORT int cpu_support_arm_asimddp(); +// asimdfhm = aarch64 asimd fhm +NCNN_EXPORT int cpu_support_arm_asimdfhm(); +// bf16 = aarch64 bf16 +NCNN_EXPORT int cpu_support_arm_bf16(); +// i8mm = aarch64 i8mm +NCNN_EXPORT int cpu_support_arm_i8mm(); +// sve = aarch64 sve +NCNN_EXPORT int cpu_support_arm_sve(); +// sve2 = aarch64 sve2 +NCNN_EXPORT int cpu_support_arm_sve2(); +// svebf16 = aarch64 svebf16 +NCNN_EXPORT int cpu_support_arm_svebf16(); +// svei8mm = aarch64 svei8mm +NCNN_EXPORT int cpu_support_arm_svei8mm(); +// svef32mm = aarch64 svef32mm +NCNN_EXPORT int cpu_support_arm_svef32mm(); + +// avx = x86 avx +NCNN_EXPORT int cpu_support_x86_avx(); +// fma = x86 fma +NCNN_EXPORT int cpu_support_x86_fma(); +// xop = x86 xop +NCNN_EXPORT int cpu_support_x86_xop(); +// f16c = x86 f16c +NCNN_EXPORT int cpu_support_x86_f16c(); +// avx2 = x86 avx2 + fma + f16c +NCNN_EXPORT int cpu_support_x86_avx2(); +// avx_vnni = x86 avx vnni +NCNN_EXPORT int cpu_support_x86_avx_vnni(); +// avx512 = x86 avx512f + avx512cd + avx512bw + avx512dq + avx512vl +NCNN_EXPORT int cpu_support_x86_avx512(); +// avx512_vnni = x86 avx512 vnni +NCNN_EXPORT int cpu_support_x86_avx512_vnni(); +// avx512_bf16 = x86 avx512 bf16 +NCNN_EXPORT int cpu_support_x86_avx512_bf16(); +// avx512_fp16 = x86 avx512 fp16 +NCNN_EXPORT int cpu_support_x86_avx512_fp16(); + +// lsx = loongarch lsx +NCNN_EXPORT int cpu_support_loongarch_lsx(); +// lasx = loongarch lasx +NCNN_EXPORT int cpu_support_loongarch_lasx(); + +// msa = mips mas +NCNN_EXPORT int cpu_support_mips_msa(); +// mmi = loongson mmi +NCNN_EXPORT int cpu_support_loongson_mmi(); + +// v = riscv vector +NCNN_EXPORT int cpu_support_riscv_v(); +// zfh = riscv half-precision float +NCNN_EXPORT int cpu_support_riscv_zfh(); +// vlenb = riscv vector length in bytes +NCNN_EXPORT int cpu_riscv_vlenb(); + +// cpu info +NCNN_EXPORT int get_cpu_count(); +NCNN_EXPORT int get_little_cpu_count(); +NCNN_EXPORT int get_big_cpu_count(); + +NCNN_EXPORT int get_physical_cpu_count(); +NCNN_EXPORT int get_physical_little_cpu_count(); +NCNN_EXPORT int get_physical_big_cpu_count(); + +// cpu l2 varies from 64k to 1M, but l3 can be zero +NCNN_EXPORT int get_cpu_level2_cache_size(); +NCNN_EXPORT int get_cpu_level3_cache_size(); + +// bind all threads on little clusters if powersave enabled +// affects HMP arch cpu like ARM big.LITTLE +// only implemented on android at the moment +// switching powersave is expensive and not thread-safe +// 0 = all cores enabled(default) +// 1 = only little clusters enabled +// 2 = only big clusters enabled +// return 0 if success for setter function +NCNN_EXPORT int get_cpu_powersave(); +NCNN_EXPORT int set_cpu_powersave(int powersave); + +// convenient wrapper +NCNN_EXPORT const CpuSet& get_cpu_thread_affinity_mask(int powersave); + +// set explicit thread affinity +NCNN_EXPORT int set_cpu_thread_affinity(const CpuSet& thread_affinity_mask); + +// runtime thread affinity info +NCNN_EXPORT int is_current_thread_running_on_a53_a55(); + +// misc function wrapper for openmp routines +NCNN_EXPORT int get_omp_num_threads(); +NCNN_EXPORT void set_omp_num_threads(int num_threads); + +NCNN_EXPORT int get_omp_dynamic(); +NCNN_EXPORT void set_omp_dynamic(int dynamic); + +NCNN_EXPORT int get_omp_thread_num(); + +NCNN_EXPORT int get_kmp_blocktime(); +NCNN_EXPORT void set_kmp_blocktime(int time_ms); + +// need to flush denormals on Intel Chipset. +// Other architectures such as ARM can be added as needed. +// 0 = DAZ OFF, FTZ OFF +// 1 = DAZ ON , FTZ OFF +// 2 = DAZ OFF, FTZ ON +// 3 = DAZ ON, FTZ ON +NCNN_EXPORT int get_flush_denormals(); +NCNN_EXPORT int set_flush_denormals(int flush_denormals); + +} // namespace ncnn + +#endif // NCNN_CPU_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/datareader.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/datareader.h new file mode 100644 index 0000000..ed2aba3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/datareader.h @@ -0,0 +1,122 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_DATAREADER_H +#define NCNN_DATAREADER_H + +#include "platform.h" +#if NCNN_STDIO +#include +#endif + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#endif +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +// data read wrapper +class NCNN_EXPORT DataReader +{ +public: + DataReader(); + virtual ~DataReader(); + +#if NCNN_STRING + // parse plain param text + // return 1 if scan success + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + + // read binary param and model data + // return bytes read + virtual size_t read(void* buf, size_t size) const; + + // get model data reference + // return bytes referenced + virtual size_t reference(size_t size, const void** buf) const; +}; + +#if NCNN_STDIO +class DataReaderFromStdioPrivate; +class NCNN_EXPORT DataReaderFromStdio : public DataReader +{ +public: + explicit DataReaderFromStdio(FILE* fp); + virtual ~DataReaderFromStdio(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + +private: + DataReaderFromStdio(const DataReaderFromStdio&); + DataReaderFromStdio& operator=(const DataReaderFromStdio&); + +private: + DataReaderFromStdioPrivate* const d; +}; +#endif // NCNN_STDIO + +class DataReaderFromMemoryPrivate; +class NCNN_EXPORT DataReaderFromMemory : public DataReader +{ +public: + explicit DataReaderFromMemory(const unsigned char*& mem); + virtual ~DataReaderFromMemory(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + virtual size_t reference(size_t size, const void** buf) const; + +private: + DataReaderFromMemory(const DataReaderFromMemory&); + DataReaderFromMemory& operator=(const DataReaderFromMemory&); + +private: + DataReaderFromMemoryPrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +class DataReaderFromAndroidAssetPrivate; +class NCNN_EXPORT DataReaderFromAndroidAsset : public DataReader +{ +public: + explicit DataReaderFromAndroidAsset(AAsset* asset); + virtual ~DataReaderFromAndroidAsset(); + +#if NCNN_STRING + virtual int scan(const char* format, void* p) const; +#endif // NCNN_STRING + virtual size_t read(void* buf, size_t size) const; + +private: + DataReaderFromAndroidAsset(const DataReaderFromAndroidAsset&); + DataReaderFromAndroidAsset& operator=(const DataReaderFromAndroidAsset&); + +private: + DataReaderFromAndroidAssetPrivate* const d; +}; +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + +} // namespace ncnn + +#endif // NCNN_DATAREADER_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/gpu.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/gpu.h new file mode 100644 index 0000000..1eff228 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/gpu.h @@ -0,0 +1,392 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_GPU_H +#define NCNN_GPU_H + +#include "platform.h" + +#if NCNN_VULKAN + +#include "mat.h" + +#include + +#include "vulkan_header_fix.h" + +namespace ncnn { + +// instance + +// Create VkInstance and initialize some objects that need to be calculated by GPU +// Creates a VkInstance object, Checks the extended attributes supported by the Vulkan instance concerned, +// Initializes, and creates Vulkan validation layers (if ENABLE_VALIDATION_LAYER is enabled), +// Iterates over all supported physical devices, etc. +NCNN_EXPORT int create_gpu_instance(); + +// Get global VkInstance variable +// Must be called after create_gpu_instance() and before destroy_gpu_instance() +NCNN_EXPORT VkInstance get_gpu_instance(); + +// Destroy VkInstance object and free the memory of the associated object +// Usually called in the destructor of the main program exit +NCNN_EXPORT void destroy_gpu_instance(); + +// instance extension capability +extern int support_VK_KHR_external_memory_capabilities; +extern int support_VK_KHR_get_physical_device_properties2; +extern int support_VK_KHR_get_surface_capabilities2; +extern int support_VK_KHR_surface; +extern int support_VK_EXT_debug_utils; +extern int support_VK_EXT_validation_features; +extern int support_VK_EXT_validation_flags; +#if __ANDROID_API__ >= 26 +extern int support_VK_KHR_android_surface; +#endif // __ANDROID_API__ >= 26 + +// VK_KHR_cooperative_matrix +extern PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR; + +// VK_KHR_external_memory_capabilities +extern PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR vkGetPhysicalDeviceExternalBufferPropertiesKHR; + +// VK_KHR_get_physical_device_properties2 +extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; +extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; +extern PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceImageFormatProperties2KHR vkGetPhysicalDeviceImageFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR; +extern PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR; +extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR vkGetPhysicalDeviceSparseImageFormatProperties2KHR; + +// VK_KHR_get_surface_capabilities2 +extern PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR; + +// VK_KHR_surface +extern PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; +extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; +extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; +extern PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; + +#if __ANDROID_API__ >= 26 +// VK_KHR_android_surface +extern PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; +#endif // __ANDROID_API__ >= 26 + +// VK_NV_cooperative_matrix +extern PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV vkGetPhysicalDeviceCooperativeMatrixPropertiesNV; + +// get info +NCNN_EXPORT int get_gpu_count(); +NCNN_EXPORT int get_default_gpu_index(); + +class GpuInfoPrivate; +class NCNN_EXPORT GpuInfo +{ +public: + explicit GpuInfo(); + virtual ~GpuInfo(); + + // vulkan physical device + VkPhysicalDevice physical_device() const; + + // memory properties + const VkPhysicalDeviceMemoryProperties& physical_device_memory_properties() const; + + // info + uint32_t api_version() const; + uint32_t driver_version() const; + uint32_t vendor_id() const; + uint32_t device_id() const; + const char* device_name() const; + uint8_t* pipeline_cache_uuid() const; + + // 0 = discrete gpu + // 1 = integrated gpu + // 2 = virtual gpu + // 3 = cpu + int type() const; + + // hardware limit + uint32_t max_shared_memory_size() const; + uint32_t max_workgroup_count_x() const; + uint32_t max_workgroup_count_y() const; + uint32_t max_workgroup_count_z() const; + uint32_t max_workgroup_invocations() const; + uint32_t max_workgroup_size_x() const; + uint32_t max_workgroup_size_y() const; + uint32_t max_workgroup_size_z() const; + size_t memory_map_alignment() const; + size_t buffer_offset_alignment() const; + size_t non_coherent_atom_size() const; + size_t buffer_image_granularity() const; + uint32_t max_image_dimension_1d() const; + uint32_t max_image_dimension_2d() const; + uint32_t max_image_dimension_3d() const; + float timestamp_period() const; + + // runtime + uint32_t compute_queue_family_index() const; + uint32_t graphics_queue_family_index() const; + uint32_t transfer_queue_family_index() const; + + uint32_t compute_queue_count() const; + uint32_t graphics_queue_count() const; + uint32_t transfer_queue_count() const; + + // property + bool unified_compute_transfer_queue() const; + + // subgroup + uint32_t subgroup_size() const; + bool support_subgroup_basic() const; + bool support_subgroup_vote() const; + bool support_subgroup_ballot() const; + bool support_subgroup_shuffle() const; + + // bug is not feature + bool bug_storage_buffer_no_l1() const; + bool bug_corrupted_online_pipeline_cache() const; + bool bug_buffer_image_load_zero() const; + + // but sometimes bug is a feature + bool bug_implicit_fp16_arithmetic() const; + + // fp16 and int8 feature + bool support_fp16_packed() const; + bool support_fp16_storage() const; + bool support_fp16_arithmetic() const; + bool support_int8_packed() const; + bool support_int8_storage() const; + bool support_int8_arithmetic() const; + + // ycbcr conversion feature + bool support_ycbcr_conversion() const; + + // cooperative matrix feature + bool support_cooperative_matrix() const; + bool support_cooperative_matrix_16_8_8() const; + bool support_cooperative_matrix_16_8_16() const; + bool support_cooperative_matrix_16_16_16() const; + + // extension capability + int support_VK_KHR_8bit_storage() const; + int support_VK_KHR_16bit_storage() const; + int support_VK_KHR_bind_memory2() const; + int support_VK_KHR_buffer_device_address() const; + int support_VK_KHR_create_renderpass2() const; + int support_VK_KHR_cooperative_matrix() const; + int support_VK_KHR_dedicated_allocation() const; + int support_VK_KHR_descriptor_update_template() const; + int support_VK_KHR_external_memory() const; + int support_VK_KHR_get_memory_requirements2() const; + int support_VK_KHR_maintenance1() const; + int support_VK_KHR_maintenance2() const; + int support_VK_KHR_maintenance3() const; + int support_VK_KHR_multiview() const; + int support_VK_KHR_portability_subset() const; + int support_VK_KHR_push_descriptor() const; + int support_VK_KHR_sampler_ycbcr_conversion() const; + int support_VK_KHR_shader_float16_int8() const; + int support_VK_KHR_shader_float_controls() const; + int support_VK_KHR_storage_buffer_storage_class() const; + int support_VK_KHR_swapchain() const; + int support_VK_EXT_buffer_device_address() const; + int support_VK_EXT_descriptor_indexing() const; + int support_VK_EXT_memory_budget() const; + int support_VK_EXT_memory_priority() const; + int support_VK_EXT_queue_family_foreign() const; + int support_VK_AMD_device_coherent_memory() const; +#if __ANDROID_API__ >= 26 + int support_VK_ANDROID_external_memory_android_hardware_buffer() const; +#endif // __ANDROID_API__ >= 26 + int support_VK_NV_cooperative_matrix() const; + +private: + GpuInfo(const GpuInfo&); + GpuInfo& operator=(const GpuInfo&); + +private: + friend int create_gpu_instance(); + GpuInfoPrivate* const d; +}; + +NCNN_EXPORT const GpuInfo& get_gpu_info(int device_index = get_default_gpu_index()); + +class VkAllocator; +class VkCompute; +class Option; +class PipelineCache; +class VulkanDevicePrivate; +class NCNN_EXPORT VulkanDevice +{ +public: + VulkanDevice(int device_index = get_default_gpu_index()); + ~VulkanDevice(); + + const GpuInfo& info; + + VkDevice vkdevice() const; + + VkShaderModule compile_shader_module(const uint32_t* spv_data, size_t spv_data_size) const; + + // with fixed workgroup size + VkShaderModule compile_shader_module(const uint32_t* spv_data, size_t spv_data_size, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z) const; + + // helper for creating pipeline + int create_descriptorset_layout(int binding_count, const int* binding_types, VkDescriptorSetLayout* descriptorset_layout) const; + int create_pipeline_layout(int push_constant_count, VkDescriptorSetLayout descriptorset_layout, VkPipelineLayout* pipeline_layout) const; + int create_pipeline(VkShaderModule shader_module, VkPipelineLayout pipeline_layout, const std::vector& specializations, VkPipeline* pipeline) const; + int create_descriptor_update_template(int binding_count, const int* binding_types, VkDescriptorSetLayout descriptorset_layout, VkPipelineLayout pipeline_layout, VkDescriptorUpdateTemplateKHR* descriptor_update_template) const; + + uint32_t find_memory_index(uint32_t memory_type_bits, VkFlags required, VkFlags preferred, VkFlags preferred_not) const; + bool is_mappable(uint32_t memory_type_index) const; + bool is_coherent(uint32_t memory_type_index) const; + + VkQueue acquire_queue(uint32_t queue_family_index) const; + void reclaim_queue(uint32_t queue_family_index, VkQueue queue) const; + + // allocator on this device + VkAllocator* acquire_blob_allocator() const; + void reclaim_blob_allocator(VkAllocator* allocator) const; + + VkAllocator* acquire_staging_allocator() const; + void reclaim_staging_allocator(VkAllocator* allocator) const; + + // immutable sampler for texelfetch + const VkSampler* immutable_texelfetch_sampler() const; + + // dummy buffer image + VkMat get_dummy_buffer() const; + VkImageMat get_dummy_image() const; + VkImageMat get_dummy_image_readonly() const; + + // pipeline cache on this device + const PipelineCache* get_pipeline_cache() const; + + // test image allocation + bool shape_support_image_storage(const Mat& shape) const; + + // current gpu heap memory budget in MB + uint32_t get_heap_budget() const; + + // utility operator + void convert_packing(const VkMat& src, VkMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkImageMat& src, VkImageMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkMat& src, VkImageMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + void convert_packing(const VkImageMat& src, VkMat& dst, int dst_elempack, VkCompute& cmd, const Option& opt) const; + + // VK_KHR_bind_memory2 + PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; + PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; + + // VK_KHR_buffer_device_address + PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR; + PFN_vkGetBufferOpaqueCaptureAddressKHR vkGetBufferOpaqueCaptureAddressKHR; + PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR vkGetDeviceMemoryOpaqueCaptureAddressKHR; + + // VK_KHR_create_renderpass2 + PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; + PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; + PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; + + // VK_KHR_descriptor_update_template + PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; + PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; + PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; + + // VK_KHR_get_memory_requirements2 + PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; + PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; + PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; + + // VK_KHR_maintenance1 + PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; + + // VK_KHR_maintenance3 + PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; + + // VK_KHR_push_descriptor + PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; + PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; + + // VK_KHR_sampler_ycbcr_conversion + PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; + PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; + + // VK_KHR_swapchain + PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; + PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; + PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; + PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; + PFN_vkQueuePresentKHR vkQueuePresentKHR; + + // VK_EXT_buffer_device_address + PFN_vkGetBufferDeviceAddressEXT vkGetBufferDeviceAddressEXT; + +#if __ANDROID_API__ >= 26 + // VK_ANDROID_external_memory_android_hardware_buffer + PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; + PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; +#endif // __ANDROID_API__ >= 26 + +protected: + // device extension + int init_device_extension(); + +private: + VulkanDevice(const VulkanDevice&); + VulkanDevice& operator=(const VulkanDevice&); + +private: + VulkanDevicePrivate* const d; +}; + +NCNN_EXPORT VulkanDevice* get_gpu_device(int device_index = get_default_gpu_index()); + +// online spirv compilation +NCNN_EXPORT int compile_spirv_module(const char* comp_string, const Option& opt, std::vector& spirv); +NCNN_EXPORT int compile_spirv_module(const char* comp_data, int comp_data_size, const Option& opt, std::vector& spirv); +NCNN_EXPORT int compile_spirv_module(int shader_type_index, const Option& opt, std::vector& spirv); + +// info from spirv +class NCNN_EXPORT ShaderInfo +{ +public: + int specialization_count; + int binding_count; + int push_constant_count; + + // 0 = null + // 1 = storage buffer + // 2 = storage image + // 3 = combined image sampler + int binding_types[16]; // 16 is large enough I think ... + + int reserved_0; + int reserved_1; + int reserved_2; + int reserved_3; +}; + +NCNN_EXPORT int resolve_shader_info(const uint32_t* spv_data, size_t spv_data_size, ShaderInfo& shader_info); + +} // namespace ncnn + +#endif // NCNN_VULKAN + +#endif // NCNN_GPU_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/layer.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/layer.h new file mode 100644 index 0000000..f0418a9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/layer.h @@ -0,0 +1,222 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_H +#define NCNN_LAYER_H + +#include "mat.h" +#include "modelbin.h" +#include "option.h" +#include "paramdict.h" +#include "platform.h" + +#if NCNN_VULKAN +#include "command.h" +#include "pipeline.h" + +#include +#endif // NCNN_VULKAN + +namespace ncnn { + +class NCNN_EXPORT Layer +{ +public: + // empty + Layer(); + // virtual destructor + virtual ~Layer(); + + // load layer specific parameter from parsed dict + // return 0 if success + virtual int load_param(const ParamDict& pd); + + // load layer specific weight data from model binary + // return 0 if success + virtual int load_model(const ModelBin& mb); + + // layer implementation specific setup + // return 0 if success + virtual int create_pipeline(const Option& opt); + + // layer implementation specific clean + // return 0 if success + virtual int destroy_pipeline(const Option& opt); + +public: + // one input and one output blob + bool one_blob_only; + + // support inplace inference + bool support_inplace; + + // support vulkan compute + bool support_vulkan; + + // accept input blob with packed storage + bool support_packing; + + // accept bf16 + bool support_bf16_storage; + + // accept fp16 + bool support_fp16_storage; + + // accept int8 + bool support_int8_storage; + + // shader image storage + bool support_image_storage; + + // shader tensor storage + bool support_tensor_storage; + + bool support_reserved_00; + + bool support_reserved_0; + bool support_reserved_1; + bool support_reserved_2; + bool support_reserved_3; + bool support_reserved_4; + bool support_reserved_5; + bool support_reserved_6; + bool support_reserved_7; + bool support_reserved_8; + bool support_reserved_9; + + // feature disabled set + int featmask; + +public: + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, const Option& opt) const; + virtual int forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, const Option& opt) const; + virtual int forward_inplace(Mat& bottom_top_blob, const Option& opt) const; + +#if NCNN_VULKAN +public: + // upload weight blob from host to device + virtual int upload_model(VkTransfer& cmd, const Option& opt); + +public: + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inference + // return 0 if success + virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward_inplace(VkMat& bottom_top_blob, VkCompute& cmd, const Option& opt) const; + + // implement inplace inference + // return 0 if success + virtual int forward_inplace(std::vector& bottom_top_blobs, VkCompute& cmd, const Option& opt) const; + virtual int forward_inplace(VkImageMat& bottom_top_blob, VkCompute& cmd, const Option& opt) const; + +public: + // assigned immediately after creating this layer + const VulkanDevice* vkdev; +#endif // NCNN_VULKAN + +public: + // custom user data + void* userdata; + // layer type index + int typeindex; +#if NCNN_STRING + // layer type name + std::string type; + // layer name + std::string name; +#endif // NCNN_STRING + // blob index which this layer needs as input + std::vector bottoms; + // blob index which this layer produces as output + std::vector tops; + // shape hint + std::vector bottom_shapes; + std::vector top_shapes; +}; + +// layer factory function +typedef Layer* (*layer_creator_func)(void*); +typedef void (*layer_destroyer_func)(Layer*, void*); + +struct layer_registry_entry +{ +#if NCNN_STRING + // layer type name + const char* name; +#endif // NCNN_STRING + // layer factory entry + layer_creator_func creator; +}; + +struct custom_layer_registry_entry +{ +#if NCNN_STRING + // layer type name + const char* name; +#endif // NCNN_STRING + // layer factory entry + layer_creator_func creator; + layer_destroyer_func destroyer; + void* userdata; +}; + +struct overwrite_builtin_layer_registry_entry +{ + // layer type index + int typeindex; + // layer factory entry + layer_creator_func creator; + layer_destroyer_func destroyer; + void* userdata; +}; + +#if NCNN_STRING +// get layer type from type name +NCNN_EXPORT int layer_to_index(const char* type); +// create layer from type name +NCNN_EXPORT Layer* create_layer(const char* type); +#endif // NCNN_STRING +// create layer from layer type +NCNN_EXPORT Layer* create_layer(int index); + +#define DEFINE_LAYER_CREATOR(name) \ + ::ncnn::Layer* name##_layer_creator(void* /*userdata*/) \ + { \ + return new name; \ + } + +#define DEFINE_LAYER_DESTROYER(name) \ + void name##_layer_destroyer(::ncnn::Layer* layer, void* /*userdata*/) \ + { \ + delete layer; \ + } + +} // namespace ncnn + +#endif // NCNN_LAYER_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/layer_shader_type.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/layer_shader_type.h new file mode 100644 index 0000000..c143e7d --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/layer_shader_type.h @@ -0,0 +1,29 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_SHADER_TYPE_H +#define NCNN_LAYER_SHADER_TYPE_H + +namespace ncnn { + +namespace LayerShaderType { +enum LayerShaderType +{ +#include "layer_shader_type_enum.h" +}; +} // namespace LayerShaderType + +} // namespace ncnn + +#endif // NCNN_LAYER_SHADER_TYPE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/layer_shader_type_enum.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/layer_shader_type_enum.h new file mode 100644 index 0000000..aac8803 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/layer_shader_type_enum.h @@ -0,0 +1,5 @@ +// Layer Shader Enum header +// +// This file is auto-generated by cmake, don't edit it. + + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/layer_type.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/layer_type.h new file mode 100644 index 0000000..511c714 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/layer_type.h @@ -0,0 +1,30 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_LAYER_TYPE_H +#define NCNN_LAYER_TYPE_H + +namespace ncnn { + +namespace LayerType { +enum LayerType +{ +#include "layer_type_enum.h" + CustomBit = (1 << 8), +}; +} // namespace LayerType + +} // namespace ncnn + +#endif // NCNN_LAYER_TYPE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/layer_type_enum.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/layer_type_enum.h new file mode 100644 index 0000000..97153ed --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/layer_type_enum.h @@ -0,0 +1,109 @@ +// Layer Type Enum header +// +// This file is auto-generated by cmake, don't edit it. + +AbsVal = 0, +ArgMax = 1, +BatchNorm = 2, +Bias = 3, +BNLL = 4, +Concat = 5, +Convolution = 6, +Crop = 7, +Deconvolution = 8, +Dropout = 9, +Eltwise = 10, +ELU = 11, +Embed = 12, +Exp = 13, +Flatten = 14, +InnerProduct = 15, +Input = 16, +Log = 17, +LRN = 18, +MemoryData = 19, +MVN = 20, +Pooling = 21, +Power = 22, +PReLU = 23, +Proposal = 24, +Reduction = 25, +ReLU = 26, +Reshape = 27, +ROIPooling = 28, +Scale = 29, +Sigmoid = 30, +Slice = 31, +Softmax = 32, +Split = 33, +SPP = 34, +TanH = 35, +Threshold = 36, +Tile = 37, +RNN = 38, +LSTM = 39, +BinaryOp = 40, +UnaryOp = 41, +ConvolutionDepthWise = 42, +Padding = 43, +Squeeze = 44, +ExpandDims = 45, +Normalize = 46, +Permute = 47, +PriorBox = 48, +DetectionOutput = 49, +Interp = 50, +DeconvolutionDepthWise = 51, +ShuffleChannel = 52, +InstanceNorm = 53, +Clip = 54, +Reorg = 55, +YoloDetectionOutput = 56, +Quantize = 57, +Dequantize = 58, +Yolov3DetectionOutput = 59, +PSROIPooling = 60, +ROIAlign = 61, +Packing = 62, +Requantize = 63, +Cast = 64, +HardSigmoid = 65, +SELU = 66, +HardSwish = 67, +Noop = 68, +PixelShuffle = 69, +DeepCopy = 70, +Mish = 71, +StatisticsPooling = 72, +Swish = 73, +Gemm = 74, +GroupNorm = 75, +LayerNorm = 76, +Softplus = 77, +GRU = 78, +MultiHeadAttention = 79, +GELU = 80, +Convolution1D = 81, +Pooling1D = 82, +ConvolutionDepthWise1D = 83, +Convolution3D = 84, +ConvolutionDepthWise3D = 85, +Pooling3D = 86, +MatMul = 87, +Deconvolution1D = 88, +DeconvolutionDepthWise1D = 89, +Deconvolution3D = 90, +DeconvolutionDepthWise3D = 91, +Einsum = 92, +DeformableConv2D = 93, +GLU = 94, +Fold = 95, +Unfold = 96, +GridSample = 97, +CumulativeSum = 98, +CopyTo = 99, +Erf = 100, +Diag = 101, +CELU = 102, +Shrink = 103, + diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/mat.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/mat.h new file mode 100644 index 0000000..c6f59ef --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/mat.h @@ -0,0 +1,1843 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_MAT_H +#define NCNN_MAT_H + +#include +#include +#if __ARM_NEON +#include +#endif +#if __SSE2__ +#include +#if __AVX__ +#include +#endif +#endif +#if __mips_msa +#include +#endif +#if __loongarch_sx +#include +#endif +#if __riscv_vector +#include +#include "cpu.h" // cpu_riscv_vlenb() +#endif + +#include "allocator.h" +#include "option.h" +#include "platform.h" + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#if NCNN_PIXEL +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#include +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API +#endif // NCNN_PIXEL + +namespace ncnn { + +#if NCNN_VULKAN +class VkMat; +class VkImageMat; +#endif // NCNN_VULKAN + +// the three dimension matrix +class NCNN_EXPORT Mat +{ +public: + // empty + Mat(); + // vec + Mat(int w, size_t elemsize = 4u, Allocator* allocator = 0); + // image + Mat(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0); + // dim + Mat(int w, int h, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // cube + Mat(int w, int h, int d, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // packed vec + Mat(int w, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed image + Mat(int w, int h, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed dim + Mat(int w, int h, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed cube + Mat(int w, int h, int d, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // copy + Mat(const Mat& m); + // external vec + Mat(int w, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external image + Mat(int w, int h, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external dim + Mat(int w, int h, int c, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external cube + Mat(int w, int h, int d, int c, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external packed vec + Mat(int w, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed image + Mat(int w, int h, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed dim + Mat(int w, int h, int c, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed cube + Mat(int w, int h, int d, int c, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // release + ~Mat(); + // assign + Mat& operator=(const Mat& m); + // set all + void fill(float v); + void fill(int v); +#if __ARM_NEON + void fill(float32x4_t _v); + void fill(uint16x4_t _v); + void fill(int32x4_t _v); + void fill(int32x4_t _v0, int32x4_t _v1); +#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC + void fill(float16x4_t _v); + void fill(float16x8_t _v); +#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +#endif // __ARM_NEON +#if __SSE2__ +#if __AVX__ +#if __AVX512F__ + void fill(__m512 _v); +#endif // __AVX512F__ + void fill(__m256 _v, int i = 0); +#endif // __AVX__ + void fill(__m128 _v); + void fill(__m128i _v); +#endif // __SSE2__ +#if __mips_msa + void fill(v4f32 _v); +#endif // __mips_msa +#if __loongarch_sx + void fill(__m128 _v); +#endif //__loongarch_sx +#if __riscv_vector + void fill(vfloat32m1_t _v); + void fill(vuint16m1_t _v); + void fill(vint8m1_t _v); +#if __riscv_zfh + void fill(vfloat16m1_t _v); +#endif // __riscv_zfh +#endif // __riscv_vector + template + void fill(T v); + // deep copy + Mat clone(Allocator* allocator = 0) const; + // deep copy from other mat, inplace + void clone_from(const ncnn::Mat& mat, Allocator* allocator = 0); + // reshape vec + Mat reshape(int w, Allocator* allocator = 0) const; + // reshape image + Mat reshape(int w, int h, Allocator* allocator = 0) const; + // reshape dim + Mat reshape(int w, int h, int c, Allocator* allocator = 0) const; + // reshape cube + Mat reshape(int w, int h, int d, int c, Allocator* allocator = 0) const; + // allocate vec + void create(int w, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate image + void create(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate dim + void create(int w, int h, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate like + void create_like(const Mat& m, Allocator* allocator = 0); +#if NCNN_VULKAN + // allocate like + void create_like(const VkMat& m, Allocator* allocator = 0); + // allocate like + void create_like(const VkImageMat& im, Allocator* allocator = 0); +#endif // NCNN_VULKAN + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // data reference + Mat channel(int c); + const Mat channel(int c) const; + Mat depth(int z); + const Mat depth(int z) const; + float* row(int y); + const float* row(int y) const; + template + T* row(int y); + template + const T* row(int y) const; + + // range reference + Mat channel_range(int c, int channels); + const Mat channel_range(int c, int channels) const; + Mat depth_range(int z, int depths); + const Mat depth_range(int z, int depths) const; + Mat row_range(int y, int rows); + const Mat row_range(int y, int rows) const; + Mat range(int x, int n); + const Mat range(int x, int n) const; + + // access raw data + template + operator T*(); + template + operator const T*() const; + + // convenient access float vec element + float& operator[](size_t i); + const float& operator[](size_t i) const; + +#if NCNN_PIXEL + enum PixelType + { + PIXEL_CONVERT_SHIFT = 16, + PIXEL_FORMAT_MASK = 0x0000ffff, + PIXEL_CONVERT_MASK = 0xffff0000, + + PIXEL_RGB = 1, + PIXEL_BGR = 2, + PIXEL_GRAY = 3, + PIXEL_RGBA = 4, + PIXEL_BGRA = 5, + + PIXEL_RGB2BGR = PIXEL_RGB | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2GRAY = PIXEL_RGB | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2RGBA = PIXEL_RGB | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_RGB2BGRA = PIXEL_RGB | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_BGR2RGB = PIXEL_BGR | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2GRAY = PIXEL_BGR | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2RGBA = PIXEL_BGR | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_BGR2BGRA = PIXEL_BGR | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_GRAY2RGB = PIXEL_GRAY | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2BGR = PIXEL_GRAY | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2RGBA = PIXEL_GRAY | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + PIXEL_GRAY2BGRA = PIXEL_GRAY | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_RGBA2RGB = PIXEL_RGBA | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2BGR = PIXEL_RGBA | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2GRAY = PIXEL_RGBA | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_RGBA2BGRA = PIXEL_RGBA | (PIXEL_BGRA << PIXEL_CONVERT_SHIFT), + + PIXEL_BGRA2RGB = PIXEL_BGRA | (PIXEL_RGB << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2BGR = PIXEL_BGRA | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2GRAY = PIXEL_BGRA | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), + PIXEL_BGRA2RGBA = PIXEL_BGRA | (PIXEL_RGBA << PIXEL_CONVERT_SHIFT), + }; + // convenient construct from pixel data + static Mat from_pixels(const unsigned char* pixels, int type, int w, int h, Allocator* allocator = 0); + // convenient construct from pixel data with stride(bytes-per-row) parameter + static Mat from_pixels(const unsigned char* pixels, int type, int w, int h, int stride, Allocator* allocator = 0); + // convenient construct from pixel data and resize to specific size + static Mat from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data and resize to specific size with stride(bytes-per-row) parameter + static Mat from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data roi + static Mat from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from pixel data roi with stride(bytes-per-row) parameter + static Mat from_pixels_roi(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from pixel data roi and resize to specific size + static Mat from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from pixel data roi and resize to specific size with stride(bytes-per-row) parameter + static Mat from_pixels_roi_resize(const unsigned char* pixels, int type, int w, int h, int stride, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + + // convenient export to pixel data + void to_pixels(unsigned char* pixels, int type) const; + // convenient export to pixel data with stride(bytes-per-row) parameter + void to_pixels(unsigned char* pixels, int type, int stride) const; + // convenient export to pixel data and resize to specific size + void to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height) const; + // convenient export to pixel data and resize to specific size with stride(bytes-per-row) parameter + void to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height, int target_stride) const; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 + // convenient construct from android Bitmap + static Mat from_android_bitmap(JNIEnv* env, jobject bitmap, int type_to, Allocator* allocator = 0); + // convenient construct from android Bitmap and resize to specific size + static Mat from_android_bitmap_resize(JNIEnv* env, jobject bitmap, int type_to, int target_width, int target_height, Allocator* allocator = 0); + // convenient construct from android Bitmap roi + static Mat from_android_bitmap_roi(JNIEnv* env, jobject bitmap, int type_to, int roix, int roiy, int roiw, int roih, Allocator* allocator = 0); + // convenient construct from android Bitmap roi and resize to specific size + static Mat from_android_bitmap_roi_resize(JNIEnv* env, jobject bitmap, int type_to, int roix, int roiy, int roiw, int roih, int target_width, int target_height, Allocator* allocator = 0); + // convenient export to android Bitmap and resize to the android Bitmap size + void to_android_bitmap(JNIEnv* env, jobject bitmap, int type_from) const; +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API +#endif // NCNN_PIXEL + + // substract channel-wise mean values, then multiply by normalize values, pass 0 to skip + void substract_mean_normalize(const float* mean_vals, const float* norm_vals); + + // convenient construct from half precision floating point data + static Mat from_float16(const unsigned short* data, int size); + + // pointer to the data + void* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + Allocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; + + size_t cstep; +}; + +#if NCNN_VULKAN + +// the three dimension matrix, vulkan version +class NCNN_EXPORT VkMat +{ +public: + // empty + VkMat(); + // vec + VkMat(int w, size_t elemsize, VkAllocator* allocator); + // image + VkMat(int w, int h, size_t elemsize, VkAllocator* allocator); + // dim + VkMat(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // cube + VkMat(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // packed vec + VkMat(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // packed image + VkMat(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // packed dim + VkMat(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // packed cube + VkMat(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // copy + VkMat(const VkMat& m); + // external vec + VkMat(int w, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external image + VkMat(int w, int h, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external dim + VkMat(int w, int h, int c, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external cube + VkMat(int w, int h, int d, int c, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external packed vec + VkMat(int w, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed image + VkMat(int w, int h, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed dim + VkMat(int w, int h, int c, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed cube + VkMat(int w, int h, int d, int c, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // release + ~VkMat(); + // assign + VkMat& operator=(const VkMat& m); + // allocate vec + void create(int w, size_t elemsize, VkAllocator* allocator); + // allocate image + void create(int w, int h, size_t elemsize, VkAllocator* allocator); + // allocate dim + void create(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate like + void create_like(const Mat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkMat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkImageMat& im, VkAllocator* allocator); + + // mapped + Mat mapped() const; + void* mapped_ptr() const; + + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // low-level reference + VkBuffer buffer() const; + size_t buffer_offset() const; + size_t buffer_capacity() const; + + // device buffer + VkBufferMemory* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + VkAllocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; + + size_t cstep; +}; + +class NCNN_EXPORT VkImageMat +{ +public: + // empty + VkImageMat(); + // vec + VkImageMat(int w, size_t elemsize, VkAllocator* allocator); + // image + VkImageMat(int w, int h, size_t elemsize, VkAllocator* allocator); + // dim + VkImageMat(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // cube + VkImageMat(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // packed vec + VkImageMat(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // packed image + VkImageMat(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // packed dim + VkImageMat(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // packed cube + VkImageMat(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // copy + VkImageMat(const VkImageMat& m); + // external vec + VkImageMat(int w, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external image + VkImageMat(int w, int h, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external dim + VkImageMat(int w, int h, int c, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external cube + VkImageMat(int w, int h, int d, int c, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external packed vec + VkImageMat(int w, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed image + VkImageMat(int w, int h, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed dim + VkImageMat(int w, int h, int c, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed cube + VkImageMat(int w, int h, int d, int c, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // release + ~VkImageMat(); + // assign + VkImageMat& operator=(const VkImageMat& m); + // allocate vec + void create(int w, size_t elemsize, VkAllocator* allocator); + // allocate image + void create(int w, int h, size_t elemsize, VkAllocator* allocator); + // allocate dim + void create(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); + // allocate packed vec + void create(int w, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed image + void create(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed dim + void create(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate like + void create_like(const Mat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkMat& m, VkAllocator* allocator); + // allocate like + void create_like(const VkImageMat& im, VkAllocator* allocator); + + // mapped + Mat mapped() const; + void* mapped_ptr() const; + + // refcount++ + void addref(); + // refcount-- + void release(); + + bool empty() const; + size_t total() const; + + // bits per element + int elembits() const; + + // shape only + Mat shape() const; + + // low-level reference + VkImage image() const; + VkImageView imageview() const; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 + // convenient construct from android hardware buffer + static VkImageMat from_android_hardware_buffer(VkAndroidHardwareBufferImageAllocator* allocator); +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + + // device image + VkImageMemory* data; + + // pointer to the reference counter + // when points to user-allocated data, the pointer is NULL + int* refcount; + + // element size in bytes + // 4 = float32/int32 + // 2 = float16 + // 1 = int8/uint8 + // 0 = empty + size_t elemsize; + + // packed count inside element + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + int elempack; + + // the allocator + VkAllocator* allocator; + + // the dimension rank + int dims; + + int w; + int h; + int d; + int c; +}; + +// type for vulkan specialization constant and push constant +union vk_specialization_type +{ + int i; + float f; + uint32_t u32; +}; +union vk_constant_type +{ + int i; + float f; +}; +#endif // NCNN_VULKAN + +// misc function +#if NCNN_PIXEL +// convert yuv420sp(nv21) to rgb, the fast approximate version +NCNN_EXPORT void yuv420sp2rgb(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// convert yuv420sp(nv12) to rgb, the fast approximate version +NCNN_EXPORT void yuv420sp2rgb_nv12(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// convert yuv420sp(nv21) to rgb with half resize, the faster approximate version +NCNN_EXPORT void yuv420sp2rgb_half(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb); +// image pixel bilinear resize +NCNN_EXPORT void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +NCNN_EXPORT void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +// image pixel bilinear resize with stride(bytes-per-row) parameter +NCNN_EXPORT void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +NCNN_EXPORT void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride); +// image pixel bilinear resize, convenient wrapper for yuv420sp(nv21/nv12) +NCNN_EXPORT void resize_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h); +#endif // NCNN_PIXEL +#if NCNN_PIXEL_ROTATE +// type is the from type, 6 means rotating from 6 to 1 +// +// 1 2 3 4 5 6 7 8 +// +// 888888 888888 88 88 8888888888 88 88 8888888888 +// 88 88 88 88 88 88 88 88 88 88 88 88 +// 8888 8888 8888 8888 88 8888888888 8888888888 88 +// 88 88 88 88 +// 88 88 888888 888888 +// +// ref http://sylvana.net/jpegcrop/exif_orientation.html +// image pixel kanna rotate +NCNN_EXPORT void kanna_rotate_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +NCNN_EXPORT void kanna_rotate_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +// image pixel kanna rotate with stride(bytes-per-row) parameter +NCNN_EXPORT void kanna_rotate_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +NCNN_EXPORT void kanna_rotate_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, int type); +// image pixel kanna rotate, convenient wrapper for yuv420sp(nv21/nv12) +NCNN_EXPORT void kanna_rotate_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, int type); +#endif // NCNN_PIXEL_ROTATE +#if NCNN_PIXEL_AFFINE +// resolve affine transform matrix from rotation angle, scale factor and x y offset +NCNN_EXPORT void get_rotation_matrix(float angle, float scale, float dx, float dy, float* tm); +// resolve affine transform matrix from two set of points, num_point must be >= 2 +NCNN_EXPORT void get_affine_transform(const float* points_from, const float* points_to, int num_point, float* tm); +// resolve the inversion affine transform matrix +NCNN_EXPORT void invert_affine_transform(const float* tm, float* tm_inv); +// image pixel bilinear warpaffine inverse transform, set -233 for transparent border color, the color RGBA is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +// image pixel bilinear warpaffine inverse transform with stride(bytes-per-row) parameter, set -233 for transparent border color, the color RGBA is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +NCNN_EXPORT void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type = 0, unsigned int v = 0); +// image pixel bilinear warpaffine, convenient wrapper for yuv420sp(nv21/nv12), set -233 for transparent border color, the color YUV_ is little-endian encoded +NCNN_EXPORT void warpaffine_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0); +#endif // NCNN_PIXEL_AFFINE +#if NCNN_PIXEL_DRAWING +// draw rectangle, set thickness -1 for filled rectangle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_rectangle_c1(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c2(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c3(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c4(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw rectangle with stride(bytes-per-row) parameter, set thickness -1 for filled rectangle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_rectangle_c1(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c2(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c3(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +NCNN_EXPORT void draw_rectangle_c4(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw rectangle, convenient wrapper for yuv420sp(nv21/nv12), set thickness -1 for filled rectangle, the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_rectangle_yuv420sp(unsigned char* yuv420sp, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness); +// draw circle, set thickness -1 for filled circle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_circle_c1(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c2(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c3(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c4(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +// draw circle with stride(bytes-per-row) parameter, set thickness -1 for filled circle, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_circle_c1(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c2(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c3(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +NCNN_EXPORT void draw_circle_c4(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness); +// draw circle, convenient wrapper for yuv420sp(nv21/nv12), set thickness -1 for filled circle, the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_circle_yuv420sp(unsigned char* yuv420sp, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness); +// draw line, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_line_c1(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c2(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c3(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c4(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// draw line with stride(bytes-per-row) parameter, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_line_c1(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c2(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c3(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +NCNN_EXPORT void draw_line_c4(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// draw line, convenient wrapper for yuv420sp(nv21/nv12), the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_line_yuv420sp(unsigned char* yuv420sp, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness); +// resolve text bounding box size +NCNN_EXPORT void get_text_drawing_size(const char* text, int fontpixelsize, int* w, int* h); +// draw ascii printables and newline, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_text_c1(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c2(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c3(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c4(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +// draw ascii printables and newline with stride(bytes-per-row) parameter, the color RGBA is little-endian encoded +NCNN_EXPORT void draw_text_c1(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c2(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c3(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +NCNN_EXPORT void draw_text_c4(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color); +// draw ascii printables and newline, convenient wrapper for yuv420sp(nv21/nv12), the color YUV_ is little-endian encoded +NCNN_EXPORT void draw_text_yuv420sp(unsigned char* yuv420sp, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color); +#endif // NCNN_PIXEL_DRAWING + +// type conversion +// convert float to half precision floating point +NCNN_EXPORT unsigned short float32_to_float16(float value); +// convert half precision floating point to float +NCNN_EXPORT float float16_to_float32(unsigned short value); +// convert float to brain half +NCNN_EXPORT NCNN_FORCEINLINE unsigned short float32_to_bfloat16(float value) +{ + // 16 : 16 + union + { + unsigned int u; + float f; + } tmp; + tmp.f = value; + return tmp.u >> 16; +} +// convert brain half to float +NCNN_EXPORT NCNN_FORCEINLINE float bfloat16_to_float32(unsigned short value) +{ + // 16 : 16 + union + { + unsigned int u; + float f; + } tmp; + tmp.u = value << 16; + return tmp.f; +} + +// mat process +enum BorderType +{ + BORDER_CONSTANT = 0, + BORDER_REPLICATE = 1, + BORDER_REFLECT = 2, + BORDER_TRANSPARENT = -233, +}; +NCNN_EXPORT void copy_make_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int type, float v, const Option& opt = Option()); +NCNN_EXPORT void copy_make_border_3d(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int front, int behind, int type, float v, const Option& opt = Option()); +NCNN_EXPORT void copy_cut_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, const Option& opt = Option()); +NCNN_EXPORT void copy_cut_border_3d(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int front, int behind, const Option& opt = Option()); +NCNN_EXPORT void resize_nearest(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void resize_bilinear(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void resize_bicubic(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); +NCNN_EXPORT void convert_packing(const Mat& src, Mat& dst, int elempack, const Option& opt = Option()); +NCNN_EXPORT void flatten(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float32_to_float16(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float16_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_int8_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_float32_to_bfloat16(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void cast_bfloat16_to_float32(const Mat& src, Mat& dst, const Option& opt = Option()); +NCNN_EXPORT void quantize_to_int8(const Mat& src, Mat& dst, const Mat& scale_data, const Option& opt = Option()); +NCNN_EXPORT void dequantize_from_int32(const Mat& src, Mat& dst, const Mat& scale_data, const Mat& bias_data, const Option& opt = Option()); +NCNN_EXPORT void requantize_from_int32_to_int8(const Mat& src, Mat& dst, const Mat& scale_in_data, const Mat& scale_out_data, const Mat& bias_data, int activation_type, const Mat& activation_params, const Option& opt = Option()); + +NCNN_FORCEINLINE Mat::Mat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ +} + +NCNN_FORCEINLINE Mat::Mat(int _w, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE Mat::Mat(const Mat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c), cstep(m.cstep) +{ + addref(); +} + +NCNN_FORCEINLINE Mat::Mat(int _w, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = (size_t)w * h; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = (size_t)w * h; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::Mat(int _w, int _h, int _d, int _c, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE Mat::~Mat() +{ + release(); +} + +NCNN_FORCEINLINE void Mat::fill(float _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + + int i = 0; +#if __ARM_NEON + float32x4_t _c = vdupq_n_f32(_v); + for (; i + 3 < size; i += 4) + { + vst1q_f32(ptr, _c); + ptr += 4; + } +#endif // __ARM_NEON + for (; i < size; i++) + { + *ptr++ = _v; + } +} + +NCNN_FORCEINLINE void Mat::fill(int _v) +{ + int size = (int)total(); + int* ptr = (int*)data; + + int i = 0; +#if __ARM_NEON + int32x4_t _c = vdupq_n_s32(_v); + for (; i + 3 < size; i += 4) + { + vst1q_s32(ptr, _c); + ptr += 4; + } +#endif // __ARM_NEON + for (; i < size; i++) + { + *ptr++ = _v; + } +} + +#if __ARM_NEON +NCNN_FORCEINLINE void Mat::fill(float32x4_t _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + vst1q_f32(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(uint16x4_t _v) +{ + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + vst1_u16(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(int32x4_t _v) +{ + int size = (int)total(); + int* ptr = (int*)data; + for (int i = 0; i < size; i++) + { + vst1q_s32(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(int32x4_t _v0, int32x4_t _v1) +{ + int size = (int)total(); + int* ptr = (int*)data; + for (int i = 0; i < size; i++) + { + vst1q_s32(ptr, _v0); + vst1q_s32(ptr + 4, _v1); + ptr += 8; + } +} +#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +NCNN_FORCEINLINE void Mat::fill(float16x4_t _v) +{ + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vst1_f16(ptr, _v); + ptr += 4; + } +} + +NCNN_FORCEINLINE void Mat::fill(float16x8_t _v) +{ + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vst1q_f16(ptr, _v); + ptr += 8; + } +} +#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC +#endif // __ARM_NEON + +#if __SSE2__ +#if __AVX__ +#if __AVX512F__ +NCNN_FORCEINLINE void Mat::fill(__m512 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm512_storeu_ps(ptr, _v); + ptr += 16; + } +} +#endif // __AVX512F__ +NCNN_FORCEINLINE void Mat::fill(__m256 _v, int _i) +{ + // old gcc cannot overload __m128 and __m256 type + // add a dummy int parameter for different mangled function symbol + (void)_i; + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm256_storeu_ps(ptr, _v); + ptr += 8; + } +} +#endif // __AVX__ +NCNN_FORCEINLINE void Mat::fill(__m128 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + _mm_storeu_ps(ptr, _v); + ptr += 4; + } +} +NCNN_FORCEINLINE void Mat::fill(__m128i _v) +{ + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + _mm_store_si128((__m128i*)ptr, _v); + ptr += 8; + } +} +#endif // __SSE2__ + +#if __mips_msa +NCNN_FORCEINLINE void Mat::fill(v4f32 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + __msa_st_w((v4i32)_v, ptr, 0); + ptr += 4; + } +} +#endif // __mips_msa + +#if __loongarch_sx +NCNN_FORCEINLINE void Mat::fill(__m128 _v) +{ + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + __lsx_vst(_v, ptr, 0); + ptr += 4; + } +} +#endif // __loongarch_sx +#if __riscv_vector +NCNN_FORCEINLINE void Mat::fill(vfloat32m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 4; + const size_t vl = vsetvl_e32m1(packn); + + int size = (int)total(); + float* ptr = (float*)data; + for (int i = 0; i < size; i++) + { + vse32_v_f32m1(ptr, _v, vl); + ptr += packn; + } +} + +NCNN_FORCEINLINE void Mat::fill(vuint16m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 2; + const size_t vl = vsetvl_e16m1(packn); + + int size = (int)total(); + unsigned short* ptr = (unsigned short*)data; + for (int i = 0; i < size; i++) + { + vse16_v_u16m1(ptr, _v, vl); + ptr += packn; + } +} + +NCNN_FORCEINLINE void Mat::fill(vint8m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 1; + const size_t vl = vsetvl_e8m1(packn); + + int size = (int)total(); + signed char* ptr = (signed char*)data; + for (int i = 0; i < size; i++) + { + vse8_v_i8m1(ptr, _v, vl); + ptr += packn; + } +} +#if __riscv_zfh +NCNN_FORCEINLINE void Mat::fill(vfloat16m1_t _v) +{ + const int packn = cpu_riscv_vlenb() / 2; + const size_t vl = vsetvl_e16m1(packn); + + int size = (int)total(); + __fp16* ptr = (__fp16*)data; + for (int i = 0; i < size; i++) + { + vse16_v_f16m1(ptr, _v, vl); + ptr += packn; + } +} +#endif // __riscv_zfh +#endif // __riscv_vector + +template +NCNN_FORCEINLINE void Mat::fill(T _v) +{ + int size = (int)total(); + T* ptr = (T*)data; + for (int i = 0; i < size; i++) + { + ptr[i] = _v; + } +} + +NCNN_FORCEINLINE Mat& Mat::operator=(const Mat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + cstep = m.cstep; + + return *this; +} + +NCNN_FORCEINLINE void Mat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void Mat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator) + allocator->fastFree(data); + else + fastFree(data); + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + cstep = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool Mat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t Mat::total() const +{ + return cstep * c; +} + +NCNN_FORCEINLINE int Mat::elembits() const +{ + return elempack ? static_cast(elemsize * 8) / elempack : 0; +} + +NCNN_FORCEINLINE Mat Mat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE Mat Mat::channel(int _c) +{ + Mat m(w, h, d, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims - 1; + if (dims == 4) + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::channel(int _c) const +{ + Mat m(w, h, d, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims - 1; + if (dims == 4) + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE Mat Mat::depth(int z) +{ + return Mat(w, h, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::depth(int z) const +{ + return Mat(w, h, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE float* Mat::row(int y) +{ + return (float*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +NCNN_FORCEINLINE const float* Mat::row(int y) const +{ + return (const float*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +template +NCNN_FORCEINLINE T* Mat::row(int y) +{ + return (T*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +template +NCNN_FORCEINLINE const T* Mat::row(int y) const +{ + return (const T*)((unsigned char*)data + (size_t)w * y * elemsize); +} + +NCNN_FORCEINLINE Mat Mat::channel_range(int _c, int channels) +{ + Mat m(w, h, d, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::channel_range(int _c, int channels) const +{ + Mat m(w, h, d, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.dims = dims; + return m; +} + +NCNN_FORCEINLINE Mat Mat::depth_range(int z, int depths) +{ + Mat m(w, h, depths, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE const Mat Mat::depth_range(int z, int depths) const +{ + Mat m(w, h, depths, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; +} + +NCNN_FORCEINLINE Mat Mat::row_range(int y, int rows) +{ + return Mat(w, rows, (unsigned char*)data + (size_t)w * y * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::row_range(int y, int rows) const +{ + return Mat(w, rows, (unsigned char*)data + (size_t)w * y * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE Mat Mat::range(int x, int n) +{ + return Mat(n, (unsigned char*)data + x * elemsize, elemsize, elempack, allocator); +} + +NCNN_FORCEINLINE const Mat Mat::range(int x, int n) const +{ + return Mat(n, (unsigned char*)data + x * elemsize, elemsize, elempack, allocator); +} + +template +NCNN_FORCEINLINE Mat::operator T*() +{ + return (T*)data; +} + +template +NCNN_FORCEINLINE Mat::operator const T*() const +{ + return (const T*)data; +} + +NCNN_FORCEINLINE float& Mat::operator[](size_t i) +{ + return ((float*)data)[i]; +} + +NCNN_FORCEINLINE const float& Mat::operator[](size_t i) const +{ + return ((const float*)data)[i]; +} + +#if NCNN_VULKAN + +NCNN_FORCEINLINE VkMat::VkMat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkMat::VkMat(const VkMat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c) +{ + addref(); + + cstep = m.cstep; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = w * h; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize(w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ + cstep = w; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ + cstep = w * h; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _c, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ + cstep = alignSize(w * h * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::VkMat(int _w, int _h, int _d, int _c, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; +} + +NCNN_FORCEINLINE VkMat::~VkMat() +{ + release(); +} + +NCNN_FORCEINLINE VkMat& VkMat::operator=(const VkMat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + cstep = m.cstep; + + return *this; +} + +NCNN_FORCEINLINE Mat VkMat::mapped() const +{ + if (!allocator->mappable) + return Mat(); + + if (dims == 1) + return Mat(w, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 2) + return Mat(w, h, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 3) + return Mat(w, h, c, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 4) + return Mat(w, h, d, c, mapped_ptr(), elemsize, elempack, 0); + + return Mat(); +} + +NCNN_FORCEINLINE void* VkMat::mapped_ptr() const +{ + if (!allocator->mappable) + return 0; + + return (unsigned char*)data->mapped_ptr + data->offset; +} + +NCNN_FORCEINLINE void VkMat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void VkMat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator && data) + { + allocator->fastFree(data); + } + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + cstep = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool VkMat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t VkMat::total() const +{ + return cstep * c; +} + +NCNN_FORCEINLINE int VkMat::elembits() const +{ + return elempack ? static_cast(elemsize) * 8 / elempack : 0; +} + +NCNN_FORCEINLINE Mat VkMat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE VkBuffer VkMat::buffer() const +{ + return data->buffer; +} + +NCNN_FORCEINLINE size_t VkMat::buffer_offset() const +{ + return data->offset; +} + +NCNN_FORCEINLINE size_t VkMat::buffer_capacity() const +{ + return data->capacity; +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat() + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(const VkImageMat& m) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c) +{ + addref(); +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _c, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ +} + +NCNN_FORCEINLINE VkImageMat::~VkImageMat() +{ + release(); +} + +NCNN_FORCEINLINE VkImageMat& VkImageMat::operator=(const VkImageMat& m) +{ + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + elemsize = m.elemsize; + elempack = m.elempack; + allocator = m.allocator; + + dims = m.dims; + w = m.w; + h = m.h; + d = m.d; + c = m.c; + + return *this; +} + +NCNN_FORCEINLINE Mat VkImageMat::mapped() const +{ + if (!allocator->mappable || !data->mapped_ptr) + return Mat(); + + if (dims == 1) + return Mat(w, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 2) + return Mat(w, h, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 3) + return Mat(w, h, c, mapped_ptr(), elemsize, elempack, 0); + + if (dims == 4) + return Mat(w, h, d, c, mapped_ptr(), elemsize, elempack, 0); + + return Mat(); +} + +NCNN_FORCEINLINE void* VkImageMat::mapped_ptr() const +{ + if (!allocator->mappable || !data->mapped_ptr) + return 0; + + return (unsigned char*)data->mapped_ptr + data->bind_offset; +} + +NCNN_FORCEINLINE void VkImageMat::addref() +{ + if (refcount) + NCNN_XADD(refcount, 1); +} + +NCNN_FORCEINLINE void VkImageMat::release() +{ + if (refcount && NCNN_XADD(refcount, -1) == 1) + { + if (allocator && data) + { + allocator->fastFree(data); + } + } + + data = 0; + + elemsize = 0; + elempack = 0; + + dims = 0; + w = 0; + h = 0; + d = 0; + c = 0; + + refcount = 0; +} + +NCNN_FORCEINLINE bool VkImageMat::empty() const +{ + return data == 0 || total() == 0; +} + +NCNN_FORCEINLINE size_t VkImageMat::total() const +{ + return w * h * d * c; +} + +NCNN_FORCEINLINE int VkImageMat::elembits() const +{ + return elempack ? static_cast(elemsize) * 8 / elempack : 0; +} + +NCNN_FORCEINLINE Mat VkImageMat::shape() const +{ + if (dims == 1) + return Mat(w * elempack, (void*)0); + if (dims == 2) + return Mat(w, h * elempack, (void*)0); + if (dims == 3) + return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); + + return Mat(); +} + +NCNN_FORCEINLINE VkImage VkImageMat::image() const +{ + return data->image; +} + +NCNN_FORCEINLINE VkImageView VkImageMat::imageview() const +{ + return data->imageview; +} + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_MAT_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/modelbin.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/modelbin.h new file mode 100644 index 0000000..aada5f6 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/modelbin.h @@ -0,0 +1,80 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_MODELBIN_H +#define NCNN_MODELBIN_H + +#include "mat.h" + +namespace ncnn { + +class DataReader; +class NCNN_EXPORT ModelBin +{ +public: + ModelBin(); + virtual ~ModelBin(); + // element type + // 0 = auto + // 1 = float32 + // 2 = float16 + // 3 = int8 + // load vec + virtual Mat load(int w, int type) const; + // load image + virtual Mat load(int w, int h, int type) const; + // load dim + virtual Mat load(int w, int h, int c, int type) const; + // load cube + virtual Mat load(int w, int h, int d, int c, int type) const; +}; + +class ModelBinFromDataReaderPrivate; +class NCNN_EXPORT ModelBinFromDataReader : public ModelBin +{ +public: + explicit ModelBinFromDataReader(const DataReader& dr); + virtual ~ModelBinFromDataReader(); + + virtual Mat load(int w, int type) const; + +private: + ModelBinFromDataReader(const ModelBinFromDataReader&); + ModelBinFromDataReader& operator=(const ModelBinFromDataReader&); + +private: + ModelBinFromDataReaderPrivate* const d; +}; + +class ModelBinFromMatArrayPrivate; +class NCNN_EXPORT ModelBinFromMatArray : public ModelBin +{ +public: + // construct from weight blob array + explicit ModelBinFromMatArray(const Mat* weights); + virtual ~ModelBinFromMatArray(); + + virtual Mat load(int w, int type) const; + +private: + ModelBinFromMatArray(const ModelBinFromMatArray&); + ModelBinFromMatArray& operator=(const ModelBinFromMatArray&); + +private: + ModelBinFromMatArrayPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_MODELBIN_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/ncnn_export.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/ncnn_export.h new file mode 100644 index 0000000..e2f5fde --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/ncnn_export.h @@ -0,0 +1,42 @@ + +#ifndef NCNN_EXPORT_H +#define NCNN_EXPORT_H + +#ifdef NCNN_STATIC_DEFINE +# define NCNN_EXPORT +# define NCNN_NO_EXPORT +#else +# ifndef NCNN_EXPORT +# ifdef ncnn_EXPORTS + /* We are building this library */ +# define NCNN_EXPORT __attribute__((visibility("default"))) +# else + /* We are using this library */ +# define NCNN_EXPORT __attribute__((visibility("default"))) +# endif +# endif + +# ifndef NCNN_NO_EXPORT +# define NCNN_NO_EXPORT __attribute__((visibility("hidden"))) +# endif +#endif + +#ifndef NCNN_DEPRECATED +# define NCNN_DEPRECATED __attribute__ ((__deprecated__)) +#endif + +#ifndef NCNN_DEPRECATED_EXPORT +# define NCNN_DEPRECATED_EXPORT NCNN_EXPORT NCNN_DEPRECATED +#endif + +#ifndef NCNN_DEPRECATED_NO_EXPORT +# define NCNN_DEPRECATED_NO_EXPORT NCNN_NO_EXPORT NCNN_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef NCNN_NO_DEPRECATED +# define NCNN_NO_DEPRECATED +# endif +#endif + +#endif /* NCNN_EXPORT_H */ diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/net.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/net.h new file mode 100644 index 0000000..98e3ec3 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/net.h @@ -0,0 +1,274 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_NET_H +#define NCNN_NET_H + +#include "blob.h" +#include "layer.h" +#include "mat.h" +#include "option.h" +#include "platform.h" + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#include +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + +namespace ncnn { + +#if NCNN_VULKAN +class VkCompute; +#endif // NCNN_VULKAN +class DataReader; +class Extractor; +class NetPrivate; +class NCNN_EXPORT Net +{ +public: + // empty init + Net(); + // clear and destroy + virtual ~Net(); + +public: + // option can be changed before loading + Option opt; + +#if NCNN_VULKAN + // set gpu device by index + void set_vulkan_device(int device_index); + + // set gpu device by device handle, no owner transfer + void set_vulkan_device(const VulkanDevice* vkdev); + + const VulkanDevice* vulkan_device() const; +#endif // NCNN_VULKAN + +#if NCNN_STRING + // register custom layer or overwrite built-in layer by layer type name + // return 0 if success + int register_custom_layer(const char* type, layer_creator_func creator, layer_destroyer_func destroyer = 0, void* userdata = 0); + virtual int custom_layer_to_index(const char* type); +#endif // NCNN_STRING + // register custom layer or overwrite built-in layer by layer type + // return 0 if success + int register_custom_layer(int index, layer_creator_func creator, layer_destroyer_func destroyer = 0, void* userdata = 0); + +#if NCNN_STRING + int load_param(const DataReader& dr); +#endif // NCNN_STRING + + int load_param_bin(const DataReader& dr); + + int load_model(const DataReader& dr); + +#if NCNN_STDIO +#if NCNN_STRING + // load network structure from plain param file + // return 0 if success + int load_param(FILE* fp); + int load_param(const char* protopath); + int load_param_mem(const char* mem); +#endif // NCNN_STRING + // load network structure from binary param file + // return 0 if success + int load_param_bin(FILE* fp); + int load_param_bin(const char* protopath); + + // load network weight data from model file + // return 0 if success + int load_model(FILE* fp); + int load_model(const char* modelpath); +#endif // NCNN_STDIO + + // load network structure from external memory + // memory pointer must be 32-bit aligned + // return bytes consumed + int load_param(const unsigned char* mem); + + // reference network weight data from external memory + // weight data is not copied but referenced + // so external memory should be retained when used + // memory pointer must be 32-bit aligned + // return bytes consumed + int load_model(const unsigned char* mem); + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 9 +#if NCNN_STRING + // convenient load network structure from android asset plain param file + int load_param(AAsset* asset); + int load_param(AAssetManager* mgr, const char* assetpath); +#endif // NCNN_STRING + // convenient load network structure from android asset binary param file + int load_param_bin(AAsset* asset); + int load_param_bin(AAssetManager* mgr, const char* assetpath); + + // convenient load network weight data from android asset model file + int load_model(AAsset* asset); + int load_model(AAssetManager* mgr, const char* assetpath); +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PLATFORM_API + + // unload network structure and weight data + void clear(); + + // construct an Extractor from network + Extractor create_extractor() const; + + // get input/output indexes/names + const std::vector& input_indexes() const; + const std::vector& output_indexes() const; +#if NCNN_STRING + const std::vector& input_names() const; + const std::vector& output_names() const; +#endif + + const std::vector& blobs() const; + const std::vector& layers() const; + + std::vector& mutable_blobs(); + std::vector& mutable_layers(); + +protected: + friend class Extractor; +#if NCNN_STRING + int find_blob_index_by_name(const char* name) const; + int find_layer_index_by_name(const char* name) const; + virtual Layer* create_custom_layer(const char* type); + virtual Layer* create_overwrite_builtin_layer(const char* type); +#endif // NCNN_STRING + virtual Layer* create_custom_layer(int index); + virtual Layer* create_overwrite_builtin_layer(int typeindex); + +private: + Net(const Net&); + Net& operator=(const Net&); + +private: + NetPrivate* const d; +}; + +class ExtractorPrivate; +class NCNN_EXPORT Extractor +{ +public: + virtual ~Extractor(); + + // copy + Extractor(const Extractor&); + + // assign + Extractor& operator=(const Extractor&); + + // clear blob mats and alloctors + void clear(); + + // enable light mode + // intermediate blob will be recycled when enabled + // enabled by default + void set_light_mode(bool enable); + + // set thread count for this extractor + // this will overwrite the global setting + // default count is system depended + void set_num_threads(int num_threads); + + // set blob memory allocator + void set_blob_allocator(Allocator* allocator); + + // set workspace memory allocator + void set_workspace_allocator(Allocator* allocator); + +#if NCNN_VULKAN + void set_vulkan_compute(bool enable); + + void set_blob_vkallocator(VkAllocator* allocator); + + void set_workspace_vkallocator(VkAllocator* allocator); + + void set_staging_vkallocator(VkAllocator* allocator); +#endif // NCNN_VULKAN + +#if NCNN_STRING + // set input by blob name + // return 0 if success + int input(const char* blob_name, const Mat& in); + + // get result by blob name + // return 0 if success + // type = 0, default + // type = 1, do not convert fp16/bf16 or / and packing + int extract(const char* blob_name, Mat& feat, int type = 0); +#endif // NCNN_STRING + + // set input by blob index + // return 0 if success + int input(int blob_index, const Mat& in); + + // get result by blob index + // return 0 if success + // type = 0, default + // type = 1, do not convert fp16/bf16 or / and packing + int extract(int blob_index, Mat& feat, int type = 0); + +#if NCNN_VULKAN +#if NCNN_STRING + // set input by blob name + // return 0 if success + int input(const char* blob_name, const VkMat& in); + + // get result by blob name + // return 0 if success + int extract(const char* blob_name, VkMat& feat, VkCompute& cmd); + + // set input by blob name + // return 0 if success + int input(const char* blob_name, const VkImageMat& in); + + // get result by blob name + // return 0 if success + int extract(const char* blob_name, VkImageMat& feat, VkCompute& cmd); +#endif // NCNN_STRING + + // set input by blob index + // return 0 if success + int input(int blob_index, const VkMat& in); + + // get result by blob index + // return 0 if success + int extract(int blob_index, VkMat& feat, VkCompute& cmd); + + // set input by blob index + // return 0 if success + int input(int blob_index, const VkImageMat& in); + + // get result by blob index + // return 0 if success + int extract(int blob_index, VkImageMat& feat, VkCompute& cmd); +#endif // NCNN_VULKAN + +protected: + friend Extractor Net::create_extractor() const; + Extractor(const Net* net, size_t blob_count); + +private: + ExtractorPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_NET_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/option.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/option.h new file mode 100644 index 0000000..7d0cc60 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/option.h @@ -0,0 +1,156 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_OPTION_H +#define NCNN_OPTION_H + +#include "platform.h" + +namespace ncnn { + +#if NCNN_VULKAN +class VkAllocator; +class PipelineCache; +#endif // NCNN_VULKAN + +class Allocator; +class NCNN_EXPORT Option +{ +public: + // default option + Option(); + +public: + // light mode + // intermediate blob will be recycled when enabled + // enabled by default + bool lightmode; + + // thread count + // default value is the one returned by get_cpu_count() + int num_threads; + + // blob memory allocator + Allocator* blob_allocator; + + // workspace memory allocator + Allocator* workspace_allocator; + +#if NCNN_VULKAN + // blob memory allocator + VkAllocator* blob_vkallocator; + + // workspace memory allocator + VkAllocator* workspace_vkallocator; + + // staging memory allocator + VkAllocator* staging_vkallocator; + + // pipeline cache + PipelineCache* pipeline_cache; +#endif // NCNN_VULKAN + + // the time openmp threads busy-wait for more work before going to sleep + // default value is 20ms to keep the cores enabled + // without too much extra power consumption afterwards + int openmp_blocktime; + + // enable winograd convolution optimization + // improve convolution 3x3 stride1 performance, may consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_winograd_convolution; + + // enable sgemm convolution optimization + // improve convolution 1x1 stride1 performance, may consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_sgemm_convolution; + + // enable quantized int8 inference + // use low-precision int8 path for quantized model + // changes should be applied before loading network structure and weight + // enabled by default + bool use_int8_inference; + + // enable vulkan compute + bool use_vulkan_compute; + + // enable bf16 data type for storage + // improve most operator performance on all arm devices, may consume more memory + bool use_bf16_storage; + + // enable options for gpu inference + bool use_fp16_packed; + bool use_fp16_storage; + bool use_fp16_arithmetic; + bool use_int8_packed; + bool use_int8_storage; + bool use_int8_arithmetic; + + // enable simd-friendly packed memory layout + // improve all operator performance on all arm devices, will consume more memory + // changes should be applied before loading network structure and weight + // enabled by default + bool use_packing_layout; + + bool use_shader_pack8; + + // subgroup option + bool use_subgroup_basic; + bool use_subgroup_vote; + bool use_subgroup_ballot; + bool use_subgroup_shuffle; + + // turn on for adreno + bool use_image_storage; + bool use_tensor_storage; + + bool use_reserved_0; + + // enable DAZ(Denormals-Are-Zero) and FTZ(Flush-To-Zero) + // default value is 3 + // 0 = DAZ OFF, FTZ OFF + // 1 = DAZ ON , FTZ OFF + // 2 = DAZ OFF, FTZ ON + // 3 = DAZ ON, FTZ ON + int flush_denormals; + + bool use_local_pool_allocator; + + // enable local memory optimization for gpu inference + bool use_shader_local_memory; + + // enable cooperative matrix optimization for gpu inference + bool use_cooperative_matrix; + + // more fine-grained control of winograd convolution + bool use_winograd23_convolution; + bool use_winograd43_convolution; + bool use_winograd63_convolution; + + // this option is turned on for A53/A55 automatically + // but you can force this on/off if you wish + bool use_a53_a55_optimized_kernel; + + bool use_reserved_7; + bool use_reserved_8; + bool use_reserved_9; + bool use_reserved_10; + bool use_reserved_11; +}; + +} // namespace ncnn + +#endif // NCNN_OPTION_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/paramdict.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/paramdict.h new file mode 100644 index 0000000..c2ef160 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/paramdict.h @@ -0,0 +1,73 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PARAMDICT_H +#define NCNN_PARAMDICT_H + +#include "mat.h" + +// at most 32 parameters +#define NCNN_MAX_PARAM_COUNT 32 + +namespace ncnn { + +class DataReader; +class Net; +class ParamDictPrivate; +class NCNN_EXPORT ParamDict +{ +public: + // empty + ParamDict(); + + virtual ~ParamDict(); + + // copy + ParamDict(const ParamDict&); + + // assign + ParamDict& operator=(const ParamDict&); + + // get type + int type(int id) const; + + // get int + int get(int id, int def) const; + // get float + float get(int id, float def) const; + // get array + Mat get(int id, const Mat& def) const; + + // set int + void set(int id, int i); + // set float + void set(int id, float f); + // set array + void set(int id, const Mat& v); + +protected: + friend class Net; + + void clear(); + + int load_param(const DataReader& dr); + int load_param_bin(const DataReader& dr); + +private: + ParamDictPrivate* const d; +}; + +} // namespace ncnn + +#endif // NCNN_PARAMDICT_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/pipeline.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/pipeline.h new file mode 100644 index 0000000..c284a14 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/pipeline.h @@ -0,0 +1,113 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PIPELINE_H +#define NCNN_PIPELINE_H + +#include "mat.h" +#include "platform.h" +#if NCNN_VULKAN +#include "gpu.h" + +#include +#endif // NCNN_VULKAN + +namespace ncnn { + +#if NCNN_VULKAN +class Option; +class PipelinePrivate; +class NCNN_EXPORT Pipeline +{ +public: + explicit Pipeline(const VulkanDevice* vkdev); + virtual ~Pipeline(); + +public: + void set_optimal_local_size_xyz(int w = 4, int h = 4, int c = 4); + void set_optimal_local_size_xyz(const Mat& local_size_xyz); + void set_local_size_xyz(int w, int h, int c); + + int create(const uint32_t* spv_data, size_t spv_data_size, const std::vector& specializations); + + int create(int shader_type_index, const Option& opt, const std::vector& specializations); + +public: + VkShaderModule shader_module() const; + VkDescriptorSetLayout descriptorset_layout() const; + VkPipelineLayout pipeline_layout() const; + VkPipeline pipeline() const; + VkDescriptorUpdateTemplateKHR descriptor_update_template() const; + + const ShaderInfo& shader_info() const; + + uint32_t local_size_x() const; + uint32_t local_size_y() const; + uint32_t local_size_z() const; + +protected: + void set_shader_module(VkShaderModule shader_module); + void set_descriptorset_layout(VkDescriptorSetLayout descriptorset_layout); + void set_pipeline_layout(VkPipelineLayout pipeline_layout); + void set_pipeline(VkPipeline pipeline); + void set_descriptor_update_template(VkDescriptorUpdateTemplateKHR descriptor_update_template); + + void set_shader_info(const ShaderInfo& shader_info); + +public: + const VulkanDevice* vkdev; + +private: + Pipeline(const Pipeline&); + Pipeline& operator=(const Pipeline&); + +private: + PipelinePrivate* const d; +}; + +#if NCNN_PLATFORM_API +#if __ANDROID_API__ >= 26 +class VkCompute; +class NCNN_EXPORT ImportAndroidHardwareBufferPipeline : private Pipeline +{ +public: + explicit ImportAndroidHardwareBufferPipeline(const VulkanDevice* vkdev); + virtual ~ImportAndroidHardwareBufferPipeline(); + + int create(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator, int type_to, int rotate_from, const Option& opt); + int create(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator, int type_to, int rotate_from, int target_width, int target_height, const Option& opt); + void destroy(); + + friend class VkCompute; + +protected: + int create_shader_module(const Option& opt); + int create_sampler(VkAndroidHardwareBufferImageAllocator* ahb_im_allocator); + int create_descriptorset_layout(); + +public: + int type_to; + int rotate_from; + bool need_resize; + + VkSampler sampler; +}; +#endif // __ANDROID_API__ >= 26 +#endif // NCNN_PLATFORM_API + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_PIPELINE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/pipelinecache.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/pipelinecache.h new file mode 100644 index 0000000..bb6b8fb --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/pipelinecache.h @@ -0,0 +1,85 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PIPELINECACHE_H +#define NCNN_PIPELINECACHE_H + +#include "platform.h" + +#if NCNN_VULKAN +#include +#endif // NCNN_VULKAN + +#include "mat.h" +#include "gpu.h" + +namespace ncnn { + +#if NCNN_VULKAN + +class VulkanDevice; +class PipelineCachePrivate; +class NCNN_EXPORT PipelineCache +{ +public: + explicit PipelineCache(const VulkanDevice* _vkdev); + + virtual ~PipelineCache(); + + void clear(); + + int get_pipeline(const uint32_t* spv_data, size_t spv_data_size, const std::vector& specializations, + uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* shader_module, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template, + ShaderInfo& shader_info) const; + + int get_pipeline(int shader_type_index, const Option& opt, const std::vector& specializations, + uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* shader_module, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template, + ShaderInfo& shader_info) const; + +protected: + int create_shader_module(int shader_type_index, const Option& opt, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z, + VkShaderModule* _shader_module, ShaderInfo& si) const; + + int new_pipeline(VkShaderModule shader_module, const ShaderInfo& shader_info, const std::vector& specializations, + VkDescriptorSetLayout* descriptorset_layout, + VkPipelineLayout* pipeline_layout, + VkPipeline* pipeline, + VkDescriptorUpdateTemplateKHR* descriptor_update_template) const; + +protected: + const VulkanDevice* vkdev; + +private: + PipelineCache(const PipelineCache&); + PipelineCache& operator=(const PipelineCache&); + +private: + PipelineCachePrivate* const d; +}; + +#endif // NCNN_VULKAN + +} // namespace ncnn + +#endif // NCNN_PIPELINECACHE_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/platform.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/platform.h new file mode 100644 index 0000000..b5f4337 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/platform.h @@ -0,0 +1,293 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_PLATFORM_H +#define NCNN_PLATFORM_H + +#define NCNN_STDIO 1 +#define NCNN_STRING 1 +#define NCNN_SIMPLEOCV 0 +#define NCNN_SIMPLEOMP 0 +#define NCNN_SIMPLESTL 0 +#define NCNN_SIMPLEMATH 0 +#define NCNN_THREADS 1 +#define NCNN_BENCHMARK 0 +#define NCNN_C_API 1 +#define NCNN_PLATFORM_API 1 +#define NCNN_PIXEL 1 +#define NCNN_PIXEL_ROTATE 1 +#define NCNN_PIXEL_AFFINE 1 +#define NCNN_PIXEL_DRAWING 1 +#define NCNN_VULKAN 0 +#define NCNN_SYSTEM_GLSLANG 0 +#define NCNN_RUNTIME_CPU 1 +#define NCNN_GNU_INLINE_ASM 1 +#define NCNN_AVX 1 +#define NCNN_XOP 1 +#define NCNN_FMA 1 +#define NCNN_F16C 1 +#define NCNN_AVX2 1 +#define NCNN_AVXVNNI 1 +#define NCNN_AVX512 1 +#define NCNN_AVX512VNNI 1 +#define NCNN_AVX512BF16 1 +#define NCNN_AVX512FP16 1 +#define NCNN_VFPV4 0 +#define NCNN_ARM82 0 +#define NCNN_ARM82DOT 0 +#define NCNN_ARM82FP16FML 0 +#define NCNN_ARM84BF16 0 +#define NCNN_ARM84I8MM 0 +#define NCNN_ARM86SVE 0 +#define NCNN_ARM86SVE2 0 +#define NCNN_ARM86SVEBF16 0 +#define NCNN_ARM86SVEI8MM 0 +#define NCNN_ARM86SVEF32MM 0 +#define NCNN_MSA 0 +#define NCNN_LSX 0 +#define NCNN_MMI 0 +#define NCNN_RVV 0 +#define NCNN_INT8 1 +#define NCNN_BF16 1 +#define NCNN_FORCE_INLINE 1 + +#define NCNN_VERSION_STRING "1.0.20231027" + +#include "ncnn_export.h" + +#ifdef __cplusplus + +#if NCNN_THREADS +#if (defined _WIN32 && !(defined __MINGW32__)) +#define WIN32_LEAN_AND_MEAN +#include +#include +#else +#include +#endif +#endif // NCNN_THREADS + +#if __ANDROID_API__ >= 26 +#define VK_USE_PLATFORM_ANDROID_KHR +#endif // __ANDROID_API__ >= 26 + +namespace ncnn { + +#if NCNN_THREADS +#if (defined _WIN32 && !(defined __MINGW32__)) +class NCNN_EXPORT Mutex +{ +public: + Mutex() { InitializeSRWLock(&srwlock); } + ~Mutex() {} + void lock() { AcquireSRWLockExclusive(&srwlock); } + void unlock() { ReleaseSRWLockExclusive(&srwlock); } +private: + friend class ConditionVariable; + // NOTE SRWLock is available from windows vista + SRWLOCK srwlock; +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() { InitializeConditionVariable(&condvar); } + ~ConditionVariable() {} + void wait(Mutex& mutex) { SleepConditionVariableSRW(&condvar, &mutex.srwlock, INFINITE, 0); } + void broadcast() { WakeAllConditionVariable(&condvar); } + void signal() { WakeConditionVariable(&condvar); } +private: + CONDITION_VARIABLE condvar; +}; + +static unsigned __stdcall start_wrapper(void* args); +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*start)(void*), void* args = 0) { _start = start; _args = args; handle = (HANDLE)_beginthreadex(0, 0, start_wrapper, this, 0, 0); } + ~Thread() {} + void join() { WaitForSingleObject(handle, INFINITE); CloseHandle(handle); } +private: + friend unsigned __stdcall start_wrapper(void* args) + { + Thread* t = (Thread*)args; + t->_start(t->_args); + return 0; + } + HANDLE handle; + void* (*_start)(void*); + void* _args; +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { key = TlsAlloc(); } + ~ThreadLocalStorage() { TlsFree(key); } + void set(void* value) { TlsSetValue(key, (LPVOID)value); } + void* get() { return (void*)TlsGetValue(key); } +private: + DWORD key; +}; +#else // (defined _WIN32 && !(defined __MINGW32__)) +class NCNN_EXPORT Mutex +{ +public: + Mutex() { pthread_mutex_init(&mutex, 0); } + ~Mutex() { pthread_mutex_destroy(&mutex); } + void lock() { pthread_mutex_lock(&mutex); } + void unlock() { pthread_mutex_unlock(&mutex); } +private: + friend class ConditionVariable; + pthread_mutex_t mutex; +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() { pthread_cond_init(&cond, 0); } + ~ConditionVariable() { pthread_cond_destroy(&cond); } + void wait(Mutex& mutex) { pthread_cond_wait(&cond, &mutex.mutex); } + void broadcast() { pthread_cond_broadcast(&cond); } + void signal() { pthread_cond_signal(&cond); } +private: + pthread_cond_t cond; +}; + +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*start)(void*), void* args = 0) { pthread_create(&t, 0, start, args); } + ~Thread() {} + void join() { pthread_join(t, 0); } +private: + pthread_t t; +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { pthread_key_create(&key, 0); } + ~ThreadLocalStorage() { pthread_key_delete(key); } + void set(void* value) { pthread_setspecific(key, value); } + void* get() { return pthread_getspecific(key); } +private: + pthread_key_t key; +}; +#endif // (defined _WIN32 && !(defined __MINGW32__)) +#else // NCNN_THREADS +class NCNN_EXPORT Mutex +{ +public: + Mutex() {} + ~Mutex() {} + void lock() {} + void unlock() {} +}; + +class NCNN_EXPORT ConditionVariable +{ +public: + ConditionVariable() {} + ~ConditionVariable() {} + void wait(Mutex& /*mutex*/) {} + void broadcast() {} + void signal() {} +}; + +class NCNN_EXPORT Thread +{ +public: + Thread(void* (*/*start*/)(void*), void* /*args*/ = 0) {} + ~Thread() {} + void join() {} +}; + +class NCNN_EXPORT ThreadLocalStorage +{ +public: + ThreadLocalStorage() { data = 0; } + ~ThreadLocalStorage() {} + void set(void* value) { data = value; } + void* get() { return data; } +private: + void* data; +}; +#endif // NCNN_THREADS + +class NCNN_EXPORT MutexLockGuard +{ +public: + MutexLockGuard(Mutex& _mutex) : mutex(_mutex) { mutex.lock(); } + ~MutexLockGuard() { mutex.unlock(); } +private: + Mutex& mutex; +}; + +} // namespace ncnn + +#if NCNN_SIMPLESTL +#include "simplestl.h" +#else +#include +#include +#include +#include +#endif + +// simplemath +#if NCNN_SIMPLEMATH +#include "simplemath.h" +#else +#include +#include +#endif + +#endif // __cplusplus + +#if NCNN_STDIO +#if NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#include +#define NCNN_LOGE(...) do { \ + fprintf(stderr, ##__VA_ARGS__); fprintf(stderr, "\n"); \ + __android_log_print(ANDROID_LOG_WARN, "ncnn", ##__VA_ARGS__); } while(0) +#else // NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#include +#define NCNN_LOGE(...) do { \ + fprintf(stderr, ##__VA_ARGS__); fprintf(stderr, "\n"); } while(0) +#endif // NCNN_PLATFORM_API && __ANDROID_API__ >= 8 +#else +#define NCNN_LOGE(...) +#endif + + +#if NCNN_FORCE_INLINE +#ifdef _MSC_VER + #define NCNN_FORCEINLINE __forceinline +#elif defined(__GNUC__) + #define NCNN_FORCEINLINE inline __attribute__((__always_inline__)) +#elif defined(__CLANG__) + #if __has_attribute(__always_inline__) + #define NCNN_FORCEINLINE inline __attribute__((__always_inline__)) + #else + #define NCNN_FORCEINLINE inline + #endif +#else + #define NCNN_FORCEINLINE inline +#endif +#else + #define NCNN_FORCEINLINE inline +#endif + +#endif // NCNN_PLATFORM_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/simplemath.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/simplemath.h new file mode 100644 index 0000000..fd7fa69 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/simplemath.h @@ -0,0 +1,102 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEMATH_H +#define NCNN_SIMPLEMATH_H + +#include "platform.h" + +#if NCNN_SIMPLEMATH + +#ifdef __cplusplus +extern "C" { +#endif +/* +* ==================================================== +* discrete functions +* ==================================================== +*/ +NCNN_EXPORT float fabs(float); +NCNN_EXPORT float fabsf(float); +NCNN_EXPORT float fmod(float, float); +NCNN_EXPORT float floor(float); +NCNN_EXPORT float floorf(float); +NCNN_EXPORT float round(float); +NCNN_EXPORT float roundf(float); +NCNN_EXPORT float ceil(float); +NCNN_EXPORT float ceilf(float); +NCNN_EXPORT float fmaxf(float, float); +NCNN_EXPORT float truncf(float); +NCNN_EXPORT float frac(float); +/* +* ==================================================== +* trigonometric functions +* ==================================================== +*/ +NCNN_EXPORT float sinf(float); +NCNN_EXPORT float cosf(float); +NCNN_EXPORT float tanf(float); +NCNN_EXPORT float asinf(float); +NCNN_EXPORT float acosf(float); +NCNN_EXPORT float atanf(float); +NCNN_EXPORT float atan2f(float, float); +NCNN_EXPORT float tanhf(float); + +/* +* ==================================================== +* power functions +* ==================================================== +*/ +NCNN_EXPORT float sqrtf(float); +NCNN_EXPORT float sqrt(float); +NCNN_EXPORT float powf(float, float); + +/* +* ==================================================== +* exponential and logarithm functions +* ==================================================== +*/ +NCNN_EXPORT float expf(float); +NCNN_EXPORT float frexp(float, int*); +NCNN_EXPORT float logf(float); +NCNN_EXPORT float log(float); +NCNN_EXPORT float log10f(float); + +/* +* ==================================================== +* probability functions +* ==================================================== +*/ +NCNN_EXPORT float erf(float); +NCNN_EXPORT float erfcf(float); + +/* +* ==================================================== +* other functions +* ==================================================== +*/ +NCNN_EXPORT int msb(unsigned int); +NCNN_EXPORT float fmaf(float, float, float); +NCNN_EXPORT float copysignf(float, float); +NCNN_EXPORT void fesetround(int); +NCNN_EXPORT int fegetround(); +NCNN_EXPORT float nearbyintf(float); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // NCNN_SIMPLEMATH + +#endif // NCNN_SIMPLEMATH_H \ No newline at end of file diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/simpleocv.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/simpleocv.h new file mode 100644 index 0000000..54b22d9 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/simpleocv.h @@ -0,0 +1,503 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEOCV_H +#define NCNN_SIMPLEOCV_H + +#include "platform.h" + +#if NCNN_SIMPLEOCV + +#include +#include +#include "allocator.h" +#include "mat.h" + +#if defined(_MSC_VER) || defined(__GNUC__) +#pragma push_macro("min") +#pragma push_macro("max") +#undef min +#undef max +#endif + +#ifndef NCNN_XADD +using ncnn::NCNN_XADD; +#endif + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; + +enum +{ + CV_LOAD_IMAGE_UNCHANGED = -1, + CV_LOAD_IMAGE_GRAYSCALE = 0, + CV_LOAD_IMAGE_COLOR = 1, +}; + +enum +{ + CV_IMWRITE_JPEG_QUALITY = 1 +}; + +// minimal opencv style data structure implementation +namespace cv { + +template +static inline _Tp saturate_cast(int v) +{ + return _Tp(v); +} +template<> +inline uchar saturate_cast(int v) +{ + return (uchar)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); +} + +template +struct Scalar_ +{ + Scalar_() + { + v[0] = 0; + v[1] = 0; + v[2] = 0; + v[3] = 0; + } + Scalar_(_Tp _v0) + { + v[0] = _v0; + v[1] = 0; + v[2] = 0; + v[3] = 0; + } + Scalar_(_Tp _v0, _Tp _v1, _Tp _v2) + { + v[0] = _v0; + v[1] = _v1; + v[2] = _v2; + v[3] = 0; + } + Scalar_(_Tp _v0, _Tp _v1, _Tp _v2, _Tp _v3) + { + v[0] = _v0; + v[1] = _v1; + v[2] = _v2; + v[3] = _v3; + } + + const _Tp operator[](const int i) const + { + return v[i]; + } + + _Tp operator[](const int i) + { + return v[i]; + } + + _Tp v[4]; +}; + +typedef Scalar_ Scalar; + +template +struct Point_ +{ + Point_() + : x(0), y(0) + { + } + Point_(_Tp _x, _Tp _y) + : x(_x), y(_y) + { + } + + template + operator Point_<_Tp2>() const + { + return Point_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y)); + } + + _Tp x; + _Tp y; +}; + +typedef Point_ Point; +typedef Point_ Point2f; + +template +struct Size_ +{ + Size_() + : width(0), height(0) + { + } + Size_(_Tp _w, _Tp _h) + : width(_w), height(_h) + { + } + + template + operator Size_<_Tp2>() const + { + return Size_<_Tp2>(saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); + } + + _Tp width; + _Tp height; +}; + +typedef Size_ Size; +typedef Size_ Size2f; + +template +struct Rect_ +{ + Rect_() + : x(0), y(0), width(0), height(0) + { + } + Rect_(_Tp _x, _Tp _y, _Tp _w, _Tp _h) + : x(_x), y(_y), width(_w), height(_h) + { + } + Rect_(Point_<_Tp> _p, Size_<_Tp> _size) + : x(_p.x), y(_p.y), width(_size.width), height(_size.height) + { + } + + template + operator Rect_<_Tp2>() const + { + return Rect_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y), saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); + } + + _Tp x; + _Tp y; + _Tp width; + _Tp height; + + // area + _Tp area() const + { + return width * height; + } +}; + +template +static inline Rect_<_Tp>& operator&=(Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + _Tp x1 = std::max(a.x, b.x), y1 = std::max(a.y, b.y); + a.width = std::min(a.x + a.width, b.x + b.width) - x1; + a.height = std::min(a.y + a.height, b.y + b.height) - y1; + a.x = x1; + a.y = y1; + if (a.width <= 0 || a.height <= 0) + a = Rect_<_Tp>(); + return a; +} + +template +static inline Rect_<_Tp>& operator|=(Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + _Tp x1 = std::min(a.x, b.x), y1 = std::min(a.y, b.y); + a.width = std::max(a.x + a.width, b.x + b.width) - x1; + a.height = std::max(a.y + a.height, b.y + b.height) - y1; + a.x = x1; + a.y = y1; + return a; +} + +template +static inline Rect_<_Tp> operator&(const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c &= b; +} + +template +static inline Rect_<_Tp> operator|(const Rect_<_Tp>& a, const Rect_<_Tp>& b) +{ + Rect_<_Tp> c = a; + return c |= b; +} + +typedef Rect_ Rect; +typedef Rect_ Rect2f; + +#define CV_8UC1 1 +#define CV_8UC3 3 +#define CV_8UC4 4 +#define CV_32FC1 4 + +struct NCNN_EXPORT Mat +{ + Mat() + : data(0), refcount(0), rows(0), cols(0), c(0) + { + } + + Mat(int _rows, int _cols, int flags) + : data(0), refcount(0) + { + create(_rows, _cols, flags); + } + + // copy + Mat(const Mat& m) + : data(m.data), refcount(m.refcount) + { + if (refcount) + NCNN_XADD(refcount, 1); + + rows = m.rows; + cols = m.cols; + c = m.c; + } + + Mat(int _rows, int _cols, int flags, void* _data) + : data((unsigned char*)_data), refcount(0) + { + rows = _rows; + cols = _cols; + c = flags; + } + + ~Mat() + { + release(); + } + + // assign + Mat& operator=(const Mat& m) + { + if (this == &m) + return *this; + + if (m.refcount) + NCNN_XADD(m.refcount, 1); + + release(); + + data = m.data; + refcount = m.refcount; + + rows = m.rows; + cols = m.cols; + c = m.c; + + return *this; + } + + Mat& operator=(const Scalar& s) + { + if (total() > 0) + { + uchar* p = data; + for (int i = 0; i < cols * rows; i++) + { + for (int j = 0; j < c; j++) + { + *p++ = s[j]; + } + } + } + + return *this; + } + + void create(int _rows, int _cols, int flags) + { + release(); + + rows = _rows; + cols = _cols; + c = flags; + + if (total() > 0) + { + // refcount address must be aligned, so we expand totalsize here + size_t totalsize = (total() + 3) >> 2 << 2; + data = (uchar*)ncnn::fastMalloc(totalsize + (int)sizeof(*refcount)); + refcount = (int*)(((uchar*)data) + totalsize); + *refcount = 1; + } + } + + void release() + { + if (refcount && NCNN_XADD(refcount, -1) == 1) + ncnn::fastFree(data); + + data = 0; + + rows = 0; + cols = 0; + c = 0; + + refcount = 0; + } + + Mat clone() const + { + if (empty()) + return Mat(); + + Mat m(rows, cols, c); + + if (total() > 0) + { + memcpy(m.data, data, total()); + } + + return m; + } + + bool empty() const + { + return data == 0 || total() == 0; + } + + int channels() const + { + return c; + } + + int type() const + { + return c; + } + + size_t total() const + { + return cols * rows * c; + } + + const uchar* ptr(int y) const + { + return data + y * cols * c; + } + + uchar* ptr(int y) + { + return data + y * cols * c; + } + + template + const _Tp* ptr(int y) const + { + return (const _Tp*)data + y * cols * c; + } + + template + _Tp* ptr(int y) + { + return (_Tp*)data + y * cols * c; + } + + // roi + Mat operator()(const Rect& roi) const + { + if (empty()) + return Mat(); + + Mat m(roi.height, roi.width, c); + + int sy = roi.y; + for (int y = 0; y < roi.height; y++) + { + const uchar* sptr = ptr(sy) + roi.x * c; + uchar* dptr = m.ptr(y); + memcpy(dptr, sptr, roi.width * c); + sy++; + } + + return m; + } + + uchar* data; + + // pointer to the reference counter; + // when points to user-allocated data, the pointer is NULL + int* refcount; + + int rows; + int cols; + + int c; +}; + +enum ImreadModes +{ + IMREAD_UNCHANGED = -1, + IMREAD_GRAYSCALE = 0, + IMREAD_COLOR = 1 +}; + +NCNN_EXPORT Mat imread(const std::string& path, int flags = IMREAD_COLOR); + +NCNN_EXPORT Mat imdecode(const std::vector& buf, int flags = IMREAD_COLOR); + +enum ImwriteFlags +{ + IMWRITE_JPEG_QUALITY = 1 +}; + +NCNN_EXPORT bool imwrite(const std::string& path, const Mat& m, const std::vector& params = std::vector()); + +NCNN_EXPORT void imshow(const std::string& name, const Mat& m); + +NCNN_EXPORT int waitKey(int delay = 0); + +#if NCNN_PIXEL +NCNN_EXPORT void resize(const Mat& src, Mat& dst, const Size& size, float sw = 0.f, float sh = 0.f, int flags = 0); +#endif // NCNN_PIXEL + +#if NCNN_PIXEL_DRAWING + +enum +{ + FILLED = -1 +}; + +NCNN_EXPORT void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void rectangle(Mat& img, Rect rec, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void circle(Mat& img, Point center, int radius, const Scalar& color, int thickness = 1); + +NCNN_EXPORT void line(Mat& img, Point p0, Point p1, const Scalar& color, int thickness = 1); + +enum +{ + FONT_HERSHEY_SIMPLEX = 0 +}; + +NCNN_EXPORT void putText(Mat& img, const std::string& text, Point org, int fontFace, double fontScale, Scalar color, int thickness = 1); + +NCNN_EXPORT Size getTextSize(const std::string& text, int fontFace, double fontScale, int thickness, int* baseLine); + +#endif // NCNN_PIXEL_DRAWING + +} // namespace cv + +#if defined(_MSC_VER) || defined(__GNUC__) +#pragma pop_macro("min") +#pragma pop_macro("max") +#endif + +#endif // NCNN_SIMPLEOCV + +#endif // NCNN_SIMPLEOCV_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/simpleomp.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/simpleomp.h new file mode 100644 index 0000000..13e2452 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/simpleomp.h @@ -0,0 +1,53 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLEOMP_H +#define NCNN_SIMPLEOMP_H + +#include "platform.h" + +#if NCNN_SIMPLEOMP + +#include + +// This minimal openmp runtime implementation only supports the llvm openmp abi +// and only supports #pragma omp parallel for num_threads(X) + +#ifdef __cplusplus +extern "C" { +#endif + +NCNN_EXPORT int omp_get_max_threads(); + +NCNN_EXPORT void omp_set_num_threads(int num_threads); + +NCNN_EXPORT int omp_get_dynamic(); + +NCNN_EXPORT void omp_set_dynamic(int dynamic); + +NCNN_EXPORT int omp_get_num_threads(); + +NCNN_EXPORT int omp_get_thread_num(); + +NCNN_EXPORT int kmp_get_blocktime(); + +NCNN_EXPORT void kmp_set_blocktime(int blocktime); + +#ifdef __cplusplus +} +#endif + +#endif // NCNN_SIMPLEOMP + +#endif // NCNN_SIMPLEOMP_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/simplestl.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/simplestl.h new file mode 100644 index 0000000..00ff468 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/simplestl.h @@ -0,0 +1,565 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_SIMPLESTL_H +#define NCNN_SIMPLESTL_H + +#include +#include +#include + +#if !NCNN_SIMPLESTL + +#include + +#else + +// allocation functions +NCNN_EXPORT void* operator new(size_t size); +NCNN_EXPORT void* operator new[](size_t size); +// placement allocation functions +NCNN_EXPORT void* operator new(size_t size, void* ptr); +NCNN_EXPORT void* operator new[](size_t size, void* ptr); +// deallocation functions +NCNN_EXPORT void operator delete(void* ptr); +NCNN_EXPORT void operator delete[](void* ptr); +// deallocation functions since c++14 +#if __cplusplus >= 201402L +NCNN_EXPORT void operator delete(void* ptr, size_t sz); +NCNN_EXPORT void operator delete[](void* ptr, size_t sz); +#endif +// placement deallocation functions +NCNN_EXPORT void operator delete(void* ptr, void* voidptr2); +NCNN_EXPORT void operator delete[](void* ptr, void* voidptr2); + +#endif + +// minimal stl data structure implementation +namespace std { + +template +const T& max(const T& a, const T& b) +{ + return (a < b) ? b : a; +} + +template +const T& min(const T& a, const T& b) +{ + return (a > b) ? b : a; +} + +template +void swap(T& a, T& b) +{ + T temp(a); + a = b; + b = temp; +} + +template +struct pair +{ + pair() + : first(), second() + { + } + pair(const T1& t1, const T2& t2) + : first(t1), second(t2) + { + } + + T1 first; + T2 second; +}; + +template +bool operator==(const pair& x, const pair& y) +{ + return (x.first == y.first && x.second == y.second); +} +template +bool operator<(const pair& x, const pair& y) +{ + return x.first < y.first || (!(y.first < x.first) && x.second < y.second); +} +template +bool operator!=(const pair& x, const pair& y) +{ + return !(x == y); +} +template +bool operator>(const pair& x, const pair& y) +{ + return y < x; +} +template +bool operator<=(const pair& x, const pair& y) +{ + return !(y < x); +} +template +bool operator>=(const pair& x, const pair& y) +{ + return !(x < y); +} + +template +pair make_pair(const T1& t1, const T2& t2) +{ + return pair(t1, t2); +} + +template +struct node +{ + node* prev_; + node* next_; + T data_; + + node() + : prev_(0), next_(0), data_() + { + } + node(const T& t) + : prev_(0), next_(0), data_(t) + { + } +}; + +template +struct iter_list +{ + iter_list() + : curr_(0) + { + } + iter_list(node* n) + : curr_(n) + { + } + iter_list(const iter_list& i) + : curr_(i.curr_) + { + } + ~iter_list() + { + } + + iter_list& operator=(const iter_list& i) + { + curr_ = i.curr_; + return *this; + } + + T& operator*() + { + return curr_->data_; + } + T* operator->() + { + return &(curr_->data_); + } + + bool operator==(const iter_list& i) + { + return curr_ == i.curr_; + } + bool operator!=(const iter_list& i) + { + return curr_ != i.curr_; + } + + iter_list& operator++() + { + curr_ = curr_->next_; + return *this; + } + iter_list& operator--() + { + curr_ = curr_->prev_; + return *this; + } + + node* curr_; +}; + +template +struct list +{ + typedef iter_list iterator; + + list() + { + head_ = new node(); + tail_ = head_; + count_ = 0; + } + ~list() + { + clear(); + delete head_; + } + list(const list& l) + { + head_ = new node(); + tail_ = head_; + count_ = 0; + + for (iter_list i = l.begin(); i != l.end(); ++i) + { + push_back(*i); + } + } + + list& operator=(const list& l) + { + if (this == &l) + { + return *this; + } + clear(); + + for (iter_list i = l.begin(); i != l.end(); ++i) + { + push_back(*i); + } + return *this; + } + + void clear() + { + while (count_ > 0) + { + pop_front(); + } + } + + void pop_front() + { + if (count_ > 0) + { + head_ = head_->next_; + delete head_->prev_; + head_->prev_ = 0; + --count_; + } + } + + size_t size() const + { + return count_; + } + iter_list begin() const + { + return iter_list(head_); + } + iter_list end() const + { + return iter_list(tail_); + } + bool empty() const + { + return count_ == 0; + } + + void push_back(const T& t) + { + if (count_ == 0) + { + head_ = new node(t); + head_->prev_ = 0; + head_->next_ = tail_; + tail_->prev_ = head_; + count_ = 1; + } + else + { + node* temp = new node(t); + temp->prev_ = tail_->prev_; + temp->next_ = tail_; + tail_->prev_->next_ = temp; + tail_->prev_ = temp; + ++count_; + } + } + + iter_list erase(iter_list pos) + { + if (pos != end()) + { + node* temp = pos.curr_; + if (temp == head_) + { + ++pos; + temp->next_->prev_ = 0; + head_ = temp->next_; + } + else + { + --pos; + temp->next_->prev_ = temp->prev_; + temp->prev_->next_ = temp->next_; + ++pos; + } + delete temp; + --count_; + } + return pos; + } + +protected: + node* head_; + node* tail_; + size_t count_; +}; + +template +struct greater +{ + bool operator()(const T& x, const T& y) const + { + return (x > y); + } +}; + +template +struct less +{ + bool operator()(const T& x, const T& y) const + { + return (x < y); + } +}; + +template +void partial_sort(RandomAccessIter first, RandomAccessIter middle, RandomAccessIter last, Compare comp) +{ + // [TODO] heap sort should be used here, but we simply use bubble sort now + for (RandomAccessIter i = first; i < middle; ++i) + { + // bubble sort + for (RandomAccessIter j = last - 1; j > first; --j) + { + if (comp(*j, *(j - 1))) + { + swap(*j, *(j - 1)); + } + } + } +} + +template +struct vector +{ + vector() + : data_(0), size_(0), capacity_(0) + { + } + vector(const size_t new_size, const T& value = T()) + : data_(0), size_(0), capacity_(0) + { + resize(new_size, value); + } + ~vector() + { + clear(); + } + vector(const vector& v) + : data_(0), size_(0), capacity_(0) + { + resize(v.size()); + for (size_t i = 0; i < size_; i++) + { + data_[i] = v.data_[i]; + } + } + + vector& operator=(const vector& v) + { + if (this == &v) + { + return *this; + } + resize(0); + resize(v.size()); + for (size_t i = 0; i < size_; i++) + { + data_[i] = v.data_[i]; + } + return *this; + } + + void resize(const size_t new_size, const T& value = T()) + { + try_alloc(new_size); + if (new_size > size_) + { + for (size_t i = size_; i < new_size; i++) + { + new (&data_[i]) T(value); + } + } + else if (new_size < size_) + { + for (size_t i = new_size; i < size_; i++) + { + data_[i].~T(); + } + } + size_ = new_size; + } + + void clear() + { + for (size_t i = 0; i < size_; i++) + { + data_[i].~T(); + } + delete[](char*) data_; + data_ = 0; + size_ = 0; + capacity_ = 0; + } + + T* data() const + { + return data_; + } + size_t size() const + { + return size_; + } + T& operator[](size_t i) const + { + return data_[i]; + } + T* begin() const + { + return &data_[0]; + } + T* end() const + { + return &data_[size_]; + } + bool empty() const + { + return size_ == 0; + } + + void push_back(const T& t) + { + try_alloc(size_ + 1); + new (&data_[size_]) T(t); + size_++; + } + + void insert(T* pos, T* b, T* e) + { + vector* v = 0; + if (b >= begin() && b < end()) + { + //the same vector + v = new vector(*this); + b = v->begin() + (b - begin()); + e = v->begin() + (e - begin()); + } + size_t diff = pos - begin(); + try_alloc(size_ + (e - b)); + pos = begin() + diff; + memmove(pos + (e - b), pos, (end() - pos) * sizeof(T)); + size_t len = e - b; + size_ += len; + for (size_t i = 0; i < len; i++) + { + *pos = *b; + pos++; + b++; + } + delete v; + } + + T* erase(T* pos) + { + pos->~T(); + memmove(pos, pos + 1, (end() - pos - 1) * sizeof(T)); + size_--; + return pos; + } + +protected: + T* data_; + size_t size_; + size_t capacity_; + void try_alloc(size_t new_size) + { + if (new_size * 3 / 2 > capacity_ / 2) + { + capacity_ = new_size * 2; + T* new_data = (T*)new char[capacity_ * sizeof(T)]; + memset(static_cast(new_data), 0, capacity_ * sizeof(T)); + if (data_) + { + memmove(new_data, data_, sizeof(T) * size_); + delete[](char*) data_; + } + data_ = new_data; + } + } +}; + +struct NCNN_EXPORT string : public vector +{ + string() + { + } + string(const char* str) + { + size_t len = strlen(str); + resize(len); + memcpy(data_, str, len); + } + const char* c_str() const + { + return (const char*)data_; + } + bool operator==(const string& str2) const + { + return strcmp(data_, str2.data_) == 0; + } + bool operator==(const char* str2) const + { + return strcmp(data_, str2) == 0; + } + bool operator!=(const char* str2) const + { + return strcmp(data_, str2) != 0; + } + string& operator+=(const string& str1) + { + insert(end(), str1.begin(), str1.end()); + return *this; + } +}; + +inline string operator+(const string& str1, const string& str2) +{ + string str(str1); + str.insert(str.end(), str2.begin(), str2.end()); + return str; +} + +} // namespace std + +#endif // NCNN_SIMPLESTL_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/vulkan_header_fix.h b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/vulkan_header_fix.h new file mode 100644 index 0000000..0a5ea9b --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/include/ncnn/vulkan_header_fix.h @@ -0,0 +1,449 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef NCNN_VULKAN_HEADER_FIX_H +#define NCNN_VULKAN_HEADER_FIX_H + +#include + +// This header contains new structure and function declearation to fix build with old vulkan sdk + +#if VK_HEADER_VERSION < 70 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES (VkStructureType)1000094000 +typedef enum VkSubgroupFeatureFlagBits +{ + VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001, + VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002, + VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004, + VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008, + VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010, + VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020, + VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040, + VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080, + VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 0x00000100, + VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubgroupFeatureFlagBits; +typedef VkFlags VkSubgroupFeatureFlags; +typedef struct VkPhysicalDeviceSubgroupProperties +{ + VkStructureType sType; + void* pNext; + uint32_t subgroupSize; + VkShaderStageFlags supportedStages; + VkSubgroupFeatureFlags supportedOperations; + VkBool32 quadOperationsInAllStages; +} VkPhysicalDeviceSubgroupProperties; +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES (VkStructureType)1000168000 +#define VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT (VkStructureType)1000168001 +typedef struct VkPhysicalDeviceMaintenance3Properties +{ + VkStructureType sType; + void* pNext; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceMaintenance3Properties; +typedef struct VkDescriptorSetLayoutSupport +{ + VkStructureType sType; + void* pNext; + VkBool32 supported; +} VkDescriptorSetLayoutSupport; +typedef VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; +typedef VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; +typedef void(VKAPI_PTR* PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); +#endif // VK_HEADER_VERSION < 70 + +#if VK_HEADER_VERSION < 80 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR (VkStructureType)1000177000 +typedef struct VkPhysicalDevice8BitStorageFeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; +} VkPhysicalDevice8BitStorageFeaturesKHR; +#define VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR (VkStructureType)1000109000 +#define VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR (VkStructureType)1000109001 +#define VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR (VkStructureType)1000109002 +#define VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR (VkStructureType)1000109003 +#define VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR (VkStructureType)1000109004 +#define VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR (VkStructureType)1000109005 +#define VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR (VkStructureType)1000109006 +typedef struct VkAttachmentDescription2KHR +{ + VkStructureType sType; + const void* pNext; + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription2KHR; +typedef struct VkAttachmentReference2KHR +{ + VkStructureType sType; + const void* pNext; + uint32_t attachment; + VkImageLayout layout; + VkImageAspectFlags aspectMask; +} VkAttachmentReference2KHR; +typedef struct VkSubpassDescription2KHR +{ + VkStructureType sType; + const void* pNext; + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t viewMask; + uint32_t inputAttachmentCount; + const VkAttachmentReference2KHR* pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference2KHR* pColorAttachments; + const VkAttachmentReference2KHR* pResolveAttachments; + const VkAttachmentReference2KHR* pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t* pPreserveAttachments; +} VkSubpassDescription2KHR; +typedef struct VkSubpassDependency2KHR +{ + VkStructureType sType; + const void* pNext; + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; + int32_t viewOffset; +} VkSubpassDependency2KHR; +typedef struct VkRenderPassCreateInfo2KHR +{ + VkStructureType sType; + const void* pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription2KHR* pAttachments; + uint32_t subpassCount; + const VkSubpassDescription2KHR* pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency2KHR* pDependencies; + uint32_t correlatedViewMaskCount; + const uint32_t* pCorrelatedViewMasks; +} VkRenderPassCreateInfo2KHR; +typedef struct VkSubpassBeginInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkSubpassContents contents; +} VkSubpassBeginInfoKHR; + +typedef struct VkSubpassEndInfoKHR +{ + VkStructureType sType; + const void* pNext; +} VkSubpassEndInfoKHR; +typedef VkResult(VKAPI_PTR* PFN_vkCreateRenderPass2KHR)(VkDevice device, const VkRenderPassCreateInfo2KHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void(VKAPI_PTR* PFN_vkCmdBeginRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfoKHR* pSubpassBeginInfo); +typedef void(VKAPI_PTR* PFN_vkCmdNextSubpass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfoKHR* pSubpassBeginInfo, const VkSubpassEndInfoKHR* pSubpassEndInfo); +typedef void(VKAPI_PTR* PFN_vkCmdEndRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassEndInfoKHR* pSubpassEndInfo); +#endif // VK_HEADER_VERSION < 80 + +#if VK_HEADER_VERSION < 95 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR (VkStructureType)1000082000 +typedef struct VkPhysicalDeviceFloat16Int8FeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; +} VkPhysicalDeviceFloat16Int8FeaturesKHR; +#endif // VK_HEADER_VERSION < 95 + +#if VK_HEADER_VERSION < 97 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT (VkStructureType)1000237000 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT (VkStructureType)1000238000 +#define VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT (VkStructureType)1000238001 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT (VkStructureType)1000244000 +#define VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_EXT (VkStructureType)1000244001 +#define VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT (VkStructureType)1000244002 +#define VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT (VkStructureType)1000247000 +#define VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT (VkBufferCreateFlagBits)0x00020000 +#define VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT (VkBufferUsageFlagBits)0x00020000 +typedef uint64_t VkDeviceAddress; +typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT +{ + VkStructureType sType; + void* pNext; + VkDeviceSize heapBudget[VK_MAX_MEMORY_HEAPS]; + VkDeviceSize heapUsage[VK_MAX_MEMORY_HEAPS]; +} VkPhysicalDeviceMemoryBudgetPropertiesEXT; +typedef struct VkPhysicalDeviceMemoryPriorityFeaturesEXT +{ + VkStructureType sType; + void* pNext; + VkBool32 memoryPriority; +} VkPhysicalDeviceMemoryPriorityFeaturesEXT; +typedef struct VkMemoryPriorityAllocateInfoEXT +{ + VkStructureType sType; + const void* pNext; + float priority; +} VkMemoryPriorityAllocateInfoEXT; +typedef struct VkPhysicalDeviceBufferAddressFeaturesEXT +{ + VkStructureType sType; + void* pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferAddressFeaturesEXT; +typedef struct VkBufferDeviceAddressInfoEXT +{ + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferDeviceAddressInfoEXT; +typedef struct VkBufferDeviceAddressCreateInfoEXT +{ + VkStructureType sType; + const void* pNext; + VkDeviceSize deviceAddress; +} VkBufferDeviceAddressCreateInfoEXT; +typedef VkDeviceAddress(VKAPI_PTR* PFN_vkGetBufferDeviceAddressEXT)(VkDevice device, const VkBufferDeviceAddressInfoEXT* pInfo); +typedef enum VkValidationFeatureEnableEXT +{ + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT = 0, + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT = 1, + VK_VALIDATION_FEATURE_ENABLE_BEGIN_RANGE_EXT = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT, + VK_VALIDATION_FEATURE_ENABLE_END_RANGE_EXT = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT, + VK_VALIDATION_FEATURE_ENABLE_RANGE_SIZE_EXT = (VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT - VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT + 1), + VK_VALIDATION_FEATURE_ENABLE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationFeatureEnableEXT; +typedef enum VkValidationFeatureDisableEXT +{ + VK_VALIDATION_FEATURE_DISABLE_ALL_EXT = 0, + VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT = 1, + VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT = 2, + VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT = 3, + VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT = 4, + VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT = 5, + VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT = 6, + VK_VALIDATION_FEATURE_DISABLE_BEGIN_RANGE_EXT = VK_VALIDATION_FEATURE_DISABLE_ALL_EXT, + VK_VALIDATION_FEATURE_DISABLE_END_RANGE_EXT = VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT, + VK_VALIDATION_FEATURE_DISABLE_RANGE_SIZE_EXT = (VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT - VK_VALIDATION_FEATURE_DISABLE_ALL_EXT + 1), + VK_VALIDATION_FEATURE_DISABLE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationFeatureDisableEXT; +typedef struct VkValidationFeaturesEXT +{ + VkStructureType sType; + const void* pNext; + uint32_t enabledValidationFeatureCount; + const VkValidationFeatureEnableEXT* pEnabledValidationFeatures; + uint32_t disabledValidationFeatureCount; + const VkValidationFeatureDisableEXT* pDisabledValidationFeatures; +} VkValidationFeaturesEXT; +#endif // VK_HEADER_VERSION < 97 + +#if VK_HEADER_VERSION < 101 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV (VkStructureType)1000249000 +#define VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV (VkStructureType)1000249001 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV (VkStructureType)1000249002 +typedef enum VkComponentTypeNV +{ + VK_COMPONENT_TYPE_FLOAT16_NV = 0, + VK_COMPONENT_TYPE_FLOAT32_NV = 1, + VK_COMPONENT_TYPE_FLOAT64_NV = 2, + VK_COMPONENT_TYPE_SINT8_NV = 3, + VK_COMPONENT_TYPE_SINT16_NV = 4, + VK_COMPONENT_TYPE_SINT32_NV = 5, + VK_COMPONENT_TYPE_SINT64_NV = 6, + VK_COMPONENT_TYPE_UINT8_NV = 7, + VK_COMPONENT_TYPE_UINT16_NV = 8, + VK_COMPONENT_TYPE_UINT32_NV = 9, + VK_COMPONENT_TYPE_UINT64_NV = 10, + VK_COMPONENT_TYPE_BEGIN_RANGE_NV = VK_COMPONENT_TYPE_FLOAT16_NV, + VK_COMPONENT_TYPE_END_RANGE_NV = VK_COMPONENT_TYPE_UINT64_NV, + VK_COMPONENT_TYPE_RANGE_SIZE_NV = (VK_COMPONENT_TYPE_UINT64_NV - VK_COMPONENT_TYPE_FLOAT16_NV + 1), + VK_COMPONENT_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkComponentTypeNV; +typedef enum VkScopeNV +{ + VK_SCOPE_DEVICE_NV = 1, + VK_SCOPE_WORKGROUP_NV = 2, + VK_SCOPE_SUBGROUP_NV = 3, + VK_SCOPE_QUEUE_FAMILY_NV = 5, + VK_SCOPE_BEGIN_RANGE_NV = VK_SCOPE_DEVICE_NV, + VK_SCOPE_END_RANGE_NV = VK_SCOPE_QUEUE_FAMILY_NV, + VK_SCOPE_RANGE_SIZE_NV = (VK_SCOPE_QUEUE_FAMILY_NV - VK_SCOPE_DEVICE_NV + 1), + VK_SCOPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkScopeNV; +typedef struct VkCooperativeMatrixPropertiesNV +{ + VkStructureType sType; + void* pNext; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeNV AType; + VkComponentTypeNV BType; + VkComponentTypeNV CType; + VkComponentTypeNV DType; + VkScopeNV scope; +} VkCooperativeMatrixPropertiesNV; +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesNV +{ + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesNV; +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesNV +{ + VkStructureType sType; + void* pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesNV; +typedef VkResult(VKAPI_PTR* PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixPropertiesNV* pProperties); +#endif // VK_HEADER_VERSION < 101 + +#if VK_HEADER_VERSION < 121 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD (VkStructureType)1000229000 +#define VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD (VkMemoryPropertyFlagBits)0x00000040 +#define VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD (VkMemoryPropertyFlagBits)0x00000040 +typedef struct VkPhysicalDeviceCoherentMemoryFeaturesAMD +{ + VkStructureType sType; + void* pNext; + VkBool32 deviceCoherentMemory; +} VkPhysicalDeviceCoherentMemoryFeaturesAMD; +#endif // VK_HEADER_VERSION < 121 + +#if VK_HEADER_VERSION < 129 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR (VkStructureType)1000257000 +#define VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR (VkStructureType)1000244001 +#define VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO_KHR (VkStructureType)1000257002 +#define VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO_KHR (VkStructureType)1000257003 +#define VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO_KHR (VkStructureType)1000257004 +#define VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR (VkBufferCreateFlagBits)0x00020000 +#define VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR (VkBufferUsageFlagBits)0x00020000 +#define VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR (VkMemoryAllocateFlagBits)0x00000002 +#define VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR (VkMemoryAllocateFlagBits)0x00000004 +typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferDeviceAddressFeaturesKHR; +typedef struct VkBufferDeviceAddressInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferDeviceAddressInfoKHR; +typedef struct VkBufferOpaqueCaptureAddressCreateInfoKHR +{ + VkStructureType sType; + const void* pNext; + uint64_t opaqueCaptureAddress; +} VkBufferOpaqueCaptureAddressCreateInfoKHR; +typedef struct VkMemoryOpaqueCaptureAddressAllocateInfoKHR +{ + VkStructureType sType; + const void* pNext; + uint64_t opaqueCaptureAddress; +} VkMemoryOpaqueCaptureAddressAllocateInfoKHR; +typedef struct VkDeviceMemoryOpaqueCaptureAddressInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; +} VkDeviceMemoryOpaqueCaptureAddressInfoKHR; +typedef VkDeviceAddress(VKAPI_PTR* PFN_vkGetBufferDeviceAddressKHR)(VkDevice device, const VkBufferDeviceAddressInfoKHR* pInfo); +typedef uint64_t(VKAPI_PTR* PFN_vkGetBufferOpaqueCaptureAddressKHR)(VkDevice device, const VkBufferDeviceAddressInfoKHR* pInfo); +typedef uint64_t(VKAPI_PTR* PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR)(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfoKHR* pInfo); +#endif // VK_HEADER_VERSION < 129 + +#if VK_HEADER_VERSION < 208 +typedef enum VkInstanceCreateFlagBits +{ + VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR = 0x00000001, + VK_INSTANCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkInstanceCreateFlagBits; +#endif // VK_HEADER_VERSION < 208 + +#if VK_HEADER_VERSION < 255 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR (VkStructureType)1000506000 +#define VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_KHR (VkStructureType)1000506001 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR (VkStructureType)1000506002 +typedef enum VkComponentTypeKHR +{ + VK_COMPONENT_TYPE_FLOAT16_KHR = 0, + VK_COMPONENT_TYPE_FLOAT32_KHR = 1, + VK_COMPONENT_TYPE_FLOAT64_KHR = 2, + VK_COMPONENT_TYPE_SINT8_KHR = 3, + VK_COMPONENT_TYPE_SINT16_KHR = 4, + VK_COMPONENT_TYPE_SINT32_KHR = 5, + VK_COMPONENT_TYPE_SINT64_KHR = 6, + VK_COMPONENT_TYPE_UINT8_KHR = 7, + VK_COMPONENT_TYPE_UINT16_KHR = 8, + VK_COMPONENT_TYPE_UINT32_KHR = 9, + VK_COMPONENT_TYPE_UINT64_KHR = 10, + VK_COMPONENT_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkComponentTypeKHR; +typedef enum VkScopeKHR +{ + VK_SCOPE_DEVICE_KHR = 1, + VK_SCOPE_WORKGROUP_KHR = 2, + VK_SCOPE_SUBGROUP_KHR = 3, + VK_SCOPE_QUEUE_FAMILY_KHR = 5, + VK_SCOPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkScopeKHR; +typedef struct VkCooperativeMatrixPropertiesKHR +{ + VkStructureType sType; + void* pNext; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeKHR AType; + VkComponentTypeKHR BType; + VkComponentTypeKHR CType; + VkComponentTypeKHR ResultType; + VkBool32 saturatingAccumulation; + VkScopeKHR scope; +} VkCooperativeMatrixPropertiesKHR; +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesKHR +{ + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesKHR; +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesKHR +{ + VkStructureType sType; + void* pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesKHR; +typedef VkResult(VKAPI_PTR* PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixPropertiesKHR* pProperties); +#endif // VK_HEADER_VERSION < 255 + +#endif // NCNN_VULKAN_HEADER_FIX_H diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/lib/cmake/ncnn/ncnn-release.cmake b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/lib/cmake/ncnn/ncnn-release.cmake new file mode 100644 index 0000000..1fb8660 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/lib/cmake/ncnn/ncnn-release.cmake @@ -0,0 +1,19 @@ +#---------------------------------------------------------------- +# Generated CMake target import file for configuration "Release". +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "ncnn" for configuration "Release" +set_property(TARGET ncnn APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(ncnn PROPERTIES + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libncnn.so" + IMPORTED_SONAME_RELEASE "libncnn.so" + ) + +list(APPEND _cmake_import_check_targets ncnn ) +list(APPEND _cmake_import_check_files_for_ncnn "${_IMPORT_PREFIX}/lib/libncnn.so" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/lib/cmake/ncnn/ncnn.cmake b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/lib/cmake/ncnn/ncnn.cmake new file mode 100644 index 0000000..6726e95 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/lib/cmake/ncnn/ncnn.cmake @@ -0,0 +1,109 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8) + message(FATAL_ERROR "CMake >= 2.8.0 required") +endif() +if(CMAKE_VERSION VERSION_LESS "2.8.3") + message(FATAL_ERROR "CMake >= 2.8.3 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.8.3...3.25) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_cmake_targets_defined "") +set(_cmake_targets_not_defined "") +set(_cmake_expected_targets "") +foreach(_cmake_expected_target IN ITEMS ncnn) + list(APPEND _cmake_expected_targets "${_cmake_expected_target}") + if(TARGET "${_cmake_expected_target}") + list(APPEND _cmake_targets_defined "${_cmake_expected_target}") + else() + list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") + endif() +endforeach() +unset(_cmake_expected_target) +if(_cmake_targets_defined STREQUAL _cmake_expected_targets) + unset(_cmake_targets_defined) + unset(_cmake_targets_not_defined) + unset(_cmake_expected_targets) + unset(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT _cmake_targets_defined STREQUAL "") + string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") + string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") +endif() +unset(_cmake_targets_defined) +unset(_cmake_targets_not_defined) +unset(_cmake_expected_targets) + + +# Compute the installation prefix relative to this file. +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +if(_IMPORT_PREFIX STREQUAL "/") + set(_IMPORT_PREFIX "") +endif() + +# Create imported target ncnn +add_library(ncnn SHARED IMPORTED) + +set_target_properties(ncnn PROPERTIES + INTERFACE_COMPILE_OPTIONS "-fno-rtti;-fno-exceptions" + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include/ncnn" + INTERFACE_LINK_LIBRARIES "-fopenmp;-static-openmp;-Wl,-wrap,__kmp_affinity_determine_capable;Threads::Threads;android;jnigraphics;log" + INTERFACE_POSITION_INDEPENDENT_CODE "ON" +) + +if(CMAKE_VERSION VERSION_LESS 2.8.12) + message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.") +endif() + +# Load information for each installed configuration. +file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/ncnn-*.cmake") +foreach(_cmake_config_file IN LISTS _cmake_config_files) + include("${_cmake_config_file}") +endforeach() +unset(_cmake_config_file) +unset(_cmake_config_files) + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(_cmake_target IN LISTS _cmake_import_check_targets) + foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}") + if(NOT EXISTS "${_cmake_file}") + message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file + \"${_cmake_file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + unset(_cmake_file) + unset("_cmake_import_check_files_for_${_cmake_target}") +endforeach() +unset(_cmake_target) +unset(_cmake_import_check_targets) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/lib/cmake/ncnn/ncnnConfig.cmake b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/lib/cmake/ncnn/ncnnConfig.cmake new file mode 100644 index 0000000..d3ac286 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/lib/cmake/ncnn/ncnnConfig.cmake @@ -0,0 +1,42 @@ +set(NCNN_OPENMP ON) +set(NCNN_THREADS ON) +set(NCNN_VULKAN OFF) +set(NCNN_SHARED_LIB ON) +set(NCNN_SYSTEM_GLSLANG OFF) + +if(NCNN_OPENMP) + find_package(OpenMP) +endif() + +if(NCNN_THREADS) + set(CMAKE_THREAD_PREFER_PTHREAD TRUE) + set(THREADS_PREFER_PTHREAD_FLAG TRUE) + find_package(Threads REQUIRED) +endif() + +if(NCNN_VULKAN) + find_package(Vulkan REQUIRED) + + if(NOT NCNN_SHARED_LIB) + if(NCNN_SYSTEM_GLSLANG) + find_package(glslang QUIET) + if(NOT glslang_FOUND) + set(GLSLANG_TARGET_DIR "") + include(${GLSLANG_TARGET_DIR}/OSDependentTargets.cmake) + include(${GLSLANG_TARGET_DIR}/OGLCompilerTargets.cmake) + if(EXISTS "${GLSLANG_TARGET_DIR}/HLSLTargets.cmake") + # hlsl support can be optional + include("${GLSLANG_TARGET_DIR}/HLSLTargets.cmake") + endif() + include(${GLSLANG_TARGET_DIR}/glslangTargets.cmake) + include(${GLSLANG_TARGET_DIR}/SPIRVTargets.cmake) + endif() + else() + set(glslang_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../lib/cmake/glslang") + find_package(glslang QUIET) + endif() + + endif() +endif() + +include(${CMAKE_CURRENT_LIST_DIR}/ncnn.cmake) diff --git a/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/lib/pkgconfig/ncnn.pc b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/lib/pkgconfig/ncnn.pc new file mode 100644 index 0000000..4e80236 --- /dev/null +++ b/duix-sdk/src/main/cpp/third/ncnn-20231027-android-shared/x86_64/lib/pkgconfig/ncnn.pc @@ -0,0 +1,11 @@ +prefix=${pcfiledir}/../.. +librarydir=${prefix}/lib +includedir=${prefix}/include + +Name: ncnn +Description: high-performance neural network inference framework optimized for the mobile platform +Version: 1.0.20231027 +URL: https://github.com/Tencent/ncnn +Libs: -L"${librarydir}" -lncnn +Cflags: -I"${includedir}" + diff --git a/duix-sdk/src/main/java/ai/guiji/duix/DuixNcnn.java b/duix-sdk/src/main/java/ai/guiji/duix/DuixNcnn.java new file mode 100644 index 0000000..c54ff31 --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/DuixNcnn.java @@ -0,0 +1,34 @@ +package ai.guiji.duix; + +public class DuixNcnn +{ + public native int alloc(int taskid,int mincalc,int width,int height); + public native int free(int taskid); + public native int initPcmex(int maxsize,int minoff,int minblock,int maxblock,int rgb); + public native int initWenet(String fnwenet); + public native int initMunet(String fnparam,String fnbin,String fnmask); + public native int initMunetex(String fnparam,String fnbin,String fnmask, int kind); + + public native long newsession(); + public native int finsession(long sessid); + public native int consession(long sessid); + public native int allcnt(long sessid); + public native int readycnt(long sessid); + public native int pushpcm(long sessid,byte[] arrbuf,int size, int kind); + + public native int filerst(long sessid,String picfn,String mskfn, + int[] arrbox,String fgpic,int index, byte[] arrimg,byte[] arrmsk,int imgsize); + + public native int bufrst(long sessid, int[] arrbox,int index, byte[] arrimg,int imgsize); + + public native int fileload(String picfn,String mskfn,int width,int height, + byte[] arrpic,byte[] arrmsk,int imgsize); + + public native int startgpg(String picfn,String gpgfn); + public native int stopgpg(); + public native int processmd5(int kind,String infn,String outfn); + + static { + System.loadLibrary("gjduix"); + } +} diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/Callback.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/Callback.java new file mode 100644 index 0000000..274eb14 --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/Callback.java @@ -0,0 +1,7 @@ +package ai.guiji.duix.sdk.client; + +public interface Callback { + + void onEvent(String event, String msg, Object info); + +} \ No newline at end of file diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/Constant.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/Constant.java new file mode 100644 index 0000000..c783c05 --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/Constant.java @@ -0,0 +1,21 @@ +package ai.guiji.duix.sdk.client; + +public class Constant { + + public static final int VERSION_CODE = BuildConfig.VERSION_CODE; + public static final String VERSION_NAME = BuildConfig.VERSION_NAME; + + + // DUIX的回调事件 + public static final String CALLBACK_EVENT_INIT_READY = "init.ready"; + public static final String CALLBACK_EVENT_INIT_ERROR = "init.error"; + public static final String CALLBACK_EVENT_AUDIO_PLAY_START = "play.start"; + public static final String CALLBACK_EVENT_AUDIO_PLAY_END = "play.end"; + public static final String CALLBACK_EVENT_AUDIO_PLAY_ERROR = "play.error"; + public static final String CALLBACK_EVENT_MOTION_START = "motion.start"; + public static final String CALLBACK_EVENT_MOTION_END = "motion.end"; + + + public static final String BASE_DOWNLOAD_URL = "https://github.com/GuijiAI/duix.ai/releases/download/v1.0.0/gj_dh_res.zip"; // 基础配置文件包 + +} diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/DUIX.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/DUIX.java new file mode 100644 index 0000000..3f16e6f --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/DUIX.java @@ -0,0 +1,231 @@ +package ai.guiji.duix.sdk.client; + +import android.content.Context; + +import java.io.File; +import java.io.FileInputStream; +import java.util.Arrays; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import ai.guiji.duix.sdk.client.loader.ModelInfo; +import ai.guiji.duix.sdk.client.render.RenderSink; +import ai.guiji.duix.sdk.client.thread.RenderThread; + +public class DUIX { + + private final Context mContext; + private final Callback mCallback; + private final String modelName; + private final RenderSink renderSink; + private ExecutorService commonExecutor = Executors.newSingleThreadExecutor(); + private RenderThread mRenderThread; + + private boolean isReady; // 准备完成的标记 + private float mVolume = 1.0F; + private RenderThread.Reporter reporter; + + public DUIX(Context context, String modelName, RenderSink sink, Callback callback) { + this.mContext = context; + this.mCallback = callback; + this.modelName = modelName; + this.renderSink = sink; + } + + /** + * 模型读取 + */ + public void init() { + // 先检查模型文件 + File duixDir = mContext.getExternalFilesDir("duix"); + + File baseConfigDir = new File(duixDir + "/model/gj_dh_res"); + File baseConfigTag = new File(duixDir + "/model/tmp/gj_dh_res"); + if (!baseConfigDir.exists() || !baseConfigTag.exists()){ + if (mCallback != null){ + mCallback.onEvent(Constant.CALLBACK_EVENT_INIT_ERROR, "[gj_dh_res] does not exist", null); + } + return; + } + + String dirName = ""; + if (modelName.startsWith("https://") || modelName.startsWith("http://")){ + try { + dirName = modelName.substring(modelName.lastIndexOf("/") + 1).replace(".zip", ""); + }catch (Exception ignore){ + } + } else { + dirName = modelName; + } + File modelDir = new File(duixDir + "/model", dirName); + File modelTag = new File(duixDir + "/model/tmp", dirName); + if (!modelDir.exists() || !modelTag.exists()){ + if (mCallback != null){ + mCallback.onEvent(Constant.CALLBACK_EVENT_INIT_ERROR, "[" + dirName + "] does not exist", null); + } + return; + } + + if (mRenderThread != null) { + mRenderThread.stopPreview(); + mRenderThread = null; + } + mRenderThread = new RenderThread(mContext, modelDir, renderSink, mVolume, new RenderThread.RenderCallback() { + + @Override + public void onInitResult(int code, int subCode, String message, ModelInfo modelInfo) { + if (code == 0){ + isReady = true; + if (mCallback != null){ + mCallback.onEvent(Constant.CALLBACK_EVENT_INIT_READY, "init ok", modelInfo); + } + } else { + if (mCallback != null){ + mCallback.onEvent(Constant.CALLBACK_EVENT_INIT_ERROR, code + ", " + subCode + ", " + message, null); + } + } + } + + @Override + public void onPlayStart() { + if (mCallback != null){ + mCallback.onEvent(Constant.CALLBACK_EVENT_AUDIO_PLAY_START, "play start", null); + } + } + + @Override + public void onPlayEnd() { + if (mCallback != null){ + mCallback.onEvent(Constant.CALLBACK_EVENT_AUDIO_PLAY_END, "play end", null); + } + } + + @Override + public void onPlayError(int code, String msg) { + if (mCallback != null){ + mCallback.onEvent(Constant.CALLBACK_EVENT_AUDIO_PLAY_ERROR, "audio play error code: " + code + " msg: " + msg, null); + } + } + + @Override + public void onMotionPlayStart(String name) { + if (mCallback != null){ + mCallback.onEvent(Constant.CALLBACK_EVENT_MOTION_START, "", null); + } + } + + @Override + public void onMotionPlayComplete(String name) { + if (mCallback != null){ + mCallback.onEvent(Constant.CALLBACK_EVENT_MOTION_END, "", null); + } + } + }, reporter); + mRenderThread.setName("DUIXRender-Thread"); + mRenderThread.start(); + } + + public boolean isReady() { + return isReady; + } + + public void setVolume(float volume){ + if (volume >= 0.0F && volume <= 1.0F){ + mVolume = volume; + if (mRenderThread != null){ + mRenderThread.setVolume(volume); + } + } + } + + public void startPush(){ + if (mRenderThread != null){ + mRenderThread.startPush(); + } + } + + public void pushPcm(byte[] buffer){ + if (mRenderThread != null){ + mRenderThread.pushAudio(buffer.clone()); + } + } + + public void stopPush(){ + if (mRenderThread != null){ + mRenderThread.stopPush(); + } + } + + + /** + * 播放音频文件 + * 这里演示了兼容旧的wav音频文件驱动 + * @param wavPath 16k采样率单通道16位深的wav本地文件 + */ + public void playAudio(String wavPath) { + File wavFile = new File(wavPath); + if (isReady && mRenderThread != null && wavFile.exists() && wavFile.length() > 44) { +// mRenderThread.prepareAudio(wavPath); + // 这里默认wav的头是44bytes,并且采样率是16000、单通道、16bit深度 + byte[] data = new byte[(int) wavFile.length()]; + try (FileInputStream inputStream = new FileInputStream(wavFile)) { + inputStream.read(data); + } catch (Exception e) { + throw new RuntimeException(e); + } + byte[] slice = Arrays.copyOfRange(data, 44, data.length); + startPush(); + pushPcm(slice); + stopPush(); + } + } + + /** + * 停止音频播放 + */ + public boolean stopAudio() { + if (isReady && mRenderThread != null) { + mRenderThread.stopPlayAudio(); + return true; + } else { + return false; + } + } + + + /** + * 播放一只指定动作区间 + */ + public void startMotion(String name, boolean now) { + if (mRenderThread != null) { + mRenderThread.requireMotion(name, now); + } + } + + /** + * 随机播放一个动作区间 + */ + public void startRandomMotion(boolean now) { + if (mRenderThread != null) { + mRenderThread.requireRandomMotion(now); + } + } + + public void release() { + isReady = false; + if (commonExecutor != null) { + commonExecutor.shutdown(); + commonExecutor = null; + } + if (mRenderThread != null) { + mRenderThread.stopPreview(); + } + } + + public void setReporter(RenderThread.Reporter reporter){ + this.reporter = reporter; + if (mRenderThread != null) { + mRenderThread.setReporter(reporter); + } + } +} diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/VirtualModelUtil.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/VirtualModelUtil.java new file mode 100644 index 0000000..20c4e8d --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/VirtualModelUtil.java @@ -0,0 +1,162 @@ +package ai.guiji.duix.sdk.client; + +import android.content.Context; +import android.text.TextUtils; + +import java.io.File; + +import ai.guiji.duix.sdk.client.net.DownloadZipService; + + +public class VirtualModelUtil { + + public static boolean checkBaseConfig(Context context){ + String duixDir = context.getExternalFilesDir("duix").getAbsolutePath(); + File baseDir = new File(duixDir + "/model", "gj_dh_res"); + File baseTag = new File(duixDir + "/model/tmp", "gj_dh_res"); + return baseDir.exists() && baseTag.exists(); + } + + public static boolean checkModel(Context context, String name){ + if (!TextUtils.isEmpty(name)){ + String duixDir = context.getExternalFilesDir("duix").getAbsolutePath(); + if (name.startsWith("https://") || name.startsWith("http://")){ + String dirName = ""; + try { + dirName = name.substring(name.lastIndexOf("/") + 1).replace(".zip", ""); + }catch (Exception ignore){ + } + if (!TextUtils.isEmpty(dirName)){ + File modelDir = new File(duixDir + "/model", dirName); + File modelTag = new File(duixDir + "/model/tmp", dirName); + return modelDir.exists() && modelTag.exists(); + } else { + return false; + } + } else { + File modelDir = new File(duixDir + "/model", name); + File modelTag = new File(duixDir + "/model/tmp", name); + return modelDir.exists() && modelTag.exists(); + } + } else { + return false; + } + } + + public static void baseConfigDownload(Context context, ModelDownloadCallback callback){ + String url = Constant.BASE_DOWNLOAD_URL; + baseConfigDownload(context, url, callback); + } + /** + * 基础配置文件下载 + */ + public static void baseConfigDownload(Context context, String url, ModelDownloadCallback callback){ + String duixDir = context.getExternalFilesDir("duix").getAbsolutePath(); + File baseDir = new File(duixDir + "/model", "gj_dh_res"); + DownloadZipService.downloadAndUnzip(context, url, baseDir, new DownloadZipService.Callback() { + @Override + public void onDownloadProgress(long current, long total) { + if (callback != null){ + callback.onDownloadProgress(url, current, total); + } + } + + @Override + public void onUnzipProgress(long current, long total) { + if (callback != null){ + callback.onUnzipProgress(url, current, total); + } + } + + @Override + public void onComplete(File baseDirFile) { + // init model + if (callback != null){ + callback.onDownloadComplete(url, baseDirFile); + } + } + + @Override + public void onError(int code, String msg) { + if (callback != null){ + callback.onDownloadFail(url, code, msg); + } + } + }, true); + } + + /** + * 模型文件下载 + */ + public static void modelDownload(Context context, String modelUrl, ModelDownloadCallback callback){ + String duixDir = context.getExternalFilesDir("duix").getAbsolutePath(); + if (!TextUtils.isEmpty(modelUrl) && (modelUrl.startsWith("https://") || modelUrl.startsWith("http://"))){ + String dirName = ""; + try { + dirName = modelUrl.substring(modelUrl.lastIndexOf("/") + 1).replace(".zip", ""); + }catch (Exception ignore){ + } + if (!TextUtils.isEmpty(dirName)){ + File modelDir = new File(duixDir + "/model", dirName); + // 下载模型文件 + DownloadZipService.downloadAndUnzip(context, modelUrl, modelDir, new DownloadZipService.Callback() { + @Override + public void onDownloadProgress(long current, long total) { + if (callback != null){ + callback.onDownloadProgress(modelUrl, current, total); + } + } + + @Override + public void onUnzipProgress(long current, long total) { + if (callback != null){ + callback.onUnzipProgress(modelUrl, current, total); + } + } + + @Override + public void onComplete(File modelFile) { + // init model + if (callback != null){ + callback.onDownloadComplete(modelUrl, modelFile); + } + } + + @Override + public void onError(int code, String msg) { + if (callback != null){ + callback.onDownloadFail(modelUrl, code, msg); + } + } + }, true); + } else { + if (callback != null){ + callback.onDownloadFail(modelUrl, -1004, "Illegal model url[" + modelUrl + "]"); + } + } + } else { + if (callback != null){ + callback.onDownloadFail(modelUrl, -1003, "Illegal download url[" + modelUrl + "]"); + } + } + } + + public interface ModelDownloadCallback { + + void onDownloadProgress(String url, long current, long total); + + void onUnzipProgress(String url, long current, long total); + + void onDownloadComplete(String url, File dir); + + /** + * -1000 Compressed file download failed + * -1001 An exception occurred while decompressing the file + * -1002 Target folder not found + * -1003 Illegal download url + * -1004 Illegal model url + * -1005 Service not initialized + */ + void onDownloadFail(String url, int code, String msg); + } +} diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/audio/AudioPlayer.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/audio/AudioPlayer.java new file mode 100644 index 0000000..43a4cf1 --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/audio/AudioPlayer.java @@ -0,0 +1,172 @@ +package ai.guiji.duix.sdk.client.audio; + +import android.media.AudioFormat; +import android.media.AudioManager; +import android.media.AudioTrack; + +import java.nio.ByteBuffer; +import java.util.concurrent.ConcurrentLinkedQueue; + +import ai.guiji.duix.sdk.client.bean.AudioFrame; +import ai.guiji.duix.sdk.client.util.Logger; + + +public class AudioPlayer { + + private AudioTrack audioTrack; + private PlaybackThread playbackThread; + + private int sampleRate = 16000; // 采样率 + private int channelConfig = AudioFormat.CHANNEL_OUT_MONO; // 声道配置 + private int audioFormat = AudioFormat.ENCODING_PCM_16BIT; // 音频格式 + // int bufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat); + private int bufferSize = 1280; // 10ms 320 + + private ConcurrentLinkedQueue mPlayQueue = new ConcurrentLinkedQueue<>(); // 播放帧 + + private AudioPlayerCallback callback; + + private ByteBuffer waitNextBuffer; + + public AudioPlayer(AudioPlayerCallback callback, float volume){ + this.callback = callback; + audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, // 音频流类型 + sampleRate, + channelConfig, + audioFormat, + bufferSize, + AudioTrack.MODE_STREAM); // 流模式 + if (volume != 1.0F){ + audioTrack.setVolume(volume); + } + int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat); + Logger.d("AudioPlayer init bufferSize: " + bufferSize + " minBufferSize: " + minBufferSize); + waitNextBuffer = ByteBuffer.allocate(bufferSize); + } + + public void setVolume(float volume){ + audioTrack.setVolume(volume); + } + + public void startPlay(){ + stop(); + try { + audioTrack.play(); + callback.onPlayStart(); + } catch (Exception e){ + callback.onPlayError(-1000, e.getMessage()); + } +// Logger.e("AudioPlayer 开始播放"); + playbackThread = new PlaybackThread(); + playbackThread.start(); + } + + public void pushStart(){ + mPlayQueue.clear(); + waitNextBuffer.clear(); + waitNextBuffer.position(0); + } + + public void pushData(ByteBuffer data){ + while (data.hasRemaining()){ + int min = Math.min(waitNextBuffer.remaining(), data.remaining()); + byte[] b = new byte[min]; + data.get(b); + waitNextBuffer.put(b); + if (!waitNextBuffer.hasRemaining()){ + waitNextBuffer.position(0); + byte[] pushBytes = new byte[waitNextBuffer.remaining()]; + waitNextBuffer.get(pushBytes); + waitNextBuffer.position(0); + mPlayQueue.add(new AudioFrame(pushBytes, pushBytes.length)); + } + } + } + + public void pushDone(){ + int size = waitNextBuffer.position(); + if (size > 0){ + waitNextBuffer.position(0); + byte[] pushBytes = new byte[waitNextBuffer.remaining()]; + waitNextBuffer.get(pushBytes); + waitNextBuffer.position(0); + mPlayQueue.add(new AudioFrame(pushBytes, size)); + } + mPlayQueue.add(new AudioFrame(true)); + } + + public void stop() { + if (playbackThread != null) { + try { + playbackThread.stopPlay(); + playbackThread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + playbackThread = null; + } + if (audioTrack != null) { + audioTrack.stop(); + } + } + + public void release(){ + stop(); + if (audioTrack != null) { + audioTrack.release(); + } + mPlayQueue.clear(); + } + + public int getPlayIndex(){ + long framesPlayed = audioTrack.getPlaybackHeadPosition(); + int durationInMillis = (int)((framesPlayed * 1000L) / audioTrack.getSampleRate()); + return durationInMillis / 40; + } + + private class PlaybackThread extends Thread { + + private volatile boolean isPlaying = true; + private final Object mPlayingFence = new Object(); // 给isPlaying加一个对象锁 + + public void stopPlay(){ + synchronized (mPlayingFence){ + isPlaying = false; + } + } + + private boolean isPlaying(){ + synchronized (mPlayingFence){ + return isPlaying; + } + } + + @Override + public void run() { + super.run(); + while (isPlaying()) { + AudioFrame top = mPlayQueue.poll(); + if (top != null){ + if (top.completeEmptyFrame){ + callback.onPlayEnd(); + stopPlay(); + break; + } else { + audioTrack.write(top.buffer, 0, top.size, AudioTrack.WRITE_BLOCKING); + } + } + } + if (audioTrack != null) { + audioTrack.stop(); + } + Logger.i("AudioPlayer play finish"); + } + } + + public interface AudioPlayerCallback{ + void onPlayStart(); + void onPlayEnd(); + void onPlayError(int code, String msg); + } + +} diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/bean/AudioFrame.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/bean/AudioFrame.java new file mode 100644 index 0000000..b60f374 --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/bean/AudioFrame.java @@ -0,0 +1,25 @@ +package ai.guiji.duix.sdk.client.bean; + +public class AudioFrame { + + public AudioFrame(byte[] buffer, int size){ + this.buffer = buffer; + this.size = size; + } + + public AudioFrame(boolean completeEmptyFrame){ + this.completeEmptyFrame = completeEmptyFrame; + } + + public boolean completeEmptyFrame; + + public byte[] buffer; + public int size; + + @Override + public String toString() { + return "AudioFrame{" + + "completeEmptyFrame=" + completeEmptyFrame + + '}'; + } +} diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/bean/ImageFrame.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/bean/ImageFrame.java new file mode 100644 index 0000000..d814832 --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/bean/ImageFrame.java @@ -0,0 +1,21 @@ +package ai.guiji.duix.sdk.client.bean; + + +import java.nio.ByteBuffer; + +public class ImageFrame { + + public ImageFrame(ByteBuffer rawBuffer, ByteBuffer maskBuffer, int width, int height) { + this.rawBuffer = rawBuffer; + this.maskBuffer = maskBuffer; + this.width = width; + this.height = height; + } + + public int width; + public int height; + + public ByteBuffer rawBuffer; + public ByteBuffer maskBuffer; + +} diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/net/DownloadZipService.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/net/DownloadZipService.java new file mode 100644 index 0000000..ed0ee50 --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/net/DownloadZipService.java @@ -0,0 +1,99 @@ +package ai.guiji.duix.sdk.client.net; + +import android.content.Context; + +import java.io.File; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +import ai.guiji.duix.sdk.client.util.Logger; +import ai.guiji.duix.sdk.client.util.MD5Util; +import ai.guiji.duix.sdk.client.util.ZipUtil; + + +public class DownloadZipService { + + public interface Callback { + void onDownloadProgress(long current, long total); + + void onUnzipProgress(long current, long total); + + void onComplete(File dirFile); + + void onError(int code, String msg); + } + + /** + * 下载zip文件并解压 + * + */ + public static void downloadAndUnzip(Context context, String url, File targetDirFile, Callback callback, boolean deleteZip) { + Executor executor = Executors.newSingleThreadExecutor(); + executor.execute(() -> { + File cacheDir = context.getExternalCacheDir(); + if (!cacheDir.exists()) { + cacheDir.mkdirs(); + } + File zipFile = new File(cacheDir, MD5Util.string2MD5(url)); + boolean result = true; + if (!zipFile.exists()) { + Logger.d("zip not found, try download."); + result = new FileDownloader(url, zipFile.getAbsolutePath(), callback::onDownloadProgress).download(); + Logger.d("download file done."); + } else { + Logger.d( "found cache zip file."); + } + if (result) { + Logger.e( "try unzip file."); + if (targetDirFile.exists()) { + Logger.e("delete old files."); + deleteContents(targetDirFile); + } + // 拿到目标路径的父级 + File targetParentDir = targetDirFile.getParentFile(); + if (!targetParentDir.exists()) { + targetParentDir.mkdirs(); + } + result = ZipUtil.unzip(zipFile.getAbsolutePath(), targetParentDir.getAbsolutePath(), callback::onUnzipProgress); + if (result) { + Logger.d( "unzip file complete."); + // 这里时候targetDirFile应该是存在的 + if (targetDirFile.exists()) { + File tmpDir = new File(targetParentDir, "tmp/" + targetDirFile.getName()); + if (!tmpDir.mkdirs()){ + Logger.e("make tmp dir fail"); + } + if (deleteZip && zipFile.exists()){ + zipFile.delete(); + } + callback.onComplete(targetDirFile); + } else { + callback.onError(-1002,"unzip dir not found!"); + } + } else { + callback.onError(-1001, "unzip file error!"); + zipFile.delete(); + } + } else { + callback.onError(-1000, "zip file download error"); + } + }); + } + + public static boolean deleteContents(File dir) { + File[] files = dir.listFiles(); + boolean success = true; + if (files != null) { + for (File file : files) { + if (file.isDirectory()) { + success &= deleteContents(file); + } + if (!file.delete()) { + success = false; + } + } + } + return success; + } + +} diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/net/FileDownloader.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/net/FileDownloader.java new file mode 100644 index 0000000..4f7d8e9 --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/net/FileDownloader.java @@ -0,0 +1,75 @@ +package ai.guiji.duix.sdk.client.net; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +import ai.guiji.duix.sdk.client.util.Logger; + + +public class FileDownloader { + + private String url; + private String path; + + private Callback callback; + + public FileDownloader(String url, String path, Callback callback){ + this.url = url; + this.path = path; + this.callback = callback; + } + + public boolean download(){ + try { + URL httpUrl = new URL(url); + HttpURLConnection conn = (HttpURLConnection) httpUrl.openConnection(); + conn.setConnectTimeout(15000); + conn.setReadTimeout(15000); + long contentLength = conn.getContentLengthLong(); + conn.connect(); + int httpCode = conn.getResponseCode();//获取HTTP状态码 + if (httpCode == HttpURLConnection.HTTP_OK) { + File tmpFile = new File(path + ".tmp"); + File parent = tmpFile.getParentFile(); + if (parent != null && !parent.exists()) { + if (!parent.mkdirs()) { + return false; + } + } + if (tmpFile.exists()) { + tmpFile.delete(); + } + FileOutputStream fileOutputStream = new FileOutputStream(tmpFile); + long downloadLength = 0; + int len; + byte[] data = new byte[1024]; + InputStream is = conn.getInputStream(); + while ((len = is.read(data)) != -1) { + fileOutputStream.write(data, 0, len); + downloadLength += len; + if (callback != null){ + callback.onProgress(downloadLength , contentLength); + } + } + fileOutputStream.flush(); + is.close(); + fileOutputStream.close(); + File target = new File(path); + if (tmpFile.renameTo(target)) { + return true; + } + } + } catch (Exception e){ + Logger.d("download error:" + e); + } + return false; + } + + public interface Callback { + void onProgress(long current, long total); + } + +} diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/render/DUIXRenderer.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/render/DUIXRenderer.java new file mode 100644 index 0000000..82b97b9 --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/render/DUIXRenderer.java @@ -0,0 +1,110 @@ +package ai.guiji.duix.sdk.client.render; + +import android.content.Context; +import android.opengl.GLES20; +import android.util.Log; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + +import ai.guiji.duix.sdk.client.bean.ImageFrame; +import ai.guiji.duix.sdk.client.util.OpenGLUtil; + +public final class DUIXRenderer implements DUIXTextureView.Renderer, RenderSink{ + + private static final String TAG = "DUIXRenderer"; + + DUIXTextureView glTextureView; + private Context mContext; + + private int mViewWidth = 0; + private int mViewHeight = 0; + private int mVideoWidth = 0; + private int mVideoHeight = 0; + + protected float[] mMvpMatrix = new float[16]; // 缩放的矩阵 + + private ImageFrame pendingFrame; + + private ImageDrawer mImageDrawer; + + private static final int SCALE_TYPE_CROP = 0; + private static final int SCALE_TYPE_INSIDE = 1; + private int scaleType = SCALE_TYPE_CROP; + + public DUIXRenderer(Context context, DUIXTextureView glTextureView) { + mContext = context; + this.glTextureView = glTextureView; + } + + @Override + public void onVideoFrame(ImageFrame imageFrame) { + pendingFrame = imageFrame; + if (mVideoWidth != imageFrame.width || mVideoHeight != imageFrame.height) { + mVideoWidth = imageFrame.width; + mVideoHeight = imageFrame.height; + tryChangeScale(); + } + glTextureView.requestRender(); + } + + public void setScaleType(int scaleType) { + this.scaleType = scaleType; + } + + @Override + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + Log.e(TAG, "onSurfaceCreated"); + mImageDrawer = new ImageDrawer(); + } + + @Override + public void onSurfaceChanged(GL10 gl, int width, int height) { + Log.e(TAG, "onSurfaceChanged size: " + " width: " + width + " height: " + height); + GLES20.glViewport(0, 0, width, height); + mViewWidth = width; + mViewHeight = height; + tryChangeScale(); + } + + private void tryChangeScale() { + if (mViewWidth > 0 && mViewHeight > 0 && mVideoWidth > 0 && mVideoHeight > 0) { + if (scaleType == SCALE_TYPE_CROP){ + mMvpMatrix = OpenGLUtil.changeMvpMatrixCrop(mViewWidth, mViewHeight, mVideoWidth, mVideoHeight); + } else { + mMvpMatrix = OpenGLUtil.changeMvpMatrixInside(mViewWidth, mViewHeight, mVideoWidth, mVideoHeight); + } + } + } + + @Override + public void onDrawFrame(GL10 gl) { +// Log.e(TAG, "onDrawFrame"); + GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); + GLES20.glClearColor(0, 0, 0, 0); + // 融合,不然透明会有问题 + GLES20.glEnable(GLES20.GL_BLEND); + // 半透明会有白色边框 +// GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ZERO); + // 使用glBlendFuncSeparate为RGB和alpha通道分别设置不同的选项:照常设置了RGB分量,但让最终的alpha分量只被源颜色向量的alpha值影响。 + GLES20.glBlendFuncSeparate(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA, GLES20.GL_ONE, GLES20.GL_ZERO); + + if (pendingFrame != null) { + mImageDrawer.draw(pendingFrame, mMvpMatrix); + } + } + + @Override + public void onSurfaceDestroyed(GL10 gl) { + Log.e(TAG, "onSurfaceDestroyed"); + if (mImageDrawer != null) { + mImageDrawer.release(); + } + } + + + public void release() { + + } + +} diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/render/DUIXTextureView.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/render/DUIXTextureView.java new file mode 100644 index 0000000..dae8213 --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/render/DUIXTextureView.java @@ -0,0 +1,1832 @@ +package ai.guiji.duix.sdk.client.render; + +import android.content.Context; +import android.graphics.SurfaceTexture; +import android.opengl.GLDebugHelper; +import android.util.AttributeSet; +import android.util.Log; +import android.view.TextureView; +import android.view.View; + +import java.io.Writer; +import java.lang.ref.WeakReference; +import java.util.ArrayList; + +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGL11; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; +import javax.microedition.khronos.egl.EGLSurface; +import javax.microedition.khronos.opengles.GL; +import javax.microedition.khronos.opengles.GL10; + +import ai.guiji.duix.sdk.client.BuildConfig; + + +public class DUIXTextureView + extends TextureView + implements TextureView.SurfaceTextureListener, + View.OnLayoutChangeListener { + + private final static boolean DEBUG = false; + + private final static String TAG = "DUIXTextureView"; + private final static boolean LOG_ATTACH_DETACH = DEBUG; + private final static boolean LOG_THREADS = DEBUG; + private final static boolean LOG_PAUSE_RESUME = DEBUG; + private final static boolean LOG_SURFACE = DEBUG; + private final static boolean LOG_RENDERER = DEBUG; + private final static boolean LOG_RENDERER_DRAW_FRAME = DEBUG; + private final static boolean LOG_EGL = DEBUG; + /** + * The renderer only renders + * when the surface is created, or when {@link #requestRender} is called. + * + * @see #getRenderMode() + * @see #setRenderMode(int) + * @see #requestRender() + */ + public final static int RENDERMODE_WHEN_DIRTY = 0; + /** + * The renderer is called + * continuously to re-render the scene. + * + * @see #getRenderMode() + * @see #setRenderMode(int) + */ + public final static int RENDERMODE_CONTINUOUSLY = 1; + + /** + * Check glError() after every GL call and throw an exception if glError indicates + * that an error has occurred. This can be used to help track down which OpenGL ES call + * is causing an error. + * + * @see #getDebugFlags + * @see #setDebugFlags + */ + public final static int DEBUG_CHECK_GL_ERROR = 1; + + /** + * Log GL calls to the system log at "verbose" level with tag "DUIXTextureView". + * + * @see #getDebugFlags + * @see #setDebugFlags + */ + public final static int DEBUG_LOG_GL_CALLS = 2; + + /** + * Standard View constructor. In order to render something, you + * must call {@link #setRenderer} to register a renderer. + */ + public DUIXTextureView(Context context) { + super(context); + init(); + } + + /** + * Standard View constructor. In order to render something, you + * must call {@link #setRenderer} to register a renderer. + */ + public DUIXTextureView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + @Override + protected void finalize() throws Throwable { + try { + if (mGLThread != null) { + // GLThread may still be running if this view was never + // attached to a window. + mGLThread.requestExitAndWait(); + } + } finally { + super.finalize(); + } + } + + private void init() { + setSurfaceTextureListener(this); + } + +// /** +// * 设置监听器,上报 DUIXTextureView 内部的错误 +// */ +// private IMonitor monitor; +// public void setMonitor(IMonitor monitor) { +// this.monitor = monitor; +// } +// +// private void sendMonitor(boolean status, String info) { +// if (monitor != null) { +// monitor.monitor(status, "unknown", 0, 0, info); +// } +// } + + /** + * Set the glWrapper. If the glWrapper is not null, its + * {@link GLWrapper#wrap(GL)} method is called + * whenever a surface is created. A GLWrapper can be used to wrap + * the GL object that's passed to the renderer. Wrapping a GL + * object enables examining and modifying the behavior of the + * GL calls made by the renderer. + *

+ * Wrapping is typically used for debugging purposes. + *

+ * The default value is null. + * @param glWrapper the new GLWrapper + */ + public void setGLWrapper(GLWrapper glWrapper) { + mGLWrapper = glWrapper; + } + + /** + * Set the debug flags to a new value. The value is + * constructed by OR-together zero or more + * of the DEBUG_CHECK_* constants. The debug flags take effect + * whenever a surface is created. The default value is zero. + * @param debugFlags the new debug flags + * @see #DEBUG_CHECK_GL_ERROR + * @see #DEBUG_LOG_GL_CALLS + */ + public void setDebugFlags(int debugFlags) { + mDebugFlags = debugFlags; + } + + /** + * Get the current value of the debug flags. + * @return the current value of the debug flags. + */ + public int getDebugFlags() { + return mDebugFlags; + } + + /** + * Control whether the EGL context is preserved when the DUIXTextureView is paused and + * resumed. + *

+ * If set to true, then the EGL context may be preserved when the DUIXTextureView is paused. + * Whether the EGL context is actually preserved or not depends upon whether the + * Android device that the program is running on can support an arbitrary number of EGL + * contexts or not. Devices that can only support a limited number of EGL contexts must + * release the EGL context in order to allow multiple applications to share the GPU. + *

+ * If set to false, the EGL context will be released when the DUIXTextureView is paused, + * and recreated when the DUIXTextureView is resumed. + *

+ * + * The default is false. + * + * @param preserveOnPause preserve the EGL context when paused + */ + public void setPreserveEGLContextOnPause(boolean preserveOnPause) { + mPreserveEGLContextOnPause = preserveOnPause; + } + + /** + * @return true if the EGL context will be preserved when paused + */ + public boolean getPreserveEGLContextOnPause() { + return mPreserveEGLContextOnPause; + } + + /** + * Set the renderer associated with this view. Also starts the thread that + * will call the renderer, which in turn causes the rendering to start. + *

This method should be called once and only once in the life-cycle of + * a DUIXTextureView. + *

The following DUIXTextureView methods can only be called before + * setRenderer is called: + *

    + *
  • {@link #setEGLConfigChooser(boolean)} + *
  • {@link #setEGLConfigChooser(EGLConfigChooser)} + *
  • {@link #setEGLConfigChooser(int, int, int, int, int, int)} + *
+ *

+ * The following DUIXTextureView methods can only be called after + * setRenderer is called: + *

    + *
  • {@link #getRenderMode()} + *
  • {@link #onPause()} + *
  • {@link #onResume()} + *
  • {@link #queueEvent(Runnable)} + *
  • {@link #requestRender()} + *
  • {@link #setRenderMode(int)} + *
+ * + * @param renderer the renderer to use to perform OpenGL drawing. + */ + public void setRenderer(Renderer renderer) { + checkRenderThreadState(); + if (mEGLConfigChooser == null) { + mEGLConfigChooser = new SimpleEGLConfigChooser(true); + } + if (mEGLContextFactory == null) { + mEGLContextFactory = new DefaultContextFactory(); + } + if (mEGLWindowSurfaceFactory == null) { + mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory(); + } + mRenderer = renderer; + mGLThread = new GLThread(mThisWeakRef); + mGLThread.start(); + } + + /** + * Install a custom EGLContextFactory. + *

If this method is + * called, it must be called before {@link #setRenderer(Renderer)} + * is called. + *

+ * If this method is not called, then by default + * a context will be created with no shared context and + * with a null attribute list. + */ + public void setEGLContextFactory(EGLContextFactory factory) { + checkRenderThreadState(); + mEGLContextFactory = factory; + } + + /** + * Install a custom EGLWindowSurfaceFactory. + *

If this method is + * called, it must be called before {@link #setRenderer(Renderer)} + * is called. + *

+ * If this method is not called, then by default + * a window surface will be created with a null attribute list. + */ + public void setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory factory) { + checkRenderThreadState(); + mEGLWindowSurfaceFactory = factory; + } + + /** + * Install a custom EGLConfigChooser. + *

If this method is + * called, it must be called before {@link #setRenderer(Renderer)} + * is called. + *

+ * If no setEGLConfigChooser method is called, then by default the + * view will choose an EGLConfig that is compatible with the current + * android.view.Surface, with a depth buffer depth of + * at least 16 bits. + * @param configChooser + */ + public void setEGLConfigChooser(EGLConfigChooser configChooser) { + checkRenderThreadState(); + mEGLConfigChooser = configChooser; + } + + /** + * Install a config chooser which will choose a config + * as close to 16-bit RGB as possible, with or without an optional depth + * buffer as close to 16-bits as possible. + *

If this method is + * called, it must be called before {@link #setRenderer(Renderer)} + * is called. + *

+ * If no setEGLConfigChooser method is called, then by default the + * view will choose an RGB_888 surface with a depth buffer depth of + * at least 16 bits. + * + * @param needDepth + */ + public void setEGLConfigChooser(boolean needDepth) { + setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth)); + } + + /** + * Install a config chooser which will choose a config + * with at least the specified depthSize and stencilSize, + * and exactly the specified redSize, greenSize, blueSize and alphaSize. + *

If this method is + * called, it must be called before {@link #setRenderer(Renderer)} + * is called. + *

+ * If no setEGLConfigChooser method is called, then by default the + * view will choose an RGB_888 surface with a depth buffer depth of + * at least 16 bits. + * + */ + public void setEGLConfigChooser(int redSize, int greenSize, int blueSize, + int alphaSize, int depthSize, int stencilSize) { + setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize, + blueSize, alphaSize, depthSize, stencilSize)); + } + + /** + * Inform the default EGLContextFactory and default EGLConfigChooser + * which EGLContext client version to pick. + *

Use this method to create an OpenGL ES 2.0-compatible context. + * Example: + *

+     *     public MyView(Context context) {
+     *         super(context);
+     *         setEGLContextClientVersion(2); // Pick an OpenGL ES 2.0 context.
+     *         setRenderer(new MyRenderer());
+     *     }
+     * 
+ *

Note: Activities which require OpenGL ES 2.0 should indicate this by + * setting @lt;uses-feature android:glEsVersion="0x00020000" /> in the activity's + * AndroidManifest.xml file. + *

If this method is called, it must be called before {@link #setRenderer(Renderer)} + * is called. + *

This method only affects the behavior of the default EGLContexFactory and the + * default EGLConfigChooser. If + * {@link #setEGLContextFactory(EGLContextFactory)} has been called, then the supplied + * EGLContextFactory is responsible for creating an OpenGL ES 2.0-compatible context. + * If + * {@link #setEGLConfigChooser(EGLConfigChooser)} has been called, then the supplied + * EGLConfigChooser is responsible for choosing an OpenGL ES 2.0-compatible config. + * @param version The EGLContext client version to choose. Use 2 for OpenGL ES 2.0 + */ + public void setEGLContextClientVersion(int version) { + checkRenderThreadState(); + mEGLContextClientVersion = version; + } + + /** + * Set the rendering mode. When renderMode is + * RENDERMODE_CONTINUOUSLY, the renderer is called + * repeatedly to re-render the scene. When renderMode + * is RENDERMODE_WHEN_DIRTY, the renderer only rendered when the surface + * is created, or when {@link #requestRender} is called. Defaults to RENDERMODE_CONTINUOUSLY. + *

+ * Using RENDERMODE_WHEN_DIRTY can improve battery life and overall system performance + * by allowing the GPU and CPU to idle when the view does not need to be updated. + *

+ * This method can only be called after {@link #setRenderer(Renderer)} + * + * @param renderMode one of the RENDERMODE_X constants + * @see #RENDERMODE_CONTINUOUSLY + * @see #RENDERMODE_WHEN_DIRTY + */ + public void setRenderMode(int renderMode) { + mGLThread.setRenderMode(renderMode); + } + + /** + * Get the current rendering mode. May be called + * from any thread. Must not be called before a renderer has been set. + * @return the current rendering mode. + * @see #RENDERMODE_CONTINUOUSLY + * @see #RENDERMODE_WHEN_DIRTY + */ + public int getRenderMode() { + return mGLThread.getRenderMode(); + } + + /** + * Request that the renderer render a frame. + * This method is typically used when the render mode has been set to + * {@link #RENDERMODE_WHEN_DIRTY}, so that frames are only rendered on demand. + * May be called + * from any thread. Must not be called before a renderer has been set. + */ + public void requestRender() { + mGLThread.requestRender(); + } + + /** + * This method is part of the SurfaceHolder.Callback interface, and is + * not normally called or subclassed by clients of DUIXTextureView. + */ + public void surfaceCreated(SurfaceTexture texture) { + mGLThread.surfaceCreated(); + } + + /** + * This method is part of the SurfaceHolder.Callback interface, and is + * not normally called or subclassed by clients of DUIXTextureView. + */ + public void surfaceDestroyed(SurfaceTexture texture) { + // Surface will be destroyed when we return + mGLThread.surfaceDestroyed(); + } + + /** + * This method is part of the SurfaceHolder.Callback interface, and is + * not normally called or subclassed by clients of DUIXTextureView. + */ + public void surfaceChanged(SurfaceTexture texture, int format, int w, int h) { + mGLThread.onWindowResize(w, h); + } + + /** + * Inform the view that the activity is paused. The owner of this view must + * call this method when the activity is paused. Calling this method will + * pause the rendering thread. + * Must not be called before a renderer has been set. + */ + public void onPause() { + mGLThread.onPause(); + } + + /** + * Inform the view that the activity is resumed. The owner of this view must + * call this method when the activity is resumed. Calling this method will + * recreate the OpenGL display and resume the rendering + * thread. + * Must not be called before a renderer has been set. + */ + public void onResume() { + mGLThread.onResume(); + } + + /** + * Queue a runnable to be run on the GL rendering thread. This can be used + * to communicate with the Renderer on the rendering thread. + * Must not be called before a renderer has been set. + * @param r the runnable to be run on the GL rendering thread. + */ + public void queueEvent(Runnable r) { + mGLThread.queueEvent(r); + } + + /** + * This method is used as part of the View class and is not normally + * called or subclassed by clients of DUIXTextureView. + */ + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (LOG_ATTACH_DETACH) { + Log.d(TAG, "onAttachedToWindow reattach =" + mDetached); + } + if (mDetached && (mRenderer != null)) { + int renderMode = RENDERMODE_CONTINUOUSLY; + if (mGLThread != null) { + renderMode = mGLThread.getRenderMode(); + } + mGLThread = new GLThread(mThisWeakRef); + if (renderMode != RENDERMODE_CONTINUOUSLY) { + mGLThread.setRenderMode(renderMode); + } + mGLThread.start(); + } + mDetached = false; + } + + /** + * This method is used as part of the View class and is not normally + * called or subclassed by clients of DUIXTextureView. + * Must not be called before a renderer has been set. + */ + @Override + protected void onDetachedFromWindow() { + if (LOG_ATTACH_DETACH) { + Log.d(TAG, "onDetachedFromWindow"); + } + if (mGLThread != null) { + mGLThread.requestExitAndWait(); + } + mDetached = true; + super.onDetachedFromWindow(); + } + + public void onLayoutChange(View v, int left, int top, int right, int bottom, + int oldLeft, int oldTop, int oldRight, int oldBottom) { + surfaceChanged(getSurfaceTexture(), 0, right - left, bottom - top); + } + + public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { + surfaceCreated(surface); + surfaceChanged(surface, 0, width, height); + } + + public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { + surfaceChanged(surface, 0, width, height); + } + + public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { + surfaceDestroyed(surface); + return true; + } + + public void onSurfaceTextureUpdated(SurfaceTexture surface) { +// requestRender(); + } + + // ---------------------------------------------------------------------- + + /** + * An interface used to wrap a GL interface. + *

Typically + * used for implementing debugging and tracing on top of the default + * GL interface. You would typically use this by creating your own class + * that implemented all the GL methods by delegating to another GL instance. + * Then you could add your own behavior before or after calling the + * delegate. All the GLWrapper would do was instantiate and return the + * wrapper GL instance: + *

+     * class MyGLWrapper implements GLWrapper {
+     *     GL wrap(GL gl) {
+     *         return new MyGLImplementation(gl);
+     *     }
+     *     static class MyGLImplementation implements GL,GL10,GL11,... {
+     *         ...
+     *     }
+     * }
+     * 
+ * @see #setGLWrapper(GLWrapper) + */ + public interface GLWrapper { + /** + * Wraps a gl interface in another gl interface. + * @param gl a GL interface that is to be wrapped. + * @return either the input argument or another GL object that wraps the input argument. + */ + GL wrap(GL gl); + } + + /** + * A generic renderer interface. + *

+ * The renderer is responsible for making OpenGL calls to render a frame. + *

+ * DUIXTextureView clients typically create their own classes that implement + * this interface, and then call {@link DUIXTextureView#setRenderer} to + * register the renderer with the DUIXTextureView. + *

+ * + *

+ *

Developer Guides

+ *

For more information about how to use OpenGL, read the + * OpenGL developer guide.

+ *
+ * + *

Threading

+ * The renderer will be called on a separate thread, so that rendering + * performance is decoupled from the UI thread. Clients typically need to + * communicate with the renderer from the UI thread, because that's where + * input events are received. Clients can communicate using any of the + * standard Java techniques for cross-thread communication, or they can + * use the {@link DUIXTextureView#queueEvent(Runnable)} convenience method. + *

+ *

EGL Context Lost

+ * There are situations where the EGL rendering context will be lost. This + * typically happens when device wakes up after going to sleep. When + * the EGL context is lost, all OpenGL resources (such as textures) that are + * associated with that context will be automatically deleted. In order to + * keep rendering correctly, a renderer must recreate any lost resources + * that it still needs. The {@link #onSurfaceCreated(GL10, EGLConfig)} method + * is a convenient place to do this. + * + * + * @see #setRenderer(Renderer) + */ + public interface Renderer { + /** + * Called when the surface is created or recreated. + *

+ * Called when the rendering thread + * starts and whenever the EGL context is lost. The EGL context will typically + * be lost when the Android device awakes after going to sleep. + *

+ * Since this method is called at the beginning of rendering, as well as + * every time the EGL context is lost, this method is a convenient place to put + * code to create resources that need to be created when the rendering + * starts, and that need to be recreated when the EGL context is lost. + * Textures are an example of a resource that you might want to create + * here. + *

+ * Note that when the EGL context is lost, all OpenGL resources associated + * with that context will be automatically deleted. You do not need to call + * the corresponding "glDelete" methods such as glDeleteTextures to + * manually delete these lost resources. + *

+ * @param gl the GL interface. Use instanceof to + * test if the interface supports GL11 or higher interfaces. + * @param config the EGLConfig of the created surface. Can be used + * to create matching pbuffers. + */ + void onSurfaceCreated(GL10 gl, EGLConfig config); + + /** + * Called when the surface changed size. + *

+ * Called after the surface is created and whenever + * the OpenGL ES surface size changes. + *

+ * Typically you will set your viewport here. If your camera + * is fixed then you could also set your projection matrix here: + *

+         * void onSurfaceChanged(GL10 gl, int width, int height) {
+         *     gl.glViewport(0, 0, width, height);
+         *     // for a fixed camera, set the projection too
+         *     float ratio = (float) width / height;
+         *     gl.glMatrixMode(GL10.GL_PROJECTION);
+         *     gl.glLoadIdentity();
+         *     gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
+         * }
+         * 
+ * @param gl the GL interface. Use instanceof to + * test if the interface supports GL11 or higher interfaces. + * @param width + * @param height + */ + void onSurfaceChanged(GL10 gl, int width, int height); + + /** + * Called to draw the current frame. + *

+ * This method is responsible for drawing the current frame. + *

+ * The implementation of this method typically looks like this: + *

+         * void onDrawFrame(GL10 gl) {
+         *     gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
+         *     //... other gl calls to render the scene ...
+         * }
+         * 
+ * @param gl the GL interface. Use instanceof to + * test if the interface supports GL11 or higher interfaces. + */ + void onDrawFrame(GL10 gl); + + void onSurfaceDestroyed(GL10 gl); + } + + /** + * An interface for customizing the eglCreateContext and eglDestroyContext calls. + *

+ * This interface must be implemented by clients wishing to call + * {@link DUIXTextureView#setEGLContextFactory(EGLContextFactory)} + */ + public interface EGLContextFactory { + EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig); + void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context); + } + + private class DefaultContextFactory implements EGLContextFactory { + private int EGL_CONTEXT_CLIENT_VERSION = 0x3098; + + public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) { + int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, mEGLContextClientVersion, + EGL10.EGL_NONE }; + + return egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, + mEGLContextClientVersion != 0 ? attrib_list : null); + } + + public void destroyContext(EGL10 egl, EGLDisplay display, + EGLContext context) { + if (!egl.eglDestroyContext(display, context)) { + Log.e("DefaultContextFactory", "display:" + display + " context: " + context); + if (LOG_THREADS) { + Log.i("DefaultContextFactory", "tid=" + Thread.currentThread().getId()); + } + EglHelper.throwEglException("eglDestroyContex", egl.eglGetError()); + } + } + } + + /** + * An interface for customizing the eglCreateWindowSurface and eglDestroySurface calls. + *

+ * This interface must be implemented by clients wishing to call + * {@link DUIXTextureView#setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory)} + */ + public interface EGLWindowSurfaceFactory { + /** + * @return null if the surface cannot be constructed. + */ + EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config, + Object nativeWindow); + void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface); + } + + private static class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory { + + public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, + EGLConfig config, Object nativeWindow) { + EGLSurface result = null; + try { + result = egl.eglCreateWindowSurface(display, config, nativeWindow, null); + } catch (IllegalArgumentException e) { + // This exception indicates that the surface flinger surface + // is not valid. This can happen if the surface flinger surface has + // been torn down, but the application has not yet been + // notified via SurfaceHolder.Callback.surfaceDestroyed. + // In theory the application should be notified first, + // but in practice sometimes it is not. See b/4588890 + Log.e(TAG, "eglCreateWindowSurface", e); + } + return result; + } + + public void destroySurface(EGL10 egl, EGLDisplay display, + EGLSurface surface) { + egl.eglDestroySurface(display, surface); + } + } + + /** + * An interface for choosing an EGLConfig configuration from a list of + * potential configurations. + *

+ * This interface must be implemented by clients wishing to call + * {@link DUIXTextureView#setEGLConfigChooser(EGLConfigChooser)} + */ + public interface EGLConfigChooser { + /** + * Choose a configuration from the list. Implementors typically + * implement this method by calling + * {@link EGL10#eglChooseConfig} and iterating through the results. Please consult the + * EGL specification available from The Khronos Group to learn how to call eglChooseConfig. + * @param egl the EGL10 for the current display. + * @param display the current display. + * @return the chosen configuration. + */ + EGLConfig chooseConfig(EGL10 egl, EGLDisplay display); + } + + private abstract class BaseConfigChooser + implements EGLConfigChooser { + public BaseConfigChooser(int[] configSpec) { + mConfigSpec = filterConfigSpec(configSpec); + } + + public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { + int[] num_config = new int[1]; + if (!egl.eglChooseConfig(display, mConfigSpec, null, 0, + num_config)) { +// sendMonitor(false, Log.getStackTraceString(new IllegalArgumentException("eglChooseConfig failed"))); + throw new IllegalArgumentException("eglChooseConfig failed"); + } + + int numConfigs = num_config[0]; + + if (numConfigs <= 0) { + throw new IllegalArgumentException( + "No configs match configSpec"); + } + + EGLConfig[] configs = new EGLConfig[numConfigs]; + if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, + num_config)) { + throw new IllegalArgumentException("eglChooseConfig#2 failed"); + } + EGLConfig config = chooseConfig(egl, display, configs); + if (config == null) { + throw new IllegalArgumentException("No config chosen"); + } + return config; + } + + abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, + EGLConfig[] configs); + + protected int[] mConfigSpec; + + private int[] filterConfigSpec(int[] configSpec) { + if (mEGLContextClientVersion != 2) { + return configSpec; + } + /* We know none of the subclasses define EGL_RENDERABLE_TYPE. + * And we know the configSpec is well formed. + */ + int len = configSpec.length; + int[] newConfigSpec = new int[len + 2]; + System.arraycopy(configSpec, 0, newConfigSpec, 0, len-1); + newConfigSpec[len-1] = EGL10.EGL_RENDERABLE_TYPE; + newConfigSpec[len] = 4; /* EGL_OPENGL_ES2_BIT */ + newConfigSpec[len+1] = EGL10.EGL_NONE; + return newConfigSpec; + } + } + + /** + * Choose a configuration with exactly the specified r,g,b,a sizes, + * and at least the specified depth and stencil sizes. + */ + private class ComponentSizeChooser extends BaseConfigChooser { + public ComponentSizeChooser(int redSize, int greenSize, int blueSize, + int alphaSize, int depthSize, int stencilSize) { + super(new int[] { + EGL10.EGL_RED_SIZE, redSize, + EGL10.EGL_GREEN_SIZE, greenSize, + EGL10.EGL_BLUE_SIZE, blueSize, + EGL10.EGL_ALPHA_SIZE, alphaSize, + EGL10.EGL_DEPTH_SIZE, depthSize, + EGL10.EGL_STENCIL_SIZE, stencilSize, + EGL10.EGL_NONE}); + mValue = new int[1]; + mRedSize = redSize; + mGreenSize = greenSize; + mBlueSize = blueSize; + mAlphaSize = alphaSize; + mDepthSize = depthSize; + mStencilSize = stencilSize; + } + + @Override + public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, + EGLConfig[] configs) { + for (EGLConfig config : configs) { + int d = findConfigAttrib(egl, display, config, + EGL10.EGL_DEPTH_SIZE, 0); + int s = findConfigAttrib(egl, display, config, + EGL10.EGL_STENCIL_SIZE, 0); + if ((d >= mDepthSize) && (s >= mStencilSize)) { + int r = findConfigAttrib(egl, display, config, + EGL10.EGL_RED_SIZE, 0); + int g = findConfigAttrib(egl, display, config, + EGL10.EGL_GREEN_SIZE, 0); + int b = findConfigAttrib(egl, display, config, + EGL10.EGL_BLUE_SIZE, 0); + int a = findConfigAttrib(egl, display, config, + EGL10.EGL_ALPHA_SIZE, 0); + if ((r == mRedSize) && (g == mGreenSize) + && (b == mBlueSize) && (a == mAlphaSize)) { + return config; + } + } + } + return null; + } + + private int findConfigAttrib(EGL10 egl, EGLDisplay display, + EGLConfig config, int attribute, int defaultValue) { + + if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { + return mValue[0]; + } + return defaultValue; + } + + private int[] mValue; + // Subclasses can adjust these values: + protected int mRedSize; + protected int mGreenSize; + protected int mBlueSize; + protected int mAlphaSize; + protected int mDepthSize; + protected int mStencilSize; + } + + /** + * This class will choose a RGB_888 surface with + * or without a depth buffer. + * + */ + private class SimpleEGLConfigChooser extends ComponentSizeChooser { + public SimpleEGLConfigChooser(boolean withDepthBuffer) { + super(8, 8, 8, 0, withDepthBuffer ? 16 : 0, 0); + } + } + + /** + * An EGL helper class. + */ + + private static class EglHelper { + public EglHelper(WeakReference glSurfaceViewWeakRef) { + mGLSurfaceViewWeakRef = glSurfaceViewWeakRef; + } + + /** + * Initialize EGL for a given configuration spec. + * @param + */ + public void start() { + if (LOG_EGL) { + Log.w("EglHelper", "start() tid=" + Thread.currentThread().getId()); + } + /* + * Get an EGL instance + */ + mEgl = (EGL10) EGLContext.getEGL(); + + /* + * Get to the default display. + */ + mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + + if (mEglDisplay == EGL10.EGL_NO_DISPLAY) { + throw new RuntimeException("eglGetDisplay failed"); + } + + /* + * We can now initialize EGL for that display + */ + int[] version = new int[2]; + if(!mEgl.eglInitialize(mEglDisplay, version)) { + throw new RuntimeException("eglInitialize failed"); + } + DUIXTextureView view = mGLSurfaceViewWeakRef.get(); + if (view == null) { + mEglConfig = null; + mEglContext = null; + } else { + mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay); + + /* + * Create an EGL context. We want to do this as rarely as we can, because an + * EGL context is a somewhat heavy object. + */ + mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig); + } + if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) { + mEglContext = null; + throwEglException("createContext"); + } + if (LOG_EGL) { + Log.w("EglHelper", "createContext " + mEglContext + " tid=" + Thread.currentThread().getId()); + } + + mEglSurface = null; + } + + /** + * Create an egl surface for the current SurfaceHolder surface. If a surface + * already exists, destroy it before creating the new surface. + * + * @return true if the surface was created successfully. + */ + public boolean createSurface() { + if (LOG_EGL) { + Log.w("EglHelper", "createSurface() tid=" + Thread.currentThread().getId()); + } + /* + * Check preconditions. + */ + if (mEgl == null) { + throw new RuntimeException("egl not initialized"); + } + if (mEglDisplay == null) { + throw new RuntimeException("eglDisplay not initialized"); + } + if (mEglConfig == null) { + throw new RuntimeException("mEglConfig not initialized"); + } + + /* + * The window size has changed, so we need to create a new + * surface. + */ + destroySurfaceImp(); + + /* + * Create an EGL surface we can render into. + */ + DUIXTextureView view = mGLSurfaceViewWeakRef.get(); + if (view != null) { + mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl, + mEglDisplay, mEglConfig, view.getSurfaceTexture()); + } else { + mEglSurface = null; + } + + if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) { + int error = mEgl.eglGetError(); + if (error == EGL10.EGL_BAD_NATIVE_WINDOW) { + Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); + } + return false; + } + + /* + * Before we can issue GL commands, we need to make sure + * the context is current and bound to a surface. + */ + if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { + /* + * Could not make the context current, probably because the underlying + * SurfaceView surface has been destroyed. + */ + logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError()); + return false; + } + + return true; + } + + /** + * Create a GL object for the current EGL context. + * @return + */ + GL createGL() { + + GL gl = mEglContext.getGL(); + DUIXTextureView view = mGLSurfaceViewWeakRef.get(); + if (view != null) { + if (view.mGLWrapper != null) { + gl = view.mGLWrapper.wrap(gl); + } + + if ((view.mDebugFlags & (DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS)) != 0) { + int configFlags = 0; + Writer log = null; + if ((view.mDebugFlags & DEBUG_CHECK_GL_ERROR) != 0) { + configFlags |= GLDebugHelper.CONFIG_CHECK_GL_ERROR; + } + if ((view.mDebugFlags & DEBUG_LOG_GL_CALLS) != 0) { + log = new LogWriter(); + } + gl = GLDebugHelper.wrap(gl, configFlags, log); + } + } + return gl; + } + + /** + * Display the current render surface. + * @return the EGL error code from eglSwapBuffers. + */ + public int swap() { + if (! mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) { + return mEgl.eglGetError(); + } + return EGL10.EGL_SUCCESS; + } + + public void destroySurface() { + if (LOG_EGL) { + Log.w("EglHelper", "destroySurface() tid=" + Thread.currentThread().getId()); + } + destroySurfaceImp(); + } + + private void destroySurfaceImp() { + if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) { + mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, + EGL10.EGL_NO_SURFACE, + EGL10.EGL_NO_CONTEXT); + DUIXTextureView view = mGLSurfaceViewWeakRef.get(); + if (view != null) { + view.mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface); + } + mEglSurface = null; + } + } + + public void finish() { + if (LOG_EGL) { + Log.w("EglHelper", "finish() tid=" + Thread.currentThread().getId()); + } + if (mEglContext != null) { + DUIXTextureView view = mGLSurfaceViewWeakRef.get(); + if (view != null) { + view.mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext); + } + mEglContext = null; + } + if (mEglDisplay != null) { + mEgl.eglTerminate(mEglDisplay); + mEglDisplay = null; + } + } + + private void throwEglException(String function) { + throwEglException(function, mEgl.eglGetError()); + } + + public static void throwEglException(String function, int error) { + String message = formatEglError(function, error); + if (LOG_THREADS) { + Log.e("EglHelper", "throwEglException tid=" + Thread.currentThread().getId() + " " + + message); + } +// throw new RuntimeException(message); + } + + public static void logEglErrorAsWarning(String tag, String function, int error) { + Log.w(tag, formatEglError(function, error)); + } + + public static String formatEglError(String function, int error) { + return function + " failed: " + error; + } + + private WeakReference mGLSurfaceViewWeakRef; + EGL10 mEgl; + EGLDisplay mEglDisplay; + EGLSurface mEglSurface; + EGLConfig mEglConfig; + EGLContext mEglContext; + + } + + /** + * A generic GL Thread. Takes care of initializing EGL and GL. Delegates + * to a Renderer instance to do the actual drawing. Can be configured to + * render continuously or on request. + * + * All potentially blocking synchronization is done through the + * sGLThreadManager object. This avoids multiple-lock ordering issues. + * + */ + static class GLThread extends Thread { + GLThread(WeakReference glSurfaceViewWeakRef) { + super(); + mWidth = 0; + mHeight = 0; + mRequestRender = true; + mRenderMode = RENDERMODE_CONTINUOUSLY; + mGLSurfaceViewWeakRef = glSurfaceViewWeakRef; + } + + @Override + public void run() { + setName("GLThread " + getId()); + if (LOG_THREADS) { + Log.i("GLThread", "starting tid=" + getId()); + } + + try { + guardedRun(); + } catch (InterruptedException e) { + // fall thru and exit normally + } finally { + sGLThreadManager.threadExiting(this); + } + } + + /* + * This private method should only be called inside a + * synchronized(sGLThreadManager) block. + */ + private void stopEglSurfaceLocked() { + if (mHaveEglSurface) { + mHaveEglSurface = false; + mEglHelper.destroySurface(); + } + } + + /* + * This private method should only be called inside a + * synchronized(sGLThreadManager) block. + */ + private void stopEglContextLocked() { + if (mHaveEglContext) { + mEglHelper.finish(); + mHaveEglContext = false; + sGLThreadManager.releaseEglContextLocked(this); + } + } + private void guardedRun() throws InterruptedException { + mEglHelper = new EglHelper(mGLSurfaceViewWeakRef); + mHaveEglContext = false; + mHaveEglSurface = false; + try { + GL10 gl = null; + boolean createEglContext = false; + boolean createEglSurface = false; + boolean createGlInterface = false; + boolean lostEglContext = false; + boolean sizeChanged = false; + boolean wantRenderNotification = false; + boolean doRenderNotification = false; + boolean askedToReleaseEglContext = false; + int w = 0; + int h = 0; + Runnable event = null; + + while (true) { + synchronized (sGLThreadManager) { + while (true) { + if (mShouldExit) { + return; + } + + if (! mEventQueue.isEmpty()) { + event = mEventQueue.remove(0); + break; + } + + // Update the pause state. + boolean pausing = false; + if (mPaused != mRequestPaused) { + pausing = mRequestPaused; + mPaused = mRequestPaused; + sGLThreadManager.notifyAll(); + if (LOG_PAUSE_RESUME) { + Log.i("GLThread", "mPaused is now " + mPaused + " tid=" + getId()); + } + } + + // Do we need to give up the EGL context? + if (mShouldReleaseEglContext) { + if (LOG_SURFACE) { + Log.i("GLThread", "releasing EGL context because asked to tid=" + getId()); + } + stopEglSurfaceLocked(); + stopEglContextLocked(); + mShouldReleaseEglContext = false; + askedToReleaseEglContext = true; + } + + // Have we lost the EGL context? + if (lostEglContext) { + stopEglSurfaceLocked(); + stopEglContextLocked(); + lostEglContext = false; + } + + // When pausing, release the EGL surface: + if (pausing && mHaveEglSurface) { + if (LOG_SURFACE) { + Log.i("GLThread", "releasing EGL surface because paused tid=" + getId()); + } + stopEglSurfaceLocked(); + } + + // When pausing, optionally release the EGL Context: + if (pausing && mHaveEglContext) { + DUIXTextureView view = mGLSurfaceViewWeakRef.get(); + boolean preserveEglContextOnPause = view == null ? + false : view.mPreserveEGLContextOnPause; + if (!preserveEglContextOnPause || sGLThreadManager.shouldReleaseEGLContextWhenPausing()) { + stopEglContextLocked(); + if (LOG_SURFACE) { + Log.i("GLThread", "releasing EGL context because paused tid=" + getId()); + } + } + } + + // When pausing, optionally terminate EGL: + if (pausing) { + if (sGLThreadManager.shouldTerminateEGLWhenPausing()) { + mEglHelper.finish(); + if (LOG_SURFACE) { + Log.i("GLThread", "terminating EGL because paused tid=" + getId()); + } + } + } + + // Have we lost the SurfaceView surface? + if ((! mHasSurface) && (! mWaitingForSurface)) { + if (LOG_SURFACE) { + Log.i("GLThread", "noticed surfaceView surface lost tid=" + getId()); + } + if (mHaveEglSurface) { + stopEglSurfaceLocked(); + } + mWaitingForSurface = true; + mSurfaceIsBad = false; + sGLThreadManager.notifyAll(); + } + + // Have we acquired the surface view surface? + if (mHasSurface && mWaitingForSurface) { + if (LOG_SURFACE) { + Log.i("GLThread", "noticed surfaceView surface acquired tid=" + getId()); + } + mWaitingForSurface = false; + sGLThreadManager.notifyAll(); + } + + if (doRenderNotification) { + if (LOG_SURFACE) { + Log.i("GLThread", "sending render notification tid=" + getId()); + } + wantRenderNotification = false; + doRenderNotification = false; + mRenderComplete = true; + sGLThreadManager.notifyAll(); + } + + // Ready to draw? + if (readyToDraw()) { + + // If we don't have an EGL context, try to acquire one. + if (! mHaveEglContext) { + if (askedToReleaseEglContext) { + askedToReleaseEglContext = false; + } else if (sGLThreadManager.tryAcquireEglContextLocked(this)) { + try { + mEglHelper.start(); + } catch (RuntimeException t) { + sGLThreadManager.releaseEglContextLocked(this); + throw t; + } + mHaveEglContext = true; + createEglContext = true; + + sGLThreadManager.notifyAll(); + } + } + + if (mHaveEglContext && !mHaveEglSurface) { + mHaveEglSurface = true; + createEglSurface = true; + createGlInterface = true; + sizeChanged = true; + } + + if (mHaveEglSurface) { + if (mSizeChanged) { + sizeChanged = true; + w = mWidth; + h = mHeight; + wantRenderNotification = true; + if (LOG_SURFACE) { + Log.i("GLThread", + "noticing that we want render notification tid=" + + getId()); + } + + // Destroy and recreate the EGL surface. + createEglSurface = true; + + mSizeChanged = false; + } + mRequestRender = false; + sGLThreadManager.notifyAll(); + break; + } + } + + // By design, this is the only place in a GLThread thread where we wait(). + if (LOG_THREADS) { + Log.i("GLThread", "waiting tid=" + getId() + + " mHaveEglContext: " + mHaveEglContext + + " mHaveEglSurface: " + mHaveEglSurface + + " mPaused: " + mPaused + + " mHasSurface: " + mHasSurface + + " mSurfaceIsBad: " + mSurfaceIsBad + + " mWaitingForSurface: " + mWaitingForSurface + + " mWidth: " + mWidth + + " mHeight: " + mHeight + + " mRequestRender: " + mRequestRender + + " mRenderMode: " + mRenderMode); + } + sGLThreadManager.wait(); + } + } // end of synchronized(sGLThreadManager) + + if (event != null) { + event.run(); + event = null; + continue; + } + + if (createEglSurface) { + if (LOG_SURFACE) { + Log.w("GLThread", "egl createSurface"); + } + if (!mEglHelper.createSurface()) { + synchronized(sGLThreadManager) { + mSurfaceIsBad = true; + sGLThreadManager.notifyAll(); + } + continue; + } + createEglSurface = false; + } + + if (createGlInterface) { + gl = (GL10) mEglHelper.createGL(); + + sGLThreadManager.checkGLDriver(gl); + createGlInterface = false; + } + + if (createEglContext) { + if (LOG_RENDERER) { + Log.w("GLThread", "onSurfaceCreated"); + } + DUIXTextureView view = mGLSurfaceViewWeakRef.get(); + if (view != null) { + view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig); + } + createEglContext = false; + } + + if (sizeChanged) { + if (LOG_RENDERER) { + Log.w("GLThread", "onSurfaceChanged(" + w + ", " + h + ")"); + } + DUIXTextureView view = mGLSurfaceViewWeakRef.get(); + if (view != null) { + view.mRenderer.onSurfaceChanged(gl, w, h); + } + sizeChanged = false; + } + + if (LOG_RENDERER_DRAW_FRAME) { + Log.w("GLThread", "onDrawFrame tid=" + getId()); + } + { + DUIXTextureView view = mGLSurfaceViewWeakRef.get(); + if (view != null) { + view.mRenderer.onDrawFrame(gl); + } + } + int swapError = mEglHelper.swap(); + switch (swapError) { + case EGL10.EGL_SUCCESS: + break; + case EGL11.EGL_CONTEXT_LOST: + if (LOG_SURFACE) { + Log.i("GLThread", "egl context lost tid=" + getId()); + } + lostEglContext = true; + break; + default: + // Other errors typically mean that the current surface is bad, + // probably because the SurfaceView surface has been destroyed, + // but we haven't been notified yet. + // Log the error to help developers understand why rendering stopped. + EglHelper.logEglErrorAsWarning("GLThread", "eglSwapBuffers", swapError); + + synchronized(sGLThreadManager) { + mSurfaceIsBad = true; + sGLThreadManager.notifyAll(); + } + break; + } + + if (wantRenderNotification) { + doRenderNotification = true; + } + } + + } finally { + /* + * clean-up everything... + */ + synchronized (sGLThreadManager) { + stopEglSurfaceLocked(); + stopEglContextLocked(); + } + } + } + + public boolean ableToDraw() { + return mHaveEglContext && mHaveEglSurface && readyToDraw(); + } + + private boolean readyToDraw() { + return (!mPaused) && mHasSurface && (!mSurfaceIsBad) + && (mWidth > 0) && (mHeight > 0) + && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY)); + } + + public void setRenderMode(int renderMode) { + if ( !((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTINUOUSLY)) ) { + throw new IllegalArgumentException("renderMode"); + } + synchronized(sGLThreadManager) { + mRenderMode = renderMode; + sGLThreadManager.notifyAll(); + } + } + + public int getRenderMode() { + synchronized(sGLThreadManager) { + return mRenderMode; + } + } + + public void requestRender() { + synchronized(sGLThreadManager) { + mRequestRender = true; + sGLThreadManager.notifyAll(); + } + } + + public void surfaceCreated() { + synchronized(sGLThreadManager) { + if (LOG_THREADS) { + Log.i("GLThread", "surfaceCreated tid=" + getId()); + } + mHasSurface = true; + sGLThreadManager.notifyAll(); + while((mWaitingForSurface) && (!mExited)) { + try { + sGLThreadManager.wait(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + } + + public void surfaceDestroyed() { + synchronized(sGLThreadManager) { + if (LOG_THREADS) { + Log.i("GLThread", "surfaceDestroyed tid=" + getId()); + } + mHasSurface = false; + sGLThreadManager.notifyAll(); + while((!mWaitingForSurface) && (!mExited)) { + try { + sGLThreadManager.wait(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + } + + public void onPause() { + synchronized (sGLThreadManager) { + if (LOG_PAUSE_RESUME) { + Log.i("GLThread", "onPause tid=" + getId()); + } + mRequestPaused = true; + sGLThreadManager.notifyAll(); + while ((! mExited) && (! mPaused)) { + if (LOG_PAUSE_RESUME) { + Log.i("Main thread", "onPause waiting for mPaused."); + } + try { + sGLThreadManager.wait(); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + } + } + + public void onResume() { + synchronized (sGLThreadManager) { + if (LOG_PAUSE_RESUME) { + Log.i("GLThread", "onResume tid=" + getId()); + } + mRequestPaused = false; + mRequestRender = true; + mRenderComplete = false; + sGLThreadManager.notifyAll(); + while ((! mExited) && mPaused && (!mRenderComplete)) { + if (LOG_PAUSE_RESUME) { + Log.i("Main thread", "onResume waiting for !mPaused."); + } + try { + sGLThreadManager.wait(); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + } + } + + public void onWindowResize(int w, int h) { + synchronized (sGLThreadManager) { + mWidth = w; + mHeight = h; + mSizeChanged = true; + mRequestRender = true; + mRenderComplete = false; + sGLThreadManager.notifyAll(); + + // Wait for thread to react to resize and render a frame + while (! mExited && !mPaused && !mRenderComplete + && ableToDraw()) { + if (LOG_SURFACE) { + Log.i("Main thread", "onWindowResize waiting for render complete from tid=" + getId()); + } + try { + sGLThreadManager.wait(); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + } + } + + public void requestExitAndWait() { + // don't call this from GLThread thread or it is a guaranteed + // deadlock! + synchronized(sGLThreadManager) { + mShouldExit = true; + sGLThreadManager.notifyAll(); + while (! mExited) { + try { + sGLThreadManager.wait(); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + } + } + + public void requestReleaseEglContextLocked() { + mShouldReleaseEglContext = true; + sGLThreadManager.notifyAll(); + } + + /** + * Queue an "event" to be run on the GL rendering thread. + * @param r the runnable to be run on the GL rendering thread. + */ + public void queueEvent(Runnable r) { + if (r == null) { + throw new IllegalArgumentException("r must not be null"); + } + synchronized(sGLThreadManager) { + mEventQueue.add(r); + sGLThreadManager.notifyAll(); + } + } + + // Once the thread is started, all accesses to the following member + // variables are protected by the sGLThreadManager monitor + private boolean mShouldExit; + private boolean mExited; + private boolean mRequestPaused; + private boolean mPaused; + private boolean mHasSurface; + private boolean mSurfaceIsBad; + private boolean mWaitingForSurface; + private boolean mHaveEglContext; + private boolean mHaveEglSurface; + private boolean mShouldReleaseEglContext; + private int mWidth; + private int mHeight; + private int mRenderMode; + private boolean mRequestRender; + private boolean mRenderComplete; + private ArrayList mEventQueue = new ArrayList(); + private boolean mSizeChanged = true; + + // End of member variables protected by the sGLThreadManager monitor. + + private EglHelper mEglHelper; + + /** + * Set once at thread construction time, nulled out when the parent view is garbage + * called. This weak reference allows the DUIXTextureView to be garbage collected while + * the GLThread is still alive. + */ + private WeakReference mGLSurfaceViewWeakRef; + + } + + static class LogWriter extends Writer { + + @Override + public void close() { + flushBuilder(); + } + + @Override + public void flush() { + flushBuilder(); + } + + @Override + public void write(char[] buf, int offset, int count) { + for(int i = 0; i < count; i++) { + char c = buf[offset + i]; + if ( c == '\n') { + flushBuilder(); + } + else { + mBuilder.append(c); + } + } + } + + private void flushBuilder() { + if (mBuilder.length() > 0) { + Log.v("DUIXTextureView", mBuilder.toString()); + mBuilder.delete(0, mBuilder.length()); + } + } + + private StringBuilder mBuilder = new StringBuilder(); + } + + + private void checkRenderThreadState() { + if (mGLThread != null) { + throw new IllegalStateException( + "setRenderer has already been called for this instance."); + } + } + + private static class GLThreadManager { + private static String TAG = "GLThreadManager"; + + public synchronized void threadExiting(GLThread thread) { + if (LOG_THREADS) { + Log.i("GLThread", "exiting tid=" + thread.getId()); + } + thread.mExited = true; + if (mEglOwner == thread) { + mEglOwner = null; + } + notifyAll(); + } + + /* + * Tries once to acquire the right to use an EGL + * context. Does not block. Requires that we are already + * in the sGLThreadManager monitor when this is called. + * + * @return true if the right to use an EGL context was acquired. + */ + public boolean tryAcquireEglContextLocked(GLThread thread) { + if (mEglOwner == thread || mEglOwner == null) { + mEglOwner = thread; + notifyAll(); + return true; + } + checkGLESVersion(); + if (mMultipleGLESContextsAllowed) { + return true; + } + // Notify the owning thread that it should release the context. + // TODO: implement a fairness policy. Currently + // if the owning thread is drawing continuously it will just + // reacquire the EGL context. + if (mEglOwner != null) { + mEglOwner.requestReleaseEglContextLocked(); + } + return false; + } + + /* + * Releases the EGL context. Requires that we are already in the + * sGLThreadManager monitor when this is called. + */ + public void releaseEglContextLocked(GLThread thread) { + if (mEglOwner == thread) { + mEglOwner = null; + } + notifyAll(); + } + + public synchronized boolean shouldReleaseEGLContextWhenPausing() { + // Release the EGL context when pausing even if + // the hardware supports multiple EGL contexts. + // Otherwise the device could run out of EGL contexts. + return mLimitedGLESContexts; + } + + public synchronized boolean shouldTerminateEGLWhenPausing() { + checkGLESVersion(); + return !mMultipleGLESContextsAllowed; + } + + public synchronized void checkGLDriver(GL10 gl) { + if (! mGLESDriverCheckComplete) { + checkGLESVersion(); + String renderer = gl.glGetString(GL10.GL_RENDERER); + if (mGLESVersion < kGLES_20) { + mMultipleGLESContextsAllowed = + ! renderer.startsWith(kMSM7K_RENDERER_PREFIX); + notifyAll(); + } + mLimitedGLESContexts = !mMultipleGLESContextsAllowed; + if (LOG_SURFACE) { + Log.w(TAG, "checkGLDriver renderer = \"" + renderer + "\" multipleContextsAllowed = " + + mMultipleGLESContextsAllowed + + " mLimitedGLESContexts = " + mLimitedGLESContexts); + } + mGLESDriverCheckComplete = true; + } + } + + private void checkGLESVersion() { + if (! mGLESVersionCheckComplete) { +// mGLESVersion = SystemProperties.getInt( +// "ro.opengles.version", +// ConfigurationInfo.GL_ES_VERSION_UNDEFINED); +// if (mGLESVersion >= kGLES_20) { +// mMultipleGLESContextsAllowed = true; +// } +// if (LOG_SURFACE) { +// Log.w(TAG, "checkGLESVersion mGLESVersion =" + +// " " + mGLESVersion + " mMultipleGLESContextsAllowed = " + mMultipleGLESContextsAllowed); +// } + mGLESVersionCheckComplete = true; + } + } + + /** + * This check was required for some pre-Android-3.0 hardware. Android 3.0 provides + * support for hardware-accelerated views, therefore multiple EGL contexts are + * supported on all Android 3.0+ EGL drivers. + */ + private boolean mGLESVersionCheckComplete; + private int mGLESVersion; + private boolean mGLESDriverCheckComplete; + private boolean mMultipleGLESContextsAllowed; + private boolean mLimitedGLESContexts; + private static final int kGLES_20 = 0x20000; + private static final String kMSM7K_RENDERER_PREFIX = + "Q3Dimension MSM7500 "; + private GLThread mEglOwner; + } + + private static final GLThreadManager sGLThreadManager = new GLThreadManager(); + + private final WeakReference mThisWeakRef = + new WeakReference(this); + private GLThread mGLThread; + private Renderer mRenderer; + private boolean mDetached; + private EGLConfigChooser mEGLConfigChooser; + private EGLContextFactory mEGLContextFactory; + private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory; + private GLWrapper mGLWrapper; + private int mDebugFlags; + private int mEGLContextClientVersion; + private boolean mPreserveEGLContextOnPause; +} \ No newline at end of file diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/render/ImageDrawer.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/render/ImageDrawer.java new file mode 100644 index 0000000..7f30900 --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/render/ImageDrawer.java @@ -0,0 +1,176 @@ +package ai.guiji.duix.sdk.client.render; + +import android.opengl.GLES20; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; + +import ai.guiji.duix.sdk.client.bean.ImageFrame; +import ai.guiji.duix.sdk.client.util.OpenGLUtil; + + +public class ImageDrawer { + + protected int mImageTexId; + + protected int mMaskTexId; + + private final String vertexShaderCode = + "uniform mat4 uMVPMatrix;\n" + + "attribute vec4 inputTextureCoordinate;\n" + + " varying vec2 textureCoordinate;\n" + + "attribute vec4 vPosition;\n" + + "void main() {\n" + + " gl_Position = uMVPMatrix * vPosition;\n" + + " textureCoordinate = inputTextureCoordinate.xy;\n" + + "}\n"; + + private final String fragmentShaderCode = + "precision mediump float;\n" + + "varying vec2 textureCoordinate;\n" + + "uniform sampler2D inputImageTexture;\n" + + "uniform sampler2D inputImageTexture2;\n" + + "vec4 imageColor;\n" + + "vec4 maskColor;\n" + + "float alpha;\n" + + "void main() {\n" + + " imageColor = texture2D(inputImageTexture, textureCoordinate);\n" + + " maskColor = texture2D(inputImageTexture2, textureCoordinate);\n" + + " alpha = (maskColor.r + maskColor.g + maskColor.b) / 3.0;\n" + + " gl_FragColor = vec4(imageColor.b, imageColor.g, imageColor.r, alpha);\n" + + "}\n"; + + + //顶点坐标 + static float vertexData[] = { // in counterclockwise order: + -1f, -1f, 0.0f, // bottom left + 1f, -1f, 0.0f, // bottom right + -1f, 1f, 0.0f, // top left + 1f, 1f, 0.0f, // top right + }; + + private FloatBuffer vertexBuffer; // buffer holding the vertices + + // 绘制索引 + //纹理坐标 对应顶点坐标 与之映射 + static float textureData[] = { // in counterclockwise order: + 0f, 1f, 0.0f, // bottom left + 1f, 1f, 0.0f, // bottom right + 0f, 0f, 0.0f, // top left + 1f, 0f, 0.0f, // top right + }; + + private FloatBuffer textureBuffer; // buffer holding the texture coordinates + + //每一次取点的时候取几个点 + static final int COORDS_PER_VERTEX = 3; + + private final int vertexCount = vertexData.length / COORDS_PER_VERTEX; + + //每一次取的总的点 大小 + private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex + + private int mProgram; + + private int uMVPMatrixLoc; + private int maPositionLoc; + private int maTextureCoordLoc; + + private int inputImageTextureLoc; + + private int inputImageTexture2Loc; + + public ImageDrawer() { + mImageTexId = OpenGLUtil.createTextureObject(GLES20.GL_TEXTURE_2D); + mMaskTexId = OpenGLUtil.createTextureObject(GLES20.GL_TEXTURE_2D); + + ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertexData.length * 4); + byteBuffer.order(ByteOrder.nativeOrder()); + vertexBuffer = byteBuffer.asFloatBuffer(); + vertexBuffer.put(vertexData); + vertexBuffer.position(0); + + byteBuffer = ByteBuffer.allocateDirect(textureData.length * 4); + byteBuffer.order(ByteOrder.nativeOrder()); + textureBuffer = byteBuffer.asFloatBuffer(); + textureBuffer.put(textureData); + textureBuffer.position(0); + + mProgram = OpenGLUtil.createProgram(vertexShaderCode, fragmentShaderCode); + + if (mProgram > 0) { + // 正交投影 + uMVPMatrixLoc = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); + OpenGLUtil.checkLocation(uMVPMatrixLoc, "uMVPMatrix"); + + //获取顶点坐标字段 + maPositionLoc = GLES20.glGetAttribLocation(mProgram, "vPosition"); + OpenGLUtil.checkLocation(maPositionLoc, "vPosition"); + //获取纹理坐标字段 + maTextureCoordLoc = GLES20.glGetAttribLocation(mProgram, "inputTextureCoordinate"); + OpenGLUtil.checkLocation(maTextureCoordLoc, "inputTextureCoordinate"); + + inputImageTextureLoc = GLES20.glGetUniformLocation(mProgram, "inputImageTexture"); + OpenGLUtil.checkLocation(inputImageTextureLoc, "inputImageTexture"); + + inputImageTexture2Loc = GLES20.glGetUniformLocation(mProgram, "inputImageTexture2"); + OpenGLUtil.checkLocation(inputImageTexture2Loc, "inputImageTexture2"); + } + + } + + public void draw(ImageFrame imageFrame, float[] mvpMatrix) { + // 将程序添加到OpenGL ES环境 + GLES20.glUseProgram(mProgram); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mImageTexId); + GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1); // 设置1字节对齐 +// GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, imageFrame.bitmap, 0); + GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, imageFrame.width, imageFrame.height, 0, + GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, imageFrame.rawBuffer); + GLES20.glUniform1i(inputImageTextureLoc, 0); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE1); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mMaskTexId); +// GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, maskBitmap, 0); + GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, imageFrame.width, imageFrame.height, 0, + GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, imageFrame.maskBuffer); + GLES20.glUniform1i(inputImageTexture2Loc, 1); + + GLES20.glUniformMatrix4fv(uMVPMatrixLoc, 1, false, mvpMatrix, 0); + + GLES20.glEnableVertexAttribArray(maPositionLoc); + GLES20.glEnableVertexAttribArray(maTextureCoordLoc); + //设置顶点位置值 + GLES20.glVertexAttribPointer(maPositionLoc, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer); + //设置纹理位置值 + GLES20.glVertexAttribPointer(maTextureCoordLoc, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, textureBuffer); + //绘制 GLES20.GL_TRIANGLE_STRIP:复用坐标 + GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount); + + // 禁用顶点数组 + GLES20.glDisableVertexAttribArray(maPositionLoc); + GLES20.glDisableVertexAttribArray(maTextureCoordLoc); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); + GLES20.glUseProgram(0); + } + + public void release() { + if (mProgram > 0) { + GLES20.glDeleteProgram(mProgram); + mProgram = -1; + } + if (mImageTexId != 0) { + GLES20.glDeleteTextures(1, new int[]{mImageTexId}, 0); + mImageTexId = 0; + } + if (mMaskTexId != 0) { + GLES20.glDeleteTextures(1, new int[]{mMaskTexId}, 0); + mMaskTexId = 0; + } + + } + +} diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/render/RenderSink.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/render/RenderSink.java new file mode 100644 index 0000000..3070698 --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/render/RenderSink.java @@ -0,0 +1,12 @@ +package ai.guiji.duix.sdk.client.render; + +import ai.guiji.duix.sdk.client.bean.ImageFrame; + +/** + * 渲染管道,通过该接口返回渲染数据 + */ +public interface RenderSink { + + void onVideoFrame(ImageFrame imageFrame); + +} diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/render/TextureMatrix.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/render/TextureMatrix.java new file mode 100644 index 0000000..f06262d --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/render/TextureMatrix.java @@ -0,0 +1,161 @@ +package ai.guiji.duix.sdk.client.render; + +public class TextureMatrix { + + + public static final float[] DINGDING_TEXTURE_MATRIX = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 1.0f + }; + // private static final float[] TEXTURE_MATRIX = { +// 0.0f, -1.0f, 0.0f, 0.0f, +// 1.0f, 0.0f, 0.0f, 0.0f, +// 0.0f, 0.0f, 1.0f, 0.0f, +// 0.0f, 1.0f, 0.0f, 1.0f +// }; + //X 轴旋转 180 // 中心点需要在加一下// + public static final float[] TEXTURE_MATRIX = { + 0.0f, 1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + //Y 轴旋转 + /*public static final float[] TEXTURE_MATRIX = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + };*/ + + public static final float[] TEXTURE_MATRIX_0 = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + // X轴旋转 90度 + public static final float[] TEXTURE_MATRIX_90 = { + //X轴旋转 90度 +// 0.0f, 1.0f, 0.0f, 0.0f, +// 1.0f, 0.0f, 0.0f, 0.0f, +// 0.0f, 0.0f, 1.0f, 0.0f, +// 0.0f, 0.0f, 0.0f, 1.0f + +// 0.0f, -1.0f, 0.0f, 0.0f, +// 1.0f, 0.0f, 0.0f, 0.0f, +// 0.0f, 0.0f, 1.0f, 0.0f, +// 0.0f, 1.0f, 0.0f, 1.0f + //90度水平翻转 + 0.0f, -1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + + }; + public static final float[] TEXTURE_MATRIX_90_V = { + //X轴旋转 90度 + 0.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + +// 0.0f, -1.0f, 0.0f, 0.0f, +// 1.0f, 0.0f, 0.0f, 0.0f, +// 0.0f, 0.0f, 1.0f, 0.0f, +// 0.0f, 1.0f, 0.0f, 1.0f + //90度水平翻转 +// 0.0f, -1.0f, 0.0f, 0.0f, +// 1.0f, 0.0f, 0.0f, 0.0f, +// 0.0f, 0.0f, 1.0f, 0.0f, +// 0.0f, 0.0f, 0.0f, 1.0f + + }; + // X轴旋转 180度 + public static final float[] TEXTURE_MATRIX_180 = { + -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, -1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + +// -1.0f, 0.0f, 0.0f, 0.0f, +// 0.0f, 1.0f, 0.0f, 0.0f, +// 0.0f, 0.0f, -1.0f, 0.0f, +// 0.0f, 0.0f, 0.0f, 1.0f + +// 1.0f, 0.0f, 0.0f, 0.0f, +// 0.0f, -1.0f, 0.0f, 0.0f, +// 0.0f, 0.0f, 1.0f, 0.0f, +// 0.0f, 1.0f, 0.0f, 1.0f + + }; + // X轴旋转 270度 + public static final float[] TEXTURE_MATRIX_270 = { + 0.0f, 1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + + public static float[] getRotation(final int rotation, boolean flipHorizontal, + boolean flipVertical) { + float[] rotatedTex; + boolean temp; + switch (rotation) { + case 90: + rotatedTex = TEXTURE_MATRIX_90; + temp = flipHorizontal; + flipHorizontal = flipVertical; + flipVertical = temp; + break; + case 180: + rotatedTex = TEXTURE_MATRIX_180; + break; + case 270: + rotatedTex = TEXTURE_MATRIX_270; + temp = flipHorizontal; + flipHorizontal = flipVertical; + flipVertical = temp; + break; + case 0: + case 360: + default: + rotatedTex = TEXTURE_MATRIX_0; + break; + } + if (flipHorizontal) { + rotatedTex = new float[]{ + flip(rotatedTex[0]), rotatedTex[1], + flip(rotatedTex[2]), rotatedTex[3], + flip(rotatedTex[4]), rotatedTex[5], + flip(rotatedTex[6]), rotatedTex[7], + flip(rotatedTex[8]), rotatedTex[9], + flip(rotatedTex[10]), rotatedTex[11], + flip(rotatedTex[12]), rotatedTex[13], + flip(rotatedTex[14]), rotatedTex[15], + }; + } + if (flipVertical) { + rotatedTex = new float[]{ + rotatedTex[0], flip(rotatedTex[1]), + rotatedTex[2], flip(rotatedTex[3]), + rotatedTex[4], flip(rotatedTex[5]), + rotatedTex[6], flip(rotatedTex[7]), + rotatedTex[8], flip(rotatedTex[9]), + rotatedTex[10], flip(rotatedTex[11]), + rotatedTex[12], flip(rotatedTex[13]), + rotatedTex[14], flip(rotatedTex[15]), + }; + } + return rotatedTex; + } + + private static float flip(final float i) { + if (i == 0.0f) { + return 1.0f; + } + return 0.0f; + } +} diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/thread/RenderThread.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/thread/RenderThread.java new file mode 100644 index 0000000..acff7b1 --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/thread/RenderThread.java @@ -0,0 +1,460 @@ +package ai.guiji.duix.sdk.client.thread; + +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.text.TextUtils; + + +import java.io.File; +import java.lang.ref.WeakReference; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Random; +import java.util.concurrent.ConcurrentLinkedQueue; + +import ai.guiji.duix.DuixNcnn; +import ai.guiji.duix.sdk.client.audio.AudioPlayer; +import ai.guiji.duix.sdk.client.bean.ImageFrame; +import ai.guiji.duix.sdk.client.loader.ModelInfo; +import ai.guiji.duix.sdk.client.loader.ModelInfoLoader; +import ai.guiji.duix.sdk.client.render.RenderSink; +import ai.guiji.duix.sdk.client.util.Logger; + + +public class RenderThread extends Thread { + + private static final int MSG_RENDER_STEP = 1; // 请求下一帧渲染 + private static final int MSG_STOP_RENDER = 2; // 停止渲染 + private static final int MSG_QUIT = 3; // 退出线程 + private static final int MSG_STOP_PUSH_AUDIO = 5; // 停止音频推送 + private static final int MSG_STOP_PLAY_AUDIO = 6; // 停止音频播放 + + private static final int MSG_REQUIRE_MOTION = 7; // 请求播放一个指定动作区间 + private static final int MSG_REQUIRE_MOTION_RANDOM = 8; // 请求随机播放一个动作区间 + private static final int MSG_START_PUSH_AUDIO = 11; // 启动音频推送 + private static final int MSG_PUSH_AUDIO = 12; // 推送播放音频 + + + private volatile boolean isRendering = false; // 为false时终止线程 + RenderHandler mHandler; // 使用该处理器来调度线程的事件 + + private final Object mReadyFence = new Object(); // 给isReady加一个对象锁 + + private final Object mBnfFence = new Object(); // 给isReady加一个对象锁 + + private final Context mContext; + private DuixNcnn scrfdncnn; + + private final RenderCallback callback; + + private RenderSink mRenderSink; + + private ConcurrentLinkedQueue mPreviewQueue; // 播放帧 + + private boolean requireMotion = false; // 请求播放动作 + private ModelInfo.Region prepareActionRegion; // 准备在静默节点或动作节点播放完播放的动作区间 + + private ModelInfo mModelInfo; // 模型的全部信息都放在这里面 + private ByteBuffer rawBuffer; + private ByteBuffer maskBuffer; + private final File modelDir; + + private AudioPlayer audioPlayer; + private long mCurrentBnfSession = -1; + private long mLastBnfSession = -1; + + private float mVolume; + + private int scrfRst; + private boolean isLip = false; // 用于统计是否正在渲染口型 + + private Reporter mReporter; + + public RenderThread(Context context, File modelDir, RenderSink renderSink, float volume, RenderCallback callback, Reporter reporter) { + this.mContext = context; + this.modelDir = modelDir; + this.mRenderSink = renderSink; + this.callback = callback; + this.mReporter = reporter; + this.mVolume = volume; + } + + public void setReporter(Reporter reporter){ + this.mReporter = reporter; + } + + @Override + public void run() { + super.run(); + Looper.prepare(); + mHandler = new RenderHandler(this); + mPreviewQueue = new ConcurrentLinkedQueue<>(); + audioPlayer = new AudioPlayer(new AudioPlayer.AudioPlayerCallback() { + @Override + public void onPlayStart() { + callback.onPlayStart(); + } + + @Override + public void onPlayEnd() { + mCurrentBnfSession = -1; + callback.onPlayEnd(); + } + + @Override + public void onPlayError(int code, String message) { + callback.onPlayError(code, message); + } + }, mVolume); + + scrfdncnn = new DuixNcnn(); + String duixDir = mContext.getExternalFilesDir("duix").getAbsolutePath(); + ModelInfo info = ModelInfoLoader.load(mContext, scrfdncnn, duixDir + "/model/gj_dh_res", modelDir.getAbsolutePath()); + if (info != null) { + try { + scrfdncnn.alloc(0, 20, info.getWidth(), info.getHeight()); + scrfdncnn.initPcmex(0,10,20,50,0); + if (info.getModelkind() > 0){ + scrfdncnn.initMunetex(info.getUnetparam(), info.getUnetbin(), info .getUnetmsk(), info.getModelkind()); + } else { + scrfdncnn.initMunet(info.getUnetparam(), info.getUnetbin(), info.getUnetmsk()); + } + scrfdncnn.initWenet(info.getWenetfn()); + mModelInfo = info; + Logger.d("分辨率: " + mModelInfo.getWidth() + "x" + mModelInfo.getHeight()); + rawBuffer = ByteBuffer.allocate(mModelInfo.getWidth() * mModelInfo.getHeight() * 3); + maskBuffer = ByteBuffer.allocate(mModelInfo.getWidth() * mModelInfo.getHeight() * 3); + if (!mModelInfo.isHasMask()) { + // 用纯白填充mask + Arrays.fill(maskBuffer.array(), (byte) 255); + } + Logger.d("模型初始化完成"); + if (callback != null) { + callback.onInitResult(0, 0, mModelInfo.toString(), mModelInfo); + } + } catch (Exception e){ + if (callback != null) { + callback.onInitResult(-1002, -1001, "Model loading exception: " + e, null); + } + } + } else { + if (callback != null) { + callback.onInitResult(-1002, -1000, "Model configuration read exception", null); + } + } + + synchronized (mReadyFence) { + mReadyFence.notify(); + } + isRendering = true; + handleAudioStep(); + Looper.loop(); + synchronized (mBnfFence) { + // 线程最后释放NCNN + scrfdncnn.free(0); + } + Logger.d("NCNN释放"); + if (audioPlayer != null) { + audioPlayer.release(); + audioPlayer = null; + } + synchronized (mReadyFence) { + mHandler = null; + } + } + + public void setVolume(float volume){ + if (audioPlayer != null){ + audioPlayer.setVolume(volume); + } + } + + public void stopPreview() { + if (mHandler != null) { + mHandler.sendEmptyMessage(MSG_STOP_RENDER); + } + } + + public void startPush() { + if (mHandler != null) { + mHandler.sendEmptyMessage(MSG_START_PUSH_AUDIO); + } + } + + public void pushAudio(byte[] data){ + if (mHandler != null) { + Message message = new Message(); + message.what = MSG_PUSH_AUDIO; + message.obj = data; + mHandler.sendMessage(message); + } + } + + public void stopPush() { + if (mHandler != null) { + mHandler.sendEmptyMessage(MSG_STOP_PUSH_AUDIO); + } + } + + public void stopPlayAudio(){ + if (mHandler != null) { + mHandler.sendEmptyMessage(MSG_STOP_PLAY_AUDIO); + } + } + + public void requireMotion(String name, boolean now) { + if (mHandler != null) { + Message message = new Message(); + message.what = MSG_REQUIRE_MOTION; + message.obj = name; + message.arg1 = now ? 0 : 1; + mHandler.sendMessage(message); + } + } + + public void requireRandomMotion(boolean now){ + if (mHandler != null) { + Message message = new Message(); + message.what = MSG_REQUIRE_MOTION_RANDOM; + message.arg1 = now ? 0 : 1; + mHandler.sendMessage(message); + } + } + + private void handleAudioStep() { + if (isRendering) { + long useTime = renderStep(); + long delay = 40 - (useTime); + if (delay < 0) { + Logger.w("渲染耗时过高: " + (useTime) + "(>40ms)"); + delay = 0; + } + if (mHandler != null) { + mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RENDER_STEP), delay); + } + } else { + if (mPreviewQueue != null) { + mPreviewQueue.clear(); + } + if (mHandler != null) { + mHandler.sendEmptyMessage(MSG_QUIT); + } + } + } + + private long renderStep() { + long startTime = System.currentTimeMillis(); + ModelInfo.Frame frame; + if (requireMotion) { + // 收到动作的通知 + requireMotion = false; + if (prepareActionRegion != null){ + mPreviewQueue.clear(); + Logger.d("发现想要播放的动作区间region: " + prepareActionRegion); + mPreviewQueue.addAll(prepareActionRegion.frames); + } + } + if (mPreviewQueue.isEmpty()) { + // 先假设把静默的都加进来 + ModelInfo.Region silenceRegion = mModelInfo.getSilenceRegion(); + mPreviewQueue.addAll(silenceRegion.frames); + List copiedList = new ArrayList<>(silenceRegion.frames); + // 反向的也加进来 + Collections.reverse(copiedList); + mPreviewQueue.addAll(copiedList); + } + frame = mPreviewQueue.poll(); + + if (frame != null) { + int readyCnt = scrfdncnn.readycnt(mCurrentBnfSession); + if (readyCnt > 0 && audioPlayer != null){ + if (mLastBnfSession != mCurrentBnfSession){ + mLastBnfSession = mCurrentBnfSession; + // 通知新的一段读取完成了,准备播放 + audioPlayer.startPlay(); + } + int bnfIndex = audioPlayer.getPlayIndex(); + Logger.i("scrfdncnn readyCnt: " + readyCnt + " bnfIndex: " + bnfIndex); + scrfRst = scrfdncnn.filerst(mCurrentBnfSession, !TextUtils.isEmpty(frame.sgPath) ? frame.sgPath : frame.rawPath, !TextUtils.isEmpty(frame.maskPath) ? frame.maskPath : "", frame.rect, "", bnfIndex, rawBuffer.array(), maskBuffer.array(),mModelInfo.getWidth() * mModelInfo.getHeight() * 3); + isLip = true; + if (scrfRst < 0){ + Logger.i("scrfdncnn.filerst bnf index: " + bnfIndex + " rst: " + scrfRst); + } + } else { + isLip = false; + scrfRst = scrfdncnn.fileload(!TextUtils.isEmpty(frame.sgPath) ? frame.sgPath : frame.rawPath, !TextUtils.isEmpty(frame.maskPath) ? frame.maskPath : "", mModelInfo.getWidth(), mModelInfo.getHeight(), rawBuffer.array(), maskBuffer.array(), mModelInfo.getWidth() * mModelInfo.getHeight() * 3); + if (scrfRst < 0){ + Logger.i("scrfdncnn.fileload rst: " + scrfRst); + } + } + if (frame.startFlag){ + callback.onMotionPlayStart(frame.actionName); + } + if (frame.endFlag){ + callback.onMotionPlayComplete(frame.actionName); + } + if (mRenderSink != null) { + mRenderSink.onVideoFrame(new ImageFrame(rawBuffer, maskBuffer, mModelInfo.getWidth(), mModelInfo.getHeight())); + } + } + long useTime = System.currentTimeMillis() - startTime; + if (mReporter != null){ + mReporter.onRenderStat(scrfRst, isLip, useTime); + } + return useTime; + } + + private void handleStopRender() { + Logger.i("handleStopRender"); + if (isRendering) { + isRendering = false; + } else { + mHandler.sendEmptyMessage(MSG_QUIT); + } + } + + private void handleStartPushAudio(){ + if (mCurrentBnfSession > 0){ + scrfdncnn.finsession(mCurrentBnfSession); + } + mCurrentBnfSession = scrfdncnn.newsession(); + if (audioPlayer != null && isRendering){ + audioPlayer.pushStart(); + } + } + + private void handlePushAudio(byte[] data){ + if (audioPlayer != null && isRendering){ + scrfdncnn.pushpcm(mCurrentBnfSession, data, data.length, 0); + audioPlayer.pushData(ByteBuffer.wrap(data)); + } + } + + private void handleStopPushAudio() { + if (scrfdncnn != null && isRendering){ + scrfdncnn.finsession(mCurrentBnfSession); + } + if (audioPlayer != null){ + audioPlayer.pushDone(); + } + } + + private void handleStopPlayAudio(){ + if (scrfdncnn != null && isRendering){ + scrfdncnn.finsession(mCurrentBnfSession); + mCurrentBnfSession = -1; + if (audioPlayer != null){ + audioPlayer.stop(); + } + } + } + + private void handleRequireMotion(String name, boolean now) { + ModelInfo.Region matchRegion = null; + for (ModelInfo.Region region : mModelInfo.getMotionRegions()){ + if (name != null && name.equals(region.name)){ + matchRegion = region; + } + } + if (matchRegion != null){ + if (now){ + prepareActionRegion = matchRegion; + requireMotion = true; + } else { + Logger.d("在播放队列最后插入动作区间region: " + matchRegion); + mPreviewQueue.addAll(matchRegion.frames); + } + } + } + + private void handleRequireMotionRandom(boolean now){ + if (!mModelInfo.getMotionRegions().isEmpty()){ + int randomIndex = new Random().nextInt(mModelInfo.getMotionRegions().size()); + ModelInfo.Region region = mModelInfo.getMotionRegions().get(randomIndex); + if (now){ + requireMotion = true; + prepareActionRegion = region; + } else { + Logger.d("在播放队列最后插入随机动作区间region: " + region); + mPreviewQueue.addAll(region.frames); + } + } + } + + static class RenderHandler extends Handler { + + private final WeakReference encoderWeakReference; + + public RenderHandler(RenderThread render) { + encoderWeakReference = new WeakReference<>(render); + } + + @Override + public void handleMessage(Message msg) { + int what = msg.what; + RenderThread render = encoderWeakReference.get(); + if (render == null) { + return; + } + switch (what) { + case MSG_RENDER_STEP: + render.handleAudioStep(); + break; + case MSG_STOP_RENDER: + render.handleStopRender(); + break; + case MSG_STOP_PUSH_AUDIO: + render.handleStopPushAudio(); + break; + case MSG_REQUIRE_MOTION: + String name = (String)msg.obj; + render.handleRequireMotion(name, msg.arg1 == 0); + break; + case MSG_REQUIRE_MOTION_RANDOM: + render.handleRequireMotionRandom(msg.arg1 == 0); + break; + case MSG_QUIT: + Logger.i("duix thread quit!"); + Looper myLooper = Looper.myLooper(); + if (myLooper != null) { + myLooper.quit(); + } + break; + case MSG_START_PUSH_AUDIO: + render.handleStartPushAudio(); + break; + case MSG_PUSH_AUDIO: + byte[] data = (byte[])msg.obj; + render.handlePushAudio(data); + break; + case MSG_STOP_PLAY_AUDIO: + render.handleStopPlayAudio(); + break; + } + } + + } + + public interface RenderCallback { + void onInitResult(int code, int subCode, String message, ModelInfo modelInfo); + + void onPlayStart(); + + void onPlayEnd(); + + void onPlayError(int code, String msg); + + void onMotionPlayStart(String name); + + void onMotionPlayComplete(String name); + } + + public interface Reporter { + void onRenderStat(int resultCode, boolean isLip, long useTime); + } +} diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/DeviceUtils.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/DeviceUtils.java new file mode 100644 index 0000000..14789da --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/DeviceUtils.java @@ -0,0 +1,149 @@ +package ai.guiji.duix.sdk.client.util; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.Display; +import android.view.WindowManager; + +import java.util.UUID; + +public class DeviceUtils { + + public static String getVersionName(Context context) { + try { + PackageInfo pi = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); + return pi.versionName; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return "Unknown"; + } + } + + public static int getVersionCode(Context context) { + try { + PackageInfo pi = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); + return pi.versionCode; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return 0; + } + } + + @SuppressLint("MissingPermission") + public static boolean isWifi(Context mContext) { + ConnectivityManager connectivityManager = (ConnectivityManager) mContext + .getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo info = null; + if (connectivityManager != null) { + info = connectivityManager.getActiveNetworkInfo(); + } + return info != null && info.getType() == ConnectivityManager.TYPE_WIFI; + } + + private static String getAndroidID(Context context) { + String id = Settings.System.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); + return id; + } + + private static String getDeviceUUid(Context context) { + String androidId = DeviceUtils.getAndroidID(context); + if (TextUtils.isEmpty(androidId)) { + return null; + } + UUID deviceUuid = new UUID(androidId.hashCode(), ((long) androidId.hashCode() << 32)); + return deviceUuid.toString(); + } + + private static String getAppUUid(Context context) { + SharedPreferences preferences = context.getSharedPreferences("device", Context.MODE_PRIVATE); + String uuid = preferences.getString("UUID", null); + if (TextUtils.isEmpty(uuid)) { + uuid = UUID.randomUUID().toString(); + preferences.edit().putString("UUID", uuid).apply(); + } + return uuid; + } + + public static String getUUID(Context context) { + Log.d("DeviceUtils", "getUUID: "); + String uuid = getDeviceUUid(context); + if (TextUtils.isEmpty(uuid)) { + uuid = getAppUUid(context); + } + return uuid; + } + + public static boolean isNetworkConnected(Context context) { + if (context != null) { + ConnectivityManager mConnectivityManager = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + @SuppressLint("MissingPermission") NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo(); + if (mNetworkInfo != null) { + return mNetworkInfo.isAvailable(); + } + } + return false; + } + + /** + * 获取屏幕信息 + * + * @param context + * @return + */ + public static ScreenInfo getScreenInfo(Context context) { + return new ScreenInfo(context); + } + + public static class ScreenInfo { + + public final float screenWidthDp;// dp单位 + public final float screenHeightDp;// dp单位 + public final int screenWidthPx; //屏幕宽 px + public final int screenHeightPx; //屏幕高 px + public final float uiScale;// density + public final float fontScale;// scaledDensity + + public ScreenInfo(Context context) { + WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + Display defaultDisplay = windowManager.getDefaultDisplay(); + DisplayMetrics displayMetrics = new DisplayMetrics(); + defaultDisplay.getMetrics(displayMetrics); + screenWidthPx = displayMetrics.widthPixels; + screenHeightPx = displayMetrics.heightPixels; + uiScale = context.getResources().getDisplayMetrics().density; + fontScale = context.getResources().getDisplayMetrics().scaledDensity; + screenWidthDp = px2dp(screenWidthPx); + screenHeightDp = px2dp(screenHeightPx); + } + + public int dp2px(float dpValue) { + return (int) (dpValue * uiScale + 0.5f); + } + + public int px2dp(float pxValue) { + return (int) (pxValue / uiScale + 0.5f); + } + + public int sp2px(float spValue) { + return (int) (spValue * fontScale + 0.5f); + } + + public int px2sp(float pxValue) { + return (int) (pxValue / fontScale + 0.5f); + } + + + } + + +} diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/FileUtil.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/FileUtil.java new file mode 100644 index 0000000..6b23e9f --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/FileUtil.java @@ -0,0 +1,23 @@ +package ai.guiji.duix.sdk.client.util; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; + +public class FileUtil { + + public static String readFile(String path){ + StringBuilder sb = new StringBuilder(); + try (BufferedReader reader = new BufferedReader(new FileReader(path))){ + String line; + while ((line = reader.readLine()) != null) { + // 处理每行数据 + sb.append(line); + } + } catch (IOException e) { + e.printStackTrace(); + } + return sb.toString(); + } + +} diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/Logger.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/Logger.java new file mode 100644 index 0000000..5240c21 --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/Logger.java @@ -0,0 +1,56 @@ +package ai.guiji.duix.sdk.client.util; + +import android.util.Log; + +import ai.guiji.duix.sdk.client.BuildConfig; + +public class Logger { + + private static boolean logFlag = BuildConfig.DEBUG; + + private static String TAG = "DUIX-SDK"; + + public static void debugEnable(boolean enable) { + logFlag = enable; + } + + public static void e(String text) { + e("", text); + } + + public static void e(String tag, String text) { + if (logFlag) { + Log.e(TAG, tag + "~" + text); + } + } + + public static void i(String text) { + i("", text); + } + + public static void i(String tag, String text) { + if (logFlag) { + Log.i(TAG, tag + "~" + text); + } + } + + public static void d(String text) { + d("", text); + } + + public static void d(String tag, String text) { + if (logFlag) { + Log.d(TAG, tag + "~" + text); + } + } + + public static void w(String text) { + w("", text); + } + + public static void w(String tag, String text) { + if (logFlag) { + Log.w(TAG, tag + "~" + text); + } + } +} diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/MD5Util.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/MD5Util.java new file mode 100644 index 0000000..15589a6 --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/MD5Util.java @@ -0,0 +1,172 @@ +package ai.guiji.duix.sdk.client.util; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * 采用MD5加密解密 + * + * @author tfq + * @datetime 2011-10-13 + */ +public class MD5Util { + private static final char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f'}; + + public final static String md5Encode(final String s) { + try { + final byte[] strTemp = s.getBytes(); + final MessageDigest mdTemp = MessageDigest.getInstance("MD5"); + mdTemp.update(strTemp); + final byte[] md = mdTemp.digest(); + final int j = md.length; + final char str[] = new char[j * 2]; + int k = 0; + for (int i = 0; i < j; i++) { + final byte byte0 = md[i]; + str[k++] = hexDigits[byte0 >>> 4 & 0xf]; + str[k++] = hexDigits[byte0 & 0xf]; + } + return new String(str); + } catch (Exception e) { + return null; + } + } + + public final static String md5Encode(final byte[] md) { + try { + final int j = md.length; + final char str[] = new char[j * 2]; + int k = 0; + for (int i = 0; i < j; i++) { + final byte byte0 = md[i]; + str[k++] = hexDigits[byte0 >>> 4 & 0xf]; + str[k++] = hexDigits[byte0 & 0xf]; + } + return new String(str); + } catch (Exception e) { + return null; + } + } + + private static String toHexString(final byte[] b) { + final StringBuilder sb = new StringBuilder(b.length * 2); + for (int i = 0; i < b.length; i++) { + final byte byte0 = b[i]; + sb.append(hexDigits[byte0 >>> 4 & 0xf]); + sb.append(hexDigits[byte0 & 0x0f]); + } + return sb.toString(); + } + + /** + * 求一个文件的MD5签名 + * + * @return + */ + public final static String md5EncodeFile(final File file) { + try { + return md5EncodeFile(new FileInputStream(file)); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return null; + } + } + + public final static String md5EncodeFile(InputStream inputStream) { + final byte[] buffer = new byte[1024]; + int bytes; + MessageDigest md5; + try { + final InputStream is = inputStream; + md5 = MessageDigest.getInstance("MD5"); + while ((bytes = is.read(buffer)) > 0) { + md5.update(buffer, 0, bytes); + } + is.close(); + return toHexString(md5.digest()); + } catch (Exception e) { + return null; + } + } + + public final static String md5EncodeFile(final String fileName) { + try { + return md5EncodeFile(new FileInputStream(fileName)); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return null; + } + } + + + public final static boolean verifyMD5File(File file, String md5) { + String md5File = md5EncodeFile(file); + if (md5File != null && md5 != null) { + return md5File.toLowerCase().trim().equals(md5.toLowerCase().trim()); + } + return false; + } + + + /** + * MD5加码 生成32位md5码 + */ + public static byte[] MD5(String val) { + MessageDigest md5 = null; + try { + md5 = MessageDigest.getInstance("MD5"); + md5.update(val.getBytes()); + byte[] m = md5.digest();//加密 MessageDigest md5 = null; + return m; + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + return null; + } + } + + public static String string2MD5(String inStr) { + MessageDigest md5 = null; + try { + md5 = MessageDigest.getInstance("MD5"); + } catch (Exception e) { + System.out.println(e.toString()); + e.printStackTrace(); + return ""; + } + char[] charArray = inStr.toCharArray(); + byte[] byteArray = new byte[charArray.length]; + + for (int i = 0; i < charArray.length; i++) + byteArray[i] = (byte) charArray[i]; + byte[] md5Bytes = md5.digest(byteArray); + StringBuffer hexValue = new StringBuffer(); + for (int i = 0; i < md5Bytes.length; i++) { + int val = ((int) md5Bytes[i]) & 0xff; + if (val < 16) + hexValue.append("0"); + hexValue.append(Integer.toHexString(val)); + } + return hexValue.toString(); + + } + + /** + * 加密解密算法 执行一次加密,两次解密 + */ + public static String convertMD5(String inStr) { + + char[] a = inStr.toCharArray(); + for (int i = 0; i < a.length; i++) { + a[i] = (char) (a[i] ^ 't'); + } + String s = new String(a); + return s; + + } + +} diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/OpenGLUtil.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/OpenGLUtil.java new file mode 100644 index 0000000..295b8ff --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/OpenGLUtil.java @@ -0,0 +1,537 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ai.guiji.duix.sdk.client.util; + +import android.app.ActivityManager; +import android.content.Context; +import android.content.pm.ConfigurationInfo; +import android.graphics.Bitmap; +import android.opengl.GLES10; +import android.opengl.GLES20; +import android.opengl.GLES30; +import android.opengl.GLUtils; +import android.opengl.Matrix; +import android.os.Build; +import android.util.Log; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.util.Arrays; + +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; +import javax.microedition.khronos.egl.EGLSurface; + +public class OpenGLUtil { + public static final String TAG = "OpenGLUtil"; + public static final int NO_TEXTURE = -1; + public static final float[] IDENTITY_MATRIX; + private static final int SIZEOF_FLOAT = 4; + + static { + IDENTITY_MATRIX = new float[16]; + Matrix.setIdentityM(IDENTITY_MATRIX, 0); + } + + public static int loadTexture(final Bitmap img, final int usedTexId) { + return loadTexture(img, usedTexId, true); + } + + public static int loadTexture(final Bitmap img, final int usedTexId, final boolean recycle) { + int textures[] = new int[1]; + if (usedTexId == NO_TEXTURE) { + GLES20.glGenTextures(1, textures, 0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]); + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); + + GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, img, 0); + } else { + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, usedTexId); + GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, img); + textures[0] = usedTexId; + } + if (recycle) { + img.recycle(); + } + return textures[0]; + } + + public static int loadTexture(final ByteBuffer data, final int width, final int height, final int usedTexId) { + int textures[] = new int[1]; + if (usedTexId == NO_TEXTURE) { + GLES20.glGenTextures(1, textures, 0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]); + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, + GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, + GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, + GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, + GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); + GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, + 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, data); + } else { + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, usedTexId); + GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, width, + height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, data); + textures[0] = usedTexId; + } + return textures[0]; + } + + public static int createProgram(String vertexSource, String fragmentSource) { + int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); + if (vertexShader == 0) { + return 0; + } + int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); + if (pixelShader == 0) { + return 0; + } + + int program = GLES20.glCreateProgram(); + checkGLError("glCreateProgram"); + if (program == 0) { + Log.e(TAG, "Could not create program"); + } + GLES20.glAttachShader(program, vertexShader); + checkGLError("glAttachShader"); + GLES20.glAttachShader(program, pixelShader); + checkGLError("glAttachShader"); + GLES20.glLinkProgram(program); + int[] linkStatus = new int[1]; + GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0); + if (linkStatus[0] != GLES20.GL_TRUE) { + Log.e(TAG, "Could not link program: "); + Log.e(TAG, GLES20.glGetProgramInfoLog(program)); + GLES20.glDeleteProgram(program); + program = 0; + } + return program; + } + + public static int loadShader(int shaderType, String source) { + int shader = GLES20.glCreateShader(shaderType); + checkGLError("glCreateShader type=" + shaderType); + GLES20.glShaderSource(shader, source); + GLES20.glCompileShader(shader); + int[] compiled = new int[1]; + GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0); + if (compiled[0] == 0) { + Log.e(TAG, "Could not compile shader " + shaderType + ":"); + Log.e(TAG, " " + GLES20.glGetShaderInfoLog(shader)); + GLES20.glDeleteShader(shader); + shader = 0; + } + return shader; + } + + public static void checkGLError(String op) { + int error = GLES20.glGetError(); + if (error != GLES20.GL_NO_ERROR) { + String msg = op + ": glError 0x" + Integer.toHexString(error); + Log.e(TAG, msg); + } + } + + public static void checkLocation(int location, String label) { + if (location < 0) { + Log.e(TAG, "Unable to locate '" + label + "' in program"); + } + } + + /** + * Creates a texture from raw data. + * + * @param data Image data, in a "direct" ByteBuffer. + * @param width Texture width, in pixels (not bytes). + * @param height Texture height, in pixels. + * @param format Image data format (use constant appropriate for glTexImage2D(), e.g. GL_RGBA). + * @return Handle to texture. + */ + public static int createImageTexture(ByteBuffer data, int width, int height, int format) { + int[] textureHandles = new int[1]; + int textureHandle; + + GLES20.glGenTextures(1, textureHandles, 0); + textureHandle = textureHandles[0]; + OpenGLUtil.checkGLError("glGenTextures"); + + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle); + + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, + GLES20.GL_LINEAR); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, + GLES20.GL_LINEAR); + OpenGLUtil.checkGLError("loadImageTexture"); + + // Load the data from the buffer into the texture handle. + GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, /*level*/ 0, format, + width, height, /*border*/ 0, format, GLES20.GL_UNSIGNED_BYTE, data); + OpenGLUtil.checkGLError("loadImageTexture"); + + return textureHandle; + } + + public static int createImageTexture(Bitmap bmp) { + int[] textureHandles = new int[1]; + int textureHandle; + + GLES20.glGenTextures(1, textureHandles, 0); + textureHandle = textureHandles[0]; + OpenGLUtil.checkGLError("glGenTextures"); + + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, + GLES20.GL_LINEAR); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, + GLES20.GL_LINEAR); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, + GLES20.GL_CLAMP_TO_EDGE); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, + GLES20.GL_CLAMP_TO_EDGE); + OpenGLUtil.checkGLError("loadImageTexture"); + // Load the data from the buffer into the texture handle. + GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, /*level*/ 0, bmp, 0); + OpenGLUtil.checkGLError("loadImageTexture"); + + return textureHandle; + } + + /** + * Allocates a direct float buffer, and populates it with the float array data. + */ + public static FloatBuffer createFloatBuffer(float[] coords) { + // Allocate a direct ByteBuffer, using 4 bytes per float, and copy coords into it. + ByteBuffer bb = ByteBuffer.allocateDirect(coords.length * SIZEOF_FLOAT); + bb.order(ByteOrder.nativeOrder()); + FloatBuffer fb = bb.asFloatBuffer(); + fb.put(coords); + fb.position(0); + return fb; + } + + /** + * Writes GL version info to the log. + */ + public static void printVersionInfo() { + Log.i(TAG, "vendor : " + GLES20.glGetString(GLES20.GL_VENDOR)); + Log.i(TAG, "renderer: " + GLES20.glGetString(GLES20.GL_RENDERER)); + Log.i(TAG, "version : " + GLES20.glGetString(GLES20.GL_VERSION)); + + int[] values = new int[1]; + GLES30.glGetIntegerv(GLES30.GL_MAJOR_VERSION, values, 0); + int majorVersion = values[0]; + GLES30.glGetIntegerv(GLES30.GL_MINOR_VERSION, values, 0); + int minorVersion = values[0]; + if (GLES30.glGetError() == GLES30.GL_NO_ERROR) { + Log.i(TAG, "OpenGL Version: " + majorVersion + "." + minorVersion); + } + } + + /** + * 获取OpenGL主版本号,必须在GL线程调用 + * + * @return 主版本号 + */ + public static int getGlMajorVersion() { + int[] values = new int[1]; + GLES30.glGetIntegerv(GLES30.GL_MAJOR_VERSION, values, 0); + int majorVersion = values[0]; + return majorVersion; + } + + public static int createTextureObject(int textureTarget) { + int[] textures = new int[1]; + GLES20.glGenTextures(1, textures, 0); + OpenGLUtil.checkGLError("glGenTextures"); + + int texId = textures[0]; + GLES20.glBindTexture(textureTarget, texId); + OpenGLUtil.checkGLError("glBindTexture " + texId); + + GLES20.glTexParameterf(textureTarget, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); + GLES20.glTexParameterf(textureTarget, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); + GLES20.glTexParameteri(textureTarget, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); + GLES20.glTexParameteri(textureTarget, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); + OpenGLUtil.checkGLError("glTexParameter"); + + return texId; + } + + public static void deleteTextures(int[] textureId) { + if (textureId != null && textureId.length > 0) { + GLES20.glDeleteTextures(textureId.length, textureId, 0); + } + } + + public static void createFrameBuffers(int[] fboTex, int[] fboId, int width, int height) { + GLES20.glGenFramebuffers(fboId.length, fboId, 0); + GLES20.glGenTextures(fboTex.length, fboTex, 0); + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId[0]); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fboTex[0]); + GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); + GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, fboTex[0], 0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); + } + + public static void deleteFrameBuffers(int[] fboId) { + if (fboId != null && fboId.length > 0) { + GLES20.glDeleteFramebuffers(fboId.length, fboId, 0); + } + } + + public static float[] changeMvpMatrixCrop(float viewWidth, float viewHeight, float textureWidth, float textureHeight) { + float scale = viewWidth * textureHeight / viewHeight / textureWidth; + float[] mvp = Arrays.copyOf(IDENTITY_MATRIX, IDENTITY_MATRIX.length); + Matrix.scaleM(mvp, 0, scale > 1 ? 1F : (1F / scale), scale > 1 ? scale : 1F, 1F); +// Matrix.translateM(mvp,0,0f,0f,-2.5f); +// Matrix.rotateM(mvp,0,-60f,1f,0f,0f); + return mvp; + } + + public static float[] changeMvpMatrixInside(float viewWidth, float viewHeight, float textureWidth, float textureHeight) { + float scale = viewWidth * textureHeight / viewHeight / textureWidth; + float[] mvp = Arrays.copyOf(IDENTITY_MATRIX, IDENTITY_MATRIX.length); + Matrix.scaleM(mvp, 0, scale > 1 ? (1F / scale) : 1F, scale > 1 ? 1F : scale, 1F); + return mvp; + } + + /** + * 获取当前设备支持openGL ES版本,优先返回3。0 + * + * @param context + * @return ver + */ + public static int getSupportGLVersion(Context context) { + final ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo(); + int version = configurationInfo.reqGlEsVersion >= 0x30000 ? 3 : 2; + String glEsVersion = configurationInfo.getGlEsVersion(); + Log.d(TAG, "OpenGL ES Version: " + Integer.toHexString(configurationInfo.reqGlEsVersion) + + ", glEsVersion: " + glEsVersion + ", return: " + version); + return version; + } + + /** + * 获取当前设备支持OpenGL最大纹理大小 + * + * @return + */ + public static int getMaxTextureSize() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + EGL10 egl = (EGL10) EGLContext.getEGL(); + EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + int[] vers = new int[2]; + egl.eglInitialize(dpy, vers); + int[] configAttr = { + EGL10.EGL_COLOR_BUFFER_TYPE, EGL10.EGL_RGB_BUFFER, + EGL10.EGL_LEVEL, 0, + EGL10.EGL_SURFACE_TYPE, EGL10.EGL_PBUFFER_BIT, + EGL10.EGL_NONE + }; + EGLConfig[] configs = new EGLConfig[1]; + int[] numConfig = new int[1]; + egl.eglChooseConfig(dpy, configAttr, configs, 1, numConfig); + if (numConfig[0] == 0) {// TROUBLE! No config found. + } + EGLConfig config = configs[0]; + int[] surfAttr = { + EGL10.EGL_WIDTH, 64, + EGL10.EGL_HEIGHT, 64, + EGL10.EGL_NONE + }; + EGLSurface surf = egl.eglCreatePbufferSurface(dpy, config, surfAttr); + final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; // missing in EGL10 + int[] ctxAttrib = { + EGL_CONTEXT_CLIENT_VERSION, 1, + EGL10.EGL_NONE + }; + EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, ctxAttrib); + egl.eglMakeCurrent(dpy, surf, surf, ctx); + int[] maxSize = new int[1]; + GLES10.glGetIntegerv(GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0); + egl.eglMakeCurrent(dpy, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); + egl.eglDestroySurface(dpy, surf); + egl.eglDestroyContext(dpy, ctx); + egl.eglTerminate(dpy); + return maxSize[0]; + } else { + int[] maxSize = new int[1]; + GLES10.glGetIntegerv(GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0); + return maxSize[0]; + } + } + + /** + * Helper function that compiles the shaders, links and validates the + * program, returning the program ID. + */ + public static int buildProgram(String vertexShaderSource, + String fragmentShaderSource) { + int program; + + // Compile the shaders. + int vertexShader = compileVertexShader(vertexShaderSource); + int fragmentShader = compileFragmentShader(fragmentShaderSource); + + // Link them into a shader program. + program = linkProgram(vertexShader, fragmentShader); + + validateProgram(program); + + return program; + } + + /** + * Loads and compiles a vertex shader, returning the OpenGL object ID. + */ + public static int compileVertexShader(String shaderCode) { + return compileShader(GLES20.GL_VERTEX_SHADER, shaderCode); + } + + /** + * Loads and compiles a fragment shader, returning the OpenGL object ID. + */ + public static int compileFragmentShader(String shaderCode) { + return compileShader(GLES20.GL_FRAGMENT_SHADER, shaderCode); + } + + /** + * Links a vertex shader and a fragment shader together into an OpenGL + * program. Returns the OpenGL program object ID, or 0 if linking failed. + */ + public static int linkProgram(int vertexShaderId, int fragmentShaderId) { + + // Create a new program object. + final int programObjectId = GLES20.glCreateProgram(); + + if (programObjectId == 0) { + Log.w(TAG, "Could not create new program"); + return 0; + } + + // Attach the vertex shader to the program. + GLES20.glAttachShader(programObjectId, vertexShaderId); + + // Attach the fragment shader to the program. + GLES20.glAttachShader(programObjectId, fragmentShaderId); + + // Link the two shaders together into a program. + GLES20.glLinkProgram(programObjectId); + + // Get the link status. + final int[] linkStatus = new int[1]; + GLES20.glGetProgramiv(programObjectId, GLES20.GL_LINK_STATUS, + linkStatus, 0); + + // Print the program info log to the Android log output. + Log.v(TAG, + "Results of linking program:\n" + + GLES20.glGetProgramInfoLog(programObjectId)); + + // Verify the link status. + if (linkStatus[0] == 0) { + // If it failed, delete the program object. + GLES20.glDeleteProgram(programObjectId); + Log.w(TAG, "Linking of program failed."); + return 0; + } + + // Return the program object ID. + return programObjectId; + } + + /** + * Validates an OpenGL program. Should only be called when developing the + * application. + */ + public static boolean validateProgram(int programObjectId) { + GLES20.glValidateProgram(programObjectId); + final int[] validateStatus = new int[1]; + GLES20.glGetProgramiv(programObjectId, GLES20.GL_VALIDATE_STATUS, + validateStatus, 0); + Log.v(TAG, "Results of validating program: " + validateStatus[0] + + "\nLog:" + GLES20.glGetProgramInfoLog(programObjectId)); + + return validateStatus[0] != 0; + } + + /** + * Compiles a shader, returning the OpenGL object ID. + */ + private static int compileShader(int type, String shaderCode) { + // Create a new shader object. + final int shaderObjectId = GLES20.glCreateShader(type); + + if (shaderObjectId == 0) { + Log.e(TAG, "Could not create new shader."); + return 0; + } + + // Pass in the shader source. + GLES20.glShaderSource(shaderObjectId, shaderCode); + + // Compile the shader. + GLES20.glCompileShader(shaderObjectId); + + // Get the compilation status. + final int[] compileStatus = new int[1]; + GLES20.glGetShaderiv(shaderObjectId, GLES20.GL_COMPILE_STATUS, + compileStatus, 0); + + // Verify the compile status. + if (compileStatus[0] == 0) { + // If it failed, delete the shader object. + GLES20.glDeleteShader(shaderObjectId); + Log.e(TAG, "Compilation of shader failed."); + return 0; + } + + // Return the shader object ID. + return shaderObjectId; + } + + public static float[] scale(float[] m) { + Matrix.scaleM(m, 0, 2.0F, 1.0F, 1); + return m; + } + + public static float[] rotate(float[] m, float angle) { + Matrix.rotateM(m, 0, angle, 0, 0, 1); + return m; + } + + public static float[] flip(float[] m, boolean x, boolean y) { + if (x || y) { + Matrix.scaleM(m, 0, x ? -1 : 1, y ? -1 : 1, 1); + } + return m; + } + +} diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/SystemUtils.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/SystemUtils.java new file mode 100644 index 0000000..12d5485 --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/SystemUtils.java @@ -0,0 +1,71 @@ +package ai.guiji.duix.sdk.client.util; + +import android.content.Context; +import android.content.pm.PackageManager; + +public class SystemUtils { + + public static int getVersionCode(Context context) { + try { + return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return -1; + } + } + + public static String getVersionName(Context context) { + try { + return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return ""; + } + } + + /** + * 版本号比较 + * + * @param version1 + * @param version2 + * @return + */ + public static int compareVersion(String version1, String version2) { + try { + if (version1.equals(version2)) { + return 0; + } + String[] version1Array = version1.split("\\."); + String[] version2Array = version2.split("\\."); + int index = 0; + // 获取最小长度值 + int minLen = Math.min(version1Array.length, version2Array.length); + int diff = 0; + while (index < minLen + && (diff = Integer.parseInt(version1Array[index]) + - Integer.parseInt(version2Array[index])) == 0) { + index++; + } + if (diff == 0) { + // 如果位数不一致,比较多余位数 + for (int i = index; i < version1Array.length; i++) { + if (Integer.parseInt(version1Array[i]) > 0) { + return 1; + } + } + + for (int i = index; i < version2Array.length; i++) { + if (Integer.parseInt(version2Array[i]) > 0) { + return -1; + } + } + return 0; + } else { + return diff > 0 ? 1 : -1; + } + } catch (Exception e) { + e.printStackTrace(); + } + return -1; + } +} diff --git a/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/ZipUtil.java b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/ZipUtil.java new file mode 100644 index 0000000..29bb261 --- /dev/null +++ b/duix-sdk/src/main/java/ai/guiji/duix/sdk/client/util/ZipUtil.java @@ -0,0 +1,98 @@ +package ai.guiji.duix.sdk.client.util; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipInputStream; + +public class ZipUtil { + + //解压缩文件 + // 这里unzip需要使用canonicalPath做校验,但是该方法取的路径可能和getAbsolutePath()方式获取的不一致 + // getCanonicalPath() /data/data/....... + // getAbsolutePath /data/user/0/...... + public static boolean unzip(String zipFilePath, String outOutPath, Callback callback) { + try (FileInputStream fis = new FileInputStream(zipFilePath)) { + long total = 0; + if (callback != null){ + total = getZipSize(zipFilePath); + } + ZipInputStream inZip = new ZipInputStream(fis); + long currentSize = 0; + ZipEntry zipEntry; + String szName = ""; + while ((zipEntry = inZip.getNextEntry()) != null) { + szName = zipEntry.getName(); + if (zipEntry.isDirectory()) { + szName = szName.substring(0, szName.length() - 1); + File folder = new File(outOutPath + File.separator + szName); + String canonicalPath = folder.getCanonicalPath(); + if (!canonicalPath.startsWith(outOutPath)) { + Logger.e("绝对值路径比较异常忽略该地址: " + folder.getAbsolutePath()); + } else { + if (!folder.exists()) { + if (!folder.mkdirs()) { + return false; + } + } + } + } else { + File file = new File(outOutPath + File.separator + szName); + String canonicalPath = file.getCanonicalPath(); + if (!canonicalPath.startsWith(outOutPath)) { + Logger.e( "绝对值路径比较异常忽略该地址: " + file.getAbsolutePath()); + } else { + if (!file.exists()) { + if (!file.getParentFile().exists()) { + file.getParentFile().mkdirs(); + } + if (!file.createNewFile()) { + return false; + } + FileOutputStream out = new FileOutputStream(file); + int len; + byte[] buffer = new byte[2048]; + while ((len = inZip.read(buffer)) != -1) { + out.write(buffer, 0, len); + out.flush(); + if (callback != null) { + currentSize += len; + callback.onProgress(currentSize, total); // 通过回调函数更新进度 + } + } + out.close(); + } + } + } + } + inZip.close(); + return true; + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + + private static long getZipSize(String filePath){ + long size = 0; + ZipFile f; + try { + f = new ZipFile(filePath); + Enumeration en = f.entries(); + while (en.hasMoreElements()) { + size += en.nextElement().getSize(); + } + } catch (IOException e) { + size = 0; + } + return size; + } + + public interface Callback { + void onProgress(long current, long total); + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..38d44b7 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,17 @@ +android.enableJetifier=true +android.useAndroidX=true +org.gradle.daemon=true +org.gradle.jvmargs=-Xms2048m -Xmx6656m + +appcompatVersion=1.3.0 +recyclerviewVersion=1.2.1 +preferenceVersion=1.1.0 +annotationVersion=1.1.0 +ottoVersion=1.3.8 +ijkVersion=0.8.8 +core_ktx=1.5.0 +lifecycle_ktx=2.3.1 +android.injected.testOnly=false +android.defaults.buildfeatures.buildconfig=true +android.nonTransitiveRClass=false +android.nonFinalResIds=false \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..f6b961fd5a86aa5fbfe90f707c3138408be7c718 GIT binary patch literal 54329 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

<5G2M1WZP5 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 F{|7XC?P&l2 literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..34e4582 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sun Aug 25 10:34:48 CST 2019 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..959ad2d --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +include ':duix-sdk' +include ':test' diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/test/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/test/build.gradle b/test/build.gradle new file mode 100644 index 0000000..f5e9fab --- /dev/null +++ b/test/build.gradle @@ -0,0 +1,90 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} + +static def getCurrentTime() { + return new Date().format("yyyy-MM-dd-HH-mm", TimeZone.getTimeZone("GMT+08:00")) +} + +android { + namespace 'ai.guiji.duix.test' + compileSdk 34 + + defaultConfig { + applicationId "ai.guiji.duix.test" + minSdk 24 + targetSdk 34 + versionCode 13 + versionName '4.1.1' + } + + signingConfigs { + release { + storeFile file('../demo.jks') + storePassword '123456' + keyAlias 'demo' + keyPassword '123456' + } + } + + buildTypes { + debug { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.release + } + release { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.release + + applicationVariants.all { variant -> + variant.outputs.all { + outputFileName = "duix_mobile_test_${buildType.name}_${getCurrentTime()}_${defaultConfig.versionName}.apk" + } + } + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } + buildFeatures { + viewBinding true + } + composeOptions { + kotlinCompilerExtensionVersion '1.4.3' + } + packaging { + resources { + excludes += '/META-INF/{AL2.0,LGPL2.1}' + } + } + + lint { + baseline = file("lint-baseline.xml") + } + lintOptions{ + checkReleaseBuilds false + } +} + +dependencies { + + implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs') + implementation 'androidx.core:core-ktx:1.12.0' + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'com.google.android.material:material:1.4.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.1' + implementation "androidx.activity:activity:1.3.0" + implementation "androidx.fragment:fragment:1.3.0" + + implementation 'com.github.bumptech.glide:glide:4.12.0' + + implementation project(":duix-sdk") + implementation 'com.squareup.okhttp3:okhttp:4.10.0' +} \ No newline at end of file diff --git a/test/lint-baseline.xml b/test/lint-baseline.xml new file mode 100644 index 0000000..3654247 --- /dev/null +++ b/test/lint-baseline.xml @@ -0,0 +1,561 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/proguard-rules.pro b/test/proguard-rules.pro new file mode 100644 index 0000000..30e622b --- /dev/null +++ b/test/proguard-rules.pro @@ -0,0 +1,26 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +-dontwarn com.squareup.okhttp3.** +-keep class com.squareup.okhttp3.** { *;} + +-keep class ai.guiji.duix.DuixNcnn{*; } \ No newline at end of file diff --git a/test/src/main/AndroidManifest.xml b/test/src/main/AndroidManifest.xml new file mode 100644 index 0000000..62f5af7 --- /dev/null +++ b/test/src/main/AndroidManifest.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/src/main/assets/bg/bg1.png b/test/src/main/assets/bg/bg1.png new file mode 100644 index 0000000000000000000000000000000000000000..57d25ed4c2ed997c9818210a53d69d923b70fc9e GIT binary patch literal 1022393 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

-{~gdQ7KZl%7_Qk+YA4fky+D7oQrXD{s}Qv! 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

ygv^1#&hgxO-p+Rbh!!R&wguF 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 z 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�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

=i7T``G2D|w75t1eJ-PCdJe{?|ERv+ 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�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

VcxgsG_@gy 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 literal 0 HcmV?d00001 diff --git a/test/src/main/assets/bg/bg2.jpg b/test/src/main/assets/bg/bg2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..67dfb4b5a1631b2bb33f75d7d8ba3a0b8cea296e GIT binary patch literal 290851 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%0Ar zAtKe2XcRs%A<%!)*N`k)wDZVTFjA73;8kp%G{+tL;?s%$G5UECbyy3R2`mqQ8sx`6 zierVQ0rmq;MdN>4R@@K6{@{|G4`z`cst%N1IMeqiT|Ayvf(VD^{k15C@c{Xm7hpQ! zC%yJ6n!d^tKccDED@(czmeWoPT(K*nvG$aI4g%g?m+-F@? zalU~RoFw!_Y|L+>pUiJmOLZBi-s^W@Ej(+z?9?X@tUGu)9OCXb6G!8K^@Sv`dJZ$B zvVUY@P9l_NdJ2h*lrfn~90lGwSH;FEGTDv&n;riqmLk54fQ)}Z3S7}FCzis`^G1z_ zfMdBzvQ}0DZiqX>yaJ#HCMEhp+Vo;lV9@^~5lE&@G~lGUKgvO^SK8Qxn0ox{oLTXX z0O$;!Y|~d-2dVL|%9eXTP{_}QMmY4ktjN4O?52*GDVLHri1;_-$!b5#_U)opMQDS8}n1GUVGE zsQWZA8G1+pcw{oDX01&>;!=Z`sHAqcW<+Xgh2{ou|deI2R5VH9M3qHcb*U;WfqdsJ{fB7v$ zhu#;b4udhdU~daS494(FpA~5KCw9h11e~$G^dVue{|`l>38*%60`hjlt`F9{;O&^d zs;yPWz!`Y^@o0e$I|)Dj7tT|iQFL*v?m-GYwgaXCgck1`RsI1z6 zx7N$Tp6~*ZYP0J3v|sxFgIY?8#2*=7#rd2mEhQ0l}Oj6Csc^{4o=goY5o> zWCB@szzKqB5FAL=Hv#IG#r9-YfF_P5$rKQERc!8S#!Q6Ac4U|(B_ms0{IGW2p#a1o zB#YRXc+8L;3JRgRi6I&?68%cgh9mM$0aWN->CoI+NwzO_N78ffNE_wWvq(0U-z$I$`d5%+ z^1s>~d4uh3uz3m|-XhMTTyxg@=jF0C9wPW0j=U_?5~V-W({*4SRRKpW_{aG9U3oTh z^{^ZCWzq!en=f|=qWl>R2QyZ%@AihGdc&YO8g);w=;3Ug3eh2~S>MKF@#HIZVC1r< zNj+&7<@kcbruCVB#Slkql7;O#6G9pB@?V?>)49Lwy;K>!c>vKQ&9PmERL6#LB;22a_h(Z?{12{Fa z-sCoG0QhgqPhGb%7B}0!9-3k5IqhfEhkI)@#z_1DC!rQud|Fn4LGi$yR?-0q>ExI) zKS=++g|e60Gz2d=zd33+oA3Lhk~B&7b%NJVZVXsy#py-~L-f$a1bThe=CS_brszlE zhS$CRG8)0$R}~Q=ewAPsd6&|a)>F2iW?2!Z$gOurzp2bXB}CuypAD7KZ0ggRJ$0MZ z2XuD?u9CJ+ir5x%d!hU8D_{kd)3FgXD-eAOB`NIHIbnL&)bB1 zvQQtsZZ>|>H_DTn!Z{|O;Wc!K6?w7A^&HGJ&`ZLFo$&G0(26+Men&mp>vOS(jAOOg zo^37C7B2(61Q%A(nOpT}8x|2fh*_>%M;bQ4VJ`_PSV)R1avdi^Quewmcq(dkM9^7a zN$f6V+U|+J@I`;j@FmEpgQaX*GbY&D?e3~eG6)=+q-!%9wf#0+7@{9c4^wwB;tz#q z(e8a+PccdTS%NX@E-+pM;z~s{ER)FEoKsxN)*^@8#U|UQC_}adjk)`*JuiFxDPa%q zzkM^0^HggoQn(bffSgDs=EOf8EQqK?JI4>l9op~U% zgR@Q#ylAa;G?QYQ-NO(puUvBId%|v-IWBJ{q$qt)Ibv?dK;@*KsC0n9rhV@T>G|8i zy(pP=~^RNeE^-uR7O;Am~;2To#y?3ByM#^zS2j*{PdTSj|cHXceDj=PrT>h z-!0G5wIROPJ4an#WF+B>rAJofPm=(cD<#~Y=>ZhgRj>W6njS^5U!s!rF+RW=Sdl!9 zufESRm~)MHA(}_s;*e#YJ~WogTBL~1ec2#*9Hc(9A!^LsY+#8BqOg&6M6V!Uf)4lYAY2vzAgWK7ED4jQB*PI2U!=@-GfKCla+MLGO-v6N- zdjJCY#zR)kRR^w!a9-ba7y-kp#)aDJo64~ACq87F

espAp}jPQmLttqhmVtGlxV zI~iHi&ak&FnMu1su{qRz(?gl%3K;@Z+Hu884$ek;`Ew4L*B2jkuS)oePh2BfA4Pu? ztbm0vO)Uq(dv^3c0*R${qg7skDcUP(?r+}FkqwEK;$n3Av&>yZtr6_=cP`CWSenWS zpza$n<-N#{x};;E<~F>}*<5?I=k6gS6Yo1|FqW@Kk&b@18OUSj#;W^st=lO?#V5j? ztj|hcfs#X6-YoG@harLg6r#jrNKk$@J;41SdOjN-W%b7(srDClM9nzER2%Je>ti|J z+9JOJwjXm3x6QfU08k2p_S0ozE^;l}vP689uSu;SM)94#+}vO7!6SC{X)W1BGWen4 zu$<)KxS2-5A*(i(_jEO3u+U6XO#6N=B4=I|IIIdg

>(i=8Z&^5Om7)CZf`p;w15 zM5ZEV6+nx%x15VMQi*G@e7!dpfgH(GAd#cS!$oL|%Z-l)AAMq-?Elo4 z{KPt)1SKS#EW6nEqay#2=4<&_41J)iGdHmg{m`kLeqGaG4wgRJoHK|Zq8M;`0((ya zs<>>ck6Npbsv5(4hUaPj1|VRek5a1+m_a^NmZK zA7EbrPR$8+-TFiseB(L}hePBnAkpVXej!9tRg4Y$Zr?~XlQxi3>NxW9P~EF&?J|3O z0cf@o#pMPra1>FaV*jCJaBmC8nT!Qf5s00ptmgb11c6wI>JZ~M?&t~Imkand#GcG& zrMEP>@xO`hW|Wv|evz62+|HSwpL5oKa zgrfmjM>&9xL^(ZVMq3bR=)(mRhXF50rm`r<;1bL`<}~uh~{VW8Ds0G z{r^zfWB6?v;B@DwlArz`z%$+@>#ICaprXV)?5~d!0EAoEtStpmI*3(9u1n0E28b~8 zM_Dq+fd^CY}7_GchMc^FMRhv9^49?&(`D{WAX$qlAZ1qADXo-eqfnKG~AMQ2f zx!R=PP{*=x3ga)guVt_ROI(6tz_01(MuhXH3bcShd2ow**f#nRGxuPS2&m$bxki+( zdI4o08jI{I#}J%>nm@ifS#51L7Y1mIaF9{h^1b%q7mgmF35JB#GRZwwc2~2Zp`5M8 zJFfqCX74IcFStu+C9Lb-m2N`Ug@zt(30tNXykD$eHPwhg0Du}Gku$uhK36HKyO8P-T^<239ybM zX^8T5@t!txH5$mK#&FQ@pRlwZo251>|FYO`_KhI!g1r`Ll&fp&edM$@R3{ajCoq&} z7Fi_KbXNQITY%@w@z0S3n=JE!x+nTPD^tw@KlJT0Hp*Fzr`+gR1gHUr#Zk{C~ zvUiJ1FM%3&yo@sy)ib=3^$?~?Zucn7`Sjy}56weNO|LiqH5%)EAb#llm96VUSV<=8W zN+LXnZyjZc6LnB$#jUu{HoivM`6J9OZc|wB8_I>@q(7d>4|KT9Hd>1R-tI}gA`SF9 zHR01oX6aOMzT=$7AY;f(LZc{{?@(Nd3V&WAHhAQ-27a;xcI}vBCFze%jTn-?m2p`ukY>Fk6#rgvacowfLA_!8D0;}R*hFRbi9^x+nNh>{ zCrr<|J__AgzC%n39v->lJ6J!n-r32egdGiep?E9X2Tmc4R+ob2pc37^8)HcZmmhez zj=+D_v+$_ANjDkm9Q=B_Wdh{f{xS{eV|u}3Mow!}!bsJ$){rG-gB@CI5+NkC*8XG> zmpvr#c_;UT&WYgqm>C8uUrd4_!%Dy6Q5Qpu0Nj-^|9nB@~sWUGA z3PCh0V(Ug5ShkZ%`~FAjOFA9tbB60MWDlGcZP8cw928}+U_kfcv$+)tzM(s@si2py zQ@~^1+vCu#(0peJsXT=3A&$u*1 zZN51BWrfux5qp9tJI#R}0n&cuw%pHF;v7BVbvv|B@nt}>IduTrc=Oq6GpzrSZ_fJ1 zMz{jXUOWDODCQr2&ixneyh#Es*&G&DDqqe z%H=D4MPYo{pcV+po91ZO3f}=SXBoEd_8)$Xlr(IY8JU`hB;#j+BU;xsMrE;DYi^Z= z0J+CD1z{5Y#4%OdC?f5aYxpjGq4$`4;Nqriu+aS0Puhnz#vinb4BwD$2y&pWGw^YH zMk7%5M#K#S|B}ds#UjK&R?QxPjq}Ruk*(=-`VR1{Vf^ZBtRR~*?TVdqdQdEBx1Fvb zcuC#!Xlumaha}_$UveJ@7jTV6pKxip%Fhi>Dy*Y

SQ&?2wl7p9lOE^$k*RiM4J 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 literal 0 HcmV?d00001 diff --git a/test/src/main/assets/wav/2.wav b/test/src/main/assets/wav/2.wav new file mode 100644 index 0000000000000000000000000000000000000000..22a25d4a892fcad514461eac6a7d4f8df7a6fa7c GIT binary patch literal 179856 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 z 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 z�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≪B&d{nrHoGu+{D^FDi`A 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 YAdWyBfj9zj1mXz95r`x3{{?~n0k2kkQ~&?~ literal 0 HcmV?d00001 diff --git a/test/src/main/java/ai/guiji/duix/test/App.java b/test/src/main/java/ai/guiji/duix/test/App.java new file mode 100644 index 0000000..0c2a350 --- /dev/null +++ b/test/src/main/java/ai/guiji/duix/test/App.java @@ -0,0 +1,31 @@ +package ai.guiji.duix.test; + +import android.app.Application; +import android.text.TextUtils; + +import java.util.concurrent.TimeUnit; + +import okhttp3.OkHttpClient; + +public class App extends Application { + + public static App mApp; + private static OkHttpClient mOkHttpClient; + + @Override + public void onCreate() { + super.onCreate(); + mApp = this; + } + + public static OkHttpClient getOkHttpClient() { + if (mOkHttpClient == null) { + mOkHttpClient = new OkHttpClient.Builder() + .connectTimeout(15, TimeUnit.SECONDS) + .writeTimeout(15, TimeUnit.SECONDS) + .readTimeout(15, TimeUnit.SECONDS) + .build(); + } + return mOkHttpClient; + } +} diff --git a/test/src/main/java/ai/guiji/duix/test/audio/AudioRecorder.java b/test/src/main/java/ai/guiji/duix/test/audio/AudioRecorder.java new file mode 100644 index 0000000..a1d71bb --- /dev/null +++ b/test/src/main/java/ai/guiji/duix/test/audio/AudioRecorder.java @@ -0,0 +1,110 @@ +package ai.guiji.duix.test.audio; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.media.AudioFormat; +import android.media.AudioRecord; +import android.media.MediaRecorder; +import android.util.Log; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +import ai.guiji.duix.test.util.StringUtils; + +public class AudioRecorder { + + private final String TAG = getClass().getSimpleName(); + + private final Context mContext; + private AudioRecord mAudioRecorder; //录音器 + private final Executor mExecutor = Executors.newSingleThreadExecutor(); + private final RecorderCallback callback; + + public AudioRecorder(Context context, RecorderCallback callback){ + this.mContext = context; + this.callback = callback; + } + + @SuppressLint("MissingPermission") + public void start(){ + int sampleRateInHz = 16000; + int channelConfig = AudioFormat.CHANNEL_IN_MONO; + int audioFormat = AudioFormat.ENCODING_PCM_16BIT; + //20ms audio for 16k/16bit/mono +// int WAVE_FRAM_SIZE = 20 * 2 * 1 * SAMPLE_RATE / 1000; + int minBufferSize = AudioRecord.getMinBufferSize( + sampleRateInHz, + channelConfig, + audioFormat + ); + Log.d(TAG, "minBufferSize: " + minBufferSize); + mAudioRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, + sampleRateInHz, channelConfig, + audioFormat, + minBufferSize); + if (mAudioRecorder.getState() != AudioRecord.STATE_UNINITIALIZED){ + mAudioRecorder.startRecording(); + mExecutor.execute(() -> { + long startTime = System.currentTimeMillis(); + File cacheDir = mContext.getExternalCacheDir(); + if (!cacheDir.exists()){ + if (!cacheDir.mkdirs()) Log.e(TAG, "mkdirs fail path: " + cacheDir.getAbsolutePath()); + } + String pcmName = StringUtils.createFileName("record_", ".pcm"); + File pcmFile = new File(cacheDir, pcmName); + try (FileOutputStream outputStream = new FileOutputStream(pcmFile)) { + byte[] data = new byte[minBufferSize]; + while (mAudioRecorder.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING){ + int length = mAudioRecorder.read(data, 0, minBufferSize); + if (length > 0){ + outputStream.write(data, 0, length); + if (callback != null){ + callback.onReadData(data, 0, length); + } + } + } + Log.d(TAG, "Record done."); + long diff = System.currentTimeMillis() - startTime; + if (callback != null){ + if (diff > 200){ + callback.onFinish(pcmFile.getAbsolutePath()); + } else { + callback.onRecordError(-2, "too short!"); + } + } + } catch (Exception e) { + Log.e(TAG, "Record error: " + e); + if (callback != null){ + callback.onRecordError(-1, "Record error: " + e); + } + } + }); + } + } + + public void stop(){ + if (mAudioRecorder != null){ + if (mAudioRecorder.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING){ + mAudioRecorder.stop(); + } + } + } + + public void release(){ + if (mAudioRecorder != null){ + mAudioRecorder.release(); + mAudioRecorder = null; + } + } + + public interface RecorderCallback{ + void onReadData(byte[] data, int offsetInBytes, int length); + + void onRecordError(int code, String message); + + void onFinish(String path); + } +} diff --git a/test/src/main/java/ai/guiji/duix/test/audio/AudioResampler.java b/test/src/main/java/ai/guiji/duix/test/audio/AudioResampler.java new file mode 100644 index 0000000..2c913dc --- /dev/null +++ b/test/src/main/java/ai/guiji/duix/test/audio/AudioResampler.java @@ -0,0 +1,52 @@ +package ai.guiji.duix.test.audio; + +/** + * 简单线性插值重采样:24kHz 16bit mono -> 16kHz 16bit mono + * 用于将 Qwen-Omni-Realtime 输出的 24kHz 音频转换为 DUIX 所需的 16kHz + */ +public class AudioResampler { + + private static final int INPUT_RATE = 24000; + private static final int OUTPUT_RATE = 16000; + private static final double RATIO = (double) OUTPUT_RATE / INPUT_RATE; // 2/3 + + /** + * 将 24kHz 16bit 单声道 PCM 重采样为 16kHz + * + * @param input 24kHz 16bit mono PCM + * @return 16kHz 16bit mono PCM + */ + public static byte[] resample24kTo16k(byte[] input) { + if (input == null || input.length < 2) return new byte[0]; + + int inputSamples = input.length / 2; // 16bit = 2 bytes per sample + int outputSamples = (int) Math.ceil(inputSamples * RATIO); + + byte[] output = new byte[outputSamples * 2]; + + for (int i = 0; i < outputSamples; i++) { + double srcPos = i / RATIO; + int idx0 = (int) Math.floor(srcPos); + int idx1 = Math.min(idx0 + 1, inputSamples - 1); + double frac = srcPos - idx0; + + short s0 = getShortLE(input, idx0 * 2); + short s1 = getShortLE(input, idx1 * 2); + short interpolated = (short) (s0 + (s1 - s0) * frac); + putShortLE(output, i * 2, interpolated); + } + return output; + } + + private static short getShortLE(byte[] data, int offset) { + if (offset + 1 >= data.length) return 0; + return (short) ((data[offset] & 0xFF) | (data[offset + 1] << 8)); + } + + private static void putShortLE(byte[] data, int offset, short value) { + if (offset + 1 < data.length) { + data[offset] = (byte) (value & 0xFF); + data[offset + 1] = (byte) ((value >> 8) & 0xFF); + } + } +} diff --git a/test/src/main/java/ai/guiji/duix/test/audio/StreamingAudioRecorder.java b/test/src/main/java/ai/guiji/duix/test/audio/StreamingAudioRecorder.java new file mode 100644 index 0000000..da7b0b9 --- /dev/null +++ b/test/src/main/java/ai/guiji/duix/test/audio/StreamingAudioRecorder.java @@ -0,0 +1,106 @@ +package ai.guiji.duix.test.audio; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.media.AudioFormat; +import android.media.AudioRecord; +import android.media.MediaRecorder; +import android.util.Log; + +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * 流式麦克风录音器,用于实时将音频发送到 OmniRealtime API + * 16kHz, 16bit, mono - 符合 API 输入格式要求 + */ +public class StreamingAudioRecorder { + + private static final String TAG = "StreamingAudioRecorder"; + private static final int SAMPLE_RATE = 16000; + private static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO; + private static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT; + // 20ms 一帧: 16000 * 2 * 0.02 = 640 bytes, 使用 3200 与文档示例一致(100ms) + private static final int CHUNK_SIZE = 3200; + + private final Context mContext; + private AudioRecord mAudioRecord; + private final Executor mExecutor = Executors.newSingleThreadExecutor(); + private final StreamingCallback callback; + private final AtomicBoolean isRecording = new AtomicBoolean(false); + + public StreamingAudioRecorder(Context context, StreamingCallback callback) { + this.mContext = context; + this.callback = callback; + } + + @SuppressLint("MissingPermission") + public void start() { + if (isRecording.get()) { + Log.w(TAG, "Already recording"); + return; + } + int minBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT); + int bufferSize = Math.max(minBufferSize, CHUNK_SIZE * 2); + + mAudioRecord = new AudioRecord( + MediaRecorder.AudioSource.VOICE_COMMUNICATION, + SAMPLE_RATE, + CHANNEL_CONFIG, + AUDIO_FORMAT, + bufferSize + ); + + if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) { + Log.e(TAG, "AudioRecord init failed"); + if (callback != null) { + callback.onError("麦克风初始化失败"); + } + return; + } + + isRecording.set(true); + mAudioRecord.startRecording(); + + mExecutor.execute(() -> { + byte[] buffer = new byte[CHUNK_SIZE]; + while (isRecording.get() && mAudioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) { + int read = mAudioRecord.read(buffer, 0, buffer.length); + if (read > 0 && callback != null) { + byte[] data = new byte[read]; + System.arraycopy(buffer, 0, data, 0, read); + callback.onAudioData(data); + } + } + Log.d(TAG, "Recording thread ended"); + }); + } + + public void stop() { + isRecording.set(false); + if (mAudioRecord != null) { + if (mAudioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) { + mAudioRecord.stop(); + } + } + } + + public void release() { + stop(); + if (mAudioRecord != null) { + mAudioRecord.release(); + mAudioRecord = null; + } + } + + public boolean isRecording() { + return isRecording.get(); + } + + public interface StreamingCallback { + void onAudioData(byte[] pcmData); + + void onError(String message); + } +} diff --git a/test/src/main/java/ai/guiji/duix/test/camera/CameraFrameCapture.java b/test/src/main/java/ai/guiji/duix/test/camera/CameraFrameCapture.java new file mode 100644 index 0000000..b4815e3 --- /dev/null +++ b/test/src/main/java/ai/guiji/duix/test/camera/CameraFrameCapture.java @@ -0,0 +1,299 @@ +package ai.guiji.duix.test.camera; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.graphics.ImageFormat; +import android.hardware.camera2.CameraAccessException; +import android.hardware.camera2.CameraCaptureSession; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraDevice; +import android.hardware.camera2.CameraManager; +import android.hardware.camera2.CaptureRequest; +import android.media.Image; +import android.media.ImageReader; +import android.os.Handler; +import android.os.HandlerThread; +import android.util.Log; +import android.view.Surface; +import android.view.TextureView; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; + +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * 前置摄像头帧采集,按约 1 张/秒 输出 JPEG 供 OmniRealtime 使用 + * 推荐 480P/720P,单张不超过 500KB + */ +public class CameraFrameCapture { + + private static final String TAG = "CameraFrameCapture"; + private static final int TARGET_WIDTH = 640; // 480P 左右 + private static final int TARGET_HEIGHT = 480; + private static final int JPEG_QUALITY = 85; + private static final long CAPTURE_INTERVAL_MS = 1000; // 1 张/秒 + + private final Context context; + private final FrameCallback callback; + private final TextureView previewView; + private Surface previewSurface; + private CameraManager cameraManager; + private String frontCameraId; + private CameraDevice cameraDevice; + private CameraCaptureSession captureSession; + private ImageReader imageReader; + private HandlerThread backgroundThread; + private Handler backgroundHandler; + private final AtomicBoolean isCapturing = new AtomicBoolean(false); + private final AtomicBoolean isRunning = new AtomicBoolean(false); + + public CameraFrameCapture(Context context, FrameCallback callback) { + this(context, callback, null); + } + + public CameraFrameCapture(Context context, FrameCallback callback, TextureView previewView) { + this.context = context.getApplicationContext(); + this.callback = callback; + this.previewView = previewView; + } + + public void start() { + if (isRunning.get()) { + Log.w(TAG, "Already running"); + return; + } + if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { + if (callback != null) callback.onError("需要相机权限"); + return; + } + cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); + if (cameraManager == null) { + if (callback != null) callback.onError("相机不可用"); + return; + } + try { + for (String id : cameraManager.getCameraIdList()) { + CameraCharacteristics chars = cameraManager.getCameraCharacteristics(id); + Integer facing = chars.get(CameraCharacteristics.LENS_FACING); + if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) { + frontCameraId = id; + break; + } + } + if (frontCameraId == null) { + if (callback != null) callback.onError("未找到前置摄像头"); + return; + } + } catch (CameraAccessException e) { + Log.e(TAG, "Camera access error: " + e.getMessage()); + if (callback != null) callback.onError("相机访问失败: " + e.getMessage()); + return; + } + + backgroundThread = new HandlerThread("CameraFrameCapture"); + backgroundThread.start(); + backgroundHandler = new Handler(backgroundThread.getLooper()); + + imageReader = ImageReader.newInstance(TARGET_WIDTH, TARGET_HEIGHT, ImageFormat.JPEG, 2); + imageReader.setOnImageAvailableListener(reader -> { + try (Image image = reader.acquireLatestImage()) { + if (image != null && callback != null) { + byte[] jpeg = imageToJpeg(image); + if (jpeg != null && jpeg.length > 0 && jpeg.length < 500 * 1024) { + callback.onFrame(jpeg); + } + } + } catch (Exception e) { + Log.e(TAG, "Image process error: " + e.getMessage()); + } + }, backgroundHandler); + + isRunning.set(true); + if (previewView != null) { + if (previewView.isAvailable()) { + setupPreviewSurface(); + openCamera(); + } else { + previewView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { + @Override + public void onSurfaceTextureAvailable(android.graphics.SurfaceTexture surface, int width, int height) { + setupPreviewSurface(); + openCamera(); + } + @Override + public void onSurfaceTextureSizeChanged(android.graphics.SurfaceTexture surface, int width, int height) {} + @Override + public boolean onSurfaceTextureDestroyed(android.graphics.SurfaceTexture surface) { + return true; + } + @Override + public void onSurfaceTextureUpdated(android.graphics.SurfaceTexture surface) {} + }); + } + } else { + openCamera(); + } + } + + private void setupPreviewSurface() { + if (previewView != null && previewView.getSurfaceTexture() != null) { + android.graphics.SurfaceTexture st = previewView.getSurfaceTexture(); + st.setDefaultBufferSize(TARGET_WIDTH, TARGET_HEIGHT); + previewSurface = new Surface(st); + } + } + + private void openCamera() { + try { + cameraManager.openCamera(frontCameraId, new CameraDevice.StateCallback() { + @Override + public void onOpened(@NonNull CameraDevice camera) { + cameraDevice = camera; + createCaptureSession(); + } + + @Override + public void onDisconnected(@NonNull CameraDevice camera) { + camera.close(); + cameraDevice = null; + } + + @Override + public void onError(@NonNull CameraDevice camera, int error) { + Log.e(TAG, "Camera error: " + error); + camera.close(); + cameraDevice = null; + if (callback != null) callback.onError("相机打开失败"); + } + }, backgroundHandler); + } catch (CameraAccessException e) { + Log.e(TAG, "Open camera error: " + e.getMessage()); + if (callback != null) callback.onError("相机打开失败: " + e.getMessage()); + } catch (SecurityException e) { + Log.e(TAG, "Camera permission denied: " + e.getMessage()); + if (callback != null) callback.onError("需要相机权限"); + } + } + + private void createCaptureSession() { + if (cameraDevice == null || imageReader == null || !isRunning.get()) return; + try { + java.util.List surfaces = new java.util.ArrayList<>(); + surfaces.add(imageReader.getSurface()); + if (previewSurface != null) { + surfaces.add(previewSurface); + } + cameraDevice.createCaptureSession( + surfaces, + new CameraCaptureSession.StateCallback() { + @Override + public void onConfigured(@NonNull CameraCaptureSession session) { + captureSession = session; + isCapturing.set(true); + startPreview(); + scheduleNextCapture(); + } + + @Override + public void onConfigureFailed(@NonNull CameraCaptureSession session) { + Log.e(TAG, "Capture session configure failed"); + if (callback != null) callback.onError("相机配置失败"); + } + }, + backgroundHandler + ); + } catch (CameraAccessException e) { + Log.e(TAG, "Create session error: " + e.getMessage()); + } + } + + private void startPreview() { + if (captureSession == null || cameraDevice == null || previewSurface == null) return; + try { + CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); + builder.addTarget(previewSurface); + builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); + captureSession.setRepeatingRequest(builder.build(), null, backgroundHandler); + } catch (CameraAccessException e) { + Log.e(TAG, "Start preview error: " + e.getMessage()); + } + } + + private void scheduleNextCapture() { + if (!isCapturing.get() || !isRunning.get() || captureSession == null || cameraDevice == null) return; + try { + CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); + builder.addTarget(imageReader.getSurface()); + builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); + CaptureRequest request = builder.build(); + captureSession.capture(request, new CameraCaptureSession.CaptureCallback() { + @Override + public void onCaptureCompleted(@NonNull CameraCaptureSession session, + @NonNull android.hardware.camera2.CaptureRequest request, + @NonNull android.hardware.camera2.TotalCaptureResult result) { + if (isRunning.get()) { + backgroundHandler.postDelayed(CameraFrameCapture.this::scheduleNextCapture, CAPTURE_INTERVAL_MS); + } + } + }, backgroundHandler); + } catch (CameraAccessException e) { + Log.e(TAG, "Capture error: " + e.getMessage()); + } + } + + private byte[] imageToJpeg(Image image) { + Image.Plane[] planes = image.getPlanes(); + if (planes.length == 0) return null; + ByteBuffer buffer = planes[0].getBuffer(); + byte[] data = new byte[buffer.remaining()]; + buffer.get(data); + return data; + } + + public void stop() { + isRunning.set(false); + isCapturing.set(false); + try { + if (captureSession != null) { + captureSession.close(); + captureSession = null; + } + if (cameraDevice != null) { + cameraDevice.close(); + cameraDevice = null; + } + if (imageReader != null) { + imageReader.close(); + imageReader = null; + } + if (previewSurface != null) { + previewSurface.release(); + previewSurface = null; + } + } catch (Exception e) { + Log.e(TAG, "Stop error: " + e.getMessage()); + } + if (backgroundThread != null && backgroundThread.isAlive()) { + backgroundThread.quitSafely(); + try { + backgroundThread.join(500); + } catch (InterruptedException ignored) { + } + backgroundThread = null; + } + backgroundHandler = null; + } + + public boolean isRunning() { + return isRunning.get(); + } + + public interface FrameCallback { + void onFrame(byte[] jpegData); + + void onError(String message); + } +} diff --git a/test/src/main/java/ai/guiji/duix/test/net/SyncDownloadFile.java b/test/src/main/java/ai/guiji/duix/test/net/SyncDownloadFile.java new file mode 100644 index 0000000..b2dedf8 --- /dev/null +++ b/test/src/main/java/ai/guiji/duix/test/net/SyncDownloadFile.java @@ -0,0 +1,83 @@ +package ai.guiji.duix.test.net; + +import android.util.Log; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; + +import ai.guiji.duix.test.App; +import okhttp3.Call; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; + +/** + * 同步下载小文件,不要再UI线程里面直接调用 + */ +public class SyncDownloadFile { + + private String url; + private String path; + private Callback callback; + + public SyncDownloadFile(String url, String path, Callback callback) { + this.url = url; + this.path = path; + this.callback = callback; + } + + public boolean download() { + try { + Request request = new Request.Builder() + .url(url) + .build(); + Call call = App.getOkHttpClient().newCall(request); + + Response response = call.execute(); + if (response.code() == 200) { + ResponseBody body = response.body(); + if (body != null) { + long contentLength = body.contentLength(); + InputStream is = body.byteStream(); + File tmpFile = new File(path + ".tmp"); + File parent = tmpFile.getParentFile(); + if (parent != null && !parent.exists()) { + if (!parent.mkdirs()) { + return false; + } + } + if (tmpFile.exists()) { + tmpFile.delete(); + } + FileOutputStream fileOutputStream = new FileOutputStream(tmpFile); + long downloadLength = 0; + int len; + byte[] data = new byte[1024]; + while ((len = is.read(data)) != -1) { + fileOutputStream.write(data, 0, len); + downloadLength += len; + if (callback != null){ + callback.onProgress((int) (downloadLength * 100 / contentLength)); + } + } + fileOutputStream.flush(); + is.close(); + fileOutputStream.close(); + File target = new File(path); + if (tmpFile.renameTo(target)) { + return true; + } + } + } + } catch (Exception e) { + Log.e("123", "SyncDownloadFile error: " + e.getMessage()); + } + return false; + } + + public interface Callback { + void onProgress(int progress); + } + +} diff --git a/test/src/main/java/ai/guiji/duix/test/realtime/OmniRealtimeClient.java b/test/src/main/java/ai/guiji/duix/test/realtime/OmniRealtimeClient.java new file mode 100644 index 0000000..c09f74b --- /dev/null +++ b/test/src/main/java/ai/guiji/duix/test/realtime/OmniRealtimeClient.java @@ -0,0 +1,311 @@ +package ai.guiji.duix.test.realtime; + +import android.util.Base64; +import android.util.Log; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.WebSocket; +import okhttp3.WebSocketListener; + +/** + * Qwen-Omni-Realtime WebSocket 客户端 + * 接入 qwen3-omni-flash-realtime-2025-12-01 模型 + */ +public class OmniRealtimeClient { + + private static final String TAG = "OmniRealtimeClient"; + + // Demo 配置(硬编码) + private static final String API_KEY = "sk-7c32083ace99472e97209e611b9ecbb1"; + private static final String WS_URL = "wss://dashscope.aliyuncs.com/api-ws/v1/realtime?model=qwen3-omni-flash-realtime-2025-12-01"; + + private final OkHttpClient okHttpClient; + private WebSocket webSocket; + private final Callback callback; + private final AtomicBoolean isConnected = new AtomicBoolean(false); + private final AtomicBoolean userSpeaking = new AtomicBoolean(false); + + public OmniRealtimeClient(Callback callback) { + this.callback = callback; + this.okHttpClient = new OkHttpClient.Builder() + .connectTimeout(30, TimeUnit.SECONDS) + .readTimeout(120, TimeUnit.MINUTES) + .writeTimeout(30, TimeUnit.SECONDS) + .pingInterval(30, TimeUnit.SECONDS) + .build(); + } + + public void connect() { + if (isConnected.get()) { + Log.w(TAG, "Already connected"); + return; + } + Request request = new Request.Builder() + .url(WS_URL) + .addHeader("Authorization", "Bearer " + API_KEY) + .build(); + + webSocket = okHttpClient.newWebSocket(request, new WebSocketListener() { + @Override + public void onOpen(WebSocket webSocket, Response response) { + Log.i(TAG, "WebSocket connected"); + isConnected.set(true); + sendSessionUpdate(); + if (callback != null) { + callback.onConnected(); + } + } + + @Override + public void onMessage(WebSocket webSocket, String text) { + handleMessage(text); + } + + @Override + public void onFailure(WebSocket webSocket, Throwable t, Response response) { + Log.e(TAG, "WebSocket error: " + t.getMessage()); + isConnected.set(false); + if (callback != null) { + callback.onError("连接失败: " + t.getMessage()); + } + } + + @Override + public void onClosing(WebSocket webSocket, int code, String reason) { + Log.i(TAG, "WebSocket closing: " + code + " " + reason); + } + + @Override + public void onClosed(WebSocket webSocket, int code, String reason) { + Log.i(TAG, "WebSocket closed: " + code + " " + reason); + isConnected.set(false); + if (callback != null) { + callback.onDisconnected(); + } + } + }); + } + + private void sendSessionUpdate() { + try { + JSONObject session = new JSONObject(); + session.put("modalities", new org.json.JSONArray().put("text").put("audio")); + session.put("voice", "Ethan"); + session.put("input_audio_format", "pcm"); + session.put("output_audio_format", "pcm"); + session.put("instructions", "你是一名面向中国老年群体的心理陪伴 AI。你的职责是为老人提供温和、耐心、尊重、稳定的情感陪伴、情绪支持、回忆唤起、生活关怀和风险识别服务。你不是医生,也不是心理治疗师,不能替代专业诊疗,但应在必要时建议联系家属、社区、医生或急救资源。\n" + + "\n" + + "请始终遵循以下原则:\n" + + "\n" + + "先共情,再回应问题;\n" + + "\n" + + "先接住情绪,再给建议;\n" + + "\n" + + "使用简短、朴素、生活化的中文,始终用“您”称呼;\n" + + "\n" + + "不说教、不训诫、不否定、不敷衍;\n" + + "\n" + + "不把老人当小孩,不制造虚假亲密;\n" + + "\n" + + "一次不提供超过两个建议;\n" + + "\n" + + "鼓励老人表达感受,可适度引导回忆人生经历、兴趣、家庭和过往成就;\n" + + "\n" + + "对孤独、丧偶、被忽视、无价值感、失眠、焦虑、怕拖累家人等议题保持高度敏感;\n" + + "\n" + + "若出现自杀、自伤、重度绝望、幻觉妄想、意识混乱、虐待、严重医疗异常等风险,必须立即建议联系真人帮助和专业机构;\n" + + "\n" + + "不编造医疗知识、政策信息、机构电话,不确定时明确说明。\n" + + "\n" + + "你的回复风格应温和、平稳、尊重、有耐心。每次回答尽量包含:一句共情、一句理解或复述、一句温和追问或一个微小建议。核心目标是让老人感到:我被听见了,我被尊重了,有人愿意陪我。"); + + // 服务端 VAD 模式 + JSONObject turnDetection = new JSONObject(); + turnDetection.put("type", "server_vad"); + turnDetection.put("threshold", 0.5); + turnDetection.put("silence_duration_ms", 800); + session.put("turn_detection", turnDetection); + + JSONObject event = new JSONObject(); + event.put("event_id", "event_" + System.currentTimeMillis()); + event.put("type", "session.update"); + event.put("session", session); + + sendEvent(event); + } catch (JSONException e) { + Log.e(TAG, "Failed to build session.update: " + e.getMessage()); + } + } + + private void handleMessage(String text) { + try { + JSONObject event = new JSONObject(text); + String type = event.optString("type", ""); + + switch (type) { + case "session.created": + case "session.updated": + Log.d(TAG, "Session: " + type); + break; + + case "input_audio_buffer.speech_started": + Log.d(TAG, "User started speaking"); + userSpeaking.set(true); + if (callback != null) { + callback.onUserSpeechStarted(); + } + break; + + case "input_audio_buffer.speech_stopped": + Log.d(TAG, "User stopped speaking"); + userSpeaking.set(false); + if (callback != null) { + callback.onUserSpeechStopped(); + } + break; + + case "conversation.item.input_audio_transcription.completed": + String userTranscript = event.optString("transcript", ""); + Log.d(TAG, "User said: " + userTranscript); + if (callback != null) { + callback.onUserTranscript(userTranscript); + } + break; + + case "response.audio_transcript.delta": + String textDelta = event.optString("delta", ""); + if (callback != null && !textDelta.isEmpty()) { + callback.onAssistantTextDelta(textDelta); + } + break; + + case "response.audio_transcript.done": + String fullTranscript = event.optString("transcript", ""); + Log.d(TAG, "Assistant said: " + fullTranscript); + if (callback != null) { + callback.onAssistantTranscriptDone(fullTranscript); + } + break; + + case "response.audio.delta": + String audioB64 = event.optString("delta", ""); + if (!audioB64.isEmpty() && callback != null && !userSpeaking.get()) { + byte[] audioData = Base64.decode(audioB64, Base64.NO_WRAP); + callback.onAssistantAudioDelta(audioData); + } + break; + + case "response.audio.done": + Log.d(TAG, "Audio generation done"); + if (callback != null) { + callback.onAssistantAudioDone(); + } + break; + + case "response.done": + Log.d(TAG, "Response done"); + if (callback != null) { + callback.onResponseDone(); + } + break; + + case "error": + String errMsg = event.optJSONObject("error") != null + ? event.optJSONObject("error").optString("message", "Unknown error") + : "Unknown error"; + Log.e(TAG, "Server error: " + errMsg); + if (callback != null) { + callback.onError(errMsg); + } + break; + + default: + Log.v(TAG, "Unhandled event: " + type); + } + } catch (JSONException e) { + Log.e(TAG, "Parse message error: " + e.getMessage()); + } + } + + public void appendAudio(byte[] pcmData) { + if (!isConnected.get() || webSocket == null) return; + try { + String audioB64 = Base64.encodeToString(pcmData, Base64.NO_WRAP); + JSONObject event = new JSONObject(); + event.put("event_id", "event_" + System.currentTimeMillis()); + event.put("type", "input_audio_buffer.append"); + event.put("audio", audioB64); + sendEvent(event); + } catch (JSONException e) { + Log.e(TAG, "Failed to append audio: " + e.getMessage()); + } + } + + /** + * 向图像缓冲区追加图像数据(用于视频通话) + * 图片格式: JPG/JPEG,推荐 480P 或 720P,单张不超过 500KB + */ + public void appendImage(byte[] jpegData) { + if (!isConnected.get() || webSocket == null) return; + try { + String imageB64 = Base64.encodeToString(jpegData, Base64.NO_WRAP); + JSONObject event = new JSONObject(); + event.put("event_id", "event_" + System.currentTimeMillis()); + event.put("type", "input_image_buffer.append"); + event.put("image", imageB64); + sendEvent(event); + } catch (JSONException e) { + Log.e(TAG, "Failed to append image: " + e.getMessage()); + } + } + + private void sendEvent(JSONObject event) { + if (webSocket != null && isConnected.get()) { + webSocket.send(event.toString()); + } + } + + public void disconnect() { + if (webSocket != null) { + webSocket.close(1000, "bye"); + webSocket = null; + } + isConnected.set(false); + } + + public boolean isConnected() { + return isConnected.get(); + } + + public interface Callback { + void onConnected(); + + void onDisconnected(); + + void onError(String message); + + void onUserSpeechStarted(); + + void onUserSpeechStopped(); + + void onUserTranscript(String transcript); + + void onAssistantTextDelta(String delta); + + void onAssistantTranscriptDone(String transcript); + + void onAssistantAudioDelta(byte[] pcmData); + + void onAssistantAudioDone(); + + void onResponseDone(); + } +} diff --git a/test/src/main/java/ai/guiji/duix/test/render/DebugSink.java b/test/src/main/java/ai/guiji/duix/test/render/DebugSink.java new file mode 100644 index 0000000..65dcd41 --- /dev/null +++ b/test/src/main/java/ai/guiji/duix/test/render/DebugSink.java @@ -0,0 +1,24 @@ +package ai.guiji.duix.test.render; + +import ai.guiji.duix.sdk.client.bean.ImageFrame; +import ai.guiji.duix.sdk.client.render.RenderSink; + +public class DebugSink implements RenderSink { + + VideoFrameCallback callback; + + public DebugSink(VideoFrameCallback callback){ + this.callback = callback; + } + + @Override + public void onVideoFrame(ImageFrame imageFrame) { + if (callback != null){ + callback.onVideoFrame(imageFrame); + } + } + + public interface VideoFrameCallback{ + void onVideoFrame(ImageFrame imageFrame); + } +} diff --git a/test/src/main/java/ai/guiji/duix/test/service/StorageService.java b/test/src/main/java/ai/guiji/duix/test/service/StorageService.java new file mode 100644 index 0000000..6bd407c --- /dev/null +++ b/test/src/main/java/ai/guiji/duix/test/service/StorageService.java @@ -0,0 +1,216 @@ +package ai.guiji.duix.test.service; + +import android.content.Context; +import android.content.res.AssetManager; +import android.os.Environment; +import android.util.Log; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +import ai.guiji.duix.sdk.client.util.MD5Util; +import ai.guiji.duix.test.net.SyncDownloadFile; +import ai.guiji.duix.test.util.StringUtils; +import ai.guiji.duix.test.util.ZipUtil; + + +public class StorageService { + + public interface Callback { + + void onDownloadProgress(int progress); + + void onUnzipProgress(int progress); + + void onComplete(String path); + + void onError(String msg); + } + + /** + * 下载zip文件并解压 + * + * @param context + * @param url + * @param targetPath + * @param uuid + * @param callback + */ + public static void downloadAndUnzip(Context context, String url, String targetPath, String uuid, Callback callback, boolean deleteZip) { + Executor executor = Executors.newSingleThreadExecutor(); + executor.execute(() -> { + File cacheDir = context.getExternalCacheDir(); + if (!cacheDir.exists()) { + cacheDir.mkdirs(); + } + File zipFile = new File(cacheDir, MD5Util.string2MD5(url)); + boolean result = true; + if (!zipFile.exists()) { + Log.d("123", "zip not found, try download."); + result = new SyncDownloadFile(url, zipFile.getAbsolutePath(), callback::onDownloadProgress).download(); + Log.d("123", "download file success."); + } else { + Log.d("123", "found cache zip file."); + } + if (result) { + Log.e("123", "try unzip file."); + File targetDirFile = new File(targetPath); + if (targetDirFile.exists()) { + Log.e("123", "delete old files."); + deleteContents(targetDirFile); + } + // 拿到目标路径的父级 + File targetParentDir = new File(targetPath).getParentFile(); + if (!targetParentDir.exists()) { + targetParentDir.mkdirs(); + } + result = ZipUtil.unzip(zipFile.getAbsolutePath(), targetParentDir.getAbsolutePath(), callback::onUnzipProgress); + if (result) { + Log.d("123", "unzip file complete."); + // 这里时候targetDirFile应该是存在的 + if (targetDirFile.exists()) { + File uuidFile = new File(targetDirFile, "uuid"); + try { + OutputStream out = new FileOutputStream(uuidFile); + byte[] uuidBytes = uuid.getBytes(); + out.write(uuidBytes, 0, uuidBytes.length); + out.flush(); + out.close(); + if (deleteZip && zipFile.exists()){ + zipFile.delete(); + } + callback.onComplete(targetPath); + } catch (Exception e) { + callback.onError("touch uuid file error!"); + } + } else { + callback.onError("unzip dir not found!"); + } + } else { + if (zipFile.exists()){ + zipFile.delete(); + } + callback.onError("unzip file error!"); + } + } else { + callback.onError("zip file download error"); + } + }); + } + + /** + * 从assets拷贝文件到sdcard + * + * @param context + * @param sourcePath 在assets目录的路径 + * @param targetPath 在sd卡的路径 + */ + public static void unpack(Context context, String sourcePath, final String targetPath, final Callback callback) { + Executor executor = Executors.newSingleThreadExecutor(); + executor.execute(() -> { + try { + final String outputPath = sync(context, sourcePath, targetPath); + callback.onComplete(outputPath); + } catch (final IOException e) { + callback.onError("拷贝文件异常: " + e); + } + }); + } + + public static boolean deleteContents(File dir) { + File[] files = dir.listFiles(); + boolean success = true; + if (files != null) { + for (File file : files) { + if (file.isDirectory()) { + success &= deleteContents(file); + } + if (!file.delete()) { + success = false; + } + } + } + return success; + } + + private static String sync(Context context, String sourcePath, String targetPath) throws IOException { + + AssetManager assetManager = context.getAssets(); + + File externalFilesDir = context.getExternalFilesDir(null); + if (externalFilesDir == null) { + throw new IOException("cannot get external files dir, " + + "external storage state is " + Environment.getExternalStorageState()); + } + + File targetDir = new File(externalFilesDir, targetPath); + String resultPath = new File(targetDir, sourcePath).getAbsolutePath(); + String sourceUUID = readLine(assetManager.open(sourcePath + "/uuid")); + try { + String targetUUID = readLine(new FileInputStream(new File(targetDir, sourcePath + "/uuid"))); + if (targetUUID.equals(sourceUUID)) return resultPath; + } catch (FileNotFoundException e) { + // ignore + } + deleteContents(targetDir); + + copyAssets(assetManager, sourcePath, targetDir); + + // Copy uuid + copyFile(assetManager, sourcePath + "/uuid", targetDir); + + return resultPath; + } + + private static String readLine(InputStream is) throws IOException { + return new BufferedReader(new InputStreamReader(is)).readLine(); + } + + private static void copyAssets(AssetManager assetManager, String path, File outPath) throws IOException { + String[] assets = assetManager.list(path); + if (assets == null) { + return; + } + if (assets.length == 0) { + if (!path.endsWith("uuid")) + copyFile(assetManager, path, outPath); + } else { + File dir = new File(outPath, path); + if (!dir.exists()) { + Log.d("123", "Making directory " + dir.getAbsolutePath()); + if (!dir.mkdirs()) { + Log.d("123", "Failed to create directory " + dir.getAbsolutePath()); + } + } + for (String asset : assets) { + copyAssets(assetManager, path + "/" + asset, outPath); + } + } + } + + private static void copyFile(AssetManager assetManager, String fileName, File outPath) throws IOException { + InputStream in; + + Log.d("123", "Copy " + fileName + " to " + outPath); + in = assetManager.open(fileName); + OutputStream out = new FileOutputStream(outPath + "/" + fileName); + + byte[] buffer = new byte[4000]; + int read; + while ((read = in.read(buffer)) != -1) { + out.write(buffer, 0, read); + } + in.close(); + out.close(); + } + +} diff --git a/test/src/main/java/ai/guiji/duix/test/ui/activity/BaseActivity.java b/test/src/main/java/ai/guiji/duix/test/ui/activity/BaseActivity.java new file mode 100644 index 0000000..a3b1597 --- /dev/null +++ b/test/src/main/java/ai/guiji/duix/test/ui/activity/BaseActivity.java @@ -0,0 +1,119 @@ +package ai.guiji.duix.test.ui.activity; + +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Message; +import android.util.Log; +import android.view.WindowManager; + +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.content.ContextCompat; + +import java.util.ArrayList; +import java.util.List; + + +public abstract class BaseActivity extends AppCompatActivity implements Handler.Callback { + + public final String TAG = getClass().getName(); + protected BaseActivity mContext; + protected Handler mHandler; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mContext = this; + HandlerThread mHandlerThread = new HandlerThread(TAG); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper(), this); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + Log.i(TAG, "onDestroy"); + if (mHandler != null && mHandler.getLooper() != null) { + mHandler.getLooper().quit(); + } + } + + @Override + public boolean handleMessage(@NonNull Message msg) { + onMessage(msg); + return false; + } + + // try abstract + protected void onMessage(@NonNull Message msg) { + + } + + protected void keepScreenOn() { + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } + + private String[] mRequestPermissions; + private int mRequestPermissionCode; + ActivityResultLauncher permissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), + result -> { + boolean hasDeny = false; + for (String permission : mRequestPermissions) { + if (null == permission) { + continue; + } + if (ContextCompat.checkSelfPermission(mContext, permission) != + PackageManager.PERMISSION_GRANTED) { + hasDeny = true; + } + } + if (hasDeny) { + permissionsGet(false, mRequestPermissionCode); + } else { + permissionsGet(true, mRequestPermissionCode); + } + }); + + //申请权限 + public void requestPermission(String[] permissions, int code) { + if (null == permissions) { + permissionsGet(true, code); + return; + } + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + permissionsGet(true, code); + return; + } + mRequestPermissions = permissions; + mRequestPermissionCode = code; + List requestPermissions = new ArrayList<>(); + for (String permission : permissions) { + if (ContextCompat.checkSelfPermission(mContext, permission) != + PackageManager.PERMISSION_GRANTED) { + requestPermissions.add(permission); + } + } + if (0 != requestPermissions.size()) { + String[] permissionArray = new String[requestPermissions.size()]; + for (int i = 0; i < requestPermissions.size(); i++) { + permissionArray[i] = requestPermissions.get(i); + } + permissionLauncher.launch(permissionArray); + } else { + permissionsGet(true, mRequestPermissionCode); + } + } + + //申请权限回调 + public void permissionsGet(boolean get, int code) { + + } + + +} diff --git a/test/src/main/java/ai/guiji/duix/test/ui/activity/CallActivity.kt b/test/src/main/java/ai/guiji/duix/test/ui/activity/CallActivity.kt new file mode 100644 index 0000000..508ebfa --- /dev/null +++ b/test/src/main/java/ai/guiji/duix/test/ui/activity/CallActivity.kt @@ -0,0 +1,490 @@ +package ai.guiji.duix.test.ui.activity + +import ai.guiji.duix.sdk.client.Constant +import ai.guiji.duix.sdk.client.DUIX +import ai.guiji.duix.sdk.client.loader.ModelInfo +import ai.guiji.duix.sdk.client.render.DUIXRenderer +import ai.guiji.duix.sdk.client.thread.RenderThread +import ai.guiji.duix.test.R +import ai.guiji.duix.test.audio.AudioResampler +import ai.guiji.duix.test.audio.StreamingAudioRecorder +import ai.guiji.duix.test.camera.CameraFrameCapture +import ai.guiji.duix.test.databinding.ActivityCallBinding +import ai.guiji.duix.test.realtime.OmniRealtimeClient +import ai.guiji.duix.test.ui.adapter.MotionAdapter +import ai.guiji.duix.test.ui.dialog.AudioRecordDialog +import ai.guiji.duix.test.util.StringUtils +import android.Manifest +import android.annotation.SuppressLint +import android.opengl.GLSurfaceView +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.text.TextUtils +import android.util.Log +import android.view.View +import android.widget.CompoundButton +import android.widget.Toast +import androidx.core.content.ContextCompat +import com.bumptech.glide.Glide +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream + + +class CallActivity : BaseActivity() { + + companion object { + const val GL_CONTEXT_VERSION = 2 + } + + private var modelUrl = "" + private var debug = false + private var mMessage = "" + + @SuppressLint("SetTextI18n") + private fun applyMessage(msg: String){ + if (debug){ + runOnUiThread { + binding.tvDebug.visibility = View.VISIBLE + if (mMessage.length > 10000){ + mMessage = "" + } + mMessage = "${StringUtils.dateToStringMS4()} $msg\n$mMessage" + binding.tvDebug.text = mMessage + } + } + + } + + private lateinit var binding: ActivityCallBinding + private var duix: DUIX? = null + private var mDUIXRender: DUIXRenderer? = null + private var mModelInfo: ModelInfo?=null // 加载的模型信息 + + // AI 实时对话 + private var omniClient: OmniRealtimeClient? = null + private var streamingRecorder: StreamingAudioRecorder? = null + private var cameraFrameCapture: CameraFrameCapture? = null + private var isAIConversationActive = false + private var isCameraEnabled = false + private val mainHandler = Handler(Looper.getMainLooper()) + private var assistantTextBuffer = StringBuilder() + private var hasStartedPushForResponse = false + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + keepScreenOn() +// val audioManager = mContext.getSystemService(AUDIO_SERVICE) as AudioManager +// audioManager.mode = AudioManager.MODE_IN_COMMUNICATION +// audioManager.isSpeakerphoneOn = true + binding = ActivityCallBinding.inflate(layoutInflater) + setContentView(binding.root) + + modelUrl = intent.getStringExtra("modelUrl") ?: "" + debug = intent.getBooleanExtra("debug", false) + + Glide.with(mContext).load("file:///android_asset/bg/bg1.png").into(binding.ivBg) + + binding.glTextureView.setEGLContextClientVersion(GL_CONTEXT_VERSION) + binding.glTextureView.setEGLConfigChooser(8, 8, 8, 8, 16, 0) +// binding.glTextureView.preserveEGLContextOnPause = true + binding.glTextureView.isOpaque = false + + binding.switchMute.setOnCheckedChangeListener(object : CompoundButton.OnCheckedChangeListener { + override fun onCheckedChanged( + buttonView: CompoundButton?, + isChecked: Boolean, + ) { + if (isChecked) { + duix?.setVolume(0.0F) + } else { + duix?.setVolume(1.0F) + } + } + }) + + binding.btnRecord.setOnClickListener { + requestPermission(arrayOf(Manifest.permission.RECORD_AUDIO), 1) + } + + binding.btnPlayPCM.setOnClickListener { + applyMessage("start play pcm") + playPCMStream() + } + + binding.btnPlayWAV.setOnClickListener { + applyMessage("start play wav") + playWAVFile() + } + + binding.btnRandomMotion.setOnClickListener { + applyMessage("start random motion") + duix?.startRandomMotion(true) + } + binding.btnAIConversation.setOnClickListener { + requestPermission(arrayOf(Manifest.permission.RECORD_AUDIO), 2) + } + + binding.btnCameraToggle.setOnClickListener { + if (isCameraEnabled) { + toggleCamera() + } else { + requestPermission(arrayOf(Manifest.permission.CAMERA), 3) + } + } + + mDUIXRender = + DUIXRenderer( + mContext, + binding.glTextureView + ) + binding.glTextureView.setRenderer(mDUIXRender) + binding.glTextureView.renderMode = + GLSurfaceView.RENDERMODE_WHEN_DIRTY // 一定要在设置完Render之后再调用 + + duix = DUIX(mContext, modelUrl, mDUIXRender) { event, msg, info -> + when (event) { + Constant.CALLBACK_EVENT_INIT_READY -> { + mModelInfo = info as ModelInfo + Log.i(TAG, "CALLBACK_EVENT_INIT_READY: $mModelInfo") + initOk() + } + + Constant.CALLBACK_EVENT_INIT_ERROR -> { + runOnUiThread { + applyMessage("init error: $msg") + Log.e(TAG, "CALLBACK_EVENT_INIT_ERROR: $msg") + Toast.makeText(mContext, "Initialization exception: $msg", Toast.LENGTH_SHORT).show() + } + } + + Constant.CALLBACK_EVENT_AUDIO_PLAY_START -> { + applyMessage("callback audio play start") + Log.i(TAG, "CALLBACK_EVENT_AUDIO_PLAY_START") + } + + Constant.CALLBACK_EVENT_AUDIO_PLAY_END -> { + applyMessage("callback audio play end") + Log.i(TAG, "CALLBACK_EVENT_PLAY_END") + } + + Constant.CALLBACK_EVENT_AUDIO_PLAY_ERROR -> { + applyMessage("callback audio play error: $msg") + Log.e(TAG, "CALLBACK_EVENT_PLAY_ERROR: $msg") + } + + Constant.CALLBACK_EVENT_MOTION_START -> { + applyMessage("callback motion play start") + Log.e(TAG, "CALLBACK_EVENT_MOTION_START") + } + + Constant.CALLBACK_EVENT_MOTION_END -> { + applyMessage("callback motion play end") + Log.e(TAG, "CALLBACK_EVENT_MOTION_END") + } + } + } + // Rendering status callback +// duix?.setReporter(object : RenderThread.Reporter { +// override fun onRenderStat( +// resultCode: Int, +// isLip: Boolean, +// useTime: Long, +// ) { +// +// } +// }) + applyMessage("start init") + duix?.init() + } + + private fun initOk() { + Log.i(TAG, "init ok") + applyMessage("init ok") + runOnUiThread { + binding.btnRecord.isEnabled = true + binding.btnPlayPCM.isEnabled = true + binding.btnPlayWAV.isEnabled = true + binding.switchMute.isEnabled = true + binding.btnAIConversation.isEnabled = true + + if (debug) { + binding.btnPlayPCM.visibility = View.VISIBLE + binding.btnPlayWAV.visibility = View.VISIBLE + } + + mModelInfo?.let { modelInfo -> + if (modelInfo.motionRegions.isNotEmpty()) { + val names = ArrayList() + for (motion in modelInfo.motionRegions){ + if (!TextUtils.isEmpty(motion.name) && "unknown" != motion.name){ + names.add(motion.name) + } + } + // Named action regions + if (names.isNotEmpty()){ + val motionAdapter = MotionAdapter(names, object : MotionAdapter.Callback{ + override fun onClick(name: String, now: Boolean) { + applyMessage("start [${name}] motion") + duix?.startMotion(name, now) + } + }) + binding.rvMotion.adapter = motionAdapter + } + binding.btnRandomMotion.visibility = View.VISIBLE + binding.tvMotionTips.visibility = View.VISIBLE + } + } + } + } + + + override fun onDestroy() { + super.onDestroy() + stopAIConversation() + duix?.release() + } + + private fun playPCMStream(){ + val thread = Thread { + duix?.startPush() + val inputStream = assets.open("pcm/2.pcm") + val buffer = ByteArray(320) + var length: Int + while (inputStream.read(buffer).also { length = it } > 0){ + val data = buffer.copyOfRange(0, length) + duix?.pushPcm(data) + } + duix?.stopPush() + inputStream.close() + } + thread.start() + } + + private fun playWAVFile(){ + val thread = Thread { + val wavName = "1.wav" + val wavFile = File(mContext.externalCacheDir, wavName) + if (!wavFile.exists()){ + // copy assets -> sd card + val inputStream = assets.open("wav/$wavName") + if (!mContext.externalCacheDir!!.exists()){ + mContext.externalCacheDir!!.mkdirs() + } + val out = FileOutputStream(wavFile) + val buffer = ByteArray(1024) + var length: Int + while ((inputStream.read(buffer).also { length = it }) > 0) { + out.write(buffer, 0, length) + } + out.close() + inputStream.close() + } + duix?.playAudio(wavFile.absolutePath) + } + thread.start() + } + + override fun permissionsGet(get: Boolean, code: Int) { + super.permissionsGet(get, code) + when (code) { + 1 -> if (get) showRecordDialog() else Toast.makeText(mContext, R.string.need_permission_continue, Toast.LENGTH_SHORT).show() + 2 -> if (get) toggleAIConversation() else Toast.makeText(mContext, R.string.need_permission_continue, Toast.LENGTH_SHORT).show() + 3 -> if (get) toggleCamera() else Toast.makeText(mContext, R.string.need_permission_continue, Toast.LENGTH_SHORT).show() + } + } + + private fun toggleAIConversation() { + if (isAIConversationActive) { + stopAIConversation() + } else { + startAIConversation() + } + } + + private fun startAIConversation() { + if (duix?.isReady() != true) { + Toast.makeText(mContext, "数字人未就绪", Toast.LENGTH_SHORT).show() + return + } + applyMessage("AI对话: 连接中...") + binding.tvSubtitle.visibility = View.VISIBLE + binding.tvSubtitle.text = "正在连接..." + binding.btnAIConversation.text = getString(R.string.ai_fab_stop) + + omniClient = OmniRealtimeClient(object : OmniRealtimeClient.Callback { + override fun onConnected() { + mainHandler.post { + binding.tvSubtitle.text = "已连接,请对着麦克风说话" + binding.btnCameraToggle.visibility = View.VISIBLE + binding.btnCameraToggle.background = ContextCompat.getDrawable(mContext, R.drawable.shape_circle_camera_off) + binding.btnCameraToggle.contentDescription = getString(R.string.camera_off) + isCameraEnabled = false + applyMessage("AI对话: 已连接") + streamingRecorder = StreamingAudioRecorder(mContext, object : StreamingAudioRecorder.StreamingCallback { + override fun onAudioData(pcmData: ByteArray) { + omniClient?.appendAudio(pcmData) + } + override fun onError(message: String) { + mainHandler.post { + Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show() + } + } + }) + streamingRecorder?.start() + } + } + + override fun onDisconnected() { + mainHandler.post { stopAIConversation() } + } + + override fun onError(message: String) { + mainHandler.post { + Toast.makeText(mContext, "AI错误: $message", Toast.LENGTH_SHORT).show() + binding.tvSubtitle.text = "错误: $message" + } + } + + override fun onUserSpeechStarted() { + mainHandler.post { + binding.tvSubtitle.text = "正在聆听..." + } + } + + override fun onUserSpeechStopped() { + mainHandler.post { + binding.tvSubtitle.text = "思考中..." + } + } + + override fun onUserTranscript(transcript: String) { + mainHandler.post { + binding.tvSubtitle.text = "您: $transcript" + } + } + + override fun onAssistantTextDelta(delta: String) { + mainHandler.post { + assistantTextBuffer.append(delta) + binding.tvSubtitle.text = assistantTextBuffer.toString() + } + } + + override fun onAssistantTranscriptDone(transcript: String) { + mainHandler.post { + assistantTextBuffer.clear() + assistantTextBuffer.append(transcript) + binding.tvSubtitle.text = transcript + } + } + + override fun onAssistantAudioDelta(pcmData: ByteArray) { + if (!hasStartedPushForResponse) { + hasStartedPushForResponse = true + duix?.startPush() + } + val resampled = AudioResampler.resample24kTo16k(pcmData) + if (resampled.isNotEmpty()) { + duix?.pushPcm(resampled) + } + } + + override fun onAssistantAudioDone() { + if (hasStartedPushForResponse) { + duix?.stopPush() + hasStartedPushForResponse = false + } + } + + override fun onResponseDone() { + mainHandler.post { + if (hasStartedPushForResponse) { + duix?.stopPush() + hasStartedPushForResponse = false + } + assistantTextBuffer.clear() + } + } + }) + + isAIConversationActive = true + omniClient?.connect() + } + + private fun stopAIConversation() { + isAIConversationActive = false + stopCamera() + streamingRecorder?.release() + streamingRecorder = null + omniClient?.disconnect() + omniClient = null + duix?.stopAudio() + assistantTextBuffer.clear() + + mainHandler.post { + if (!isFinishing) { + binding.btnAIConversation.text = getString(R.string.ai_fab_start) + binding.btnCameraToggle.visibility = View.GONE + binding.tvSubtitle.visibility = View.GONE + binding.tvSubtitle.text = "" + applyMessage("AI对话: 已结束") + } + } + } + + private fun toggleCamera() { + if (!isAIConversationActive || omniClient == null) return + isCameraEnabled = !isCameraEnabled + if (isCameraEnabled) { + binding.cameraPreview.visibility = View.VISIBLE + cameraFrameCapture = CameraFrameCapture(mContext, object : CameraFrameCapture.FrameCallback { + override fun onFrame(jpegData: ByteArray) { + omniClient?.appendImage(jpegData) + } + override fun onError(message: String) { + mainHandler.post { + Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show() + stopCamera() + } + } + }, binding.cameraPreview) + cameraFrameCapture?.start() + binding.btnCameraToggle.background = ContextCompat.getDrawable(mContext, R.drawable.shape_circle_camera_on) + binding.btnCameraToggle.contentDescription = getString(R.string.camera_on) + } else { + stopCamera() + binding.btnCameraToggle.background = ContextCompat.getDrawable(mContext, R.drawable.shape_circle_camera_off) + binding.btnCameraToggle.contentDescription = getString(R.string.camera_off) + } + } + + private fun stopCamera() { + cameraFrameCapture?.stop() + cameraFrameCapture = null + isCameraEnabled = false + binding.cameraPreview.visibility = View.GONE + } + + private fun showRecordDialog(){ + val audioRecordDialog = AudioRecordDialog(mContext, object : AudioRecordDialog.Listener{ + override fun onFinish(path: String) { + val thread = Thread { + duix?.startPush() + val inputStream = FileInputStream(path) + val buffer = ByteArray(320) + var length: Int + while (inputStream.read(buffer).also { length = it } > 0){ + val data = buffer.copyOfRange(0, length) + duix?.pushPcm(data) + } + duix?.stopPush() + inputStream.close() + } + thread.start() + } + }) + audioRecordDialog.show() + } +} diff --git a/test/src/main/java/ai/guiji/duix/test/ui/activity/MainActivity.kt b/test/src/main/java/ai/guiji/duix/test/ui/activity/MainActivity.kt new file mode 100644 index 0000000..15b5ef7 --- /dev/null +++ b/test/src/main/java/ai/guiji/duix/test/ui/activity/MainActivity.kt @@ -0,0 +1,203 @@ +package ai.guiji.duix.test.ui.activity + +import ai.guiji.duix.sdk.client.BuildConfig +import ai.guiji.duix.sdk.client.VirtualModelUtil +import ai.guiji.duix.test.R +import ai.guiji.duix.test.databinding.ActivityMainBinding +import ai.guiji.duix.test.ui.dialog.LoadingDialog +import ai.guiji.duix.test.ui.dialog.ModelSelectorDialog +import android.annotation.SuppressLint +import android.content.Intent +import android.os.Bundle +import android.text.TextUtils +import android.widget.Toast +import java.io.File + + +class MainActivity : BaseActivity() { + + private lateinit var binding: ActivityMainBinding + private var mLoadingDialog: LoadingDialog?=null + private var mLastProgress = 0 + + val models = arrayListOf( + "https://github.com/duixcom/Duix-Mobile/releases/download/v1.0.0/bendi3_20240518.zip", + "https://github.com/duixcom/Duix-Mobile/releases/download/v1.0.0/airuike_20240409.zip", + "https://github.com/duixcom/Duix-Mobile/releases/download/v1.0.0/675429759852613_7f8d9388a4213080b1820b83dd057cfb_optim_m80.zip", + "https://github.com/duixcom/Duix-Mobile/releases/download/v1.0.0/674402003804229_f6e86fb375c4f1f1b82b24f7ee4e7cb4_optim_m80.zip", + "https://github.com/duixcom/Duix-Mobile/releases/download/v1.0.0/674400178376773_3925e756433c5a9caa9b9d54147ae4ab_optim_m80.zip", + "https://github.com/duixcom/Duix-Mobile/releases/download/v1.0.0/674397294927941_6e297e18a4bdbe35c07a6ae48a1f021f_optim_m80.zip", + "https://github.com/duixcom/Duix-Mobile/releases/download/v1.0.0/674393494597701_f49fcf68f5afdb241d516db8a7d88a7b_optim_m80.zip", + "https://github.com/duixcom/Duix-Mobile/releases/download/v1.0.0/651705983152197_ccf3256b2449c76e77f94276dffcb293_optim_m80.zip", + "https://github.com/duixcom/Duix-Mobile/releases/download/v1.0.0/627306542239813_1871244b5e6912efc636ba31ea4c5c6d_optim_m80.zip", + ) + + private var mBaseConfigUrl = "" + private var mModelUrl = "" + + @SuppressLint("SetTextI18n") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + + binding.tvSdkVersion.text = "SDK Version: ${BuildConfig.VERSION_NAME}" + + + binding.btnMoreModel.setOnClickListener { + val modelSelectorDialog = ModelSelectorDialog(mContext, models, object : ModelSelectorDialog.Listener{ + override fun onSelect(url: String) { + binding.etUrl.setText(url) + } + }) + modelSelectorDialog.show() + } + binding.btnPlay.setOnClickListener { + play() + } + } + + private fun play(){ + mBaseConfigUrl = binding.etBaseConfig.text.toString() + mModelUrl = binding.etUrl.text.toString() + if (TextUtils.isEmpty(mBaseConfigUrl)){ + Toast.makeText(mContext, R.string.base_config_cannot_be_empty, Toast.LENGTH_SHORT).show() + return + } + if (TextUtils.isEmpty(mModelUrl)){ + Toast.makeText(mContext, R.string.model_url_cannot_be_empty, Toast.LENGTH_SHORT).show() + return + } + checkBaseConfig() + } + + private fun checkBaseConfig(){ + if (VirtualModelUtil.checkBaseConfig(mContext)){ + checkModel() + } else { + baseConfigDownload() + } + } + + private fun checkModel(){ + if (VirtualModelUtil.checkModel(mContext, mModelUrl)){ + jumpPlayPage() + } else { + modelDownload() + } + } + + private fun jumpPlayPage(){ + val intent = Intent(mContext, CallActivity::class.java) + intent.putExtra("modelUrl", mModelUrl) + val debug = binding.switchDebug.isChecked + intent.putExtra("debug", debug) + startActivity(intent) + } + + private fun baseConfigDownload(){ + mLoadingDialog?.dismiss() + mLoadingDialog = LoadingDialog(mContext, "Start downloading") + mLoadingDialog?.show() + VirtualModelUtil.baseConfigDownload(mContext, mBaseConfigUrl, object : + VirtualModelUtil.ModelDownloadCallback { + override fun onDownloadProgress(url: String?, current: Long, total: Long) { + val progress = (current * 100 / total).toInt() + if (progress != mLastProgress){ + mLastProgress = progress + runOnUiThread { + if (mLoadingDialog?.isShowing == true){ + mLoadingDialog?.setContent("Config download(${progress}%)") + } + } + } + } + + override fun onUnzipProgress(url: String?, current: Long, total: Long) { + val progress = (current * 100 / total).toInt() + if (progress != mLastProgress){ + mLastProgress = progress + runOnUiThread { + if (mLoadingDialog?.isShowing == true){ + mLoadingDialog?.setContent("Config unzip(${progress}%)") + } + } + } + } + + override fun onDownloadComplete(url: String?, dir: File?) { + runOnUiThread { + mLoadingDialog?.dismiss() + checkModel() + } + } + + override fun onDownloadFail(url: String?, code: Int, msg: String?) { + runOnUiThread { + mLoadingDialog?.dismiss() + Toast.makeText(mContext, "BaseConfig download error: $msg", Toast.LENGTH_SHORT).show() + } + } + + }) + } + + private fun modelDownload(){ + mLoadingDialog?.dismiss() + mLoadingDialog = LoadingDialog(mContext, "Start downloading") + mLoadingDialog?.show() + VirtualModelUtil.modelDownload(mContext, mModelUrl, object : VirtualModelUtil.ModelDownloadCallback{ + override fun onDownloadProgress( + url: String?, + current: Long, + total: Long, + ) { + val progress = (current * 100 / total).toInt() + if (progress != mLastProgress){ + mLastProgress = progress + runOnUiThread { + if (mLoadingDialog?.isShowing == true){ + mLoadingDialog?.setContent("Model download(${progress}%)") + } + } + } + } + + override fun onUnzipProgress( + url: String?, + current: Long, + total: Long, + ) { + val progress = (current * 100 / total).toInt() + if (progress != mLastProgress){ + mLastProgress = progress + runOnUiThread { + if (mLoadingDialog?.isShowing == true){ + mLoadingDialog?.setContent("Model unzip(${progress}%)") + } + } + } + } + + override fun onDownloadComplete(url: String?, dir: File?) { + runOnUiThread { + mLoadingDialog?.dismiss() + jumpPlayPage() + } + } + + override fun onDownloadFail( + url: String?, + code: Int, + msg: String?, + ) { + runOnUiThread { + mLoadingDialog?.dismiss() + Toast.makeText(mContext, "Model download error: $msg", Toast.LENGTH_SHORT).show() + } + } + + }) + } + +} diff --git a/test/src/main/java/ai/guiji/duix/test/ui/adapter/ModelSelectorAdapter.kt b/test/src/main/java/ai/guiji/duix/test/ui/adapter/ModelSelectorAdapter.kt new file mode 100644 index 0000000..288d7d3 --- /dev/null +++ b/test/src/main/java/ai/guiji/duix/test/ui/adapter/ModelSelectorAdapter.kt @@ -0,0 +1,39 @@ +package ai.guiji.duix.test.ui.adapter + +import ai.guiji.duix.test.databinding.ItemModelSelectorBinding +import android.annotation.SuppressLint +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView + + +class ModelSelectorAdapter( + private val mList: ArrayList, + private val callback: Callback +) : RecyclerView.Adapter() { + + class ItemHolder(val itemBinding: ItemModelSelectorBinding) : + RecyclerView.ViewHolder(itemBinding.root) + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemHolder { + val itemBinding = + ItemModelSelectorBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return ItemHolder(itemBinding) + } + + @SuppressLint("SetTextI18n") + override fun onBindViewHolder(holder: ItemHolder, position: Int) { + holder.itemBinding.tvModelUrl.text = mList[position] + holder.itemBinding.tvModelUrl.setOnClickListener { + callback.onClick(mList[position]) + } + } + + override fun getItemCount(): Int { + return mList.size + } + + interface Callback { + fun onClick(url: String) + } +} \ No newline at end of file diff --git a/test/src/main/java/ai/guiji/duix/test/ui/adapter/MotionAdapter.kt b/test/src/main/java/ai/guiji/duix/test/ui/adapter/MotionAdapter.kt new file mode 100644 index 0000000..8b24e52 --- /dev/null +++ b/test/src/main/java/ai/guiji/duix/test/ui/adapter/MotionAdapter.kt @@ -0,0 +1,39 @@ +package ai.guiji.duix.test.ui.adapter + +import ai.guiji.duix.test.databinding.ItemMotionButtonBinding +import android.annotation.SuppressLint +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView + + +class MotionAdapter( + private val mList: ArrayList, + private val callback: Callback +) : RecyclerView.Adapter() { + + class ItemHolder(val itemBinding: ItemMotionButtonBinding) : + RecyclerView.ViewHolder(itemBinding.root) + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemHolder { + val itemBinding = + ItemMotionButtonBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return ItemHolder(itemBinding) + } + + @SuppressLint("SetTextI18n") + override fun onBindViewHolder(holder: ItemHolder, position: Int) { + holder.itemBinding.btnMotion.text = mList[position] + holder.itemBinding.btnMotion.setOnClickListener { + callback.onClick(mList[position], true) + } + } + + override fun getItemCount(): Int { + return mList.size + } + + interface Callback { + fun onClick(name: String, now: Boolean) + } +} \ No newline at end of file diff --git a/test/src/main/java/ai/guiji/duix/test/ui/dialog/AudioRecordDialog.kt b/test/src/main/java/ai/guiji/duix/test/ui/dialog/AudioRecordDialog.kt new file mode 100644 index 0000000..11b1a21 --- /dev/null +++ b/test/src/main/java/ai/guiji/duix/test/ui/dialog/AudioRecordDialog.kt @@ -0,0 +1,96 @@ +package ai.guiji.duix.test.ui.dialog + +import ai.guiji.duix.test.R +import ai.guiji.duix.test.audio.AudioRecorder +import ai.guiji.duix.test.databinding.DialogAudioRecordBinding +import android.annotation.SuppressLint +import android.app.Dialog +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.MotionEvent +import android.view.ViewGroup +import android.view.Window +import android.widget.Toast + +class AudioRecordDialog( + private val mContext: Context, + private val listener: Listener +) : Dialog(mContext, R.style.dialog_center) { + + private var binding: DialogAudioRecordBinding + + private var audioRecorder: AudioRecorder?=null + + init { + requestWindowFeature(Window.FEATURE_NO_TITLE) + binding = DialogAudioRecordBinding.inflate(layoutInflater) + setContentView(binding.root) + } + + + @SuppressLint("ClickableViewAccessibility") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + window?.let { + it.setGravity(Gravity.BOTTOM) + it.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + it.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + } + + binding.tvTouch.setOnTouchListener { _, event -> + when (event?.action) { + MotionEvent.ACTION_DOWN -> { + startRecord() + } + + MotionEvent.ACTION_UP -> { + stopRecord() + } + } + false + } + + setCancelable(true) + setCanceledOnTouchOutside(true) + } + + private fun startRecord(){ + audioRecorder = AudioRecorder(mContext, object : AudioRecorder.RecorderCallback{ + override fun onReadData(data: ByteArray, offsetInBytes: Int, length: Int) { + } + + override fun onRecordError(code: Int, message: String) { + binding.layoutFrame.post { + Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show() + audioRecorder?.release() + } + } + + override fun onFinish(path: String) { + binding.layoutFrame.post { + audioRecorder?.release() + listener.onFinish(path) + dismiss() + } + } + }) + audioRecorder?.start() + } + + private fun stopRecord(){ + audioRecorder?.stop() + } + + override fun dismiss() { + super.dismiss() + audioRecorder?.release() + } + + interface Listener { + fun onFinish(path: String) + } + +} \ No newline at end of file diff --git a/test/src/main/java/ai/guiji/duix/test/ui/dialog/LoadingDialog.kt b/test/src/main/java/ai/guiji/duix/test/ui/dialog/LoadingDialog.kt new file mode 100644 index 0000000..1b30ca0 --- /dev/null +++ b/test/src/main/java/ai/guiji/duix/test/ui/dialog/LoadingDialog.kt @@ -0,0 +1,50 @@ +package ai.guiji.duix.test.ui.dialog + +import ai.guiji.duix.test.R +import ai.guiji.duix.test.databinding.DialogLoadingBinding +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.text.TextUtils +import android.view.Window +import android.view.animation.Animation +import android.view.animation.AnimationUtils +import android.view.animation.LinearInterpolator + + +class LoadingDialog(private var mContext: Context, private val content: String = "") : + Dialog(mContext, R.style.dialog_center) { + + private lateinit var binding: DialogLoadingBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + requestWindowFeature(Window.FEATURE_NO_TITLE) + binding = DialogLoadingBinding.inflate(layoutInflater) + super.setContentView(binding.root) + + if (!TextUtils.isEmpty(content)){ + binding.tvContent.text = content + } + + setCancelable(false) + setCanceledOnTouchOutside(false) + } + + fun setContent(content: String){ + binding.tvContent.text = content + } + + override fun show() { + super.show() + val animation: Animation = AnimationUtils.loadAnimation(mContext, R.anim.rotate) + val lin = LinearInterpolator() + animation.interpolator = lin + binding.ivProgress.startAnimation(animation) + } + + override fun dismiss() { + super.dismiss() + binding.ivProgress.clearAnimation() + } +} \ No newline at end of file diff --git a/test/src/main/java/ai/guiji/duix/test/ui/dialog/ModelSelectorDialog.kt b/test/src/main/java/ai/guiji/duix/test/ui/dialog/ModelSelectorDialog.kt new file mode 100644 index 0000000..42a306b --- /dev/null +++ b/test/src/main/java/ai/guiji/duix/test/ui/dialog/ModelSelectorDialog.kt @@ -0,0 +1,39 @@ +package ai.guiji.duix.test.ui.dialog + +import ai.guiji.duix.test.R +import ai.guiji.duix.test.databinding.DialogModelSelectorBinding +import ai.guiji.duix.test.ui.adapter.ModelSelectorAdapter +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.Window + + +class ModelSelectorDialog(mContext: Context, val models: ArrayList, private val listener: Listener) : + Dialog(mContext, R.style.dialog_center) { + + private lateinit var binding: DialogModelSelectorBinding + private var mAdapter: ModelSelectorAdapter?=null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + requestWindowFeature(Window.FEATURE_NO_TITLE) + binding = DialogModelSelectorBinding.inflate(layoutInflater) + super.setContentView(binding.root) + + mAdapter = ModelSelectorAdapter(models, object : ModelSelectorAdapter.Callback{ + override fun onClick(url: String) { + dismiss() + listener.onSelect(url) + } + }) + binding.rvModels.adapter = mAdapter + + setCancelable(true) + setCanceledOnTouchOutside(true) + } + + interface Listener { + fun onSelect(url: String) + } +} \ No newline at end of file diff --git a/test/src/main/java/ai/guiji/duix/test/util/StringUtils.java b/test/src/main/java/ai/guiji/duix/test/util/StringUtils.java new file mode 100644 index 0000000..1ddec8e --- /dev/null +++ b/test/src/main/java/ai/guiji/duix/test/util/StringUtils.java @@ -0,0 +1,396 @@ +package ai.guiji.duix.test.util; + +import static java.lang.Character.UnicodeBlock.CJK_COMPATIBILITY_FORMS; +import static java.lang.Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS; +import static java.lang.Character.UnicodeBlock.CJK_RADICALS_SUPPLEMENT; +import static java.lang.Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS; +import static java.lang.Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A; +import static java.lang.Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B; + +import java.math.BigDecimal; +import java.net.URLEncoder; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class StringUtils { + + /* + * 秒数转时间 + * */ + public static String secondsToHMS(int seconds) { + StringBuilder time = new StringBuilder(); + int min = 0; + int hour = 0; +// 将毫秒转换成秒 +// seconds = seconds / 1000; + if (seconds > 60) { + min = seconds / 60; + seconds = seconds % 60; + } + if (min > 60) { + hour = min / 60; + min = min % 60; + } + //拼接 + if (hour < 10) + time.append("0"); + time.append(hour); + time.append(":"); + if (min < 10) + time.append("0"); + time.append(min); + time.append(":"); + if (seconds < 10) + time.append("0"); + time.append(seconds); + return time.toString(); + } + + /* + * 秒数转时间 + * */ + public static String secondsToMS(int seconds) { + StringBuilder time = new StringBuilder(); + int min = 0; +// 将毫秒转换成秒 +// seconds = seconds / 1000; + if (seconds > 60) { + min = seconds / 60; + seconds = seconds % 60; + } + /*if (min > 60) { + min = min % 60; + }*/ + if (min < 10) + time.append("0"); + time.append(min); + time.append(":"); + if (seconds < 10) + time.append("0"); + time.append(seconds); + return time.toString(); + } + + public static String formatDateTime(long mss) { + String DateTimes; + long days = mss / (60 * 60 * 24); + long hours = (mss % (60 * 60 * 24)) / (60 * 60); + long minutes = (mss % (60 * 60)) / 60; + long seconds = mss % 60; + if (days > 0) { + DateTimes = days + "天" + hours + "时"; + } else if (hours > 0) { + DateTimes = hours + "时" + minutes + "分钟"; + } else if (minutes > 0) { + DateTimes = minutes + "分钟" + + seconds + "秒"; + } else { + DateTimes = seconds + "秒"; + } + + return DateTimes; + } + + //只展示秒,分钟 + public static String formatDateTime2(long mss) { + long min = mss / 60; + long second = mss % 60; + String result = ""; + if (mss < 60) { + result = mss + "秒"; + } else { + if (0 == second) { + result = min + "分钟"; + } else { + result = min + "分钟" + second + "秒"; + } + } + return result; + } + + //只展示秒或者分钟 + public static String formatDateTime3(long mss) { + return mss < 60 ? (mss + "秒") : ((mss / 60) + "分钟"); + } + + //只展示秒,分 + public static String formatDateTime4(long mss) { + return mss < 60 ? (mss + "秒") : ((mss / 60) + "分" + ((mss % 60) == 0 ? "" : (mss % 60) + "秒")); + } + + public static String formatVideoDateTime(long mss) { + String DateTimes; + long hours = mss / (60 * 60); + long minutes = (mss % (60 * 60)) / 60; + long seconds = mss % 60; + String hourStr = (hours < 10 ? "0" : "") + hours; + String minuteStr = (minutes < 10 ? "0" : "") + minutes; + String secondStr = (seconds < 10 ? "0" : "") + seconds; + if (hours > 0) { + DateTimes = hourStr + ":" + minuteStr + ":" + secondStr; + } else { + DateTimes = minuteStr + ":" + secondStr; + } + + return DateTimes; + } + + /** + * 格式化文件大小 + * + * @param size + * @return + */ + public static String formatSize(long size) { + String sizeStr = ""; + String unit[] = {"byte", "kb", "mb", "g" }; + long lastValue = size; + for (int i = 0; i < unit.length; i++) { + size = size / 1024; + if (0 == size) { + sizeStr = lastValue + unit[i]; + break; + } else { + if (i == unit.length - 1) { + sizeStr = lastValue + unit[i]; + } else { + lastValue = size; + } + } + } + return sizeStr; + } + + public static String createFileName(String prefix, String suffix) { + Date dt = new Date(System.currentTimeMillis()); + SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMddHHmmssSSS"); + String fileName = fmt.format(dt); + fileName = prefix + fileName + suffix; //extension, you can change it. + return fileName; + } + + public static String dateToStringMS(long date) { + SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmssSSS"); + Date dt = new Date(date); + return format.format(dt); + } + + public static String dateToStringMS2() { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM"); + Date dt = new Date(); + return format.format(dt); + } + + public static String dateToStringMS3() { + SimpleDateFormat format = new SimpleDateFormat("MM-dd HH:mm"); + Date dt = new Date(); + return format.format(dt); + } + + public static String dateToStringMS4() { + SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss.SSS"); + Date dt = new Date(); + return format.format(dt); + } + + //去除数字结尾无用的0 + public static String filterUnUselessZero(String str) { + String value = ""; + if (null != str) { + String regEx = "\\.(0+)$"; + Pattern pattern = Pattern.compile(regEx); + Matcher matcher = pattern.matcher(str); + boolean rs = matcher.find(); + if (rs && null != matcher.group(0)) { + value = str.replace(matcher.group(0), ""); + } else { + value = str; + } + } + return value; + } + + //判断数字是否为0 + public static boolean isNullOrZero(String str) { + boolean result = false; + if (null == str || "".equals(str.trim())) { + result = true; + } else { + try { + double d = Double.parseDouble(str); + result = d == 0; + } catch (Exception e) { + } + } + return result; + } + + //判断是否为空 + public static boolean isEmpty(String str) { + boolean result = false; + if (null == str || "".equals(str.trim())) { + result = true; + } + return result; + } + + // encode + public String urlEncoded(String paramString) { + if (paramString == null || paramString == "") { + return ""; + } + try { + String str = URLEncoder.encode(paramString, "UTF-8"); + return str; + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + //判断大小 + public static Boolean isEnough(String v1, String v2) { + Boolean result = null; + try { + Double d1 = Double.parseDouble(v1); + Double d2 = Double.parseDouble(v2); + result = d1 >= d2; + } catch (Exception e) { + } + return result; + } + + /** + * 比较两个字符串不相等处,两个字符串去除标点之后,长度必须一致才会比对 + * + * @param str1 + * @param str2 + * @return + */ + public static List compareTwoStr(String str1, String str2) { + List mark = new ArrayList<>(); + String str1WithoutSymbol = removeSymbol(str1); + String str2WithoutSymbol = removeSymbol(str2); + int symbolCount = 0; + char[] str1Char = str1.toCharArray(); + char[] str2Char = str2WithoutSymbol.toCharArray(); + for (int i = 0; i < str1Char.length; i++) { + if ("".equals(removeSymbol(String.valueOf(str1Char[i])))) { + symbolCount++; + continue; + } + if (str1Char[i] != str2Char[i - symbolCount]) { + if (0 == mark.size() % 2) { + mark.add(i); + } + } else { + if (0 != mark.size() % 2) { + mark.add(i); + } + } + //提前结束 + if (i - symbolCount == str2Char.length - 1) { + if (0 == mark.size() % 2 && i + 1 < str1Char.length) { + //存在非符号,才把后面标出来 + if (!"".equals(removeSymbol(str1.substring(i + 1)))) { + mark.add(i + 1); + } + } + break; + } + } + if (0 != mark.size() % 2) { + mark.add(str1Char.length); + } + if (0 == mark.size() && str1WithoutSymbol.length() < str2WithoutSymbol.length()) { + mark.add(0); + mark.add(str1Char.length); + } + return mark; + } + + /** + * 去除字符串中的符号标点 + * + * @param input + * @return + */ + public static String removeSymbol(String input) { + return input.replaceAll("\\p{P}|\\p{S}", ""); + } + + public static double formatDouble(double value, int accuracy) { + BigDecimal b = new BigDecimal(value); + //保留2位小数 + double out = b.setScale(accuracy, BigDecimal.ROUND_HALF_UP).doubleValue(); + return out; + } + + /** + * 字符串中是否只包含汉字字母 + * + * @return + */ + public static boolean isCharOrLetter(String str) { + String ruleString = "[\\u4e00-\\u9fa5a-zA-Z0-9]*"; + Pattern p = Pattern.compile(ruleString); + char[] c = str.toCharArray(); + for (int i = 0; i < c.length; i++) { + Matcher matcher = p.matcher("" + c[i]); + boolean b = matcher.matches(); + if (b) { + continue; + } else { + return false; + } + } + return true; + } + + /** + * 判断是否含有中文 + * + * @param checkChar + * @return + */ + public static boolean checkCharContainChinese(char checkChar) { + Character.UnicodeBlock ub = Character.UnicodeBlock.of(checkChar); + if (CJK_UNIFIED_IDEOGRAPHS == ub || CJK_COMPATIBILITY_IDEOGRAPHS == ub || CJK_COMPATIBILITY_FORMS == ub || + CJK_RADICALS_SUPPLEMENT == ub || CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A == ub || CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B == ub) { + return true; + } + return false; + } + + //格式化时间为年月日 + public static String formatDateString(String time) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + String formatString = ""; + try { + Date date = sdf.parse(time); + formatString = sdf.format(date); + } catch (Exception e) { + e.printStackTrace(); + } + return formatString; + } + + public static String subZeroAndDot(String s) { + if (s.indexOf(".") > 0) { + s = s.replaceAll("0+?$", "");//去掉多余的0 + s = s.replaceAll("[.]$", "");//如最后一位是.则去掉 + } + return s; + } + // 是否包含特殊字符 + public static boolean isSpecialChar(String str) { + String regEx = "[ _`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]|\n|\r|\t"; + Pattern p = Pattern.compile(regEx); + Matcher m = p.matcher(str); + return m.find(); + } +} diff --git a/test/src/main/java/ai/guiji/duix/test/util/SystemUtils.java b/test/src/main/java/ai/guiji/duix/test/util/SystemUtils.java new file mode 100644 index 0000000..1b65bff --- /dev/null +++ b/test/src/main/java/ai/guiji/duix/test/util/SystemUtils.java @@ -0,0 +1,71 @@ +package ai.guiji.duix.test.util; + +import android.content.Context; +import android.content.pm.PackageManager; + +public class SystemUtils { + + public static int getVersionCode(Context context) { + try { + return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return -1; + } + } + + public static String getVersionName(Context context) { + try { + return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return ""; + } + } + + /** + * 版本号比较 + * + * @param version1 + * @param version2 + * @return + */ + public static int compareVersion(String version1, String version2) { + try { + if (version1.equals(version2)) { + return 0; + } + String[] version1Array = version1.split("\\."); + String[] version2Array = version2.split("\\."); + int index = 0; + // 获取最小长度值 + int minLen = Math.min(version1Array.length, version2Array.length); + int diff = 0; + while (index < minLen + && (diff = Integer.parseInt(version1Array[index]) + - Integer.parseInt(version2Array[index])) == 0) { + index++; + } + if (diff == 0) { + // 如果位数不一致,比较多余位数 + for (int i = index; i < version1Array.length; i++) { + if (Integer.parseInt(version1Array[i]) > 0) { + return 1; + } + } + + for (int i = index; i < version2Array.length; i++) { + if (Integer.parseInt(version2Array[i]) > 0) { + return -1; + } + } + return 0; + } else { + return diff > 0 ? 1 : -1; + } + } catch (Exception e) { + e.printStackTrace(); + } + return -1; + } +} diff --git a/test/src/main/java/ai/guiji/duix/test/util/ZipUtil.java b/test/src/main/java/ai/guiji/duix/test/util/ZipUtil.java new file mode 100644 index 0000000..0b6f53d --- /dev/null +++ b/test/src/main/java/ai/guiji/duix/test/util/ZipUtil.java @@ -0,0 +1,101 @@ +package ai.guiji.duix.test.util; + +import android.util.Log; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipInputStream; + +public class ZipUtil { + + //解压缩文件 + // 这里unzip需要使用canonicalPath做校验,但是该方法取的路径可能和getAbsolutePath()方式获取的不一致 + // getCanonicalPath() /data/data/....... + // getAbsolutePath /data/user/0/...... + public static boolean unzip(String zipFilePath, String outOutPath, Callback callback) { + try (FileInputStream fis = new FileInputStream(zipFilePath)) { + long total = 0; + if (callback != null){ + total = getZipSize(zipFilePath); + } + ZipInputStream inZip = new ZipInputStream(fis); + long currentSize = 0; + ZipEntry zipEntry; + String szName = ""; + while ((zipEntry = inZip.getNextEntry()) != null) { + szName = zipEntry.getName(); + if (zipEntry.isDirectory()) { + szName = szName.substring(0, szName.length() - 1); + File folder = new File(outOutPath + File.separator + szName); + String canonicalPath = folder.getCanonicalPath(); + if (!canonicalPath.startsWith(outOutPath)) { + Log.e("123", "绝对值路径比较异常忽略该地址: " + folder.getAbsolutePath()); + } else { + if (!folder.exists()) { + if (!folder.mkdirs()) { + return false; + } + } + } + } else { + File file = new File(outOutPath + File.separator + szName); + String canonicalPath = file.getCanonicalPath(); + if (!canonicalPath.startsWith(outOutPath)) { + Log.e("123", "绝对值路径比较异常忽略该地址: " + file.getAbsolutePath()); + } else { + if (!file.exists()) { + if (!file.getParentFile().exists()) { + file.getParentFile().mkdirs(); + } + if (!file.createNewFile()) { + return false; + } + FileOutputStream out = new FileOutputStream(file); + int len; + byte[] buffer = new byte[2048]; + while ((len = inZip.read(buffer)) != -1) { + out.write(buffer, 0, len); + out.flush(); + if (callback != null) { + currentSize += len; + int progress = (int)(currentSize * 100.0f / total); + callback.onProgress(progress); // 通过回调函数更新进度 + } + } + out.close(); + } + } + } + } + inZip.close(); + return true; + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + + private static long getZipSize(String filePath){ + long size = 0; + ZipFile f; + try { + f = new ZipFile(filePath); + Enumeration en = f.entries(); + while (en.hasMoreElements()) { + size += en.nextElement().getSize(); + } + } catch (IOException e) { + size = 0; + } + return size; + } + + public interface Callback { + void onProgress(int progress); + } +} diff --git a/test/src/main/res/anim/rotate.xml b/test/src/main/res/anim/rotate.xml new file mode 100644 index 0000000..cdf1458 --- /dev/null +++ b/test/src/main/res/anim/rotate.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/test/src/main/res/drawable/ic_launcher_background.xml b/test/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/test/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/src/main/res/drawable/ic_launcher_foreground.xml b/test/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/test/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/test/src/main/res/drawable/selector_60_primary.xml b/test/src/main/res/drawable/selector_60_primary.xml new file mode 100644 index 0000000..2b4ce9c --- /dev/null +++ b/test/src/main/res/drawable/selector_60_primary.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/test/src/main/res/drawable/shape_circle_camera_off.xml b/test/src/main/res/drawable/shape_circle_camera_off.xml new file mode 100644 index 0000000..1a55f79 --- /dev/null +++ b/test/src/main/res/drawable/shape_circle_camera_off.xml @@ -0,0 +1,5 @@ + + + + diff --git a/test/src/main/res/drawable/shape_circle_camera_on.xml b/test/src/main/res/drawable/shape_circle_camera_on.xml new file mode 100644 index 0000000..d454605 --- /dev/null +++ b/test/src/main/res/drawable/shape_circle_camera_on.xml @@ -0,0 +1,5 @@ + + + + diff --git a/test/src/main/res/drawable/shape_circle_fab.xml b/test/src/main/res/drawable/shape_circle_fab.xml new file mode 100644 index 0000000..d454605 --- /dev/null +++ b/test/src/main/res/drawable/shape_circle_fab.xml @@ -0,0 +1,5 @@ + + + + diff --git a/test/src/main/res/drawable/shape_common_btn.xml b/test/src/main/res/drawable/shape_common_btn.xml new file mode 100644 index 0000000..d2984a6 --- /dev/null +++ b/test/src/main/res/drawable/shape_common_btn.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/test/src/main/res/drawable/shape_corners_60_99_primary.xml b/test/src/main/res/drawable/shape_corners_60_99_primary.xml new file mode 100644 index 0000000..d4e150c --- /dev/null +++ b/test/src/main/res/drawable/shape_corners_60_99_primary.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/test/src/main/res/drawable/shape_corners_60_primary.xml b/test/src/main/res/drawable/shape_corners_60_primary.xml new file mode 100644 index 0000000..fa3f139 --- /dev/null +++ b/test/src/main/res/drawable/shape_corners_60_primary.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/test/src/main/res/drawable/shape_solid_b3000000_radius_7.xml b/test/src/main/res/drawable/shape_solid_b3000000_radius_7.xml new file mode 100644 index 0000000..f0f6d53 --- /dev/null +++ b/test/src/main/res/drawable/shape_solid_b3000000_radius_7.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/test/src/main/res/drawable/shape_tl_tr_32_ffffffff.xml b/test/src/main/res/drawable/shape_tl_tr_32_ffffffff.xml new file mode 100644 index 0000000..9ffaec5 --- /dev/null +++ b/test/src/main/res/drawable/shape_tl_tr_32_ffffffff.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/test/src/main/res/drawable/shape_tl_tr_bl_20_ff147bf7.xml b/test/src/main/res/drawable/shape_tl_tr_bl_20_ff147bf7.xml new file mode 100644 index 0000000..740842c --- /dev/null +++ b/test/src/main/res/drawable/shape_tl_tr_bl_20_ff147bf7.xml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/test/src/main/res/drawable/shape_tl_tr_br_20_ffd9eaff.xml b/test/src/main/res/drawable/shape_tl_tr_br_20_ffd9eaff.xml new file mode 100644 index 0000000..0d461f6 --- /dev/null +++ b/test/src/main/res/drawable/shape_tl_tr_br_20_ffd9eaff.xml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/test/src/main/res/layout/activity_call.xml b/test/src/main/res/layout/activity_call.xml new file mode 100644 index 0000000..2219ea2 --- /dev/null +++ b/test/src/main/res/layout/activity_call.xml @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + +